From 225006a4f768a603f698b25f830e0819b1696f1e Mon Sep 17 00:00:00 2001 From: Ke Wang Date: Wed, 1 Nov 2017 16:07:38 +0800 Subject: [PATCH 0001/1834] sched: EAS: Fix the calculation of group util in group_idle_state() util_delta becomes not zero in eenv_before, which will affect the calculation of grp_util in group_idle_state(). Fix it under the new condition. Change-Id: Ic3853bb45876a8e388afcbe4e72d25fc42b1d7b0 Signed-off-by: Ke Wang (cherry picked from commit 47c87b2654376e7dda646ca5a2af067c5d368ca7) Signed-off-by: Quentin Perret --- kernel/sched/fair.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index b0dce0a8c950..a146ac437883 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5568,13 +5568,6 @@ static int group_idle_state(struct energy_env *eenv, struct sched_group *sg) /* Take non-cpuidle idling into account (active idle/arch_cpu_idle()) */ state++; - /* - * Try to estimate if a deeper idle state is - * achievable when we move the task. - */ - for_each_cpu(i, sched_group_cpus(sg)) - grp_util += cpu_util(i); - src_in_grp = cpumask_test_cpu(eenv->src_cpu, sched_group_cpus(sg)); dst_in_grp = cpumask_test_cpu(eenv->dst_cpu, sched_group_cpus(sg)); if (src_in_grp == dst_in_grp) { @@ -5583,10 +5576,16 @@ static int group_idle_state(struct energy_env *eenv, struct sched_group *sg) */ goto end; } - /* add or remove util as appropriate to indicate what group util - * will be (worst case - no concurrent execution) after moving the task + + /* + * Try to estimate if a deeper idle state is + * achievable when we move the task. */ - grp_util += src_in_grp ? -eenv->util_delta : eenv->util_delta; + for_each_cpu(i, sched_group_cpus(sg)) { + grp_util += cpu_util_wake(i, eenv->task); + if (unlikely(i == eenv->trg_cpu)) + grp_util += eenv->util_delta; + } if (grp_util <= ((long)sg->sgc->max_capacity * (int)sg->group_weight)) { -- GitLab From e997bf0fdea2ce27f30567c2952fdd94a8db9c30 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Tue, 12 Sep 2017 14:48:29 +0100 Subject: [PATCH 0002/1834] sched/fair: use *p to reference task_structs This is a simple renaming patch which just align to the most common code convention used in fair.c, task_structs pointers are usually named *p. Change-Id: Id0769e52b6a271014d89353fdb4be9bb721b5b2f Signed-off-by: Patrick Bellasi Signed-off-by: Chris Redpath Signed-off-by: Quentin Perret --- kernel/sched/fair.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index a146ac437883..4eb5a2e8834a 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5439,7 +5439,7 @@ struct energy_env { int trg_cpu; int energy; int payoff; - struct task_struct *task; + struct task_struct *p; struct { int before; int after; @@ -5485,7 +5485,7 @@ static unsigned long group_max_util(struct energy_env *eenv) int cpu; for_each_cpu(cpu, sched_group_cpus(eenv->sg_cap)) { - util = cpu_util_wake(cpu, eenv->task); + util = cpu_util_wake(cpu, eenv->p); /* * If we are looking at the target CPU specified by the eenv, @@ -5520,7 +5520,7 @@ long group_norm_util(struct energy_env *eenv, struct sched_group *sg) int cpu; for_each_cpu(cpu, sched_group_cpus(sg)) { - util = cpu_util_wake(cpu, eenv->task); + util = cpu_util_wake(cpu, eenv->p); /* * If we are looking at the target CPU specified by the eenv, @@ -5582,7 +5582,7 @@ static int group_idle_state(struct energy_env *eenv, struct sched_group *sg) * achievable when we move the task. */ for_each_cpu(i, sched_group_cpus(sg)) { - grp_util += cpu_util_wake(i, eenv->task); + grp_util += cpu_util_wake(i, eenv->p); if (unlikely(i == eenv->trg_cpu)) grp_util += eenv->util_delta; } @@ -5741,13 +5741,13 @@ static inline int __energy_diff(struct energy_env *eenv) int diff, margin; struct energy_env eenv_before = { - .util_delta = task_util(eenv->task), + .util_delta = task_util(eenv->p), .src_cpu = eenv->src_cpu, .dst_cpu = eenv->dst_cpu, .trg_cpu = eenv->src_cpu, .nrg = { 0, 0, 0, 0}, .cap = { 0, 0, 0 }, - .task = eenv->task, + .p = eenv->p, }; if (eenv->src_cpu == eenv->dst_cpu) @@ -5784,7 +5784,7 @@ static inline int __energy_diff(struct energy_env *eenv) eenv->nrg.diff = eenv->nrg.after - eenv->nrg.before; eenv->payoff = 0; #ifndef CONFIG_SCHED_TUNE - trace_sched_energy_diff(eenv->task, + trace_sched_energy_diff(eenv->p, eenv->src_cpu, eenv->dst_cpu, eenv->util_delta, eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff, eenv->cap.before, eenv->cap.after, eenv->cap.delta, @@ -5848,7 +5848,7 @@ normalize_energy(int energy_diff) static inline int energy_diff(struct energy_env *eenv) { - int boost = schedtune_task_boost(eenv->task); + int boost = schedtune_task_boost(eenv->p); int nrg_delta; /* Conpute "absolute" energy diff */ @@ -5856,7 +5856,7 @@ energy_diff(struct energy_env *eenv) /* Return energy diff when boost margin is 0 */ if (boost == 0) { - trace_sched_energy_diff(eenv->task, + trace_sched_energy_diff(eenv->p, eenv->src_cpu, eenv->dst_cpu, eenv->util_delta, eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff, eenv->cap.before, eenv->cap.after, eenv->cap.delta, @@ -5871,9 +5871,9 @@ energy_diff(struct energy_env *eenv) eenv->payoff = schedtune_accept_deltas( eenv->nrg.delta, eenv->cap.delta, - eenv->task); + eenv->p); - trace_sched_energy_diff(eenv->task, + trace_sched_energy_diff(eenv->p, eenv->src_cpu, eenv->dst_cpu, eenv->util_delta, eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff, eenv->cap.before, eenv->cap.after, eenv->cap.delta, @@ -6000,7 +6000,7 @@ static inline unsigned long task_util(struct task_struct *p) return p->se.avg.util_avg; } -static inline unsigned long boosted_task_util(struct task_struct *task); +static inline unsigned long boosted_task_util(struct task_struct *p); static inline bool __task_fits(struct task_struct *p, int cpu, int util) { @@ -6077,16 +6077,16 @@ schedtune_cpu_margin(unsigned long util, int cpu) } static inline long -schedtune_task_margin(struct task_struct *task) +schedtune_task_margin(struct task_struct *p) { - int boost = schedtune_task_boost(task); + int boost = schedtune_task_boost(p); unsigned long util; long margin; if (boost == 0) return 0; - util = task_util(task); + util = task_util(p); margin = schedtune_margin(util, boost); return margin; @@ -6101,7 +6101,7 @@ schedtune_cpu_margin(unsigned long util, int cpu) } static inline int -schedtune_task_margin(struct task_struct *task) +schedtune_task_margin(struct task_struct *p) { return 0; } @@ -6120,12 +6120,12 @@ boosted_cpu_util(int cpu) } static inline unsigned long -boosted_task_util(struct task_struct *task) +boosted_task_util(struct task_struct *p) { - unsigned long util = task_util(task); - long margin = schedtune_task_margin(task); + unsigned long util = task_util(p); + long margin = schedtune_task_margin(p); - trace_sched_boost_task(task, util, margin); + trace_sched_boost_task(p, util, margin); return util + margin; } @@ -7042,8 +7042,8 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync .util_delta = task_util(p), .src_cpu = prev_cpu, .dst_cpu = target_cpu, - .task = p, - .trg_cpu = target_cpu, + .p = p, + .trg_cpu = target_cpu, }; -- GitLab From 4905932b059289d22f320b92c42331752ad82845 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Wed, 28 Jun 2017 15:59:46 +0100 Subject: [PATCH 0003/1834] sched/fair: remove energy_diff tracepoint in preparation to re-factoring The format of the energy_diff tracepoint is going to be changed by the following energ_diff refactoring patches. Let's remove it now to start from a clean slate. Change-Id: Id4f537ed60d90a7ddcca0a29a49944bfacb85c8c Signed-off-by: Patrick Bellasi Signed-off-by: Chris Redpath Signed-off-by: Quentin Perret --- include/trace/events/sched.h | 57 ------------------------------------ kernel/sched/fair.c | 14 +-------- 2 files changed, 1 insertion(+), 70 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index f0517de5a8b5..212c5dbb8d56 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -894,63 +894,6 @@ TRACE_EVENT(sched_find_best_target, __entry->target) ); -/* - * Tracepoint for accounting sched group energy - */ -TRACE_EVENT(sched_energy_diff, - - TP_PROTO(struct task_struct *tsk, int scpu, int dcpu, int udelta, - int nrgb, int nrga, int nrgd, int capb, int capa, int capd, - int nrgn, int nrgp), - - TP_ARGS(tsk, scpu, dcpu, udelta, - nrgb, nrga, nrgd, capb, capa, capd, - nrgn, nrgp), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( int, scpu ) - __field( int, dcpu ) - __field( int, udelta ) - __field( int, nrgb ) - __field( int, nrga ) - __field( int, nrgd ) - __field( int, capb ) - __field( int, capa ) - __field( int, capd ) - __field( int, nrgn ) - __field( int, nrgp ) - ), - - TP_fast_assign( - memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); - __entry->pid = tsk->pid; - __entry->scpu = scpu; - __entry->dcpu = dcpu; - __entry->udelta = udelta; - __entry->nrgb = nrgb; - __entry->nrga = nrga; - __entry->nrgd = nrgd; - __entry->capb = capb; - __entry->capa = capa; - __entry->capd = capd; - __entry->nrgn = nrgn; - __entry->nrgp = nrgp; - ), - - TP_printk("pid=%d comm=%s " - "src_cpu=%d dst_cpu=%d usage_delta=%d " - "nrg_before=%d nrg_after=%d nrg_diff=%d " - "cap_before=%d cap_after=%d cap_delta=%d " - "nrg_delta=%d nrg_payoff=%d", - __entry->pid, __entry->comm, - __entry->scpu, __entry->dcpu, __entry->udelta, - __entry->nrgb, __entry->nrga, __entry->nrgd, - __entry->capb, __entry->capa, __entry->capd, - __entry->nrgn, __entry->nrgp) -); - /* * Tracepoint for schedtune_tasks_update */ diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 4eb5a2e8834a..bf40575bf48f 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5783,13 +5783,7 @@ static inline int __energy_diff(struct energy_env *eenv) eenv->nrg.after = energy_after; eenv->nrg.diff = eenv->nrg.after - eenv->nrg.before; eenv->payoff = 0; -#ifndef CONFIG_SCHED_TUNE - trace_sched_energy_diff(eenv->p, - eenv->src_cpu, eenv->dst_cpu, eenv->util_delta, - eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff, - eenv->cap.before, eenv->cap.after, eenv->cap.delta, - eenv->nrg.delta, eenv->payoff); -#endif + /* * Dead-zone margin preventing too many migrations. */ @@ -5873,12 +5867,6 @@ energy_diff(struct energy_env *eenv) eenv->cap.delta, eenv->p); - trace_sched_energy_diff(eenv->p, - eenv->src_cpu, eenv->dst_cpu, eenv->util_delta, - eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff, - eenv->cap.before, eenv->cap.after, eenv->cap.delta, - eenv->nrg.delta, eenv->payoff); - /* * When SchedTune is enabled, the energy_diff() function will return * the computed energy payoff value. Since the energy_diff() return -- GitLab From 7f44e92d1ce6e78cc0d360aa29392633cbecfa03 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Tue, 12 Sep 2017 14:57:51 +0100 Subject: [PATCH 0004/1834] sched/fair: remove capacity tracking from energy_diff In preparation for the energy_diff refactoring, let's remove all the SchedTune specific bits which are used to keep track of the capacity variations requited by the PESpace filtering. This removes also the energy_normalization function and the wrapper of energy_diff which is used to trigger a PESpace filtering by schedtune_accept_deltas(). The remaining code is the "original" energy_diff function which looks just at the energy variations to compare prev_cpu vs next_cpu. Change-Id: I4fb1d1c5ba45a364e6db9ab8044969349aba0307 Signed-off-by: Patrick Bellasi Signed-off-by: Chris Redpath Signed-off-by: Quentin Perret --- kernel/sched/fair.c | 151 ++++---------------------------------------- kernel/sched/tune.c | 2 +- 2 files changed, 13 insertions(+), 140 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index bf40575bf48f..4bc5508b8fa2 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5438,19 +5438,7 @@ struct energy_env { int dst_cpu; int trg_cpu; int energy; - int payoff; struct task_struct *p; - struct { - int before; - int after; - int delta; - int diff; - } nrg; - struct { - int before; - int after; - int delta; - } cap; }; static int cpu_util_wake(int cpu, struct task_struct *p); @@ -5669,22 +5657,6 @@ static int sched_group_energy(struct energy_env *eenv) eenv->sg_cap = sg; cap_idx = find_new_capacity(eenv, sg->sge); - - if (sg->group_weight == 1) { - /* Remove capacity of src CPU (before task move) */ - if (eenv->trg_cpu == eenv->src_cpu && - cpumask_test_cpu(eenv->src_cpu, sched_group_cpus(sg))) { - eenv->cap.before = sg->sge->cap_states[cap_idx].cap; - eenv->cap.delta -= eenv->cap.before; - } - /* Add capacity of dst CPU (after task move) */ - if (eenv->trg_cpu == eenv->dst_cpu && - cpumask_test_cpu(eenv->dst_cpu, sched_group_cpus(sg))) { - eenv->cap.after = sg->sge->cap_states[cap_idx].cap; - eenv->cap.delta += eenv->cap.after; - } - } - idle_idx = group_idle_state(eenv, sg); group_util = group_norm_util(eenv, sg); @@ -5715,7 +5687,7 @@ static int sched_group_energy(struct energy_env *eenv) continue; } - eenv->energy = total_energy >> SCHED_CAPACITY_SHIFT; + eenv->energy += (total_energy >> SCHED_CAPACITY_SHIFT); return 0; } @@ -5733,21 +5705,21 @@ static inline unsigned long task_util(struct task_struct *p); * utilization is removed from or added to the system (e.g. task wake-up). If * both are specified, the utilization is migrated. */ -static inline int __energy_diff(struct energy_env *eenv) +static inline int energy_diff(struct energy_env *eenv) { struct sched_domain *sd; struct sched_group *sg; - int sd_cpu = -1, energy_before = 0, energy_after = 0; - int diff, margin; + int energy_diff = 0; + int sd_cpu = -1; + int margin; struct energy_env eenv_before = { .util_delta = task_util(eenv->p), .src_cpu = eenv->src_cpu, .dst_cpu = eenv->dst_cpu, .trg_cpu = eenv->src_cpu, - .nrg = { 0, 0, 0, 0}, - .cap = { 0, 0, 0 }, - .p = eenv->p, + .energy = 0, + .p = eenv->p, }; if (eenv->src_cpu == eenv->dst_cpu) @@ -5764,122 +5736,23 @@ static inline int __energy_diff(struct energy_env *eenv) do { if (cpu_in_sg(sg, eenv->src_cpu) || cpu_in_sg(sg, eenv->dst_cpu)) { eenv_before.sg_top = eenv->sg_top = sg; - if (sched_group_energy(&eenv_before)) return 0; /* Invalid result abort */ - energy_before += eenv_before.energy; - - /* Keep track of SRC cpu (before) capacity */ - eenv->cap.before = eenv_before.cap.before; - eenv->cap.delta = eenv_before.cap.delta; - if (sched_group_energy(eenv)) return 0; /* Invalid result abort */ - energy_after += eenv->energy; } } while (sg = sg->next, sg != sd->groups); - - eenv->nrg.before = energy_before; - eenv->nrg.after = energy_after; - eenv->nrg.diff = eenv->nrg.after - eenv->nrg.before; - eenv->payoff = 0; + energy_diff = eenv->energy - eenv_before.energy; /* * Dead-zone margin preventing too many migrations. */ + margin = eenv->energy >> 6; /* ~1.56% */ + if (abs(energy_diff) < margin) + energy_diff = 0; - margin = eenv->nrg.before >> 6; /* ~1.56% */ - - diff = eenv->nrg.after - eenv->nrg.before; - - eenv->nrg.diff = (abs(diff) < margin) ? 0 : eenv->nrg.diff; - - return eenv->nrg.diff; -} - -#ifdef CONFIG_SCHED_TUNE - -struct target_nrg schedtune_target_nrg; -extern bool schedtune_initialized; -/* - * System energy normalization - * Returns the normalized value, in the range [0..SCHED_CAPACITY_SCALE], - * corresponding to the specified energy variation. - */ -static inline int -normalize_energy(int energy_diff) -{ - u32 normalized_nrg; - - /* during early setup, we don't know the extents */ - if (unlikely(!schedtune_initialized)) - return energy_diff < 0 ? -1 : 1 ; - -#ifdef CONFIG_SCHED_DEBUG - { - int max_delta; - - /* Check for boundaries */ - max_delta = schedtune_target_nrg.max_power; - max_delta -= schedtune_target_nrg.min_power; - WARN_ON(abs(energy_diff) >= max_delta); - } -#endif - - /* Do scaling using positive numbers to increase the range */ - normalized_nrg = (energy_diff < 0) ? -energy_diff : energy_diff; - - /* Scale by energy magnitude */ - normalized_nrg <<= SCHED_CAPACITY_SHIFT; - - /* Normalize on max energy for target platform */ - normalized_nrg = reciprocal_divide( - normalized_nrg, schedtune_target_nrg.rdiv); - - return (energy_diff < 0) ? -normalized_nrg : normalized_nrg; -} - -static inline int -energy_diff(struct energy_env *eenv) -{ - int boost = schedtune_task_boost(eenv->p); - int nrg_delta; - - /* Conpute "absolute" energy diff */ - __energy_diff(eenv); - - /* Return energy diff when boost margin is 0 */ - if (boost == 0) { - trace_sched_energy_diff(eenv->p, - eenv->src_cpu, eenv->dst_cpu, eenv->util_delta, - eenv->nrg.before, eenv->nrg.after, eenv->nrg.diff, - eenv->cap.before, eenv->cap.after, eenv->cap.delta, - 0, -eenv->nrg.diff); - return eenv->nrg.diff; - } - - /* Compute normalized energy diff */ - nrg_delta = normalize_energy(eenv->nrg.diff); - eenv->nrg.delta = nrg_delta; - - eenv->payoff = schedtune_accept_deltas( - eenv->nrg.delta, - eenv->cap.delta, - eenv->p); - - /* - * When SchedTune is enabled, the energy_diff() function will return - * the computed energy payoff value. Since the energy_diff() return - * value is expected to be negative by its callers, this evaluation - * function return a negative value each time the evaluation return a - * positive payoff, which is the condition for the acceptance of - * a scheduling decision - */ - return -eenv->payoff; + return energy_diff; } -#else /* CONFIG_SCHED_TUNE */ -#define energy_diff(eenv) __energy_diff(eenv) -#endif /* * Detect M:N waker/wakee relationships via a switching-frequency heuristic. diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 654934fc5e47..9be1bb0d69b1 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -18,7 +18,7 @@ bool schedtune_initialized = false; unsigned int sysctl_sched_cfs_boost __read_mostly; extern struct reciprocal_value schedtune_spc_rdiv; -extern struct target_nrg schedtune_target_nrg; +struct target_nrg schedtune_target_nrg; /* Performance Boost region (B) threshold params */ static int perf_boost_idx; -- GitLab From 142ce32a63953adcf12fc70e85c9738352520852 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Tue, 12 Sep 2017 15:01:17 +0100 Subject: [PATCH 0005/1834] sched/fair: cleanup select_energy_cpu_brute to be more consistent The current definition of select_energy_cpu_brute is a bit confusing in the definition of the value for the target_cpu to be returned as wakeup CPU for the specified task. This cleanup the code by ensuring that we always set target_cpu right before returning it. rcu_read_lock and check on *sd!=NULL are also moved around to be exactly where they are required. Change-Id: I70a4b558b3624a13395da1a87ddc0776fd1d6641 Signed-off-by: Patrick Bellasi Signed-off-by: Chris Redpath Signed-off-by: Quentin Perret --- kernel/sched/fair.c | 54 +++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 4bc5508b8fa2..a25e13accaf1 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6854,9 +6854,11 @@ static int wake_cap(struct task_struct *p, int cpu, int prev_cpu) static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync) { - struct sched_domain *sd; - int target_cpu = prev_cpu, tmp_target, tmp_backup; bool boosted, prefer_idle; + struct sched_domain *sd; + int target_cpu; + int backup_cpu; + int next_cpu; schedstat_inc(p->se.statistics.nr_wakeups_secb_attempts); schedstat_inc(this_rq()->eas_stats.secb_attempts); @@ -6871,7 +6873,6 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync } } - rcu_read_lock(); #ifdef CONFIG_CGROUP_SCHEDTUNE boosted = schedtune_task_boost(p) > 0; prefer_idle = schedtune_prefer_idle(p) > 0; @@ -6880,31 +6881,40 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync prefer_idle = 0; #endif - sync_entity_load_avg(&p->se); + rcu_read_lock(); sd = rcu_dereference(per_cpu(sd_ea, prev_cpu)); + if (!sd) { + target_cpu = prev_cpu; + goto unlock; + } + + sync_entity_load_avg(&p->se); + /* Find a cpu with sufficient capacity */ - tmp_target = find_best_target(p, &tmp_backup, boosted, prefer_idle); + next_cpu = find_best_target(p, &backup_cpu, boosted, prefer_idle); + if (next_cpu == -1) { + target_cpu = prev_cpu; + goto unlock; + } - if (!sd) + /* Unconditionally prefer IDLE CPUs for boosted/prefer_idle tasks */ + if ((boosted || prefer_idle) && idle_cpu(next_cpu)) { + schedstat_inc(p->se.statistics.nr_wakeups_secb_idle_bt); + schedstat_inc(this_rq()->eas_stats.secb_idle_bt); + target_cpu = next_cpu; goto unlock; - if (tmp_target >= 0) { - target_cpu = tmp_target; - if ((boosted || prefer_idle) && idle_cpu(target_cpu)) { - schedstat_inc(p->se.statistics.nr_wakeups_secb_idle_bt); - schedstat_inc(this_rq()->eas_stats.secb_idle_bt); - goto unlock; - } } - if (target_cpu != prev_cpu) { + target_cpu = prev_cpu; + if (next_cpu != prev_cpu) { int delta = 0; struct energy_env eenv = { .util_delta = task_util(p), .src_cpu = prev_cpu, - .dst_cpu = target_cpu, + .dst_cpu = next_cpu, + .trg_cpu = next_cpu, .p = p, - .trg_cpu = target_cpu, }; @@ -6917,16 +6927,18 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync if (__cpu_overutilized(prev_cpu, delta)) { schedstat_inc(p->se.statistics.nr_wakeups_secb_insuff_cap); schedstat_inc(this_rq()->eas_stats.secb_insuff_cap); + target_cpu = next_cpu; goto unlock; } + target_cpu = next_cpu; if (energy_diff(&eenv) >= 0) { /* No energy saving for target_cpu, try backup */ - target_cpu = tmp_backup; - eenv.dst_cpu = target_cpu; - eenv.trg_cpu = target_cpu; - if (tmp_backup < 0 || - tmp_backup == prev_cpu || + target_cpu = backup_cpu; + eenv.dst_cpu = backup_cpu; + eenv.trg_cpu = backup_cpu; + if (backup_cpu < 0 || + backup_cpu == prev_cpu || energy_diff(&eenv) >= 0) { schedstat_inc(p->se.statistics.nr_wakeups_secb_no_nrg_sav); schedstat_inc(this_rq()->eas_stats.secb_no_nrg_sav); -- GitLab From cf28cf03a33ee33180628aa93fc85a940240f893 Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Wed, 5 Jul 2017 10:59:59 +0100 Subject: [PATCH 0006/1834] sched/fair: re-factor energy_diff to use a single (extensible) energy_env The energy_env data structure is used to cache values required by multiple different functions involved in energy_diff computation. Some of these functions require additional parameters which can be easily embedded into the energy_env itself. The current implementation of energy_diff hardcodes the usage of two different energy_env structures to estimate and compare the energy consumption related to a "before" and an "after" CPU. Moreover, it does this energy estimation by walking multiple times the SDs/SGs data structures. A better design can be envisioned by better using the energy_env structure to support a more efficient and concurrent evaluation of multiple schedule candidates. To this purpose, this patch provides a complete re-factoring of the energy_diff implementation to: 1. use a single energy_env structure for the evaluation of all the candidate CPUs 2. walk just one time the SDs/SGs, thus improving the overall performance to compute the energy estimation for each CPU candidate specified by the single used energy_env 3. simplify the code (at least if you look at the new version and not at this re-factoring patch) thus providing a more clean code to maintain and extend for additional features This patch updated all the clients of energy_env to use only the data provided by this structure and an index for one of its CPUs candidates. Embedding everything within the energy env will make it simple to add tracepoints for this new version, which can easily provide an holistic view on how energy_diff evaluated the proposed CPU candidates. The new proposed structure, for both "struct energy_env" and the functions using it, is designed in such a way to easily accommodate additional further extensions (e.g. SchedTune filtering) without requiring an additional big re-factoring of these core functions. Finally, the usage of a CPUs candidate array, embedded into the energy_diff structure, allows also to seamless extend the exploration of multiple candidate CPUs, for example to support the comparison of a spread-vs-packing strategy. Change-Id: Ic04ffb6848b2c763cf1788767f22c6872eb12bee Signed-off-by: Patrick Bellasi Signed-off-by: Chris Redpath [reworked find_new_capacity() and enforced the respect of find_best_target() selection order] Signed-off-by: Quentin Perret --- kernel/sched/fair.c | 340 ++++++++++++++++++++++++++++++-------------- 1 file changed, 232 insertions(+), 108 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index a25e13accaf1..315078c28816 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5429,16 +5429,66 @@ static inline bool energy_aware(void) return sched_feat(ENERGY_AWARE); } +/* + * CPU candidates. + * + * These are labels to reference CPU candidates for an energy_diff. + * Currently we support only two possible candidates: the task's previous CPU + * and another candiate CPU. + * More advanced/aggressive EAS selection policies can consider more + * candidates. + */ +#define EAS_CPU_PRV 0 +#define EAS_CPU_NXT 1 +#define EAS_CPU_BKP 2 +#define EAS_CPU_CNT 3 + +/* + * energy_diff - supports the computation of the estimated energy impact in + * moving a "task"'s "util_delta" between different CPU candidates. + */ struct energy_env { + /* Utilization to move */ + struct task_struct *p; + int util_delta; + + /* Mask of CPUs candidates to evaluate */ + cpumask_t cpus_mask; + + /* CPU candidates to evaluate */ + struct { + + /* CPU ID, must be in cpus_mask */ + int cpu_id; + + /* + * Index (into sched_group_energy::cap_states) of the OPP the + * CPU needs to run at if the task is placed on it. + * This includes the both active and blocked load, due to + * other tasks on this CPU, as well as the task's own + * utilization. + */ + int cap_idx; + int cap; + + /* Estimated system energy */ + unsigned int energy; + + /* Estimated energy variation wrt EAS_CPU_PRV */ + int nrg_delta; + + } cpu[EAS_CPU_CNT]; + + /* + * Index (into energy_env::cpu) of the morst energy efficient CPU for + * the specified energy_env::task + */ + int next_idx; + + /* Support data */ struct sched_group *sg_top; struct sched_group *sg_cap; - int cap_idx; - int util_delta; - int src_cpu; - int dst_cpu; - int trg_cpu; - int energy; - struct task_struct *p; + struct sched_group *sg; }; static int cpu_util_wake(int cpu, struct task_struct *p); @@ -5466,7 +5516,7 @@ static unsigned long __cpu_norm_util(unsigned long util, unsigned long capacity) return (util << SCHED_CAPACITY_SHIFT)/capacity; } -static unsigned long group_max_util(struct energy_env *eenv) +static unsigned long group_max_util(struct energy_env *eenv, int cpu_idx) { unsigned long max_util = 0; unsigned long util; @@ -5480,7 +5530,7 @@ static unsigned long group_max_util(struct energy_env *eenv) * then we should add the (estimated) utilization of the task * assuming we will wake it up on that CPU. */ - if (unlikely(cpu == eenv->trg_cpu)) + if (unlikely(cpu == eenv->cpu[cpu_idx].cpu_id)) util += eenv->util_delta; max_util = max(max_util, util); @@ -5501,13 +5551,13 @@ static unsigned long group_max_util(struct energy_env *eenv) * estimate (more busy). */ static unsigned -long group_norm_util(struct energy_env *eenv, struct sched_group *sg) +long group_norm_util(struct energy_env *eenv, int cpu_idx) { - unsigned long capacity = sg->sge->cap_states[eenv->cap_idx].cap; + unsigned long capacity = eenv->cpu[cpu_idx].cap; unsigned long util, util_sum = 0; int cpu; - for_each_cpu(cpu, sched_group_cpus(sg)) { + for_each_cpu(cpu, sched_group_cpus(eenv->sg)) { util = cpu_util_wake(cpu, eenv->p); /* @@ -5515,7 +5565,7 @@ long group_norm_util(struct energy_env *eenv, struct sched_group *sg) * then we should add the (estimated) utilization of the task * assuming we will wake it up on that CPU. */ - if (unlikely(cpu == eenv->trg_cpu)) + if (unlikely(cpu == eenv->cpu[cpu_idx].cpu_id)) util += eenv->util_delta; util_sum += __cpu_norm_util(util, capacity); @@ -5524,27 +5574,31 @@ long group_norm_util(struct energy_env *eenv, struct sched_group *sg) return min_t(unsigned long, util_sum, SCHED_CAPACITY_SCALE); } -static int find_new_capacity(struct energy_env *eenv, - const struct sched_group_energy * const sge) +static int find_new_capacity(struct energy_env *eenv, int cpu_idx) { + const struct sched_group_energy *sge = eenv->sg->sge; int idx, max_idx = sge->nr_cap_states - 1; - unsigned long util = group_max_util(eenv); + unsigned long util = group_max_util(eenv, cpu_idx); /* default is max_cap if we don't find a match */ - eenv->cap_idx = max_idx; + eenv->cpu[cpu_idx].cap_idx = max_idx; + eenv->cpu[cpu_idx].cap = sge->cap_states[max_idx].cap; for (idx = 0; idx < sge->nr_cap_states; idx++) { if (sge->cap_states[idx].cap >= util) { - eenv->cap_idx = idx; + /* Keep track of SG's capacity */ + eenv->cpu[cpu_idx].cap_idx = idx; + eenv->cpu[cpu_idx].cap = sge->cap_states[idx].cap; break; } } - return eenv->cap_idx; + return eenv->cpu[cpu_idx].cap_idx; } -static int group_idle_state(struct energy_env *eenv, struct sched_group *sg) +static int group_idle_state(struct energy_env *eenv, int cpu_idx) { + struct sched_group *sg = eenv->sg; int i, state = INT_MAX; int src_in_grp, dst_in_grp; long grp_util = 0; @@ -5556,8 +5610,10 @@ static int group_idle_state(struct energy_env *eenv, struct sched_group *sg) /* Take non-cpuidle idling into account (active idle/arch_cpu_idle()) */ state++; - src_in_grp = cpumask_test_cpu(eenv->src_cpu, sched_group_cpus(sg)); - dst_in_grp = cpumask_test_cpu(eenv->dst_cpu, sched_group_cpus(sg)); + src_in_grp = cpumask_test_cpu(eenv->cpu[EAS_CPU_PRV].cpu_id, + sched_group_cpus(sg)); + dst_in_grp = cpumask_test_cpu(eenv->cpu[cpu_idx].cpu_id, + sched_group_cpus(sg)); if (src_in_grp == dst_in_grp) { /* both CPUs under consideration are in the same group or not in * either group, migration should leave idle state the same. @@ -5571,7 +5627,7 @@ static int group_idle_state(struct energy_env *eenv, struct sched_group *sg) */ for_each_cpu(i, sched_group_cpus(sg)) { grp_util += cpu_util_wake(i, eenv->p); - if (unlikely(i == eenv->trg_cpu)) + if (unlikely(i == eenv->cpu[cpu_idx].cpu_id)) grp_util += eenv->util_delta; } @@ -5607,19 +5663,62 @@ static int group_idle_state(struct energy_env *eenv, struct sched_group *sg) } /* - * sched_group_energy(): Computes the absolute energy consumption of cpus - * belonging to the sched_group including shared resources shared only by - * members of the group. Iterates over all cpus in the hierarchy below the - * sched_group starting from the bottom working it's way up before going to - * the next cpu until all cpus are covered at all levels. The current - * implementation is likely to gather the same util statistics multiple times. - * This can probably be done in a faster but more complex way. - * Note: sched_group_energy() may fail when racing with sched_domain updates. + * calc_sg_energy: compute energy for the eenv's SG (i.e. eenv->sg). + * + * This works in iterations to compute the SG's energy for each CPU + * candidate defined by the energy_env's cpu array. + */ +static void calc_sg_energy(struct energy_env *eenv) +{ + struct sched_group *sg = eenv->sg; + int busy_energy, idle_energy; + unsigned int busy_power; + unsigned int idle_power; + unsigned long sg_util; + int cap_idx, idle_idx; + int total_energy = 0; + int cpu_idx; + + for (cpu_idx = EAS_CPU_PRV; cpu_idx < EAS_CPU_CNT; ++cpu_idx) { + + + if (eenv->cpu[cpu_idx].cpu_id == -1) + continue; + /* Compute ACTIVE energy */ + cap_idx = find_new_capacity(eenv, cpu_idx); + busy_power = sg->sge->cap_states[cap_idx].power; + /* + * in order to calculate cpu_norm_util, we need to know which + * capacity level the group will be at, so calculate that first + */ + sg_util = group_norm_util(eenv, cpu_idx); + + busy_energy = sg_util * busy_power; + busy_energy >>= SCHED_CAPACITY_SHIFT; + + /* Compute IDLE energy */ + idle_idx = group_idle_state(eenv, cpu_idx); + idle_power = sg->sge->idle_states[idle_idx].power; + + idle_energy = SCHED_CAPACITY_SCALE - sg_util; + idle_energy *= idle_power; + idle_energy >>= SCHED_CAPACITY_SHIFT; + + total_energy = busy_energy + idle_energy; + eenv->cpu[cpu_idx].energy += total_energy; + } +} + +/* + * compute_energy() computes the absolute variation in energy consumption by + * moving eenv.util_delta from EAS_CPU_PRV to EAS_CPU_NXT. + * + * NOTE: compute_energy() may fail when racing with sched_domain updates, in + * which case we abort by returning -EINVAL. */ -static int sched_group_energy(struct energy_env *eenv) +static int compute_energy(struct energy_env *eenv) { struct cpumask visit_cpus; - u64 total_energy = 0; WARN_ON(!eenv->sg_top->sge); @@ -5635,7 +5734,6 @@ static int sched_group_energy(struct energy_env *eenv) * sched_group? */ sd = rcu_dereference(per_cpu(sd_scs, cpu)); - if (sd && sd->parent) sg_shared_cap = sd->parent->groups; @@ -5647,25 +5745,18 @@ static int sched_group_energy(struct energy_env *eenv) break; do { - unsigned long group_util; - int sg_busy_energy, sg_idle_energy; - int cap_idx, idle_idx; - + eenv->sg_cap = sg; if (sg_shared_cap && sg_shared_cap->group_weight >= sg->group_weight) eenv->sg_cap = sg_shared_cap; - else - eenv->sg_cap = sg; - - cap_idx = find_new_capacity(eenv, sg->sge); - idle_idx = group_idle_state(eenv, sg); - group_util = group_norm_util(eenv, sg); - - sg_busy_energy = (group_util * sg->sge->cap_states[cap_idx].power); - sg_idle_energy = ((SCHED_CAPACITY_SCALE-group_util) - * sg->sge->idle_states[idle_idx].power); - total_energy += sg_busy_energy + sg_idle_energy; + /* + * Compute the energy for all the candidate + * CPUs in the current visited SG. + */ + eenv->sg = sg; + calc_sg_energy(eenv); + /* remove CPUs we have just visited */ if (!sd->child) cpumask_xor(&visit_cpus, &visit_cpus, sched_group_cpus(sg)); @@ -5687,7 +5778,6 @@ static int sched_group_energy(struct energy_env *eenv) continue; } - eenv->energy += (total_energy >> SCHED_CAPACITY_SHIFT); return 0; } @@ -5696,62 +5786,94 @@ static inline bool cpu_in_sg(struct sched_group *sg, int cpu) return cpu != -1 && cpumask_test_cpu(cpu, sched_group_cpus(sg)); } -static inline unsigned long task_util(struct task_struct *p); - /* - * energy_diff(): Estimate the energy impact of changing the utilization - * distribution. eenv specifies the change: utilisation amount, source, and - * destination cpu. Source or destination cpu may be -1 in which case the - * utilization is removed from or added to the system (e.g. task wake-up). If - * both are specified, the utilization is migrated. + * select_energy_cpu_idx(): estimate the energy impact of changing the + * utilization distribution. + * + * The eenv parameter specifies the changes: utilisation amount and a pair of + * possible CPU candidates (the previous CPU and a different target CPU). + * + * This function returns the index of a CPU candidate specified by the + * energy_env which corresponds to the first CPU saving energy. + * Thus, 0 (EAS_CPU_PRV) means that non of the CPU candidate is more energy + * efficient than running on prev_cpu. This is also the value returned in case + * of abort due to error conditions during the computations. + * A value greater than zero means that the first energy-efficient CPU is the + * one represented by eenv->cpu[eenv->next_idx].cpu_id. */ -static inline int energy_diff(struct energy_env *eenv) +static inline int select_energy_cpu_idx(struct energy_env *eenv) { struct sched_domain *sd; struct sched_group *sg; - int energy_diff = 0; int sd_cpu = -1; + int cpu_idx; int margin; - struct energy_env eenv_before = { - .util_delta = task_util(eenv->p), - .src_cpu = eenv->src_cpu, - .dst_cpu = eenv->dst_cpu, - .trg_cpu = eenv->src_cpu, - .energy = 0, - .p = eenv->p, - }; - - if (eenv->src_cpu == eenv->dst_cpu) - return 0; - - sd_cpu = (eenv->src_cpu != -1) ? eenv->src_cpu : eenv->dst_cpu; + sd_cpu = eenv->cpu[EAS_CPU_PRV].cpu_id; sd = rcu_dereference(per_cpu(sd_ea, sd_cpu)); - if (!sd) - return 0; /* Error */ + return EAS_CPU_PRV; - sg = sd->groups; + cpumask_clear(&eenv->cpus_mask); + for (cpu_idx = EAS_CPU_PRV; cpu_idx < EAS_CPU_CNT; ++cpu_idx) { + int cpu = eenv->cpu[cpu_idx].cpu_id; + if (cpu < 0) + continue; + cpumask_set_cpu(cpu, &eenv->cpus_mask); + } + + sg = sd->groups; do { - if (cpu_in_sg(sg, eenv->src_cpu) || cpu_in_sg(sg, eenv->dst_cpu)) { - eenv_before.sg_top = eenv->sg_top = sg; - if (sched_group_energy(&eenv_before)) - return 0; /* Invalid result abort */ - if (sched_group_energy(eenv)) - return 0; /* Invalid result abort */ - } + /* Skip SGs which do not contains a candidate CPU */ + if (!cpumask_intersects(&eenv->cpus_mask, sched_group_cpus(sg))) + continue; + + eenv->sg_top = sg; + if (compute_energy(eenv) == -EINVAL) + return EAS_CPU_PRV; + } while (sg = sg->next, sg != sd->groups); - energy_diff = eenv->energy - eenv_before.energy; /* - * Dead-zone margin preventing too many migrations. + * Compute the dead-zone margin used to prevent too many task + * migrations with negligible energy savings. + * An energy saving is considered meaningful if it reduces the energy + * consumption of EAS_CPU_PRV CPU candidate by at least ~1.56% + */ + margin = eenv->cpu[EAS_CPU_PRV].energy >> 6; + + /* + * By default the EAS_CPU_PRV CPU is considered the most energy + * efficient, with a 0 energy variation. + */ + eenv->next_idx = EAS_CPU_PRV; + eenv->cpu[cpu_idx].nrg_delta = 0; + + /* + * Compare the other CPU candidates to find a CPU which can be + * more energy efficient then EAS_CPU_PRV */ - margin = eenv->energy >> 6; /* ~1.56% */ - if (abs(energy_diff) < margin) - energy_diff = 0; + for (cpu_idx = EAS_CPU_NXT; cpu_idx < EAS_CPU_CNT; ++cpu_idx) { + /* Skip not valid scheduled candidates */ + if (eenv->cpu[cpu_idx].cpu_id < 0) + continue; + /* Compute energy delta wrt EAS_CPU_PRV */ + eenv->cpu[cpu_idx].nrg_delta = + eenv->cpu[cpu_idx].energy - + eenv->cpu[EAS_CPU_PRV].energy; + /* filter energy variations within the dead-zone margin */ + if (abs(eenv->cpu[cpu_idx].nrg_delta) < margin) + eenv->cpu[cpu_idx].nrg_delta = 0; + /* update the schedule candidate with min(nrg_delta) */ + if (eenv->cpu[cpu_idx].nrg_delta < + eenv->cpu[eenv->next_idx].nrg_delta) { + eenv->next_idx = cpu_idx; + break; + } + } - return energy_diff; + return eenv->next_idx; } /* @@ -6910,11 +7032,20 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync if (next_cpu != prev_cpu) { int delta = 0; struct energy_env eenv = { - .util_delta = task_util(p), - .src_cpu = prev_cpu, - .dst_cpu = next_cpu, - .trg_cpu = next_cpu, .p = p, + .util_delta = task_util(p), + /* Task's previous CPU candidate */ + .cpu[EAS_CPU_PRV] = { + .cpu_id = prev_cpu, + }, + /* Main alternative CPU candidate */ + .cpu[EAS_CPU_NXT] = { + .cpu_id = next_cpu, + }, + /* Backup alternative CPU candidate */ + .cpu[EAS_CPU_BKP] = { + .cpu_id = backup_cpu, + }, }; @@ -6931,24 +7062,17 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync goto unlock; } - target_cpu = next_cpu; - if (energy_diff(&eenv) >= 0) { - /* No energy saving for target_cpu, try backup */ - target_cpu = backup_cpu; - eenv.dst_cpu = backup_cpu; - eenv.trg_cpu = backup_cpu; - if (backup_cpu < 0 || - backup_cpu == prev_cpu || - energy_diff(&eenv) >= 0) { - schedstat_inc(p->se.statistics.nr_wakeups_secb_no_nrg_sav); - schedstat_inc(this_rq()->eas_stats.secb_no_nrg_sav); - target_cpu = prev_cpu; - goto unlock; - } + /* Check if EAS_CPU_NXT is a more energy efficient CPU */ + if (select_energy_cpu_idx(&eenv) != EAS_CPU_PRV) { + schedstat_inc(p->se.statistics.nr_wakeups_secb_nrg_sav); + schedstat_inc(this_rq()->eas_stats.secb_nrg_sav); + target_cpu = eenv.cpu[eenv.next_idx].cpu_id; + goto unlock; } - schedstat_inc(p->se.statistics.nr_wakeups_secb_nrg_sav); - schedstat_inc(this_rq()->eas_stats.secb_nrg_sav); + schedstat_inc(p->se.statistics.nr_wakeups_secb_no_nrg_sav); + schedstat_inc(this_rq()->eas_stats.secb_no_nrg_sav); + target_cpu = prev_cpu; goto unlock; } -- GitLab From 3b9305de3216df79966c31c3735f23d04b0a79ac Mon Sep 17 00:00:00 2001 From: Patrick Bellasi Date: Mon, 31 Jul 2017 11:21:37 +0100 Subject: [PATCH 0007/1834] sched/fair: reduce rounding errors in energy computations The SG's energy is obtained by adding busy and idle contributions which are computed by considering a proper fraction of the SCHED_CAPACITY_SCALE defined by the SG's utilizations. By scaling each and every contribution conputed we risk to accumulate rounding errors which can results into a non null energy_delta also in cases when the same total accomulated utilization is differently distributed among different CPUs. To reduce rouding errors, this patch accumulated non-scaled busy/idle energy contributions for each visited SG, and scale each of them just one time at the end. Change-Id: Idf8367fee0ac11938c6436096f0c1b2d630210d2 Suggested-by: Joonwoo Park Signed-off-by: Patrick Bellasi Signed-off-by: Chris Redpath Signed-off-by: Quentin Perret --- kernel/sched/fair.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 315078c28816..15c48524c70a 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5667,6 +5667,11 @@ static int group_idle_state(struct energy_env *eenv, int cpu_idx) * * This works in iterations to compute the SG's energy for each CPU * candidate defined by the energy_env's cpu array. + * + * NOTE: in the following computations for busy_energy and idle_energy we do + * not shift by SCHED_CAPACITY_SHIFT in order to reduce rounding errors. + * The required scaling will be performed just one time, by the calling + * functions, once we accumulated the contributons for all the SGs. */ static void calc_sg_energy(struct energy_env *eenv) { @@ -5694,7 +5699,6 @@ static void calc_sg_energy(struct energy_env *eenv) sg_util = group_norm_util(eenv, cpu_idx); busy_energy = sg_util * busy_power; - busy_energy >>= SCHED_CAPACITY_SHIFT; /* Compute IDLE energy */ idle_idx = group_idle_state(eenv, cpu_idx); @@ -5702,7 +5706,6 @@ static void calc_sg_energy(struct energy_env *eenv) idle_energy = SCHED_CAPACITY_SCALE - sg_util; idle_energy *= idle_power; - idle_energy >>= SCHED_CAPACITY_SHIFT; total_energy = busy_energy + idle_energy; eenv->cpu[cpu_idx].energy += total_energy; @@ -5830,11 +5833,16 @@ static inline int select_energy_cpu_idx(struct energy_env *eenv) continue; eenv->sg_top = sg; + /* energy is unscaled to reduce rounding errors */ if (compute_energy(eenv) == -EINVAL) return EAS_CPU_PRV; } while (sg = sg->next, sg != sd->groups); + /* Scale energy before comparisons */ + for (cpu_idx = EAS_CPU_PRV; cpu_idx < EAS_CPU_CNT; ++cpu_idx) + eenv->cpu[cpu_idx].energy >>= SCHED_CAPACITY_SHIFT; + /* * Compute the dead-zone margin used to prevent too many task * migrations with negligible energy savings. -- GitLab From 3f27035eb833695cd3642d0ff393aefe9a6e1061 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Thu, 1 Feb 2018 15:39:17 +0000 Subject: [PATCH 0008/1834] Revert "ANDROID: arm64: Enable max freq invariant scheduler load-tracking and capacity support" This reverts commit 8f4855421f616a186fa6bbfccaaf8a1056fa9df1. Change-Id: Icddb9545030e81b2a8861e3acb44192a890c8e0f Signed-off-by: Quentin Perret --- arch/arm64/include/asm/topology.h | 1 - arch/arm64/kernel/topology.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 7ec84d0191c8..237eaa0d5cf7 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -35,7 +35,6 @@ struct sched_domain; #ifdef CONFIG_CPU_FREQ #define arch_scale_freq_capacity cpufreq_scale_freq_capacity extern unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu); -extern unsigned long cpufreq_scale_max_freq_capacity(int cpu); #endif #define arch_scale_cpu_capacity scale_cpu_capacity extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu); diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index 7758f7ff131b..ed734264a516 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -29,13 +29,7 @@ static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE; unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu) { -#ifdef CONFIG_CPU_FREQ - unsigned long max_freq_scale = cpufreq_scale_max_freq_capacity(cpu); - - return per_cpu(cpu_scale, cpu) * max_freq_scale >> SCHED_CAPACITY_SHIFT; -#else return per_cpu(cpu_scale, cpu); -#endif } static void set_capacity_scale(unsigned int cpu, unsigned long capacity) -- GitLab From 03ba1e3595b0751edbe7b328590301da058693ff Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Thu, 1 Feb 2018 15:41:19 +0000 Subject: [PATCH 0009/1834] Revert "ANDROID: arm: Enable max freq invariant scheduler load-tracking and capacity support" This reverts commit 568913e203a12178620e5619606e54375fd690fa. Change-Id: I08d4eebcc1d027e42ab3571b0704ec697e74d7f0 Signed-off-by: Quentin Perret --- arch/arm/kernel/topology.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index df3020071f32..07b0812a0109 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -44,13 +44,7 @@ static DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE; unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu) { -#ifdef CONFIG_CPU_FREQ - unsigned long max_freq_scale = cpufreq_scale_max_freq_capacity(cpu); - - return per_cpu(cpu_scale, cpu) * max_freq_scale >> SCHED_CAPACITY_SHIFT; -#else return per_cpu(cpu_scale, cpu); -#endif } static void set_capacity_scale(unsigned int cpu, unsigned long capacity) -- GitLab From 85f139e71678b45f4786a0f5f6705821cbd67fd2 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Thu, 1 Feb 2018 15:42:46 +0000 Subject: [PATCH 0010/1834] Revert "ANDROID: cpufreq: Max freq invariant scheduler load-tracking and cpu capacity support" This reverts commit 4eb92977b24f39bb37b0138b2ee51a23ed36aa72. Change-Id: I54be27771b58b630c12925ce40d5651cee135b2d Signed-off-by: Quentin Perret --- drivers/cpufreq/cpufreq.c | 19 ------------------- include/linux/cpufreq.h | 1 - 2 files changed, 20 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index b3b9d97b7d1c..c09f55629dc9 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -315,14 +315,12 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) *********************************************************************/ static DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; -static DEFINE_PER_CPU(unsigned long, max_freq_scale) = SCHED_CAPACITY_SCALE; static void scale_freq_capacity(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs) { unsigned long cur = freqs ? freqs->new : policy->cur; unsigned long scale = (cur << SCHED_CAPACITY_SHIFT) / policy->max; - struct cpufreq_cpuinfo *cpuinfo = &policy->cpuinfo; int cpu; pr_debug("cpus %*pbl cur/cur max freq %lu/%u kHz freq scale %lu\n", @@ -330,18 +328,6 @@ scale_freq_capacity(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs) for_each_cpu(cpu, policy->cpus) per_cpu(freq_scale, cpu) = scale; - - if (freqs) - return; - - scale = (policy->max << SCHED_CAPACITY_SHIFT) / cpuinfo->max_freq; - - pr_debug("cpus %*pbl cur max/max freq %u/%u kHz max freq scale %lu\n", - cpumask_pr_args(policy->cpus), policy->max, cpuinfo->max_freq, - scale); - - for_each_cpu(cpu, policy->cpus) - per_cpu(max_freq_scale, cpu) = scale; } unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu) @@ -349,11 +335,6 @@ unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu) return per_cpu(freq_scale, cpu); } -unsigned long cpufreq_scale_max_freq_capacity(int cpu) -{ - return per_cpu(max_freq_scale, cpu); -} - static void __cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state) { diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 0b985998643a..822d110ec86e 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -932,5 +932,4 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, struct sched_domain; unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu); -unsigned long cpufreq_scale_max_freq_capacity(int cpu); #endif /* _LINUX_CPUFREQ_H */ -- GitLab From 19e1513f875694a63cf6b45b1841f8b30d9684f9 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Wed, 12 Jul 2017 14:09:50 +0100 Subject: [PATCH 0011/1834] cpufreq: remove max frequency capping from scale_freq_capacity() After the revert of "cpufreq: Max freq invariant scheduler load-tracking and cpu capacity support" scale_freq_capacity() is now only the setter of the Frequency Invariant Engine (FIE). That's why the call to scale_freq_capacity() in cpufreq_set_policy() can be deleted because this was driving max frequency capping. The patch changes the parameter list of scale_freq_capacity() to (1) set of cpus involved (cpumask) (2) current frequency (3) max possible frequency (cpuinfo related) to not be forced to expose cpufreq internal data structures like struct cpufreq_policy or struct cpufreq_freqs. Change-Id: I4a8d319d2d01854409f55ab058cb5a15ed9faf9a Signed-off-by: Dietmar Eggemann Signed-off-by: Chris Redpath --- drivers/cpufreq/cpufreq.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index c09f55629dc9..bc2000c25442 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -317,17 +317,17 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) static DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; static void -scale_freq_capacity(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs) +scale_freq_capacity(const cpumask_t *cpus, unsigned long cur_freq, + unsigned long max_freq) { - unsigned long cur = freqs ? freqs->new : policy->cur; - unsigned long scale = (cur << SCHED_CAPACITY_SHIFT) / policy->max; + unsigned long scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq; int cpu; - pr_debug("cpus %*pbl cur/cur max freq %lu/%u kHz freq scale %lu\n", - cpumask_pr_args(policy->cpus), cur, policy->max, scale); - - for_each_cpu(cpu, policy->cpus) + for_each_cpu(cpu, cpus) per_cpu(freq_scale, cpu) = scale; + + pr_debug("cpus %*pbl cur freq/max freq %lu/%lu kHz freq scale %lu\n", + cpumask_pr_args(cpus), cur_freq, max_freq, scale); } unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu) @@ -442,7 +442,7 @@ void cpufreq_freq_transition_begin(struct cpufreq_policy *policy, spin_unlock(&policy->transition_lock); - scale_freq_capacity(policy, freqs); + scale_freq_capacity(policy->cpus, freqs->new, policy->cpuinfo.max_freq); #ifdef CONFIG_SMP for_each_cpu(cpu, policy->cpus) trace_cpu_capacity(capacity_curr_of(cpu), cpu); @@ -2238,8 +2238,6 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, new_policy); - scale_freq_capacity(new_policy, NULL); - policy->min = new_policy->min; policy->max = new_policy->max; trace_cpu_frequency_limits(policy->max, policy->min, policy->cpu); -- GitLab From da6833cff7fd23296c7d3512c515149752fe5900 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Thu, 13 Jul 2017 09:48:42 +0100 Subject: [PATCH 0012/1834] sched/fair: introduce an arch scaling function for max frequency capping The max frequency scaling factor is defined as: max_freq_scale = policy_max_freq / cpuinfo_max_freq To be able to scale the cpu capacity by this factor introduce a call to the new arch scaling function arch_scale_max_freq_capacity() in update_cpu_capacity() and provide a default implementation which returns SCHED_CAPACITY_SCALE. Another subsystem (e.g. cpufreq) can overwrite this default implementation, exactly as for frequency and cpu invariance. It has to be enabled by the arch by defining arch_scale_max_freq_capacity to the actual implementation. Change-Id: I266cd1f4c1c82f54b80063c36aa5f7662599dd28 Signed-off-by: Dietmar Eggemann Signed-off-by: Chris Redpath --- kernel/sched/fair.c | 3 +++ kernel/sched/sched.h | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 15c48524c70a..34c39d6a693c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8331,6 +8331,9 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) cpu_rq(cpu)->cpu_capacity_orig = capacity; + capacity *= arch_scale_max_freq_capacity(sd, cpu); + capacity >>= SCHED_CAPACITY_SHIFT; + mcc = &cpu_rq(cpu)->rd->max_cpu_capacity; raw_spin_lock_irqsave(&mcc->lock, flags); diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 3e1a821aaa13..9400de0c8dcd 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1583,6 +1583,14 @@ unsigned long arch_scale_freq_capacity(struct sched_domain *sd, int cpu) } #endif +#ifndef arch_scale_max_freq_capacity +static __always_inline +unsigned long arch_scale_max_freq_capacity(struct sched_domain *sd, int cpu) +{ + return SCHED_CAPACITY_SCALE; +} +#endif + #ifndef arch_scale_cpu_capacity static __always_inline unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu) -- GitLab From 7b619defb7bb44a5f0ab9c68b1d902e0e7db468c Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Thu, 13 Jul 2017 12:11:11 +0100 Subject: [PATCH 0013/1834] cpufreq: implement max frequency capping Implements the Max Frequency Capping Engine (MFCE) getter function cpufreq_scale_max_freq_capacity() to provide the scheduler with a maximum frequency scaling correction factor for more accurate cpu capacity handling by being able to deal with max frequency capping. This scaling factor describes the influence of running a cpu with a current maximum frequency (policy) lower than the maximum possible frequency (cpuinfo). The factor is: policy_max_freq(cpu) << SCHED_CAPACITY_SHIFT / cpuinfo_max_freq(cpu) It also implements the MFCE setter function scale_max_freq_capacity() which is called from cpufreq_set_policy(). Change-Id: I38ef736cfa587520cf4f97012be25cbb0c5af04d Signed-off-by: Dietmar Eggemann Signed-off-by: Chris Redpath --- drivers/cpufreq/cpufreq.c | 36 +++++++++++++++++++++++++++++++++++- include/linux/cpufreq.h | 1 + 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index bc2000c25442..e3043c2a0e83 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -315,6 +315,8 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) *********************************************************************/ static DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; +static DEFINE_PER_CPU(unsigned long, max_freq_cpu); +static DEFINE_PER_CPU(unsigned long, max_freq_scale) = SCHED_CAPACITY_SCALE; static void scale_freq_capacity(const cpumask_t *cpus, unsigned long cur_freq, @@ -323,8 +325,10 @@ scale_freq_capacity(const cpumask_t *cpus, unsigned long cur_freq, unsigned long scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq; int cpu; - for_each_cpu(cpu, cpus) + for_each_cpu(cpu, cpus) { per_cpu(freq_scale, cpu) = scale; + per_cpu(max_freq_cpu, cpu) = max_freq; + } pr_debug("cpus %*pbl cur freq/max freq %lu/%lu kHz freq scale %lu\n", cpumask_pr_args(cpus), cur_freq, max_freq, scale); @@ -335,6 +339,34 @@ unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu) return per_cpu(freq_scale, cpu); } +static void +scale_max_freq_capacity(const cpumask_t *cpus, unsigned long policy_max_freq) +{ + unsigned long scale, max_freq; + int cpu = cpumask_first(cpus); + + if (cpu >= nr_cpu_ids) + return; + + max_freq = per_cpu(max_freq_cpu, cpu); + + if (!max_freq) + return; + + scale = (policy_max_freq << SCHED_CAPACITY_SHIFT) / max_freq; + + for_each_cpu(cpu, cpus) + per_cpu(max_freq_scale, cpu) = scale; + + pr_debug("cpus %*pbl policy max freq/max freq %lu/%lu kHz max freq scale %lu\n", + cpumask_pr_args(cpus), policy_max_freq, max_freq, scale); +} + +unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu) +{ + return per_cpu(max_freq_scale, cpu); +} + static void __cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state) { @@ -2238,6 +2270,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_NOTIFY, new_policy); + scale_max_freq_capacity(policy->cpus, policy->max); + policy->min = new_policy->min; policy->max = new_policy->max; trace_cpu_frequency_limits(policy->max, policy->min, policy->cpu); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 822d110ec86e..23704568c9b7 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -932,4 +932,5 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, struct sched_domain; unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu); +unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu); #endif /* _LINUX_CPUFREQ_H */ -- GitLab From 47a69f091114e82dc90163bb5dd176bd65f761ca Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Fri, 14 Jul 2017 14:37:26 +0100 Subject: [PATCH 0014/1834] arm: enable max frequency capping Defines arch_scale_max_freq_capacity() to use cpufreq implementation. Change-Id: Ibb5e3e04558477862565680e92ed265d8dee743e Signed-off-by: Dietmar Eggemann Signed-off-by: Chris Redpath --- arch/arm/include/asm/topology.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index d06064120694..775353deec4a 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -27,6 +27,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu); #ifdef CONFIG_CPU_FREQ #define arch_scale_freq_capacity cpufreq_scale_freq_capacity +#define arch_scale_max_freq_capacity cpufreq_scale_max_freq_capacity #endif #define arch_scale_cpu_capacity scale_cpu_capacity extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu); -- GitLab From bcf1c9d86fe2bc003d9aaae1c661c881ac9a92e6 Mon Sep 17 00:00:00 2001 From: Dietmar Eggemann Date: Fri, 14 Jul 2017 14:30:31 +0100 Subject: [PATCH 0015/1834] arm64: enable max frequency capping Defines arch_scale_max_freq_capacity() to use cpufreq implementation. Change-Id: I06f9ffbe521d5ba317482b09ea0df4488dab197c Signed-off-by: Dietmar Eggemann Signed-off-by: Chris Redpath --- arch/arm64/include/asm/topology.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 237eaa0d5cf7..342ff869023f 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -35,6 +35,8 @@ struct sched_domain; #ifdef CONFIG_CPU_FREQ #define arch_scale_freq_capacity cpufreq_scale_freq_capacity extern unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu); +#define arch_scale_max_freq_capacity cpufreq_scale_max_freq_capacity +extern unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu); #endif #define arch_scale_cpu_capacity scale_cpu_capacity extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu); -- GitLab From 0f96d86732ff89f317a707f9bf4fdf33fe0c02d7 Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Thu, 7 Dec 2017 19:24:41 +0000 Subject: [PATCH 0016/1834] cpufreq: add scaled minimum capacity tracking for policy changes When the minimum frequency available to a policy is modified either by userspace or by external actors setting a minimum frequency for a voltage domain to control behaviour of some connected component, we expect that the cpufreq policy will be updated to reflect this. If we wish to use this information to guide energy estimation and scheduling decisions, we need to track it. Implement cpufreq_scale_min_freq_capacity() to provide the scheduler with a minimum frequency scaling correction factor for more accurate cpu capacity information. This scaling factor describes the influence of running a cpu with a current policy minimum frequency higher than the minimum possible frequency. The factor is: current_min_freq(cpu) << SCHED_CAPACITY_SHIFT / max_freq(cpu) This factor is computed in scale_min_freq_capacity and returned, per cpu, in cpufreq_scale_min_freq_capacity. Change-Id: I66237025a7c0bce6bfd6e973ea22b8d3f6c41827 Signed-off-by: Chris Redpath Signed-off-by: Ionela Voinescu --- drivers/cpufreq/cpufreq.c | 30 ++++++++++++++++++++++++++++++ include/linux/cpufreq.h | 1 + 2 files changed, 31 insertions(+) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index e3043c2a0e83..837a281cf767 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -317,6 +317,7 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci) static DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE; static DEFINE_PER_CPU(unsigned long, max_freq_cpu); static DEFINE_PER_CPU(unsigned long, max_freq_scale) = SCHED_CAPACITY_SCALE; +static DEFINE_PER_CPU(unsigned long, min_freq_scale); static void scale_freq_capacity(const cpumask_t *cpus, unsigned long cur_freq, @@ -367,6 +368,34 @@ unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu) return per_cpu(max_freq_scale, cpu); } +static void +scale_min_freq_capacity(const cpumask_t *cpus, unsigned long policy_min_freq) +{ + unsigned long scale, max_freq; + int cpu = cpumask_first(cpus); + + if (cpu >= nr_cpu_ids) + return; + + max_freq = per_cpu(max_freq_cpu, cpu); + + if (!max_freq) + return; + + scale = (policy_min_freq << SCHED_CAPACITY_SHIFT) / max_freq; + + for_each_cpu(cpu, cpus) + per_cpu(min_freq_scale, cpu) = scale; + + pr_debug("cpus %*pbl policy min freq/max freq %lu/%lu kHz min freq scale %lu\n", + cpumask_pr_args(cpus), policy_min_freq, max_freq, scale); +} + +unsigned long cpufreq_scale_min_freq_capacity(struct sched_domain *sd, int cpu) +{ + return per_cpu(min_freq_scale, cpu); +} + static void __cpufreq_notify_transition(struct cpufreq_policy *policy, struct cpufreq_freqs *freqs, unsigned int state) { @@ -2271,6 +2300,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, CPUFREQ_NOTIFY, new_policy); scale_max_freq_capacity(policy->cpus, policy->max); + scale_min_freq_capacity(policy->cpus, policy->min); policy->min = new_policy->min; policy->max = new_policy->max; diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 23704568c9b7..61f405d70556 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -933,4 +933,5 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, struct sched_domain; unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu); unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu); +unsigned long cpufreq_scale_min_freq_capacity(struct sched_domain *sd, int cpu); #endif /* _LINUX_CPUFREQ_H */ -- GitLab From 33550efbaa81d8083f86844e55e7284cf743bea7 Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Wed, 30 Aug 2017 16:43:11 +0100 Subject: [PATCH 0017/1834] sched: add arch_scale_min_freq_capacity to track minimum capacity caps If the minimum capacity of a group is capped by userspace or internal dependencies which are not otherwise visible to the scheduler, we need a way to see these and integrate this information into the energy calculations and task placement decisions we make. Add arch_scale_min_freq_capacity to determine the lowest capacity which a specific cpu can provide under the current set of known constraints. Change-Id: Ied4a1dc0982bbf42cb5ea2f27201d4363db59705 Signed-off-by: Chris Redpath Signed-off-by: Ionela Voinescu --- kernel/sched/sched.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 9400de0c8dcd..646ff3c94e7d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1591,6 +1591,18 @@ unsigned long arch_scale_max_freq_capacity(struct sched_domain *sd, int cpu) } #endif +#ifndef arch_scale_min_freq_capacity +static __always_inline +unsigned long arch_scale_min_freq_capacity(struct sched_domain *sd, int cpu) +{ + /* + * Multiplied with any capacity value, this scale factor will return + * 0, which represents an un-capped state + */ + return 0; +} +#endif + #ifndef arch_scale_cpu_capacity static __always_inline unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu) -- GitLab From 55e95f99e7e00510b09fa384c3f1b40ea2c363b4 Mon Sep 17 00:00:00 2001 From: Chris Redpath Date: Thu, 25 May 2017 11:17:05 +0100 Subject: [PATCH 0018/1834] arm64/topology: link arch_scale_min_freq_capacity to cpufreq Cpufreq tracks minimum frequency constraints per-cpu. Link this to the generic arch_scale_min_freq_capacity which is used in the scheduler. Change-Id: I9f4f838bc7ebf929947ccc9e729e5ab24728e81c Signed-off-by: Chris Redpath Signed-off-by: Ionela Voinescu --- arch/arm64/include/asm/topology.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 342ff869023f..a4f86ded68c3 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -37,6 +37,8 @@ struct sched_domain; extern unsigned long cpufreq_scale_freq_capacity(struct sched_domain *sd, int cpu); #define arch_scale_max_freq_capacity cpufreq_scale_max_freq_capacity extern unsigned long cpufreq_scale_max_freq_capacity(struct sched_domain *sd, int cpu); +#define arch_scale_min_freq_capacity cpufreq_scale_min_freq_capacity +extern unsigned long cpufreq_scale_min_freq_capacity(struct sched_domain *sd, int cpu); #endif #define arch_scale_cpu_capacity scale_cpu_capacity extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu); -- GitLab From 4f7837d7418e559a703d7bb57139d72a3bd65dff Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Thu, 7 Dec 2017 17:58:37 +0000 Subject: [PATCH 0019/1834] arm/topology: link arch_scale_min_freq_capacity to cpufreq Cpufreq tracks minimum frequency constraints per-cpu. Link this to the generic arch_scale_min_freq_capacity which is used in the scheduler. Change-Id: I351dc1d45d8722cf1d6361ca843c6b49e9732665 Signed-off-by: Chris Redpath Signed-off-by: Ionela Voinescu --- arch/arm/include/asm/topology.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index 775353deec4a..4e9b95745217 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -28,6 +28,7 @@ const struct cpumask *cpu_coregroup_mask(int cpu); #ifdef CONFIG_CPU_FREQ #define arch_scale_freq_capacity cpufreq_scale_freq_capacity #define arch_scale_max_freq_capacity cpufreq_scale_max_freq_capacity +#define arch_scale_min_freq_capacity cpufreq_scale_min_freq_capacity #endif #define arch_scale_cpu_capacity scale_cpu_capacity extern unsigned long scale_cpu_capacity(struct sched_domain *sd, int cpu); -- GitLab From 58b761f4c089c6138195334ebd5b1c880e502551 Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Thu, 7 Dec 2017 19:43:46 +0000 Subject: [PATCH 0020/1834] sched/fair: introduce minimum capacity capping sched feature We have the ability to track minimum capacity forced onto a CPU by userspace or external actors. This is provided though a minimum frequency scale factor exposed by arch_scale_min_freq_capacity. The use of this information is enabled through the MIN_CAPACITY_CAPPING feature. If not enabled, the minimum frequency scale factor will remain 0 and it will not impact energy estimation or scheduling decisions. Change-Id: Ibc61f2bf4fddf186695b72b262e602a6e8bfde37 Signed-off-by: Ionela Voinescu Signed-off-by: Chris Redpath --- kernel/sched/fair.c | 14 ++++++++++++++ kernel/sched/features.h | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 34c39d6a693c..ae28b1cbe653 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5424,6 +5424,20 @@ unsigned long capacity_curr_of(int cpu) >> SCHED_CAPACITY_SHIFT; } +/* + * Returns the current capacity of cpu after applying both + * cpu and min freq scaling. + */ +unsigned long capacity_min_of(int cpu) +{ + if (!sched_feat(MIN_CAPACITY_CAPPING)) + return 0; + return arch_scale_cpu_capacity(NULL, cpu) * + arch_scale_min_freq_capacity(NULL, cpu) + >> SCHED_CAPACITY_SHIFT; +} + + static inline bool energy_aware(void) { return sched_feat(ENERGY_AWARE); diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 55e461055332..69f202b4c976 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -78,3 +78,11 @@ SCHED_FEAT(ENERGY_AWARE, true) #else SCHED_FEAT(ENERGY_AWARE, false) #endif + +/* + * Minimum capacity capping. Keep track of minimum capacity factor when + * minimum frequency available to a policy is modified. + * If enabled, this can be used to inform the scheduler about capacity + * restrictions. + */ +SCHED_FEAT(MIN_CAPACITY_CAPPING, false) -- GitLab From 9e1c648c711eae8945ea9e05a6e44530d406f85c Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Thu, 7 Dec 2017 19:50:45 +0000 Subject: [PATCH 0021/1834] sched/fair: use min capacity when evaluating placement energy costs Add the ability to track minimim capacity forced onto a sched_group by some external actor. group_max_util returns the highest utilisation inside a sched_group and is used when we are trying to calculate an energy cost estimate for a specific scheduling scenario. Minimum capacities imposed from elsewhere will influence this energy cost so we should reflect it here. Change-Id: Ibd537a6dbe6d67b11cc9e9be18f40fcb2c0f13de Signed-off-by: Ionela Voinescu Signed-off-by: Chris Redpath --- kernel/sched/fair.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index ae28b1cbe653..8007d2d202d9 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5548,6 +5548,15 @@ static unsigned long group_max_util(struct energy_env *eenv, int cpu_idx) util += eenv->util_delta; max_util = max(max_util, util); + + /* + * Take into account any minimum frequency imposed + * elsewhere which limits the energy states available + * If the MIN_CAPACITY_CAPPING feature is not enabled + * capacity_min_of will return 0 (not capped). + */ + max_util = max(max_util, capacity_min_of(cpu)); + } return max_util; -- GitLab From 88a968ca63f84ecd0747bba67ccab878684bb0a1 Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Thu, 7 Dec 2017 20:09:11 +0000 Subject: [PATCH 0022/1834] sched/fair: use min capacity when evaluating idle backup cpus When we are calculating what the impact of placing a task on a specific cpu is, we should include the information that there might be a minimum capacity imposed upon that cpu which could change the performance and/or energy cost decisions. When choosing an idle backup CPU, favour CPUs that won't end up running at a high OPP due to a min capacity cap imposed by external actors. Change-Id: I566623ffb3a7c5b61a23242dcce1cb4147ef8a4a Signed-off-by: Ionela Voinescu Signed-off-by: Chris Redpath --- kernel/sched/fair.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 8007d2d202d9..b7d603d92e03 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6711,6 +6711,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, unsigned long target_max_spare_cap = 0; unsigned long target_util = ULONG_MAX; unsigned long best_active_util = ULONG_MAX; + unsigned long target_idle_max_spare_cap = 0; int best_idle_cstate = INT_MAX; struct sched_domain *sd; struct sched_group *sg; @@ -6746,7 +6747,7 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, for_each_cpu_and(i, tsk_cpus_allowed(p), sched_group_cpus(sg)) { unsigned long capacity_curr = capacity_curr_of(i); unsigned long capacity_orig = capacity_orig_of(i); - unsigned long wake_util, new_util; + unsigned long wake_util, new_util, min_capped_util; if (!cpu_online(i)) continue; @@ -6768,6 +6769,16 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, * than the one required to boost the task. */ new_util = max(min_util, new_util); + + /* + * Include minimum capacity constraint: + * new_util contains the required utilization including + * boost. min_capped_util also takes into account a + * minimum capacity cap imposed on the CPU by external + * actors. + */ + min_capped_util = max(new_util, capacity_min_of(i)); + if (new_util > capacity_orig) continue; @@ -6890,6 +6901,12 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, /* Select idle CPU with lower cap_orig */ if (capacity_orig > best_idle_min_cap_orig) continue; + /* Favor CPUs that won't end up running at a + * high OPP. + */ + if ((capacity_orig - min_capped_util) < + target_idle_max_spare_cap) + continue; /* * Skip CPUs in deeper idle state, but only @@ -6903,6 +6920,8 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, /* Keep track of best idle CPU */ best_idle_min_cap_orig = capacity_orig; + target_idle_max_spare_cap = capacity_orig - + min_capped_util; best_idle_cstate = idle_idx; best_idle_cpu = i; continue; -- GitLab From f964120739fc08339f0e4368a4bad099fdfb4537 Mon Sep 17 00:00:00 2001 From: Ionela Voinescu Date: Thu, 7 Dec 2017 20:09:50 +0000 Subject: [PATCH 0023/1834] sched/fair: use min capacity when evaluating active cpus When we are calculating what the impact of placing a task on a specific cpu is, we should include the information that there might be a minimum capacity imposed upon that cpu which could change the performance and/or energy cost decisions. When choosing an active target CPU, favour CPUs that won't end up running at a high OPP due to a min capacity cap imposed by external actors. Change-Id: Ibc3302304345b63107f172b1fc3ffdabc19aa9d4 Signed-off-by: Ionela Voinescu Signed-off-by: Chris Redpath --- kernel/sched/fair.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index b7d603d92e03..32d1443dc033 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6952,10 +6952,11 @@ static inline int find_best_target(struct task_struct *p, int *backup_cpu, continue; /* Favor CPUs with maximum spare capacity */ - if ((capacity_orig - new_util) < target_max_spare_cap) + if ((capacity_orig - min_capped_util) < + target_max_spare_cap) continue; - target_max_spare_cap = capacity_orig - new_util; + target_max_spare_cap = capacity_orig - min_capped_util; target_capacity = capacity_orig; target_util = new_util; target_cpu = i; -- GitLab From de22a05ed0914eafb7d6ee47152626c38ba2b582 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Fri, 2 Feb 2018 11:34:53 +0530 Subject: [PATCH 0024/1834] sched/fair: fix array out of bounds access in select_energy_cpu_idx() We are using an incorrect index while initializing the nrg_delta for the previous CPU in select_energy_cpu_idx(). This initialization it self is not needed as the nrg_delta for the previous CPU is already initialized to 0 while preparing the energ_env struct. Change-Id: Iee4e2c62f904050d2680a0a1df646d4d515c62cc Signed-off-by: Pavankumar Kondeti --- kernel/sched/fair.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 32d1443dc033..18020b32799b 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5879,7 +5879,6 @@ static inline int select_energy_cpu_idx(struct energy_env *eenv) * efficient, with a 0 energy variation. */ eenv->next_idx = EAS_CPU_PRV; - eenv->cpu[cpu_idx].nrg_delta = 0; /* * Compare the other CPU candidates to find a CPU which can be -- GitLab From b5ba569f6f894078248ebc4bd27e44af95d90786 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Mon, 11 Dec 2017 14:56:12 +0000 Subject: [PATCH 0025/1834] sched/fair: select the most energy-efficient CPU candidate on wake-up The current implementation of the energy-aware wake-up path relies on find_best_target() to select an ordered list of CPU candidates for task placement. The first candidate of the list saving energy is then chosen, disregarding all the others to avoid the overhead of an expensive energy_diff. With the recent refactoring of select_energy_cpu_idx(), the cost of exploring multiple CPUs has been reduced, hence offering the opportunity to select the most energy-efficient candidate at a lower cost. This commit seizes this opportunity by allowing to change select_energy_cpu_idx()'s behaviour as to ignore the order of CPUs returned by find_best_target() and to pick the best candidate energy-wise. As this functionality is still considered as experimental, it is hidden behind a sched_feature named FBT_STRICT_ORDER (like the equivalent feature in Android 4.14) which defaults to true, hence keeping the current behaviour by default. Change-Id: I0cb833bfec1a4a053eddaff1652c0b6cad554f97 Suggested-by: Patrick Bellasi Suggested-by: Chris Redpath Signed-off-by: Quentin Perret --- kernel/sched/fair.c | 3 ++- kernel/sched/features.h | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 18020b32799b..33b8142758bd 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -5899,7 +5899,8 @@ static inline int select_energy_cpu_idx(struct energy_env *eenv) if (eenv->cpu[cpu_idx].nrg_delta < eenv->cpu[eenv->next_idx].nrg_delta) { eenv->next_idx = cpu_idx; - break; + if (sched_feat(FBT_STRICT_ORDER)) + break; } } diff --git a/kernel/sched/features.h b/kernel/sched/features.h index 69f202b4c976..a8fe53bd51df 100644 --- a/kernel/sched/features.h +++ b/kernel/sched/features.h @@ -86,3 +86,10 @@ SCHED_FEAT(ENERGY_AWARE, false) * restrictions. */ SCHED_FEAT(MIN_CAPACITY_CAPPING, false) + +/* + * Enforce the priority of candidates selected by find_best_target() + * ON: If the target CPU saves any energy, use that. + * OFF: Use whichever of target or backup saves most. + */ +SCHED_FEAT(FBT_STRICT_ORDER, true) -- GitLab From e7f51a5b0be603f78456ef5827cf766c9ac1d682 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Mon, 4 Dec 2017 09:51:07 +0530 Subject: [PATCH 0026/1834] ANDROID: sdcardfs: Set num in extension_details during make_item Without this patch when you delete an extension from configfs it still exists in the hash table data structures and we are unable to delete it or change it's group. This happens because during deletion the key & value is taken from extension_details, and was not properly set. Fix it by this patch. Change-Id: I7c20cb1ab4d99e6aceadcb5ef850f0bb47f18be8 Signed-off-by: Ritesh Harjani Signed-off-by: Daniel Rosenberg Bug: 73055997 --- fs/sdcardfs/packagelist.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c index 6da0c2186d39..4b9a5635f1e0 100644 --- a/fs/sdcardfs/packagelist.c +++ b/fs/sdcardfs/packagelist.c @@ -659,6 +659,7 @@ static struct config_item *extension_details_make_item(struct config_group *grou return ERR_PTR(-ENOMEM); } qstr_init(&extension_details->name, tmp); + extension_details->num = extensions_value->num; ret = insert_ext_gid_entry(&extension_details->name, extensions_value->num); if (ret) { -- GitLab From d58d78c207a348a87cb143dadcbf839ea35443b6 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 8 Feb 2018 12:19:00 +0100 Subject: [PATCH 0027/1834] netfilter: drop outermost socket lock in getsockopt() commit 01ea306f2ac2baff98d472da719193e738759d93 upstream. The Syzbot reported a possible deadlock in the netfilter area caused by rtnl lock, xt lock and socket lock being acquired with a different order on different code paths, leading to the following backtrace: Reviewed-by: Xin Long ====================================================== WARNING: possible circular locking dependency detected 4.15.0+ #301 Not tainted ------------------------------------------------------ syzkaller233489/4179 is trying to acquire lock: (rtnl_mutex){+.+.}, at: [<0000000048e996fd>] rtnl_lock+0x17/0x20 net/core/rtnetlink.c:74 but task is already holding lock: (&xt[i].mutex){+.+.}, at: [<00000000328553a2>] xt_find_table_lock+0x3e/0x3e0 net/netfilter/x_tables.c:1041 which lock already depends on the new lock. === Since commit 3f34cfae1230 ("netfilter: on sockopt() acquire sock lock only in the required scope"), we already acquire the socket lock in the innermost scope, where needed. In such commit I forgot to remove the outer-most socket lock from the getsockopt() path, this commit addresses the issues dropping it now. v1 -> v2: fix bad subj, added relavant 'fixes' tag Fixes: 22265a5c3c10 ("netfilter: xt_TEE: resolve oif using netdevice notifiers") Fixes: 202f59afd441 ("netfilter: ipt_CLUSTERIP: do not hold dev") Fixes: 3f34cfae1230 ("netfilter: on sockopt() acquire sock lock only in the required scope") Reported-by: syzbot+ddde1c7b7ff7442d7f2d@syzkaller.appspotmail.com Suggested-by: Florian Westphal Signed-off-by: Paolo Abeni Signed-off-by: Pablo Neira Ayuso Tested-by: Krzysztof Piotr Oledzki Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_sockglue.c | 7 +------ net/ipv6/ipv6_sockglue.c | 10 ++-------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index bf62fa487262..fd1e6b8562e0 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -1552,10 +1552,7 @@ int ip_getsockopt(struct sock *sk, int level, if (get_user(len, optlen)) return -EFAULT; - lock_sock(sk); - err = nf_getsockopt(sk, PF_INET, optname, optval, - &len); - release_sock(sk); + err = nf_getsockopt(sk, PF_INET, optname, optval, &len); if (err >= 0) err = put_user(len, optlen); return err; @@ -1587,9 +1584,7 @@ int compat_ip_getsockopt(struct sock *sk, int level, int optname, if (get_user(len, optlen)) return -EFAULT; - lock_sock(sk); err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len); - release_sock(sk); if (err >= 0) err = put_user(len, optlen); return err; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 493a32f6a5f2..c66b9a87e995 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1343,10 +1343,7 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, if (get_user(len, optlen)) return -EFAULT; - lock_sock(sk); - err = nf_getsockopt(sk, PF_INET6, optname, optval, - &len); - release_sock(sk); + err = nf_getsockopt(sk, PF_INET6, optname, optval, &len); if (err >= 0) err = put_user(len, optlen); } @@ -1385,10 +1382,7 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, if (get_user(len, optlen)) return -EFAULT; - lock_sock(sk); - err = compat_nf_getsockopt(sk, PF_INET6, - optname, optval, &len); - release_sock(sk); + err = compat_nf_getsockopt(sk, PF_INET6, optname, optval, &len); if (err >= 0) err = put_user(len, optlen); } -- GitLab From a5ecf56cb25462c07afabeee1ba12e09cd8484bd Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Tue, 13 Feb 2018 15:31:05 -0800 Subject: [PATCH 0028/1834] xtensa: fix high memory/reserved memory collision commit 6ac5a11dc674bc5016ea716e8082fff61f524dc1 upstream. Xtensa memory initialization code frees high memory pages without checking whether they are in the reserved memory regions or not. That results in invalid value of totalram_pages and duplicate page usage by CMA and highmem. It produces a bunch of BUGs at startup looking like this: BUG: Bad page state in process swapper pfn:70800 page:be60c000 count:0 mapcount:-127 mapping: (null) index:0x1 flags: 0x80000000() raw: 80000000 00000000 00000001 ffffff80 00000000 be60c014 be60c014 0000000a page dumped because: nonzero mapcount Modules linked in: CPU: 0 PID: 1 Comm: swapper Tainted: G B 4.16.0-rc1-00015-g7928b2cbe55b-dirty #23 Stack: bd839d33 00000000 00000018 ba97b64c a106578c bd839d70 be60c000 00000000 a1378054 bd86a000 00000003 ba97b64c a1066166 bd839da0 be60c000 ffe00000 a1066b58 bd839dc0 be504000 00000000 000002f4 bd838000 00000000 0000001e Call Trace: [] bad_page+0xac/0xd0 [] free_pages_check_bad+0x34/0x4c [] __free_pages_ok+0xae/0x14c [] __free_pages+0x30/0x64 [] init_cma_reserved_pageblock+0x35/0x44 [] cma_init_reserved_areas+0xf4/0x148 [] do_one_initcall+0x80/0xf8 [] kernel_init_freeable+0xda/0x13c [] kernel_init+0x9/0xd0 [] ret_from_kernel_thread+0xc/0x18 Only free high memory pages that are not reserved. Cc: stable@vger.kernel.org Signed-off-by: Max Filippov Signed-off-by: Greg Kroah-Hartman --- arch/xtensa/mm/init.c | 70 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index 80e4cfb2471a..d5abdf8878fe 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c @@ -77,19 +77,75 @@ void __init zones_init(void) free_area_init_node(0, zones_size, ARCH_PFN_OFFSET, NULL); } +#ifdef CONFIG_HIGHMEM +static void __init free_area_high(unsigned long pfn, unsigned long end) +{ + for (; pfn < end; pfn++) + free_highmem_page(pfn_to_page(pfn)); +} + +static void __init free_highpages(void) +{ + unsigned long max_low = max_low_pfn; + struct memblock_region *mem, *res; + + reset_all_zones_managed_pages(); + /* set highmem page free */ + for_each_memblock(memory, mem) { + unsigned long start = memblock_region_memory_base_pfn(mem); + unsigned long end = memblock_region_memory_end_pfn(mem); + + /* Ignore complete lowmem entries */ + if (end <= max_low) + continue; + + if (memblock_is_nomap(mem)) + continue; + + /* Truncate partial highmem entries */ + if (start < max_low) + start = max_low; + + /* Find and exclude any reserved regions */ + for_each_memblock(reserved, res) { + unsigned long res_start, res_end; + + res_start = memblock_region_reserved_base_pfn(res); + res_end = memblock_region_reserved_end_pfn(res); + + if (res_end < start) + continue; + if (res_start < start) + res_start = start; + if (res_start > end) + res_start = end; + if (res_end > end) + res_end = end; + if (res_start != start) + free_area_high(start, res_start); + start = res_end; + if (start == end) + break; + } + + /* And now free anything which remains */ + if (start < end) + free_area_high(start, end); + } +} +#else +static void __init free_highpages(void) +{ +} +#endif + /* * Initialize memory pages. */ void __init mem_init(void) { -#ifdef CONFIG_HIGHMEM - unsigned long tmp; - - reset_all_zones_managed_pages(); - for (tmp = max_low_pfn; tmp < max_pfn; tmp++) - free_highmem_page(pfn_to_page(tmp)); -#endif + free_highpages(); max_mapnr = max_pfn - ARCH_PFN_OFFSET; high_memory = (void *)__va(max_low_pfn << PAGE_SHIFT); -- GitLab From bed7cb3191699212ea84cdbc35232492682ae27e Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Tue, 23 Jan 2018 20:11:32 -0600 Subject: [PATCH 0029/1834] scsi: ibmvfc: fix misdefined reserved field in ibmvfc_fcp_rsp_info commit c39813652700f3df552b6557530f1e5f782dbe2f upstream. The fcp_rsp_info structure as defined in the FC spec has an initial 3 bytes reserved field. The ibmvfc driver mistakenly defined this field as 4 bytes resulting in the rsp_code field being defined in what should be the start of the second reserved field and thus always being reported as zero by the driver. Ideally, we should wire ibmvfc up with libfc for the sake of code deduplication, and ease of maintaining standardized structures in a single place. However, for now simply fixup the definition in ibmvfc for backporting to distros on older kernels. Wiring up with libfc will be done in a followup patch. Cc: Reported-by: Hannes Reinecke Signed-off-by: Tyrel Datwyler Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ibmvscsi/ibmvfc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 9a0696f68f37..b81a53c4a9a8 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -367,7 +367,7 @@ enum ibmvfc_fcp_rsp_info_codes { }; struct ibmvfc_fcp_rsp_info { - __be16 reserved; + u8 reserved[3]; u8 rsp_code; u8 reserved2[4]; }__attribute__((packed, aligned (2))); -- GitLab From 3b4dd8ac6b4f957e8e4b0434bb4cff724615e9e6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 16:31:23 +0100 Subject: [PATCH 0030/1834] cfg80211: fix cfg80211_beacon_dup commit bee92d06157fc39d5d7836a061c7d41289a55797 upstream. gcc-8 warns about some obviously incorrect code: net/mac80211/cfg.c: In function 'cfg80211_beacon_dup': net/mac80211/cfg.c:2896:3: error: 'memcpy' source argument is the same as destination [-Werror=restrict] From the context, I conclude that we want to copy from beacon into new_beacon, as we do in the rest of the function. Cc: stable@vger.kernel.org Fixes: 73da7d5bab79 ("mac80211: add channel switch command and beacon callbacks") Signed-off-by: Arnd Bergmann Signed-off-by: Johannes Berg Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 07001b6d36cc..dee60428c78c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2792,7 +2792,7 @@ cfg80211_beacon_dup(struct cfg80211_beacon_data *beacon) } if (beacon->probe_resp_len) { new_beacon->probe_resp_len = beacon->probe_resp_len; - beacon->probe_resp = pos; + new_beacon->probe_resp = pos; memcpy(pos, beacon->probe_resp, beacon->probe_resp_len); pos += beacon->probe_resp_len; } -- GitLab From c60e246f56738036a4962b0aa40ff7ffbad6ec5f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 22 Feb 2018 14:38:33 +0000 Subject: [PATCH 0031/1834] X.509: fix BUG_ON() when hash algorithm is unsupported commit 437499eea4291ae9621e8763a41df027c110a1ef upstream. The X.509 parser mishandles the case where the certificate's signature's hash algorithm is not available in the crypto API. In this case, x509_get_sig_params() doesn't allocate the cert->sig->digest buffer; this part seems to be intentional. However, public_key_verify_signature() is still called via x509_check_for_self_signed(), which triggers the 'BUG_ON(!sig->digest)'. Fix this by making public_key_verify_signature() return -ENOPKG if the hash buffer has not been allocated. Reproducer when all the CONFIG_CRYPTO_SHA512* options are disabled: openssl req -new -sha512 -x509 -batch -nodes -outform der \ | keyctl padd asymmetric desc @s Fixes: 6c2dc5ae4ab7 ("X.509: Extract signature digest and make self-signed cert checks earlier") Reported-by: Paolo Valente Cc: Paolo Valente Cc: # v4.7+ Signed-off-by: Eric Biggers Signed-off-by: David Howells Signed-off-by: Greg Kroah-Hartman --- crypto/asymmetric_keys/public_key.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c index 4955eb66e361..8525fe474abd 100644 --- a/crypto/asymmetric_keys/public_key.c +++ b/crypto/asymmetric_keys/public_key.c @@ -93,9 +93,11 @@ int public_key_verify_signature(const struct public_key *pkey, BUG_ON(!pkey); BUG_ON(!sig); - BUG_ON(!sig->digest); BUG_ON(!sig->s); + if (!sig->digest) + return -ENOPKG; + alg_name = sig->pkey_algo; if (strcmp(sig->pkey_algo, "rsa") == 0) { /* The data wangled by the RSA algorithm is typically padded -- GitLab From e4b02ca6149773f86af266e75a0e69c374bb90ed Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 22 Feb 2018 14:38:33 +0000 Subject: [PATCH 0032/1834] PKCS#7: fix certificate chain verification commit 971b42c038dc83e3327872d294fe7131bab152fc upstream. When pkcs7_verify_sig_chain() is building the certificate chain for a SignerInfo using the certificates in the PKCS#7 message, it is passing the wrong arguments to public_key_verify_signature(). Consequently, when the next certificate is supposed to be used to verify the previous certificate, the next certificate is actually used to verify itself. An attacker can use this bug to create a bogus certificate chain that has no cryptographic relationship between the beginning and end. Fortunately I couldn't quite find a way to use this to bypass the overall signature verification, though it comes very close. Here's the reasoning: due to the bug, every certificate in the chain beyond the first actually has to be self-signed (where "self-signed" here refers to the actual key and signature; an attacker might still manipulate the certificate fields such that the self_signed flag doesn't actually get set, and thus the chain doesn't end immediately). But to pass trust validation (pkcs7_validate_trust()), either the SignerInfo or one of the certificates has to actually be signed by a trusted key. Since only self-signed certificates can be added to the chain, the only way for an attacker to introduce a trusted signature is to include a self-signed trusted certificate. But, when pkcs7_validate_trust_one() reaches that certificate, instead of trying to verify the signature on that certificate, it will actually look up the corresponding trusted key, which will succeed, and then try to verify the *previous* certificate, which will fail. Thus, disaster is narrowly averted (as far as I could tell). Fixes: 6c2dc5ae4ab7 ("X.509: Extract signature digest and make self-signed cert checks earlier") Cc: # v4.7+ Signed-off-by: Eric Biggers Signed-off-by: David Howells Signed-off-by: Greg Kroah-Hartman --- crypto/asymmetric_keys/pkcs7_verify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 5a37962d2199..df1bde273bba 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -261,7 +261,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, sinfo->index); return 0; } - ret = public_key_verify_signature(p->pub, p->sig); + ret = public_key_verify_signature(p->pub, x509->sig); if (ret < 0) return ret; x509->signer = p; -- GitLab From 239ef9cf2695c7e6d2d0dc673b34a4123dde7425 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 13 Feb 2018 12:18:41 +0200 Subject: [PATCH 0033/1834] RDMA/uverbs: Protect from command mask overflow commit 3f802b162dbf4a558ff98986449eddc717826209 upstream. The command number is not bounds checked against the command mask before it is shifted, resulting in an ubsan hit. This does not cause malfunction since the command number is eventually bounds checked, but we can make this ubsan clean by moving the bounds check to before the mask check. ================================================================================ UBSAN: Undefined behaviour in drivers/infiniband/core/uverbs_main.c:647:21 shift exponent 207 is too large for 64-bit type 'long long unsigned int' CPU: 0 PID: 446 Comm: syz-executor3 Not tainted 4.15.0-rc2+ #61 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ? dma_virt_map_sg+0x22c/0x22c ubsan_epilogue+0xe/0x81 __ubsan_handle_shift_out_of_bounds+0x293/0x2f7 ? debug_check_no_locks_freed+0x340/0x340 ? __ubsan_handle_load_invalid_value+0x19b/0x19b ? lock_acquire+0x440/0x440 ? lock_acquire+0x19d/0x440 ? __might_fault+0xf4/0x240 ? ib_uverbs_write+0x68d/0xe20 ib_uverbs_write+0x68d/0xe20 ? __lock_acquire+0xcf7/0x3940 ? uverbs_devnode+0x110/0x110 ? cyc2ns_read_end+0x10/0x10 ? sched_clock_cpu+0x18/0x200 ? sched_clock_cpu+0x18/0x200 __vfs_write+0x10d/0x700 ? uverbs_devnode+0x110/0x110 ? kernel_read+0x170/0x170 ? __fget+0x35b/0x5d0 ? security_file_permission+0x93/0x260 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x18/0x85 RIP: 0033:0x448e29 RSP: 002b:00007f033f567c58 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 00007f033f5686bc RCX: 0000000000448e29 RDX: 0000000000000060 RSI: 0000000020001000 RDI: 0000000000000012 RBP: 000000000070bea0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000246 R12: 00000000ffffffff R13: 00000000000056a0 R14: 00000000006e8740 R15: 0000000000000000 ================================================================================ Cc: syzkaller Cc: # 4.5 Fixes: 2dbd5186a39c ("IB/core: IB/core: Allow legacy verbs through extended interfaces") Reported-by: Noa Osherovich Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/uverbs_main.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 44b1104eb168..c5e921bf9130 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -735,12 +735,21 @@ static int verify_command_mask(struct ib_device *ib_dev, __u32 command) return -1; } +static bool verify_command_idx(u32 command, bool extended) +{ + if (extended) + return command < ARRAY_SIZE(uverbs_ex_cmd_table); + + return command < ARRAY_SIZE(uverbs_cmd_table); +} + static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_file *file = filp->private_data; struct ib_device *ib_dev; struct ib_uverbs_cmd_hdr hdr; + bool extended_command; __u32 command; __u32 flags; int srcu_key; @@ -770,6 +779,15 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, } command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK; + flags = (hdr.command & + IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; + + extended_command = flags & IB_USER_VERBS_CMD_FLAG_EXTENDED; + if (!verify_command_idx(command, extended_command)) { + ret = -EINVAL; + goto out; + } + if (verify_command_mask(ib_dev, command)) { ret = -EOPNOTSUPP; goto out; @@ -781,12 +799,8 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, goto out; } - flags = (hdr.command & - IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; - if (!flags) { - if (command >= ARRAY_SIZE(uverbs_cmd_table) || - !uverbs_cmd_table[command]) { + if (!uverbs_cmd_table[command]) { ret = -EINVAL; goto out; } @@ -807,8 +821,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, struct ib_udata uhw; size_t written_count = count; - if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) || - !uverbs_ex_cmd_table[command]) { + if (!uverbs_ex_cmd_table[command]) { ret = -ENOSYS; goto out; } -- GitLab From 97e604775d4170c4c6daea5318adf43d7a1f7f5f Mon Sep 17 00:00:00 2001 From: Stefan Windfeldt-Prytz Date: Thu, 15 Feb 2018 15:02:53 +0100 Subject: [PATCH 0034/1834] iio: buffer: check if a buffer has been set up when poll is called commit 4cd140bda6494543f1c1b0ccceceaa44b676eef6 upstream. If no iio buffer has been set up and poll is called return 0. Without this check there will be a null pointer dereference when calling poll on a iio driver without an iio buffer. Cc: stable@vger.kernel.org Signed-off-by: Stefan Windfeldt-Prytz Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/industrialio-buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 158aaf44dd95..5d05c38c4ba9 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -174,7 +174,7 @@ unsigned int iio_buffer_poll(struct file *filp, struct iio_dev *indio_dev = filp->private_data; struct iio_buffer *rb = indio_dev->buffer; - if (!indio_dev->info) + if (!indio_dev->info || rb == NULL) return 0; poll_wait(filp, &rb->pollq, wait); -- GitLab From 964e8ceadfe6c30483e4b1131b9ddc9b1c069d50 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 14 Feb 2018 15:43:00 +0100 Subject: [PATCH 0035/1834] iio: adis_lib: Initialize trigger before requesting interrupt commit f027e0b3a774e10302207e91d304bbf99e3a8b36 upstream. The adis_probe_trigger() creates a new IIO trigger and requests an interrupt associated with the trigger. The interrupt uses the generic iio_trigger_generic_data_rdy_poll() function as its interrupt handler. Currently the driver initializes some fields of the trigger structure after the interrupt has been requested. But an interrupt can fire as soon as it has been requested. This opens up a race condition. iio_trigger_generic_data_rdy_poll() will access the trigger data structure and dereference the ops field. If the ops field is not yet initialized this will result in a NULL pointer deref. It is not expected that the device generates an interrupt at this point, so typically this issue did not surface unless e.g. due to a hardware misconfiguration (wrong interrupt number, wrong polarity, etc.). But some newer devices from the ADIS family start to generate periodic interrupts in their power-on reset configuration and unfortunately the interrupt can not be masked in the device. This makes the race condition much more visible and the following crash has been observed occasionally when booting a system using the ADIS16460. Unable to handle kernel NULL pointer dereference at virtual address 00000008 pgd = c0004000 [00000008] *pgd=00000000 Internal error: Oops: 5 [#1] PREEMPT SMP ARM Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.9.0-04126-gf9739f0-dirty #257 Hardware name: Xilinx Zynq Platform task: ef04f640 task.stack: ef050000 PC is at iio_trigger_notify_done+0x30/0x68 LR is at iio_trigger_generic_data_rdy_poll+0x18/0x20 pc : [] lr : [] psr: 60000193 sp : ef051bb8 ip : 00000000 fp : ef106400 r10: c081d80a r9 : ef3bfa00 r8 : 00000087 r7 : ef051bec r6 : 00000000 r5 : ef3bfa00 r4 : ee92ab00 r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : ee97e400 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none Control: 18c5387d Table: 0000404a DAC: 00000051 Process swapper/0 (pid: 1, stack limit = 0xef050210) [] (iio_trigger_notify_done) from [] (__handle_irq_event_percpu+0x88/0x118) [] (__handle_irq_event_percpu) from [] (handle_irq_event_percpu+0x1c/0x58) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x38/0x5c) [] (handle_irq_event) from [] (handle_level_irq+0xa4/0x130) [] (handle_level_irq) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (zynq_gpio_irqhandler+0xb8/0x13c) [] (zynq_gpio_irqhandler) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (__handle_domain_irq+0x5c/0xb4) [] (__handle_domain_irq) from [] (gic_handle_irq+0x48/0x8c) [] (gic_handle_irq) from [] (__irq_svc+0x6c/0xa8) To fix this make sure that the trigger is fully initialized before requesting the interrupt. Fixes: ccd2b52f4ac6 ("staging:iio: Add common ADIS library") Reported-by: Robin Getz Signed-off-by: Lars-Peter Clausen Cc: Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/imu/adis_trigger.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/iio/imu/adis_trigger.c b/drivers/iio/imu/adis_trigger.c index f53e9a803a0e..93b99bd93738 100644 --- a/drivers/iio/imu/adis_trigger.c +++ b/drivers/iio/imu/adis_trigger.c @@ -47,6 +47,10 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (adis->trig == NULL) return -ENOMEM; + adis->trig->dev.parent = &adis->spi->dev; + adis->trig->ops = &adis_trigger_ops; + iio_trigger_set_drvdata(adis->trig, adis); + ret = request_irq(adis->spi->irq, &iio_trigger_generic_data_rdy_poll, IRQF_TRIGGER_RISING, @@ -55,9 +59,6 @@ int adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev) if (ret) goto error_free_trig; - adis->trig->dev.parent = &adis->spi->dev; - adis->trig->ops = &adis_trigger_ops; - iio_trigger_set_drvdata(adis->trig, adis); ret = iio_trigger_register(adis->trig); indio_dev->trig = iio_trigger_get(adis->trig); -- GitLab From dcc92a16da6d56b946e79d354364b87e1b5ea5ea Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 20 Feb 2018 21:58:21 +0100 Subject: [PATCH 0036/1834] x86/oprofile: Fix bogus GCC-8 warning in nmi_setup() commit 85c615eb52222bc5fab6c7190d146bc59fac289e upstream. GCC-8 shows a warning for the x86 oprofile code that copies per-CPU data from CPU 0 to all other CPUs, which when building a non-SMP kernel turns into a memcpy() with identical source and destination pointers: arch/x86/oprofile/nmi_int.c: In function 'mux_clone': arch/x86/oprofile/nmi_int.c:285:2: error: 'memcpy' source argument is the same as destination [-Werror=restrict] memcpy(per_cpu(cpu_msrs, cpu).multiplex, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ per_cpu(cpu_msrs, 0).multiplex, ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ sizeof(struct op_msr) * model->num_virt_counters); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ arch/x86/oprofile/nmi_int.c: In function 'nmi_setup': arch/x86/oprofile/nmi_int.c:466:3: error: 'memcpy' source argument is the same as destination [-Werror=restrict] arch/x86/oprofile/nmi_int.c:470:3: error: 'memcpy' source argument is the same as destination [-Werror=restrict] I have analyzed a number of such warnings now: some are valid and the GCC warning is welcome. Others turned out to be false-positives, and GCC was changed to not warn about those any more. This is a corner case that is a false-positive but the GCC developers feel it's better to keep warning about it. In this case, it seems best to work around it by telling GCC a little more clearly that this code path is never hit with an IS_ENABLED() configuration check. Cc:stable as we also want old kernels to build cleanly with GCC-8. Signed-off-by: Arnd Bergmann Cc: Jessica Yu Cc: Kees Cook Cc: Linus Torvalds Cc: Martin Sebor Cc: Peter Zijlstra Cc: Robert Richter Cc: Thomas Gleixner Cc: oprofile-list@lists.sf.net Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180220205826.2008875-1-arnd@arndb.de Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84095 Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/oprofile/nmi_int.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 28c04123b6dd..842ca3cab6b3 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -472,7 +472,7 @@ static int nmi_setup(void) goto fail; for_each_possible_cpu(cpu) { - if (!cpu) + if (!IS_ENABLED(CONFIG_SMP) || !cpu) continue; memcpy(per_cpu(cpu_msrs, cpu).counters, -- GitLab From 2146b6ec0e96ab283c46f7391ddf3bf01f7975e2 Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Wed, 31 Jan 2018 18:03:42 -0600 Subject: [PATCH 0037/1834] irqchip/gic-v3: Use wmb() instead of smb_wmb() in gic_raise_softirq() commit 21ec30c0ef5234fb1039cc7c7737d885bf875a9e upstream. A DMB instruction can be used to ensure the relative order of only memory accesses before and after the barrier. Since writes to system registers are not memory operations, barrier DMB is not sufficient for observability of memory accesses that occur before ICC_SGI1R_EL1 writes. A DSB instruction ensures that no instructions that appear in program order after the DSB instruction, can execute until the DSB instruction has completed. Cc: stable@vger.kernel.org Acked-by: Will Deacon , Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index a37576a1798d..fd4a78296b48 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -616,7 +616,7 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq) * Ensure that stores to Normal memory are visible to the * other CPUs before issuing the IPI. */ - smp_wmb(); + wmb(); for_each_cpu(cpu, mask) { unsigned long cluster_id = cpu_logical_map(cpu) & ~0xffUL; -- GitLab From c529ff430693180d0f2a57a44a19cc51009de3a4 Mon Sep 17 00:00:00 2001 From: Casey Leedom Date: Thu, 15 Feb 2018 20:03:18 +0530 Subject: [PATCH 0038/1834] PCI/cxgb4: Extend T3 PCI quirk to T4+ devices commit 7dcf688d4c78a18ba9538b2bf1b11dc7a43fe9be upstream. We've run into a problem where our device is attached to a Virtual Machine and the use of the new pci_set_vpd_size() API doesn't help. The VM kernel has been informed that the accesses are okay, but all of the actual VPD Capability Accesses are trapped down into the KVM Hypervisor where it goes ahead and imposes the silent denials. The right idea is to follow the kernel.org commit 1c7de2b4ff88 ("PCI: Enable access to non-standard VPD for Chelsio devices (cxgb3)") which Alexey Kardashevskiy authored to establish a PCI Quirk for our T3-based adapters. This commit extends that PCI Quirk to cover Chelsio T4 devices and later. The advantage of this approach is that the VPD Size gets set early in the Base OS/Hypervisor Boot and doesn't require that the cxgb4 driver even be available in the Base OS/Hypervisor. Thus PF4 can be exported to a Virtual Machine and everything should work. Fixes: 67e658794ca1 ("cxgb4: Set VPD size so we can read both VPD structures") Cc: # v4.9+ Signed-off-by: Casey Leedom Signed-off-by: Arjun Vynipadath Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 10 ------ drivers/pci/quirks.c | 39 +++++++++++++--------- 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 9e073fb6870a..6fd3be69ff21 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -2596,7 +2596,6 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) } #define EEPROM_STAT_ADDR 0x7bfc -#define VPD_SIZE 0x800 #define VPD_BASE 0x400 #define VPD_BASE_OLD 0 #define VPD_LEN 1024 @@ -2634,15 +2633,6 @@ int t4_get_raw_vpd_params(struct adapter *adapter, struct vpd_params *p) if (!vpd) return -ENOMEM; - /* We have two VPD data structures stored in the adapter VPD area. - * By default, Linux calculates the size of the VPD area by traversing - * the first VPD area at offset 0x0, so we need to tell the OS what - * our real VPD size is. - */ - ret = pci_set_vpd_size(adapter->pdev, VPD_SIZE); - if (ret < 0) - goto out; - /* Card information normally starts at VPD_BASE but early cards had * it at 0. */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 98eba9127a0b..0c9edc9d7c44 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3369,22 +3369,29 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE, static void quirk_chelsio_extend_vpd(struct pci_dev *dev) { - pci_set_vpd_size(dev, 8192); -} - -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x20, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x21, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x22, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x23, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x24, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x25, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x26, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x30, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x31, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x32, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x35, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x36, quirk_chelsio_extend_vpd); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x37, quirk_chelsio_extend_vpd); + int chip = (dev->device & 0xf000) >> 12; + int func = (dev->device & 0x0f00) >> 8; + int prod = (dev->device & 0x00ff) >> 0; + + /* + * If this is a T3-based adapter, there's a 1KB VPD area at offset + * 0xc00 which contains the preferred VPD values. If this is a T4 or + * later based adapter, the special VPD is at offset 0x400 for the + * Physical Functions (the SR-IOV Virtual Functions have no VPD + * Capabilities). The PCI VPD Access core routines will normally + * compute the size of the VPD by parsing the VPD Data Structure at + * offset 0x000. This will result in silent failures when attempting + * to accesses these other VPD areas which are beyond those computed + * limits. + */ + if (chip == 0x0 && prod >= 0x20) + pci_set_vpd_size(dev, 8192); + else if (chip >= 0x4 && func < 0x8) + pci_set_vpd_size(dev, 2048); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, PCI_ANY_ID, + quirk_chelsio_extend_vpd); #ifdef CONFIG_ACPI /* -- GitLab From 4a41d4412de0517eaa531ae273c3a847c8031984 Mon Sep 17 00:00:00 2001 From: Shigeru Yoshida Date: Fri, 2 Feb 2018 13:51:39 +0800 Subject: [PATCH 0039/1834] ohci-hcd: Fix race condition caused by ohci_urb_enqueue() and io_watchdog_func() commit b2685bdacdaab065c172b97b55ab46c6be77a037 upstream. Running io_watchdog_func() while ohci_urb_enqueue() is running can cause a race condition where ohci->prev_frame_no is corrupted and the watchdog can mis-detect following error: ohci-platform 664a0800.usb: frame counter not updating; disabled ohci-platform 664a0800.usb: HC died; cleaning up Specifically, following scenario causes a race condition: 1. ohci_urb_enqueue() calls spin_lock_irqsave(&ohci->lock, flags) and enters the critical section 2. ohci_urb_enqueue() calls timer_pending(&ohci->io_watchdog) and it returns false 3. ohci_urb_enqueue() sets ohci->prev_frame_no to a frame number read by ohci_frame_no(ohci) 4. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 5. ohci_urb_enqueue() calls spin_unlock_irqrestore(&ohci->lock, flags) and exits the critical section 6. Later, ohci_urb_enqueue() is called 7. ohci_urb_enqueue() calls spin_lock_irqsave(&ohci->lock, flags) and enters the critical section 8. The timer scheduled on step 4 expires and io_watchdog_func() runs 9. io_watchdog_func() calls spin_lock_irqsave(&ohci->lock, flags) and waits on it because ohci_urb_enqueue() is already in the critical section on step 7 10. ohci_urb_enqueue() calls timer_pending(&ohci->io_watchdog) and it returns false 11. ohci_urb_enqueue() sets ohci->prev_frame_no to new frame number read by ohci_frame_no(ohci) because the frame number proceeded between step 3 and 6 12. ohci_urb_enqueue() schedules io_watchdog_func() with mod_timer() 13. ohci_urb_enqueue() calls spin_unlock_irqrestore(&ohci->lock, flags) and exits the critical section, then wake up io_watchdog_func() which is waiting on step 9 14. io_watchdog_func() enters the critical section 15. io_watchdog_func() calls ohci_frame_no(ohci) and set frame_no variable to the frame number 16. io_watchdog_func() compares frame_no and ohci->prev_frame_no On step 16, because this calling of io_watchdog_func() is scheduled on step 4, the frame number set in ohci->prev_frame_no is expected to the number set on step 3. However, ohci->prev_frame_no is overwritten on step 11. Because step 16 is executed soon after step 11, the frame number might not proceed, so ohci->prev_frame_no must equals to frame_no. To address above scenario, this patch introduces a special sentinel value IO_WATCHDOG_OFF and set this value to ohci->prev_frame_no when the watchdog is not pending or running. When ohci_urb_enqueue() schedules the watchdog (step 4 and 12 above), it compares ohci->prev_frame_no to IO_WATCHDOG_OFF so that ohci->prev_frame_no is not overwritten while io_watchdog_func() is running. Signed-off-by: Shigeru Yoshida Signed-off-by: Haiqing Bai Acked-by: Alan Stern Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-hcd.c | 10 +++++++--- drivers/usb/host/ohci-hub.c | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index f6c7a2744e5c..a646ca3b0d00 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -73,6 +73,7 @@ static const char hcd_name [] = "ohci_hcd"; #define STATECHANGE_DELAY msecs_to_jiffies(300) #define IO_WATCHDOG_DELAY msecs_to_jiffies(275) +#define IO_WATCHDOG_OFF 0xffffff00 #include "ohci.h" #include "pci-quirks.h" @@ -230,7 +231,7 @@ static int ohci_urb_enqueue ( } /* Start up the I/O watchdog timer, if it's not running */ - if (!timer_pending(&ohci->io_watchdog) && + if (ohci->prev_frame_no == IO_WATCHDOG_OFF && list_empty(&ohci->eds_in_use) && !(ohci->flags & OHCI_QUIRK_QEMU)) { ohci->prev_frame_no = ohci_frame_no(ohci); @@ -501,6 +502,7 @@ static int ohci_init (struct ohci_hcd *ohci) setup_timer(&ohci->io_watchdog, io_watchdog_func, (unsigned long) ohci); + ohci->prev_frame_no = IO_WATCHDOG_OFF; ohci->hcca = dma_alloc_coherent (hcd->self.controller, sizeof(*ohci->hcca), &ohci->hcca_dma, GFP_KERNEL); @@ -730,7 +732,7 @@ static void io_watchdog_func(unsigned long _ohci) u32 head; struct ed *ed; struct td *td, *td_start, *td_next; - unsigned frame_no; + unsigned frame_no, prev_frame_no = IO_WATCHDOG_OFF; unsigned long flags; spin_lock_irqsave(&ohci->lock, flags); @@ -835,7 +837,7 @@ static void io_watchdog_func(unsigned long _ohci) } } if (!list_empty(&ohci->eds_in_use)) { - ohci->prev_frame_no = frame_no; + prev_frame_no = frame_no; ohci->prev_wdh_cnt = ohci->wdh_cnt; ohci->prev_donehead = ohci_readl(ohci, &ohci->regs->donehead); @@ -845,6 +847,7 @@ static void io_watchdog_func(unsigned long _ohci) } done: + ohci->prev_frame_no = prev_frame_no; spin_unlock_irqrestore(&ohci->lock, flags); } @@ -973,6 +976,7 @@ static void ohci_stop (struct usb_hcd *hcd) if (quirk_nec(ohci)) flush_work(&ohci->nec_work); del_timer_sync(&ohci->io_watchdog); + ohci->prev_frame_no = IO_WATCHDOG_OFF; ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); ohci_usb_reset(ohci); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ed678c17c4ea..798b2d25dda9 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -310,8 +310,10 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) rc = ohci_rh_suspend (ohci, 0); spin_unlock_irq (&ohci->lock); - if (rc == 0) + if (rc == 0) { del_timer_sync(&ohci->io_watchdog); + ohci->prev_frame_no = IO_WATCHDOG_OFF; + } return rc; } -- GitLab From 31fec948b3a25899647eb9f88284e54b6a8a4614 Mon Sep 17 00:00:00 2001 From: AMAN DEEP Date: Thu, 8 Feb 2018 11:55:01 +0800 Subject: [PATCH 0040/1834] usb: ohci: Proper handling of ed_rm_list to handle race condition between usb_kill_urb() and finish_unlinks() commit 46408ea558df13b110e0866b99624384a33bdeba upstream. There is a race condition between finish_unlinks->finish_urb() function and usb_kill_urb() in ohci controller case. The finish_urb calls spin_unlock(&ohci->lock) before usb_hcd_giveback_urb() function call, then if during this time, usb_kill_urb is called for another endpoint, then new ed will be added to ed_rm_list at beginning for unlink, and ed_rm_list will point to newly added. When finish_urb() is completed in finish_unlinks() and ed->td_list becomes empty as in below code (in finish_unlinks() function): if (list_empty(&ed->td_list)) { *last = ed->ed_next; ed->ed_next = NULL; } else if (ohci->rh_state == OHCI_RH_RUNNING) { *last = ed->ed_next; ed->ed_next = NULL; ed_schedule(ohci, ed); } The *last = ed->ed_next will make ed_rm_list to point to ed->ed_next and previously added ed by usb_kill_urb will be left unreferenced by ed_rm_list. This causes usb_kill_urb() hang forever waiting for finish_unlink to remove added ed from ed_rm_list. The main reason for hang in this race condtion is addition and removal of ed from ed_rm_list in the beginning during usb_kill_urb and later last* is modified in finish_unlinks(). As suggested by Alan Stern, the solution for proper handling of ohci->ed_rm_list is to remove ed from the ed_rm_list before finishing any URBs. Then at the end, we can add ed back to the list if necessary. This properly handle the updated ohci->ed_rm_list in usb_kill_urb(). Fixes: 977dcfdc6031 ("USB: OHCI: don't lose track of EDs when a controller dies") Acked-by: Alan Stern CC: Signed-off-by: Aman Deep Signed-off-by: Jeffy Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-q.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index 641fed609911..24edb7674710 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -1018,6 +1018,8 @@ static void finish_unlinks(struct ohci_hcd *ohci) * have modified this list. normally it's just prepending * entries (which we'd ignore), but paranoia won't hurt. */ + *last = ed->ed_next; + ed->ed_next = NULL; modified = 0; /* unlink urbs as requested, but rescan the list after @@ -1076,21 +1078,22 @@ static void finish_unlinks(struct ohci_hcd *ohci) goto rescan_this; /* - * If no TDs are queued, take ED off the ed_rm_list. + * If no TDs are queued, ED is now idle. * Otherwise, if the HC is running, reschedule. - * If not, leave it on the list for further dequeues. + * If the HC isn't running, add ED back to the + * start of the list for later processing. */ if (list_empty(&ed->td_list)) { - *last = ed->ed_next; - ed->ed_next = NULL; ed->state = ED_IDLE; list_del(&ed->in_use_list); } else if (ohci->rh_state == OHCI_RH_RUNNING) { - *last = ed->ed_next; - ed->ed_next = NULL; ed_schedule(ohci, ed); } else { - last = &ed->ed_next; + ed->ed_next = ohci->ed_rm_list; + ohci->ed_rm_list = ed; + /* Don't loop on the same ED */ + if (last == &ohci->ed_rm_list) + last = &ed->ed_next; } if (modified) -- GitLab From 8bd22b1828b81b16a0802b534261b1caeb26f3d0 Mon Sep 17 00:00:00 2001 From: Michael Weiser Date: Thu, 1 Feb 2018 23:13:38 +0100 Subject: [PATCH 0041/1834] arm64: Disable unhandled signal log messages by default commit 5ee39a71fd89ab7240c5339d04161c44a8e03269 upstream. aarch64 unhandled signal kernel messages are very verbose, suggesting them to be more of a debugging aid: sigsegv[33]: unhandled level 2 translation fault (11) at 0x00000000, esr 0x92000046, in sigsegv[400000+71000] CPU: 1 PID: 33 Comm: sigsegv Tainted: G W 4.15.0-rc3+ #3 Hardware name: linux,dummy-virt (DT) pstate: 60000000 (nZCv daif -PAN -UAO) pc : 0x4003f4 lr : 0x4006bc sp : 0000fffffe94a060 x29: 0000fffffe94a070 x28: 0000000000000000 x27: 0000000000000000 x26: 0000000000000000 x25: 0000000000000000 x24: 00000000004001b0 x23: 0000000000486ac8 x22: 00000000004001c8 x21: 0000000000000000 x20: 0000000000400be8 x19: 0000000000400b30 x18: 0000000000484728 x17: 000000000865ffc8 x16: 000000000000270f x15: 00000000000000b0 x14: 0000000000000002 x13: 0000000000000001 x12: 0000000000000000 x11: 0000000000000000 x10: 0008000020008008 x9 : 000000000000000f x8 : ffffffffffffffff x7 : 0004000000000000 x6 : ffffffffffffffff x5 : 0000000000000000 x4 : 0000000000000000 x3 : 00000000004003e4 x2 : 0000fffffe94a1e8 x1 : 000000000000000a x0 : 0000000000000000 Disable them by default, so they can be enabled using /proc/sys/debug/exception-trace. Cc: Signed-off-by: Michael Weiser Signed-off-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index c743d1fd8286..5963be2e05f0 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -50,7 +50,7 @@ static const char *handler[]= { "Error" }; -int show_unhandled_signals = 1; +int show_unhandled_signals = 0; /* * Dump out the contents of some kernel memory nicely... -- GitLab From 9b99be3b9e1d1ee5758f52df8ff76ccdad4ea815 Mon Sep 17 00:00:00 2001 From: Jack Stocker Date: Thu, 15 Feb 2018 18:24:10 +0000 Subject: [PATCH 0042/1834] Add delay-init quirk for Corsair K70 RGB keyboards commit 7a1646d922577b5b48c0d222e03831141664bb59 upstream. Following on from this patch: https://lkml.org/lkml/2017/11/3/516, Corsair K70 RGB keyboards also require the DELAY_INIT quirk to start correctly at boot. Device ids found here: usb 3-3: New USB device found, idVendor=1b1c, idProduct=1b13 usb 3-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3 usb 3-3: Product: Corsair K70 RGB Gaming Keyboard Signed-off-by: Jack Stocker Cc: stable Signed-off-by: Greg Kroah-Hartman --- 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 c05c4f877750..774c97bb1c08 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -225,6 +225,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1a0a, 0x0200), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Corsair K70 RGB */ + { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, + /* Corsair Strafe RGB */ { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, -- GitLab From 6f1e00f5e3f123ed0313d3f736f9c583bd6441cc Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sun, 18 Feb 2018 16:53:59 +0800 Subject: [PATCH 0043/1834] drm/edid: Add 6 bpc quirk for CPT panel in Asus UX303LA commit 06998a756a3865817b87a129a7e5d5bb66dc1ec3 upstream. Similar to commit e10aec652f31 ("drm/edid: Add 6 bpc quirk for display AEO model 0."), the EDID reports "DFP 1.x compliant TMDS" but it support 6bpc instead of 8 bpc. Hence, use 6 bpc quirk for this panel. Fixes: 196f954e2509 ("drm/i915/dp: Revert "drm/i915/dp: fall back to 18 bpp when sink capability is unknown"") BugLink: https://bugs.launchpad.net/bugs/1749420 Signed-off-by: Kai-Heng Feng Reviewed-by: Mario Kleiner Cc: # v4.8+ Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180218085359.7817-1-kai.heng.feng@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_edid.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0151ed2de770..c6b281aa762f 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -107,6 +107,9 @@ static const struct edid_quirk { /* AEO model 0 reports 8 bpc, but is a 6 bpc panel */ { "AEO", 0, EDID_QUIRK_FORCE_6BPC }, + /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ + { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, + /* Belinea 10 15 55 */ { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, -- GitLab From 3c0cbbf693968e55b024648637ff15581043aad0 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 12 Jan 2018 18:18:05 -0800 Subject: [PATCH 0044/1834] usb: dwc3: gadget: Set maxpacket size for ep0 IN commit 6180026341e852a250e1f97ebdcf71684a3c81b9 upstream. There are 2 control endpoint structures for DWC3. However, the driver only updates the OUT direction control endpoint structure during ConnectDone event. DWC3 driver needs to update the endpoint max packet size for control IN endpoint as well. If the max packet size is not properly set, then the driver will incorrectly calculate the data transfer size and fail to send ZLP for HS/FS 3-stage control read transfer. The fix is simply to update the max packet size for the ep0 IN direction during ConnectDone event. Cc: stable@vger.kernel.org Fixes: 72246da40f37 ("usb: Introduce DesignWare USB3 DRD Driver") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/gadget.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f483c3b1e971..26efe8c7535f 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2528,6 +2528,8 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) break; } + dwc->eps[1]->endpoint.maxpacket = dwc->gadget.ep0->maxpacket; + /* Enable USB2 LPM Capability */ if ((dwc->revision > DWC3_REVISION_194A) && -- GitLab From f04280fd570e2aad2cc0b8f6f678fe737efe829d Mon Sep 17 00:00:00 2001 From: Karsten Koop Date: Fri, 9 Feb 2018 09:12:06 +0000 Subject: [PATCH 0045/1834] usb: ldusb: add PIDs for new CASSY devices supported by this driver commit 52ad2bd8918158266fc88a05f95429b56b6a33c5 upstream. This patch adds support for new CASSY devices to the ldusb driver. The PIDs are also added to the ignore list in hid-quirks. Signed-off-by: Karsten Koop Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 3 +++ drivers/hid/hid-ids.h | 3 +++ drivers/usb/misc/ldusb.c | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 03cac5731afc..49406e106cee 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2443,6 +2443,9 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 244b97c1b74e..9347b37a1303 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -608,6 +608,9 @@ #define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 #define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 +#define USB_DEVICE_ID_LD_POWERANALYSERCASSY 0x1040 +#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY 0x1042 +#define USB_DEVICE_ID_LD_MACHINETESTCASSY 0x1043 #define USB_DEVICE_ID_LD_JWM 0x1080 #define USB_DEVICE_ID_LD_DMMP 0x1081 #define USB_DEVICE_ID_LD_UMIP 0x1090 diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 9ca595632f17..c5e3032a4d6b 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -46,6 +46,9 @@ #define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 /* USB Product ID of Micro-CASSY Time (reserved) */ #define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 /* USB Product ID of Micro-CASSY Temperature */ #define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 /* USB Product ID of Micro-CASSY pH */ +#define USB_DEVICE_ID_LD_POWERANALYSERCASSY 0x1040 /* USB Product ID of Power Analyser CASSY */ +#define USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY 0x1042 /* USB Product ID of Converter Controller CASSY */ +#define USB_DEVICE_ID_LD_MACHINETESTCASSY 0x1043 /* USB Product ID of Machine Test CASSY */ #define USB_DEVICE_ID_LD_JWM 0x1080 /* USB Product ID of Joule and Wattmeter */ #define USB_DEVICE_ID_LD_DMMP 0x1081 /* USB Product ID of Digital Multimeter P (reserved) */ #define USB_DEVICE_ID_LD_UMIP 0x1090 /* USB Product ID of UMI P */ @@ -88,6 +91,9 @@ static const struct usb_device_id ld_usb_table[] = { { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERANALYSERCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CONVERTERCONTROLLERCASSY) }, + { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETESTCASSY) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, -- GitLab From fe80d7385e744824443276fdfc6cfaa0a93da0cb Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Tue, 20 Feb 2018 07:31:35 -0600 Subject: [PATCH 0046/1834] Revert "usb: musb: host: don't start next rx urb if current one failed" commit 44eb5e12b845cc8a0634f21b70ef07d774eb4b25 upstream. This reverts commit dbac5d07d13e330e6706813c9fde477140fb5d80. commit dbac5d07d13e ("usb: musb: host: don't start next rx urb if current one failed") along with commit b5801212229f ("usb: musb: host: clear rxcsr error bit if set") try to solve the issue described in [1], but the latter alone is sufficient, and the former causes the issue as in [2], so now revert it. [1] https://marc.info/?l=linux-usb&m=146173995117456&w=2 [2] https://marc.info/?l=linux-usb&m=151689238420622&w=2 Cc: stable@vger.kernel.org # v4.7+ Signed-off-by: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_host.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 55c624f2a8c0..43033895e8f6 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -418,13 +418,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb, } } - /* - * The pipe must be broken if current urb->status is set, so don't - * start next urb. - * TODO: to minimize the risk of regression, only check urb->status - * for RX, until we have a test case to understand the behavior of TX. - */ - if ((!status || !is_in) && qh && qh->is_ready) { + if (qh != NULL && qh->is_ready) { musb_dbg(musb, "... next ep%d %cX urb %p", hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh)); musb_start_urb(musb, is_in, qh); -- GitLab From 8bedacf13d59b6da429780ba67f16fd0a92b1b8e Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 24 Jan 2018 00:11:53 -0800 Subject: [PATCH 0047/1834] usb: gadget: f_fs: Process all descriptors during bind commit 6cf439e0d37463e42784271179c8a308fd7493c6 upstream. During _ffs_func_bind(), the received descriptors are evaluated to prepare for binding with the gadget in order to allocate endpoints and optionally set up OS descriptors. However, the high- and super-speed descriptors are only parsed based on whether the gadget_is_dualspeed() and gadget_is_superspeed() calls are true, respectively. This is a problem in case a userspace program always provides all of the {full,high,super,OS} descriptors when configuring a function. Then, for example if a gadget device is not capable of SuperSpeed, the call to ffs_do_descs() for the SS descriptors is skipped, resulting in an incorrect offset calculation for the vla_ptr when moving on to the OS descriptors that follow. This causes ffs_do_os_descs() to fail as it is now looking at the SS descriptors' offset within the raw_descs buffer instead. _ffs_func_bind() should evaluate the descriptors unconditionally, so remove the checks for gadget speed. Fixes: f0175ab51993 ("usb: gadget: f_fs: OS descriptors support") Cc: stable@vger.kernel.org Co-Developed-by: Mayank Rana Signed-off-by: Mayank Rana Signed-off-by: Jack Pham Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d90bf57ba30e..48f52138bb1a 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -2956,10 +2956,8 @@ static int _ffs_func_bind(struct usb_configuration *c, struct ffs_data *ffs = func->ffs; const int full = !!func->ffs->fs_descs_count; - const int high = gadget_is_dualspeed(func->gadget) && - func->ffs->hs_descs_count; - const int super = gadget_is_superspeed(func->gadget) && - func->ffs->ss_descs_count; + const int high = !!func->ffs->hs_descs_count; + const int super = !!func->ffs->ss_descs_count; int fs_len, hs_len, ss_len, ret, i; struct ffs_ep *eps_ptr; -- GitLab From 18ec706ed4ce3fe5c9381471ef414fef6a82c779 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Mon, 5 Feb 2018 17:12:35 +0900 Subject: [PATCH 0048/1834] usb: renesas_usbhs: missed the "running" flag in usb_dmac with rx path commit 17aa31f13cad25daa19d3f923323f552e87bc874 upstream. This fixes an issue that a gadget driver (usb_f_fs) is possible to stop rx transactions after the usb-dmac is used because the following functions missed to set/check the "running" flag. - usbhsf_dma_prepare_pop_with_usb_dmac() - usbhsf_dma_pop_done_with_usb_dmac() So, if next transaction uses pio, the usbhsf_prepare_pop() can not start the transaction because the "running" flag is 0. Fixes: 8355b2b3082d ("usb: renesas_usbhs: fix the behavior of some usbhs_pkt_handle") Cc: # v3.19+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/renesas_usbhs/fifo.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 6c6a3a8df07a..968ade5a35f5 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -1001,6 +1001,10 @@ static int usbhsf_dma_prepare_pop_with_usb_dmac(struct usbhs_pkt *pkt, if ((uintptr_t)pkt->buf & (USBHS_USB_DMAC_XFER_SIZE - 1)) goto usbhsf_pio_prepare_pop; + /* return at this time if the pipe is running */ + if (usbhs_pipe_is_running(pipe)) + return 0; + usbhs_pipe_config_change_bfre(pipe, 1); ret = usbhsf_fifo_select(pipe, fifo, 0); @@ -1191,6 +1195,7 @@ static int usbhsf_dma_pop_done_with_usb_dmac(struct usbhs_pkt *pkt, usbhsf_fifo_clear(pipe, fifo); pkt->actual = usbhs_dma_calc_received_size(pkt, chan, rcv_len); + usbhs_pipe_running(pipe, 0); usbhsf_dma_stop(pipe, fifo); usbhsf_dma_unmap(pkt); usbhsf_fifo_unselect(pipe, pipe->fifo); -- GitLab From cf7780a6b0d242e77d8432298087fc4833f3a6ec Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 21 Nov 2017 12:10:57 -0500 Subject: [PATCH 0049/1834] drm/amdgpu: Add dpm quirk for Jet PRO (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f2e5262f75ecb40a6e56554e156a292ab9e1d1b7 upstream. Fixes stability issues. v2: clamp sclk to 600 Mhz Bug: https://bugs.freedesktop.org/show_bug.cgi?id=103370 Acked-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 4cb347e88cf0..002862be2df6 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -3507,6 +3507,11 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, max_sclk = 75000; max_mclk = 80000; } + if ((adev->pdev->revision == 0xC3) || + (adev->pdev->device == 0x6665)) { + max_sclk = 60000; + max_mclk = 80000; + } } else if (adev->asic_type == CHIP_OLAND) { if ((adev->pdev->revision == 0xC7) || (adev->pdev->revision == 0x80) || -- GitLab From 3a66f9739da86cb552336eb20664d16e757e3fc6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 20 Dec 2017 13:29:58 -0500 Subject: [PATCH 0050/1834] drm/amdgpu: add atpx quirk handling (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 052c299080cd6859f82a8154a7a673fafabe644c upstream. Add quirks for handling PX/HG systems. In this case, add a quirk for a weston dGPU that only seems to properly power down using ATPX power control rather than HG (_PR3). v2: append a new weston XT Signed-off-by: Alex Deucher Signed-off-by: Junwei Zhang (v2) Reviewed-and-Tested-by: Junwei Zhang Reviewed-by: Alex Deucher Acked-by: Christian König Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 57 ++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 6c343a933182..d451c40def0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -14,6 +14,16 @@ #include "amd_acpi.h" +#define AMDGPU_PX_QUIRK_FORCE_ATPX (1 << 0) + +struct amdgpu_px_quirk { + u32 chip_vendor; + u32 chip_device; + u32 subsys_vendor; + u32 subsys_device; + u32 px_quirk_flags; +}; + struct amdgpu_atpx_functions { bool px_params; bool power_cntl; @@ -35,6 +45,7 @@ struct amdgpu_atpx { static struct amdgpu_atpx_priv { bool atpx_detected; bool bridge_pm_usable; + unsigned int quirks; /* handle for device - and atpx */ acpi_handle dhandle; acpi_handle other_handle; @@ -205,13 +216,19 @@ static int amdgpu_atpx_validate(struct amdgpu_atpx *atpx) atpx->is_hybrid = false; if (valid_bits & ATPX_MS_HYBRID_GFX_SUPPORTED) { - printk("ATPX Hybrid Graphics\n"); - /* - * Disable legacy PM methods only when pcie port PM is usable, - * otherwise the device might fail to power off or power on. - */ - atpx->functions.power_cntl = !amdgpu_atpx_priv.bridge_pm_usable; - atpx->is_hybrid = true; + if (amdgpu_atpx_priv.quirks & AMDGPU_PX_QUIRK_FORCE_ATPX) { + printk("ATPX Hybrid Graphics, forcing to ATPX\n"); + atpx->functions.power_cntl = true; + atpx->is_hybrid = false; + } else { + printk("ATPX Hybrid Graphics\n"); + /* + * Disable legacy PM methods only when pcie port PM is usable, + * otherwise the device might fail to power off or power on. + */ + atpx->functions.power_cntl = !amdgpu_atpx_priv.bridge_pm_usable; + atpx->is_hybrid = true; + } } atpx->dgpu_req_power_for_displays = false; @@ -547,6 +564,30 @@ static const struct vga_switcheroo_handler amdgpu_atpx_handler = { .get_client_id = amdgpu_atpx_get_client_id, }; +static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { + /* HG _PR3 doesn't seem to work on this A+A weston board */ + { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0, 0, 0, 0, 0 }, +}; + +static void amdgpu_atpx_get_quirks(struct pci_dev *pdev) +{ + const struct amdgpu_px_quirk *p = amdgpu_px_quirk_list; + + /* Apply PX quirks */ + while (p && p->chip_device != 0) { + if (pdev->vendor == p->chip_vendor && + pdev->device == p->chip_device && + pdev->subsystem_vendor == p->subsys_vendor && + pdev->subsystem_device == p->subsys_device) { + amdgpu_atpx_priv.quirks |= p->px_quirk_flags; + break; + } + ++p; + } +} + /** * amdgpu_atpx_detect - detect whether we have PX * @@ -570,6 +611,7 @@ static bool amdgpu_atpx_detect(void) parent_pdev = pci_upstream_bridge(pdev); d3_supported |= parent_pdev && parent_pdev->bridge_d3; + amdgpu_atpx_get_quirks(pdev); } while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) { @@ -579,6 +621,7 @@ static bool amdgpu_atpx_detect(void) parent_pdev = pci_upstream_bridge(pdev); d3_supported |= parent_pdev && parent_pdev->bridge_d3; + amdgpu_atpx_get_quirks(pdev); } if (has_atpx && vga_count == 2) { -- GitLab From 3a58e8489cf51772810cb7d1e20147e21c255c69 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 22 Jan 2018 23:13:32 -0500 Subject: [PATCH 0051/1834] drm/amdgpu: Avoid leaking PM domain on driver unbind (v2) commit 458d876eb869d5a88b53074c6c271b8b9adc0f07 upstream. We only support vga_switcheroo and runtime pm on PX/HG systems so forcing runpm to 1 doesn't do anything useful anyway. Only call vga_switcheroo_init_domain_pm_ops() for PX/HG so that the cleanup path is correct as well. This mirrors what radeon does as well. v2: rework the patch originally sent by Lukas (Alex) Acked-by: Lukas Wunner Reported-by: Lukas Wunner Signed-off-by: Alex Deucher Signed-off-by: Lukas Wunner (v1) Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index ce9797b6f9c7..50f18f666d67 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1678,8 +1678,6 @@ int amdgpu_device_init(struct amdgpu_device *adev, * ignore it */ vga_client_register(adev->pdev, adev, NULL, amdgpu_vga_set_decode); - if (amdgpu_runtime_pm == 1) - runtime = true; if (amdgpu_device_is_px(ddev)) runtime = true; vga_switcheroo_register_client(adev->pdev, &amdgpu_switcheroo_ops, runtime); -- GitLab From 65aeceb58fe4e49dc1e4a581296e21cc5186ce6d Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Thu, 8 Feb 2018 17:46:01 +0800 Subject: [PATCH 0052/1834] drm/amdgpu: add new device to use atpx quirk commit 6e59de2048eb375a9bfcd39461ef841cd2a78962 upstream. The affected system (0x0813) is pretty similar to another one (0x0812), it also needs to use ATPX power control. Signed-off-by: Kai-Heng Feng Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index d451c40def0d..0e8f8972a160 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -568,6 +568,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { /* HG _PR3 doesn't seem to work on this A+A weston board */ { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0, 0, 0, 0, 0 }, }; -- GitLab From febf108e6c82d981ac6306978129dccb75db8b64 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 26 Feb 2018 10:56:45 -0800 Subject: [PATCH 0053/1834] binder: add missing binder_unlock() When commit 4be5a2810489 ("binder: check for binder_thread allocation failure in binder_poll()") was applied to 4.4-stable and 4.9-stable it was forgotten to release the global binder lock in the new error path. The global binder lock wasn't removed until v4.14, by commit a60b890f607d ("binder: remove global binder lock"). Fix the new error path to release the lock. Reported-by: Guenter Roeck Signed-off-by: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 3b6ac80b2127..49199bd2ab93 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2628,8 +2628,10 @@ static unsigned int binder_poll(struct file *filp, binder_lock(__func__); thread = binder_get_thread(proc); - if (!thread) + if (!thread) { + binder_unlock(__func__); return POLLERR; + } wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo) && thread->return_error == BR_OK; -- GitLab From f2915986f892dfb6201dfc821cee5696be1c9b86 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 26 Feb 2018 10:17:15 -0800 Subject: [PATCH 0054/1834] X.509: fix NULL dereference when restricting key with unsupported_sig commit 4b34968e77ad09628cfb3c4a7daf2adc2cefc6e8 upstream. The asymmetric key type allows an X.509 certificate to be added even if its signature's hash algorithm is not available in the crypto API. In that case 'payload.data[asym_auth]' will be NULL. But the key restriction code failed to check for this case before trying to use the signature, resulting in a NULL pointer dereference in key_or_keyring_common() or in restrict_link_by_signature(). Fix this by returning -ENOPKG when the signature is unsupported. Reproducer when all the CONFIG_CRYPTO_SHA512* options are disabled and keyctl has support for the 'restrict_keyring' command: keyctl new_session keyctl restrict_keyring @s asymmetric builtin_trusted openssl req -new -sha512 -x509 -batch -nodes -outform der \ | keyctl padd asymmetric desc @s Fixes: a511e1af8b12 ("KEYS: Move the point of trust determination to __key_link()") Cc: # v4.7+ Signed-off-by: Eric Biggers Signed-off-by: David Howells Signed-off-by: Greg Kroah-Hartman --- crypto/asymmetric_keys/restrict.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crypto/asymmetric_keys/restrict.c b/crypto/asymmetric_keys/restrict.c index 19d1afb9890f..09b1374dc619 100644 --- a/crypto/asymmetric_keys/restrict.c +++ b/crypto/asymmetric_keys/restrict.c @@ -66,8 +66,9 @@ __setup("ca_keys=", ca_keys_setup); * * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a * matching parent certificate in the trusted list, -EKEYREJECTED if the - * signature check fails or the key is blacklisted and some other error if - * there is a matching certificate but the signature check cannot be performed. + * signature check fails or the key is blacklisted, -ENOPKG if the signature + * uses unsupported crypto, or some other error if there is a matching + * certificate but the signature check cannot be performed. */ int restrict_link_by_signature(struct key *trust_keyring, const struct key_type *type, @@ -86,6 +87,8 @@ int restrict_link_by_signature(struct key *trust_keyring, return -EOPNOTSUPP; sig = payload->data[asym_auth]; + if (!sig) + return -ENOPKG; if (!sig->auth_ids[0] && !sig->auth_ids[1]) return -ENOKEY; -- GitLab From f2562ed549054d3f7dfcc17ac17975440a33dcde Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Fri, 23 Feb 2018 14:05:27 -0800 Subject: [PATCH 0055/1834] mm: avoid spurious 'bad pmd' warning messages commit d0f0931de936a0a468d7e59284d39581c16d3a73 upstream. When the pmd_devmap() checks were added by 5c7fb56e5e3f ("mm, dax: dax-pmd vs thp-pmd vs hugetlbfs-pmd") to add better support for DAX huge pages, they were all added to the end of if() statements after existing pmd_trans_huge() checks. So, things like: - if (pmd_trans_huge(*pmd)) + if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) When further checks were added after pmd_trans_unstable() checks by commit 7267ec008b5c ("mm: postpone page table allocation until we have page to map") they were also added at the end of the conditional: + if (pmd_trans_unstable(fe->pmd) || pmd_devmap(*fe->pmd)) This ordering is fine for pmd_trans_huge(), but doesn't work for pmd_trans_unstable(). This is because DAX huge pages trip the bad_pmd() check inside of pmd_none_or_trans_huge_or_clear_bad() (called by pmd_trans_unstable()), which prints out a warning and returns 1. So, we do end up doing the right thing, but only after spamming dmesg with suspicious looking messages: mm/pgtable-generic.c:39: bad pmd ffff8808daa49b88(84000001006000a5) Reorder these checks in a helper so that pmd_devmap() is checked first, avoiding the error messages, and add a comment explaining why the ordering is important. Fixes: commit 7267ec008b5c ("mm: postpone page table allocation until we have page to map") Link: http://lkml.kernel.org/r/20170522215749.23516-1-ross.zwisler@linux.intel.com Signed-off-by: Ross Zwisler Reviewed-by: Jan Kara Cc: Pawel Lebioda Cc: "Darrick J. Wong" Cc: Alexander Viro Cc: Christoph Hellwig Cc: Dan Williams Cc: Dave Hansen Cc: Matthew Wilcox Cc: "Kirill A . Shutemov" Cc: Dave Jiang Cc: Xiong Zhou Cc: Eryu Guan Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/memory.c | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index e2e68767a373..d2db2c4eb0a4 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2848,6 +2848,17 @@ static int __do_fault(struct fault_env *fe, pgoff_t pgoff, return ret; } +/* + * The ordering of these checks is important for pmds with _PAGE_DEVMAP set. + * If we check pmd_trans_unstable() first we will trip the bad_pmd() check + * inside of pmd_none_or_trans_huge_or_clear_bad(). This will end up correctly + * returning 1 but not before it spams dmesg with the pmd_clear_bad() output. + */ +static int pmd_devmap_trans_unstable(pmd_t *pmd) +{ + return pmd_devmap(*pmd) || pmd_trans_unstable(pmd); +} + static int pte_alloc_one_map(struct fault_env *fe) { struct vm_area_struct *vma = fe->vma; @@ -2871,18 +2882,27 @@ static int pte_alloc_one_map(struct fault_env *fe) map_pte: /* * If a huge pmd materialized under us just retry later. Use - * pmd_trans_unstable() instead of pmd_trans_huge() to ensure the pmd - * didn't become pmd_trans_huge under us and then back to pmd_none, as - * a result of MADV_DONTNEED running immediately after a huge pmd fault - * in a different thread of this mm, in turn leading to a misleading - * pmd_trans_huge() retval. All we have to ensure is that it is a - * regular pmd that we can walk with pte_offset_map() and we can do that - * through an atomic read in C, which is what pmd_trans_unstable() - * provides. + * pmd_trans_unstable() via pmd_devmap_trans_unstable() instead of + * pmd_trans_huge() to ensure the pmd didn't become pmd_trans_huge + * under us and then back to pmd_none, as a result of MADV_DONTNEED + * running immediately after a huge pmd fault in a different thread of + * this mm, in turn leading to a misleading pmd_trans_huge() retval. + * All we have to ensure is that it is a regular pmd that we can walk + * with pte_offset_map() and we can do that through an atomic read in + * C, which is what pmd_trans_unstable() provides. */ - if (pmd_trans_unstable(fe->pmd) || pmd_devmap(*fe->pmd)) + if (pmd_devmap_trans_unstable(fe->pmd)) return VM_FAULT_NOPAGE; + /* + * At this point we know that our vmf->pmd points to a page of ptes + * and it cannot become pmd_none(), pmd_devmap() or pmd_trans_huge() + * for the duration of the fault. If a racing MADV_DONTNEED runs and + * we zap the ptes pointed to by our vmf->pmd, the vmf->ptl will still + * be valid and we will re-check to make sure the vmf->pte isn't + * pte_none() under vmf->ptl protection when we return to + * alloc_set_pte(). + */ fe->pte = pte_offset_map_lock(vma->vm_mm, fe->pmd, fe->address, &fe->ptl); return 0; @@ -3456,7 +3476,7 @@ static int handle_pte_fault(struct fault_env *fe) fe->pte = NULL; } else { /* See comment in pte_alloc_one_map() */ - if (pmd_trans_unstable(fe->pmd) || pmd_devmap(*fe->pmd)) + if (pmd_devmap_trans_unstable(fe->pmd)) return 0; /* * A regular pmd is established and it can't morph into a huge -- GitLab From f06c2c659ccad2c5da074311a6980cd888ea2779 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 23 Feb 2018 14:05:33 -0800 Subject: [PATCH 0056/1834] fs/dax.c: fix inefficiency in dax_writeback_mapping_range() commit 1eb643d02b21412e603b42cdd96010a2ac31c05f upstream. dax_writeback_mapping_range() fails to update iteration index when searching radix tree for entries needing cache flushing. Thus each pagevec worth of entries is searched starting from the start which is inefficient and prone to livelocks. Update index properly. Link: http://lkml.kernel.org/r/20170619124531.21491-1-jack@suse.cz Fixes: 9973c98ecfda3 ("dax: add support for fsync/sync") Signed-off-by: Jan Kara Reviewed-by: Ross Zwisler Cc: Dan Williams Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/dax.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/dax.c b/fs/dax.c index 800748f10b3d..71f87d74afe1 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -785,6 +785,7 @@ int dax_writeback_mapping_range(struct address_space *mapping, if (ret < 0) return ret; } + start_index = indices[pvec.nr - 1] + 1; } return 0; } -- GitLab From 29c969c3031b20595f6c3a0d16348cf6d11d8a13 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:05:38 -0800 Subject: [PATCH 0057/1834] libnvdimm: fix integer overflow static analysis warning commit 58738c495e15badd2015e19ff41f1f1ed55200bc upstream. Dan reports: The patch 62232e45f4a2: "libnvdimm: control (ioctl) messages for nvdimm_bus and nvdimm devices" from Jun 8, 2015, leads to the following static checker warning: drivers/nvdimm/bus.c:1018 __nd_ioctl() warn: integer overflows 'buf_len' From a casual review, this seems like it might be a real bug. On the first iteration we load some data into in_env[]. On the second iteration we read a use controlled "in_size" from nd_cmd_in_size(). It can go up to UINT_MAX - 1. A high number means we will fill the whole in_env[] buffer. But we potentially keep looping and adding more to in_len so now it can be any value. It simple enough to change, but it feels weird that we keep looping even though in_env is totally full. Shouldn't we just return an error if we don't have space for desc->in_num. We keep looping because the size of the total input is allowed to be bigger than the 'envelope' which is a subset of the payload that tells us how much data to expect. For safety explicitly check that buf_len does not overflow which is what the checker flagged. Cc: Fixes: 62232e45f4a2: "libnvdimm: control (ioctl) messages for nvdimm_bus..." Reported-by: Dan Carpenter Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/nvdimm/bus.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 0392eb8a0dea..8311a93cabd8 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -812,16 +812,17 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, int read_only, unsigned int ioctl_cmd, unsigned long arg) { struct nvdimm_bus_descriptor *nd_desc = nvdimm_bus->nd_desc; - size_t buf_len = 0, in_len = 0, out_len = 0; static char out_env[ND_CMD_MAX_ENVELOPE]; static char in_env[ND_CMD_MAX_ENVELOPE]; const struct nd_cmd_desc *desc = NULL; unsigned int cmd = _IOC_NR(ioctl_cmd); void __user *p = (void __user *) arg; struct device *dev = &nvdimm_bus->dev; - struct nd_cmd_pkg pkg; const char *cmd_name, *dimm_name; + u32 in_len = 0, out_len = 0; unsigned long cmd_mask; + struct nd_cmd_pkg pkg; + u64 buf_len = 0; void *buf; int rc, i; @@ -882,7 +883,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, } if (cmd == ND_CMD_CALL) { - dev_dbg(dev, "%s:%s, idx: %llu, in: %zu, out: %zu, len %zu\n", + dev_dbg(dev, "%s:%s, idx: %llu, in: %u, out: %u, len %llu\n", __func__, dimm_name, pkg.nd_command, in_len, out_len, buf_len); @@ -912,9 +913,9 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, out_len += out_size; } - buf_len = out_len + in_len; + buf_len = (u64) out_len + (u64) in_len; if (buf_len > ND_IOCTL_MAX_BUFLEN) { - dev_dbg(dev, "%s:%s cmd: %s buf_len: %zu > %d\n", __func__, + dev_dbg(dev, "%s:%s cmd: %s buf_len: %llu > %d\n", __func__, dimm_name, cmd_name, buf_len, ND_IOCTL_MAX_BUFLEN); return -EINVAL; -- GitLab From be38759eb2d697f9e907eddfbb8d33aa26d37acc Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:05:43 -0800 Subject: [PATCH 0058/1834] device-dax: implement ->split() to catch invalid munmap attempts commit 9702cffdbf2129516db679e4467db81e1cd287da upstream. Similar to how device-dax enforces that the 'address', 'offset', and 'len' parameters to mmap() be aligned to the device's fundamental alignment, the same constraints apply to munmap(). Implement ->split() to fail munmap calls that violate the alignment constraint. Otherwise, we later fail VM_BUG_ON checks in the unmap_page_range() path with crash signatures of the form: vma ffff8800b60c8a88 start 00007f88c0000000 end 00007f88c0e00000 next (null) prev (null) mm ffff8800b61150c0 prot 8000000000000027 anon_vma (null) vm_ops ffffffffa0091240 pgoff 0 file ffff8800b638ef80 private_data (null) flags: 0x380000fb(read|write|shared|mayread|maywrite|mayexec|mayshare|softdirty|mixedmap|hugepage) ------------[ cut here ]------------ kernel BUG at mm/huge_memory.c:2014! [..] RIP: 0010:__split_huge_pud+0x12a/0x180 [..] Call Trace: unmap_page_range+0x245/0xa40 ? __vma_adjust+0x301/0x990 unmap_vmas+0x4c/0xa0 unmap_region+0xae/0x120 ? __vma_rb_erase+0x11a/0x230 do_munmap+0x276/0x410 vm_munmap+0x6a/0xa0 SyS_munmap+0x1d/0x30 Link: http://lkml.kernel.org/r/151130418681.4029.7118245855057952010.stgit@dwillia2-desk3.amr.corp.intel.com Fixes: dee410792419 ("/dev/dax, core: file operations and dax-mmap") Signed-off-by: Dan Williams Reported-by: Jeff Moyer Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/dax/dax.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 40be3747724d..473b44c008dd 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -453,9 +453,21 @@ static int dax_dev_pmd_fault(struct vm_area_struct *vma, unsigned long addr, return rc; } +static int dax_dev_split(struct vm_area_struct *vma, unsigned long addr) +{ + struct file *filp = vma->vm_file; + struct dax_dev *dax_dev = filp->private_data; + struct dax_region *dax_region = dax_dev->region; + + if (!IS_ALIGNED(addr, dax_region->align)) + return -EINVAL; + return 0; +} + static const struct vm_operations_struct dax_dev_vm_ops = { .fault = dax_dev_fault, .pmd_fault = dax_dev_pmd_fault, + .split = dax_dev_split, }; static int dax_mmap(struct file *filp, struct vm_area_struct *vma) -- GitLab From b29ea3c0af9e6947f9384c25c5e4d8f34d9018b3 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:05:49 -0800 Subject: [PATCH 0059/1834] mm: introduce get_user_pages_longterm commit 2bb6d2837083de722bfdc369cb0d76ce188dd9b4 upstream. Patch series "introduce get_user_pages_longterm()", v2. Here is a new get_user_pages api for cases where a driver intends to keep an elevated page count indefinitely. This is distinct from usages like iov_iter_get_pages where the elevated page counts are transient. The iov_iter_get_pages cases immediately turn around and submit the pages to a device driver which will put_page when the i/o operation completes (under kernel control). In the longterm case userspace is responsible for dropping the page reference at some undefined point in the future. This is untenable for filesystem-dax case where the filesystem is in control of the lifetime of the block / page and needs reasonable limits on how long it can wait for pages in a mapping to become idle. Fixing filesystems to actually wait for dax pages to be idle before blocks from a truncate/hole-punch operation are repurposed is saved for a later patch series. Also, allowing longterm registration of dax mappings is a future patch series that introduces a "map with lease" semantic where the kernel can revoke a lease and force userspace to drop its page references. I have also tagged these for -stable to purposely break cases that might assume that longterm memory registrations for filesystem-dax mappings were supported by the kernel. The behavior regression this policy change implies is one of the reasons we maintain the "dax enabled. Warning: EXPERIMENTAL, use at your own risk" notification when mounting a filesystem in dax mode. It is worth noting the device-dax interface does not suffer the same constraints since it does not support file space management operations like hole-punch. This patch (of 4): Until there is a solution to the dma-to-dax vs truncate problem it is not safe to allow long standing memory registrations against filesytem-dax vmas. Device-dax vmas do not have this problem and are explicitly allowed. This is temporary until a "memory registration with layout-lease" mechanism can be implemented for the affected sub-systems (RDMA and V4L2). [akpm@linux-foundation.org: use kcalloc()] Link: http://lkml.kernel.org/r/151068939435.7446.13560129395419350737.stgit@dwillia2-desk3.amr.corp.intel.com Fixes: 3565fce3a659 ("mm, x86: get_user_pages() for dax mappings") Signed-off-by: Dan Williams Suggested-by: Christoph Hellwig Cc: Doug Ledford Cc: Hal Rosenstock Cc: Inki Dae Cc: Jan Kara Cc: Jason Gunthorpe Cc: Jeff Moyer Cc: Joonyoung Shim Cc: Kyungmin Park Cc: Mauro Carvalho Chehab Cc: Mel Gorman Cc: Ross Zwisler Cc: Sean Hefty Cc: Seung-Woo Kim Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/dax.h | 5 ---- include/linux/fs.h | 20 ++++++++++++++ include/linux/mm.h | 13 +++++++++ mm/gup.c | 64 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 5 deletions(-) diff --git a/include/linux/dax.h b/include/linux/dax.h index add6c4bc568f..ed9cf2f5cd06 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -61,11 +61,6 @@ static inline int dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *); #define dax_mkwrite(vma, vmf, gb) dax_fault(vma, vmf, gb) -static inline bool vma_is_dax(struct vm_area_struct *vma) -{ - return vma->vm_file && IS_DAX(vma->vm_file->f_mapping->host); -} - static inline bool dax_mapping(struct address_space *mapping) { return mapping->host && IS_DAX(mapping->host); diff --git a/include/linux/fs.h b/include/linux/fs.h index d705ae084edd..745ea1b2e02c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -3033,6 +3034,25 @@ static inline bool io_is_direct(struct file *filp) return (filp->f_flags & O_DIRECT) || IS_DAX(filp->f_mapping->host); } +static inline bool vma_is_dax(struct vm_area_struct *vma) +{ + return vma->vm_file && IS_DAX(vma->vm_file->f_mapping->host); +} + +static inline bool vma_is_fsdax(struct vm_area_struct *vma) +{ + struct inode *inode; + + if (!vma->vm_file) + return false; + if (!vma_is_dax(vma)) + return false; + inode = file_inode(vma->vm_file); + if (inode->i_mode == S_IFCHR) + return false; /* device-dax */ + return true; +} + static inline int iocb_flags(struct file *file) { int res = 0; diff --git a/include/linux/mm.h b/include/linux/mm.h index 2217e2f18247..8e506783631b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1288,6 +1288,19 @@ long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, struct page **pages, unsigned int gup_flags); long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, struct page **pages, unsigned int gup_flags); +#ifdef CONFIG_FS_DAX +long get_user_pages_longterm(unsigned long start, unsigned long nr_pages, + unsigned int gup_flags, struct page **pages, + struct vm_area_struct **vmas); +#else +static inline long get_user_pages_longterm(unsigned long start, + unsigned long nr_pages, unsigned int gup_flags, + struct page **pages, struct vm_area_struct **vmas) +{ + return get_user_pages(start, nr_pages, gup_flags, pages, vmas); +} +#endif /* CONFIG_FS_DAX */ + int get_user_pages_fast(unsigned long start, int nr_pages, int write, struct page **pages); diff --git a/mm/gup.c b/mm/gup.c index c63a0341ae38..6c3b4e822946 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -982,6 +982,70 @@ long get_user_pages(unsigned long start, unsigned long nr_pages, } EXPORT_SYMBOL(get_user_pages); +#ifdef CONFIG_FS_DAX +/* + * This is the same as get_user_pages() in that it assumes we are + * operating on the current task's mm, but it goes further to validate + * that the vmas associated with the address range are suitable for + * longterm elevated page reference counts. For example, filesystem-dax + * mappings are subject to the lifetime enforced by the filesystem and + * we need guarantees that longterm users like RDMA and V4L2 only + * establish mappings that have a kernel enforced revocation mechanism. + * + * "longterm" == userspace controlled elevated page count lifetime. + * Contrast this to iov_iter_get_pages() usages which are transient. + */ +long get_user_pages_longterm(unsigned long start, unsigned long nr_pages, + unsigned int gup_flags, struct page **pages, + struct vm_area_struct **vmas_arg) +{ + struct vm_area_struct **vmas = vmas_arg; + struct vm_area_struct *vma_prev = NULL; + long rc, i; + + if (!pages) + return -EINVAL; + + if (!vmas) { + vmas = kcalloc(nr_pages, sizeof(struct vm_area_struct *), + GFP_KERNEL); + if (!vmas) + return -ENOMEM; + } + + rc = get_user_pages(start, nr_pages, gup_flags, pages, vmas); + + for (i = 0; i < rc; i++) { + struct vm_area_struct *vma = vmas[i]; + + if (vma == vma_prev) + continue; + + vma_prev = vma; + + if (vma_is_fsdax(vma)) + break; + } + + /* + * Either get_user_pages() failed, or the vma validation + * succeeded, in either case we don't need to put_page() before + * returning. + */ + if (i >= rc) + goto out; + + for (i = 0; i < rc; i++) + put_page(pages[i]); + rc = -EOPNOTSUPP; +out: + if (vmas != vmas_arg) + kfree(vmas); + return rc; +} +EXPORT_SYMBOL(get_user_pages_longterm); +#endif /* CONFIG_FS_DAX */ + /** * populate_vma_page_range() - populate a range of pages in the vma. * @vma: target vma -- GitLab From 53dfce305929bc3c7f4018b7b18027b74284802c Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:05:54 -0800 Subject: [PATCH 0060/1834] v4l2: disable filesystem-dax mapping support commit b70131de648c2b997d22f4653934438013f407a1 upstream. V4L2 memory registrations are incompatible with filesystem-dax that needs the ability to revoke dma access to a mapping at will, or otherwise allow the kernel to wait for completion of DMA. The filesystem-dax implementation breaks the traditional solution of truncate of active file backed mappings since there is no page-cache page we can orphan to sustain ongoing DMA. If v4l2 wants to support long lived DMA mappings it needs to arrange to hold a file lease or use some other mechanism so that the kernel can coordinate revoking DMA access when the filesystem needs to truncate mappings. Link: http://lkml.kernel.org/r/151068940499.7446.12846708245365671207.stgit@dwillia2-desk3.amr.corp.intel.com Fixes: 3565fce3a659 ("mm, x86: get_user_pages() for dax mappings") Signed-off-by: Dan Williams Reported-by: Jan Kara Reviewed-by: Jan Kara Cc: Mauro Carvalho Chehab Cc: Christoph Hellwig Cc: Doug Ledford Cc: Hal Rosenstock Cc: Inki Dae Cc: Jason Gunthorpe Cc: Jeff Moyer Cc: Joonyoung Shim Cc: Kyungmin Park Cc: Mel Gorman Cc: Ross Zwisler Cc: Sean Hefty Cc: Seung-Woo Kim Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/videobuf-dma-sg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 1db0af6c7f94..b6189a4958c5 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -185,12 +185,13 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma, dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n", data, size, dma->nr_pages); - err = get_user_pages(data & PAGE_MASK, dma->nr_pages, + err = get_user_pages_longterm(data & PAGE_MASK, dma->nr_pages, flags, dma->pages, NULL); if (err != dma->nr_pages) { dma->nr_pages = (err >= 0) ? err : 0; - dprintk(1, "get_user_pages: err=%d [%d]\n", err, dma->nr_pages); + dprintk(1, "get_user_pages_longterm: err=%d [%d]\n", err, + dma->nr_pages); return err < 0 ? err : -EINVAL; } return 0; -- GitLab From 00a6e639b58d23c0b6e36bb44b117afd2e245f52 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:06:00 -0800 Subject: [PATCH 0061/1834] IB/core: disable memory registration of filesystem-dax vmas commit 5f1d43de54164dcfb9bfa542fcc92c1e1a1b6c1d upstream. Until there is a solution to the dma-to-dax vs truncate problem it is not safe to allow RDMA to create long standing memory registrations against filesytem-dax vmas. Link: http://lkml.kernel.org/r/151068941011.7446.7766030590347262502.stgit@dwillia2-desk3.amr.corp.intel.com Fixes: 3565fce3a659 ("mm, x86: get_user_pages() for dax mappings") Signed-off-by: Dan Williams Reported-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Acked-by: Jason Gunthorpe Acked-by: Doug Ledford Cc: Sean Hefty Cc: Hal Rosenstock Cc: Jeff Moyer Cc: Ross Zwisler Cc: Inki Dae Cc: Jan Kara Cc: Joonyoung Shim Cc: Kyungmin Park Cc: Mauro Carvalho Chehab Cc: Mel Gorman Cc: Seung-Woo Kim Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/umem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index c22fde6207d1..8e973a2993a6 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -193,7 +193,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, sg_list_start = umem->sg_head.sgl; while (npages) { - ret = get_user_pages(cur_base, + ret = get_user_pages_longterm(cur_base, min_t(unsigned long, npages, PAGE_SIZE / sizeof (struct page *)), gup_flags, page_list, vma_list); -- GitLab From 807e3365895ca847749864c482d95c0ec1c89461 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:06:05 -0800 Subject: [PATCH 0062/1834] libnvdimm, dax: fix 1GB-aligned namespaces vs physical misalignment commit 41fce90f26333c4fa82e8e43b9ace86c4e8a0120 upstream. The following namespace configuration attempt: # ndctl create-namespace -e namespace0.0 -m devdax -a 1G -f libndctl: ndctl_dax_enable: dax0.1: failed to enable Error: namespace0.0: failed to enable failed to reconfigure namespace: No such device or address ...fails when the backing memory range is not physically aligned to 1G: # cat /proc/iomem | grep Persistent 210000000-30fffffff : Persistent Memory (legacy) In the above example the 4G persistent memory range starts and ends on a 256MB boundary. We handle this case correctly when needing to handle cases that violate section alignment (128MB) collisions against "System RAM", and we simply need to extend that padding/truncation for the 1GB alignment use case. Cc: Fixes: 315c562536c4 ("libnvdimm, pfn: add 'align' attribute...") Reported-and-tested-by: Jane Chu Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/nvdimm/pfn_devs.c | 15 ++++++++++++--- include/linux/kernel.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index 42abdd2391c9..d6aa59ca68b9 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -563,6 +563,12 @@ static struct vmem_altmap *__nvdimm_setup_pfn(struct nd_pfn *nd_pfn, return altmap; } +static u64 phys_pmem_align_down(struct nd_pfn *nd_pfn, u64 phys) +{ + return min_t(u64, PHYS_SECTION_ALIGN_DOWN(phys), + ALIGN_DOWN(phys, nd_pfn->align)); +} + static int nd_pfn_init(struct nd_pfn *nd_pfn) { u32 dax_label_reserve = is_nd_dax(&nd_pfn->dev) ? SZ_128K : 0; @@ -618,13 +624,16 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) start = nsio->res.start; size = PHYS_SECTION_ALIGN_UP(start + size) - start; if (region_intersects(start, size, IORESOURCE_SYSTEM_RAM, - IORES_DESC_NONE) == REGION_MIXED) { + IORES_DESC_NONE) == REGION_MIXED + || !IS_ALIGNED(start + resource_size(&nsio->res), + nd_pfn->align)) { size = resource_size(&nsio->res); - end_trunc = start + size - PHYS_SECTION_ALIGN_DOWN(start + size); + end_trunc = start + size - phys_pmem_align_down(nd_pfn, + start + size); } if (start_pad + end_trunc) - dev_info(&nd_pfn->dev, "%s section collision, truncate %d bytes\n", + dev_info(&nd_pfn->dev, "%s alignment collision, truncate %d bytes\n", dev_name(&ndns->dev), start_pad + end_trunc); /* diff --git a/include/linux/kernel.h b/include/linux/kernel.h index bc6ed52a39b9..61054f12be7c 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -46,6 +46,7 @@ #define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) #define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) +#define ALIGN_DOWN(x, a) __ALIGN_KERNEL((x) - ((a) - 1), (a)) #define __ALIGN_MASK(x, mask) __ALIGN_KERNEL_MASK((x), (mask)) #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) #define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) -- GitLab From 8f7cf88d59f0026af8d4c9fe0a14a445ba499d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=2E=20Sch=C3=B6nherr?= Date: Fri, 23 Feb 2018 14:06:10 -0800 Subject: [PATCH 0063/1834] mm: Fix devm_memremap_pages() collision handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 77dd66a3c67c93ab401ccc15efff25578be281fd upstream. If devm_memremap_pages() detects a collision while adding entries to the radix-tree, we call pgmap_radix_release(). Unfortunately, the function removes *all* entries for the range -- including the entries that caused the collision in the first place. Modify pgmap_radix_release() to take an additional argument to indicate where to stop, so that only newly added entries are removed from the tree. Cc: Fixes: 9476df7d80df ("mm: introduce find_dev_pagemap()") Signed-off-by: Jan H. Schönherr Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- kernel/memremap.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kernel/memremap.c b/kernel/memremap.c index 426547a21a0c..f61a8c387c3e 100644 --- a/kernel/memremap.c +++ b/kernel/memremap.c @@ -194,7 +194,7 @@ void put_zone_device_page(struct page *page) } EXPORT_SYMBOL(put_zone_device_page); -static void pgmap_radix_release(struct resource *res) +static void pgmap_radix_release(struct resource *res, resource_size_t end_key) { resource_size_t key, align_start, align_size, align_end; @@ -203,8 +203,11 @@ static void pgmap_radix_release(struct resource *res) align_end = align_start + align_size - 1; mutex_lock(&pgmap_lock); - for (key = res->start; key <= res->end; key += SECTION_SIZE) + for (key = res->start; key <= res->end; key += SECTION_SIZE) { + if (key >= end_key) + break; radix_tree_delete(&pgmap_radix, key >> PA_SECTION_SHIFT); + } mutex_unlock(&pgmap_lock); } @@ -255,7 +258,7 @@ static void devm_memremap_pages_release(struct device *dev, void *data) unlock_device_hotplug(); untrack_pfn(NULL, PHYS_PFN(align_start), align_size); - pgmap_radix_release(res); + pgmap_radix_release(res, -1); dev_WARN_ONCE(dev, pgmap->altmap && pgmap->altmap->alloc, "%s: failed to free all reserved pages\n", __func__); } @@ -289,7 +292,7 @@ struct dev_pagemap *find_dev_pagemap(resource_size_t phys) void *devm_memremap_pages(struct device *dev, struct resource *res, struct percpu_ref *ref, struct vmem_altmap *altmap) { - resource_size_t key, align_start, align_size, align_end; + resource_size_t key = 0, align_start, align_size, align_end; pgprot_t pgprot = PAGE_KERNEL; struct dev_pagemap *pgmap; struct page_map *page_map; @@ -392,7 +395,7 @@ void *devm_memremap_pages(struct device *dev, struct resource *res, untrack_pfn(NULL, PHYS_PFN(align_start), align_size); err_pfn_remap: err_radix: - pgmap_radix_release(res); + pgmap_radix_release(res, key); devres_free(page_map); return ERR_PTR(error); } -- GitLab From 78b1cb3fe38a509dc0fdbdb52c742d4630db7502 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:06:16 -0800 Subject: [PATCH 0064/1834] mm: fail get_vaddr_frames() for filesystem-dax mappings commit b7f0554a56f21fb3e636a627450a9add030889be upstream. Until there is a solution to the dma-to-dax vs truncate problem it is not safe to allow V4L2, Exynos, and other frame vector users to create long standing / irrevocable memory registrations against filesytem-dax vmas. [dan.j.williams@intel.com: add comment for vma_is_fsdax() check in get_vaddr_frames(), per Jan] Link: http://lkml.kernel.org/r/151197874035.26211.4061781453123083667.stgit@dwillia2-desk3.amr.corp.intel.com Link: http://lkml.kernel.org/r/151068939985.7446.15684639617389154187.stgit@dwillia2-desk3.amr.corp.intel.com Fixes: 3565fce3a659 ("mm, x86: get_user_pages() for dax mappings") Signed-off-by: Dan Williams Reviewed-by: Jan Kara Cc: Inki Dae Cc: Seung-Woo Kim Cc: Joonyoung Shim Cc: Kyungmin Park Cc: Mauro Carvalho Chehab Cc: Mel Gorman Cc: Vlastimil Babka Cc: Christoph Hellwig Cc: Doug Ledford Cc: Hal Rosenstock Cc: Jason Gunthorpe Cc: Jeff Moyer Cc: Ross Zwisler Cc: Sean Hefty Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/frame_vector.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mm/frame_vector.c b/mm/frame_vector.c index db77dcb38afd..375a103d7a56 100644 --- a/mm/frame_vector.c +++ b/mm/frame_vector.c @@ -52,6 +52,18 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, ret = -EFAULT; goto out; } + + /* + * While get_vaddr_frames() could be used for transient (kernel + * controlled lifetime) pinning of memory pages all current + * users establish long term (userspace controlled lifetime) + * page pinning. Treat get_vaddr_frames() like + * get_user_pages_longterm() and disallow it for filesystem-dax + * mappings. + */ + if (vma_is_fsdax(vma)) + return -EOPNOTSUPP; + if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) { vec->got_ref = true; vec->is_pfns = false; -- GitLab From 22b5557f1fef4adaddfc9fe6a0cd72d0be69bef1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 23 Feb 2018 14:06:21 -0800 Subject: [PATCH 0065/1834] x86/entry/64: Clear extra registers beyond syscall arguments, to reduce speculation attack surface commit 8e1eb3fa009aa7c0b944b3c8b26b07de0efb3200 upstream. At entry userspace may have (maliciously) populated the extra registers outside the syscall calling convention with arbitrary values that could be useful in a speculative execution (Spectre style) attack. Clear these registers to minimize the kernel's attack surface. Note, this only clears the extra registers and not the unused registers for syscalls less than 6 arguments, since those registers are likely to be clobbered well before their values could be put to use under speculation. Note, Linus found that the XOR instructions can be executed with minimized cost if interleaved with the PUSH instructions, and Ingo's analysis found that R10 and R11 should be included in the register clearing beyond the typical 'extra' syscall calling convention registers. Suggested-by: Linus Torvalds Reported-by: Andi Kleen Signed-off-by: Dan Williams Cc: Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/151787988577.7847.16733592218894189003.stgit@dwillia2-desk3.amr.corp.intel.com [ Made small improvements to the changelog and the code comments. ] Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/entry/entry_64.S | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index db5009ce065a..8d7e4d48db0d 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -176,13 +176,26 @@ GLOBAL(entry_SYSCALL_64_after_swapgs) pushq %r8 /* pt_regs->r8 */ pushq %r9 /* pt_regs->r9 */ pushq %r10 /* pt_regs->r10 */ + /* + * Clear extra registers that a speculation attack might + * otherwise want to exploit. Interleave XOR with PUSH + * for better uop scheduling: + */ + xorq %r10, %r10 /* nospec r10 */ pushq %r11 /* pt_regs->r11 */ + xorq %r11, %r11 /* nospec r11 */ pushq %rbx /* pt_regs->rbx */ + xorl %ebx, %ebx /* nospec rbx */ pushq %rbp /* pt_regs->rbp */ + xorl %ebp, %ebp /* nospec rbp */ pushq %r12 /* pt_regs->r12 */ + xorq %r12, %r12 /* nospec r12 */ pushq %r13 /* pt_regs->r13 */ + xorq %r13, %r13 /* nospec r13 */ pushq %r14 /* pt_regs->r14 */ + xorq %r14, %r14 /* nospec r14 */ pushq %r15 /* pt_regs->r15 */ + xorq %r15, %r15 /* nospec r15 */ /* IRQs are off. */ movq %rsp, %rdi -- GitLab From c426a717c3c633c743bfa84af902012aa84063f4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 28 Feb 2018 10:18:34 +0100 Subject: [PATCH 0066/1834] Linux 4.9.85 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index db13b13cdcc2..77deaa395d69 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 84 +SUBLEVEL = 85 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 6e463bb69c991d1cc0e3898a66b3640cb0e432c2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 28 Feb 2018 17:17:14 +0100 Subject: [PATCH 0067/1834] Revert "binder: add missing binder_unlock()" This reverts commit febf108e6c82d981ac6306978129dccb75db8b64. There is no binder_unlock() in this branch, so this patch needs to be reverted. Cc: Guenter Roeck Cc: Eric Biggers Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 4d4fd919e944..ff367b8faece 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -4573,10 +4573,8 @@ static unsigned int binder_poll(struct file *filp, bool wait_for_proc_work; thread = binder_get_thread(proc); - if (!thread) { - binder_unlock(__func__); + if (!thread) return POLLERR; - } binder_inner_proc_lock(thread->proc); thread->looper |= BINDER_LOOPER_STATE_POLL; -- GitLab From b7ee59ba3390b5c5766abed375bc51b0fd66a2f3 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 17 Nov 2017 15:38:23 -0800 Subject: [PATCH 0068/1834] FROMLIST: kbuild: add clang-version.sh Based on gcc-version.sh, clang-version.sh prints out the correct version of clang. Bug: 62093296 Bug: 67506682 Change-Id: I399ed4cfbe30f6ac93e519abd84dd4c7cb96e32c (am from https://patchwork.kernel.org/patch/10085763/) Tested-by: Nick Desaulniers Signed-off-by: Sami Tolvanen --- scripts/clang-version.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 scripts/clang-version.sh diff --git a/scripts/clang-version.sh b/scripts/clang-version.sh new file mode 100755 index 000000000000..9780efa56980 --- /dev/null +++ b/scripts/clang-version.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# clang-version [-p] clang-command +# +# Prints the compiler version of `clang-command' in a canonical 4-digit form +# such as `0500' for clang-5.0 etc. +# +# With the -p option, prints the patchlevel as well, for example `050001' for +# clang-5.0.1 etc. +# + +if [ "$1" = "-p" ] ; then + with_patchlevel=1; + shift; +fi + +compiler="$*" + +if [ ${#compiler} -eq 0 ]; then + echo "Error: No compiler specified." + printf "Usage:\n\t$0 \n" + exit 1 +fi + +MAJOR=$(echo __clang_major__ | $compiler -E -x c - | tail -n 1) +MINOR=$(echo __clang_minor__ | $compiler -E -x c - | tail -n 1) +if [ "x$with_patchlevel" != "x" ] ; then + PATCHLEVEL=$(echo __clang_patchlevel__ | $compiler -E -x c - | tail -n 1) + printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL +else + printf "%02d%02d\\n" $MAJOR $MINOR +fi -- GitLab From 4f9dc80379bc896961c63466f4623ea0d5c50119 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 17 Nov 2017 15:37:42 -0800 Subject: [PATCH 0069/1834] FROMLIST: BACKPORT: kbuild: add __cc-ifversion and compiler-specific variants This change adds macros for testing both compiler name and version. Current cc-version, cc-ifversion etc. macros that test gcc version are left unchanged to prevent compatibility issues with existing tests. Bug: 62093296 Bug: 67506682 Change-Id: I14965fcc21dae8dfe31881b172214bf6f8a9f440 (am from https://patchwork.kernel.org/patch/10085767/) Signed-off-by: Sami Tolvanen --- scripts/Kbuild.include | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 140a0fa24f84..da69cc0c8de4 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -147,6 +147,37 @@ cc-disable-warning = $(call try-run,\ # Expands to either gcc or clang cc-name = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) +# __cc-version +# Returns compiler version +__cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/$(cc-name)-version.sh $(CC)) + +# __cc-fullversion +# Returns full compiler version +__cc-fullversion = $(shell $(CONFIG_SHELL) \ + $(srctree)/scripts/$(cc-name)-version.sh -p $(CC)) + +# __cc-ifversion +# Matches compiler name and version +# Usage: EXTRA_CFLAGS += $(call cc-if-name-version, gcc, -lt, 0402, -O1) +__cc-ifversion = $(shell [ $(cc-name) = $(1) ] && [ $(__cc-version) $(2) $(3) ] && echo $(4) || echo $(5)) + +# __cc-if-fullversion +# Matches compiler name and full version +# Usage: EXTRA_CFLAGS += $(call cc-if-name-fullversion, gcc, -lt, 040502, -O1) +__cc-if-fullversion = $(shell [ $(cc-name) = $(1) ] && [ $(__cc-fullversion) $(2) $(3) ] && echo $(4) || echo $(5)) + +# gcc-ifversion +gcc-ifversion = $(call __cc-ifversion, gcc, $(1), $(2), $(3), $(4)) + +# gcc-if-fullversion +gcc-if-fullversion = (call __cc-if-fullversion, gcc, $(1), $(2), $(3), $(4)) + +# clang-ifversion +clang-ifversion = $(call __cc-ifversion, clang, $(1), $(2), $(3), $(4)) + +# clang-if-fullversion +clang-if-fullversion = (call __cc-if-fullversion, clang, $(1), $(2), $(3), $(4)) + # cc-version cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) @@ -154,9 +185,9 @@ cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) cc-fullversion = $(shell $(CONFIG_SHELL) \ $(srctree)/scripts/gcc-version.sh -p $(CC)) -# cc-ifversion -# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) -cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) +# backward compatibility +cc-ifversion = $(gcc-ifversion) +cc-if-fullversion = $(gcc-if-fullversion) # cc-ldoption # Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) -- GitLab From 4d10cc8e3fd07f7ff77623a1551dad3ead787d26 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 13 Feb 2018 13:59:47 -0800 Subject: [PATCH 0070/1834] FROMLIST: kbuild: fix LD_DEAD_CODE_DATA_ELIMINATION Don't remove .head.text or .exitcall.exit when linking with --gc-sections, and include .init.text.* in .init.text and .init.rodata.* in .init.rodata. Bug: 62093296 Bug: 67506682 Change-Id: Ia0f9e735d04c2322dcc8bcfc94241f0551b149c4 (am from https://patchwork.kernel.org/patch/10085773/) Reviewed-by: Nicholas Piggin Signed-off-by: Sami Tolvanen --- include/asm-generic/vmlinux.lds.h | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 3a396a9cb176..d1d7d5db55b4 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -105,7 +105,7 @@ #ifdef CONFIG_FTRACE_MCOUNT_RECORD #define MCOUNT_REC() . = ALIGN(8); \ VMLINUX_SYMBOL(__start_mcount_loc) = .; \ - *(__mcount_loc) \ + KEEP(*(__mcount_loc)) \ VMLINUX_SYMBOL(__stop_mcount_loc) = .; #else #define MCOUNT_REC() @@ -139,10 +139,10 @@ #ifdef CONFIG_EVENT_TRACING #define FTRACE_EVENTS() . = ALIGN(8); \ VMLINUX_SYMBOL(__start_ftrace_events) = .; \ - *(_ftrace_events) \ + KEEP(*(_ftrace_events)) \ VMLINUX_SYMBOL(__stop_ftrace_events) = .; \ VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .; \ - *(_ftrace_enum_map) \ + KEEP(*(_ftrace_enum_map)) \ VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .; #else #define FTRACE_EVENTS() @@ -185,8 +185,8 @@ #define _OF_TABLE_1(name) \ . = ALIGN(8); \ VMLINUX_SYMBOL(__##name##_of_table) = .; \ - *(__##name##_of_table) \ - *(__##name##_of_table_end) + KEEP(*(__##name##_of_table)) \ + KEEP(*(__##name##_of_table_end)) #define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) #define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) @@ -304,28 +304,28 @@ /* PCI quirks */ \ .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ - *(.pci_fixup_early) \ + KEEP(*(.pci_fixup_early)) \ VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ - *(.pci_fixup_header) \ + KEEP(*(.pci_fixup_header)) \ VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ - *(.pci_fixup_final) \ + KEEP(*(.pci_fixup_final)) \ VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \ - *(.pci_fixup_enable) \ + KEEP(*(.pci_fixup_enable)) \ VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \ - *(.pci_fixup_resume) \ + KEEP(*(.pci_fixup_resume)) \ VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \ - *(.pci_fixup_resume_early) \ + KEEP(*(.pci_fixup_resume_early)) \ VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \ - *(.pci_fixup_suspend) \ + KEEP(*(.pci_fixup_suspend)) \ VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \ VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \ - *(.pci_fixup_suspend_late) \ + KEEP(*(.pci_fixup_suspend_late)) \ VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \ } \ \ @@ -512,7 +512,7 @@ VMLINUX_SYMBOL(__softirqentry_text_end) = .; /* Section used for early init (in .S files) */ -#define HEAD_TEXT *(.head.text) +#define HEAD_TEXT KEEP(*(.head.text)) #define HEAD_TEXT_SECTION \ .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) { \ @@ -557,7 +557,7 @@ MEM_DISCARD(init.data) \ KERNEL_CTORS() \ MCOUNT_REC() \ - *(.init.rodata) \ + *(.init.rodata .init.rodata.*) \ FTRACE_EVENTS() \ TRACE_SYSCALLS() \ KPROBE_BLACKLIST() \ @@ -575,7 +575,7 @@ EARLYCON_TABLE() #define INIT_TEXT \ - *(.init.text) \ + *(.init.text .init.text.*) \ *(.text.startup) \ MEM_DISCARD(init.text) @@ -592,7 +592,7 @@ MEM_DISCARD(exit.text) #define EXIT_CALL \ - *(.exitcall.exit) + KEEP(*(.exitcall.exit)) /* * bss (Block Started by Symbol) - uninitialized data @@ -697,7 +697,7 @@ #define INIT_SETUP(initsetup_align) \ . = ALIGN(initsetup_align); \ VMLINUX_SYMBOL(__setup_start) = .; \ - *(.init.setup) \ + KEEP(*(.init.setup)) \ VMLINUX_SYMBOL(__setup_end) = .; #define INIT_CALLS_LEVEL(level) \ -- GitLab From 0d6fbe4ecd484e913889c02c5ad7fd28b7ec6293 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 13 Feb 2018 14:00:14 -0800 Subject: [PATCH 0071/1834] arm64: fix LD_DEAD_CODE_DATA_ELIMINATION Keep .entry.tramp.text to avoid the "Entry trampoline text too big" error while linking. Bug: 62093296 Bug: 67506682 Change-Id: Idab3216244bd2f8537bb2a5bb47e25e8588394da Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/vmlinux.lds.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 34d3ed64fe8e..a527b1c7d278 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -60,7 +60,7 @@ jiffies = jiffies_64; #define TRAMP_TEXT \ . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__entry_tramp_text_start) = .; \ - *(.entry.tramp.text) \ + KEEP(*(.entry.tramp.text)) \ . = ALIGN(PAGE_SIZE); \ VMLINUX_SYMBOL(__entry_tramp_text_end) = .; #else -- GitLab From e611641232f79677a0aa0f34c51c179655b57222 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 10 Oct 2017 10:56:17 -0700 Subject: [PATCH 0072/1834] FROMLIST: BACKPORT: arm64: keep .altinstructions and .altinstr_replacement Make sure the linker doesn't remove .altinstructions or .altinstr_replacement when CONFIG_LD_DEAD_CODE_DATA_ELIMINATION is enabled. Bug: 62093296 Bug: 67506682 Change-Id: I73f8a96679083909ec6865ee87519163ac7dcbe3 (am from https://patchwork.kernel.org/patch/10085799/) Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/vmlinux.lds.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index a527b1c7d278..402a62165d40 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -179,11 +179,11 @@ SECTIONS . = ALIGN(4); .altinstructions : { __alt_instructions = .; - *(.altinstructions) + KEEP(*(.altinstructions)) __alt_instructions_end = .; } .altinstr_replacement : { - *(.altinstr_replacement) + KEEP(*(.altinstr_replacement)) } .rela : ALIGN(8) { *(.rela .rela*) -- GitLab From 552777bdc1d775bee1ffde43c23ab0b2c4501f35 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 25 Oct 2017 12:33:58 -0700 Subject: [PATCH 0073/1834] FROMLIST: kbuild: add ld-name macro GNU gold may require different flags than GNU ld. Add a macro for detecting the linker. Bug: 62093296 Bug: 67506682 Change-Id: I777f14bf4fd902de1f8dc73d7ecc3c0403eae5f5 (am from https://patchwork.kernel.org/patch/10085775/) Reviewed-by: Nick Desaulniers Signed-off-by: Sami Tolvanen --- scripts/Kbuild.include | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index da69cc0c8de4..107e2f50a469 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -204,6 +204,10 @@ ld-option = $(call try-run,\ # Important: no spaces around options ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2)) +# ld-name +# Expands to either bfd or gold +ld-name = $(shell $(LD) -v 2>&1 | grep -q "GNU gold" && echo gold || echo bfd) + # ld-version # Note this is mainly for HJ Lu's 3 number binutil versions ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh) -- GitLab From 9403b68067aaa4941facfd260e14bb2b892073f5 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 17 Nov 2017 15:55:54 -0800 Subject: [PATCH 0074/1834] FROMLIST: kbuild: add __ld-ifversion and linker-specific macros Add macros for testing both linker name and version. Bug: 62093296 Bug: 67506682 Change-Id: Icbb13e9bb889017cd4a7457a62dea7e0335c53b5 (am from https://patchwork.kernel.org/patch/10085789/) Signed-off-by: Sami Tolvanen --- scripts/Kbuild.include | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 107e2f50a469..0f101f73cf09 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -216,6 +216,18 @@ ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh) # Usage: $(call ld-ifversion, -ge, 22252, y) ld-ifversion = $(shell [ $(ld-version) $(1) $(2) ] && echo $(3) || echo $(4)) +# __ld-ifversion +# Usage: $(call __ld-ifversion, gold, -ge, 112000000, y) +__ld-ifversion = $(shell [ $(ld-name) = $(1) ] && [ $(ld-version) $(2) $(3) ] && echo $(4) || echo $(5)) + +# bfd-ifversion +# Usage: $(call bfd-ifversion, -ge, 227000000, y) +bfd-ifversion = $(call __ld-ifversion, bfd, $(1), $(2), $(3), $(4)) + +# gold-ifversion +# Usage: $(call gold-ifversion, -ge, 112000000, y) +gold-ifversion = $(call __ld-ifversion, gold, $(1), $(2), $(3), $(4)) + ###### ### -- GitLab From 5c41c483accd942c053cc232148d7eb557f5a049 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 1 Nov 2017 08:42:49 -0700 Subject: [PATCH 0075/1834] FROMLIST: arm64: explicitly pass --no-fix-cortex-a53-843419 to GNU gold Some versions of GNU gold are known to produce broken code with --fix-cortex-a53-843419 as explained in this bug: https://sourceware.org/bugzilla/show_bug.cgi?id=21491 If ARM64_ERRATUM_843419 is disabled and we're using GNU gold, pass --no-fix-cortex-a53-843419 to the linker to ensure the erratum fix is not used even if the linker is configured to enable it by default. This change also adds a warning if the erratum fix is enabled and gold version <1.14 is used. Bug: 62093296 Bug: 67506682 Change-Id: I5669fa920292adc0fd973035f27dafd4a76d919a (am from https://patchwork.kernel.org/patch/10085777/) Signed-off-by: Sami Tolvanen --- arch/arm64/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index c76311c2f5d6..47e3d7ac852e 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -26,8 +26,17 @@ ifeq ($(CONFIG_ARM64_ERRATUM_843419),y) ifeq ($(call ld-option, --fix-cortex-a53-843419),) $(warning ld does not support --fix-cortex-a53-843419; kernel may be susceptible to erratum) else + ifeq ($(call gold-ifversion, -lt, 114000000, y), y) +$(warning This version of GNU gold may generate incorrect code with --fix-cortex-a53-843419;\ + see https://sourceware.org/bugzilla/show_bug.cgi?id=21491) + endif LDFLAGS_vmlinux += --fix-cortex-a53-843419 endif +else + ifeq ($(ld-name),gold) +# Pass --no-fix-cortex-a53-843419 to ensure the erratum fix is disabled +LDFLAGS += --no-fix-cortex-a53-843419 + endif endif KBUILD_DEFCONFIG := defconfig -- GitLab From 331f1f5c7b05132e71232e33eba32b57d1683afc Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 4 Aug 2017 12:44:35 -0700 Subject: [PATCH 0076/1834] FROMLIST: BACKPORT: arm64: add a workaround for GNU gold with ARM64_MODULE_PLTS All current versions of GNU gold crash when linking kernel modules with ARM64_MODULE_PLTS due to a known bug: https://sourceware.org/bugzilla/show_bug.cgi?id=14592 To work around the problem, this change removes NOLOAD from .plt and .init.plt. Bug: 62093296 Bug: 67506682 Change-Id: Ie59c15dc2e60859361b5c7dac5a515eabf8bb005 (am from https://patchwork.kernel.org/patch/10085781/) Acked-by: Ard Biesheuvel Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/module.lds | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/module.lds b/arch/arm64/kernel/module.lds index 8949f6c6f729..05881e2b414c 100644 --- a/arch/arm64/kernel/module.lds +++ b/arch/arm64/kernel/module.lds @@ -1,3 +1,3 @@ SECTIONS { - .plt (NOLOAD) : { BYTE(0) } + .plt : { BYTE(0) } } -- GitLab From 475bdd7d351c3ce80dbb38df719df315473c16d9 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 28 Nov 2017 08:48:49 -0800 Subject: [PATCH 0077/1834] FROMLIST: BACKPORT: kbuild: add support for clang LTO This change adds the configuration option CONFIG_LTO_CLANG, and build system support for clang's Link Time Optimization (LTO). In preparation for LTO support for other compilers, potentially common parts of the changes are gated behind CONFIG_LTO instead. With -flto, instead of object files, clang produces LLVM bitcode, which is compiled into a native object at link time, allowing the final binary to be optimized globally. For more details, see: https://llvm.org/docs/LinkTimeOptimization.html While the kernel normally uses GNU ld for linking, LLVM supports LTO only with lld or GNU gold linkers. This patch set assumes gold will be used with the LLVMgold plug-in to perform the LTO link step. Due to potential incompatibilities with GNU ld, this change also adds LDFINAL_vmlinux for using a different linker for the vmlinux_link step, and defaults to using GNU ld. Assuming LLVMgold.so is in LD_LIBRARY_PATH and CONFIG_LTO_CLANG has been selected, an LTO kernel can be built simply by running make CC=clang. LTO requires clang >= 5.0 and gold from binutils >= 2.27. Bug: 62093296 Bug: 67506682 Change-Id: Ibcd9fc7ec501b4f30b43b4877897615645f8655f (am from https://patchwork.kernel.org/patch/10060329/) Signed-off-by: Sami Tolvanen --- Makefile | 54 +++++++++++++++++++- arch/Kconfig | 30 +++++++++++ scripts/Makefile.build | 105 ++++++++++++++++++++++++++++++++++----- scripts/Makefile.modpost | 40 ++++++++++++--- scripts/link-vmlinux.sh | 81 ++++++++++++++++++++++++------ 5 files changed, 276 insertions(+), 34 deletions(-) diff --git a/Makefile b/Makefile index b8ec38eb8c4d..24b1f9259343 100644 --- a/Makefile +++ b/Makefile @@ -348,6 +348,7 @@ include scripts/Kbuild.include # Make variables (CC, etc...) AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld +LDGOLD = $(CROSS_COMPILE)ld.gold CC = $(CROSS_COMPILE)gcc CPP = $(CC) -E AR = $(CROSS_COMPILE)ar @@ -623,6 +624,20 @@ CFLAGS_GCOV := -fprofile-arcs -ftest-coverage -fno-tree-loop-im $(call cc-disabl CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) export CFLAGS_GCOV CFLAGS_KCOV +# Make toolchain changes before including arch/$(SRCARCH)/Makefile to ensure +# ar/cc/ld-* macros return correct values. +ifdef CONFIG_LTO_CLANG +# use GNU gold with LLVMgold for LTO linking, and LD for vmlinux_link +LDFINAL_vmlinux := $(LD) +LD := $(LDGOLD) +LDFLAGS += -plugin LLVMgold.so +# use llvm-ar for building symbol tables from IR files, and llvm-dis instead +# of objdump for processing symbol versions and exports +LLVM_AR := llvm-ar +LLVM_DIS := llvm-dis +export LLVM_AR LLVM_DIS +endif + # The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default # values of the respective KBUILD_* variables ARCH_CPPFLAGS := @@ -641,6 +656,26 @@ KBUILD_CFLAGS += $(call cc-option,-ffunction-sections,) KBUILD_CFLAGS += $(call cc-option,-fdata-sections,) endif +ifdef CONFIG_LTO_CLANG +lto-clang-flags := -flto -fvisibility=hidden + +# allow disabling only clang LTO where needed +DISABLE_LTO_CLANG := -fno-lto -fvisibility=default +export DISABLE_LTO_CLANG +endif + +ifdef CONFIG_LTO +lto-flags := $(lto-clang-flags) +KBUILD_CFLAGS += $(lto-flags) + +DISABLE_LTO := $(DISABLE_LTO_CLANG) +export DISABLE_LTO + +# LDFINAL_vmlinux and LDFLAGS_FINAL_vmlinux can be set to override +# the linker and flags for vmlinux_link. +export LDFINAL_vmlinux LDFLAGS_FINAL_vmlinux +endif + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += $(call cc-option,-Oz,-Os) KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) @@ -1083,6 +1118,22 @@ prepare-objtool: $(objtool_target) # CC_STACKPROTECTOR_STRONG! Why did it build with _REGULAR?!") PHONY += prepare-compiler-check prepare-compiler-check: FORCE +# Make sure we're using a supported toolchain with LTO_CLANG +ifdef CONFIG_LTO_CLANG + ifneq ($(call clang-ifversion, -ge, 0500, y), y) + @echo Cannot use CONFIG_LTO_CLANG: requires clang 5.0 or later >&2 && exit 1 + endif + ifneq ($(call gold-ifversion, -ge, 112000000, y), y) + @echo Cannot use CONFIG_LTO_CLANG: requires GNU gold 1.12 or later >&2 && exit 1 + endif +endif +# Make sure compiler supports LTO flags +ifdef lto-flags + ifeq ($(call cc-option, $(lto-flags)),) + @echo Cannot use CONFIG_LTO: $(lto-flags) not supported by compiler \ + >&2 && exit 1 + endif +endif # Make sure compiler supports requested stack protector flag. ifdef stackp-name ifeq ($(call cc-option, $(stackp-flag)),) @@ -1569,7 +1620,8 @@ clean: $(clean-dirs) -o -name modules.builtin -o -name '.tmp_*.o.*' \ -o -name '*.c.[012]*.*' \ -o -name '*.ll' \ - -o -name '*.gcno' \) -type f -print | xargs rm -f + -o -name '*.gcno' \ + -o -name '*.*.symversions' \) -type f -print | xargs rm -f # Generate tags for editors # --------------------------------------------------------------------------- diff --git a/arch/Kconfig b/arch/Kconfig index 659bdd079277..5f96c8fb2f09 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -489,6 +489,36 @@ config LD_DEAD_CODE_DATA_ELIMINATION sections (e.g., '.text.init'). Typically '.' in section names is used to distinguish them from label names / C identifiers. +config LTO + bool + +config ARCH_SUPPORTS_LTO_CLANG + bool + help + An architecture should select this option it supports: + - compiling with clang, + - compiling inline assembly with clang's integrated assembler, + - and linking with either lld or GNU gold w/ LLVMgold. + +config LTO_CLANG + bool "Use clang Link Time Optimization (LTO) (EXPERIMENTAL)" + depends on ARCH_SUPPORTS_LTO_CLANG + depends on !FTRACE_MCOUNT_RECORD + select LTO + select THIN_ARCHIVES + select LD_DEAD_CODE_DATA_ELIMINATION + help + This option enables clang's Link Time Optimization (LTO), which allows + the compiler to optimize the kernel globally at link time. If you + enable this option, the compiler generates LLVM IR instead of object + files, and the actual compilation from IR occurs at the LTO link step, + which may take several minutes. + + If you select this option, you must compile the kernel with clang >= + 5.0 (make CC=clang) and GNU gold from binutils >= 2.27, and have the + LLVMgold plug-in in LD_LIBRARY_PATH. + + config HAVE_ARCH_WITHIN_STACK_FRAMES bool help diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 3e3efd37ba47..4ce5e1adec58 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -208,6 +208,23 @@ else cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< +ifdef CONFIG_LTO_CLANG +# Generate .o.symversions files for each .o with exported symbols, and link these +# to the kernel and/or modules at the end. +cmd_modversions_c = \ + if $(OBJDUMP) -h $(@D)/.tmp_$(@F) >/dev/null 2>/dev/null; then \ + if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ + $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ + > $(@D)/$(@F).symversions; \ + fi; \ + else \ + if $(LLVM_DIS) -o=- $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ + $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ + > $(@D)/$(@F).symversions; \ + fi; \ + fi; \ + mv -f $(@D)/.tmp_$(@F) $@; +else cmd_modversions_c = \ if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ @@ -220,6 +237,7 @@ cmd_modversions_c = \ mv -f $(@D)/.tmp_$(@F) $@; \ fi; endif +endif ifdef CONFIG_FTRACE_MCOUNT_RECORD ifdef BUILD_C_RECORDMCOUNT @@ -434,9 +452,30 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ; # ifdef builtin-target +ifdef CONFIG_LTO_CLANG + ifdef CONFIG_MODVERSIONS + # combine symversions for later processing + update_lto_symversions = \ + rm -f $@.symversions; \ + for i in $(filter-out FORCE,$^); do \ + if [ -f $$i.symversions ]; then \ + cat $$i.symversions \ + >> $@.symversions; \ + fi; \ + done; + endif + # rebuild the symbol table with llvm-ar to include IR files + update_lto_symtable = ; \ + mv -f $@ $@.tmp; \ + $(LLVM_AR) rcsT$(KBUILD_ARFLAGS) $@ \ + $$($(AR) t $@.tmp); \ + rm -f $@.tmp +endif + ifdef CONFIG_THIN_ARCHIVES - cmd_make_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) - cmd_make_empty_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) + cmd_make_builtin = $(update_lto_symversions) \ + rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) + cmd_make_empty_builtin = rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) quiet_cmd_link_o_target = AR $@ else cmd_make_builtin = $(LD) $(ld_flags) -r -o @@ -476,7 +515,11 @@ ifdef lib-target quiet_cmd_link_l_target = AR $@ ifdef CONFIG_THIN_ARCHIVES - cmd_link_l_target = rm -f $@; $(AR) rcsT$(KBUILD_ARFLAGS) $@ $(lib-y) + cmd_link_l_target = \ + $(update_lto_symversions) \ + rm -f $@; \ + $(AR) rcsTP$(KBUILD_ARFLAGS) $@ $(lib-y) \ + $(update_lto_symtable) else cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y) endif @@ -494,14 +537,36 @@ else ref_prefix = EXTERN( endif -quiet_cmd_export_list = EXPORTS $@ -cmd_export_list = $(OBJDUMP) -h $< | \ - sed -ne '/___ksymtab/{s/.*+/$(ref_prefix)/;s/ .*/)/;p}' >$(ksyms-lds);\ - rm -f $(dummy-object);\ - $(AR) rcs$(KBUILD_ARFLAGS) $(dummy-object);\ +filter_export_list = sed -ne '/___ksymtab/s/.*+\([^ "]*\).*/$(ref_prefix)\1)/p' +link_export_list = rm -f $(dummy-object);\ + echo | $(CC) $(a_flags) -c -o $(dummy-object) -x assembler -;\ $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\ rm $(dummy-object) $(ksyms-lds) +quiet_cmd_export_list = EXPORTS $@ + +ifdef CONFIG_LTO_CLANG +# objdump doesn't understand IR files and llvm-dis doesn't support archives, +# so we'll walk through each file in the archive separately +cmd_export_list = \ + rm -f $(ksyms-lds); \ + for o in $$($(AR) t $<); do \ + if $(OBJDUMP) -h $$o >/dev/null 2>/dev/null; then \ + $(OBJDUMP) -h $$o | \ + $(filter_export_list) \ + >>$(ksyms-lds); \ + else \ + $(LLVM_DIS) -o=- $$o | \ + $(filter_export_list) \ + >>$(ksyms-lds); \ + fi; \ + done; \ + $(link_export_list) +else +cmd_export_list = $(OBJDUMP) -h $< | $(filter_export_list) >$(ksyms-lds); \ + $(link_export_list) +endif + $(obj)/lib-ksyms.o: $(lib-target) FORCE $(call if_changed,export_list) @@ -525,20 +590,36 @@ $($(subst $(obj)/,,$(@:.o=-objs))) \ $($(subst $(obj)/,,$(@:.o=-y))) \ $($(subst $(obj)/,,$(@:.o=-m)))), $^) -quiet_cmd_link_multi-y = LD $@ -cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) +cmd_link_multi-link = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) + +ifdef CONFIG_THIN_ARCHIVES + quiet_cmd_link_multi-y = AR $@ + cmd_link_multi-y = $(update_lto_symversions) \ + rm -f $@; $(AR) rcSTP$(KBUILD_ARFLAGS) $@ $(link_multi_deps) \ + $(update_lto_symtable) +else + quiet_cmd_link_multi-y = LD $@ + cmd_link_multi-y = $(cmd_link_multi-link) +endif quiet_cmd_link_multi-m = LD [M] $@ -cmd_link_multi-m = $(cmd_link_multi-y) + +ifdef CONFIG_LTO_CLANG + # don't compile IR until needed + cmd_link_multi-m = $(cmd_link_multi-y) +else + cmd_link_multi-m = $(cmd_link_multi-link) +endif $(multi-used-y): FORCE $(call if_changed,link_multi-y) -$(call multi_depend, $(multi-used-y), .o, -objs -y) $(multi-used-m): FORCE $(call if_changed,link_multi-m) @{ echo $(@:.o=.ko); echo $(link_multi_deps); \ $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) + +$(call multi_depend, $(multi-used-y), .o, -objs -y) $(call multi_depend, $(multi-used-m), .o, -objs -y -m) targets += $(multi-used-y) $(multi-used-m) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 16923ba4b5b1..d26169b58a74 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -82,12 +82,28 @@ modpost = scripts/mod/modpost \ MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS))) +# If CONFIG_LTO_CLANG is enabled, .o files are either LLVM IR, or empty, so we +# need to link them into actual objects before passing them to modpost +modpost-ext = $(if $(CONFIG_LTO_CLANG),.lto,) + +ifdef CONFIG_LTO_CLANG +quiet_cmd_cc_lto_link_modules = LD [M] $@ +cmd_cc_lto_link_modules = \ + $(LD) $(ld_flags) -r -o $(@) \ + $(shell [ -s $(@:$(modpost-ext).o=.o.symversions) ] && \ + echo -T $(@:$(modpost-ext).o=.o.symversions)) \ + --whole-archive $(filter-out FORCE,$^) + +$(modules:.ko=$(modpost-ext).o): %$(modpost-ext).o: %.o FORCE + $(call if_changed,cc_lto_link_modules) +endif + # We can go over command line length here, so be careful. quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules - cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/.o/' | $(modpost) $(MODPOST_OPT) -s -T - + cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/$(modpost-ext)\.o/' | $(modpost) $(MODPOST_OPT) -s -T - PHONY += __modpost -__modpost: $(modules:.ko=.o) FORCE +__modpost: $(modules:.ko=$(modpost-ext).o) FORCE $(call cmd,modpost) $(wildcard vmlinux) quiet_cmd_kernel-mod = MODPOST $@ @@ -98,8 +114,7 @@ vmlinux.o: FORCE # Declare generated files as targets for modpost $(symverfile): __modpost ; -$(modules:.ko=.mod.c): __modpost ; - +$(modules:.ko=$(modpost-ext).mod.c): __modpost ; # Step 5), compile all *.mod.c files @@ -110,22 +125,33 @@ quiet_cmd_cc_o_c = CC $@ cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \ -c -o $@ $< -$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE +$(modules:.ko=.mod.o): %.mod.o: %$(modpost-ext).mod.c FORCE $(call if_changed_dep,cc_o_c) -targets += $(modules:.ko=.mod.o) +targets += $(modules:.ko=$(modpost-ext).mod.o) ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) # Step 6), final link of the modules with optional arch pass after final link quiet_cmd_ld_ko_o = LD [M] $@ + +ifdef CONFIG_LTO_CLANG + cmd_ld_ko_o = \ + $(LD) -r $(LDFLAGS) \ + $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ + $(shell [ -s $(@:.ko=.o.symversions) ] && \ + echo -T $(@:.ko=.o.symversions)) \ + -o $@ --whole-archive \ + $(filter-out FORCE,$(^:$(modpost-ext).o=.o)) +else cmd_ld_ko_o = \ $(LD) -r $(LDFLAGS) \ $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ -o $@ $(filter-out FORCE,$^) ; \ $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) +endif -$(modules): %.ko :%.o %.mod.o FORCE +$(modules): %.ko: %$(modpost-ext).o %.mod.o FORCE +$(call if_changed,ld_ko_o) targets += $(modules) diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index f742c65108b9..d16dc7c0b5d1 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -53,9 +53,40 @@ archive_builtin() ${AR} rcsT${KBUILD_ARFLAGS} built-in.o \ ${KBUILD_VMLINUX_INIT} \ ${KBUILD_VMLINUX_MAIN} + + if [ -n "${CONFIG_LTO_CLANG}" ]; then + mv -f built-in.o built-in.o.tmp + ${LLVM_AR} rcsT${KBUILD_ARFLAGS} built-in.o $(${AR} t built-in.o.tmp) + rm -f built-in.o.tmp + fi fi } +# If CONFIG_LTO_CLANG is selected, collect generated symbol versions into +# .tmp_symversions +modversions() +{ + if [ -z "${CONFIG_LTO_CLANG}" ]; then + return + fi + + if [ -z "${CONFIG_MODVERSIONS}" ]; then + return + fi + + rm -f .tmp_symversions + + for a in built-in.o ${KBUILD_VMLINUX_LIBS}; do + for o in $(${AR} t $a); do + if [ -f ${o}.symversions ]; then + cat ${o}.symversions >> .tmp_symversions + fi + done + done + + echo "-T .tmp_symversions" +} + # Link of vmlinux.o used for section mismatch analysis # ${1} output file modpost_link() @@ -70,7 +101,16 @@ modpost_link() ${KBUILD_VMLINUX_MAIN} \ --end-group" fi - ${LD} ${LDFLAGS} -r -o ${1} ${objects} + + if [ -n "${CONFIG_LTO_CLANG}" ]; then + # This might take a while, so indicate that we're doing + # an LTO link + info LTO vmlinux.o + else + info LD vmlinux.o + fi + + ${LD} ${LDFLAGS} -r -o ${1} $(modversions) ${objects} } # Link of vmlinux @@ -82,7 +122,15 @@ vmlinux_link() local objects if [ "${SRCARCH}" != "um" ]; then - if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then + local ld=${LD} + local ldflags="${LDFLAGS} ${LDFLAGS_vmlinux}" + + if [ -n "${LDFINAL_vmlinux}" ]; then + ld=${LDFINAL_vmlinux} + ldflags="${LDFLAGS_FINAL_vmlinux} ${LDFLAGS_vmlinux}" + fi + + if [[ -n "${CONFIG_THIN_ARCHIVES}" && -z "${CONFIG_LTO_CLANG}" ]]; then objects="--whole-archive built-in.o ${1}" else objects="${KBUILD_VMLINUX_INIT} \ @@ -92,8 +140,7 @@ vmlinux_link() ${1}" fi - ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ - -T ${lds} ${objects} + ${ld} ${ldflags} -o ${2} -T ${lds} ${objects} else if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then objects="-Wl,--whole-archive built-in.o ${1}" @@ -113,7 +160,6 @@ vmlinux_link() fi } - # Create ${2} .o file with all symbols from the ${1} object file kallsyms() { @@ -164,6 +210,7 @@ cleanup() rm -f .tmp_System.map rm -f .tmp_kallsyms* rm -f .tmp_version + rm -f .tmp_symversions rm -f .tmp_vmlinux* rm -f built-in.o rm -f System.map @@ -209,15 +256,6 @@ case "${KCONFIG_CONFIG}" in . "./${KCONFIG_CONFIG}" esac -archive_builtin - -#link vmlinux.o -info LD vmlinux.o -modpost_link vmlinux.o - -# modpost vmlinux.o to check for section mismatches -${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o - # Update version info GEN .version if [ ! -r .version ]; then @@ -228,9 +266,24 @@ else expr 0$(cat .old_version) + 1 >.version; fi; +archive_builtin + +#link vmlinux.o +modpost_link vmlinux.o + +# modpost vmlinux.o to check for section mismatches +${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o + # final build of init/ ${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" +if [ -n "${CONFIG_LTO_CLANG}" ]; then + # Re-use vmlinux.o, so we can avoid the slow LTO link step in + # vmlinux_link + KBUILD_VMLINUX_INIT= + KBUILD_VMLINUX_MAIN=vmlinux.o +fi + kallsymso="" kallsyms_vmlinux="" if [ -n "${CONFIG_KALLSYMS}" ]; then -- GitLab From 7bd125e57b003f66a1ee2b12882da0d1ad15ab56 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 16 Jun 2017 12:52:57 -0700 Subject: [PATCH 0078/1834] FROMLIST: BACKPORT: kbuild: fix dynamic ftrace with clang LTO With CONFIG_LTO_CLANG enabled, LLVM IR won't be compiled into object files until modpost_link. This change postpones calls to recordmcount until after this step. In order to exclude ftrace_process_locs from inspection, we add a new code section .text..ftrace, which we tell recordmcount to ignore, and a __norecordmcount attribute for moving functions to this section. Bug: 62093296 Bug: 67506682 Change-Id: Iba2c053968206acf533fadab1eb34a743b5088ee (am from https://patchwork.kernel.org/patch/10060327/) Signed-off-by: Sami Tolvanen --- arch/Kconfig | 2 +- include/asm-generic/vmlinux.lds.h | 1 + include/linux/compiler-clang.h | 7 +++++++ include/linux/compiler.h | 4 ++++ kernel/trace/ftrace.c | 6 +++--- scripts/Makefile.build | 16 ++++++++++++++-- scripts/Makefile.modpost | 4 ++++ scripts/link-vmlinux.sh | 16 ++++++++++++++++ scripts/recordmcount.c | 3 ++- 9 files changed, 52 insertions(+), 7 deletions(-) diff --git a/arch/Kconfig b/arch/Kconfig index 5f96c8fb2f09..194d179d41da 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -503,7 +503,7 @@ config ARCH_SUPPORTS_LTO_CLANG config LTO_CLANG bool "Use clang Link Time Optimization (LTO) (EXPERIMENTAL)" depends on ARCH_SUPPORTS_LTO_CLANG - depends on !FTRACE_MCOUNT_RECORD + depends on !FTRACE_MCOUNT_RECORD || HAVE_C_RECORDMCOUNT select LTO select THIN_ARCHIVES select LD_DEAD_CODE_DATA_ELIMINATION diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index d1d7d5db55b4..f2d0a7fbdef8 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -460,6 +460,7 @@ #define TEXT_TEXT \ ALIGN_FUNCTION(); \ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ + *(.text..ftrace) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \ diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index de179993e039..fd299451aa0b 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -15,3 +15,10 @@ * with any version that can compile the kernel */ #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) + +#ifdef CONFIG_LTO_CLANG +#ifdef CONFIG_FTRACE_MCOUNT_RECORD +#define __norecordmcount \ + __attribute__((__section__(".text..ftrace"))) +#endif +#endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 5ce911db7d88..40445d0df89c 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -451,6 +451,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s #define __visible #endif +#ifndef __norecordmcount +#define __norecordmcount +#endif + /* * Assume alignment of return value. */ diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 2884fe01cb54..063dd229bd36 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -4874,9 +4874,9 @@ static int ftrace_cmp_ips(const void *a, const void *b) return 0; } -static int ftrace_process_locs(struct module *mod, - unsigned long *start, - unsigned long *end) +static int __norecordmcount ftrace_process_locs(struct module *mod, + unsigned long *start, + unsigned long *end) { struct ftrace_page *start_pg; struct ftrace_page *pg; diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 4ce5e1adec58..5f113db8dc2f 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -244,6 +244,12 @@ ifdef BUILD_C_RECORDMCOUNT ifeq ("$(origin RECORDMCOUNT_WARN)", "command line") RECORDMCOUNT_FLAGS = -w endif + +ifdef CONFIG_LTO_CLANG +# With LTO, we postpone running recordmcount until after the LTO link step, so +# let's export the parameters for the link script. +export RECORDMCOUNT_FLAGS +else # Due to recursion, we must skip empty.o. # The empty.o file is created in the make process in order to determine # the target endianness and word size. It is made before all other C @@ -252,23 +258,29 @@ sub_cmd_record_mcount = \ if [ $(@) != "scripts/mod/empty.o" ]; then \ $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \ fi; +endif + recordmcount_source := $(srctree)/scripts/recordmcount.c \ $(srctree)/scripts/recordmcount.h -else +else # !BUILD_C_RECORDMCOUNT sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ "$(if $(CONFIG_64BIT),64,32)" \ "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \ "$(LD)" "$(NM)" "$(RM)" "$(MV)" \ "$(if $(part-of-module),1,0)" "$(@)"; + recordmcount_source := $(srctree)/scripts/recordmcount.pl -endif +endif # BUILD_C_RECORDMCOUNT + +ifndef CONFIG_LTO_CLANG cmd_record_mcount = \ if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" = \ "$(CC_FLAGS_FTRACE)" ]; then \ $(sub_cmd_record_mcount) \ fi; endif +endif # CONFIG_FTRACE_MCOUNT_RECORD ifdef CONFIG_STACK_VALIDATION ifneq ($(SKIP_STACK_VALIDATION),1) diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index d26169b58a74..b7c50cb48ba4 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -143,6 +143,10 @@ ifdef CONFIG_LTO_CLANG echo -T $(@:.ko=.o.symversions)) \ -o $@ --whole-archive \ $(filter-out FORCE,$(^:$(modpost-ext).o=.o)) + + ifdef CONFIG_FTRACE_MCOUNT_RECORD + cmd_ld_ko_o += ; $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) $@ + endif else cmd_ld_ko_o = \ $(LD) -r $(LDFLAGS) \ diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh index d16dc7c0b5d1..8b4329c33181 100755 --- a/scripts/link-vmlinux.sh +++ b/scripts/link-vmlinux.sh @@ -113,6 +113,19 @@ modpost_link() ${LD} ${LDFLAGS} -r -o ${1} $(modversions) ${objects} } +# If CONFIG_LTO_CLANG is selected, we postpone running recordmcount until +# we have compiled LLVM IR to an object file. +recordmcount() +{ + if [ -z "${CONFIG_LTO_CLANG}" ]; then + return + fi + + if [ -n "${CONFIG_FTRACE_MCOUNT_RECORD}" ]; then + scripts/recordmcount ${RECORDMCOUNT_FLAGS} $* + fi +} + # Link of vmlinux # ${1} - optional extra .o files # ${2} - output file @@ -282,6 +295,9 @@ if [ -n "${CONFIG_LTO_CLANG}" ]; then # vmlinux_link KBUILD_VMLINUX_INIT= KBUILD_VMLINUX_MAIN=vmlinux.o + + # Call recordmcount if needed + recordmcount vmlinux.o fi kallsymso="" diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c index 5423a58d1b06..e0c508203c9c 100644 --- a/scripts/recordmcount.c +++ b/scripts/recordmcount.c @@ -366,7 +366,8 @@ is_mcounted_section_name(char const *const txtname) strcmp(".softirqentry.text", txtname) == 0 || strcmp(".kprobes.text", txtname) == 0 || strcmp(".cpuidle.text", txtname) == 0 || - strcmp(".text.unlikely", txtname) == 0; + (strncmp(".text.", txtname, 6) == 0 && + strcmp(".text..ftrace", txtname) != 0); } /* 32 bit and 64 bit are very similar */ -- GitLab From 633a38f085b4f95e502620dd15b500d5a894701c Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 10 Apr 2017 12:32:24 -0700 Subject: [PATCH 0079/1834] FROMLIST: scripts/mod: disable LTO for empty.c With CONFIG_LTO_CLANG, clang generates LLVM IR instead of ELF object files. As empty.o is used for probing target properties, disable LTO for it to produce an object file instead. Bug: 62093296 Bug: 67506682 Change-Id: I0c7ac7ee0134465cac4a8c3a9c7e8b6347076a2b (am from https://patchwork.kernel.org/patch/10060317/) Signed-off-by: Sami Tolvanen --- scripts/mod/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index b497d9764dcf..247cf1fb5a4e 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile @@ -1,4 +1,5 @@ OBJECT_FILES_NON_STANDARD := y +CFLAGS_empty.o += $(DISABLE_LTO) hostprogs-y := modpost mk_elfconfig always := $(hostprogs-y) empty.o -- GitLab From 2451857f51d82c4130ab167a0831074d445ebaff Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 1 May 2017 11:08:05 -0700 Subject: [PATCH 0080/1834] FROMLIST: efi/libstub: disable LTO With CONFIG_LTO_CLANG, we produce LLVM IR instead of object files. Since LTO is not really needed here and the Makefile assumes we produce an object file, disable LTO for libstub. Bug: 62093296 Bug: 67506682 Change-Id: Ieaa3d7e2c694655788f480f4351bf7c4d3fce090 (am from https://patchwork.kernel.org/patch/10060309/) Acked-by: Ard Biesheuvel Signed-off-by: Sami Tolvanen --- drivers/firmware/efi/libstub/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index b12bc38dfa71..0e3ca82380c3 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -18,7 +18,8 @@ cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \ $(call cc-option,-ffreestanding) \ - $(call cc-option,-fno-stack-protector) + $(call cc-option,-fno-stack-protector) \ + $(DISABLE_LTO) GCOV_PROFILE := n KASAN_SANITIZE := n -- GitLab From a953df5e8cd05e4778747cd1e0d92ea78b161f31 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 13 Nov 2017 08:19:17 -0800 Subject: [PATCH 0081/1834] FROMLIST: arm64: kvm: use -fno-jump-tables with clang Starting with LLVM r308050, clang generates a jump table with EL1 virtual addresses in __init_stage2_translation, which results in a kernel panic when booting at EL2: Kernel panic - not syncing: HYP panic: PS:800003c9 PC:ffff0000089e6fd8 ESR:86000004 FAR:ffff0000089e6fd8 HPFAR:0000000009825000 PAR:0000000000000000 VCPU:000804fc20001221 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.14.0-rc7-dirty #3 Hardware name: ARM Juno development board (r1) (DT) Call trace: [] dump_backtrace+0x0/0x34c [] show_stack+0x18/0x20 [] dump_stack+0xc4/0xfc [] panic+0x138/0x2b4 [] panic+0x0/0x2b4 SMP: stopping secondary CPUs SMP: failed to stop secondary CPUs 0-3,5 Kernel Offset: disabled CPU features: 0x002086 Memory Limit: none ---[ end Kernel panic - not syncing: HYP panic: PS:800003c9 PC:ffff0000089e6fd8 ESR:86000004 FAR:ffff0000089e6fd8 HPFAR:0000000009825000 PAR:0000000000000000 VCPU:000804fc20001221 This change adds -fno-jump-tables to arm64/hyp to work around the bug. Bug: 62093296 Bug: 67506682 Change-Id: I1257be1febdcbfcc886fe6183c698b7a98d2a153 (am from https://patchwork.kernel.org/patch/10060301/) Suggested-by: AKASHI Takahiro Signed-off-by: Sami Tolvanen --- arch/arm64/kvm/hyp/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile index 48b03547a969..c470a7c5f05b 100644 --- a/arch/arm64/kvm/hyp/Makefile +++ b/arch/arm64/kvm/hyp/Makefile @@ -4,6 +4,10 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING +ifeq ($(cc-name),clang) +ccflags-y += -fno-jump-tables +endif + KVM=../../../../virt/kvm obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o -- GitLab From 79b4e3cb7460afa37b389ebd50c791e1b971ede8 Mon Sep 17 00:00:00 2001 From: Alex Matveev Date: Tue, 14 Nov 2017 15:06:17 -0800 Subject: [PATCH 0082/1834] FROMLIST: BACKPORT: arm64: make mrs_s and msr_s macros work with LTO Clang's integrated assembler does not allow assembly macros defined in one inline asm block using the .macro directive to be used across separate asm blocks. LLVM developers consider this a feature and not a bug, recommending code refactoring: https://bugs.llvm.org/show_bug.cgi?id=19749 As binutils doesn't allow macros to be redefined, this change uses UNDEFINE_MRS_S and UNDEFINE_MSR_S to define corresponding macros in-place and workaround gcc and clang limitations on redefining macros across different assembler blocks. Bug: 62093296 Bug: 67506682 Change-Id: I803fff57f639b0921ef81f90ec4befe802e7eecf (am from https://patchwork.kernel.org/patch/10060343/) Signed-off-by: Alex Matveev Signed-off-by: Yury Norov Signed-off-by: Sami Tolvanen --- arch/arm64/include/asm/arch_gicv3.h | 66 +++++++++++++++++++++++------ arch/arm64/include/asm/kvm_hyp.h | 8 +++- arch/arm64/include/asm/sysreg.h | 55 ++++++++++++++++-------- 3 files changed, 97 insertions(+), 32 deletions(-) diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h index f8ae6d6e4767..fecf7bf863f0 100644 --- a/arch/arm64/include/asm/arch_gicv3.h +++ b/arch/arm64/include/asm/arch_gicv3.h @@ -83,14 +83,20 @@ #define read_gicreg(r) \ ({ \ u64 reg; \ - asm volatile("mrs_s %0, " __stringify(r) : "=r" (reg)); \ + asm volatile(DEFINE_MRS_S \ + "mrs_s %0, " __stringify(r) "\n" \ + UNDEFINE_MRS_S \ + : "=r" (reg)); \ reg; \ }) #define write_gicreg(v,r) \ do { \ u64 __val = (v); \ - asm volatile("msr_s " __stringify(r) ", %0" : : "r" (__val));\ + asm volatile(DEFINE_MSR_S \ + "msr_s " __stringify(r) ", %0\n" \ + UNDEFINE_MSR_S \ + : : "r" (__val)); \ } while (0) /* @@ -102,13 +108,19 @@ static inline void gic_write_eoir(u32 irq) { - asm volatile("msr_s " __stringify(ICC_EOIR1_EL1) ", %0" : : "r" ((u64)irq)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_EOIR1_EL1) ", %0\n" + UNDEFINE_MSR_S + : : "r" ((u64)irq)); isb(); } static inline void gic_write_dir(u32 irq) { - asm volatile("msr_s " __stringify(ICC_DIR_EL1) ", %0" : : "r" ((u64)irq)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_DIR_EL1) ", %0\n" + UNDEFINE_MSR_S + : : "r" ((u64)irq)); isb(); } @@ -116,7 +128,10 @@ static inline u64 gic_read_iar_common(void) { u64 irqstat; - asm volatile("mrs_s %0, " __stringify(ICC_IAR1_EL1) : "=r" (irqstat)); + asm volatile(DEFINE_MRS_S + "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n" + UNDEFINE_MRS_S + : "=r" (irqstat)); dsb(sy); return irqstat; } @@ -135,7 +150,9 @@ static inline u64 gic_read_iar_cavium_thunderx(void) asm volatile( "nop;nop;nop;nop\n\t" "nop;nop;nop;nop\n\t" + DEFINE_MRS_S "mrs_s %0, " __stringify(ICC_IAR1_EL1) "\n\t" + UNDEFINE_MRS_S "nop;nop;nop;nop" : "=r" (irqstat)); mb(); @@ -145,43 +162,68 @@ static inline u64 gic_read_iar_cavium_thunderx(void) static inline void gic_write_pmr(u32 val) { - asm volatile("msr_s " __stringify(ICC_PMR_EL1) ", %0" : : "r" ((u64)val)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_PMR_EL1) ", %0\n" + UNDEFINE_MSR_S + : : "r" ((u64)val)); + /* As per the architecture specification */ + mb(); } static inline void gic_write_ctlr(u32 val) { - asm volatile("msr_s " __stringify(ICC_CTLR_EL1) ", %0" : : "r" ((u64)val)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_CTLR_EL1) ", %0\n" + UNDEFINE_MSR_S + : : "r" ((u64)val)); isb(); } static inline void gic_write_grpen1(u32 val) { - asm volatile("msr_s " __stringify(ICC_GRPEN1_EL1) ", %0" : : "r" ((u64)val)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_GRPEN1_EL1) ", %0\n" + UNDEFINE_MSR_S + : : "r" ((u64)val)); isb(); } static inline void gic_write_sgi1r(u64 val) { - asm volatile("msr_s " __stringify(ICC_SGI1R_EL1) ", %0" : : "r" (val)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_SGI1R_EL1) ", %0\n" + UNDEFINE_MSR_S + : : "r" (val)); + /* As per the architecture specification */ + mb(); } static inline u32 gic_read_sre(void) { u64 val; - asm volatile("mrs_s %0, " __stringify(ICC_SRE_EL1) : "=r" (val)); + asm volatile(DEFINE_MRS_S + "mrs_s %0, " __stringify(ICC_SRE_EL1) "\n" + UNDEFINE_MRS_S + : "=r" (val)); return val; } static inline void gic_write_sre(u32 val) { - asm volatile("msr_s " __stringify(ICC_SRE_EL1) ", %0" : : "r" ((u64)val)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_SRE_EL1) ", %0\n" + UNDEFINE_MSR_S + : : "r" ((u64)val)); isb(); } static inline void gic_write_bpr1(u32 val) { - asm volatile("msr_s " __stringify(ICC_BPR1_EL1) ", %0" : : "r" (val)); + asm volatile(DEFINE_MSR_S + "msr_s " __stringify(ICC_BPR1_EL1) ", %x0\n" + UNDEFINE_MSR_S + : : "rZ" (val)); } #define gic_read_typer(c) readq_relaxed(c) diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h index b18e852d27e8..36d6758d580b 100644 --- a/arch/arm64/include/asm/kvm_hyp.h +++ b/arch/arm64/include/asm/kvm_hyp.h @@ -29,7 +29,9 @@ ({ \ u64 reg; \ asm volatile(ALTERNATIVE("mrs %0, " __stringify(r##nvh),\ - "mrs_s %0, " __stringify(r##vh),\ + DEFINE_MRS_S \ + "mrs_s %0, " __stringify(r##vh) "\n"\ + UNDEFINE_MRS_S, \ ARM64_HAS_VIRT_HOST_EXTN) \ : "=r" (reg)); \ reg; \ @@ -39,7 +41,9 @@ do { \ u64 __val = (u64)(v); \ asm volatile(ALTERNATIVE("msr " __stringify(r##nvh) ", %x0",\ - "msr_s " __stringify(r##vh) ", %x0",\ + DEFINE_MSR_S \ + "msr_s " __stringify(r##vh) ", %x0\n"\ + UNDEFINE_MSR_S, \ ARM64_HAS_VIRT_HOST_EXTN) \ : : "rZ" (__val)); \ } while (0) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 7393cc767edb..42a6c3db4f07 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -243,20 +243,39 @@ #include -asm( -" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" -" .equ .L__reg_num_x\\num, \\num\n" -" .endr\n" +#define __DEFINE_MRS_MSR_S_REGNUM \ +" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n" \ +" .equ .L__reg_num_x\\num, \\num\n" \ +" .endr\n" \ " .equ .L__reg_num_xzr, 31\n" -"\n" -" .macro mrs_s, rt, sreg\n" -" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" + +#define DEFINE_MRS_S \ + __DEFINE_MRS_MSR_S_REGNUM \ +" .macro mrs_s, rt, sreg\n" \ +" .inst 0xd5200000|(\\sreg)|(.L__reg_num_\\rt)\n" \ " .endm\n" -"\n" -" .macro msr_s, sreg, rt\n" -" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" + +#define DEFINE_MSR_S \ + __DEFINE_MRS_MSR_S_REGNUM \ +" .macro msr_s, sreg, rt\n" \ +" .inst 0xd5000000|(\\sreg)|(.L__reg_num_\\rt)\n" \ " .endm\n" -); + +#define UNDEFINE_MRS_S \ +" .purgem mrs_s\n" + +#define UNDEFINE_MSR_S \ +" .purgem msr_s\n" + +#define __mrs_s(r, v) \ + DEFINE_MRS_S \ +" mrs_s %0, " __stringify(r) "\n" \ + UNDEFINE_MRS_S : "=r" (v) + +#define __msr_s(r, v) \ + DEFINE_MSR_S \ +" msr_s " __stringify(r) ", %x0\n" \ + UNDEFINE_MSR_S : : "rZ" (v) /* * Unlike read_cpuid, calls to read_sysreg are never expected to be @@ -282,15 +301,15 @@ asm( * For registers without architectural names, or simply unsupported by * GAS. */ -#define read_sysreg_s(r) ({ \ - u64 __val; \ - asm volatile("mrs_s %0, " __stringify(r) : "=r" (__val)); \ - __val; \ +#define read_sysreg_s(r) ({ \ + u64 __val; \ + asm volatile(__mrs_s(r, __val)); \ + __val; \ }) -#define write_sysreg_s(v, r) do { \ - u64 __val = (u64)v; \ - asm volatile("msr_s " __stringify(r) ", %x0" : : "rZ" (__val)); \ +#define write_sysreg_s(v, r) do { \ + u64 __val = (u64)(v); \ + asm volatile(__msr_s(r, __val)); \ } while (0) static inline void config_sctlr_el1(u32 clear, u32 set) -- GitLab From 7e77d5eee711a5ef7d7f6676627e802f8a937bb6 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 16 Nov 2017 15:56:44 -0800 Subject: [PATCH 0083/1834] arm64: pass code model to LLVMgold With LTO_CLANG, even if we pass -mcmodel to clang, the flag isn't stored in the generated LLVM IR, which means it won't be used for the actual compilation at link time. Therefore, the flag needs to be passed to LLVMgold to actually take effect. Bug: 62093296 Bug: 67506682 Change-Id: I5cd21f97c800466f1bce039df56101ce4087ae20 Signed-off-by: Sami Tolvanen --- arch/arm64/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 47e3d7ac852e..ee72275e1ccd 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -79,6 +79,10 @@ CHECKFLAGS += -D__aarch64__ ifeq ($(CONFIG_ARM64_MODULE_CMODEL_LARGE), y) KBUILD_CFLAGS_MODULE += -mcmodel=large +ifeq ($(CONFIG_LTO_CLANG), y) +# Code model is not stored in LLVM IR, so we need to pass it also to LLVMgold +LDFLAGS += -plugin-opt=-code-model=large +endif endif ifeq ($(CONFIG_ARM64_MODULE_PLTS),y) -- GitLab From 84ab089dd7cb392a413021a7dc462e6b0c6e8cbe Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Mon, 29 Jan 2018 11:19:19 -0800 Subject: [PATCH 0084/1834] arm64: disable ARM64_ERRATUM_843419 for clang LTO CONFIG_LTO_CLANG depends on GNU gold, which can generate ADR_PREL_PG_HI21 relocations with --fix-cortex-a53-843419, even when -code-model=large has been passed to LLVMgold. Since ARM64_ERRATUM_843419 disables kernel support for these relocations, disable the erratum when LTO is used. Bug: 67506682 Change-Id: I5d419cae432a26af5b6eff362b869639c64c6fb3 Signed-off-by: Sami Tolvanen --- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1f5f54f2c8a7..ea259686c853 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -417,7 +417,7 @@ config ARM64_ERRATUM_845719 config ARM64_ERRATUM_843419 bool "Cortex-A53: 843419: A load or store might access an incorrect address" - default y + default y if !LTO_CLANG select ARM64_MODULE_CMODEL_LARGE if MODULES help This option links the kernel with '--fix-cortex-a53-843419' and -- GitLab From eba6c8067147b4107b8f8e93573fb5b2cccfff17 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 5 Dec 2017 12:53:34 -0800 Subject: [PATCH 0085/1834] FROMLIST: arch/arm64/crypto: disable LTO for aes-ce-cipher.c LTO requires the use of LLVM's integrated assembler, which doesn't understand the inline assembly in aes-ce-cipher.c. Disable LTO for the file. Bug: 62093296 Bug: 67506682 Change-Id: I7fe82644be0d86420edb4db7923b03dfee87215f (am from https://patchwork.kernel.org/patch/10060315/) Signed-off-by: Sami Tolvanen --- arch/arm64/crypto/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index abb79b3cfcfe..965a2df4f65c 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_CRYPTO_GHASH_ARM64_CE) += ghash-ce.o ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o -CFLAGS_aes-ce-cipher.o += -march=armv8-a+crypto +CFLAGS_aes-ce-cipher.o += -march=armv8-a+crypto $(DISABLE_LTO) obj-$(CONFIG_CRYPTO_AES_ARM64_CE_CCM) += aes-ce-ccm.o aes-ce-ccm-y := aes-ce-ccm-glue.o aes-ce-ccm-core.o -- GitLab From 2bea1d0ae8184cb206b1426701a7720c22d2209a Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 10 Nov 2017 14:00:24 -0800 Subject: [PATCH 0086/1834] FROMLIST: BACKPORT: arm64: disable RANDOMIZE_MODULE_REGION_FULL with LTO_CLANG RANDOMIZE_MODULE_REGION_FULL results in "overflow in relocation type 275" when loading a module linked with GNU gold. As a workaround, disable when LTO_CLANG is selected. Bug: 62093296 Bug: 67506682 Change-Id: I6af3de0dc2e6a5053c527d7cb7fb45cb249b68b3 (am from https://patchwork.kernel.org/patch/10060337/) Signed-off-by: Sami Tolvanen --- arch/arm64/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index ea259686c853..1eaa2aec9bf1 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -945,7 +945,7 @@ config RANDOMIZE_BASE config RANDOMIZE_MODULE_REGION_FULL bool "Randomize the module region independently from the core kernel" - depends on RANDOMIZE_BASE && !DYNAMIC_FTRACE + depends on RANDOMIZE_BASE && !DYNAMIC_FTRACE && !LTO_CLANG default y help Randomizes the location of the module region without considering the -- GitLab From 957e674f13bc3c191cecaddc101a9df1439f78d6 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 2 Nov 2017 09:34:42 -0700 Subject: [PATCH 0087/1834] FROMLIST: BACKPORT: arm64: select ARCH_SUPPORTS_LTO_CLANG Allow CONFIG_LTO_CLANG to be enabled for the architecture. Bug: 62093296 Bug: 67506682 Change-Id: Id8e06b49877c4de2f15b51fc432d601b83b2c68f (am from https://patchwork.kernel.org/patch/10060333/) Signed-off-by: Sami Tolvanen --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1eaa2aec9bf1..9a88aa4b75dc 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -15,6 +15,7 @@ config ARM64 select ARCH_HAS_SG_CHAIN select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST select ARCH_USE_CMPXCHG_LOCKREF + select ARCH_SUPPORTS_LTO_CLANG select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_NUMA_BALANCING select ARCH_WANT_COMPAT_IPC_PARSE_VERSION -- GitLab From 2104b871e14409eef5f154c189aadabf87127b20 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 19 Dec 2017 08:55:23 -0800 Subject: [PATCH 0088/1834] arm64: vdso: disable LTO Due to a bug in clang, vdso fails to build when both LTO_CLANG and CC_OPTIMIZE_FOR_SIZE are enabled: https://bugs.llvm.org/show_bug.cgi?id=32155 Disable LTO for vdso to work around the problem. Bug: 62093296 Bug: 67506682 Change-Id: I1d0279535fd389db4c829e4556f9ef728f240a34 Signed-off-by: Sami Tolvanen --- arch/arm64/kernel/vdso/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile index 62c84f7cb01b..88fef3867886 100644 --- a/arch/arm64/kernel/vdso/Makefile +++ b/arch/arm64/kernel/vdso/Makefile @@ -14,6 +14,7 @@ obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) ccflags-y := -shared -fno-common -fno-builtin ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) +ccflags-y += $(DISABLE_LTO) # Disable gcov profiling for VDSO code GCOV_PROFILE := n -- GitLab From f437c20fc6af599bda4675834a79ae802db2614c Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 5 Dec 2017 12:54:13 -0800 Subject: [PATCH 0089/1834] drivers/misc: disable LTO for lkdtm_rodata.o Disable LTO for lkdtm_rodata.o to allow objcopy to be used to manipulate sections. Bug: 62093296 Bug: 67506682 Change-Id: Iedd1a3a2a9b06f44e7ceb6ac287ea764eaf5ef0a Signed-off-by: Sami Tolvanen --- drivers/misc/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 4a25950ce85f..0d5b9e189e90 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -64,6 +64,7 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o +CFLAGS_lkdtm_rodata.o += $(DISABLE_LTO) OBJCOPYFLAGS := OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ --set-section-flags .text=alloc,readonly \ -- GitLab From aadfde875ddcf324b38799297979e72f43f801c4 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 13 Feb 2018 13:48:10 -0800 Subject: [PATCH 0090/1834] xen/efi: don't use -fshort-wchar Specifying -fshort-wchar for just one object breaks LTO with the following error message: ld.gold: fatal error: Failed to link module drivers/xen/efi.o: linking module flags 'wchar_size': IDs have conflicting values Since efi.c doesn't actually use wchar_t, turn off the flag when LTO is enabled. Bug: 62093296 Bug: 67506682 Change-Id: I509c18677353add8e1ad04f99f6e42bdab7814e7 Signed-off-by: Sami Tolvanen --- drivers/xen/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 8feab810aed9..7bd882d5f025 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -7,8 +7,10 @@ obj-y += xenbus/ nostackp := $(call cc-option, -fno-stack-protector) CFLAGS_features.o := $(nostackp) +ifndef CONFIG_LTO_CLANG CFLAGS_efi.o += -fshort-wchar LDFLAGS += $(call ld-option, --no-wchar-size-warning) +endif dom0-$(CONFIG_ARM64) += arm-device.o dom0-$(CONFIG_PCI) += pci.o -- GitLab From b13cf8585df2cc51d594bdcfe46bd9e876501d7e Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 8 Dec 2017 15:49:24 -0800 Subject: [PATCH 0091/1834] HACK: init: ensure initcall ordering with LTO With LTO, LLVM sorts initcalls in a single translation unit alphabetically based on the name of the function (or actually, the variable stored in the initcall section). Use __COUNTER__ in the variable name in an attempt to preserve the intended order. Bug: 62093296 Bug: 67506682 Change-Id: I4fa3cb93cba967a1440ac53328eb6b8ac649ff36 Signed-off-by: Sami Tolvanen --- include/linux/init.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/linux/init.h b/include/linux/init.h index 8e346d1bd837..cd365db26a21 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -147,6 +147,15 @@ extern bool initcall_debug; #ifndef __ASSEMBLY__ +#ifdef CONFIG_LTO_CLANG + /* prepend the variable name with __COUNTER__ to ensure correct ordering */ + #define ___initcall_name2(c, fn, id) __initcall_##c##_##fn##id + #define ___initcall_name1(c, fn, id) ___initcall_name2(c, fn, id) + #define __initcall_name(fn, id) ___initcall_name1(__COUNTER__, fn, id) +#else + #define __initcall_name(fn, id) __initcall_##fn##id +#endif + /* * initcalls are now grouped by functionality into separate * subsections. Ordering inside the subsections is determined @@ -164,7 +173,7 @@ extern bool initcall_debug; */ #define __define_initcall(fn, id) \ - static initcall_t __initcall_##fn##id __used \ + static initcall_t __initcall_name(fn, id) __used \ __attribute__((__section__(".initcall" #id ".init"))) = fn; /* -- GitLab From 00a195e7c0752ff5d65c9caadfbcc226270ca232 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 11 May 2017 15:03:36 -0700 Subject: [PATCH 0092/1834] add support for clang Control Flow Integrity (CFI) This change adds the CONFIG_CFI_CLANG option, CFI error handling, and a faster look-up table for cross module CFI checks. Bug: 67506682 Change-Id: Ic009f0a629b552a0eb16e6d89808c7029e91447d Signed-off-by: Sami Tolvanen --- Makefile | 32 ++++ arch/Kconfig | 27 +++ include/asm-generic/vmlinux.lds.h | 3 + include/linux/cfi.h | 38 ++++ include/linux/compiler-clang.h | 2 + include/linux/compiler.h | 4 + include/linux/init.h | 2 +- include/linux/module.h | 5 + init/Kconfig | 2 +- kernel/Makefile | 4 + kernel/cfi.c | 299 ++++++++++++++++++++++++++++++ kernel/module.c | 27 +++ net/Kconfig | 1 + 13 files changed, 444 insertions(+), 2 deletions(-) create mode 100644 include/linux/cfi.h create mode 100644 kernel/cfi.c diff --git a/Makefile b/Makefile index 24b1f9259343..dd65b6074552 100644 --- a/Makefile +++ b/Makefile @@ -676,6 +676,33 @@ export DISABLE_LTO export LDFINAL_vmlinux LDFLAGS_FINAL_vmlinux endif +ifdef CONFIG_CFI_CLANG +cfi-clang-flags += -fsanitize=cfi +DISABLE_CFI_CLANG := -fno-sanitize=cfi +ifdef CONFIG_MODULES +cfi-clang-flags += -fsanitize-cfi-cross-dso +DISABLE_CFI_CLANG += -fno-sanitize-cfi-cross-dso +endif +ifdef CONFIG_CFI_PERMISSIVE +cfi-clang-flags += -fsanitize-recover=cfi -fno-sanitize-trap=cfi +endif + +# also disable CFI when LTO is disabled +DISABLE_LTO_CLANG += $(DISABLE_CFI_CLANG) +# allow disabling only clang CFI where needed +export DISABLE_CFI_CLANG +endif + +ifdef CONFIG_CFI +# cfi-flags are re-tested in prepare-compiler-check +cfi-flags := $(cfi-clang-flags) +KBUILD_CFLAGS += $(cfi-flags) + +DISABLE_CFI := $(DISABLE_CFI_CLANG) +DISABLE_LTO += $(DISABLE_CFI) +export DISABLE_CFI +endif + ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE KBUILD_CFLAGS += $(call cc-option,-Oz,-Os) KBUILD_CFLAGS += $(call cc-disable-warning,maybe-uninitialized,) @@ -1147,6 +1174,11 @@ ifdef stackp-check @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ $(stackp-flag) available but compiler is broken >&2 && exit 1 endif +endif +ifdef cfi-flags + ifeq ($(call cc-option, $(cfi-flags)),) + @echo Cannot use CONFIG_CFI: $(cfi-flags) not supported by compiler >&2 && exit 1 + endif endif @: diff --git a/arch/Kconfig b/arch/Kconfig index 194d179d41da..c0efc0b840a0 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -518,6 +518,33 @@ config LTO_CLANG 5.0 (make CC=clang) and GNU gold from binutils >= 2.27, and have the LLVMgold plug-in in LD_LIBRARY_PATH. +config CFI + bool + +config CFI_PERMISSIVE + bool "Use CFI in permissive mode" + depends on CFI + help + When selected, Control Flow Integrity (CFI) violations result in a + warning instead of a kernel panic. This option is useful for finding + CFI violations in drivers during development. + +config CFI_CLANG + bool "Use clang Control Flow Integrity (CFI) (EXPERIMENTAL)" + depends on LTO_CLANG + depends on KALLSYMS + select CFI + help + This option enables clang Control Flow Integrity (CFI), which adds + runtime checking for indirect function calls. + +config CFI_CLANG_SHADOW + bool "Use CFI shadow to speed up cross-module checks" + default y + depends on CFI_CLANG + help + If you select this option, the kernel builds a fast look-up table of + CFI check functions in loaded modules to reduce overhead. config HAVE_ARCH_WITHIN_STACK_FRAMES bool diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index f2d0a7fbdef8..f8f0e48d2aab 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -67,10 +67,12 @@ */ #ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION #define TEXT_MAIN .text .text.[0-9a-zA-Z_]* +#define TEXT_CFI_MAIN .text.cfi .text.[0-9a-zA-Z_]*.cfi #define DATA_MAIN .data .data.[0-9a-zA-Z_]* #define BSS_MAIN .bss .bss.[0-9a-zA-Z_]* #else #define TEXT_MAIN .text +#define TEXT_CFI_MAIN .text.cfi #define DATA_MAIN .data #define BSS_MAIN .bss #endif @@ -461,6 +463,7 @@ ALIGN_FUNCTION(); \ *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \ *(.text..ftrace) \ + *(TEXT_CFI_MAIN) \ *(.ref.text) \ MEM_KEEP(init.text) \ MEM_KEEP(exit.text) \ diff --git a/include/linux/cfi.h b/include/linux/cfi.h new file mode 100644 index 000000000000..e27033d5dd53 --- /dev/null +++ b/include/linux/cfi.h @@ -0,0 +1,38 @@ +#ifndef _LINUX_CFI_H +#define _LINUX_CFI_H + +#include + +#ifdef CONFIG_CFI_CLANG +#ifdef CONFIG_MODULES + +typedef void (*cfi_check_fn)(uint64_t, void *, void *); + +/* Compiler-generated function in each module, and the kernel */ +#define CFI_CHECK_FN __cfi_check +#define CFI_CHECK_FN_NAME __stringify(CFI_CHECK_FN) + +extern void CFI_CHECK_FN(uint64_t, void *, void *); + +#ifdef CONFIG_CFI_CLANG_SHADOW +extern void cfi_module_add(struct module *mod, unsigned long min_addr, + unsigned long max_addr); + +extern void cfi_module_remove(struct module *mod, unsigned long min_addr, + unsigned long max_addr); +#else +static inline void cfi_module_add(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ +} + +static inline void cfi_module_remove(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ +} +#endif /* CONFIG_CFI_CLANG_SHADOW */ + +#endif /* CONFIG_MODULES */ +#endif /* CONFIG_CFI_CLANG */ + +#endif /* _LINUX_CFI_H */ diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index fd299451aa0b..eeb2331e9fa3 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -21,4 +21,6 @@ #define __norecordmcount \ __attribute__((__section__(".text..ftrace"))) #endif + +#define __nocfi __attribute__((no_sanitize("cfi"))) #endif diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 40445d0df89c..81bcdcaaceb3 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -455,6 +455,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s #define __norecordmcount #endif +#ifndef __nocfi +#define __nocfi +#endif + /* * Assume alignment of return value. */ diff --git a/include/linux/init.h b/include/linux/init.h index cd365db26a21..2a10aca99829 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -46,7 +46,7 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __section(.init.text) __cold notrace __latent_entropy __noretpoline +#define __init __section(.init.text) __cold notrace __latent_entropy __noretpoline __nocfi #define __initdata __section(.init.data) #define __initconst __section(.init.rodata) #define __exitdata __section(.exit.data) diff --git a/include/linux/module.h b/include/linux/module.h index fd9e121c7b3f..9d6fd1d17edb 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -20,6 +20,7 @@ #include #include /* only as arch move module.h -> extable.h */ #include +#include #include #include @@ -349,6 +350,10 @@ struct module { const unsigned long *crcs; unsigned int num_syms; +#ifdef CONFIG_CFI_CLANG + cfi_check_fn cfi_check; +#endif + /* Kernel parameters. */ #ifdef CONFIG_SYSFS struct mutex param_lock; diff --git a/init/Kconfig b/init/Kconfig index 544d7910d89b..ead5f456fc3c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -2245,7 +2245,7 @@ endif # MODULES config MODULES_TREE_LOOKUP def_bool y - depends on PERF_EVENTS || TRACING + depends on PERF_EVENTS || TRACING || CFI_CLANG config INIT_ALL_POSSIBLE bool diff --git a/kernel/Makefile b/kernel/Makefile index 314e7d62f5f0..108f5bee0111 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -32,6 +32,9 @@ KASAN_SANITIZE_kcov.o := n # cond_syscall is currently not LTO compatible CFLAGS_sys_ni.o = $(DISABLE_LTO) +# Don't instrument error handlers +CFLAGS_cfi.o = $(DISABLE_CFI_CLANG) + obj-y += sched/ obj-y += locking/ obj-y += power/ @@ -101,6 +104,7 @@ obj-$(CONFIG_TRACEPOINTS) += trace/ obj-$(CONFIG_IRQ_WORK) += irq_work.o obj-$(CONFIG_CPU_PM) += cpu_pm.o obj-$(CONFIG_BPF) += bpf/ +obj-$(CONFIG_CFI_CLANG) += cfi.o obj-$(CONFIG_PERF_EVENTS) += events/ diff --git a/kernel/cfi.c b/kernel/cfi.c new file mode 100644 index 000000000000..87053e2c0acf --- /dev/null +++ b/kernel/cfi.c @@ -0,0 +1,299 @@ +/* + * CFI (Control Flow Integrity) error and slowpath handling + * + * Copyright (C) 2017 Google, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Compiler-defined handler names */ +#ifdef CONFIG_CFI_PERMISSIVE +#define cfi_failure_handler __ubsan_handle_cfi_check_fail +#define cfi_slowpath_handler __cfi_slowpath_diag +#else /* enforcing */ +#define cfi_failure_handler __ubsan_handle_cfi_check_fail_abort +#define cfi_slowpath_handler __cfi_slowpath +#endif /* CONFIG_CFI_PERMISSIVE */ + +static inline void handle_cfi_failure() +{ +#ifdef CONFIG_CFI_PERMISSIVE + WARN_RATELIMIT(1, "CFI failure:\n"); +#else + pr_err("CFI failure:\n"); + BUG(); +#endif +} + +#ifdef CONFIG_MODULES +#ifdef CONFIG_CFI_CLANG_SHADOW +struct shadow_range { + /* Module address range */ + unsigned long mod_min_addr; + unsigned long mod_max_addr; + /* Module page range */ + unsigned long min_page; + unsigned long max_page; +}; + +#define SHADOW_ORDER 1 +#define SHADOW_PAGES (1 << SHADOW_ORDER) +#define SHADOW_SIZE \ + ((SHADOW_PAGES * PAGE_SIZE - sizeof(struct shadow_range)) / sizeof(u16)) +#define SHADOW_INVALID 0xFFFF + +struct cfi_shadow { + /* Page range covered by the shadow */ + struct shadow_range r; + /* Page offsets to __cfi_check functions in modules */ + u16 shadow[SHADOW_SIZE]; +}; + +static DEFINE_SPINLOCK(shadow_update_lock); +static struct cfi_shadow __rcu *cfi_shadow __read_mostly = NULL; + +static inline int ptr_to_shadow(const struct cfi_shadow *s, unsigned long ptr) +{ + unsigned long index; + unsigned long page = ptr >> PAGE_SHIFT; + + if (unlikely(page < s->r.min_page)) + return -1; /* Outside of module area */ + + index = page - s->r.min_page; + + if (index >= SHADOW_SIZE) + return -1; /* Cannot be addressed with shadow */ + + return (int)index; +} + +static inline unsigned long shadow_to_ptr(const struct cfi_shadow *s, + int index) +{ + BUG_ON(index < 0 || index >= SHADOW_SIZE); + + if (unlikely(s->shadow[index] == SHADOW_INVALID)) + return 0; + + return (s->r.min_page + s->shadow[index]) << PAGE_SHIFT; +} + +static void prepare_next_shadow(const struct cfi_shadow __rcu *prev, + struct cfi_shadow *next) +{ + int i, index, check; + + /* Mark everything invalid */ + memset(next->shadow, 0xFF, sizeof(next->shadow)); + + if (!prev) + return; /* No previous shadow */ + + /* If the base address didn't change, update is not needed */ + if (prev->r.min_page == next->r.min_page) { + memcpy(next->shadow, prev->shadow, sizeof(next->shadow)); + return; + } + + /* Convert the previous shadow to the new address range */ + for (i = 0; i < SHADOW_SIZE; ++i) { + if (prev->shadow[i] == SHADOW_INVALID) + continue; + + index = ptr_to_shadow(next, shadow_to_ptr(prev, i)); + if (index < 0) + continue; + + check = ptr_to_shadow(next, + shadow_to_ptr(prev, prev->shadow[i])); + if (check < 0) + continue; + + next->shadow[index] = (u16)check; + } +} + +static void add_module_to_shadow(struct cfi_shadow *s, struct module *mod) +{ + unsigned long ptr; + unsigned long min_page_addr; + unsigned long max_page_addr; + unsigned long check = (unsigned long)mod->cfi_check; + int check_index = ptr_to_shadow(s, check); + + BUG_ON((check & PAGE_MASK) != check); /* Must be page aligned */ + + if (check_index < 0) + return; /* Module not addressable with shadow */ + + min_page_addr = (unsigned long)mod->core_layout.base & PAGE_MASK; + max_page_addr = (unsigned long)mod->core_layout.base + + mod->core_layout.text_size; + max_page_addr &= PAGE_MASK; + + /* For each page, store the check function index in the shadow */ + for (ptr = min_page_addr; ptr <= max_page_addr; ptr += PAGE_SIZE) { + int index = ptr_to_shadow(s, ptr); + if (index >= 0) { + /* Assume a page only contains code for one module */ + BUG_ON(s->shadow[index] != SHADOW_INVALID); + s->shadow[index] = (u16)check_index; + } + } +} + +static void remove_module_from_shadow(struct cfi_shadow *s, struct module *mod) +{ + unsigned long ptr; + unsigned long min_page_addr; + unsigned long max_page_addr; + + min_page_addr = (unsigned long)mod->core_layout.base & PAGE_MASK; + max_page_addr = (unsigned long)mod->core_layout.base + + mod->core_layout.text_size; + max_page_addr &= PAGE_MASK; + + for (ptr = min_page_addr; ptr <= max_page_addr; ptr += PAGE_SIZE) { + int index = ptr_to_shadow(s, ptr); + if (index >= 0) + s->shadow[index] = SHADOW_INVALID; + } +} + +typedef void (*update_shadow_fn)(struct cfi_shadow *, struct module *); + +static void update_shadow(struct module *mod, unsigned long min_addr, + unsigned long max_addr, update_shadow_fn fn) +{ + struct cfi_shadow *prev; + struct cfi_shadow *next = (struct cfi_shadow *) + __get_free_pages(GFP_KERNEL, SHADOW_ORDER); + + BUG_ON(!next); + + next->r.mod_min_addr = min_addr; + next->r.mod_max_addr = max_addr; + next->r.min_page = min_addr >> PAGE_SHIFT; + next->r.max_page = max_addr >> PAGE_SHIFT; + + spin_lock(&shadow_update_lock); + prev = rcu_dereference_protected(cfi_shadow, 1); + prepare_next_shadow(prev, next); + + fn(next, mod); + set_memory_ro((unsigned long)next, SHADOW_PAGES); + rcu_assign_pointer(cfi_shadow, next); + + spin_unlock(&shadow_update_lock); + synchronize_rcu(); + + if (prev) { + set_memory_rw((unsigned long)prev, SHADOW_PAGES); + free_pages((unsigned long)prev, SHADOW_ORDER); + } +} + +void cfi_module_add(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ + update_shadow(mod, min_addr, max_addr, add_module_to_shadow); +} +EXPORT_SYMBOL(cfi_module_add); + +void cfi_module_remove(struct module *mod, unsigned long min_addr, + unsigned long max_addr) +{ + update_shadow(mod, min_addr, max_addr, remove_module_from_shadow); +} +EXPORT_SYMBOL(cfi_module_remove); + +static inline cfi_check_fn ptr_to_check_fn(const struct cfi_shadow __rcu *s, + unsigned long ptr) +{ + int index; + unsigned long check; + + if (unlikely(!s)) + return NULL; /* No shadow available */ + + if (ptr < s->r.mod_min_addr || ptr > s->r.mod_max_addr) + return NULL; /* Not in a mapped module */ + + index = ptr_to_shadow(s, ptr); + if (index < 0) + return NULL; /* Cannot be addressed with shadow */ + + return (cfi_check_fn)shadow_to_ptr(s, index); +} +#endif /* CONFIG_CFI_CLANG_SHADOW */ + +static inline cfi_check_fn find_module_cfi_check(void *ptr) +{ + struct module *mod; + + preempt_disable(); + mod = __module_address((unsigned long)ptr); + preempt_enable(); + + if (mod) + return mod->cfi_check; + + return CFI_CHECK_FN; +} + +static inline cfi_check_fn find_cfi_check(void *ptr) +{ +#ifdef CONFIG_CFI_CLANG_SHADOW + cfi_check_fn f; + + if (!rcu_access_pointer(cfi_shadow)) + return CFI_CHECK_FN; /* No loaded modules */ + + /* Look up the __cfi_check function to use */ + rcu_read_lock(); + f = ptr_to_check_fn(rcu_dereference(cfi_shadow), (unsigned long)ptr); + rcu_read_unlock(); + + if (f) + return f; + + /* + * Fall back to find_module_cfi_check, which works also for a larger + * module address space, but is slower. + */ +#endif /* CONFIG_CFI_CLANG_SHADOW */ + + return find_module_cfi_check(ptr); +} + +void cfi_slowpath_handler(uint64_t id, void *ptr, void *diag) +{ + cfi_check_fn check = find_cfi_check(ptr); + + if (likely(check)) + check(id, ptr, diag); + else /* Don't allow unchecked modules */ + handle_cfi_failure(); +} +EXPORT_SYMBOL(cfi_slowpath_handler); +#endif /* CONFIG_MODULES */ + +void cfi_failure_handler(void *data, void *value, void *vtable) +{ + handle_cfi_failure(); +} +EXPORT_SYMBOL(cfi_failure_handler); + +void __cfi_check_fail(void *data, void *value) +{ + handle_cfi_failure(); +} diff --git a/kernel/module.c b/kernel/module.c index 07bfb9971f2f..dec20c76ac80 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2085,6 +2085,8 @@ void __weak module_arch_freeing_init(struct module *mod) { } +static void cfi_cleanup(struct module *mod); + /* Free a module, remove from lists, etc. */ static void free_module(struct module *mod) { @@ -2126,6 +2128,10 @@ static void free_module(struct module *mod) /* This may be empty, but that's OK */ disable_ro_nx(&mod->init_layout); + + /* Clean up CFI for the module. */ + cfi_cleanup(mod); + module_arch_freeing_init(mod); module_memfree(mod->init_layout.base); kfree(mod->args); @@ -3307,6 +3313,8 @@ int __weak module_finalize(const Elf_Ehdr *hdr, return 0; } +static void cfi_init(struct module *mod); + static int post_relocation(struct module *mod, const struct load_info *info) { /* Sort exception table now relocations are done. */ @@ -3319,6 +3327,9 @@ static int post_relocation(struct module *mod, const struct load_info *info) /* Setup kallsyms-specific fields. */ add_kallsyms(mod, info); + /* Setup CFI for the module. */ + cfi_init(mod); + /* Arch-specific module finalizing. */ return module_finalize(info->hdr, info->sechdrs, mod); } @@ -4053,6 +4064,22 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, } #endif /* CONFIG_KALLSYMS */ +static void cfi_init(struct module *mod) +{ +#ifdef CONFIG_CFI_CLANG + mod->cfi_check = + (cfi_check_fn)mod_find_symname(mod, CFI_CHECK_FN_NAME); + cfi_module_add(mod, module_addr_min, module_addr_max); +#endif +} + +static void cfi_cleanup(struct module *mod) +{ +#ifdef CONFIG_CFI_CLANG + cfi_module_remove(mod, module_addr_min, module_addr_max); +#endif +} + static char *module_flags(struct module *mod, char *buf) { int bx = 0; diff --git a/net/Kconfig b/net/Kconfig index 28071fc1594c..37757600171a 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -294,6 +294,7 @@ config BPF_JIT bool "enable BPF Just In Time compiler" depends on HAVE_CBPF_JIT || HAVE_EBPF_JIT depends on MODULES + depends on !CFI ---help--- Berkeley Packet Filter filtering capabilities are normally handled by an interpreter. This option allows kernel to generate a native -- GitLab From 84bfde9a00a8d4abb3ff19a8e848e068b4b90de4 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 14 Feb 2018 10:26:35 -0800 Subject: [PATCH 0093/1834] kallsyms: strip the .cfi postfix from symbols with CONFIG_CFI_CLANG With CFI enabled, LLVM appends .cfi to most function names, which potentially breaks user space tools. While stripping the postfix is not optimal either, this should at least create less confusion. Bug: 67506682 Bug: 73328469 Change-Id: I253f34a562629032ddd792b8498e171109ea7cbc Signed-off-by: Sami Tolvanen --- kernel/kallsyms.c | 53 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index fafd1a3ef0da..a0c3365c884b 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -306,6 +306,24 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf); } +#ifdef CONFIG_CFI_CLANG +/* + * LLVM appends .cfi to function names when CONFIG_CFI_CLANG is enabled, + * which causes confusion and potentially breaks user space tools, so we + * will strip the postfix from expanded symbol names. + */ +static inline void cleanup_symbol_name(char *s) +{ + char *res; + + res = strrchr(s, '.'); + if (res && !strcmp(res, ".cfi")) + *res = '\0'; +} +#else +static inline void cleanup_symbol_name(char *s) {} +#endif + /* * Lookup an address * - modname is set to NULL if it's in the kernel. @@ -330,16 +348,23 @@ const char *kallsyms_lookup(unsigned long addr, namebuf, KSYM_NAME_LEN); if (modname) *modname = NULL; - return namebuf; + goto found; } /* See if it's in a module. */ - return module_address_lookup(addr, symbolsize, offset, modname, - namebuf); + if (!module_address_lookup(addr, symbolsize, offset, modname, + namebuf)) + return NULL; + +found: + cleanup_symbol_name(namebuf); + return namebuf; } int lookup_symbol_name(unsigned long addr, char *symname) { + int res; + symname[0] = '\0'; symname[KSYM_NAME_LEN - 1] = '\0'; @@ -350,15 +375,23 @@ int lookup_symbol_name(unsigned long addr, char *symname) /* Grab name */ kallsyms_expand_symbol(get_symbol_offset(pos), symname, KSYM_NAME_LEN); - return 0; + goto found; } /* See if it's in a module. */ - return lookup_module_symbol_name(addr, symname); + res = lookup_module_symbol_name(addr, symname); + if (res) + return res; + +found: + cleanup_symbol_name(symname); + return 0; } int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name) { + int res; + name[0] = '\0'; name[KSYM_NAME_LEN - 1] = '\0'; @@ -370,10 +403,16 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, kallsyms_expand_symbol(get_symbol_offset(pos), name, KSYM_NAME_LEN); modname[0] = '\0'; - return 0; + goto found; } /* See if it's in a module. */ - return lookup_module_symbol_attrs(addr, size, offset, modname, name); + res = lookup_module_symbol_attrs(addr, size, offset, modname, name); + if (res) + return res; + +found: + cleanup_symbol_name(name); + return 0; } /* Look up a kernel symbol and return it in a text buffer. */ -- GitLab From 417637a2d9d2c40511fd47f133e6203b708a2c16 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 24 Aug 2017 08:59:31 -0700 Subject: [PATCH 0094/1834] bpf: fix function type for __bpf_prog_run Bug: 67506682 Change-Id: I096a470c65a2a1867c51da9a33843ae23bf5e547 Signed-off-by: Sami Tolvanen --- kernel/bpf/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 879ca844ba1d..66d64db4f8c7 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -466,7 +466,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base); * * Decode and execute eBPF instructions. */ -static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) +static unsigned int __bpf_prog_run(const struct sk_buff *ctx, const struct bpf_insn *insn) { u64 stack[MAX_BPF_STACK / sizeof(u64)]; u64 regs[MAX_BPF_REG], tmp; -- GitLab From 38cbecf2ae55478a2046ef4fc93b9d9147fbb170 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Oct 2017 19:04:41 -0700 Subject: [PATCH 0095/1834] UPSTREAM: module: Prepare to convert all module_param_call() prototypes After actually converting all module_param_call() function prototypes, we no longer need to do a tricky sizeof(func(thing)) type-check. Remove it. Signed-off-by: Kees Cook Signed-off-by: Jessica Yu Bug: 67506682 Change-Id: Ie20dbd09634c7cbef499c81bf2dbfd762ad0058a (cherry picked from commit b2f270e8747387335d80428c576118e7d87f69cc) Signed-off-by: Sami Tolvanen --- include/linux/moduleparam.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 52666d90ca94..952c7342a741 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -226,18 +226,10 @@ struct kparam_array /* Obsolete - use module_param_cb() */ #define module_param_call(name, set, get, arg, perm) \ - static const struct kernel_param_ops __param_ops_##name = \ + static const struct kernel_param_ops __param_ops_##name = \ { .flags = 0, (void *)set, (void *)get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ - name, &__param_ops_##name, arg, \ - (perm) + sizeof(__check_old_set_param(set))*0, -1, 0) - -/* We don't get oldget: it's often a new-style param_get_uint, etc. */ -static inline int -__check_old_set_param(int (*oldset)(const char *, struct kernel_param *)) -{ - return 0; -} + name, &__param_ops_##name, arg, perm, -1, 0) #ifdef CONFIG_SYSFS extern void kernel_param_lock(struct module *mod); -- GitLab From 24da2c84bd7dcdf2b56fa8d3b2f833656ee60a01 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Oct 2017 19:04:42 -0700 Subject: [PATCH 0096/1834] BACKPORT: treewide: Fix function prototypes for module_param_call() Several function prototypes for the set/get functions defined by module_param_call() have a slightly wrong argument types. This fixes those in an effort to clean up the calls when running under type-enforced compiler instrumentation for CFI. This is the result of running the following semantic patch: @match_module_param_call_function@ declarer name module_param_call; identifier _name, _set_func, _get_func; expression _arg, _mode; @@ module_param_call(_name, _set_func, _get_func, _arg, _mode); @fix_set_prototype depends on match_module_param_call_function@ identifier match_module_param_call_function._set_func; identifier _val, _param; type _val_type, _param_type; @@ int _set_func( -_val_type _val +const char * _val , -_param_type _param +const struct kernel_param * _param ) { ... } @fix_get_prototype depends on match_module_param_call_function@ identifier match_module_param_call_function._get_func; identifier _val, _param; type _val_type, _param_type; @@ int _get_func( -_val_type _val +char * _val , -_param_type _param +const struct kernel_param * _param ) { ... } Two additional by-hand changes are included for places where the above Coccinelle script didn't notice them: drivers/platform/x86/thinkpad_acpi.c fs/lockd/svc.c Signed-off-by: Kees Cook Signed-off-by: Jessica Yu Bug: 67506682 Change-Id: I2c9c0ee8ed28065e63270a52c155e5e7d2791295 (cherry picked from commit e4dca7b7aa08b22893c45485d222b5807c1375ae) Signed-off-by: Sami Tolvanen --- arch/powerpc/platforms/pseries/cmm.c | 2 +- arch/x86/oprofile/nmi_int.c | 2 +- drivers/acpi/button.c | 6 ++++-- drivers/acpi/ec.c | 6 ++++-- drivers/acpi/sysfs.c | 8 +++++--- drivers/android/binder.c | 2 +- drivers/char/ipmi/ipmi_poweroff.c | 2 +- drivers/char/ipmi/ipmi_si_intf.c | 4 ++-- drivers/edac/edac_mc_sysfs.c | 2 +- drivers/edac/edac_module.c | 3 ++- drivers/hid/hid-magicmouse.c | 3 ++- drivers/ide/ide.c | 4 ++-- drivers/infiniband/hw/qib/qib_iba7322.c | 4 ++-- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- drivers/isdn/hardware/mISDN/avmfritz.c | 2 +- drivers/isdn/hardware/mISDN/mISDNinfineon.c | 2 +- drivers/isdn/hardware/mISDN/netjet.c | 2 +- drivers/isdn/hardware/mISDN/speedfax.c | 2 +- drivers/isdn/hardware/mISDN/w6692.c | 2 +- drivers/md/md.c | 6 +++--- drivers/media/pci/tw686x/tw686x-core.c | 4 ++-- drivers/media/usb/uvc/uvc_driver.c | 4 ++-- drivers/message/fusion/mptbase.c | 4 ++-- drivers/misc/kgdbts.c | 3 ++- drivers/mtd/devices/block2mtd.c | 2 +- drivers/mtd/devices/phram.c | 2 +- drivers/mtd/ubi/build.c | 2 +- drivers/pci/pcie/aspm.c | 5 +++-- drivers/platform/x86/thinkpad_acpi.c | 2 +- drivers/scsi/fcoe/fcoe_transport.c | 20 ++++++++++++-------- drivers/scsi/mpt3sas/mpt3sas_base.c | 2 +- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 +- drivers/tty/serial/kgdboc.c | 3 ++- fs/fuse/inode.c | 4 ++-- fs/lockd/svc.c | 2 +- fs/ocfs2/dlmfs/dlmfs.c | 4 ++-- include/net/netfilter/nf_conntrack.h | 2 +- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/nf_nat_ftp.c | 2 +- net/netfilter/nf_nat_irc.c | 2 +- net/sunrpc/svc.c | 4 ++-- security/apparmor/lsm.c | 16 ++++++++-------- 42 files changed, 87 insertions(+), 72 deletions(-) diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 66e7227469b8..85018a14217a 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -708,7 +708,7 @@ static void cmm_exit(void) * Return value: * 0 on success / other on failure **/ -static int cmm_set_disable(const char *val, struct kernel_param *kp) +static int cmm_set_disable(const char *val, const struct kernel_param *kp) { int disable = simple_strtoul(val, NULL, 10); diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 842ca3cab6b3..18f9dad8dc79 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c @@ -615,7 +615,7 @@ enum __force_cpu_type { static int force_cpu_type; -static int set_cpu_type(const char *str, struct kernel_param *kp) +static int set_cpu_type(const char *str, const struct kernel_param *kp) { if (!strcmp(str, "timer")) { force_cpu_type = timer; diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index e19f530f1083..f7c4301f7fa3 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -556,7 +556,8 @@ static int acpi_button_remove(struct acpi_device *device) return 0; } -static int param_set_lid_init_state(const char *val, struct kernel_param *kp) +static int param_set_lid_init_state(const char *val, + const struct kernel_param *kp) { int result = 0; @@ -574,7 +575,8 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp) return result; } -static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) +static int param_get_lid_init_state(char *buffer, + const struct kernel_param *kp) { switch (lid_init_state) { case ACPI_BUTTON_LID_INIT_OPEN: diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c3bcb7f5986e..b4a2c3175186 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1891,7 +1891,8 @@ static const struct dev_pm_ops acpi_ec_pm = { SET_SYSTEM_SLEEP_PM_OPS(acpi_ec_suspend, acpi_ec_resume) }; -static int param_set_event_clearing(const char *val, struct kernel_param *kp) +static int param_set_event_clearing(const char *val, + const struct kernel_param *kp) { int result = 0; @@ -1909,7 +1910,8 @@ static int param_set_event_clearing(const char *val, struct kernel_param *kp) return result; } -static int param_get_event_clearing(char *buffer, struct kernel_param *kp) +static int param_get_event_clearing(char *buffer, + const struct kernel_param *kp) { switch (ec_event_clearing) { case ACPI_EC_EVT_TIMING_STATUS: diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index cf05ae973381..34328e1b52d0 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -227,7 +227,8 @@ module_param_cb(trace_method_name, ¶m_ops_trace_method, &trace_method_name, module_param_cb(trace_debug_layer, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_layer, 0644); module_param_cb(trace_debug_level, ¶m_ops_trace_attrib, &acpi_gbl_trace_dbg_level, 0644); -static int param_set_trace_state(const char *val, struct kernel_param *kp) +static int param_set_trace_state(const char *val, + const struct kernel_param *kp) { acpi_status status; const char *method = trace_method_name; @@ -263,7 +264,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp) return 0; } -static int param_get_trace_state(char *buffer, struct kernel_param *kp) +static int param_get_trace_state(char *buffer, const struct kernel_param *kp) { if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) return sprintf(buffer, "disable"); @@ -292,7 +293,8 @@ MODULE_PARM_DESC(aml_debug_output, "To enable/disable the ACPI Debug Object output."); /* /sys/module/acpi/parameters/acpica_version */ -static int param_get_acpica_version(char *buffer, struct kernel_param *kp) +static int param_get_acpica_version(char *buffer, + const struct kernel_param *kp) { int result; diff --git a/drivers/android/binder.c b/drivers/android/binder.c index ff367b8faece..dcd32521d50d 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -151,7 +151,7 @@ static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait); static int binder_stop_on_user_error; static int binder_set_stop_on_user_error(const char *val, - struct kernel_param *kp) + const struct kernel_param *kp) { int ret; diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 9f2e3be2c5b8..676c910e990f 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -66,7 +66,7 @@ static void (*specific_poweroff_func)(ipmi_user_t user); /* Holds the old poweroff function so we can restore it on removal. */ static void (*old_poweroff_func)(void); -static int set_param_ifnum(const char *val, struct kernel_param *kp) +static int set_param_ifnum(const char *val, const struct kernel_param *kp) { int rv = param_set_int(val, kp); if (rv) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index e0a53156b782..89adeb4905f1 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1344,7 +1344,7 @@ static unsigned int num_slave_addrs; #define IPMI_MEM_ADDR_SPACE 1 static const char * const addr_space_to_str[] = { "i/o", "mem" }; -static int hotmod_handler(const char *val, struct kernel_param *kp); +static int hotmod_handler(const char *val, const struct kernel_param *kp); module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200); MODULE_PARM_DESC(hotmod, "Add and remove interfaces. See" @@ -1814,7 +1814,7 @@ static struct smi_info *smi_info_alloc(void) return info; } -static int hotmod_handler(const char *val, struct kernel_param *kp) +static int hotmod_handler(const char *val, const struct kernel_param *kp) { char *str = kstrdup(val, GFP_KERNEL); int rv; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4e0f8e720ad9..bea71fb006a6 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -50,7 +50,7 @@ int edac_mc_get_poll_msec(void) return edac_mc_poll_msec; } -static int edac_set_poll_msec(const char *val, struct kernel_param *kp) +static int edac_set_poll_msec(const char *val, const struct kernel_param *kp) { unsigned long l; int ret; diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 5f8543be995a..b0d32843d58b 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -19,7 +19,8 @@ #ifdef CONFIG_EDAC_DEBUG -static int edac_set_debug_level(const char *buf, struct kernel_param *kp) +static int edac_set_debug_level(const char *buf, + const struct kernel_param *kp) { unsigned long val; int ret; diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 20b40ad26325..42ed887ba0be 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -34,7 +34,8 @@ module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); static unsigned int scroll_speed = 32; -static int param_set_scroll_speed(const char *val, struct kernel_param *kp) { +static int param_set_scroll_speed(const char *val, + const struct kernel_param *kp) { unsigned long speed; if (!val || kstrtoul(val, 0, &speed) || speed > 63) return -EINVAL; diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index d127ace6aa57..6ee866fcc5dd 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -244,7 +244,7 @@ struct chs_geom { static unsigned int ide_disks; static struct chs_geom ide_disks_chs[MAX_HWIFS * MAX_DRIVES]; -static int ide_set_disk_chs(const char *str, struct kernel_param *kp) +static int ide_set_disk_chs(const char *str, const struct kernel_param *kp) { unsigned int a, b, c = 0, h = 0, s = 0, i, j = 1; @@ -328,7 +328,7 @@ static void ide_dev_apply_params(ide_drive_t *drive, u8 unit) static unsigned int ide_ignore_cable; -static int ide_set_ignore_cable(const char *s, struct kernel_param *kp) +static int ide_set_ignore_cable(const char *s, const struct kernel_param *kp) { int i, j = 1; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index cedb447d0162..228cb4c70363 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -150,7 +150,7 @@ static struct kparam_string kp_txselect = { .string = txselect_list, .maxlen = MAX_ATTEN_LEN }; -static int setup_txselect(const char *, struct kernel_param *); +static int setup_txselect(const char *, const struct kernel_param *); module_param_call(txselect, setup_txselect, param_get_string, &kp_txselect, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(txselect, @@ -6177,7 +6177,7 @@ static void set_no_qsfp_atten(struct qib_devdata *dd, int change) } /* handle the txselect parameter changing */ -static int setup_txselect(const char *str, struct kernel_param *kp) +static int setup_txselect(const char *str, const struct kernel_param *kp) { struct qib_devdata *dd; unsigned long val; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 29ab814693fc..7cf468a8d069 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -80,7 +80,7 @@ module_param(srpt_srq_size, int, 0444); MODULE_PARM_DESC(srpt_srq_size, "Shared receive queue (SRQ) size."); -static int srpt_get_u64_x(char *buffer, struct kernel_param *kp) +static int srpt_get_u64_x(char *buffer, const struct kernel_param *kp) { return sprintf(buffer, "0x%016llx", *(u64 *)kp->arg); } diff --git a/drivers/isdn/hardware/mISDN/avmfritz.c b/drivers/isdn/hardware/mISDN/avmfritz.c index e3fa1cd64470..a57b04f749fe 100644 --- a/drivers/isdn/hardware/mISDN/avmfritz.c +++ b/drivers/isdn/hardware/mISDN/avmfritz.c @@ -156,7 +156,7 @@ _set_debug(struct fritzcard *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct fritzcard *card; diff --git a/drivers/isdn/hardware/mISDN/mISDNinfineon.c b/drivers/isdn/hardware/mISDN/mISDNinfineon.c index d5bdbaf93a1a..1fc290659e94 100644 --- a/drivers/isdn/hardware/mISDN/mISDNinfineon.c +++ b/drivers/isdn/hardware/mISDN/mISDNinfineon.c @@ -244,7 +244,7 @@ _set_debug(struct inf_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct inf_hw *card; diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c index afde4edef9ae..e9fcae4569af 100644 --- a/drivers/isdn/hardware/mISDN/netjet.c +++ b/drivers/isdn/hardware/mISDN/netjet.c @@ -111,7 +111,7 @@ _set_debug(struct tiger_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct tiger_hw *card; diff --git a/drivers/isdn/hardware/mISDN/speedfax.c b/drivers/isdn/hardware/mISDN/speedfax.c index 9815bb4eec9c..1f1446ed8d5f 100644 --- a/drivers/isdn/hardware/mISDN/speedfax.c +++ b/drivers/isdn/hardware/mISDN/speedfax.c @@ -94,7 +94,7 @@ _set_debug(struct sfax_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct sfax_hw *card; diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c index 3b067ea656bd..0db6783a139f 100644 --- a/drivers/isdn/hardware/mISDN/w6692.c +++ b/drivers/isdn/hardware/mISDN/w6692.c @@ -101,7 +101,7 @@ _set_debug(struct w6692_hw *card) } static int -set_debug(const char *val, struct kernel_param *kp) +set_debug(const char *val, const struct kernel_param *kp) { int ret; struct w6692_hw *card; diff --git a/drivers/md/md.c b/drivers/md/md.c index 8ebf1b97e1d2..93980034d687 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5095,7 +5095,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) return NULL; } -static int add_named_array(const char *val, struct kernel_param *kp) +static int add_named_array(const char *val, const struct kernel_param *kp) { /* val must be "md_*" where * is not all digits. * We allocate an array with a large free minor number, and @@ -8965,11 +8965,11 @@ static __exit void md_exit(void) subsys_initcall(md_init); module_exit(md_exit) -static int get_ro(char *buffer, struct kernel_param *kp) +static int get_ro(char *buffer, const struct kernel_param *kp) { return sprintf(buffer, "%d", start_readonly); } -static int set_ro(const char *val, struct kernel_param *kp) +static int set_ro(const char *val, const struct kernel_param *kp) { return kstrtouint(val, 10, (unsigned int *)&start_readonly); } diff --git a/drivers/media/pci/tw686x/tw686x-core.c b/drivers/media/pci/tw686x/tw686x-core.c index 71a0453b1af1..279d4478c2a1 100644 --- a/drivers/media/pci/tw686x/tw686x-core.c +++ b/drivers/media/pci/tw686x/tw686x-core.c @@ -72,12 +72,12 @@ static const char *dma_mode_name(unsigned int mode) } } -static int tw686x_dma_mode_get(char *buffer, struct kernel_param *kp) +static int tw686x_dma_mode_get(char *buffer, const struct kernel_param *kp) { return sprintf(buffer, dma_mode_name(dma_mode)); } -static int tw686x_dma_mode_set(const char *val, struct kernel_param *kp) +static int tw686x_dma_mode_set(const char *val, const struct kernel_param *kp) { if (!strcasecmp(val, dma_mode_name(TW686X_DMA_MODE_MEMCPY))) dma_mode = TW686X_DMA_MODE_MEMCPY; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index cde43b63c3da..8412dfc02b58 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2184,7 +2184,7 @@ static int uvc_reset_resume(struct usb_interface *intf) * Module parameters */ -static int uvc_clock_param_get(char *buffer, struct kernel_param *kp) +static int uvc_clock_param_get(char *buffer, const struct kernel_param *kp) { if (uvc_clock_param == CLOCK_MONOTONIC) return sprintf(buffer, "CLOCK_MONOTONIC"); @@ -2192,7 +2192,7 @@ static int uvc_clock_param_get(char *buffer, struct kernel_param *kp) return sprintf(buffer, "CLOCK_REALTIME"); } -static int uvc_clock_param_set(const char *val, struct kernel_param *kp) +static int uvc_clock_param_set(const char *val, const struct kernel_param *kp) { if (strncasecmp(val, "clock_", strlen("clock_")) == 0) val += strlen("clock_"); diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 89c7ed16b4df..1cdab6d00b43 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -99,7 +99,7 @@ module_param(mpt_channel_mapping, int, 0); MODULE_PARM_DESC(mpt_channel_mapping, " Mapping id's to channels (default=0)"); static int mpt_debug_level; -static int mpt_set_debug_level(const char *val, struct kernel_param *kp); +static int mpt_set_debug_level(const char *val, const struct kernel_param *kp); module_param_call(mpt_debug_level, mpt_set_debug_level, param_get_int, &mpt_debug_level, 0600); MODULE_PARM_DESC(mpt_debug_level, @@ -242,7 +242,7 @@ pci_enable_io_access(struct pci_dev *pdev) pci_write_config_word(pdev, PCI_COMMAND, command_reg); } -static int mpt_set_debug_level(const char *val, struct kernel_param *kp) +static int mpt_set_debug_level(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); MPT_ADAPTER *ioc; diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c index 99635dd9dbac..2290845eaba5 100644 --- a/drivers/misc/kgdbts.c +++ b/drivers/misc/kgdbts.c @@ -1130,7 +1130,8 @@ static void kgdbts_put_char(u8 chr) ts.run_test(0, chr); } -static int param_set_kgdbts_var(const char *kmessage, struct kernel_param *kp) +static int param_set_kgdbts_var(const char *kmessage, + const struct kernel_param *kp) { int len = strlen(kmessage); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 7c887f111a7d..62fd6905c648 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -431,7 +431,7 @@ static int block2mtd_setup2(const char *val) } -static int block2mtd_setup(const char *val, struct kernel_param *kp) +static int block2mtd_setup(const char *val, const struct kernel_param *kp) { #ifdef MODULE return block2mtd_setup2(val); diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 8b66e52ca3cc..7287696a21f9 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -266,7 +266,7 @@ static int phram_setup(const char *val) return ret; } -static int phram_param_call(const char *val, struct kernel_param *kp) +static int phram_param_call(const char *val, const struct kernel_param *kp) { #ifdef MODULE return phram_setup(val); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 85d54f37e28f..e1da78f40731 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1389,7 +1389,7 @@ static int __init bytes_str_to_int(const char *str) * This function returns zero in case of success and a negative error code in * case of error. */ -static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) +static int __init ubi_mtd_param_parse(const char *val, const struct kernel_param *kp) { int i, len; struct mtd_dev_param *p; diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index b0916b126923..d7269876fc03 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -782,7 +782,8 @@ void pci_disable_link_state(struct pci_dev *pdev, int state) } EXPORT_SYMBOL(pci_disable_link_state); -static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) +static int pcie_aspm_set_policy(const char *val, + const struct kernel_param *kp) { int i; struct pcie_link_state *link; @@ -809,7 +810,7 @@ static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) return 0; } -static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp) +static int pcie_aspm_get_policy(char *buffer, const struct kernel_param *kp) { int i, cnt = 0; for (i = 0; i < ARRAY_SIZE(policy_str); i++) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b65ce7519411..60ee94e57242 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9526,7 +9526,7 @@ static struct ibm_init_struct ibms_init[] __initdata = { }, }; -static int __init set_ibm_param(const char *val, struct kernel_param *kp) +static int __init set_ibm_param(const char *val, const struct kernel_param *kp) { unsigned int i; struct ibm_struct *ibm; diff --git a/drivers/scsi/fcoe/fcoe_transport.c b/drivers/scsi/fcoe/fcoe_transport.c index 375c536cbc68..c5eb0c468f0b 100644 --- a/drivers/scsi/fcoe/fcoe_transport.c +++ b/drivers/scsi/fcoe/fcoe_transport.c @@ -32,13 +32,13 @@ MODULE_AUTHOR("Open-FCoE.org"); MODULE_DESCRIPTION("FIP discovery protocol and FCoE transport for FCoE HBAs"); MODULE_LICENSE("GPL v2"); -static int fcoe_transport_create(const char *, struct kernel_param *); -static int fcoe_transport_destroy(const char *, struct kernel_param *); +static int fcoe_transport_create(const char *, const struct kernel_param *); +static int fcoe_transport_destroy(const char *, const struct kernel_param *); static int fcoe_transport_show(char *buffer, const struct kernel_param *kp); static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device); static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device); -static int fcoe_transport_enable(const char *, struct kernel_param *); -static int fcoe_transport_disable(const char *, struct kernel_param *); +static int fcoe_transport_enable(const char *, const struct kernel_param *); +static int fcoe_transport_disable(const char *, const struct kernel_param *); static int libfcoe_device_notification(struct notifier_block *notifier, ulong event, void *ptr); @@ -865,7 +865,8 @@ EXPORT_SYMBOL(fcoe_ctlr_destroy_store); * * Returns: 0 for success */ -static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_create(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; @@ -930,7 +931,8 @@ static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) * * Returns: 0 for success */ -static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_destroy(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; @@ -974,7 +976,8 @@ static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) * * Returns: 0 for success */ -static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_disable(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; @@ -1008,7 +1011,8 @@ static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) * * Returns: 0 for success */ -static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) +static int fcoe_transport_enable(const char *buffer, + const struct kernel_param *kp) { int rc = -ENODEV; struct net_device *netdev = NULL; diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index a1a5ceb42ce6..8e83e346e0b3 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -105,7 +105,7 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc); * */ static int -_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) +_scsih_set_fwfault_debug(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); struct MPT3SAS_ADAPTER *ioc; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 468acab04d3d..7568e061a168 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -281,7 +281,7 @@ struct _scsi_io_transfer { * Note: The logging levels are defined in mpt3sas_debug.h. */ static int -_scsih_set_debug_level(const char *val, struct kernel_param *kp) +_scsih_set_debug_level(const char *val, const struct kernel_param *kp) { int ret = param_set_int(val, kp); struct MPT3SAS_ADAPTER *ioc; diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index a260cde743e2..5532c440bf61 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -245,7 +245,8 @@ static void kgdboc_put_char(u8 chr) kgdb_tty_line, chr); } -static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp) +static int param_set_kgdboc_var(const char *kmessage, + const struct kernel_param *kp) { int len = strlen(kmessage); diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 6fe6a88ecb4a..c03236b50ad2 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -30,7 +30,7 @@ static struct kmem_cache *fuse_inode_cachep; struct list_head fuse_conn_list; DEFINE_MUTEX(fuse_mutex); -static int set_global_limit(const char *val, struct kernel_param *kp); +static int set_global_limit(const char *val, const struct kernel_param *kp); unsigned max_user_bgreq; module_param_call(max_user_bgreq, set_global_limit, param_get_uint, @@ -827,7 +827,7 @@ static void sanitize_global_limit(unsigned *limit) *limit = (1 << 16) - 1; } -static int set_global_limit(const char *val, struct kernel_param *kp) +static int set_global_limit(const char *val, const struct kernel_param *kp) { int rv; diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 9d373247222c..a770da32c409 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -596,7 +596,7 @@ static struct ctl_table nlm_sysctl_root[] = { */ #define param_set_min_max(name, type, which_strtol, min, max) \ -static int param_set_##name(const char *val, struct kernel_param *kp) \ +static int param_set_##name(const char *val, const struct kernel_param *kp) \ { \ char *endp; \ __typeof__(type) num = which_strtol(val, &endp, 0); \ diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index 1079fae5aa12..47e08e4f6223 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -88,13 +88,13 @@ struct workqueue_struct *user_dlm_worker; */ #define DLMFS_CAPABILITIES "bast stackglue" static int param_set_dlmfs_capabilities(const char *val, - struct kernel_param *kp) + const struct kernel_param *kp) { printk(KERN_ERR "%s: readonly parameter\n", kp->name); return -EINVAL; } static int param_get_dlmfs_capabilities(char *buffer, - struct kernel_param *kp) + const struct kernel_param *kp) { return strlcpy(buffer, DLMFS_CAPABILITIES, strlen(DLMFS_CAPABILITIES) + 1); diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 9ae819e27940..29f0d4765bfc 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -306,7 +306,7 @@ static inline bool nf_ct_should_gc(const struct nf_conn *ct) struct kernel_param; -int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); +int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp); int nf_conntrack_hash_resize(unsigned int hashsize); extern struct hlist_nulls_head *nf_conntrack_hash; diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 8da893c397da..492ce5fe137e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1794,7 +1794,7 @@ int nf_conntrack_hash_resize(unsigned int hashsize) return 0; } -int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) +int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp) { unsigned int hashsize; int rc; diff --git a/net/netfilter/nf_nat_ftp.c b/net/netfilter/nf_nat_ftp.c index e84a578dbe35..d76afafdc699 100644 --- a/net/netfilter/nf_nat_ftp.c +++ b/net/netfilter/nf_nat_ftp.c @@ -134,7 +134,7 @@ static int __init nf_nat_ftp_init(void) } /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ -static int warn_set(const char *val, struct kernel_param *kp) +static int warn_set(const char *val, const struct kernel_param *kp) { printk(KERN_INFO KBUILD_MODNAME ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); diff --git a/net/netfilter/nf_nat_irc.c b/net/netfilter/nf_nat_irc.c index 1fb2258c3535..8039bcd60758 100644 --- a/net/netfilter/nf_nat_irc.c +++ b/net/netfilter/nf_nat_irc.c @@ -107,7 +107,7 @@ static int __init nf_nat_irc_init(void) } /* Prior to 2.6.11, we had a ports param. No longer, but don't break users. */ -static int warn_set(const char *val, struct kernel_param *kp) +static int warn_set(const char *val, const struct kernel_param *kp) { printk(KERN_INFO KBUILD_MODNAME ": kernel >= 2.6.10 only uses 'ports' for conntrack modules\n"); diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 272c34551979..b43818c720b8 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c @@ -50,7 +50,7 @@ EXPORT_SYMBOL_GPL(svc_pool_map); static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ static int -param_set_pool_mode(const char *val, struct kernel_param *kp) +param_set_pool_mode(const char *val, const struct kernel_param *kp) { int *ip = (int *)kp->arg; struct svc_pool_map *m = &svc_pool_map; @@ -80,7 +80,7 @@ param_set_pool_mode(const char *val, struct kernel_param *kp) } static int -param_get_pool_mode(char *buf, struct kernel_param *kp) +param_get_pool_mode(char *buf, const struct kernel_param *kp) { int *ip = (int *)kp->arg; diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 7d3a98b2d55a..bc1b99b7d90b 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -656,11 +656,11 @@ static const struct kernel_param_ops param_ops_aalockpolicy = { .get = param_get_aalockpolicy }; -static int param_set_audit(const char *val, struct kernel_param *kp); -static int param_get_audit(char *buffer, struct kernel_param *kp); +static int param_set_audit(const char *val, const struct kernel_param *kp); +static int param_get_audit(char *buffer, const struct kernel_param *kp); -static int param_set_mode(const char *val, struct kernel_param *kp); -static int param_get_mode(char *buffer, struct kernel_param *kp); +static int param_set_mode(const char *val, const struct kernel_param *kp); +static int param_get_mode(char *buffer, const struct kernel_param *kp); /* Flag values, also controllable via /sys/module/apparmor/parameters * We define special types as we want to do additional mediation. @@ -774,7 +774,7 @@ static int param_get_aauint(char *buffer, const struct kernel_param *kp) return param_get_uint(buffer, kp); } -static int param_get_audit(char *buffer, struct kernel_param *kp) +static int param_get_audit(char *buffer, const struct kernel_param *kp) { if (!policy_view_capable()) return -EPERM; @@ -785,7 +785,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); } -static int param_set_audit(const char *val, struct kernel_param *kp) +static int param_set_audit(const char *val, const struct kernel_param *kp) { int i; if (!policy_admin_capable()) @@ -807,7 +807,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) return -EINVAL; } -static int param_get_mode(char *buffer, struct kernel_param *kp) +static int param_get_mode(char *buffer, const struct kernel_param *kp) { if (!policy_admin_capable()) return -EPERM; @@ -818,7 +818,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); } -static int param_set_mode(const char *val, struct kernel_param *kp) +static int param_set_mode(const char *val, const struct kernel_param *kp) { int i; if (!policy_admin_capable()) -- GitLab From cb214f0c4c105ceab5456556425ecec74e2ac3c1 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 17 Oct 2017 19:04:43 -0700 Subject: [PATCH 0097/1834] UPSTREAM: module: Do not paper over type mismatches in module_param_call() The module_param_call() macro was explicitly casting the .set and .get function prototypes away. This can lead to hard-to-find type mismatches. Now that all the function prototypes have been fixed tree-wide, we can drop these casts, and use named initializers too. Signed-off-by: Kees Cook Signed-off-by: Jessica Yu Bug: 67506682 Change-Id: I439c8b4b9f0108ac357267bbc396a63baec2b242 (cherry picked from commit ece1996a21eeb344b49200e627c6660111009c10) Signed-off-by: Sami Tolvanen --- include/linux/moduleparam.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 952c7342a741..060db5c327be 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -225,9 +225,9 @@ struct kparam_array VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } } /* Obsolete - use module_param_cb() */ -#define module_param_call(name, set, get, arg, perm) \ +#define module_param_call(name, _set, _get, arg, perm) \ static const struct kernel_param_ops __param_ops_##name = \ - { .flags = 0, (void *)set, (void *)get }; \ + { .flags = 0, .set = _set, .get = _get }; \ __module_param_call(MODULE_PARAM_PREFIX, \ name, &__param_ops_##name, arg, perm, -1, 0) -- GitLab From 7ce8d9fa08ae34258a3ca4f62b814d13263633eb Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 18 Aug 2017 10:00:51 -0700 Subject: [PATCH 0098/1834] v4l2-ioctl: fix function types for IOCTL_INFO_STD Bug: 67506682 Change-Id: I0bfdb4a198e8fb8719ac6aa884fd39e163dbf762 Signed-off-by: Sami Tolvanen --- drivers/media/v4l2-core/v4l2-ioctl.c | 71 ++++++++++++++++++---------- 1 file changed, 46 insertions(+), 25 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 4510e8a37244..610caa10481b 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2455,11 +2455,8 @@ struct v4l2_ioctl_info { unsigned int ioctl; u32 flags; const char * const name; - union { - u32 offset; - int (*func)(const struct v4l2_ioctl_ops *ops, - struct file *file, void *fh, void *p); - } u; + int (*func)(const struct v4l2_ioctl_ops *ops, struct file *file, + void *fh, void *p); void (*debug)(const void *arg, bool write_only); }; @@ -2467,25 +2464,21 @@ struct v4l2_ioctl_info { #define INFO_FL_PRIO (1 << 0) /* This control can be valid if the filehandle passes a control handler. */ #define INFO_FL_CTRL (1 << 1) -/* This is a standard ioctl, no need for special code */ -#define INFO_FL_STD (1 << 2) /* This is ioctl has its own function */ -#define INFO_FL_FUNC (1 << 3) +#define INFO_FL_FUNC (1 << 2) /* Queuing ioctl */ -#define INFO_FL_QUEUE (1 << 4) +#define INFO_FL_QUEUE (1 << 3) /* Zero struct from after the field to the end */ #define INFO_FL_CLEAR(v4l2_struct, field) \ ((offsetof(struct v4l2_struct, field) + \ sizeof(((struct v4l2_struct *)0)->field)) << 16) #define INFO_FL_CLEAR_MASK (_IOC_SIZEMASK << 16) -#define IOCTL_INFO_STD(_ioctl, _vidioc, _debug, _flags) \ - [_IOC_NR(_ioctl)] = { \ - .ioctl = _ioctl, \ - .flags = _flags | INFO_FL_STD, \ - .name = #_ioctl, \ - .u.offset = offsetof(struct v4l2_ioctl_ops, _vidioc), \ - .debug = _debug, \ +#define DEFINE_IOCTL_STD_FNC(_vidioc) \ + static int __v4l_ ## _vidioc ## _fnc( \ + const struct v4l2_ioctl_ops *ops, \ + struct file *file, void *fh, void *p) { \ + return ops->_vidioc(file, fh, p); \ } #define IOCTL_INFO_FNC(_ioctl, _func, _debug, _flags) \ @@ -2493,10 +2486,44 @@ struct v4l2_ioctl_info { .ioctl = _ioctl, \ .flags = _flags | INFO_FL_FUNC, \ .name = #_ioctl, \ - .u.func = _func, \ + .func = _func, \ .debug = _debug, \ } +#define IOCTL_INFO_STD(_ioctl, _vidioc, _debug, _flags) \ + IOCTL_INFO_FNC(_ioctl, __v4l_ ## _vidioc ## _fnc, _debug, _flags) + +DEFINE_IOCTL_STD_FNC(vidioc_g_fbuf) +DEFINE_IOCTL_STD_FNC(vidioc_s_fbuf) +DEFINE_IOCTL_STD_FNC(vidioc_expbuf) +DEFINE_IOCTL_STD_FNC(vidioc_g_std) +DEFINE_IOCTL_STD_FNC(vidioc_g_audio) +DEFINE_IOCTL_STD_FNC(vidioc_s_audio) +DEFINE_IOCTL_STD_FNC(vidioc_g_input) +DEFINE_IOCTL_STD_FNC(vidioc_g_edid) +DEFINE_IOCTL_STD_FNC(vidioc_s_edid) +DEFINE_IOCTL_STD_FNC(vidioc_g_output) +DEFINE_IOCTL_STD_FNC(vidioc_g_audout) +DEFINE_IOCTL_STD_FNC(vidioc_s_audout) +DEFINE_IOCTL_STD_FNC(vidioc_g_selection) +DEFINE_IOCTL_STD_FNC(vidioc_s_selection) +DEFINE_IOCTL_STD_FNC(vidioc_g_jpegcomp) +DEFINE_IOCTL_STD_FNC(vidioc_s_jpegcomp) +DEFINE_IOCTL_STD_FNC(vidioc_enumaudio) +DEFINE_IOCTL_STD_FNC(vidioc_enumaudout) +DEFINE_IOCTL_STD_FNC(vidioc_enum_framesizes) +DEFINE_IOCTL_STD_FNC(vidioc_enum_frameintervals) +DEFINE_IOCTL_STD_FNC(vidioc_g_enc_index) +DEFINE_IOCTL_STD_FNC(vidioc_encoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_try_encoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_decoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_try_decoder_cmd) +DEFINE_IOCTL_STD_FNC(vidioc_s_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_g_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_enum_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_query_dv_timings) +DEFINE_IOCTL_STD_FNC(vidioc_dv_timings_cap) + static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_FNC(VIDIOC_QUERYCAP, v4l_querycap, v4l_print_querycap, 0), IOCTL_INFO_FNC(VIDIOC_ENUM_FMT, v4l_enum_fmt, v4l_print_fmtdesc, INFO_FL_CLEAR(v4l2_fmtdesc, type)), @@ -2681,14 +2708,8 @@ static long __video_do_ioctl(struct file *file, } write_only = _IOC_DIR(cmd) == _IOC_WRITE; - if (info->flags & INFO_FL_STD) { - typedef int (*vidioc_op)(struct file *file, void *fh, void *p); - const void *p = vfd->ioctl_ops; - const vidioc_op *vidioc = p + info->u.offset; - - ret = (*vidioc)(file, fh, arg); - } else if (info->flags & INFO_FL_FUNC) { - ret = info->u.func(ops, file, fh, arg); + if (info->flags & INFO_FL_FUNC) { + ret = info->func(ops, file, fh, arg); } else if (!ops->vidioc_default) { ret = -ENOTTY; } else { -- GitLab From a30a6d312622e5e5cdd36b1e95a658fca22fa1af Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 18 Aug 2017 14:31:23 -0700 Subject: [PATCH 0099/1834] arm64: disable CFI for cpu_replace_ttbr1 Disable CFI to allow an indirect call to a physical address. Bug: 67506682 Change-Id: I0ec38f34245a4ad52f508f6989093526d3bf442f Signed-off-by: Sami Tolvanen --- arch/arm64/include/asm/mmu_context.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index 6ad61e7d9725..c0ae91c39292 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -128,7 +128,7 @@ static inline void cpu_install_idmap(void) * Atomically replaces the active TTBR1_EL1 PGD with a new VA-compatible PGD, * avoiding the possibility of conflicting TLB entries being allocated. */ -static inline void cpu_replace_ttbr1(pgd_t *pgd) +static inline void __nocfi cpu_replace_ttbr1(pgd_t *pgd) { typedef void (ttbr_replace_func)(phys_addr_t); extern ttbr_replace_func idmap_cpu_replace_ttbr1; -- GitLab From d6da00dcd74220fa085095d1cb00633f655530dd Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 10 Aug 2017 09:39:53 -0700 Subject: [PATCH 0100/1834] arch/arm64/crypto: fix CFI in SHA CE Add C wrappers to allow indirect calls to sha[12]_ce_transform without tripping CFI. Bug: 67506682 Change-Id: If872f30095994206bc768eee13670be552b2a247 Signed-off-by: Sami Tolvanen --- arch/arm64/crypto/sha1-ce-glue.c | 8 ++++++++ arch/arm64/crypto/sha2-ce-glue.c | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/arch/arm64/crypto/sha1-ce-glue.c b/arch/arm64/crypto/sha1-ce-glue.c index ea319c055f5d..f08ecf431dcf 100644 --- a/arch/arm64/crypto/sha1-ce-glue.c +++ b/arch/arm64/crypto/sha1-ce-glue.c @@ -28,6 +28,14 @@ struct sha1_ce_state { asmlinkage void sha1_ce_transform(struct sha1_ce_state *sst, u8 const *src, int blocks); +#ifdef CONFIG_CFI_CLANG +static inline void __cfi_sha1_ce_transform(struct sha1_state *sst, + u8 const *src, int blocks) +{ + sha1_ce_transform((struct sha1_ce_state *)sst, src, blocks); +} +#define sha1_ce_transform __cfi_sha1_ce_transform +#endif const u32 sha1_ce_offsetof_count = offsetof(struct sha1_ce_state, sst.count); const u32 sha1_ce_offsetof_finalize = offsetof(struct sha1_ce_state, finalize); diff --git a/arch/arm64/crypto/sha2-ce-glue.c b/arch/arm64/crypto/sha2-ce-glue.c index 0ed9486f75dd..c2432210f5e2 100644 --- a/arch/arm64/crypto/sha2-ce-glue.c +++ b/arch/arm64/crypto/sha2-ce-glue.c @@ -28,6 +28,14 @@ struct sha256_ce_state { asmlinkage void sha2_ce_transform(struct sha256_ce_state *sst, u8 const *src, int blocks); +#ifdef CONFIG_CFI_CLANG +static inline void __cfi_sha2_ce_transform(struct sha256_state *sst, + u8 const *src, int blocks) +{ + sha2_ce_transform((struct sha256_ce_state *)sst, src, blocks); +} +#define sha2_ce_transform __cfi_sha2_ce_transform +#endif const u32 sha256_ce_offsetof_count = offsetof(struct sha256_ce_state, sst.count); -- GitLab From 7c20af08dfcb59f7b89757a19ee79966e4cbb6bb Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 10 Aug 2017 09:42:10 -0700 Subject: [PATCH 0101/1834] arch/arm64/crypto: fix CFI in AES CE Move inline assembly to a separate object file that's compiled with LTO disabled due to incompatibility with clang's internal assembler. Add wrappers to allow indirect calls without tripping CFI. Bug: 67506682 Change-Id: I582b22dcdbb0bb59149f3b4cfce132b1e2d145cd Signed-off-by: Sami Tolvanen --- arch/arm64/crypto/Makefile | 4 +- arch/arm64/crypto/aes-ce-cipher-core.c | 219 +++++++++++++++++++++++++ arch/arm64/crypto/aes-ce-cipher.c | 205 +---------------------- 3 files changed, 230 insertions(+), 198 deletions(-) create mode 100644 arch/arm64/crypto/aes-ce-cipher-core.c diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index 965a2df4f65c..a4a8b17a5e2a 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -17,8 +17,8 @@ sha2-ce-y := sha2-ce-glue.o sha2-ce-core.o obj-$(CONFIG_CRYPTO_GHASH_ARM64_CE) += ghash-ce.o ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o -obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o -CFLAGS_aes-ce-cipher.o += -march=armv8-a+crypto $(DISABLE_LTO) +obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o aes-ce-cipher-core.o +CFLAGS_aes-ce-cipher-core.o += -march=armv8-a+crypto -Wa,-march=armv8-a+crypto $(DISABLE_LTO) obj-$(CONFIG_CRYPTO_AES_ARM64_CE_CCM) += aes-ce-ccm.o aes-ce-ccm-y := aes-ce-ccm-glue.o aes-ce-ccm-core.o diff --git a/arch/arm64/crypto/aes-ce-cipher-core.c b/arch/arm64/crypto/aes-ce-cipher-core.c new file mode 100644 index 000000000000..9f4191774b35 --- /dev/null +++ b/arch/arm64/crypto/aes-ce-cipher-core.c @@ -0,0 +1,219 @@ +/* + * aes-ce-cipher-core.c - core AES cipher using ARMv8 Crypto Extensions + * + * Copyright (C) 2013 - 2014 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include "aes-ce-setkey.h" + +struct aes_block { + u8 b[AES_BLOCK_SIZE]; +}; + +static int num_rounds(struct crypto_aes_ctx *ctx) +{ + /* + * # of rounds specified by AES: + * 128 bit key 10 rounds + * 192 bit key 12 rounds + * 256 bit key 14 rounds + * => n byte key => 6 + (n/4) rounds + */ + return 6 + ctx->key_length / 4; +} + +void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) +{ + struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); + struct aes_block *out = (struct aes_block *)dst; + struct aes_block const *in = (struct aes_block *)src; + void *dummy0; + int dummy1; + + kernel_neon_begin_partial(4); + + __asm__(" ld1 {v0.16b}, %[in] ;" + " ld1 {v1.16b}, [%[key]], #16 ;" + " cmp %w[rounds], #10 ;" + " bmi 0f ;" + " bne 3f ;" + " mov v3.16b, v1.16b ;" + " b 2f ;" + "0: mov v2.16b, v1.16b ;" + " ld1 {v3.16b}, [%[key]], #16 ;" + "1: aese v0.16b, v2.16b ;" + " aesmc v0.16b, v0.16b ;" + "2: ld1 {v1.16b}, [%[key]], #16 ;" + " aese v0.16b, v3.16b ;" + " aesmc v0.16b, v0.16b ;" + "3: ld1 {v2.16b}, [%[key]], #16 ;" + " subs %w[rounds], %w[rounds], #3 ;" + " aese v0.16b, v1.16b ;" + " aesmc v0.16b, v0.16b ;" + " ld1 {v3.16b}, [%[key]], #16 ;" + " bpl 1b ;" + " aese v0.16b, v2.16b ;" + " eor v0.16b, v0.16b, v3.16b ;" + " st1 {v0.16b}, %[out] ;" + + : [out] "=Q"(*out), + [key] "=r"(dummy0), + [rounds] "=r"(dummy1) + : [in] "Q"(*in), + "1"(ctx->key_enc), + "2"(num_rounds(ctx) - 2) + : "cc"); + + kernel_neon_end(); +} + +void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) +{ + struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); + struct aes_block *out = (struct aes_block *)dst; + struct aes_block const *in = (struct aes_block *)src; + void *dummy0; + int dummy1; + + kernel_neon_begin_partial(4); + + __asm__(" ld1 {v0.16b}, %[in] ;" + " ld1 {v1.16b}, [%[key]], #16 ;" + " cmp %w[rounds], #10 ;" + " bmi 0f ;" + " bne 3f ;" + " mov v3.16b, v1.16b ;" + " b 2f ;" + "0: mov v2.16b, v1.16b ;" + " ld1 {v3.16b}, [%[key]], #16 ;" + "1: aesd v0.16b, v2.16b ;" + " aesimc v0.16b, v0.16b ;" + "2: ld1 {v1.16b}, [%[key]], #16 ;" + " aesd v0.16b, v3.16b ;" + " aesimc v0.16b, v0.16b ;" + "3: ld1 {v2.16b}, [%[key]], #16 ;" + " subs %w[rounds], %w[rounds], #3 ;" + " aesd v0.16b, v1.16b ;" + " aesimc v0.16b, v0.16b ;" + " ld1 {v3.16b}, [%[key]], #16 ;" + " bpl 1b ;" + " aesd v0.16b, v2.16b ;" + " eor v0.16b, v0.16b, v3.16b ;" + " st1 {v0.16b}, %[out] ;" + + : [out] "=Q"(*out), + [key] "=r"(dummy0), + [rounds] "=r"(dummy1) + : [in] "Q"(*in), + "1"(ctx->key_dec), + "2"(num_rounds(ctx) - 2) + : "cc"); + + kernel_neon_end(); +} + +/* + * aes_sub() - use the aese instruction to perform the AES sbox substitution + * on each byte in 'input' + */ +static u32 aes_sub(u32 input) +{ + u32 ret; + + __asm__("dup v1.4s, %w[in] ;" + "movi v0.16b, #0 ;" + "aese v0.16b, v1.16b ;" + "umov %w[out], v0.4s[0] ;" + + : [out] "=r"(ret) + : [in] "r"(input) + : "v0","v1"); + + return ret; +} + +int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, + unsigned int key_len) +{ + /* + * The AES key schedule round constants + */ + static u8 const rcon[] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, + }; + + u32 kwords = key_len / sizeof(u32); + struct aes_block *key_enc, *key_dec; + int i, j; + + if (key_len != AES_KEYSIZE_128 && + key_len != AES_KEYSIZE_192 && + key_len != AES_KEYSIZE_256) + return -EINVAL; + + memcpy(ctx->key_enc, in_key, key_len); + ctx->key_length = key_len; + + kernel_neon_begin_partial(2); + for (i = 0; i < sizeof(rcon); i++) { + u32 *rki = ctx->key_enc + (i * kwords); + u32 *rko = rki + kwords; + +#ifndef CONFIG_CPU_BIG_ENDIAN + rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0]; +#else + rko[0] = rol32(aes_sub(rki[kwords - 1]), 8) ^ (rcon[i] << 24) ^ + rki[0]; +#endif + rko[1] = rko[0] ^ rki[1]; + rko[2] = rko[1] ^ rki[2]; + rko[3] = rko[2] ^ rki[3]; + + if (key_len == AES_KEYSIZE_192) { + if (i >= 7) + break; + rko[4] = rko[3] ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + } else if (key_len == AES_KEYSIZE_256) { + if (i >= 6) + break; + rko[4] = aes_sub(rko[3]) ^ rki[4]; + rko[5] = rko[4] ^ rki[5]; + rko[6] = rko[5] ^ rki[6]; + rko[7] = rko[6] ^ rki[7]; + } + } + + /* + * Generate the decryption keys for the Equivalent Inverse Cipher. + * This involves reversing the order of the round keys, and applying + * the Inverse Mix Columns transformation on all but the first and + * the last one. + */ + key_enc = (struct aes_block *)ctx->key_enc; + key_dec = (struct aes_block *)ctx->key_dec; + j = num_rounds(ctx); + + key_dec[0] = key_enc[j]; + for (i = 1, j--; j > 0; i++, j--) + __asm__("ld1 {v0.16b}, %[in] ;" + "aesimc v1.16b, v0.16b ;" + "st1 {v1.16b}, %[out] ;" + + : [out] "=Q"(key_dec[i]) + : [in] "Q"(key_enc[j]) + : "v0","v1"); + key_dec[i] = key_enc[0]; + + kernel_neon_end(); + return 0; +} +EXPORT_SYMBOL(ce_aes_expandkey); diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher.c index 50d9fe11d0c8..442949e7e849 100644 --- a/arch/arm64/crypto/aes-ce-cipher.c +++ b/arch/arm64/crypto/aes-ce-cipher.c @@ -8,7 +8,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include @@ -20,209 +19,23 @@ MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions"); MODULE_AUTHOR("Ard Biesheuvel "); MODULE_LICENSE("GPL v2"); -struct aes_block { - u8 b[AES_BLOCK_SIZE]; -}; +extern void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]); +extern void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]); -static int num_rounds(struct crypto_aes_ctx *ctx) +#ifdef CONFIG_CFI_CLANG +static inline void __cfi_aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) { - /* - * # of rounds specified by AES: - * 128 bit key 10 rounds - * 192 bit key 12 rounds - * 256 bit key 14 rounds - * => n byte key => 6 + (n/4) rounds - */ - return 6 + ctx->key_length / 4; -} - -static void aes_cipher_encrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) -{ - struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct aes_block *out = (struct aes_block *)dst; - struct aes_block const *in = (struct aes_block *)src; - void *dummy0; - int dummy1; - - kernel_neon_begin_partial(4); - - __asm__(" ld1 {v0.16b}, %[in] ;" - " ld1 {v1.16b}, [%[key]], #16 ;" - " cmp %w[rounds], #10 ;" - " bmi 0f ;" - " bne 3f ;" - " mov v3.16b, v1.16b ;" - " b 2f ;" - "0: mov v2.16b, v1.16b ;" - " ld1 {v3.16b}, [%[key]], #16 ;" - "1: aese v0.16b, v2.16b ;" - " aesmc v0.16b, v0.16b ;" - "2: ld1 {v1.16b}, [%[key]], #16 ;" - " aese v0.16b, v3.16b ;" - " aesmc v0.16b, v0.16b ;" - "3: ld1 {v2.16b}, [%[key]], #16 ;" - " subs %w[rounds], %w[rounds], #3 ;" - " aese v0.16b, v1.16b ;" - " aesmc v0.16b, v0.16b ;" - " ld1 {v3.16b}, [%[key]], #16 ;" - " bpl 1b ;" - " aese v0.16b, v2.16b ;" - " eor v0.16b, v0.16b, v3.16b ;" - " st1 {v0.16b}, %[out] ;" - - : [out] "=Q"(*out), - [key] "=r"(dummy0), - [rounds] "=r"(dummy1) - : [in] "Q"(*in), - "1"(ctx->key_enc), - "2"(num_rounds(ctx) - 2) - : "cc"); - - kernel_neon_end(); + aes_cipher_encrypt(tfm, dst, src); } -static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) +static inline void __cfi_aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[]) { - struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - struct aes_block *out = (struct aes_block *)dst; - struct aes_block const *in = (struct aes_block *)src; - void *dummy0; - int dummy1; - - kernel_neon_begin_partial(4); - - __asm__(" ld1 {v0.16b}, %[in] ;" - " ld1 {v1.16b}, [%[key]], #16 ;" - " cmp %w[rounds], #10 ;" - " bmi 0f ;" - " bne 3f ;" - " mov v3.16b, v1.16b ;" - " b 2f ;" - "0: mov v2.16b, v1.16b ;" - " ld1 {v3.16b}, [%[key]], #16 ;" - "1: aesd v0.16b, v2.16b ;" - " aesimc v0.16b, v0.16b ;" - "2: ld1 {v1.16b}, [%[key]], #16 ;" - " aesd v0.16b, v3.16b ;" - " aesimc v0.16b, v0.16b ;" - "3: ld1 {v2.16b}, [%[key]], #16 ;" - " subs %w[rounds], %w[rounds], #3 ;" - " aesd v0.16b, v1.16b ;" - " aesimc v0.16b, v0.16b ;" - " ld1 {v3.16b}, [%[key]], #16 ;" - " bpl 1b ;" - " aesd v0.16b, v2.16b ;" - " eor v0.16b, v0.16b, v3.16b ;" - " st1 {v0.16b}, %[out] ;" - - : [out] "=Q"(*out), - [key] "=r"(dummy0), - [rounds] "=r"(dummy1) - : [in] "Q"(*in), - "1"(ctx->key_dec), - "2"(num_rounds(ctx) - 2) - : "cc"); - - kernel_neon_end(); + aes_cipher_decrypt(tfm, dst, src); } -/* - * aes_sub() - use the aese instruction to perform the AES sbox substitution - * on each byte in 'input' - */ -static u32 aes_sub(u32 input) -{ - u32 ret; - - __asm__("dup v1.4s, %w[in] ;" - "movi v0.16b, #0 ;" - "aese v0.16b, v1.16b ;" - "umov %w[out], v0.4s[0] ;" - - : [out] "=r"(ret) - : [in] "r"(input) - : "v0","v1"); - - return ret; -} - -int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key, - unsigned int key_len) -{ - /* - * The AES key schedule round constants - */ - static u8 const rcon[] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, - }; - - u32 kwords = key_len / sizeof(u32); - struct aes_block *key_enc, *key_dec; - int i, j; - - if (key_len != AES_KEYSIZE_128 && - key_len != AES_KEYSIZE_192 && - key_len != AES_KEYSIZE_256) - return -EINVAL; - - memcpy(ctx->key_enc, in_key, key_len); - ctx->key_length = key_len; - - kernel_neon_begin_partial(2); - for (i = 0; i < sizeof(rcon); i++) { - u32 *rki = ctx->key_enc + (i * kwords); - u32 *rko = rki + kwords; - -#ifndef CONFIG_CPU_BIG_ENDIAN - rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0]; -#else - rko[0] = rol32(aes_sub(rki[kwords - 1]), 8) ^ (rcon[i] << 24) ^ - rki[0]; +#define aes_cipher_encrypt __cfi_aes_cipher_encrypt +#define aes_cipher_decrypt __cfi_aes_cipher_decrypt #endif - rko[1] = rko[0] ^ rki[1]; - rko[2] = rko[1] ^ rki[2]; - rko[3] = rko[2] ^ rki[3]; - - if (key_len == AES_KEYSIZE_192) { - if (i >= 7) - break; - rko[4] = rko[3] ^ rki[4]; - rko[5] = rko[4] ^ rki[5]; - } else if (key_len == AES_KEYSIZE_256) { - if (i >= 6) - break; - rko[4] = aes_sub(rko[3]) ^ rki[4]; - rko[5] = rko[4] ^ rki[5]; - rko[6] = rko[5] ^ rki[6]; - rko[7] = rko[6] ^ rki[7]; - } - } - - /* - * Generate the decryption keys for the Equivalent Inverse Cipher. - * This involves reversing the order of the round keys, and applying - * the Inverse Mix Columns transformation on all but the first and - * the last one. - */ - key_enc = (struct aes_block *)ctx->key_enc; - key_dec = (struct aes_block *)ctx->key_dec; - j = num_rounds(ctx); - - key_dec[0] = key_enc[j]; - for (i = 1, j--; j > 0; i++, j--) - __asm__("ld1 {v0.16b}, %[in] ;" - "aesimc v1.16b, v0.16b ;" - "st1 {v1.16b}, %[out] ;" - - : [out] "=Q"(key_dec[i]) - : [in] "Q"(key_enc[j]) - : "v0","v1"); - key_dec[i] = key_enc[0]; - - kernel_neon_end(); - return 0; -} -EXPORT_SYMBOL(ce_aes_expandkey); int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) -- GitLab From 04676269a0b4e1fd20a7ceaaef878fa3131517ea Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 20 Feb 2017 16:51:23 +0100 Subject: [PATCH 0102/1834] BACKPORT: vfs: pass type instead of fn to do_{loop,iter}_readv_writev() Signed-off-by: Miklos Szeredi Bug: 67506682 Change-Id: I919a90715ed71d6caf02b1333dbfec5e7e3ad52b (cherry picked from commit 0f78d06ac1e9b470cbd8f913ee1688c8b2c8feb3) Signed-off-by: Sami Tolvanen --- fs/read_write.c | 54 +++++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index ba280596ec78..2f1027d708d2 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -23,9 +23,6 @@ #include #include -typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); -typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *); - const struct file_operations generic_ro_fops = { .llseek = generic_file_llseek, .read_iter = generic_file_read_iter, @@ -675,7 +672,7 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) EXPORT_SYMBOL(iov_shorten); static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter, - loff_t *ppos, iter_fn_t fn, int flags) + loff_t *ppos, int type, int flags) { struct kiocb kiocb; ssize_t ret; @@ -692,7 +689,10 @@ static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter, kiocb.ki_flags |= (IOCB_DSYNC | IOCB_SYNC); kiocb.ki_pos = *ppos; - ret = fn(&kiocb, iter); + if (type == READ) + ret = filp->f_op->read_iter(&kiocb, iter); + else + ret = filp->f_op->write_iter(&kiocb, iter); BUG_ON(ret == -EIOCBQUEUED); *ppos = kiocb.ki_pos; return ret; @@ -700,7 +700,7 @@ static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter, /* Do it by hand, with file-ops */ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, - loff_t *ppos, io_fn_t fn, int flags) + loff_t *ppos, int type, int flags) { ssize_t ret = 0; @@ -711,7 +711,13 @@ static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, struct iovec iovec = iov_iter_iovec(iter); ssize_t nr; - nr = fn(filp, iovec.iov_base, iovec.iov_len, ppos); + if (type == READ) { + nr = filp->f_op->read(filp, iovec.iov_base, + iovec.iov_len, ppos); + } else { + nr = filp->f_op->write(filp, iovec.iov_base, + iovec.iov_len, ppos); + } if (nr < 0) { if (!ret) @@ -844,8 +850,6 @@ static ssize_t do_readv_writev(int type, struct file *file, struct iovec *iov = iovstack; struct iov_iter iter; ssize_t ret; - io_fn_t fn; - iter_fn_t iter_fn; ret = import_iovec(type, uvector, nr_segs, ARRAY_SIZE(iovstack), &iov, &iter); @@ -859,19 +863,14 @@ static ssize_t do_readv_writev(int type, struct file *file, if (ret < 0) goto out; - if (type == READ) { - fn = file->f_op->read; - iter_fn = file->f_op->read_iter; - } else { - fn = (io_fn_t)file->f_op->write; - iter_fn = file->f_op->write_iter; + if (type != READ) file_start_write(file); - } - if (iter_fn) - ret = do_iter_readv_writev(file, &iter, pos, iter_fn, flags); + if ((type == READ && file->f_op->read_iter) || + (type == WRITE && file->f_op->write_iter)) + ret = do_iter_readv_writev(file, &iter, pos, type, flags); else - ret = do_loop_readv_writev(file, &iter, pos, fn, flags); + ret = do_loop_readv_writev(file, &iter, pos, type, flags); if (type != READ) file_end_write(file); @@ -1069,8 +1068,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, struct iovec *iov = iovstack; struct iov_iter iter; ssize_t ret; - io_fn_t fn; - iter_fn_t iter_fn; ret = compat_import_iovec(type, uvector, nr_segs, UIO_FASTIOV, &iov, &iter); @@ -1084,19 +1081,14 @@ static ssize_t compat_do_readv_writev(int type, struct file *file, if (ret < 0) goto out; - if (type == READ) { - fn = file->f_op->read; - iter_fn = file->f_op->read_iter; - } else { - fn = (io_fn_t)file->f_op->write; - iter_fn = file->f_op->write_iter; + if (type != READ) file_start_write(file); - } - if (iter_fn) - ret = do_iter_readv_writev(file, &iter, pos, iter_fn, flags); + if ((type == READ && file->f_op->read_iter) || + (type == WRITE && file->f_op->write_iter)) + ret = do_iter_readv_writev(file, &iter, pos, type, flags); else - ret = do_loop_readv_writev(file, &iter, pos, fn, flags); + ret = do_loop_readv_writev(file, &iter, pos, type, flags); if (type != READ) file_end_write(file); -- GitLab From 97d5fd27f7af6b36d775f56a1c78a026686aa407 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 16 Aug 2017 10:45:46 -0700 Subject: [PATCH 0103/1834] mm: fix drain_local_pages function type Bug: 67506682 Change-Id: I6ca80f521c880589efe45dc467d494051daae015 Signed-off-by: Sami Tolvanen --- include/linux/gfp.h | 2 +- mm/page_alloc.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index f8041f9de31e..e47dbc1933a2 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -516,7 +516,7 @@ extern void __free_page_frag(void *addr); void page_alloc_init(void); void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp); void drain_all_pages(struct zone *zone); -void drain_local_pages(struct zone *zone); +void drain_local_pages(void *zone); void page_alloc_init_late(void); diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 94018ea5f935..4449ca6e0afc 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2341,8 +2341,9 @@ static void drain_pages(unsigned int cpu) * The CPU has to be pinned. When zone parameter is non-NULL, spill just * the single zone's pages. */ -void drain_local_pages(struct zone *zone) +void drain_local_pages(void *z) { + struct zone *zone = (struct zone *)z; int cpu = smp_processor_id(); if (zone) @@ -2402,8 +2403,7 @@ void drain_all_pages(struct zone *zone) else cpumask_clear_cpu(cpu, &cpus_with_pcps); } - on_each_cpu_mask(&cpus_with_pcps, (smp_call_func_t) drain_local_pages, - zone, 1); + on_each_cpu_mask(&cpus_with_pcps, drain_local_pages, zone, 1); } #ifdef CONFIG_HIBERNATION -- GitLab From 4fd840d1743308b2ef470534523009dd99b3ce2b Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 16 Aug 2017 14:38:13 -0700 Subject: [PATCH 0104/1834] mm: fix filler function type mismatch Bug: 67506682 Change-Id: I6f615164ccd86b407540ada9bbcb39d910395db9 Signed-off-by: Sami Tolvanen --- fs/fuse/file.c | 4 ++-- include/linux/pagemap.h | 4 ++-- mm/filemap.c | 6 +++--- mm/readahead.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 996aa23c409e..c4353da0591d 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -839,9 +839,9 @@ struct fuse_fill_data { unsigned nr_pages; }; -static int fuse_readpages_fill(void *_data, struct page *page) +static int fuse_readpages_fill(struct file *_data, struct page *page) { - struct fuse_fill_data *data = _data; + struct fuse_fill_data *data = (struct fuse_fill_data *)_data; struct fuse_req *req = data->req; struct inode *inode = data->inode; struct fuse_conn *fc = get_fuse_conn(inode); diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 7dbe9148b2f8..0741609bf4ab 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -225,7 +225,7 @@ static inline gfp_t readahead_gfp_mask(struct address_space *x) __GFP_COLD | __GFP_NORETRY | __GFP_NOWARN; } -typedef int filler_t(void *, struct page *); +typedef int filler_t(struct file *, struct page *); pgoff_t page_cache_next_hole(struct address_space *mapping, pgoff_t index, unsigned long max_scan); @@ -369,7 +369,7 @@ extern int read_cache_pages(struct address_space *mapping, static inline struct page *read_mapping_page(struct address_space *mapping, pgoff_t index, void *data) { - filler_t *filler = (filler_t *)mapping->a_ops->readpage; + filler_t *filler = mapping->a_ops->readpage; return read_cache_page(mapping, index, filler, data); } diff --git a/mm/filemap.c b/mm/filemap.c index edfb90e3830c..14977f73eff7 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2388,7 +2388,7 @@ static struct page *wait_on_page_read(struct page *page) static struct page *do_read_cache_page(struct address_space *mapping, pgoff_t index, - int (*filler)(void *, struct page *), + int (*filler)(struct file *, struct page *), void *data, gfp_t gfp) { @@ -2495,7 +2495,7 @@ static struct page *do_read_cache_page(struct address_space *mapping, */ struct page *read_cache_page(struct address_space *mapping, pgoff_t index, - int (*filler)(void *, struct page *), + int (*filler)(struct file *, struct page *), void *data) { return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping)); @@ -2517,7 +2517,7 @@ struct page *read_cache_page_gfp(struct address_space *mapping, pgoff_t index, gfp_t gfp) { - filler_t *filler = (filler_t *)mapping->a_ops->readpage; + filler_t *filler = mapping->a_ops->readpage; return do_read_cache_page(mapping, index, filler, NULL, gfp); } diff --git a/mm/readahead.c b/mm/readahead.c index c8a955b1297e..3c1d2a4612c8 100644 --- a/mm/readahead.c +++ b/mm/readahead.c @@ -81,7 +81,7 @@ static void read_cache_pages_invalidate_pages(struct address_space *mapping, * Hides the details of the LRU cache etc from the filesystems. */ int read_cache_pages(struct address_space *mapping, struct list_head *pages, - int (*filler)(void *, struct page *), void *data) + int (*filler)(struct file *, struct page *), void *data) { struct page *page; int ret = 0; -- GitLab From b73b94a7df67bc8f113f5e9619f9dfa4061d4f8a Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Tue, 13 Feb 2018 13:01:39 -0800 Subject: [PATCH 0105/1834] fs: nfs: fix filler function type Bug: 67506682 Change-Id: I04d4b1b9ab0720a4f342d6617dd132de8654b94c Signed-off-by: Sami Tolvanen --- fs/nfs/read.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/read.c b/fs/nfs/read.c index defc9233e985..67b80004d3f1 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -346,7 +346,7 @@ struct nfs_readdesc { }; static int -readpage_async_filler(void *data, struct page *page) +readpage_async_filler(struct file *data, struct page *page) { struct nfs_readdesc *desc = (struct nfs_readdesc *)data; struct nfs_page *new; -- GitLab From d93a963d439b4ffc3d4b0e934fd5560470f12504 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Thu, 11 May 2017 15:05:07 -0700 Subject: [PATCH 0106/1834] dummycon: fix function types Bug: 67506682 Change-Id: I8476680bbeb88ddaec2219bc6accc963a2688145 Signed-off-by: Sami Tolvanen --- drivers/video/console/dummycon.c | 69 ++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 13 deletions(-) diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index b90ef96e43d6..25d5bc3dcdb5 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -41,12 +41,55 @@ static void dummycon_init(struct vc_data *vc, int init) vc_resize(vc, DUMMY_COLUMNS, DUMMY_ROWS); } -static int dummycon_dummy(void) +static void dummycon_deinit(struct vc_data *vc) +{ +} + +static void dummycon_clear(struct vc_data *vc, int a, int b, int c, int d) +{ +} + +static void dummycon_putc(struct vc_data *vc, int a, int b, int c) +{ +} + +static void dummycon_putcs(struct vc_data *vc, const unsigned short *s, int a, int b, int c) +{ +} + +static void dummycon_cursor(struct vc_data *vc, int a) +{ +} + +static int dummycon_scroll(struct vc_data *vc, int a, int b, int c, int d) +{ + return 0; +} + +static int dummycon_switch(struct vc_data *vc) { return 0; } -#define DUMMY (void *)dummycon_dummy +static int dummycon_blank(struct vc_data *vc, int a, int b) +{ + return 0; +} + +static int dummycon_font_set(struct vc_data *vc, struct console_font *f, unsigned u) +{ + return 0; +} + +static int dummycon_font_default(struct vc_data *vc, struct console_font *f, char *c) +{ + return 0; +} + +static int dummycon_font_copy(struct vc_data *vc, int a) +{ + return 0; +} /* * The console `switch' structure for the dummy console @@ -58,16 +101,16 @@ const struct consw dummy_con = { .owner = THIS_MODULE, .con_startup = dummycon_startup, .con_init = dummycon_init, - .con_deinit = DUMMY, - .con_clear = DUMMY, - .con_putc = DUMMY, - .con_putcs = DUMMY, - .con_cursor = DUMMY, - .con_scroll = DUMMY, - .con_switch = DUMMY, - .con_blank = DUMMY, - .con_font_set = DUMMY, - .con_font_default = DUMMY, - .con_font_copy = DUMMY, + .con_deinit = dummycon_deinit, + .con_clear = dummycon_clear, + .con_putc = dummycon_putc, + .con_putcs = dummycon_putcs, + .con_cursor = dummycon_cursor, + .con_scroll = dummycon_scroll, + .con_switch = dummycon_switch, + .con_blank = dummycon_blank, + .con_font_set = dummycon_font_set, + .con_font_default = dummycon_font_default, + .con_font_copy = dummycon_font_copy, }; EXPORT_SYMBOL_GPL(dummy_con); -- GitLab From 0f98f46d9920a1aad7d10916eac4b83dbccabf42 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 16 Aug 2017 12:03:36 -0700 Subject: [PATCH 0107/1834] drivers/perf: arm_pmu: fix function type mismatch Bug: 67506682 Change-Id: I06dc3fbef96c06cbfc8619cd2d0f7aa0fa7d99d9 Signed-off-by: Sami Tolvanen --- drivers/perf/arm_pmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index b37b57294566..92d6a97f1f44 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -1012,7 +1012,7 @@ int arm_pmu_device_probe(struct platform_device *pdev, const struct pmu_probe_info *probe_table) { const struct of_device_id *of_id; - const int (*init_fn)(struct arm_pmu *); + int (*init_fn)(struct arm_pmu *); struct device_node *node = pdev->dev.of_node; struct arm_pmu *pmu; int ret = -ENODEV; -- GitLab From 4c4262aa50dc156434d8d70e8f5a5373848d81d2 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 19 Jan 2018 08:51:17 -0800 Subject: [PATCH 0108/1834] media-device: fix ioctl function types Bug: 67506682 Change-Id: I233081071d90aeea56a2201ff618e8b530c52610 Signed-off-by: Sami Tolvanen --- drivers/media/media-device.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 4462d8c69d57..cc8de5668227 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -58,9 +58,10 @@ static int media_device_close(struct file *filp) return 0; } -static int media_device_get_info(struct media_device *dev, - struct media_device_info *info) +static long media_device_get_info(struct media_device *dev, void *arg) { + struct media_device_info *info = (struct media_device_info *)arg; + memset(info, 0, sizeof(*info)); if (dev->driver_name[0]) @@ -97,9 +98,9 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id) return NULL; } -static long media_device_enum_entities(struct media_device *mdev, - struct media_entity_desc *entd) +static long media_device_enum_entities(struct media_device *mdev, void *arg) { + struct media_entity_desc *entd = (struct media_entity_desc *)arg; struct media_entity *ent; ent = find_entity(mdev, entd->id); @@ -150,9 +151,9 @@ static void media_device_kpad_to_upad(const struct media_pad *kpad, upad->flags = kpad->flags; } -static long media_device_enum_links(struct media_device *mdev, - struct media_links_enum *links) +static long media_device_enum_links(struct media_device *mdev, void *arg) { + struct media_links_enum *links = (struct media_links_enum *)arg; struct media_entity *entity; entity = find_entity(mdev, links->entity); @@ -198,9 +199,9 @@ static long media_device_enum_links(struct media_device *mdev, return 0; } -static long media_device_setup_link(struct media_device *mdev, - struct media_link_desc *linkd) +static long media_device_setup_link(struct media_device *mdev, void *arg) { + struct media_link_desc *linkd = (struct media_link_desc *)arg; struct media_link *link = NULL; struct media_entity *source; struct media_entity *sink; @@ -226,9 +227,9 @@ static long media_device_setup_link(struct media_device *mdev, return __media_entity_setup_link(link, linkd->flags); } -static long media_device_get_topology(struct media_device *mdev, - struct media_v2_topology *topo) +static long media_device_get_topology(struct media_device *mdev, void *arg) { + struct media_v2_topology *topo = (struct media_v2_topology *)arg; struct media_entity *entity; struct media_interface *intf; struct media_pad *pad; -- GitLab From f67385227a42cb91916047bfddfb281c62a395e4 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 1 Mar 2018 16:35:31 -0800 Subject: [PATCH 0109/1834] ANDROID: keychord: Check for write data size keychord driver causes a kernel warning when writing more than (1 << (MAX_ORDER - 1)) * PAGE_SIZE bytes to /dev/keychord. In reality writes to this file should be much smaller, so limiting data size to PAGE_SIZE seems to be appropriate. This change checks write data size and if it's more than PAGE_SIZE causes write to fail. Bug: 73962978 Change-Id: I8a064a396d4259ffca924fa35d80e9700c4f8d79 Signed-off-by: Suren Baghdasaryan --- drivers/input/misc/keychord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/keychord.c b/drivers/input/misc/keychord.c index fdcc14653b64..82fefdff366a 100644 --- a/drivers/input/misc/keychord.c +++ b/drivers/input/misc/keychord.c @@ -276,7 +276,7 @@ static ssize_t keychord_write(struct file *file, const char __user *buffer, size_t resid = count; size_t key_bytes; - if (count < sizeof(struct input_keychord)) + if (count < sizeof(struct input_keychord) || count > PAGE_SIZE) return -EINVAL; keychords = kzalloc(count, GFP_KERNEL); if (!keychords) -- GitLab From 53f4adf6788d71d322f810efb271a5658f44d193 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 09:02:16 -0800 Subject: [PATCH 0110/1834] ANDROID: fs: afs: fix filler function type Bug: 67506682 Change-Id: I76d208c8606ee5af144891d14bd309912d4d788d Signed-off-by: Sami Tolvanen --- fs/afs/file.c | 14 ++++++++++---- fs/afs/internal.h | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/afs/file.c b/fs/afs/file.c index 72372970725b..37f97bab78ab 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -123,11 +123,10 @@ static void afs_file_readpage_read_complete(struct page *page, /* * read page from file, directory or symlink, given a key to use */ -int afs_page_filler(void *data, struct page *page) +static int __afs_page_filler(struct key *key, struct page *page) { struct inode *inode = page->mapping->host; struct afs_vnode *vnode = AFS_FS_I(inode); - struct key *key = data; size_t len; off_t offset; int ret; @@ -209,6 +208,13 @@ int afs_page_filler(void *data, struct page *page) return ret; } +int afs_page_filler(struct file *data, struct page *page) +{ + struct key *key = (struct key *)data; + + return __afs_page_filler(key, page); +} + /* * read page from file, directory or symlink, given a file to nominate the key * to be used @@ -221,14 +227,14 @@ static int afs_readpage(struct file *file, struct page *page) if (file) { key = file->private_data; ASSERT(key != NULL); - ret = afs_page_filler(key, page); + ret = __afs_page_filler(key, page); } else { struct inode *inode = page->mapping->host; key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell); if (IS_ERR(key)) { ret = PTR_ERR(key); } else { - ret = afs_page_filler(key, page); + ret = __afs_page_filler(key, page); key_put(key); } } diff --git a/fs/afs/internal.h b/fs/afs/internal.h index dd98dcda6a3f..b4165cce985d 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -497,7 +497,7 @@ extern const struct file_operations afs_file_operations; extern int afs_open(struct inode *, struct file *); extern int afs_release(struct inode *, struct file *); -extern int afs_page_filler(void *, struct page *); +extern int afs_page_filler(struct file *, struct page *); /* * flock.c -- GitLab From 39cdeb137340baed325e695c2ded3ec8d0abda2b Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 09:04:53 -0800 Subject: [PATCH 0111/1834] ANDROID: fs: exofs: fix filler function type Bug: 67506682 Change-Id: I42f297bfe07a1b7916790415f35ad4f2574ceec7 Signed-off-by: Sami Tolvanen --- fs/exofs/inode.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index d8072bc074a4..7f5b73528663 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -377,9 +377,8 @@ static int read_exec(struct page_collect *pcol) * and will start a new collection. Eventually caller must submit the last * segment if present. */ -static int readpage_strip(void *data, struct page *page) +static int __readpage_strip(struct page_collect *pcol, struct page *page) { - struct page_collect *pcol = data; struct inode *inode = pcol->inode; struct exofs_i_info *oi = exofs_i(inode); loff_t i_size = i_size_read(inode); @@ -470,6 +469,13 @@ static int readpage_strip(void *data, struct page *page) return ret; } +static int readpage_strip(struct file *data, struct page *page) +{ + struct page_collect *pcol = (struct page_collect *)data; + + return __readpage_strip(pcol, page); +} + static int exofs_readpages(struct file *file, struct address_space *mapping, struct list_head *pages, unsigned nr_pages) { @@ -499,7 +505,7 @@ static int _readpage(struct page *page, bool read_4_write) _pcol_init(&pcol, 1, page->mapping->host); pcol.read_4_write = read_4_write; - ret = readpage_strip(&pcol, page); + ret = __readpage_strip(&pcol, page); if (ret) { EXOFS_ERR("_readpage => %d\n", ret); return ret; -- GitLab From 920c7fd62c25da3acd3e16f3808d324a08e4a453 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 09:06:24 -0800 Subject: [PATCH 0112/1834] ANDROID: fs: gfs2: fix filler function type Bug: 67506682 Change-Id: I50a3f85965de6e041d0f40e7bf9c2ced15ccfd49 Signed-off-by: Sami Tolvanen --- fs/gfs2/aops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 5a6f52ea2722..c6c507c75eb1 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c @@ -511,7 +511,7 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) * */ -static int __gfs2_readpage(void *file, struct page *page) +static int __gfs2_readpage(struct file *file, struct page *page) { struct gfs2_inode *ip = GFS2_I(page->mapping->host); struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); -- GitLab From 2be0847f6f9f4effe639f2caeb88bb6f16838332 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 09:10:22 -0800 Subject: [PATCH 0113/1834] ANDROID: fs: logfs: fix filler function type Bug: 67506682 Change-Id: If2659b91e250cbd9f1a4a028ff43caf71b8306dd Signed-off-by: Sami Tolvanen --- fs/logfs/dev_bdev.c | 4 ++-- fs/logfs/dev_mtd.c | 4 ++-- fs/logfs/dir.c | 4 ++-- fs/logfs/logfs.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index a8329cc47dec..fdf844f6d9f7 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -34,9 +34,9 @@ static int sync_request(struct page *page, struct block_device *bdev, int op) return submit_bio_wait(&bio); } -static int bdev_readpage(void *_sb, struct page *page) +static int bdev_readpage(struct file *_sb, struct page *page) { - struct super_block *sb = _sb; + struct super_block *sb = (struct super_block *)_sb; struct block_device *bdev = logfs_super(sb)->s_bdev; int err; diff --git a/fs/logfs/dev_mtd.c b/fs/logfs/dev_mtd.c index b76a62b1978f..9ec8e8f9d1c9 100644 --- a/fs/logfs/dev_mtd.c +++ b/fs/logfs/dev_mtd.c @@ -122,9 +122,9 @@ static void logfs_mtd_sync(struct super_block *sb) mtd_sync(mtd); } -static int logfs_mtd_readpage(void *_sb, struct page *page) +static int logfs_mtd_readpage(struct file *_sb, struct page *page) { - struct super_block *sb = _sb; + struct super_block *sb = (struct super_block *)_sb; int err; err = logfs_mtd_read(sb, page->index << PAGE_SHIFT, PAGE_SIZE, diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index c87ea52de3d9..8ddacc124804 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -174,7 +174,7 @@ static struct page *logfs_get_dd_page(struct inode *dir, struct dentry *dentry) if (!logfs_exist_block(dir, index)) continue; page = read_cache_page(dir->i_mapping, index, - (filler_t *)logfs_readpage, NULL); + logfs_readpage, NULL); if (IS_ERR(page)) return page; dd = kmap_atomic(page); @@ -306,7 +306,7 @@ static int logfs_readdir(struct file *file, struct dir_context *ctx) continue; } page = read_cache_page(dir->i_mapping, pos, - (filler_t *)logfs_readpage, NULL); + logfs_readpage, NULL); if (IS_ERR(page)) return PTR_ERR(page); dd = kmap(page); diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index 27d040e35faa..1a7c0b02efbc 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h @@ -151,7 +151,7 @@ struct logfs_device_ops { struct page *(*find_first_sb)(struct super_block *sb, u64 *ofs); struct page *(*find_last_sb)(struct super_block *sb, u64 *ofs); int (*write_sb)(struct super_block *sb, struct page *page); - int (*readpage)(void *_sb, struct page *page); + int (*readpage)(struct file *_sb, struct page *page); void (*writeseg)(struct super_block *sb, u64 ofs, size_t len); int (*erase)(struct super_block *sb, loff_t ofs, size_t len, int ensure_write); -- GitLab From a36719dd8899c6148f4cb62aec32e4a453582cc0 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 13:05:33 -0800 Subject: [PATCH 0114/1834] ANDROID: staging: lustre: fix filler function type Bug: 67506682 Change-Id: I3a65178adb47119a3dcbc6ca4bcf350085a73ffc Signed-off-by: Sami Tolvanen --- drivers/staging/lustre/lustre/mdc/mdc_request.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index f56ea643f9bf..6a146f45bedb 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -1219,9 +1219,9 @@ struct readpage_param { * in PAGE_SIZE (if PAGE_SIZE greater than LU_PAGE_SIZE), and the * lu_dirpage for this integrated page will be adjusted. **/ -static int mdc_read_page_remote(void *data, struct page *page0) +static int mdc_read_page_remote(struct file *data, struct page *page0) { - struct readpage_param *rp = data; + struct readpage_param *rp = (struct readpage_param *)data; struct page **page_pool; struct page *page; struct lu_dirpage *dp; -- GitLab From da3bc26599c403692536546d4e003bb8897e721a Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 13:20:40 -0800 Subject: [PATCH 0115/1834] ANDROID: arm64: crypto: fix AES CE when built as a module Rename aes-cipher.c to aes-cipher-glue.c according to existing naming convention, and make sure aes-cipher-core.c is linked into the module. Bug: 67506682 Change-Id: I63671937207cc192d8f9cbef3232841d9e30022b Signed-off-by: Sami Tolvanen --- arch/arm64/crypto/Makefile | 3 ++- arch/arm64/crypto/{aes-ce-cipher.c => aes-ce-cipher-glue.c} | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename arch/arm64/crypto/{aes-ce-cipher.c => aes-ce-cipher-glue.c} (100%) diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index a4a8b17a5e2a..550e02a5aa32 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -17,7 +17,8 @@ sha2-ce-y := sha2-ce-glue.o sha2-ce-core.o obj-$(CONFIG_CRYPTO_GHASH_ARM64_CE) += ghash-ce.o ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o -obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o aes-ce-cipher-core.o +obj-$(CONFIG_CRYPTO_AES_ARM64_CE) += aes-ce-cipher.o +aes-ce-cipher-y := aes-ce-cipher-glue.o aes-ce-cipher-core.o CFLAGS_aes-ce-cipher-core.o += -march=armv8-a+crypto -Wa,-march=armv8-a+crypto $(DISABLE_LTO) obj-$(CONFIG_CRYPTO_AES_ARM64_CE_CCM) += aes-ce-ccm.o diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher-glue.c similarity index 100% rename from arch/arm64/crypto/aes-ce-cipher.c rename to arch/arm64/crypto/aes-ce-cipher-glue.c -- GitLab From e0b05e693a9d748afb7d4ff0fd5e13ada4d2c771 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Fri, 2 Mar 2018 10:46:06 -0800 Subject: [PATCH 0116/1834] ANDROID: kbuild: change LTO into a choice This fixes allmodconfig and prepares for gcc's LTO support. Bug: 67506682 Change-Id: Ied90f9f25293321287b25fd6f214f7f1913f44cb Signed-off-by: Sami Tolvanen --- arch/Kconfig | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/Kconfig b/arch/Kconfig index c0efc0b840a0..0847b5d47da7 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -490,7 +490,7 @@ config LD_DEAD_CODE_DATA_ELIMINATION is used to distinguish them from label names / C identifiers. config LTO - bool + def_bool n config ARCH_SUPPORTS_LTO_CLANG bool @@ -500,6 +500,15 @@ config ARCH_SUPPORTS_LTO_CLANG - compiling inline assembly with clang's integrated assembler, - and linking with either lld or GNU gold w/ LLVMgold. +choice + prompt "Link-Time Optimization (LTO) (EXPERIMENTAL)" + default LTO_NONE + help + This option turns on Link-Time Optimization (LTO). + +config LTO_NONE + bool "None" + config LTO_CLANG bool "Use clang Link Time Optimization (LTO) (EXPERIMENTAL)" depends on ARCH_SUPPORTS_LTO_CLANG @@ -518,6 +527,8 @@ config LTO_CLANG 5.0 (make CC=clang) and GNU gold from binutils >= 2.27, and have the LLVMgold plug-in in LD_LIBRARY_PATH. +endchoice + config CFI bool -- GitLab From 5a9f69b2c11bee48b1884165e4e1473f7672dc28 Mon Sep 17 00:00:00 2001 From: Anna-Maria Gleixner Date: Thu, 21 Dec 2017 11:41:35 +0100 Subject: [PATCH 0117/1834] hrtimer: Ensure POSIX compliance (relative CLOCK_REALTIME hrtimers) commit 48d0c9becc7f3c66874c100c126459a9da0fdced upstream. The POSIX specification defines that relative CLOCK_REALTIME timers are not affected by clock modifications. Those timers have to use CLOCK_MONOTONIC to ensure POSIX compliance. The introduction of the additional HRTIMER_MODE_PINNED mode broke this requirement for pinned timers. There is no user space visible impact because user space timers are not using pinned mode, but for consistency reasons this needs to be fixed. Check whether the mode has the HRTIMER_MODE_REL bit set instead of comparing with HRTIMER_MODE_ABS. Signed-off-by: Anna-Maria Gleixner Cc: Christoph Hellwig Cc: John Stultz Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: keescook@chromium.org Fixes: 597d0275736d ("timers: Framework for identifying pinned timers") Link: http://lkml.kernel.org/r/20171221104205.7269-7-anna-maria@linutronix.de Signed-off-by: Ingo Molnar Cc: Mike Galbraith Signed-off-by: Greg Kroah-Hartman --- kernel/time/hrtimer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c index 54fd2fed36e9..c93729661be0 100644 --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1134,7 +1134,12 @@ static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, cpu_base = raw_cpu_ptr(&hrtimer_bases); - if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS) + /* + * POSIX magic: Relative CLOCK_REALTIME timers are not affected by + * clock modifications, so they needs to become CLOCK_MONOTONIC to + * ensure POSIX compliance. + */ + if (clock_id == CLOCK_REALTIME && mode & HRTIMER_MODE_REL) clock_id = CLOCK_MONOTONIC; base = hrtimer_clockid_to_base(clock_id); -- GitLab From b4e0649eeb65c556d01de986a589da2ffd5c2029 Mon Sep 17 00:00:00 2001 From: Ben Gardner Date: Wed, 14 Feb 2018 09:29:52 -0600 Subject: [PATCH 0118/1834] i2c: designware: must wait for enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit fba4adbbf670577e605f9ad306629db6031cd48b upstream. One I2C bus on my Atom E3845 board has been broken since 4.9. It has two devices, both declared by ACPI and with built-in drivers. There are two back-to-back transactions originating from the kernel, one targeting each device. The first transaction works, the second one locks up the I2C controller. The controller never recovers. These kernel logs show up whenever an I2C transaction is attempted after this failure. i2c-designware-pci 0000:00:18.3: timeout in disabling adapter i2c-designware-pci 0000:00:18.3: timeout waiting for bus ready Waiting for the I2C controller status to indicate that it is enabled before programming it fixes the issue. I have tested this patch on 4.14 and 4.15. Fixes: commit 2702ea7dbec5 ("i2c: designware: wait for disable/enable only if necessary") Cc: linux-stable #4.13+ Signed-off-by: Ben Gardner Acked-by: Jarkko Nikula Reviewed-by: José Roberto de Souza Signed-off-by: Wolfram Sang Signed-off-by: Ben Gardner [Jarkko: Backported to v4.9..v4.12 before i2c-designware-core.c was renamed to i2c-designware-master.c] Signed-off-by: Jarkko Nikula Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-designware-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 809f4d4e93a0..340e037b3224 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -507,7 +507,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) i2c_dw_disable_int(dev); /* Enable the adapter */ - __i2c_dw_enable(dev, true); + __i2c_dw_enable_and_wait(dev, true); /* Clear and enable interrupts */ dw_readl(dev, DW_IC_CLR_INTR); -- GitLab From 4a97b2d09d332c43612f489c99b97d691002b6d4 Mon Sep 17 00:00:00 2001 From: Yunlei He Date: Fri, 19 May 2017 15:06:12 +0800 Subject: [PATCH 0119/1834] f2fs: fix a bug caused by NULL extent tree commit dad48e73127ba10279ea33e6dbc8d3905c4d31c0 upstream. Thread A: Thread B: -f2fs_remount -sbi->mount_opt.opt = 0; <--- -f2fs_iget -do_read_inode -f2fs_init_extent_tree -F2FS_I(inode)->extent_tree is NULL -default_options && parse_options -remount return <--- -f2fs_map_blocks -f2fs_lookup_extent_tree -f2fs_bug_on(sbi, !et); The same problem with f2fs_new_inode. Signed-off-by: Yunlei He Signed-off-by: Jaegeuk Kim Signed-off-by: Nikolay Borisov Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/extent_cache.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 7b32ce979fe1..63e519658d73 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -177,7 +177,7 @@ static void __drop_largest_extent(struct inode *inode, } /* return true, if inode page is changed */ -bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) +static bool __f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et; @@ -215,6 +215,16 @@ bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) return false; } +bool f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) +{ + bool ret = __f2fs_init_extent_tree(inode, i_ext); + + if (!F2FS_I(inode)->extent_tree) + set_inode_flag(inode, FI_NO_EXTENT); + + return ret; +} + static bool f2fs_lookup_extent_tree(struct inode *inode, pgoff_t pgofs, struct extent_info *ei) { -- GitLab From 051337a8993a5481046209ec167eb6e821b6d922 Mon Sep 17 00:00:00 2001 From: Andreas Platschek Date: Thu, 14 Dec 2017 12:50:51 +0100 Subject: [PATCH 0120/1834] dmaengine: fsl-edma: disable clks on all error paths [ Upstream commit 2610acf46b9ed528ec2cacd717bc9d354e452b73 ] Previously enabled clks are only disabled if clk_prepare_enable() fails. However, there are other error paths were the previously enabled clocks are not disabled. To fix the problem, fsl_disable_clocks() now takes the number of clocks that shall be disabled + unprepared. For existing calls were all clocks were already successfully prepared + enabled, DMAMUX_NR is passed to disable + unprepare all clocks. In error paths were only some clocks were successfully prepared + enabled the loop counter is passed, in order to disable + unprepare all successfully prepared + enabled clocks. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Andreas Platschek Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/dma/fsl-edma.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 6775f2c74e25..c7568869284e 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -863,11 +863,11 @@ static void fsl_edma_irq_exit( } } -static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma) +static void fsl_disable_clocks(struct fsl_edma_engine *fsl_edma, int nr_clocks) { int i; - for (i = 0; i < DMAMUX_NR; i++) + for (i = 0; i < nr_clocks; i++) clk_disable_unprepare(fsl_edma->muxclk[i]); } @@ -904,25 +904,25 @@ static int fsl_edma_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i); fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(fsl_edma->muxbase[i])) + if (IS_ERR(fsl_edma->muxbase[i])) { + /* on error: disable all previously enabled clks */ + fsl_disable_clocks(fsl_edma, i); return PTR_ERR(fsl_edma->muxbase[i]); + } sprintf(clkname, "dmamux%d", i); fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname); if (IS_ERR(fsl_edma->muxclk[i])) { dev_err(&pdev->dev, "Missing DMAMUX block clock.\n"); + /* on error: disable all previously enabled clks */ + fsl_disable_clocks(fsl_edma, i); return PTR_ERR(fsl_edma->muxclk[i]); } ret = clk_prepare_enable(fsl_edma->muxclk[i]); - if (ret) { - /* disable only clks which were enabled on error */ - for (; i >= 0; i--) - clk_disable_unprepare(fsl_edma->muxclk[i]); - - dev_err(&pdev->dev, "DMAMUX clk block failed.\n"); - return ret; - } + if (ret) + /* on error: disable all previously enabled clks */ + fsl_disable_clocks(fsl_edma, i); } @@ -976,7 +976,7 @@ static int fsl_edma_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Can't register Freescale eDMA engine. (%d)\n", ret); - fsl_disable_clocks(fsl_edma); + fsl_disable_clocks(fsl_edma, DMAMUX_NR); return ret; } @@ -985,7 +985,7 @@ static int fsl_edma_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can't register Freescale eDMA of_dma. (%d)\n", ret); dma_async_device_unregister(&fsl_edma->dma_dev); - fsl_disable_clocks(fsl_edma); + fsl_disable_clocks(fsl_edma, DMAMUX_NR); return ret; } @@ -1015,7 +1015,7 @@ static int fsl_edma_remove(struct platform_device *pdev) fsl_edma_cleanup_vchan(&fsl_edma->dma_dev); of_dma_controller_free(np); dma_async_device_unregister(&fsl_edma->dma_dev); - fsl_disable_clocks(fsl_edma); + fsl_disable_clocks(fsl_edma, DMAMUX_NR); return 0; } -- GitLab From d4ea6118d3e36ea87b02607aea8f173b4c69f808 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Thu, 14 Dec 2017 11:20:14 -0700 Subject: [PATCH 0121/1834] nvme: check hw sectors before setting chunk sectors [ Upstream commit 249159c5f15812140fa216f9997d799ac0023a1f ] Some devices with IDs matching the "stripe" quirk don't actually have this quirk, and don't have an MDTS value. When MDTS is not set, the driver sets the max sectors to UINT_MAX, which is not a power of 2, hitting a BUG_ON from blk_queue_chunk_sectors. This patch skips setting chunk sectors for such devices. Signed-off-by: Keith Busch Reviewed-by: Martin K. Petersen Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 719ee5fb2626..ad9d82eb2aed 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1204,7 +1204,8 @@ static void nvme_set_queue_limits(struct nvme_ctrl *ctrl, blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors); blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX)); } - if (ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) + if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) && + is_power_of_2(ctrl->max_hw_sectors)) blk_queue_chunk_sectors(q, ctrl->max_hw_sectors); blk_queue_virt_boundary(q, ctrl->page_size - 1); if (ctrl->vwc & NVME_CTRL_VWC_PRESENT) -- GitLab From 83c5a93514c7404c94d1de94a4c8aa5d5684fc95 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Thu, 14 Dec 2017 16:56:14 +0100 Subject: [PATCH 0122/1834] net: usb: qmi_wwan: add Telit ME910 PID 0x1101 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c647c0d62c82eb3ddf78a0d8b3d58819d9f552aa ] This patch adds support for Telit ME910 PID 0x1101. Signed-off-by: Daniele Palmas Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index e1e5e8438457..930deb332404 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -914,6 +914,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1040, 2)}, /* Telit LE922A */ {QMI_FIXED_INTF(0x1bc7, 0x1100, 3)}, /* Telit ME910 */ + {QMI_FIXED_INTF(0x1bc7, 0x1101, 3)}, /* Telit ME910 dual modem */ {QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)}, /* XS Stick W100-2 from 4G Systems */ -- GitLab From dd1e39f4b3a81706571f03807381a21949655898 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 5 Dec 2017 11:51:40 +0100 Subject: [PATCH 0123/1834] mtd: nand: gpmi: Fix failure when a erased page has a bitflip at BBM [ Upstream commit fdf2e821052958a114618a95ab18a300d0b080cb ] When erased subpages are read then the BCH decoder returns STATUS_ERASED if they are all empty, or STATUS_UNCORRECTABLE if there are bitflips. When there are bitflips, we have to set these bits again to show the upper layers a completely erased page. When a bitflip happens in the exact byte where the bad block marker is, then this byte is swapped with another byte in block_mark_swapping(). The correction code then detects a bitflip in another subpage and no longer corrects the bitflip where it really happens. Correct this behaviour by calling block_mark_swapping() after the bitflips have been corrected. In our case UBIFS failed with this bug because it expects erased pages to be really empty: UBIFS error (pid 187): ubifs_scan: corrupt empty space at LEB 36:118735 UBIFS error (pid 187): ubifs_scanned_corruption: corruption at LEB 36:118735 UBIFS error (pid 187): ubifs_scanned_corruption: first 8192 bytes from LEB 36:118735 UBIFS error (pid 187): ubifs_scan: LEB 36 scanning failed UBIFS error (pid 187): do_commit: commit failed, error -117 Signed-off-by: Sascha Hauer Reviewed-by: Richard Weinberger Acked-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 6c062b8251d2..427039b77668 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1059,9 +1059,6 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, return ret; } - /* handle the block mark swapping */ - block_mark_swapping(this, payload_virt, auxiliary_virt); - /* Loop over status bytes, accumulating ECC status. */ status = auxiliary_virt + nfc_geo->auxiliary_status_offset; @@ -1150,6 +1147,9 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, max_bitflips = max_t(unsigned int, max_bitflips, *status); } + /* handle the block mark swapping */ + block_mark_swapping(this, buf, auxiliary_virt); + if (oob_required) { /* * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() -- GitLab From e88872ef990c8c0692963d916c9585b9b65254c6 Mon Sep 17 00:00:00 2001 From: Albert Hsieh Date: Mon, 20 Nov 2017 11:26:26 +0800 Subject: [PATCH 0124/1834] mtd: nand: brcmnand: Zero bitflip is not an error [ Upstream commit e44b9a9c135727f3410e029910275f40681dc8bc ] A negative return value of brcmstb_nand_verify_erased_page() indicates a real bitflip error of an erased page, and other return values (>= 0) show the corrected bitflip number. Zero return value means no bitflip, but the current driver code treats it as an error, and eventually leads to falsely reported ECC error. Fixes: 02b88eea9f9c ("mtd: brcmnand: Add check for erased page bitflip") Signed-off-by: Albert Hsieh Acked-by: Boris Brezillon Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/brcmnand/brcmnand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index 1a4a790054e4..ef9a6b22c9fa 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -1763,7 +1763,7 @@ static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip, err = brcmstb_nand_verify_erased_page(mtd, chip, buf, addr); /* erased page bitflips corrected */ - if (err > 0) + if (err >= 0) return err; } -- GitLab From 3cf31f5b38ed1d78d39e9fb1d460c4684690ec1e Mon Sep 17 00:00:00 2001 From: Brendan McGrath Date: Wed, 13 Dec 2017 22:14:57 +1100 Subject: [PATCH 0125/1834] ipv6: icmp6: Allow icmp messages to be looped back [ Upstream commit 588753f1eb18978512b1c9b85fddb457d46f9033 ] One example of when an ICMPv6 packet is required to be looped back is when a host acts as both a Multicast Listener and a Multicast Router. A Multicast Router will listen on address ff02::16 for MLDv2 messages. Currently, MLDv2 messages originating from a Multicast Listener running on the same host as the Multicast Router are not being delivered to the Multicast Router. This is due to dst.input being assigned the default value of dst_discard. This results in the packet being looped back but discarded before being delivered to the Multicast Router. This patch sets dst.input to ip6_input to ensure a looped back packet is delivered to the Multicast Router. Signed-off-by: Brendan McGrath Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6e8bacb0b458..a8f80bd20c55 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1651,6 +1651,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, } rt->dst.flags |= DST_HOST; + rt->dst.input = ip6_input; rt->dst.output = ip6_output; atomic_set(&rt->dst.__refcnt, 1); rt->rt6i_gateway = fl6->daddr; -- GitLab From db1e8814be999976ea901e9cf7d2e0134e938b31 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Fri, 1 Dec 2017 03:51:04 +0100 Subject: [PATCH 0126/1834] ARM: 8731/1: Fix csum_partial_copy_from_user() stack mismatch [ Upstream commit 36b0cb84ee858f02c256d26f0cb4229c78e3399e ] An additional 'ip' will be pushed to the stack, for restoring the DACR later, if CONFIG_CPU_SW_DOMAIN_PAN defined. However, the fixup still get the err_ptr by add #8*4 to sp, which results in the fact that the code area pointed by the LR will be overwritten, or the kernel will crash if CONFIG_DEBUG_RODATA is enabled. This patch fixes the stack mismatch. Fixes: a5e090acbf54 ("ARM: software-based priviledged-no-access support") Signed-off-by: Lvqiang Huang Signed-off-by: Chunyan Zhang Signed-off-by: Russell King Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/lib/csumpartialcopyuser.S | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 1712f132b80d..b83fdc06286a 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S @@ -85,7 +85,11 @@ .pushsection .text.fixup,"ax" .align 4 9001: mov r4, #-EFAULT +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + ldr r5, [sp, #9*4] @ *err_ptr +#else ldr r5, [sp, #8*4] @ *err_ptr +#endif str r4, [r5] ldmia sp, {r1, r2} @ retrieve dst, len add r2, r2, r1 -- GitLab From 9a5bd36c0bb036def9ce7d2300f350a0db36a622 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Dec 2017 13:08:47 -0300 Subject: [PATCH 0127/1834] x86/asm: Allow again using asm.h when building for the 'bpf' clang target [ Upstream commit ca26cffa4e4aaeb09bb9e308f95c7835cb149248 ] Up to f5caf621ee35 ("x86/asm: Fix inline asm call constraints for Clang") we were able to use x86 headers to build to the 'bpf' clang target, as done by the BPF code in tools/perf/. With that commit, we ended up with following failure for 'perf test LLVM', this is because "clang ... -target bpf ..." fails since 4.0 does not have bpf inline asm support and 6.0 does not recognize the register 'esp', fix it by guarding that part with an #ifndef __BPF__, that is defined by clang when building to the "bpf" target. # perf test -v LLVM 37: LLVM search and compile : 37.1: Basic BPF llvm compile : --- start --- test child forked, pid 25526 Kernel build dir is set to /lib/modules/4.14.0+/build set env: KBUILD_DIR=/lib/modules/4.14.0+/build unset env: KBUILD_OPTS include option is set to -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/7/include -I/home/acme/git/linux/arch/x86/include -I./arch/x86/include/generated -I/home/acme/git/linux/include -I./include -I/home/acme/git/linux/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -I./include/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h set env: NR_CPUS=4 set env: LINUX_VERSION_CODE=0x40e00 set env: CLANG_EXEC=/usr/local/bin/clang set env: CLANG_OPTIONS=-xc set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/7/include -I/home/acme/git/linux/arch/x86/include -I./arch/x86/include/generated -I/home/acme/git/linux/include -I./include -I/home/acme/git/linux/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -I./include/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h set env: WORKING_DIR=/lib/modules/4.14.0+/build set env: CLANG_SOURCE=- llvm compiling command template: echo '/* * bpf-script-example.c * Test basic LLVM building */ #ifndef LINUX_VERSION_CODE # error Need LINUX_VERSION_CODE # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' #endif #define BPF_ANY 0 #define BPF_MAP_TYPE_ARRAY 2 #define BPF_FUNC_map_lookup_elem 1 #define BPF_FUNC_map_update_elem 2 static void *(*bpf_map_lookup_elem)(void *map, void *key) = (void *) BPF_FUNC_map_lookup_elem; static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) = (void *) BPF_FUNC_map_update_elem; struct bpf_map_def { unsigned int type; unsigned int key_size; unsigned int value_size; unsigned int max_entries; }; #define SEC(NAME) __attribute__((section(NAME), used)) struct bpf_map_def SEC("maps") flip_table = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(int), .value_size = sizeof(int), .max_entries = 1, }; SEC("func=SyS_epoll_wait") int bpf_func__SyS_epoll_wait(void *ctx) { int ind =0; int *flag = bpf_map_lookup_elem(&flip_table, &ind); int new_flag; if (!flag) return 0; /* flip flag and store back */ new_flag = !*flag; bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY); return new_flag; } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; ' | $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o - test child finished with 0 ---- end ---- LLVM search and compile subtest 0: Ok 37.2: kbuild searching : --- start --- test child forked, pid 25950 Kernel build dir is set to /lib/modules/4.14.0+/build set env: KBUILD_DIR=/lib/modules/4.14.0+/build unset env: KBUILD_OPTS include option is set to -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/7/include -I/home/acme/git/linux/arch/x86/include -I./arch/x86/include/generated -I/home/acme/git/linux/include -I./include -I/home/acme/git/linux/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -I./include/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h set env: NR_CPUS=4 set env: LINUX_VERSION_CODE=0x40e00 set env: CLANG_EXEC=/usr/local/bin/clang set env: CLANG_OPTIONS=-xc set env: KERNEL_INC_OPTIONS= -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/7/include -I/home/acme/git/linux/arch/x86/include -I./arch/x86/include/generated -I/home/acme/git/linux/include -I./include -I/home/acme/git/linux/arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I/home/acme/git/linux/include/uapi -I./include/generated/uapi -include /home/acme/git/linux/include/linux/kconfig.h set env: WORKING_DIR=/lib/modules/4.14.0+/build set env: CLANG_SOURCE=- llvm compiling command template: echo '/* * bpf-script-test-kbuild.c * Test include from kernel header */ #ifndef LINUX_VERSION_CODE # error Need LINUX_VERSION_CODE # error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig' #endif #define SEC(NAME) __attribute__((section(NAME), used)) #include #include SEC("func=vfs_llseek") int bpf_func__vfs_llseek(void *ctx) { return 0; } char _license[] SEC("license") = "GPL"; int _version SEC("version") = LINUX_VERSION_CODE; ' | $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS -DLINUX_VERSION_CODE=$LINUX_VERSION_CODE $CLANG_OPTIONS $KERNEL_INC_OPTIONS -Wno-unused-value -Wno-pointer-sign -working-directory $WORKING_DIR -c "$CLANG_SOURCE" -target bpf -O2 -o - In file included from :12: In file included from /home/acme/git/linux/arch/x86/include/uapi/asm/ptrace.h:5: In file included from /home/acme/git/linux/include/linux/compiler.h:242: In file included from /home/acme/git/linux/arch/x86/include/asm/barrier.h:5: In file included from /home/acme/git/linux/arch/x86/include/asm/alternative.h:10: /home/acme/git/linux/arch/x86/include/asm/asm.h:145:50: error: unknown register name 'esp' in asm register unsigned long current_stack_pointer asm(_ASM_SP); ^ /home/acme/git/linux/arch/x86/include/asm/asm.h:44:18: note: expanded from macro '_ASM_SP' #define _ASM_SP __ASM_REG(sp) ^ /home/acme/git/linux/arch/x86/include/asm/asm.h:27:32: note: expanded from macro '__ASM_REG' #define __ASM_REG(reg) __ASM_SEL_RAW(e##reg, r##reg) ^ /home/acme/git/linux/arch/x86/include/asm/asm.h:18:29: note: expanded from macro '__ASM_SEL_RAW' # define __ASM_SEL_RAW(a,b) __ASM_FORM_RAW(a) ^ /home/acme/git/linux/arch/x86/include/asm/asm.h:11:32: note: expanded from macro '__ASM_FORM_RAW' # define __ASM_FORM_RAW(x) #x ^ :4:1: note: expanded from here "esp" ^ 1 error generated. ERROR: unable to compile - Hint: Check error message shown above. Hint: You can also pre-compile it into .o using: clang -target bpf -O2 -c - with proper -I and -D options. Failed to compile test case: 'kbuild searching' test child finished with -1 ---- end ---- LLVM search and compile subtest 1: FAILED! Cc: Adrian Hunter Cc: Alexander Potapenko Cc: Alexei Starovoitov Cc: Andrey Ryabinin Cc: Andy Lutomirski Cc: Arnd Bergmann Cc: Daniel Borkmann Cc: David Ahern Cc: Dmitriy Vyukov Cc: Jiri Olsa Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Matthias Kaehlcke Cc: Miguel Bernal Marin Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Wang Nan Cc: Yonghong Song Link: https://lkml.kernel.org/r/20171128175948.GL3298@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/asm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 7bb29a416b77..f35f246a26bf 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -128,6 +128,7 @@ #endif #ifndef __ASSEMBLY__ +#ifndef __BPF__ /* * This output constraint should be used for any inline asm which has a "call" * instruction. Otherwise the asm may be inserted before the frame pointer @@ -137,5 +138,6 @@ register unsigned long current_stack_pointer asm(_ASM_SP); #define ASM_CALL_CONSTRAINT "+r" (current_stack_pointer) #endif +#endif #endif /* _ASM_X86_ASM_H */ -- GitLab From fd7cbb5ad8e8b222eff3401089e3244a7a8cb32e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 18 Dec 2017 15:05:07 -0500 Subject: [PATCH 0128/1834] sget(): handle failures of register_shrinker() [ Upstream commit 9ee332d99e4d5a97548943b81c54668450ce641b ] Signed-off-by: Al Viro Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/super.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/super.c b/fs/super.c index 1058bf3e8724..7e9beab77259 100644 --- a/fs/super.c +++ b/fs/super.c @@ -519,7 +519,11 @@ struct super_block *sget_userns(struct file_system_type *type, hlist_add_head(&s->s_instances, &type->fs_supers); spin_unlock(&sb_lock); get_filesystem(type); - register_shrinker(&s->s_shrink); + err = register_shrinker(&s->s_shrink); + if (err) { + deactivate_locked_super(s); + s = ERR_PTR(err); + } return s; } -- GitLab From 396927052bad2f8228c98d3eab34c097823fd089 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 16 Dec 2017 00:52:39 +0300 Subject: [PATCH 0129/1834] net: phy: xgene: disable clk on error paths [ Upstream commit ab14436065c8066c265540312742390d6d07ddd2 ] There are several error paths in xgene_mdio_probe(), where clk is left undisabled. The patch fixes them. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mdio-xgene.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c index 92af182951be..8eb077b677f6 100644 --- a/drivers/net/phy/mdio-xgene.c +++ b/drivers/net/phy/mdio-xgene.c @@ -197,8 +197,11 @@ static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata) } ret = xgene_enet_ecc_init(pdata); - if (ret) + if (ret) { + if (pdata->dev->of_node) + clk_disable_unprepare(pdata->clk); return ret; + } xgene_gmac_reset(pdata); return 0; @@ -364,8 +367,10 @@ static int xgene_mdio_probe(struct platform_device *pdev) return ret; mdio_bus = mdiobus_alloc(); - if (!mdio_bus) - return -ENOMEM; + if (!mdio_bus) { + ret = -ENOMEM; + goto out_clk; + } mdio_bus->name = "APM X-Gene MDIO bus"; @@ -394,7 +399,7 @@ static int xgene_mdio_probe(struct platform_device *pdev) mdio_bus->phy_mask = ~0; ret = mdiobus_register(mdio_bus); if (ret) - goto out; + goto out_mdiobus; acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_HANDLE(dev), 1, acpi_register_phy, NULL, mdio_bus, NULL); @@ -402,16 +407,20 @@ static int xgene_mdio_probe(struct platform_device *pdev) } if (ret) - goto out; + goto out_mdiobus; pdata->mdio_bus = mdio_bus; xgene_mdio_status = true; return 0; -out: +out_mdiobus: mdiobus_free(mdio_bus); +out_clk: + if (dev->of_node) + clk_disable_unprepare(pdata->clk); + return ret; } -- GitLab From 5330add6da101da85ef4d1dcf31bf2e1b3252fc8 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Fri, 24 Nov 2017 03:56:26 +0100 Subject: [PATCH 0130/1834] drm/nouveau/pci: do a msi rearm on init [ Upstream commit a121027d2747168df0aac0c3da35509eea39f61c ] On my GP107 when I load nouveau after unloading it, for some reason the GPU stopped sending or the CPU stopped receiving interrupts if MSI was enabled. Doing a rearm once before getting any interrupts fixes this. Signed-off-by: Karol Herbst Reviewed-by: Thierry Reding Signed-off-by: Ben Skeggs Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index a4cb82495cee..245c946ea661 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -136,6 +136,13 @@ nvkm_pci_init(struct nvkm_subdev *subdev) return ret; pci->irq = pdev->irq; + + /* Ensure MSI interrupts are armed, for the case where there are + * already interrupts pending (for whatever reason) at load time. + */ + if (pci->msi) + pci->func->msi_rearm(pci); + return ret; } -- GitLab From ad176934842636d8b1d23298fb90d10a97e4c6f7 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Tue, 12 Dec 2017 17:26:36 +0800 Subject: [PATCH 0131/1834] mac80211_hwsim: Fix a possible sleep-in-atomic bug in hwsim_get_radio_nl [ Upstream commit 162bd5e5fd921785077b5862d8f2ffabe2fe11e5 ] The driver may sleep under a spinlock. The function call path is: hwsim_get_radio_nl (acquire the spinlock) nlmsg_new(GFP_KERNEL) --> may sleep To fix it, GFP_KERNEL is replaced with GFP_ATOMIC. This bug is found by my static analysis tool(DSAC) and checked by my code review. Signed-off-by: Jia-Ju Bai Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mac80211_hwsim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 4b462dc21c41..61e85eac706a 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -3154,7 +3154,7 @@ static int hwsim_get_radio_nl(struct sk_buff *msg, struct genl_info *info) if (!net_eq(wiphy_net(data->hw->wiphy), genl_info_net(info))) continue; - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); if (!skb) { res = -ENOMEM; goto out_err; -- GitLab From 90f7d14cef9bd30214dd7e56fc3c7a468cef6228 Mon Sep 17 00:00:00 2001 From: Radu Pirea Date: Fri, 15 Dec 2017 17:40:17 +0200 Subject: [PATCH 0132/1834] spi: atmel: fixed spin_lock usage inside atmel_spi_remove [ Upstream commit 66e900a3d225575c8b48b59ae1fe74bb6e5a65cc ] The only part of atmel_spi_remove which needs to be atomic is hardware reset. atmel_spi_stop_dma calls dma_terminate_all and this needs interrupts enabled. atmel_spi_release_dma calls dma_release_channel and dma_release_channel locks a mutex inside of spin_lock. So the call of these functions can't be inside a spin_lock. Reported-by: Jia-Ju Bai Signed-off-by: Radu Pirea Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-atmel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 8feac599e9ab..44be6b593b30 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1669,12 +1669,12 @@ static int atmel_spi_remove(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); /* reset the hardware and block queue progress */ - spin_lock_irq(&as->lock); if (as->use_dma) { atmel_spi_stop_dma(as); atmel_spi_release_dma(as); } + spin_lock_irq(&as->lock); spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ spi_readl(as, SR); -- GitLab From 1ec97b2a4475e6157ec84b2a5d14530861badd0c Mon Sep 17 00:00:00 2001 From: Abhijeet Kumar Date: Tue, 12 Dec 2017 00:40:25 +0530 Subject: [PATCH 0133/1834] ASoC: nau8825: fix issue that pop noise when start capture [ Upstream commit d070f7c703ef26e3db613f24206823f916272fc6 ] In skylake platform, we hear a loud pop noise(0 dB) at start of audio capture power up sequence. This patch removes the pop noise from the recording by adding a delay before enabling ADC. Signed-off-by: Abhijeet Kumar Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/nau8825.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index f9f2737c4ad2..a4871c4adcb0 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -882,6 +882,7 @@ static int nau8825_adc_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: + msleep(125); regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL, NAU8825_ENABLE_ADC, NAU8825_ENABLE_ADC); break; -- GitLab From 757677d0da516f9f60b7a855ecbf10b73263e006 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 18 Dec 2017 17:00:17 +0800 Subject: [PATCH 0134/1834] net: mediatek: setup proper state for disabled GMAC on the default [ Upstream commit 7352e252b5bf40d59342494a70354a2d436fd0cd ] The current solution would setup fixed and force link of 1Gbps to the both GMAC on the default. However, The GMAC should always be put to link down state when the GMAC is disabled on certain target boards. Otherwise, the driver possibly receives unexpected data from the floating hardware connection through the unused GMAC. Although the driver had been added certain protection in RX path to get rid of such kind of unexpected data sent to the upper stack. Signed-off-by: Sean Wang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mediatek/mtk_eth_soc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 4832223f1500..20de37a414fe 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -1842,11 +1842,12 @@ static int mtk_hw_init(struct mtk_eth *eth) /* set GE2 TUNE */ regmap_write(eth->pctl, GPIO_BIAS_CTRL, 0x0); - /* GE1, Force 1000M/FD, FC ON */ - mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(0)); - - /* GE2, Force 1000M/FD, FC ON */ - mtk_w32(eth, MAC_MCR_FIXED_LINK, MTK_MAC_MCR(1)); + /* Set linkdown as the default for each GMAC. Its own MCR would be set + * up with the more appropriate value when mtk_phy_link_adjust call is + * being invoked. + */ + for (i = 0; i < MTK_MAC_COUNT; i++) + mtk_w32(eth, 0, MTK_MAC_MCR(i)); /* Enable RX VLan Offloading */ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL); -- GitLab From 95e094a709eabaede6c53272b2d90925c55c02e0 Mon Sep 17 00:00:00 2001 From: Alexander Kochetkov Date: Fri, 15 Dec 2017 20:20:06 +0300 Subject: [PATCH 0135/1834] net: arc_emac: fix arc_emac_rx() error paths [ Upstream commit e688822d035b494071ecbadcccbd6f3325fb0f59 ] arc_emac_rx() has some issues found by code review. In case netdev_alloc_skb_ip_align() or dma_map_single() failure rx fifo entry will not be returned to EMAC. In case dma_map_single() failure previously allocated skb became lost to driver. At the same time address of newly allocated skb will not be provided to EMAC. Signed-off-by: Alexander Kochetkov Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/arc/emac_main.c | 53 ++++++++++++++++------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index be865b4dada2..aba4853e6b70 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -210,39 +210,48 @@ static int arc_emac_rx(struct net_device *ndev, int budget) continue; } - pktlen = info & LEN_MASK; - stats->rx_packets++; - stats->rx_bytes += pktlen; - skb = rx_buff->skb; - skb_put(skb, pktlen); - skb->dev = ndev; - skb->protocol = eth_type_trans(skb, ndev); - - dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr), - dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE); - - /* Prepare the BD for next cycle */ - rx_buff->skb = netdev_alloc_skb_ip_align(ndev, - EMAC_BUFFER_SIZE); - if (unlikely(!rx_buff->skb)) { + /* Prepare the BD for next cycle. netif_receive_skb() + * only if new skb was allocated and mapped to avoid holes + * in the RX fifo. + */ + skb = netdev_alloc_skb_ip_align(ndev, EMAC_BUFFER_SIZE); + if (unlikely(!skb)) { + if (net_ratelimit()) + netdev_err(ndev, "cannot allocate skb\n"); + /* Return ownership to EMAC */ + rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); stats->rx_errors++; - /* Because receive_skb is below, increment rx_dropped */ stats->rx_dropped++; continue; } - /* receive_skb only if new skb was allocated to avoid holes */ - netif_receive_skb(skb); - - addr = dma_map_single(&ndev->dev, (void *)rx_buff->skb->data, + addr = dma_map_single(&ndev->dev, (void *)skb->data, EMAC_BUFFER_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(&ndev->dev, addr)) { if (net_ratelimit()) - netdev_err(ndev, "cannot dma map\n"); - dev_kfree_skb(rx_buff->skb); + netdev_err(ndev, "cannot map dma buffer\n"); + dev_kfree_skb(skb); + /* Return ownership to EMAC */ + rxbd->info = cpu_to_le32(FOR_EMAC | EMAC_BUFFER_SIZE); stats->rx_errors++; + stats->rx_dropped++; continue; } + + /* unmap previosly mapped skb */ + dma_unmap_single(&ndev->dev, dma_unmap_addr(rx_buff, addr), + dma_unmap_len(rx_buff, len), DMA_FROM_DEVICE); + + pktlen = info & LEN_MASK; + stats->rx_packets++; + stats->rx_bytes += pktlen; + skb_put(rx_buff->skb, pktlen); + rx_buff->skb->dev = ndev; + rx_buff->skb->protocol = eth_type_trans(rx_buff->skb, ndev); + + netif_receive_skb(rx_buff->skb); + + rx_buff->skb = skb; dma_unmap_addr_set(rx_buff, addr, addr); dma_unmap_len_set(rx_buff, len, EMAC_BUFFER_SIZE); -- GitLab From 1148fee2173c03718b1f3ce47d67eb09c165368f Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 18 Dec 2017 14:26:21 +0800 Subject: [PATCH 0136/1834] ip6_tunnel: get the min mtu properly in ip6_tnl_xmit [ Upstream commit c9fefa08190fc879fb2e681035d7774e0a8c5170 ] Now it's using IPV6_MIN_MTU as the min mtu in ip6_tnl_xmit, but IPV6_MIN_MTU actually only works when the inner packet is ipv6. With IPV6_MIN_MTU for ipv4 packets, the new pmtu for inner dst couldn't be set less than 1280. It would cause tx_err and the packet to be dropped when the outer dst pmtu is close to 1280. Jianlin found it by running ipv4 traffic with the topo: (client) gre6 <---> eth1 (route) eth2 <---> gre6 (server) After changing eth2 mtu to 1300, the performance became very low, or the connection was even broken. The issue also affects ip4ip6 and ip6ip6 tunnels. So if the inner packet is ipv4, 576 should be considered as the min mtu. Note that for ip4ip6 and ip6ip6 tunnels, the inner packet can only be ipv4 or ipv6, but for gre6 tunnel, it may also be ARP. This patch using 576 as the min mtu for non-ipv6 packet works for all those cases. Reported-by: Jianlin Shi Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_tunnel.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 131e6aa954bc..a2fcf7bdb597 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1127,8 +1127,13 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, max_headroom += 8; mtu -= 8; } - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; + if (skb->protocol == htons(ETH_P_IPV6)) { + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + } else if (mtu < 576) { + mtu = 576; + } + if (skb_dst(skb) && !t->parms.collect_md) skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) { -- GitLab From 9d0858e71219ca4657ebeff7eea92067fbaf9b77 Mon Sep 17 00:00:00 2001 From: Fredrik Hallenberg Date: Mon, 18 Dec 2017 23:33:59 +0100 Subject: [PATCH 0137/1834] net: stmmac: Fix TX timestamp calculation [ Upstream commit 200922c93f008e03ddc804c6dacdf26ca1ba86d7 ] When using GMAC4 the value written in PTP_SSIR should be shifted however the shifted value is also used in subsequent calculations which results in a bad timestamp value. Signed-off-by: Fredrik Hallenberg Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c index 10d6059b2f26..f4074e25fb71 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c @@ -38,6 +38,7 @@ static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, { u32 value = readl(ioaddr + PTP_TCR); unsigned long data; + u32 reg_value; /* For GMAC3.x, 4.x versions, convert the ptp_clock to nano second * formula = (1/ptp_clock) * 1000000000 @@ -54,10 +55,11 @@ static u32 stmmac_config_sub_second_increment(void __iomem *ioaddr, data &= PTP_SSIR_SSINC_MASK; + reg_value = data; if (gmac4) - data = data << GMAC4_PTP_SSIR_SSINC_SHIFT; + reg_value <<= GMAC4_PTP_SSIR_SSINC_SHIFT; - writel(data, ioaddr + PTP_SSIR); + writel(reg_value, ioaddr + PTP_SSIR); return data; } -- GitLab From 6358cb4c5b273cd8ddcd7c850084fae721566523 Mon Sep 17 00:00:00 2001 From: Cathy Avery Date: Tue, 19 Dec 2017 13:32:48 -0500 Subject: [PATCH 0138/1834] scsi: storvsc: Fix scsi_cmd error assignments in storvsc_handle_error [ Upstream commit d1b8b2391c24751e44f618fcf86fb55d9a9247fd ] When an I/O is returned with an srb_status of SRB_STATUS_INVALID_LUN which has zero good_bytes it must be assigned an error. Otherwise the I/O will be continuously requeued and will cause a deadlock in the case where disks are being hot added and removed. sd_probe_async will wait forever for its I/O to complete while holding scsi_sd_probe_domain. Also returning the default error of DID_TARGET_FAILURE causes multipath to not retry the I/O resulting in applications receiving I/O errors before a failover can occur. Signed-off-by: Cathy Avery Signed-off-by: Long Li Reviewed-by: Stephen Hemminger Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/storvsc_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 2bf96d33428a..0dd1984e381e 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -915,10 +915,11 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb, case TEST_UNIT_READY: break; default: - set_host_byte(scmnd, DID_TARGET_FAILURE); + set_host_byte(scmnd, DID_ERROR); } break; case SRB_STATUS_INVALID_LUN: + set_host_byte(scmnd, DID_NO_CONNECT); do_work = true; process_err_fn = storvsc_remove_lun; break; -- GitLab From 0a1b1ee6a73bead5f3da08f60f92fdacbedfd008 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 21 Dec 2017 22:35:19 +0100 Subject: [PATCH 0139/1834] ARM: dts: ls1021a: fix incorrect clock references [ Upstream commit 506e8a912661c97b41adc8a286b875d01323ec45 ] dtc warns about two 'clocks' properties that have an extraneous '1' at the end: arch/arm/boot/dts/ls1021a-qds.dtb: Warning (clocks_property): arch/arm/boot/dts/ls1021a-twr.dtb: Warning (clocks_property): Property 'clocks', cell 1 is not a phandle reference in /soc/i2c@2180000/mux@77/i2c@4/sgtl5000@2a arch/arm/boot/dts/ls1021a-qds.dtb: Warning (clocks_property): Missing property '#clock-cells' in node /soc/interrupt-controller@1400000 or bad phandle (referred from /soc/i2c@2180000/mux@77/i2c@4/sgtl5000@2a:clocks[1]) Property 'clocks', cell 1 is not a phandle reference in /soc/i2c@2190000/sgtl5000@a arch/arm/boot/dts/ls1021a-twr.dtb: Warning (clocks_property): Missing property '#clock-cells' in node /soc/interrupt-controller@1400000 or bad phandle (referred from /soc/i2c@2190000/sgtl5000@a:clocks[1]) The clocks that get referenced here are fixed-rate, so they do not take any argument, and dtc interprets the next cell as a phandle, which is invalid. Signed-off-by: Arnd Bergmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/ls1021a-qds.dts | 2 +- arch/arm/boot/dts/ls1021a-twr.dts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts index 940875316d0f..67b4de0e3439 100644 --- a/arch/arm/boot/dts/ls1021a-qds.dts +++ b/arch/arm/boot/dts/ls1021a-qds.dts @@ -215,7 +215,7 @@ reg = <0x2a>; VDDA-supply = <®_3p3v>; VDDIO-supply = <®_3p3v>; - clocks = <&sys_mclk 1>; + clocks = <&sys_mclk>; }; }; }; diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts index a8b148ad1dd2..44715c8ef756 100644 --- a/arch/arm/boot/dts/ls1021a-twr.dts +++ b/arch/arm/boot/dts/ls1021a-twr.dts @@ -187,7 +187,7 @@ reg = <0x0a>; VDDA-supply = <®_3p3v>; VDDIO-supply = <®_3p3v>; - clocks = <&sys_mclk 1>; + clocks = <&sys_mclk>; }; }; -- GitLab From d9868db6588f587266d9c112ea14a6c2f89f0f67 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Tue, 5 Dec 2017 23:31:35 +0000 Subject: [PATCH 0140/1834] lib/mpi: Fix umul_ppmm() for MIPS64r6 [ Upstream commit bbc25bee37d2b32cf3a1fab9195b6da3a185614a ] Current MIPS64r6 toolchains aren't able to generate efficient DMULU/DMUHU based code for the C implementation of umul_ppmm(), which performs an unsigned 64 x 64 bit multiply and returns the upper and lower 64-bit halves of the 128-bit result. Instead it widens the 64-bit inputs to 128-bits and emits a __multi3 intrinsic call to perform a 128 x 128 multiply. This is both inefficient, and it results in a link error since we don't include __multi3 in MIPS linux. For example commit 90a53e4432b1 ("cfg80211: implement regdb signature checking") merged in v4.15-rc1 recently broke the 64r6_defconfig and 64r6el_defconfig builds by indirectly selecting MPILIB. The same build errors can be reproduced on older kernels by enabling e.g. CRYPTO_RSA: lib/mpi/generic_mpih-mul1.o: In function `mpihelp_mul_1': lib/mpi/generic_mpih-mul1.c:50: undefined reference to `__multi3' lib/mpi/generic_mpih-mul2.o: In function `mpihelp_addmul_1': lib/mpi/generic_mpih-mul2.c:49: undefined reference to `__multi3' lib/mpi/generic_mpih-mul3.o: In function `mpihelp_submul_1': lib/mpi/generic_mpih-mul3.c:49: undefined reference to `__multi3' lib/mpi/mpih-div.o In function `mpihelp_divrem': lib/mpi/mpih-div.c:205: undefined reference to `__multi3' lib/mpi/mpih-div.c:142: undefined reference to `__multi3' Therefore add an efficient MIPS64r6 implementation of umul_ppmm() using inline assembly and the DMULU/DMUHU instructions, to prevent __multi3 calls being emitted. Fixes: 7fd08ca58ae6 ("MIPS: Add build support for the MIPS R6 ISA") Signed-off-by: James Hogan Cc: Ralf Baechle Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-mips@linux-mips.org Cc: linux-crypto@vger.kernel.org Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- lib/mpi/longlong.h | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/mpi/longlong.h b/lib/mpi/longlong.h index 93336502af08..0f64fcee4ccd 100644 --- a/lib/mpi/longlong.h +++ b/lib/mpi/longlong.h @@ -671,7 +671,23 @@ do { \ ************** MIPS/64 ************** ***************************************/ #if (defined(__mips) && __mips >= 3) && W_TYPE_SIZE == 64 -#if (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4) +#if defined(__mips_isa_rev) && __mips_isa_rev >= 6 +/* + * GCC ends up emitting a __multi3 intrinsic call for MIPS64r6 with the plain C + * code below, so we special case MIPS64r6 until the compiler can do better. + */ +#define umul_ppmm(w1, w0, u, v) \ +do { \ + __asm__ ("dmulu %0,%1,%2" \ + : "=d" ((UDItype)(w0)) \ + : "d" ((UDItype)(u)), \ + "d" ((UDItype)(v))); \ + __asm__ ("dmuhu %0,%1,%2" \ + : "=d" ((UDItype)(w1)) \ + : "d" ((UDItype)(u)), \ + "d" ((UDItype)(v))); \ +} while (0) +#elif (__GNUC__ >= 5) || (__GNUC__ >= 4 && __GNUC_MINOR__ >= 4) #define umul_ppmm(w1, w0, u, v) \ do { \ typedef unsigned int __ll_UTItype __attribute__((mode(TI))); \ -- GitLab From f60f577f18c23db299072682ead2f357b282d01c Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Fri, 22 Dec 2017 09:35:16 +0200 Subject: [PATCH 0141/1834] tipc: error path leak fixes in tipc_enable_bearer() [ Upstream commit 19142551b2be4a9e13838099fde1351386e5e007 ] Fix memory leak in tipc_enable_bearer() if enable_media() fails, and cleanup with bearer_disable() if tipc_mon_create() fails. Acked-by: Ying Xue Acked-by: Jon Maloy Signed-off-by: Tommi Rantala Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/tipc/bearer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 52d74760fb68..ca68db207965 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -322,6 +322,7 @@ static int tipc_enable_bearer(struct net *net, const char *name, if (res) { pr_warn("Bearer <%s> rejected, enable failure (%d)\n", name, -res); + kfree(b); return -EINVAL; } @@ -345,8 +346,10 @@ static int tipc_enable_bearer(struct net *net, const char *name, if (skb) tipc_bearer_xmit_skb(net, bearer_id, skb, &b->bcast_addr); - if (tipc_mon_create(net, bearer_id)) + if (tipc_mon_create(net, bearer_id)) { + bearer_disable(net, b); return -ENOMEM; + } pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n", name, -- GitLab From edaf4ff0a2552da4d811fa82ec4cfc7fd4480871 Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Fri, 22 Dec 2017 09:35:17 +0200 Subject: [PATCH 0142/1834] tipc: fix tipc_mon_delete() oops in tipc_enable_bearer() error path [ Upstream commit 642a8439ddd8423b92f2e71960afe21ee1f66bb6 ] Calling tipc_mon_delete() before the monitor has been created will oops. This can happen in tipc_enable_bearer() error path if tipc_disc_create() fails. [ 48.589074] BUG: unable to handle kernel paging request at 0000000000001008 [ 48.590266] IP: tipc_mon_delete+0xea/0x270 [tipc] [ 48.591223] PGD 1e60c5067 P4D 1e60c5067 PUD 1eb0cf067 PMD 0 [ 48.592230] Oops: 0000 [#1] SMP KASAN [ 48.595610] CPU: 5 PID: 1199 Comm: tipc Tainted: G B 4.15.0-rc4-pc64-dirty #5 [ 48.597176] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-2.fc27 04/01/2014 [ 48.598489] RIP: 0010:tipc_mon_delete+0xea/0x270 [tipc] [ 48.599347] RSP: 0018:ffff8801d827f668 EFLAGS: 00010282 [ 48.600705] RAX: ffff8801ee813f00 RBX: 0000000000000204 RCX: 0000000000000000 [ 48.602183] RDX: 1ffffffff1de6a75 RSI: 0000000000000297 RDI: 0000000000000297 [ 48.604373] RBP: 0000000000000000 R08: 0000000000000000 R09: fffffbfff1dd1533 [ 48.605607] R10: ffffffff8eafbb05 R11: fffffbfff1dd1534 R12: 0000000000000050 [ 48.607082] R13: dead000000000200 R14: ffffffff8e73f310 R15: 0000000000001020 [ 48.608228] FS: 00007fc686484800(0000) GS:ffff8801f5540000(0000) knlGS:0000000000000000 [ 48.610189] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 48.611459] CR2: 0000000000001008 CR3: 00000001dda70002 CR4: 00000000003606e0 [ 48.612759] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 48.613831] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 48.615038] Call Trace: [ 48.615635] tipc_enable_bearer+0x415/0x5e0 [tipc] [ 48.620623] tipc_nl_bearer_enable+0x1ab/0x200 [tipc] [ 48.625118] genl_family_rcv_msg+0x36b/0x570 [ 48.631233] genl_rcv_msg+0x5a/0xa0 [ 48.631867] netlink_rcv_skb+0x1cc/0x220 [ 48.636373] genl_rcv+0x24/0x40 [ 48.637306] netlink_unicast+0x29c/0x350 [ 48.639664] netlink_sendmsg+0x439/0x590 [ 48.642014] SYSC_sendto+0x199/0x250 [ 48.649912] do_syscall_64+0xfd/0x2c0 [ 48.650651] entry_SYSCALL64_slow_path+0x25/0x25 [ 48.651843] RIP: 0033:0x7fc6859848e3 [ 48.652539] RSP: 002b:00007ffd25dff938 EFLAGS: 00000246 ORIG_RAX: 000000000000002c [ 48.654003] RAX: ffffffffffffffda RBX: 00007ffd25dff990 RCX: 00007fc6859848e3 [ 48.655303] RDX: 0000000000000054 RSI: 00007ffd25dff990 RDI: 0000000000000003 [ 48.656512] RBP: 00007ffd25dff980 R08: 00007fc685c35fc0 R09: 000000000000000c [ 48.657697] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000d13010 [ 48.658840] R13: 00007ffd25e009c0 R14: 0000000000000000 R15: 0000000000000000 [ 48.662972] RIP: tipc_mon_delete+0xea/0x270 [tipc] RSP: ffff8801d827f668 [ 48.664073] CR2: 0000000000001008 [ 48.664576] ---[ end trace e811818d54d5ce88 ]--- Acked-by: Ying Xue Acked-by: Jon Maloy Signed-off-by: Tommi Rantala Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/tipc/monitor.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c index 9e109bb1a207..0fcfb3916dcf 100644 --- a/net/tipc/monitor.c +++ b/net/tipc/monitor.c @@ -633,9 +633,13 @@ void tipc_mon_delete(struct net *net, int bearer_id) { struct tipc_net *tn = tipc_net(net); struct tipc_monitor *mon = tipc_monitor(net, bearer_id); - struct tipc_peer *self = get_self(net, bearer_id); + struct tipc_peer *self; struct tipc_peer *peer, *tmp; + if (!mon) + return; + + self = get_self(net, bearer_id); write_lock_bh(&mon->lock); tn->monitors[bearer_id] = NULL; list_for_each_entry_safe(peer, tmp, &self->list, list) { -- GitLab From 3d6becbc8063bda30a84527039fac9cf449a1e56 Mon Sep 17 00:00:00 2001 From: Siva Reddy Kallam Date: Fri, 22 Dec 2017 16:05:28 +0530 Subject: [PATCH 0143/1834] tg3: Add workaround to restrict 5762 MRRS to 2048 [ Upstream commit 4419bb1cedcda0272e1dc410345c5a1d1da0e367 ] One of AMD based server with 5762 hangs with jumbo frame traffic. This AMD platform has southbridge limitation which is restricting MRRS to 4000. As a work around, driver to restricts the MRRS to 2048 for this particular 5762 NX1 card. Signed-off-by: Siva Reddy Kallam Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 10 ++++++++++ drivers/net/ethernet/broadcom/tg3.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index bb22d325e965..3943c5c1281c 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -10049,6 +10049,16 @@ static int tg3_reset_hw(struct tg3 *tp, bool reset_phy) tw32(GRC_MODE, tp->grc_mode | val); + /* On one of the AMD platform, MRRS is restricted to 4000 because of + * south bridge limitation. As a workaround, Driver is setting MRRS + * to 2048 instead of default 4096. + */ + if (tp->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && + tp->pdev->subsystem_device == TG3PCI_SUBDEVICE_ID_DELL_5762) { + val = tr32(TG3PCI_DEV_STATUS_CTRL) & ~MAX_READ_REQ_MASK; + tw32(TG3PCI_DEV_STATUS_CTRL, val | MAX_READ_REQ_SIZE_2048); + } + /* Setup the timer prescalar register. Clock is always 66Mhz. */ val = tr32(GRC_MISC_CFG); val &= ~0xff; diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index 3b5e98ecba00..6e51b793615c 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -95,6 +95,7 @@ #define TG3PCI_SUBDEVICE_ID_DELL_JAGUAR 0x0106 #define TG3PCI_SUBDEVICE_ID_DELL_MERLOT 0x0109 #define TG3PCI_SUBDEVICE_ID_DELL_SLIM_MERLOT 0x010a +#define TG3PCI_SUBDEVICE_ID_DELL_5762 0x07f0 #define TG3PCI_SUBVENDOR_ID_COMPAQ PCI_VENDOR_ID_COMPAQ #define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE 0x007c #define TG3PCI_SUBDEVICE_ID_COMPAQ_BANSHEE_2 0x009a @@ -280,6 +281,9 @@ #define TG3PCI_STD_RING_PROD_IDX 0x00000098 /* 64-bit */ #define TG3PCI_RCV_RET_RING_CON_IDX 0x000000a0 /* 64-bit */ /* 0xa8 --> 0xb8 unused */ +#define TG3PCI_DEV_STATUS_CTRL 0x000000b4 +#define MAX_READ_REQ_SIZE_2048 0x00004000 +#define MAX_READ_REQ_MASK 0x00007000 #define TG3PCI_DUAL_MAC_CTRL 0x000000b8 #define DUAL_MAC_CTRL_CH_MASK 0x00000003 #define DUAL_MAC_CTRL_ID 0x00000004 -- GitLab From 78cc448e0882abffdc0c50309127d39bc2523146 Mon Sep 17 00:00:00 2001 From: Siva Reddy Kallam Date: Fri, 22 Dec 2017 16:05:29 +0530 Subject: [PATCH 0144/1834] tg3: Enable PHY reset in MTU change path for 5720 [ Upstream commit e60ee41aaf898584205a6af5c996860d0fe6a836 ] A customer noticed RX path hang when MTU is changed on the fly while running heavy traffic with NCSI enabled for 5717 and 5719. Since 5720 belongs to same ASIC family, we observed same issue and same fix could solve this problem for 5720. Signed-off-by: Siva Reddy Kallam Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/tg3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 3943c5c1281c..795a133fb074 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -14238,7 +14238,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) */ if (tg3_asic_rev(tp) == ASIC_REV_57766 || tg3_asic_rev(tp) == ASIC_REV_5717 || - tg3_asic_rev(tp) == ASIC_REV_5719) + tg3_asic_rev(tp) == ASIC_REV_5719 || + tg3_asic_rev(tp) == ASIC_REV_5720) reset_phy = true; err = tg3_restart_hw(tp, reset_phy); -- GitLab From af60c3822a721f9c2bf511ed1234e59ee4135010 Mon Sep 17 00:00:00 2001 From: "Guilherme G. Piccoli" Date: Fri, 22 Dec 2017 13:01:39 -0200 Subject: [PATCH 0145/1834] bnx2x: Improve reliability in case of nested PCI errors [ Upstream commit f7084059a9cb9e56a186e1677b1dcffd76c2cd24 ] While in recovery process of PCI error (called EEH on PowerPC arch), another PCI transaction could be corrupted causing a situation of nested PCI errors. Also, this scenario could be reproduced with error injection mechanisms (for debug purposes). We observe that in case of nested PCI errors, bnx2x might attempt to initialize its shmem and cause a kernel crash due to bad addresses read from MCP. Multiple different stack traces were observed depending on the point the second PCI error happens. This patch avoids the crashes by: * failing PCI recovery in case of nested errors (since multiple PCI errors in a row are not expected to lead to a functional adapter anyway), and by, * preventing access to adapter FW when MCP is failed (we mark it as failed when shmem cannot get initialized properly). Reported-by: Abdul Haleem Signed-off-by: Guilherme G. Piccoli Acked-by: Shahed Shaikh Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 ++-- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 0a5ee1d973ac..596f88b693ef 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3034,7 +3034,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) del_timer_sync(&bp->timer); - if (IS_PF(bp)) { + if (IS_PF(bp) && !BP_NOMCP(bp)) { /* Set ALWAYS_ALIVE bit in shmem */ bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE; bnx2x_drv_pulse(bp); @@ -3120,7 +3120,7 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) bp->cnic_loaded = false; /* Clear driver version indication in shmem */ - if (IS_PF(bp)) + if (IS_PF(bp) && !BP_NOMCP(bp)) bnx2x_update_mng_version(bp); /* Check if there are pending parity attentions. If there are - set diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 5d958b5bb8b1..554c4086b3c6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -9578,6 +9578,15 @@ static int bnx2x_init_shmem(struct bnx2x *bp) do { bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + + /* If we read all 0xFFs, means we are in PCI error state and + * should bail out to avoid crashes on adapter's FW reads. + */ + if (bp->common.shmem_base == 0xFFFFFFFF) { + bp->flags |= NO_MCP_FLAG; + return -ENODEV; + } + if (bp->common.shmem_base) { val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); if (val & SHR_MEM_VALIDITY_MB) @@ -14312,7 +14321,10 @@ static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev) BNX2X_ERR("IO slot reset --> driver unload\n"); /* MCP should have been reset; Need to wait for validity */ - bnx2x_init_shmem(bp); + if (bnx2x_init_shmem(bp)) { + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) { u32 v; -- GitLab From 86b9fa2190907f4f550d9d6bf490c5f89ca33836 Mon Sep 17 00:00:00 2001 From: Matthieu CASTET Date: Tue, 12 Dec 2017 11:10:44 +0100 Subject: [PATCH 0146/1834] led: core: Fix brightness setting when setting delay_off=0 [ Upstream commit 2b83ff96f51d0b039c4561b9f95c824d7bddb85c ] With the current code, the following sequence won't work : echo timer > trigger echo 0 > delay_off * at this point we call ** led_delay_off_store ** led_blink_set --- drivers/leds/led-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 3bce44893021..d70d4a5273b8 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -186,7 +186,7 @@ void led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { - del_timer_sync(&led_cdev->blink_timer); + led_stop_software_blink(led_cdev); led_cdev->flags &= ~LED_BLINK_ONESHOT; led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; -- GitLab From 64fb18c837c79d6c98985e57ae2b6a8420a616b2 Mon Sep 17 00:00:00 2001 From: Nitzan Carmi Date: Tue, 26 Dec 2017 11:20:20 +0200 Subject: [PATCH 0147/1834] IB/mlx5: Fix mlx5_ib_alloc_mr error flow [ Upstream commit 45e6ae7ef21b907dacb18da62d5787d74a31d860 ] ibmr.device is being set only after ib_alloc_mr() is (successfully) complete. Therefore, in case mlx5_core_create_mkey() return with error, the error flow calls mlx5_free_priv_descs() which uses ibmr.device (which doesn't exist yet), causing a NULL dereference oops. To fix this, the IB device should be set in the mr struct earlier stage (e.g. prior to calling mlx5_core_create_mkey()). Fixes: 8a187ee52b04 ("IB/mlx5: Support the new memory registration API") Signed-off-by: Max Gurtovoy Signed-off-by: Nitzan Carmi Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/mr.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 0a260a06876d..c7d5786d366b 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1648,6 +1648,7 @@ struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, MLX5_SET(mkc, mkc, access_mode, mr->access_mode); MLX5_SET(mkc, mkc, umr_en, 1); + mr->ibmr.device = pd->device; err = mlx5_core_create_mkey(dev->mdev, &mr->mmkey, in, inlen); if (err) goto err_destroy_psv; -- GitLab From ff5544ddfdaa3ab3cf737e2829d876ff4c537378 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 2 Dec 2017 09:13:04 -0800 Subject: [PATCH 0148/1834] genirq: Guard handle_bad_irq log messages [ Upstream commit 11bca0a83f83f6093d816295668e74ef24595944 ] An interrupt storm on a bad interrupt will cause the kernel log to be clogged. [ 60.089234] ->handle_irq(): ffffffffbe2f803f, [ 60.090455] 0xffffffffbf2af380 [ 60.090510] handle_bad_irq+0x0/0x2e5 [ 60.090522] ->irq_data.chip(): ffffffffbf2af380, [ 60.090553] IRQ_NOPROBE set [ 60.090584] ->handle_irq(): ffffffffbe2f803f, [ 60.090590] handle_bad_irq+0x0/0x2e5 [ 60.090596] ->irq_data.chip(): ffffffffbf2af380, [ 60.090602] 0xffffffffbf2af380 [ 60.090608] ->action(): (null) [ 60.090779] handle_bad_irq+0x0/0x2e5 This was seen when running an upstream kernel on Acer Chromebook R11. The system was unstable as result. Guard the log message with __printk_ratelimit to reduce the impact. This won't prevent the interrupt storm from happening, but at least the system remains stable. Signed-off-by: Guenter Roeck Signed-off-by: Thomas Gleixner Cc: Dmitry Torokhov Cc: Joe Perches Cc: Andy Shevchenko Cc: Mika Westerberg Link: https://bugzilla.kernel.org/show_bug.cgi?id=197953 Link: https://lkml.kernel.org/r/1512234784-21038-1-git-send-email-linux@roeck-us.net Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/irq/debug.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/irq/debug.h b/kernel/irq/debug.h index e75e29e4434a..3514d955af94 100644 --- a/kernel/irq/debug.h +++ b/kernel/irq/debug.h @@ -11,6 +11,11 @@ static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc) { + static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5); + + if (!__ratelimit(&ratelimit)) + return; + printk("irq %d, desc: %p, depth: %d, count: %d, unhandled: %d\n", irq, desc, desc->depth, desc->irq_count, desc->irqs_unhandled); printk("->handle_irq(): %p, ", desc->handle_irq); -- GitLab From 336c28a1228f11a6a4a3c6cc267cc45d7ce94daa Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 6 Dec 2017 10:30:39 +0100 Subject: [PATCH 0149/1834] s390/dasd: fix wrongly assigned configuration data [ Upstream commit 8a9bd4f8ebc6800bfc0596e28631ff6809a2f615 ] We store per path and per device configuration data to identify the path or device correctly. The per path configuration data might get mixed up if the original request gets into error recovery and is started with a random path mask. This would lead to a wrong identification of a path in case of a CUIR event for example. Fix by copying the path mask from the original request to the error recovery request in case it is a path verification request. Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/s390/block/dasd_3990_erp.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 8305ab688d57..a20dc2940d2d 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2755,6 +2755,16 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) erp = dasd_3990_erp_handle_match_erp(cqr, erp); } + + /* + * For path verification work we need to stick with the path that was + * originally chosen so that the per path configuration data is + * assigned correctly. + */ + if (test_bit(DASD_CQR_VERIFY_PATH, &erp->flags) && cqr->lpm) { + erp->lpm = cqr->lpm; + } + if (device->features & DASD_FEATURE_ERPLOG) { /* print current erp_chain */ dev_err(&device->cdev->dev, -- GitLab From fb426a4888216e9fadc75f7fc7f5a560c885aa0d Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 31 Dec 2017 15:33:14 +0200 Subject: [PATCH 0150/1834] IB/mlx4: Fix mlx4_ib_alloc_mr error flow [ Upstream commit 5a371cf87e145b86efd32007e46146e78c1eff6d ] ibmr.device is being set only after ib_alloc_mr() is successfully complete. Therefore, in case imlx4_mr_enable() returns with error, the error flow unwinder calls to mlx4_free_priv_pages(), which uses ibmr.device. Such usage causes to NULL dereference oops and to fix it, the IB device should be set in the mr struct earlier stage (e.g. prior to calling mlx4_free_priv_pages()). Fixes: 1b2cd0fc673c ("IB/mlx4: Support the new memory registration API") Signed-off-by: Nitzan Carmi Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx4/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 5d73989d9771..ae41623e0f13 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -406,7 +406,6 @@ struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd, goto err_free_mr; mr->max_pages = max_num_sg; - err = mlx4_mr_enable(dev->dev, &mr->mmr); if (err) goto err_free_pl; @@ -417,6 +416,7 @@ struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd, return &mr->ibmr; err_free_pl: + mr->ibmr.device = pd->device; mlx4_free_priv_pages(mr); err_free_mr: (void) mlx4_mr_free(dev->dev, &mr->mmr); -- GitLab From ab43aaa00d52d644957a8e1e9b89d94ee304a6c8 Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Sun, 31 Dec 2017 15:33:15 +0200 Subject: [PATCH 0151/1834] IB/ipoib: Fix race condition in neigh creation [ Upstream commit 16ba3defb8bd01a9464ba4820a487f5b196b455b ] When using enhanced mode for IPoIB, two threads may execute xmit in parallel to two different TX queues while the target is the same. In this case, both of them will add the same neighbor to the path's neigh link list and we might see the following message: list_add double add: new=ffff88024767a348, prev=ffff88024767a348... WARNING: lib/list_debug.c:31__list_add_valid+0x4e/0x70 ipoib_start_xmit+0x477/0x680 [ib_ipoib] dev_hard_start_xmit+0xb9/0x3e0 sch_direct_xmit+0xf9/0x250 __qdisc_run+0x176/0x5d0 __dev_queue_xmit+0x1f5/0xb10 __dev_queue_xmit+0x55/0xb10 Analysis: Two SKB are scheduled to be transmitted from two cores. In ipoib_start_xmit, both gets NULL when calling ipoib_neigh_get. Two calls to neigh_add_path are made. One thread takes the spin-lock and calls ipoib_neigh_alloc which creates the neigh structure, then (after the __path_find) the neigh is added to the path's neigh link list. When the second thread enters the critical section it also calls ipoib_neigh_alloc but in this case it gets the already allocated ipoib_neigh structure, which is already linked to the path's neigh link list and adds it again to the list. Which beside of triggering the list, it creates a loop in the linked list. This loop leads to endless loop inside path_rec_completion. Solution: Check list_empty(&neigh->list) before adding to the list. Add a similar fix in "ipoib_multicast.c::ipoib_mcast_send" Fixes: b63b70d87741 ('IPoIB: Use a private hash table for path lookup in xmit path') Signed-off-by: Erez Shitrit Reviewed-by: Alex Vesker Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 25 +++++++++++++------ .../infiniband/ulp/ipoib/ipoib_multicast.c | 5 +++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 183db0cd849e..e37e918cb935 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -919,8 +919,8 @@ static int path_rec_start(struct net_device *dev, return 0; } -static void neigh_add_path(struct sk_buff *skb, u8 *daddr, - struct net_device *dev) +static struct ipoib_neigh *neigh_add_path(struct sk_buff *skb, u8 *daddr, + struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path; @@ -933,7 +933,15 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, spin_unlock_irqrestore(&priv->lock, flags); ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); - return; + return NULL; + } + + /* To avoid race condition, make sure that the + * neigh will be added only once. + */ + if (unlikely(!list_empty(&neigh->list))) { + spin_unlock_irqrestore(&priv->lock, flags); + return neigh; } path = __path_find(dev, daddr + 4); @@ -971,7 +979,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, path->ah, IPOIB_QPN(daddr)); ipoib_neigh_put(neigh); - return; + return NULL; } } else { neigh->ah = NULL; @@ -988,7 +996,7 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, spin_unlock_irqrestore(&priv->lock, flags); ipoib_neigh_put(neigh); - return; + return NULL; err_path: ipoib_neigh_free(neigh); @@ -998,6 +1006,8 @@ static void neigh_add_path(struct sk_buff *skb, u8 *daddr, spin_unlock_irqrestore(&priv->lock, flags); ipoib_neigh_put(neigh); + + return NULL; } static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, @@ -1103,8 +1113,9 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) case htons(ETH_P_TIPC): neigh = ipoib_neigh_get(dev, phdr->hwaddr); if (unlikely(!neigh)) { - neigh_add_path(skb, phdr->hwaddr, dev); - return NETDEV_TX_OK; + neigh = neigh_add_path(skb, phdr->hwaddr, dev); + if (likely(!neigh)) + return NETDEV_TX_OK; } break; case htons(ETH_P_ARP): diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index fddff403d5d2..6b6826f3e446 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -818,7 +818,10 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) spin_lock_irqsave(&priv->lock, flags); if (!neigh) { neigh = ipoib_neigh_alloc(daddr, dev); - if (neigh) { + /* Make sure that the neigh will be added only + * once to mcast list. + */ + if (neigh && list_empty(&neigh->list)) { kref_get(&mcast->ah->ref); neigh->ah = mcast->ah; list_add_tail(&neigh->list, &mcast->neigh_list); -- GitLab From 799948750c137513c2976f62a7345f424245234b Mon Sep 17 00:00:00 2001 From: Aliaksei Karaliou Date: Thu, 21 Dec 2017 13:18:26 -0800 Subject: [PATCH 0152/1834] xfs: quota: fix missed destroy of qi_tree_lock [ Upstream commit 2196881566225f3c3428d1a5f847a992944daa5b ] xfs_qm_destroy_quotainfo() does not destroy quotainfo->qi_tree_lock while destroys quotainfo->qi_quotaofflock. Signed-off-by: Aliaksei Karaliou Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_qm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index 1fdd3face2d9..d0a86b72d921 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -735,6 +735,7 @@ xfs_qm_destroy_quotainfo( IRELE(qi->qi_pquotaip); qi->qi_pquotaip = NULL; } + mutex_destroy(&qi->qi_tree_lock); mutex_destroy(&qi->qi_quotaofflock); kmem_free(qi); mp->m_quotainfo = NULL; -- GitLab From c33d49420c5cdab3420a9516a04b988cb65ee9ad Mon Sep 17 00:00:00 2001 From: Aliaksei Karaliou Date: Thu, 21 Dec 2017 13:18:26 -0800 Subject: [PATCH 0153/1834] xfs: quota: check result of register_shrinker() [ Upstream commit 3a3882ff26fbdbaf5f7e13f6a0bccfbf7121041d ] xfs_qm_init_quotainfo() does not check result of register_shrinker() which was tagged as __must_check recently, reported by sparse. Signed-off-by: Aliaksei Karaliou [darrick: move xfs_qm_destroy_quotainos nearer xfs_qm_init_quotainos] Reviewed-by: Darrick J. Wong Signed-off-by: Darrick J. Wong Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/xfs/xfs_qm.c | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c index d0a86b72d921..e3edaa547216 100644 --- a/fs/xfs/xfs_qm.c +++ b/fs/xfs/xfs_qm.c @@ -47,7 +47,7 @@ STATIC int xfs_qm_init_quotainos(xfs_mount_t *); STATIC int xfs_qm_init_quotainfo(xfs_mount_t *); - +STATIC void xfs_qm_destroy_quotainos(xfs_quotainfo_t *qi); STATIC void xfs_qm_dqfree_one(struct xfs_dquot *dqp); /* * We use the batch lookup interface to iterate over the dquots as it @@ -694,9 +694,17 @@ xfs_qm_init_quotainfo( qinf->qi_shrinker.scan_objects = xfs_qm_shrink_scan; qinf->qi_shrinker.seeks = DEFAULT_SEEKS; qinf->qi_shrinker.flags = SHRINKER_NUMA_AWARE; - register_shrinker(&qinf->qi_shrinker); + + error = register_shrinker(&qinf->qi_shrinker); + if (error) + goto out_free_inos; + return 0; +out_free_inos: + mutex_destroy(&qinf->qi_quotaofflock); + mutex_destroy(&qinf->qi_tree_lock); + xfs_qm_destroy_quotainos(qinf); out_free_lru: list_lru_destroy(&qinf->qi_lru); out_free_qinf: @@ -705,7 +713,6 @@ xfs_qm_init_quotainfo( return error; } - /* * Gets called when unmounting a filesystem or when all quotas get * turned off. @@ -722,19 +729,7 @@ xfs_qm_destroy_quotainfo( unregister_shrinker(&qi->qi_shrinker); list_lru_destroy(&qi->qi_lru); - - if (qi->qi_uquotaip) { - IRELE(qi->qi_uquotaip); - qi->qi_uquotaip = NULL; /* paranoia */ - } - if (qi->qi_gquotaip) { - IRELE(qi->qi_gquotaip); - qi->qi_gquotaip = NULL; - } - if (qi->qi_pquotaip) { - IRELE(qi->qi_pquotaip); - qi->qi_pquotaip = NULL; - } + xfs_qm_destroy_quotainos(qi); mutex_destroy(&qi->qi_tree_lock); mutex_destroy(&qi->qi_quotaofflock); kmem_free(qi); @@ -1620,6 +1615,24 @@ xfs_qm_init_quotainos( return error; } +STATIC void +xfs_qm_destroy_quotainos( + xfs_quotainfo_t *qi) +{ + if (qi->qi_uquotaip) { + IRELE(qi->qi_uquotaip); + qi->qi_uquotaip = NULL; /* paranoia */ + } + if (qi->qi_gquotaip) { + IRELE(qi->qi_gquotaip); + qi->qi_gquotaip = NULL; + } + if (qi->qi_pquotaip) { + IRELE(qi->qi_pquotaip); + qi->qi_pquotaip = NULL; + } +} + STATIC void xfs_qm_dqfree_one( struct xfs_dquot *dqp) -- GitLab From 88f72bd9f99fc2315acfde7a15a1a8eecb154bcb Mon Sep 17 00:00:00 2001 From: Gao Feng Date: Tue, 26 Dec 2017 21:44:32 +0800 Subject: [PATCH 0154/1834] macvlan: Fix one possible double free [ Upstream commit d02fd6e7d2933ede6478a15f9e4ce8a93845824e ] Because the macvlan_uninit would free the macvlan port, so there is one double free case in macvlan_common_newlink. When the macvlan port is just created, then register_netdevice or netdev_upper_dev_link failed and they would invoke macvlan_uninit. Then it would reach the macvlan_port_destroy which triggers the double free. Signed-off-by: Gao Feng Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/macvlan.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 6d55049cd3dc..e8ad4d060da7 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -1377,9 +1377,14 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, return 0; unregister_netdev: + /* macvlan_uninit would free the macvlan port */ unregister_netdevice(dev); + return err; destroy_macvlan_port: - if (create) + /* the macvlan port may be freed by macvlan_uninit when fail to register. + * so we destroy the macvlan port only when it's valid. + */ + if (create && macvlan_port_get_rtnl(dev)) macvlan_port_destroy(port->dev); return err; } -- GitLab From 125ca9316b2bdc4c6a1b07751211e1b56683ad89 Mon Sep 17 00:00:00 2001 From: Tushar Dave Date: Wed, 6 Dec 2017 02:26:29 +0530 Subject: [PATCH 0155/1834] e1000: fix disabling already-disabled warning [ Upstream commit 0b76aae741abb9d16d2c0e67f8b1e766576f897d ] This patch adds check so that driver does not disable already disabled device. [ 44.637743] advantechwdt: Unexpected close, not stopping watchdog! [ 44.997548] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input6 [ 45.013419] e1000 0000:00:03.0: disabling already-disabled device [ 45.013447] ------------[ cut here ]------------ [ 45.014868] WARNING: CPU: 1 PID: 71 at drivers/pci/pci.c:1641 pci_disable_device+0xa1/0x105: pci_disable_device at drivers/pci/pci.c:1640 [ 45.016171] CPU: 1 PID: 71 Comm: rcu_perf_shutdo Not tainted 4.14.0-01330-g3c07399 #1 [ 45.017197] task: ffff88011bee9e40 task.stack: ffffc90000860000 [ 45.017987] RIP: 0010:pci_disable_device+0xa1/0x105: pci_disable_device at drivers/pci/pci.c:1640 [ 45.018603] RSP: 0000:ffffc90000863e30 EFLAGS: 00010286 [ 45.019282] RAX: 0000000000000035 RBX: ffff88013a230008 RCX: 0000000000000000 [ 45.020182] RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000203 [ 45.021084] RBP: ffff88013a3f31e8 R08: 0000000000000001 R09: 0000000000000000 [ 45.021986] R10: ffffffff827ec29c R11: 0000000000000002 R12: 0000000000000001 [ 45.022946] R13: ffff88013a230008 R14: ffff880117802b20 R15: ffffc90000863e8f [ 45.023842] FS: 0000000000000000(0000) GS:ffff88013fd00000(0000) knlGS:0000000000000000 [ 45.024863] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 45.025583] CR2: ffffc900006d4000 CR3: 000000000220f000 CR4: 00000000000006a0 [ 45.026478] Call Trace: [ 45.026811] __e1000_shutdown+0x1d4/0x1e2: __e1000_shutdown at drivers/net/ethernet/intel/e1000/e1000_main.c:5162 [ 45.027344] ? rcu_perf_cleanup+0x2a1/0x2a1: rcu_perf_shutdown at kernel/rcu/rcuperf.c:627 [ 45.027883] e1000_shutdown+0x14/0x3a: e1000_shutdown at drivers/net/ethernet/intel/e1000/e1000_main.c:5235 [ 45.028351] device_shutdown+0x110/0x1aa: device_shutdown at drivers/base/core.c:2807 [ 45.028858] kernel_power_off+0x31/0x64: kernel_power_off at kernel/reboot.c:260 [ 45.029343] rcu_perf_shutdown+0x9b/0xa7: rcu_perf_shutdown at kernel/rcu/rcuperf.c:637 [ 45.029852] ? __wake_up_common_lock+0xa2/0xa2: autoremove_wake_function at kernel/sched/wait.c:376 [ 45.030414] kthread+0x126/0x12e: kthread at kernel/kthread.c:233 [ 45.030834] ? __kthread_bind_mask+0x8e/0x8e: kthread at kernel/kthread.c:190 [ 45.031399] ? ret_from_fork+0x1f/0x30: ret_from_fork at arch/x86/entry/entry_64.S:443 [ 45.031883] ? kernel_init+0xa/0xf5: kernel_init at init/main.c:997 [ 45.032325] ret_from_fork+0x1f/0x30: ret_from_fork at arch/x86/entry/entry_64.S:443 [ 45.032777] Code: 00 48 85 ed 75 07 48 8b ab a8 00 00 00 48 8d bb 98 00 00 00 e8 aa d1 11 00 48 89 ea 48 89 c6 48 c7 c7 d8 e4 0b 82 e8 55 7d da ff <0f> ff b9 01 00 00 00 31 d2 be 01 00 00 00 48 c7 c7 f0 b1 61 82 [ 45.035222] ---[ end trace c257137b1b1976ef ]--- [ 45.037838] ACPI: Preparing to enter system sleep state S5 Signed-off-by: Tushar Dave Tested-by: Fengguang Wu Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000/e1000.h | 3 ++- drivers/net/ethernet/intel/e1000/e1000_main.c | 27 +++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000/e1000.h b/drivers/net/ethernet/intel/e1000/e1000.h index d7bdea79e9fa..8fd2458060a0 100644 --- a/drivers/net/ethernet/intel/e1000/e1000.h +++ b/drivers/net/ethernet/intel/e1000/e1000.h @@ -331,7 +331,8 @@ struct e1000_adapter { enum e1000_state_t { __E1000_TESTING, __E1000_RESETTING, - __E1000_DOWN + __E1000_DOWN, + __E1000_DISABLED }; #undef pr_fmt diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index f42129d09e2c..dd112aa5cebb 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -940,7 +940,7 @@ static int e1000_init_hw_struct(struct e1000_adapter *adapter, static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; - struct e1000_adapter *adapter; + struct e1000_adapter *adapter = NULL; struct e1000_hw *hw; static int cards_found; @@ -950,6 +950,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) u16 tmp = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; int bars, need_ioport; + bool disable_dev = false; /* do not allocate ioport bars when not needed */ need_ioport = e1000_is_need_ioport(pdev); @@ -1250,11 +1251,13 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) iounmap(hw->ce4100_gbe_mdio_base_virt); iounmap(hw->hw_addr); err_ioremap: + disable_dev = !test_and_set_bit(__E1000_DISABLED, &adapter->flags); free_netdev(netdev); err_alloc_etherdev: pci_release_selected_regions(pdev, bars); err_pci_reg: - pci_disable_device(pdev); + if (!adapter || disable_dev) + pci_disable_device(pdev); return err; } @@ -1272,6 +1275,7 @@ static void e1000_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + bool disable_dev; e1000_down_and_stop(adapter); e1000_release_manageability(adapter); @@ -1290,9 +1294,11 @@ static void e1000_remove(struct pci_dev *pdev) iounmap(hw->flash_address); pci_release_selected_regions(pdev, adapter->bars); + disable_dev = !test_and_set_bit(__E1000_DISABLED, &adapter->flags); free_netdev(netdev); - pci_disable_device(pdev); + if (disable_dev) + pci_disable_device(pdev); } /** @@ -5166,7 +5172,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake) if (netif_running(netdev)) e1000_free_irq(adapter); - pci_disable_device(pdev); + if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags)) + pci_disable_device(pdev); return 0; } @@ -5210,6 +5217,10 @@ static int e1000_resume(struct pci_dev *pdev) pr_err("Cannot enable PCI device from suspend\n"); return err; } + + /* flush memory to make sure state is correct */ + smp_mb__before_atomic(); + clear_bit(__E1000_DISABLED, &adapter->flags); pci_set_master(pdev); pci_enable_wake(pdev, PCI_D3hot, 0); @@ -5284,7 +5295,9 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, if (netif_running(netdev)) e1000_down(adapter); - pci_disable_device(pdev); + + if (!test_and_set_bit(__E1000_DISABLED, &adapter->flags)) + pci_disable_device(pdev); /* Request a slot slot reset. */ return PCI_ERS_RESULT_NEED_RESET; @@ -5312,6 +5325,10 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) pr_err("Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT; } + + /* flush memory to make sure state is correct */ + smp_mb__before_atomic(); + clear_bit(__E1000_DISABLED, &adapter->flags); pci_set_master(pdev); pci_enable_wake(pdev, PCI_D3hot, 0); -- GitLab From b4b73c1224de87d677dd5dc6fae8bc9e5b4849b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZ=20Lin=20=28=E6=9E=97=E4=B8=8A=E6=99=BA=29?= Date: Fri, 29 Dec 2017 17:02:17 +0800 Subject: [PATCH 0156/1834] NET: usb: qmi_wwan: add support for YUGA CLM920-NC5 PID 0x9625 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit bd30ffc414e55194ed6149fad69a145550cb7c18 ] This patch adds support for PID 0x9625 of YUGA CLM920-NC5. YUGA CLM920-NC5 needs to enable QMI_WWAN_QUIRK_DTR before QMI operation. qmicli -d /dev/cdc-wdm0 -p --dms-get-revision [/dev/cdc-wdm0] Device revision retrieved: Revision: 'CLM920_NC5-V1 1 [Oct 23 2016 19:00:00]' Signed-off-by: SZ Lin (林上智) Acked-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 930deb332404..a30d6a6dbd95 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -805,6 +805,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x05c6, 0x9084, 4)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 0)}, {QMI_FIXED_INTF(0x05c6, 0x920d, 5)}, + {QMI_QUIRK_SET_DTR(0x05c6, 0x9625, 4)}, /* YUGA CLM920-NC5 */ {QMI_FIXED_INTF(0x0846, 0x68a2, 8)}, {QMI_FIXED_INTF(0x12d1, 0x140c, 1)}, /* Huawei E173 */ {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)}, /* Huawei E1820 */ -- GitLab From 3a26db8cf2e952016dd470d02cbf2fa7f886ff29 Mon Sep 17 00:00:00 2001 From: Xiongwei Song Date: Tue, 2 Jan 2018 21:24:55 +0800 Subject: [PATCH 0157/1834] drm/ttm: check the return value of kzalloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 19d859a7205bc59ffc38303eb25ae394f61d21dc ] In the function ttm_page_alloc_init, kzalloc call is made for variable _manager, we need to check its return value, it may return NULL. Signed-off-by: Xiongwei Song Reviewed-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ttm/ttm_page_alloc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c index ddd6badd0eee..c756b2b7f5dc 100644 --- a/drivers/gpu/drm/ttm/ttm_page_alloc.c +++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c @@ -818,6 +818,8 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages) pr_info("Initializing pool allocator\n"); _manager = kzalloc(sizeof(*_manager), GFP_KERNEL); + if (!_manager) + return -ENOMEM; ttm_page_pool_init_locked(&_manager->wc_pool, GFP_HIGHUSER, "wc"); -- GitLab From 26f6873540606daf83536130714471155bcede38 Mon Sep 17 00:00:00 2001 From: Felix Janda Date: Mon, 1 Jan 2018 19:33:20 +0100 Subject: [PATCH 0158/1834] uapi libc compat: add fallback for unsupported libcs [ Upstream commit c0bace798436bca0fdc221ff61143f1376a9c3de ] libc-compat.h aims to prevent symbol collisions between uapi and libc headers for each supported libc. This requires continuous coordination between them. The goal of this commit is to improve the situation for libcs (such as musl) which are not yet supported and/or do not wish to be explicitly supported, while not affecting supported libcs. More precisely, with this commit, unsupported libcs can request the suppression of any specific uapi definition by defining the correspondings _UAPI_DEF_* macro as 0. This can fix symbol collisions for them, as long as the libc headers are included before the uapi headers. Inclusion in the other order is outside the scope of this commit. All infrastructure in order to enable this fallback for unsupported libcs is already in place, except that libc-compat.h unconditionally defines all _UAPI_DEF_* macros to 1 for all unsupported libcs so that any previous definitions are ignored. In order to fix this, this commit merely makes these definitions conditional. This commit together with the musl libc commit http://git.musl-libc.org/cgit/musl/commit/?id=04983f2272382af92eb8f8838964ff944fbb8258 fixes for example the following compiler errors when is included after musl's : ./linux/in6.h:32:8: error: redefinition of 'struct in6_addr' ./linux/in6.h:49:8: error: redefinition of 'struct sockaddr_in6' ./linux/in6.h:59:8: error: redefinition of 'struct ipv6_mreq' The comments referencing glibc are still correct, but this file is not only used for glibc any more. Signed-off-by: Felix Janda Reviewed-by: Hauke Mehrtens Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/libc-compat.h | 55 +++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/libc-compat.h b/include/uapi/linux/libc-compat.h index 44b8a6bd5fe1..774cb2db1b89 100644 --- a/include/uapi/linux/libc-compat.h +++ b/include/uapi/linux/libc-compat.h @@ -167,46 +167,99 @@ /* If we did not see any headers from any supported C libraries, * or we are being included in the kernel, then define everything - * that we need. */ + * that we need. Check for previous __UAPI_* definitions to give + * unsupported C libraries a way to opt out of any kernel definition. */ #else /* !defined(__GLIBC__) */ /* Definitions for if.h */ +#ifndef __UAPI_DEF_IF_IFCONF #define __UAPI_DEF_IF_IFCONF 1 +#endif +#ifndef __UAPI_DEF_IF_IFMAP #define __UAPI_DEF_IF_IFMAP 1 +#endif +#ifndef __UAPI_DEF_IF_IFNAMSIZ #define __UAPI_DEF_IF_IFNAMSIZ 1 +#endif +#ifndef __UAPI_DEF_IF_IFREQ #define __UAPI_DEF_IF_IFREQ 1 +#endif /* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS #define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +#endif /* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO #define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 +#endif /* Definitions for in.h */ +#ifndef __UAPI_DEF_IN_ADDR #define __UAPI_DEF_IN_ADDR 1 +#endif +#ifndef __UAPI_DEF_IN_IPPROTO #define __UAPI_DEF_IN_IPPROTO 1 +#endif +#ifndef __UAPI_DEF_IN_PKTINFO #define __UAPI_DEF_IN_PKTINFO 1 +#endif +#ifndef __UAPI_DEF_IP_MREQ #define __UAPI_DEF_IP_MREQ 1 +#endif +#ifndef __UAPI_DEF_SOCKADDR_IN #define __UAPI_DEF_SOCKADDR_IN 1 +#endif +#ifndef __UAPI_DEF_IN_CLASS #define __UAPI_DEF_IN_CLASS 1 +#endif /* Definitions for in6.h */ +#ifndef __UAPI_DEF_IN6_ADDR #define __UAPI_DEF_IN6_ADDR 1 +#endif +#ifndef __UAPI_DEF_IN6_ADDR_ALT #define __UAPI_DEF_IN6_ADDR_ALT 1 +#endif +#ifndef __UAPI_DEF_SOCKADDR_IN6 #define __UAPI_DEF_SOCKADDR_IN6 1 +#endif +#ifndef __UAPI_DEF_IPV6_MREQ #define __UAPI_DEF_IPV6_MREQ 1 +#endif +#ifndef __UAPI_DEF_IPPROTO_V6 #define __UAPI_DEF_IPPROTO_V6 1 +#endif +#ifndef __UAPI_DEF_IPV6_OPTIONS #define __UAPI_DEF_IPV6_OPTIONS 1 +#endif +#ifndef __UAPI_DEF_IN6_PKTINFO #define __UAPI_DEF_IN6_PKTINFO 1 +#endif +#ifndef __UAPI_DEF_IP6_MTUINFO #define __UAPI_DEF_IP6_MTUINFO 1 +#endif /* Definitions for ipx.h */ +#ifndef __UAPI_DEF_SOCKADDR_IPX #define __UAPI_DEF_SOCKADDR_IPX 1 +#endif +#ifndef __UAPI_DEF_IPX_ROUTE_DEFINITION #define __UAPI_DEF_IPX_ROUTE_DEFINITION 1 +#endif +#ifndef __UAPI_DEF_IPX_INTERFACE_DEFINITION #define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1 +#endif +#ifndef __UAPI_DEF_IPX_CONFIG_DATA #define __UAPI_DEF_IPX_CONFIG_DATA 1 +#endif +#ifndef __UAPI_DEF_IPX_ROUTE_DEF #define __UAPI_DEF_IPX_ROUTE_DEF 1 +#endif /* Definitions for xattr.h */ +#ifndef __UAPI_DEF_XATTR #define __UAPI_DEF_XATTR 1 +#endif #endif /* __GLIBC__ */ -- GitLab From cd80cb0be131daee2f9fd7862de52fa430f01370 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Fri, 8 Dec 2017 10:55:04 -0800 Subject: [PATCH 0159/1834] i40e/i40evf: Account for frags split over multiple descriptors in check linearize [ Upstream commit 248de22e638f10bd5bfc7624a357f940f66ba137 ] The original code for __i40e_chk_linearize didn't take into account the fact that if a fragment is 16K in size or larger it has to be split over 2 descriptors and the smaller of those 2 descriptors will be on the trailing edge of the transmit. As a result we can get into situations where we didn't catch requests that could result in a Tx hang. This patch takes care of that by subtracting the length of all but the trailing edge of the stale fragment before we test for sum. By doing this we can guarantee that we have all cases covered, including the case of a fragment that spans multiple descriptors. We don't need to worry about checking the inner portions of this since 12K is the maximum aligned DMA size and that is larger than any MSS will ever be since the MTU limit for jumbos is something on the order of 9K. Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 26 ++++++++++++++++--- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 26 ++++++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index c5430394fac9..28b640fa2e35 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2670,10 +2670,30 @@ bool __i40e_chk_linearize(struct sk_buff *skb) /* Walk through fragments adding latest fragment, testing it, and * then removing stale fragments from the sum. */ - stale = &skb_shinfo(skb)->frags[0]; - for (;;) { + for (stale = &skb_shinfo(skb)->frags[0];; stale++) { + int stale_size = skb_frag_size(stale); + sum += skb_frag_size(frag++); + /* The stale fragment may present us with a smaller + * descriptor than the actual fragment size. To account + * for that we need to remove all the data on the front and + * figure out what the remainder would be in the last + * descriptor associated with the fragment. + */ + if (stale_size > I40E_MAX_DATA_PER_TXD) { + int align_pad = -(stale->page_offset) & + (I40E_MAX_READ_REQ_SIZE - 1); + + sum -= align_pad; + stale_size -= align_pad; + + do { + sum -= I40E_MAX_DATA_PER_TXD_ALIGNED; + stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED; + } while (stale_size > I40E_MAX_DATA_PER_TXD); + } + /* if sum is negative we failed to make sufficient progress */ if (sum < 0) return true; @@ -2681,7 +2701,7 @@ bool __i40e_chk_linearize(struct sk_buff *skb) if (!nr_frags--) break; - sum -= skb_frag_size(stale++); + sum -= stale_size; } return false; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index c03800d1000a..90ebc5ac16fd 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1872,10 +1872,30 @@ bool __i40evf_chk_linearize(struct sk_buff *skb) /* Walk through fragments adding latest fragment, testing it, and * then removing stale fragments from the sum. */ - stale = &skb_shinfo(skb)->frags[0]; - for (;;) { + for (stale = &skb_shinfo(skb)->frags[0];; stale++) { + int stale_size = skb_frag_size(stale); + sum += skb_frag_size(frag++); + /* The stale fragment may present us with a smaller + * descriptor than the actual fragment size. To account + * for that we need to remove all the data on the front and + * figure out what the remainder would be in the last + * descriptor associated with the fragment. + */ + if (stale_size > I40E_MAX_DATA_PER_TXD) { + int align_pad = -(stale->page_offset) & + (I40E_MAX_READ_REQ_SIZE - 1); + + sum -= align_pad; + stale_size -= align_pad; + + do { + sum -= I40E_MAX_DATA_PER_TXD_ALIGNED; + stale_size -= I40E_MAX_DATA_PER_TXD_ALIGNED; + } while (stale_size > I40E_MAX_DATA_PER_TXD); + } + /* if sum is negative we failed to make sufficient progress */ if (sum < 0) return true; @@ -1883,7 +1903,7 @@ bool __i40evf_chk_linearize(struct sk_buff *skb) if (!nr_frags--) break; - sum -= skb_frag_size(stale++); + sum -= stale_size; } return false; -- GitLab From 4ec2b1ca93d8cd1b1ea7cc6fd4eb5c5a362e127e Mon Sep 17 00:00:00 2001 From: Hao Chen Date: Wed, 3 Jan 2018 11:00:31 +0800 Subject: [PATCH 0160/1834] nl80211: Check for the required netlink attribute presence [ Upstream commit 3ea15452ee85754f70f3b9fa1f23165ef2e77ba7 ] nl80211_nan_add_func() does not check if the required attribute NL80211_NAN_FUNC_FOLLOW_UP_DEST is present when processing NL80211_CMD_ADD_NAN_FUNCTION request. This request can be issued by users with CAP_NET_ADMIN privilege and may result in NULL dereference and a system crash. Add a check for the required attribute presence. Signed-off-by: Hao Chen Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 91722e97cdd5..a89061d59c74 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -10777,7 +10777,8 @@ static int nl80211_nan_add_func(struct sk_buff *skb, break; case NL80211_NAN_FUNC_FOLLOW_UP: if (!tb[NL80211_NAN_FUNC_FOLLOW_UP_ID] || - !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID]) { + !tb[NL80211_NAN_FUNC_FOLLOW_UP_REQ_ID] || + !tb[NL80211_NAN_FUNC_FOLLOW_UP_DEST]) { err = -EINVAL; goto out; } -- GitLab From 58c4ee842b30b7d6feac4c098949a11f42706579 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 Jan 2018 15:51:53 +0100 Subject: [PATCH 0161/1834] mac80211: mesh: drop frames appearing to be from us [ Upstream commit 736a80bbfda709fb3631f5f62056f250a38e5804 ] If there are multiple mesh stations with the same MAC address, they will both get confused and start throwing warnings. Obviously in this case nothing can actually work anyway, so just drop frames that look like they're from ourselves early on. Reported-by: Gui Iribarren Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 439e597fd374..404284a14d75 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -3611,6 +3611,8 @@ static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx) } return true; case NL80211_IFTYPE_MESH_POINT: + if (ether_addr_equal(sdata->vif.addr, hdr->addr2)) + return false; if (multicast) return true; return ether_addr_equal(sdata->vif.addr, hdr->addr1); -- GitLab From 9137deb6cf4829194c9a01b272a17ff3fd1ddfe8 Mon Sep 17 00:00:00 2001 From: Luu An Phu Date: Tue, 2 Jan 2018 10:44:18 +0700 Subject: [PATCH 0162/1834] can: flex_can: Correct the checking for frame length in flexcan_start_xmit() [ Upstream commit 13454c14550065fcc1705d6bd4ee6d40e057099f ] The flexcan_start_xmit() function compares the frame length with data register length to write frame content into data[0] and data[1] register. Data register length is 4 bytes and frame maximum length is 8 bytes. Fix the check that compares frame length with 3. Because the register length is 4. Signed-off-by: Luu An Phu Reviewed-by: Oliver Hartkopp Signed-off-by: Marc Kleine-Budde Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/flexcan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 16f7cadda5c3..47f43bdecd51 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -493,7 +493,7 @@ static int flexcan_start_xmit(struct sk_buff *skb, struct net_device *dev) data = be32_to_cpup((__be32 *)&cf->data[0]); flexcan_write(data, ®s->mb[FLEXCAN_TX_BUF_ID].data[0]); } - if (cf->can_dlc > 3) { + if (cf->can_dlc > 4) { data = be32_to_cpup((__be32 *)&cf->data[4]); flexcan_write(data, ®s->mb[FLEXCAN_TX_BUF_ID].data[1]); } -- GitLab From 0fd874142d3091d3116f5015753ca4fe4c078a06 Mon Sep 17 00:00:00 2001 From: Venkat Duvvuru Date: Thu, 4 Jan 2018 18:46:55 -0500 Subject: [PATCH 0163/1834] bnxt_en: Fix the 'Invalid VF' id check in bnxt_vf_ndo_prep routine. [ Upstream commit 78f300049335ae81a5cc6b4b232481dc5e1f9d41 ] In bnxt_vf_ndo_prep (which is called by bnxt_get_vf_config ndo), there is a check for "Invalid VF id". Currently, the check is done against max_vfs. However, the user doesn't always create max_vfs. So, the check should be against the created number of VFs. The number of bnxt_vf_info structures that are allocated in bnxt_alloc_vf_resources routine is the "number of requested VFs". So, if an "invalid VF id" falls between the requested number of VFs and the max_vfs, the driver will be dereferencing an invalid pointer. Fixes: c0c050c58d84 ("bnxt_en: New Broadcom ethernet driver.") Signed-off-by: Venkat Devvuru Signed-off-by: Michael Chan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c index 60e2af8678bd..393cce3bf2fc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c @@ -68,7 +68,7 @@ static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id) netdev_err(bp->dev, "vf ndo called though sriov is disabled\n"); return -EINVAL; } - if (vf_id >= bp->pf.max_vfs) { + if (vf_id >= bp->pf.active_vfs) { netdev_err(bp->dev, "Invalid VF id %d\n", vf_id); return -EINVAL; } -- GitLab From cded2e6f1660449e34c8bd6740614ee35e6ebf23 Mon Sep 17 00:00:00 2001 From: Eduardo Otubo Date: Fri, 5 Jan 2018 09:42:16 +0100 Subject: [PATCH 0164/1834] xen-netfront: enable device after manual module load [ Upstream commit b707fda2df4070785d0fa8a278aa13944c5f51f8 ] When loading the module after unloading it, the network interface would not be enabled and thus wouldn't have a backend counterpart and unable to be used by the guest. The guest would face errors like: [root@guest ~]# ethtool -i eth0 Cannot get driver information: No such device [root@guest ~]# ifconfig eth0 eth0: error fetching interface information: Device not found This patch initializes the state of the netfront device whenever it is loaded manually, this state would communicate the netback to create its device and establish the connection between them. Signed-off-by: Eduardo Otubo Reviewed-by: Boris Ostrovsky Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 1a9dadf7b3cc..b09c81e882b4 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1345,6 +1345,7 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) netif_carrier_off(netdev); + xenbus_switch_state(dev, XenbusStateInitialising); return netdev; exit: -- GitLab From 7086ec8f0e63792ed25398d165a9f603b64e9853 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Jan 2018 09:00:09 +0100 Subject: [PATCH 0165/1834] mdio-sun4i: Fix a memory leak [ Upstream commit 56c0290202ab94a2f2780c449395d4ae8495fab4 ] If the probing of the regulator is deferred, the memory allocated by 'mdiobus_alloc_size()' will be leaking. It should be freed before the next call to 'sun4i_mdio_probe()' which will reallocate it. Fixes: 4bdcb1dd9feb ("net: Add MDIO bus driver for the Allwinner EMAC") Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mdio-sun4i.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c index 135296508a7e..6425ce04d3f9 100644 --- a/drivers/net/phy/mdio-sun4i.c +++ b/drivers/net/phy/mdio-sun4i.c @@ -118,8 +118,10 @@ static int sun4i_mdio_probe(struct platform_device *pdev) data->regulator = devm_regulator_get(&pdev->dev, "phy"); if (IS_ERR(data->regulator)) { - if (PTR_ERR(data->regulator) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(data->regulator) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_out_free_mdiobus; + } dev_info(&pdev->dev, "no regulator found\n"); data->regulator = NULL; -- GitLab From 1bb81106a113b202e843ffb7d572033eb36cfe01 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 6 Jan 2018 21:53:26 +0300 Subject: [PATCH 0166/1834] SolutionEngine771x: fix Ether platform data [ Upstream commit 195e2addbce09e5afbc766efc1e6567c9ce840d3 ] The 'sh_eth' driver's probe() method would fail on the SolutionEngine7710 board and crash on SolutionEngine7712 board as the platform code is hopelessly behind the driver's platform data -- it passes the PHY address instead of 'struct sh_eth_plat_data *'; pass the latter to the driver in order to fix the bug... Fixes: 71557a37adb5 ("[netdrvr] sh_eth: Add SH7619 support") Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/sh/boards/mach-se/770x/setup.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/sh/boards/mach-se/770x/setup.c b/arch/sh/boards/mach-se/770x/setup.c index 658326f44df8..5e0267624d8d 100644 --- a/arch/sh/boards/mach-se/770x/setup.c +++ b/arch/sh/boards/mach-se/770x/setup.c @@ -8,6 +8,7 @@ */ #include #include +#include #include #include #include @@ -114,6 +115,11 @@ static struct platform_device heartbeat_device = { #if defined(CONFIG_CPU_SUBTYPE_SH7710) ||\ defined(CONFIG_CPU_SUBTYPE_SH7712) /* SH771X Ethernet driver */ +static struct sh_eth_plat_data sh_eth_plat = { + .phy = PHY_ID, + .phy_interface = PHY_INTERFACE_MODE_MII, +}; + static struct resource sh_eth0_resources[] = { [0] = { .start = SH_ETH0_BASE, @@ -131,7 +137,7 @@ static struct platform_device sh_eth0_device = { .name = "sh771x-ether", .id = 0, .dev = { - .platform_data = PHY_ID, + .platform_data = &sh_eth_plat, }, .num_resources = ARRAY_SIZE(sh_eth0_resources), .resource = sh_eth0_resources, @@ -154,7 +160,7 @@ static struct platform_device sh_eth1_device = { .name = "sh771x-ether", .id = 1, .dev = { - .platform_data = PHY_ID, + .platform_data = &sh_eth_plat, }, .num_resources = ARRAY_SIZE(sh_eth1_resources), .resource = sh_eth1_resources, -- GitLab From beaa7d1cea2debe0882c51639d463d3eb987804a Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 9 Jan 2018 12:10:21 +0000 Subject: [PATCH 0167/1834] xen/gntdev: Fix off-by-one error when unmapping with holes [ Upstream commit 951a010233625b77cde3430b4b8785a9a22968d1 ] If the requested range has a hole, the calculation of the number of pages to unmap is off by one. Fix it. Signed-off-by: Ross Lagerwall Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/xen/gntdev.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 79b8ab4c6663..54c4c4183fbe 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -378,10 +378,8 @@ static int unmap_grant_pages(struct grant_map *map, int offset, int pages) } range = 0; while (range < pages) { - if (map->unmap_ops[offset+range].handle == -1) { - range--; + if (map->unmap_ops[offset+range].handle == -1) break; - } range++; } err = __unmap_grant_pages(map, offset, range); -- GitLab From c65c0dfb27914e141be8193d509fcd4e6387d13c Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Tue, 9 Jan 2018 12:10:22 +0000 Subject: [PATCH 0168/1834] xen/gntdev: Fix partial gntdev_mmap() cleanup [ Upstream commit cf2acf66ad43abb39735568f55e1f85f9844e990 ] When cleaning up after a partially successful gntdev_mmap(), unmap the successfully mapped grant pages otherwise Xen will kill the domain if in debug mode (Attempt to implicitly unmap a granted PTE) or Linux will kill the process and emit "BUG: Bad page map in process" if Xen is in release mode. This is only needed when use_ptemod is true because gntdev_put_map() will unmap grant pages itself when use_ptemod is false. Signed-off-by: Ross Lagerwall Reviewed-by: Boris Ostrovsky Signed-off-by: Boris Ostrovsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/xen/gntdev.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 54c4c4183fbe..910b5d40c6e9 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -1077,8 +1077,10 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma) out_unlock_put: mutex_unlock(&priv->lock); out_put_map: - if (use_ptemod) + if (use_ptemod) { map->vma = NULL; + unmap_grant_pages(map, 0, map->count); + } gntdev_put_map(priv, map); return err; } -- GitLab From b923c86a7c6b63c0bdb410c667038e906a6c3e24 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Mon, 8 Jan 2018 19:02:29 -0200 Subject: [PATCH 0169/1834] sctp: make use of pre-calculated len [ Upstream commit c76f97c99ae6d26d14c7f0e50e074382bfbc9f98 ] Some sockopt handling functions were calculating the length of the buffer to be written to userspace and then calculating it again when actually writing the buffer, which could lead to some write not using an up-to-date length. This patch updates such places to just make use of the len variable. Also, replace some sizeof(type) to sizeof(var). Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sctp/socket.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index fd5b9d573b38..8cdd6bbe2efa 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -4765,7 +4765,7 @@ static int sctp_getsockopt_autoclose(struct sock *sk, int len, char __user *optv len = sizeof(int); if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval, &sctp_sk(sk)->autoclose, sizeof(int))) + if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len)) return -EFAULT; return 0; } @@ -5342,6 +5342,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, err = -EFAULT; goto out; } + /* XXX: We should have accounted for sizeof(struct sctp_getaddrs) too, + * but we can't change it anymore. + */ if (put_user(bytes_copied, optlen)) err = -EFAULT; out: @@ -5778,7 +5781,7 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len, params.assoc_id = 0; } else if (len >= sizeof(struct sctp_assoc_value)) { len = sizeof(struct sctp_assoc_value); - if (copy_from_user(¶ms, optval, sizeof(params))) + if (copy_from_user(¶ms, optval, len)) return -EFAULT; } else return -EINVAL; @@ -5947,7 +5950,9 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len, if (len < sizeof(struct sctp_authkeyid)) return -EINVAL; - if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) + + len = sizeof(struct sctp_authkeyid); + if (copy_from_user(&val, optval, len)) return -EFAULT; asoc = sctp_id2assoc(sk, val.scact_assoc_id); @@ -5959,7 +5964,6 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len, else val.scact_keynumber = ep->active_key_id; - len = sizeof(struct sctp_authkeyid); if (put_user(len, optlen)) return -EFAULT; if (copy_to_user(optval, &val, len)) @@ -5985,7 +5989,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, if (len < sizeof(struct sctp_authchunks)) return -EINVAL; - if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) + if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; to = p->gauth_chunks; @@ -6030,7 +6034,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, if (len < sizeof(struct sctp_authchunks)) return -EINVAL; - if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) + if (copy_from_user(&val, optval, sizeof(val))) return -EFAULT; to = p->gauth_chunks; -- GitLab From 3eb222174ee8b6280e552f71ed68f890bbbdc437 Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 9 Jan 2018 11:02:33 +0800 Subject: [PATCH 0170/1834] net: gianfar_ptp: move set_fipers() to spinlock protecting area [ Upstream commit 11d827a993a969c3c6ec56758ff63a44ba19b466 ] set_fipers() calling should be protected by spinlock in case that any interrupt breaks related registers setting and the function we expect. This patch is to move set_fipers() to spinlock protecting area in ptp_gianfar_adjtime(). Signed-off-by: Yangbo Lu Acked-by: Richard Cochran Reviewed-by: Fabio Estevam Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/gianfar_ptp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index 57798814160d..ec4b6997f24a 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -314,11 +314,10 @@ static int ptp_gianfar_adjtime(struct ptp_clock_info *ptp, s64 delta) now = tmr_cnt_read(etsects); now += delta; tmr_cnt_write(etsects, now); + set_fipers(etsects); spin_unlock_irqrestore(&etsects->lock, flags); - set_fipers(etsects); - return 0; } -- GitLab From 25039c139fdefd660b3a8ecfd001919fc3ced92d Mon Sep 17 00:00:00 2001 From: Punit Agrawal Date: Wed, 28 Feb 2018 16:40:09 +0000 Subject: [PATCH 0171/1834] KVM: arm/arm64: Fix check for hugepage size when allocating at Stage 2 Commit 45ee9d5e97a4 ("KVM: arm/arm64: Check pagesize when allocating a hugepage at Stage 2") lost the check for PMD_SIZE during the backport to 4.9. Fix this by correcting the condition to detect hugepages during stage 2 allocation. Fixes: 45ee9d5e97a4 ("KVM: arm/arm64: Check pagesize when allocating a hugepage at Stage 2") Reported-by: Ioana Ciornei Signed-off-by: Punit Agrawal Cc: Marc Zyngier Cc: Christoffer Dall Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 2a35c1963f6d..7f868d9bb5ed 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c @@ -1284,7 +1284,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, return -EFAULT; } - if (vma_kernel_pagesize(vma) && !logging_active) { + if (vma_kernel_pagesize(vma) == PMD_SIZE && !logging_active) { hugetlb = true; gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT; } else { -- GitLab From b5075ee58c788c14697993e21af9ef87a524e0e7 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 7 Dec 2017 07:20:46 +0000 Subject: [PATCH 0172/1834] MIPS: Implement __multi3 for GCC7 MIPS64r6 builds commit ebabcf17bcd7ce968b1631ebe08236275698f39b upstream. GCC7 is a bit too eager to generate suboptimal __multi3 calls (128bit multiply with 128bit result) for MIPS64r6 builds, even in code which doesn't explicitly use 128bit types, such as the following: unsigned long func(unsigned long a, unsigned long b) { return a > (~0UL) / b; } Which GCC rearanges to: return (unsigned __int128)a * (unsigned __int128)b > 0xffffffffffffffff; Therefore implement __multi3, but only for MIPS64r6 with GCC7 as under normal circumstances we wouldn't expect any calls to __multi3 to be generated from kernel code. Reported-by: Thomas Petazzoni Signed-off-by: James Hogan Tested-by: Waldemar Brodkorb Cc: Ralf Baechle Cc: Maciej W. Rozycki Cc: Matthew Fortune Cc: Florian Fainelli Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/17890/ Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- arch/mips/lib/Makefile | 3 ++- arch/mips/lib/libgcc.h | 17 +++++++++++++ arch/mips/lib/multi3.c | 54 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 arch/mips/lib/multi3.c diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 0344e575f522..fba4ca56e46a 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -15,4 +15,5 @@ obj-$(CONFIG_CPU_R3000) += r3k_dump_tlb.o obj-$(CONFIG_CPU_TX39XX) += r3k_dump_tlb.o # libgcc-style stuff needed in the kernel -obj-y += ashldi3.o ashrdi3.o bswapsi.o bswapdi.o cmpdi2.o lshrdi3.o ucmpdi2.o +obj-y += ashldi3.o ashrdi3.o bswapsi.o bswapdi.o cmpdi2.o lshrdi3.o multi3.o \ + ucmpdi2.o diff --git a/arch/mips/lib/libgcc.h b/arch/mips/lib/libgcc.h index 05909d58e2fe..56ea0df60a44 100644 --- a/arch/mips/lib/libgcc.h +++ b/arch/mips/lib/libgcc.h @@ -9,10 +9,18 @@ typedef int word_type __attribute__ ((mode (__word__))); struct DWstruct { int high, low; }; + +struct TWstruct { + long long high, low; +}; #elif defined(__LITTLE_ENDIAN) struct DWstruct { int low, high; }; + +struct TWstruct { + long long low, high; +}; #else #error I feel sick. #endif @@ -22,4 +30,13 @@ typedef union { long long ll; } DWunion; +#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) +typedef int ti_type __attribute__((mode(TI))); + +typedef union { + struct TWstruct s; + ti_type ti; +} TWunion; +#endif + #endif /* __ASM_LIBGCC_H */ diff --git a/arch/mips/lib/multi3.c b/arch/mips/lib/multi3.c new file mode 100644 index 000000000000..111ad475aa0c --- /dev/null +++ b/arch/mips/lib/multi3.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 +#include + +#include "libgcc.h" + +/* + * GCC 7 suboptimally generates __multi3 calls for mips64r6, so for that + * specific case only we'll implement it here. + * + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82981 + */ +#if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ == 7) + +/* multiply 64-bit values, low 64-bits returned */ +static inline long long notrace dmulu(long long a, long long b) +{ + long long res; + + asm ("dmulu %0,%1,%2" : "=r" (res) : "r" (a), "r" (b)); + return res; +} + +/* multiply 64-bit unsigned values, high 64-bits of 128-bit result returned */ +static inline long long notrace dmuhu(long long a, long long b) +{ + long long res; + + asm ("dmuhu %0,%1,%2" : "=r" (res) : "r" (a), "r" (b)); + return res; +} + +/* multiply 128-bit values, low 128-bits returned */ +ti_type notrace __multi3(ti_type a, ti_type b) +{ + TWunion res, aa, bb; + + aa.ti = a; + bb.ti = b; + + /* + * a * b = (a.lo * b.lo) + * + 2^64 * (a.hi * b.lo + a.lo * b.hi) + * [+ 2^128 * (a.hi * b.hi)] + */ + res.s.low = dmulu(aa.s.low, bb.s.low); + res.s.high = dmuhu(aa.s.low, bb.s.low); + res.s.high += dmulu(aa.s.high, bb.s.low); + res.s.high += dmulu(aa.s.low, bb.s.high); + + return res.ti; +} +EXPORT_SYMBOL(__multi3); + +#endif /* 64BIT && CPU_MIPSR6 && GCC7 */ -- GitLab From 6a83eb2354543e3263b880eb822c4b0993a2236b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 3 Mar 2018 10:23:29 +0100 Subject: [PATCH 0173/1834] Linux 4.9.86 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 77deaa395d69..e918d25e95bb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 85 +SUBLEVEL = 86 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From d3a2afb9382e8237ba4e3580779b3e457e070233 Mon Sep 17 00:00:00 2001 From: Todd Kjos Date: Wed, 7 Feb 2018 12:38:47 -0800 Subject: [PATCH 0174/1834] UPSTREAM: ANDROID: binder: remove WARN() for redundant txn error binder_send_failed_reply() is called when a synchronous transaction fails. It reports an error to the thread that is waiting for the completion. Given that the transaction is synchronous, there should never be more than 1 error response to that thread -- this was being asserted with a WARN(). However, when exercising the driver with syzbot tests, cases were observed where multiple "synchronous" requests were sent without waiting for responses, so it is possible that multiple errors would be reported to the thread. This testing was conducted with panic_on_warn set which forced the crash. This is easily reproduced by sending back-to-back "synchronous" transactions without checking for any response (eg, set read_size to 0): bwr.write_buffer = (uintptr_t)&bc1; bwr.write_size = sizeof(bc1); bwr.read_buffer = (uintptr_t)&br; bwr.read_size = 0; ioctl(fd, BINDER_WRITE_READ, &bwr); sleep(1); bwr2.write_buffer = (uintptr_t)&bc2; bwr2.write_size = sizeof(bc2); bwr2.read_buffer = (uintptr_t)&br; bwr2.read_size = 0; ioctl(fd, BINDER_WRITE_READ, &bwr2); sleep(1); The first transaction is sent to the servicemanager and the reply fails because no VMA is set up by this client. After binder_send_failed_reply() is called, the BINDER_WORK_RETURN_ERROR is sitting on the thread's todo list since the read_size was 0 and the client is not waiting for a response. The 2nd transaction is sent and the BINDER_WORK_RETURN_ERROR has not been consumed, so the thread's reply_error.cmd is still set (normally cleared when the BINDER_WORK_RETURN_ERROR is handled). Therefore when the servicemanager attempts to reply to the 2nd failed transaction, the error is already set and it triggers this warning. This is a user error since it is not waiting for the synchronous transaction to complete. If it ever does check, it will see an error. Changed the WARN() to a pr_warn(). Signed-off-by: Todd Kjos Reported-by: syzbot Cc: stable Signed-off-by: Greg Kroah-Hartman (cherry picked from commit e46a3b3ba7509cb7fda0e07bc7c63a2cd90f579b) Change-Id: I3365b0775ceee37bdb1d868e3ce066c260aa88ea --- drivers/android/binder.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index dcd32521d50d..e7e4560e4c6e 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2147,8 +2147,14 @@ static void binder_send_failed_reply(struct binder_transaction *t, &target_thread->reply_error.work); wake_up_interruptible(&target_thread->wait); } else { - WARN(1, "Unexpected reply error: %u\n", - target_thread->reply_error.cmd); + /* + * Cannot get here for normal operation, but + * we can if multiple synchronous transactions + * are sent without blocking for responses. + * Just ignore the 2nd error in this case. + */ + pr_warn("Unexpected reply error: %u\n", + target_thread->reply_error.cmd); } binder_inner_proc_unlock(target_thread->proc); binder_thread_dec_tmpref(target_thread); -- GitLab From 00db063b0f882f1282dbad53faa6a5838041ac3d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 19 Jan 2018 16:24:08 +0100 Subject: [PATCH 0175/1834] FROMLIST: ARM: amba: Don't read past the end of sysfs "driver_override" buffer When printing the driver_override parameter when it is 4095 and 4094 bytes long, the printing code would access invalid memory because we need count + 1 bytes for printing. Cfr. commits 4efe874aace57dba ("PCI: Don't read past the end of sysfs "driver_override" buffer") and bf563b01c2895a4b ("driver core: platform: Don't read past the end of "driver_override" buffer"). Fixes: 3cf385713460eb2b ("ARM: 8256/1: driver coamba: add device binding path 'driver_override'") Signed-off-by: Geert Uytterhoeven (cherry picked from: https://patchwork.kernel.org/patch/10175611/) Signed-off-by: Todd Kjos Change-Id: I7a9fffc8e3cc775fcf693edae7b42d57c0a375c5 --- drivers/amba/bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index a56fa2a1e9aa..7394aac91d9e 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -83,7 +83,8 @@ static ssize_t driver_override_store(struct device *_dev, struct amba_device *dev = to_amba_device(_dev); char *driver_override, *old = dev->driver_override, *cp; - if (count > PATH_MAX) + /* We need to keep extra room for a newline */ + if (count >= (PAGE_SIZE - 1)) return -EINVAL; driver_override = kstrndup(buf, count, GFP_KERNEL); -- GitLab From a2ee4e794559cf2ba17dd19117d18787e7c2838d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Fri, 23 Feb 2018 09:53:22 +0530 Subject: [PATCH 0176/1834] trace/sched: Fix compilation for 32 bit systems do_div() expects the dividend to be a 64 bit type. We are passing an unsigned long to do_div() from sched_load_avg_task and sched_load_avg_cpu trace points. This breaks compilation on a 32 bit system. Change-Id: I9eb07dba1e62b68d5fc8d12e3f478b22c4ba5e0d Signed-off-by: Pavankumar Kondeti --- include/trace/events/sched.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index 212c5dbb8d56..f5780473a5c1 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -636,7 +636,7 @@ TRACE_EVENT(sched_load_avg_task, __field( unsigned long, load_avg ) __field( unsigned long, util_avg ) __field( unsigned long, util_avg_pelt ) - __field( unsigned long, util_avg_walt ) + __field( u32, util_avg_walt ) __field( u64, load_sum ) __field( u32, util_sum ) __field( u32, period_contrib ) @@ -654,14 +654,14 @@ TRACE_EVENT(sched_load_avg_task, __entry->util_avg_pelt = avg->util_avg; __entry->util_avg_walt = 0; #ifdef CONFIG_SCHED_WALT - __entry->util_avg_walt = (((unsigned long)((struct ravg*)_ravg)->demand) << SCHED_CAPACITY_SHIFT); - do_div(__entry->util_avg_walt, walt_ravg_window); + __entry->util_avg_walt = ((struct ravg*)_ravg)->demand / + (walt_ravg_window >> SCHED_CAPACITY_SHIFT); if (!walt_disabled && sysctl_sched_use_walt_task_util) __entry->util_avg = __entry->util_avg_walt; #endif ), TP_printk("comm=%s pid=%d cpu=%d load_avg=%lu util_avg=%lu " - "util_avg_pelt=%lu util_avg_walt=%lu load_sum=%llu" + "util_avg_pelt=%lu util_avg_walt=%u load_sum=%llu" " util_sum=%u period_contrib=%u", __entry->comm, __entry->pid, @@ -689,7 +689,7 @@ TRACE_EVENT(sched_load_avg_cpu, __field( unsigned long, load_avg ) __field( unsigned long, util_avg ) __field( unsigned long, util_avg_pelt ) - __field( unsigned long, util_avg_walt ) + __field( u32, util_avg_walt ) ), TP_fast_assign( @@ -699,16 +699,15 @@ TRACE_EVENT(sched_load_avg_cpu, __entry->util_avg_pelt = cfs_rq->avg.util_avg; __entry->util_avg_walt = 0; #ifdef CONFIG_SCHED_WALT - __entry->util_avg_walt = - cpu_rq(cpu)->prev_runnable_sum << SCHED_CAPACITY_SHIFT; - do_div(__entry->util_avg_walt, walt_ravg_window); + __entry->util_avg_walt = div64_ul(cpu_rq(cpu)->prev_runnable_sum, + walt_ravg_window >> SCHED_CAPACITY_SHIFT); if (!walt_disabled && sysctl_sched_use_walt_cpu_util) __entry->util_avg = __entry->util_avg_walt; #endif ), TP_printk("cpu=%d load_avg=%lu util_avg=%lu " - "util_avg_pelt=%lu util_avg_walt=%lu", + "util_avg_pelt=%lu util_avg_walt=%u", __entry->cpu, __entry->load_avg, __entry->util_avg, __entry->util_avg_pelt, __entry->util_avg_walt) ); -- GitLab From 9be164624e90d1d1b03200c7a749d9c72ad26f23 Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:29:09 -0800 Subject: [PATCH 0177/1834] tpm: st33zp24: fix potential buffer overruns caused by bit glitches on the bus commit 6d24cd186d9fead3722108dec1b1c993354645ff upstream. Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/st33zp24/st33zp24.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 6f060c76217b..7205e6da16cd 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -458,7 +458,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, size_t count) { int size = 0; - int expected; + u32 expected; if (!chip) return -EBUSY; @@ -475,7 +475,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, } expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if (expected > count) { + if (expected > count || expected < TPM_HEADER_SIZE) { size = -EIO; goto out; } -- GitLab From e785c9e50fd7da8a547a968add753bac49054789 Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:30:01 -0800 Subject: [PATCH 0178/1834] tpm_i2c_infineon: fix potential buffer overruns caused by bit glitches on the bus commit 9b8cb28d7c62568a5916bdd7ea1c9176d7f8f2ed upstream. Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm_i2c_infineon.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index 62ee44e57ddc..da69ddea56cf 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -437,7 +437,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; - int expected, status; + int status; + u32 expected; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -452,7 +453,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) } expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if ((size_t) expected > count) { + if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) { size = -EIO; goto out; } -- GitLab From 15dcd3aa1542a1f00df25dd741200c720b870793 Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:31:16 -0800 Subject: [PATCH 0179/1834] tpm_i2c_nuvoton: fix potential buffer overruns caused by bit glitches on the bus commit f9d4d9b5a5ef2f017bc344fb65a58a902517173b upstream. Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm_i2c_nuvoton.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index c6428771841f..caa86b19c76d 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -281,7 +281,11 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) struct device *dev = chip->dev.parent; struct i2c_client *client = to_i2c_client(dev); s32 rc; - int expected, status, burst_count, retries, size = 0; + int status; + int burst_count; + int retries; + int size = 0; + u32 expected; if (count < TPM_HEADER_SIZE) { i2c_nuvoton_ready(chip); /* return to idle */ @@ -323,7 +327,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) * to machine native */ expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { + if (expected > count || expected < size) { dev_err(dev, "%s() expected > count\n", __func__); size = -EIO; continue; -- GitLab From 922f22e680e2ed1277b53f8e183265b71b5dfcf3 Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:32:06 -0800 Subject: [PATCH 0180/1834] tpm_tis: fix potential buffer overruns caused by bit glitches on the bus commit 6bb320ca4a4a7b5b3db8c8d7250cc40002046878 upstream. Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. In all the driver _recv() functions, we need to use a u32 to unmarshal the response size, otherwise a bit flip of the 31st bit would cause the expected variable to go negative, which would then try to read a huge amount of data. Also sanity check that the expected amount of data is large enough for the TPM header. Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Tested-by: Jarkko Sakkinen Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm_tis_core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 4d24ec3d7cd6..caf7b18895f2 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -208,7 +208,8 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int size = 0; - int expected, status; + int status; + u32 expected; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -223,7 +224,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) } expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { + if (expected > count || expected < TPM_HEADER_SIZE) { size = -EIO; goto out; } -- GitLab From e6b9e04f575faba84448eb8d67461a9acae45eae Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 7 Sep 2017 15:30:45 +0200 Subject: [PATCH 0181/1834] tpm: constify transmit data pointers commit c37fbc09bd4977736f6bc4050c6f099c587052a7 upstream. Making cmd_getticks 'const' introduced a couple of harmless warnings: drivers/char/tpm/tpm_tis_core.c: In function 'probe_itpm': drivers/char/tpm/tpm_tis_core.c:469:31: error: passing argument 2 of 'tpm_tis_send_data' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] rc = tpm_tis_send_data(chip, cmd_getticks, len); drivers/char/tpm/tpm_tis_core.c:477:31: error: passing argument 2 of 'tpm_tis_send_data' discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] rc = tpm_tis_send_data(chip, cmd_getticks, len); drivers/char/tpm/tpm_tis_core.c:255:12: note: expected 'u8 * {aka unsigned char *}' but argument is of type 'const u8 * {aka const unsigned char *}' static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) This changes the related functions to all take 'const' pointers so that gcc can see this as being correct. I had to slightly modify the logic around tpm_tis_spi_transfer() for this to work without introducing ugly casts. Cc: stable@vger.kernel.org Fixes: 5e35bd8e06b9 ("tpm_tis: make array cmd_getticks static const to shink object code size") Signed-off-by: Arnd Bergmann Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm_tis.c | 2 +- drivers/char/tpm/tpm_tis_core.c | 4 ++-- drivers/char/tpm/tpm_tis_core.h | 4 ++-- drivers/char/tpm/tpm_tis_spi.c | 25 +++++++++++-------------- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 8022bea27fed..06173d2e316f 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -98,7 +98,7 @@ static int tpm_tcg_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, } static int tpm_tcg_write_bytes(struct tpm_tis_data *data, u32 addr, u16 len, - u8 *value) + const u8 *value) { struct tpm_tis_tcg_phy *phy = to_tpm_tis_tcg_phy(data); diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index caf7b18895f2..f9aa47ec7af7 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -257,7 +257,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) * tpm.c can skip polling for the data to be available as the interrupt is * waited for here */ -static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) +static int tpm_tis_send_data(struct tpm_chip *chip, const u8 *buf, size_t len) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int rc, status, burstcnt; @@ -346,7 +346,7 @@ static void disable_interrupts(struct tpm_chip *chip) * tpm.c can skip polling for the data to be available as the interrupt is * waited for here */ -static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len) +static int tpm_tis_send_main(struct tpm_chip *chip, const u8 *buf, size_t len) { struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int rc; diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h index 9191aabbf9c2..e1c2193f2ed3 100644 --- a/drivers/char/tpm/tpm_tis_core.h +++ b/drivers/char/tpm/tpm_tis_core.h @@ -98,7 +98,7 @@ struct tpm_tis_phy_ops { int (*read_bytes)(struct tpm_tis_data *data, u32 addr, u16 len, u8 *result); int (*write_bytes)(struct tpm_tis_data *data, u32 addr, u16 len, - u8 *value); + const u8 *value); int (*read16)(struct tpm_tis_data *data, u32 addr, u16 *result); int (*read32)(struct tpm_tis_data *data, u32 addr, u32 *result); int (*write32)(struct tpm_tis_data *data, u32 addr, u32 src); @@ -128,7 +128,7 @@ static inline int tpm_tis_read32(struct tpm_tis_data *data, u32 addr, } static inline int tpm_tis_write_bytes(struct tpm_tis_data *data, u32 addr, - u16 len, u8 *value) + u16 len, const u8 *value) { return data->phy_ops->write_bytes(data, addr, len, value); } diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c index 3b97b14c3417..1a09a7491019 100644 --- a/drivers/char/tpm/tpm_tis_spi.c +++ b/drivers/char/tpm/tpm_tis_spi.c @@ -58,7 +58,7 @@ static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *da } static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, - u8 *buffer, u8 direction) + u8 *in, const u8 *out) { struct tpm_tis_spi_phy *phy = to_tpm_tis_spi_phy(data); int ret = 0; @@ -72,7 +72,7 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, while (len) { transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE); - phy->tx_buf[0] = direction | (transfer_len - 1); + phy->tx_buf[0] = (in ? 0x80 : 0) | (transfer_len - 1); phy->tx_buf[1] = 0xd4; phy->tx_buf[2] = addr >> 8; phy->tx_buf[3] = addr; @@ -113,14 +113,8 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, spi_xfer.cs_change = 0; spi_xfer.len = transfer_len; spi_xfer.delay_usecs = 5; - - if (direction) { - spi_xfer.tx_buf = NULL; - spi_xfer.rx_buf = buffer; - } else { - spi_xfer.tx_buf = buffer; - spi_xfer.rx_buf = NULL; - } + spi_xfer.tx_buf = out; + spi_xfer.rx_buf = in; spi_message_init(&m); spi_message_add_tail(&spi_xfer, &m); @@ -129,7 +123,10 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, goto exit; len -= transfer_len; - buffer += transfer_len; + if (in) + in += transfer_len; + if (out) + out += transfer_len; } exit: @@ -140,13 +137,13 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, static int tpm_tis_spi_read_bytes(struct tpm_tis_data *data, u32 addr, u16 len, u8 *result) { - return tpm_tis_spi_transfer(data, addr, len, result, 0x80); + return tpm_tis_spi_transfer(data, addr, len, result, NULL); } static int tpm_tis_spi_write_bytes(struct tpm_tis_data *data, u32 addr, - u16 len, u8 *value) + u16 len, const u8 *value) { - return tpm_tis_spi_transfer(data, addr, len, value, 0); + return tpm_tis_spi_transfer(data, addr, len, NULL, value); } static int tpm_tis_spi_read16(struct tpm_tis_data *data, u32 addr, u16 *result) -- GitLab From eb75717b1898c0ded2e1eaf0360008e31ad24c97 Mon Sep 17 00:00:00 2001 From: Alexander Steffen Date: Mon, 11 Sep 2017 12:26:52 +0200 Subject: [PATCH 0182/1834] tpm_tis_spi: Use DMA-safe memory for SPI transfers commit 6b3a13173f23e798e1ba213dd4a2c065a3b8d751 upstream. The buffers used as tx_buf/rx_buf in a SPI transfer need to be DMA-safe. This cannot be guaranteed for the buffers passed to tpm_tis_spi_read_bytes and tpm_tis_spi_write_bytes. Therefore, we need to use our own DMA-safe buffer and copy the data to/from it. The buffer needs to be allocated separately, to ensure that it is cacheline-aligned and not shared with other data, so that DMA can work correctly. Fixes: 0edbfea537d1 ("tpm/tpm_tis_spi: Add support for spi phy") Cc: stable@vger.kernel.org Reviewed-by: Jarkko Sakkinen Signed-off-by: Alexander Steffen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm_tis_spi.c | 45 ++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c index 1a09a7491019..01eccb193b5a 100644 --- a/drivers/char/tpm/tpm_tis_spi.c +++ b/drivers/char/tpm/tpm_tis_spi.c @@ -47,9 +47,7 @@ struct tpm_tis_spi_phy { struct tpm_tis_data priv; struct spi_device *spi_device; - - u8 tx_buf[4]; - u8 rx_buf[4]; + u8 *iobuf; }; static inline struct tpm_tis_spi_phy *to_tpm_tis_spi_phy(struct tpm_tis_data *data) @@ -72,14 +70,14 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, while (len) { transfer_len = min_t(u16, len, MAX_SPI_FRAMESIZE); - phy->tx_buf[0] = (in ? 0x80 : 0) | (transfer_len - 1); - phy->tx_buf[1] = 0xd4; - phy->tx_buf[2] = addr >> 8; - phy->tx_buf[3] = addr; + phy->iobuf[0] = (in ? 0x80 : 0) | (transfer_len - 1); + phy->iobuf[1] = 0xd4; + phy->iobuf[2] = addr >> 8; + phy->iobuf[3] = addr; memset(&spi_xfer, 0, sizeof(spi_xfer)); - spi_xfer.tx_buf = phy->tx_buf; - spi_xfer.rx_buf = phy->rx_buf; + spi_xfer.tx_buf = phy->iobuf; + spi_xfer.rx_buf = phy->iobuf; spi_xfer.len = 4; spi_xfer.cs_change = 1; @@ -89,9 +87,9 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, if (ret < 0) goto exit; - if ((phy->rx_buf[3] & 0x01) == 0) { + if ((phy->iobuf[3] & 0x01) == 0) { // handle SPI wait states - phy->tx_buf[0] = 0; + phy->iobuf[0] = 0; for (i = 0; i < TPM_RETRY; i++) { spi_xfer.len = 1; @@ -100,7 +98,7 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, ret = spi_sync_locked(phy->spi_device, &m); if (ret < 0) goto exit; - if (phy->rx_buf[0] & 0x01) + if (phy->iobuf[0] & 0x01) break; } @@ -113,8 +111,14 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, spi_xfer.cs_change = 0; spi_xfer.len = transfer_len; spi_xfer.delay_usecs = 5; - spi_xfer.tx_buf = out; - spi_xfer.rx_buf = in; + + if (in) { + spi_xfer.tx_buf = NULL; + } else if (out) { + spi_xfer.rx_buf = NULL; + memcpy(phy->iobuf, out, transfer_len); + out += transfer_len; + } spi_message_init(&m); spi_message_add_tail(&spi_xfer, &m); @@ -122,11 +126,12 @@ static int tpm_tis_spi_transfer(struct tpm_tis_data *data, u32 addr, u16 len, if (ret < 0) goto exit; - len -= transfer_len; - if (in) + if (in) { + memcpy(in, phy->iobuf, transfer_len); in += transfer_len; - if (out) - out += transfer_len; + } + + len -= transfer_len; } exit: @@ -192,6 +197,10 @@ static int tpm_tis_spi_probe(struct spi_device *dev) phy->spi_device = dev; + phy->iobuf = devm_kmalloc(&dev->dev, MAX_SPI_FRAMESIZE, GFP_KERNEL); + if (!phy->iobuf) + return -ENOMEM; + return tpm_tis_core_init(&dev->dev, &phy->priv, -1, &tpm_spi_phy_ops, NULL); } -- GitLab From 89f0fb9698810841c1a02fa8d4a80e2eb654daff Mon Sep 17 00:00:00 2001 From: Alexander Steffen Date: Fri, 8 Sep 2017 17:21:32 +0200 Subject: [PATCH 0183/1834] tpm-dev-common: Reject too short writes commit ee70bc1e7b63ac8023c9ff9475d8741e397316e7 upstream. tpm_transmit() does not offer an explicit interface to indicate the number of valid bytes in the communication buffer. Instead, it relies on the commandSize field in the TPM header that is encoded within the buffer. Therefore, ensure that a) enough data has been written to the buffer, so that the commandSize field is present and b) the commandSize field does not announce more data than has been written to the buffer. This should have been fixed with CVE-2011-1161 long ago, but apparently a correct version of that patch never made it into the kernel. Cc: stable@vger.kernel.org Signed-off-by: Alexander Steffen Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-dev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c index 912ad30be585..65b824954bdc 100644 --- a/drivers/char/tpm/tpm-dev.c +++ b/drivers/char/tpm/tpm-dev.c @@ -136,6 +136,12 @@ static ssize_t tpm_write(struct file *file, const char __user *buf, return -EFAULT; } + if (in_size < 6 || + in_size < be32_to_cpu(*((__be32 *) (priv->data_buffer + 2)))) { + mutex_unlock(&priv->buffer_mutex); + return -EINVAL; + } + /* atomic tpm command send and result receive. We only hold the ops * lock during this period so that the tpm can be unregistered even if * the char dev is held open. -- GitLab From 57adeebc8a664a506e44c509aef47cc9ed74eabe Mon Sep 17 00:00:00 2001 From: Erik Veijola Date: Fri, 23 Feb 2018 14:06:52 +0200 Subject: [PATCH 0184/1834] ALSA: usb-audio: Add a quirck for B&W PX headphones commit 240a8af929c7c57dcde28682725b29cf8474e8e5 upstream. The capture interface doesn't work and the playback interface only supports 48 kHz sampling rate even though it advertises more rates. Signed-off-by: Erik Veijola Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks-table.h | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 8a59d4782a0f..69bf5cf1e91e 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -3277,4 +3277,51 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), } }, +{ + /* + * Bower's & Wilkins PX headphones only support the 48 kHz sample rate + * even though it advertises more. The capture interface doesn't work + * even on windows. + */ + USB_DEVICE(0x19b5, 0x0021), + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_MIXER, + }, + /* Capture */ + { + .ifnum = 1, + .type = QUIRK_IGNORE_INTERFACE, + }, + /* Playback */ + { + .ifnum = 2, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 2, + .iface = 2, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_FILL_MAX | + UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x03, + .ep_attr = USB_ENDPOINT_XFER_ISOC, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .nr_rates = 1, + .rate_table = (unsigned int[]) { + 48000 + } + } + }, + } + } +}, + #undef USB_DEVICE_VENDOR_SPEC -- GitLab From 30f323752a59e18c485de7cd3b988764ffab4e4c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 22 Feb 2018 14:20:35 +0100 Subject: [PATCH 0185/1834] ALSA: hda: Add a power_save blacklist commit 1ba8f9d308174e647b864c36209b4d7934d99888 upstream. On some boards setting power_save to a non 0 value leads to clicking / popping sounds when ever we enter/leave powersaving mode. Ideally we would figure out how to avoid these sounds, but that is not always feasible. This commit adds a blacklist for devices where powersaving is known to cause problems and disables it on these devices. Note I tried to put this blacklist in userspace first: https://github.com/systemd/systemd/pull/8128 But the systemd maintainers rightfully pointed out that it would be impossible to then later remove entries once we actually find a way to make power-saving work on listed boards without issues. Having this list in the kernel will allow removal of the blacklist entry in the same commit which fixes the clicks / plops. The blacklist only applies to the default power_save module-option value, if a user explicitly sets the module-option then the blacklist is not used. [ added an ifdef CONFIG_PM for the build error -- tiwai] BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1525104 BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=198611 Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_intel.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 293f3f213776..ceb162a9dcfd 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -180,7 +180,7 @@ static const struct kernel_param_ops param_ops_xint = { }; #define param_check_xint param_check_int -static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +static int power_save = -1; module_param(power_save, xint, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " "(in second, 0 = disable)."); @@ -2042,6 +2042,24 @@ static int azx_probe(struct pci_dev *pci, return err; } +#ifdef CONFIG_PM +/* On some boards setting power_save to a non 0 value leads to clicking / + * popping sounds when ever we enter/leave powersaving mode. Ideally we would + * figure out how to avoid these sounds, but that is not always feasible. + * So we keep a list of devices where we disable powersaving as its known + * to causes problems on these devices. + */ +static struct snd_pci_quirk power_save_blacklist[] = { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ + SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0), + /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ + SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0), + /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */ + SND_PCI_QUIRK(0x17aa, 0x2227, "Lenovo X1 Carbon 3rd Gen", 0), + {} +}; +#endif /* CONFIG_PM */ + /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { [AZX_DRIVER_NVIDIA] = 8, @@ -2054,6 +2072,7 @@ static int azx_probe_continue(struct azx *chip) struct hdac_bus *bus = azx_bus(chip); struct pci_dev *pci = chip->pci; int dev = chip->dev_index; + int val; int err; hda->probe_continued = 1; @@ -2129,7 +2148,22 @@ static int azx_probe_continue(struct azx *chip) chip->running = 1; azx_add_card_list(chip); - snd_hda_set_power_save(&chip->bus, power_save * 1000); + + val = power_save; +#ifdef CONFIG_PM + if (val == -1) { + const struct snd_pci_quirk *q; + + val = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; + q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist); + if (q && val) { + dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n", + q->subvendor, q->subdevice); + val = 0; + } + } +#endif /* CONFIG_PM */ + snd_hda_set_power_save(&chip->bus, val * 1000); if (azx_has_pm_runtime(chip) || hda->use_vga_switcheroo) pm_runtime_put_autosuspend(&pci->dev); -- GitLab From 61963d34e92b4238d6c80632fc69bcf11b8f191c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 26 Feb 2018 15:36:38 +0100 Subject: [PATCH 0186/1834] ALSA: hda - Fix pincfg at resume on Lenovo T470 dock commit 71db96ddfa72671bd43cacdcc99ca178d90ba267 upstream. We've added a quirk to enable the recent Lenovo dock support, where it overwrites the pin configs of NID 0x17 and 19, not only updating the pin config cache. It works right after the boot, but the problem is that the pin configs are occasionally cleared when the machine goes to PM. Meanwhile the quirk writes the pin configs only at the pre-probe, so this won't be applied any longer. For addressing that issue, this patch moves the code to overwrite the pin configs into HDA_FIXUP_ACT_INIT section so that it's always applied at both probe and resume time. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195161 Fixes: 61fcf8ece9b6 ("ALSA: hda/realtek - Enable Thinkpad Dock device for ALC298 platform") Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 89c166b97e81..974b74e91ef0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4480,13 +4480,14 @@ static void alc_fixup_tpt470_dock(struct hda_codec *codec, if (action == HDA_FIXUP_ACT_PRE_PROBE) { spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; + snd_hda_apply_pincfgs(codec, pincfgs); + } else if (action == HDA_FIXUP_ACT_INIT) { /* Enable DOCK device */ snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0); /* Enable DOCK device */ snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0); - snd_hda_apply_pincfgs(codec, pincfgs); } } -- GitLab From 13e75c74cd69ca460778fad5ab902f0b20869267 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Thu, 18 Jan 2018 17:20:22 +0530 Subject: [PATCH 0187/1834] timers: Forward timer base before migrating timers commit c52232a49e203a65a6e1a670cd5262f59e9364a0 upstream. On CPU hotunplug the enqueued timers of the unplugged CPU are migrated to a live CPU. This happens from the control thread which initiated the unplug. If the CPU on which the control thread runs came out from a longer idle period then the base clock of that CPU might be stale because the control thread runs prior to any event which forwards the clock. In such a case the timers from the unplugged CPU are queued on the live CPU based on the stale clock which can cause large delays due to increased granularity of the outer timer wheels which are far away from base:;clock. But there is a worse problem than that. The following sequence of events illustrates it: - CPU0 timer1 is queued expires = 59969 and base->clk = 59131. The timer is queued at wheel level 2, with resulting expiry time = 60032 (due to level granularity). - CPU1 enters idle @60007, with next timer expiry @60020. - CPU0 is hotplugged at @60009 - CPU1 exits idle and runs the control thread which migrates the timers from CPU0 timer1 is now queued in level 0 for immediate handling in the next softirq because the requested expiry time 59969 is before CPU1 base->clk 60007 - CPU1 runs code which forwards the base clock which succeeds because the next expiring timer. which was collected at idle entry time is still set to 60020. So it forwards beyond 60007 and therefore misses to expire the migrated timer1. That timer gets expired when the wheel wraps around again, which takes between 63 and 630ms depending on the HZ setting. Address both problems by invoking forward_timer_base() for the control CPUs timer base. All other places, which might run into a similar problem (mod_timer()/add_timer_on()) already invoke forward_timer_base() to avoid that. [ tglx: Massaged comment and changelog ] Fixes: a683f390b93f ("timers: Forward the wheel clock whenever possible") Co-developed-by: Neeraj Upadhyay Signed-off-by: Neeraj Upadhyay Signed-off-by: Lingutla Chandrasekhar Signed-off-by: Thomas Gleixner Cc: Anna-Maria Gleixner Cc: linux-arm-msm@vger.kernel.org Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20180118115022.6368-1-clingutla@codeaurora.org Signed-off-by: Greg Kroah-Hartman --- kernel/time/timer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 2d5cc7dfee14..7c477912f36d 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c @@ -1884,6 +1884,12 @@ int timers_dead_cpu(unsigned int cpu) spin_lock_irq(&new_base->lock); spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); + /* + * The current CPUs base clock might be stale. Update it + * before moving the timers over. + */ + forward_timer_base(new_base); + BUG_ON(old_base->running_timer); for (i = 0; i < WHEEL_SIZE; i++) -- GitLab From 12efc9159129882bb2c24973806f3238fc2af5c9 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Tue, 27 Feb 2018 08:16:07 -0500 Subject: [PATCH 0188/1834] parisc: Fix ordering of cache and TLB flushes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0adb24e03a124b79130c9499731936b11ce2677d upstream. The change to flush_kernel_vmap_range() wasn't sufficient to avoid the SMP stalls.  The problem is some drivers call these routines with interrupts disabled.  Interrupts need to be enabled for flush_tlb_all() and flush_cache_all() to work.  This version adds checks to ensure interrupts are not disabled before calling routines that need IPI interrupts.  When interrupts are disabled, we now drop into slower code. The attached change fixes the ordering of cache and TLB flushes in several cases.  When we flush the cache using the existing PTE/TLB entries, we need to flush the TLB after doing the cache flush.  We don't need to do this when we flush the entire instruction and data caches as these flushes don't use the existing TLB entries.  The same is true for tmpalias region flushes. The flush_kernel_vmap_range() and invalidate_kernel_vmap_range() routines have been updated. Secondly, we added a new purge_kernel_dcache_range_asm() routine to pacache.S and use it in invalidate_kernel_vmap_range().  Nominally, purges are faster than flushes as the cache lines don't have to be written back to memory. Hopefully, this is sufficient to resolve the remaining problems due to cache speculation.  So far, testing indicates that this is the case.  I did work up a patch using tmpalias flushes, but there is a performance hit because we need the physical address for each page, and we also need to sequence access to the tmpalias flush code.  This increases the probability of stalls. Signed-off-by: John David Anglin  Cc: stable@vger.kernel.org # 4.9+ Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman --- arch/parisc/include/asm/cacheflush.h | 1 + arch/parisc/kernel/cache.c | 57 +++++++++++++++------------- arch/parisc/kernel/pacache.S | 22 +++++++++++ 3 files changed, 54 insertions(+), 26 deletions(-) diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h index 1d8c24dc04d4..88290d32b956 100644 --- a/arch/parisc/include/asm/cacheflush.h +++ b/arch/parisc/include/asm/cacheflush.h @@ -25,6 +25,7 @@ void flush_user_icache_range_asm(unsigned long, unsigned long); void flush_kernel_icache_range_asm(unsigned long, unsigned long); void flush_user_dcache_range_asm(unsigned long, unsigned long); void flush_kernel_dcache_range_asm(unsigned long, unsigned long); +void purge_kernel_dcache_range_asm(unsigned long, unsigned long); void flush_kernel_dcache_page_asm(void *); void flush_kernel_icache_page(void *); void flush_user_dcache_range(unsigned long, unsigned long); diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index df757c9675e6..025afe5f17a7 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -464,10 +464,10 @@ EXPORT_SYMBOL(copy_user_page); int __flush_tlb_range(unsigned long sid, unsigned long start, unsigned long end) { - unsigned long flags, size; + unsigned long flags; - size = (end - start); - if (size >= parisc_tlb_flush_threshold) { + if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && + end - start >= parisc_tlb_flush_threshold) { flush_tlb_all(); return 1; } @@ -538,13 +538,11 @@ void flush_cache_mm(struct mm_struct *mm) struct vm_area_struct *vma; pgd_t *pgd; - /* Flush the TLB to avoid speculation if coherency is required. */ - if (parisc_requires_coherency()) - flush_tlb_all(); - /* Flushing the whole cache on each cpu takes forever on rp3440, etc. So, avoid it if the mm isn't too big. */ - if (mm_total_size(mm) >= parisc_cache_flush_threshold) { + if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && + mm_total_size(mm) >= parisc_cache_flush_threshold) { + flush_tlb_all(); flush_cache_all(); return; } @@ -552,9 +550,9 @@ void flush_cache_mm(struct mm_struct *mm) if (mm->context == mfsp(3)) { for (vma = mm->mmap; vma; vma = vma->vm_next) { flush_user_dcache_range_asm(vma->vm_start, vma->vm_end); - if ((vma->vm_flags & VM_EXEC) == 0) - continue; - flush_user_icache_range_asm(vma->vm_start, vma->vm_end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm(vma->vm_start, vma->vm_end); + flush_tlb_range(vma, vma->vm_start, vma->vm_end); } return; } @@ -598,14 +596,9 @@ flush_user_icache_range(unsigned long start, unsigned long end) void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { - BUG_ON(!vma->vm_mm->context); - - /* Flush the TLB to avoid speculation if coherency is required. */ - if (parisc_requires_coherency()) + if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && + end - start >= parisc_cache_flush_threshold) { flush_tlb_range(vma, start, end); - - if ((end - start) >= parisc_cache_flush_threshold - || vma->vm_mm->context != mfsp(3)) { flush_cache_all(); return; } @@ -613,6 +606,7 @@ void flush_cache_range(struct vm_area_struct *vma, flush_user_dcache_range_asm(start, end); if (vma->vm_flags & VM_EXEC) flush_user_icache_range_asm(start, end); + flush_tlb_range(vma, start, end); } void @@ -621,8 +615,7 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long BUG_ON(!vma->vm_mm->context); if (pfn_valid(pfn)) { - if (parisc_requires_coherency()) - flush_tlb_page(vma, vmaddr); + flush_tlb_page(vma, vmaddr); __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); } } @@ -630,21 +623,33 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long void flush_kernel_vmap_range(void *vaddr, int size) { unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; - if ((unsigned long)size > parisc_cache_flush_threshold) + if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && + (unsigned long)size >= parisc_cache_flush_threshold) { + flush_tlb_kernel_range(start, end); flush_data_cache(); - else - flush_kernel_dcache_range_asm(start, start + size); + return; + } + + flush_kernel_dcache_range_asm(start, end); + flush_tlb_kernel_range(start, end); } EXPORT_SYMBOL(flush_kernel_vmap_range); void invalidate_kernel_vmap_range(void *vaddr, int size) { unsigned long start = (unsigned long)vaddr; + unsigned long end = start + size; - if ((unsigned long)size > parisc_cache_flush_threshold) + if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && + (unsigned long)size >= parisc_cache_flush_threshold) { + flush_tlb_kernel_range(start, end); flush_data_cache(); - else - flush_kernel_dcache_range_asm(start, start + size); + return; + } + + purge_kernel_dcache_range_asm(start, end); + flush_tlb_kernel_range(start, end); } EXPORT_SYMBOL(invalidate_kernel_vmap_range); diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 2d40c4ff3f69..67b0f7532e83 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -1110,6 +1110,28 @@ ENTRY_CFI(flush_kernel_dcache_range_asm) .procend ENDPROC_CFI(flush_kernel_dcache_range_asm) +ENTRY_CFI(purge_kernel_dcache_range_asm) + .proc + .callinfo NO_CALLS + .entry + + ldil L%dcache_stride, %r1 + ldw R%dcache_stride(%r1), %r23 + ldo -1(%r23), %r21 + ANDCM %r26, %r21, %r26 + +1: cmpb,COND(<<),n %r26, %r25,1b + pdc,m %r23(%r26) + + sync + syncdma + bv %r0(%r2) + nop + .exit + + .procend +ENDPROC_CFI(purge_kernel_dcache_range_asm) + ENTRY_CFI(flush_user_icache_range_asm) .proc .callinfo NO_CALLS -- GitLab From 144b6353ae503c055dd8bda0a03f42798d62aaa4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 23 Feb 2018 09:38:28 +0530 Subject: [PATCH 0189/1834] cpufreq: s3c24xx: Fix broken s3c_cpufreq_init() commit 0373ca74831b0f93cd4cdbf7ad3aec3c33a479a5 upstream. commit a307a1e6bc0d "cpufreq: s3c: use cpufreq_generic_init()" accidentally broke cpufreq on s3c2410 and s3c2412. These two platforms don't have a CPU frequency table and used to skip calling cpufreq_table_validate_and_show() for them. But with the above commit, we started calling it unconditionally and that will eventually fail as the frequency table pointer is NULL. Fix this by calling cpufreq_table_validate_and_show() conditionally again. Fixes: a307a1e6bc0d "cpufreq: s3c: use cpufreq_generic_init()" Cc: 3.13+ # v3.13+ Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/s3c24xx-cpufreq.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index 7b596fa38ad2..6bebc1f9f55a 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -351,7 +351,13 @@ struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name) static int s3c_cpufreq_init(struct cpufreq_policy *policy) { policy->clk = clk_arm; - return cpufreq_generic_init(policy, ftab, cpu_cur.info->latency); + + policy->cpuinfo.transition_latency = cpu_cur.info->latency; + + if (ftab) + return cpufreq_table_validate_and_show(policy, ftab); + + return 0; } static int __init s3c_cpufreq_initclks(void) -- GitLab From 43672fa6428ec186db18fc5fba2df8c642bc1c38 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 21 Feb 2018 17:08:01 -0800 Subject: [PATCH 0190/1834] dax: fix vma_is_fsdax() helper commit 230f5a8969d8345fc9bbe3683f068246cf1be4b8 upstream. Gerd reports that ->i_mode may contain other bits besides S_IFCHR. Use S_ISCHR() instead. Otherwise, get_user_pages_longterm() may fail on device-dax instances when those are meant to be explicitly allowed. Fixes: 2bb6d2837083 ("mm: introduce get_user_pages_longterm") Cc: Reported-by: Gerd Rausch Acked-by: Jane Chu Reported-by: Haozhong Zhang Reviewed-by: Jan Kara Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- include/linux/fs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/fs.h b/include/linux/fs.h index 745ea1b2e02c..18552189560b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3048,7 +3048,7 @@ static inline bool vma_is_fsdax(struct vm_area_struct *vma) if (!vma_is_dax(vma)) return false; inode = file_inode(vma->vm_file); - if (inode->i_mode == S_IFCHR) + if (S_ISCHR(inode->i_mode)) return false; /* device-dax */ return true; } -- GitLab From 78448491084ec7e5d2b75e3372cf1307c23f9457 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Mon, 26 Feb 2018 15:08:18 +0100 Subject: [PATCH 0191/1834] x86/xen: Zero MSR_IA32_SPEC_CTRL before suspend commit 71c208dd54ab971036d83ff6d9837bae4976e623 upstream. Older Xen versions (4.5 and before) might have problems migrating pv guests with MSR_IA32_SPEC_CTRL having a non-zero value. So before suspending zero that MSR and restore it after being resumed. Signed-off-by: Juergen Gross Signed-off-by: Thomas Gleixner Reviewed-by: Jan Beulich Cc: stable@vger.kernel.org Cc: xen-devel@lists.xenproject.org Cc: boris.ostrovsky@oracle.com Link: https://lkml.kernel.org/r/20180226140818.4849-1-jgross@suse.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/suspend.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c index 7f664c416faf..4ecd0de08557 100644 --- a/arch/x86/xen/suspend.c +++ b/arch/x86/xen/suspend.c @@ -1,11 +1,14 @@ #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -68,6 +71,8 @@ static void xen_pv_post_suspend(int suspend_cancelled) xen_mm_unpin_all(); } +static DEFINE_PER_CPU(u64, spec_ctrl); + void xen_arch_pre_suspend(void) { if (xen_pv_domain()) @@ -84,6 +89,9 @@ void xen_arch_post_suspend(int cancelled) static void xen_vcpu_notify_restore(void *data) { + if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL)) + wrmsrl(MSR_IA32_SPEC_CTRL, this_cpu_read(spec_ctrl)); + /* Boot processor notified via generic timekeeping_resume() */ if (smp_processor_id() == 0) return; @@ -93,7 +101,15 @@ static void xen_vcpu_notify_restore(void *data) static void xen_vcpu_notify_suspend(void *data) { + u64 tmp; + tick_suspend_local(); + + if (xen_pv_domain() && boot_cpu_has(X86_FEATURE_SPEC_CTRL)) { + rdmsrl(MSR_IA32_SPEC_CTRL, tmp); + this_cpu_write(spec_ctrl, tmp); + wrmsrl(MSR_IA32_SPEC_CTRL, 0); + } } void xen_arch_resume(void) -- GitLab From 0c2b4a3b5c5aaa2c34a40b0b20467af390592337 Mon Sep 17 00:00:00 2001 From: Sebastian Panceac Date: Wed, 28 Feb 2018 11:40:49 +0200 Subject: [PATCH 0192/1834] x86/platform/intel-mid: Handle Intel Edison reboot correctly commit 028091f82eefd5e84f81cef81a7673016ecbe78b upstream. When the Intel Edison module is powered with 3.3V, the reboot command makes the module stuck. If the module is powered at a greater voltage, like 4.4V (as the Edison Mini Breakout board does), reboot works OK. The official Intel Edison BSP sends the IPCMSG_COLD_RESET message to the SCU by default. The IPCMSG_COLD_BOOT which is used by the upstream kernel is only sent when explicitely selected on the kernel command line. Use IPCMSG_COLD_RESET unconditionally which makes reboot work independent of the power supply voltage. [ tglx: Massaged changelog ] Fixes: bda7b072de99 ("x86/platform/intel-mid: Implement power off sequence") Signed-off-by: Sebastian Panceac Signed-off-by: Thomas Gleixner Acked-by: Andy Shevchenko Cc: stable@vger.kernel.org Link: https://lkml.kernel.org/r/1519810849-15131-1-git-send-email-sebastian@resin.io Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/intel-mid/intel-mid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/platform/intel-mid/intel-mid.c b/arch/x86/platform/intel-mid/intel-mid.c index 7850128f0026..834783bc6752 100644 --- a/arch/x86/platform/intel-mid/intel-mid.c +++ b/arch/x86/platform/intel-mid/intel-mid.c @@ -79,7 +79,7 @@ static void intel_mid_power_off(void) static void intel_mid_reboot(void) { - intel_scu_ipc_simple_command(IPCMSG_COLD_BOOT, 0); + intel_scu_ipc_simple_command(IPCMSG_COLD_RESET, 0); } static unsigned long __init intel_mid_calibrate_tsc(void) -- GitLab From 9bcc9ac1cfd280e8795eb6b9fe3120a5682af939 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 10 Feb 2018 06:14:10 -0500 Subject: [PATCH 0193/1834] media: m88ds3103: don't call a non-initalized function commit b9c97c67fd19262c002d94ced2bfb513083e161e upstream. If m88d3103 chip ID is not recognized, the device is not initialized. However, it returns from probe without any error, causing this OOPS: [ 7.689289] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 7.689297] pgd = 7b0bd7a7 [ 7.689302] [00000000] *pgd=00000000 [ 7.689318] Internal error: Oops: 80000005 [#1] SMP ARM [ 7.689322] Modules linked in: dvb_usb_dvbsky(+) m88ds3103 dvb_usb_v2 dvb_core videobuf2_vmalloc videobuf2_memops videobuf2_core crc32_arm_ce videodev media [ 7.689358] CPU: 3 PID: 197 Comm: systemd-udevd Not tainted 4.15.0-mcc+ #23 [ 7.689361] Hardware name: BCM2835 [ 7.689367] PC is at 0x0 [ 7.689382] LR is at m88ds3103_attach+0x194/0x1d0 [m88ds3103] [ 7.689386] pc : [<00000000>] lr : [] psr: 60000013 [ 7.689391] sp : ed8e5c20 ip : ed8c1e00 fp : ed8945c0 [ 7.689395] r10: ed894000 r9 : ed894378 r8 : eda736c0 [ 7.689400] r7 : ed894070 r6 : ed8e5c44 r5 : bf0bb040 r4 : eda77600 [ 7.689405] r3 : 00000000 r2 : 00000000 r1 : 00000000 r0 : eda77600 [ 7.689412] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 7.689417] Control: 10c5383d Table: 2d8e806a DAC: 00000051 [ 7.689423] Process systemd-udevd (pid: 197, stack limit = 0xe9dbfb63) [ 7.689428] Stack: (0xed8e5c20 to 0xed8e6000) [ 7.689439] 5c20: ed853a80 eda73640 ed894000 ed8942c0 ed853a80 bf0b9e98 ed894070 bf0b9f10 [ 7.689449] 5c40: 00000000 00000000 bf08c17c c08dfc50 00000000 00000000 00000000 00000000 [ 7.689459] 5c60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.689468] 5c80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.689479] 5ca0: 00000000 00000000 ed8945c0 ed8942c0 ed894000 ed894830 bf0b9e98 00000000 [ 7.689490] 5cc0: ed894378 bf0a3cb4 bf0bc3b0 0000533b ed920540 00000000 00000034 bf0a6434 [ 7.689500] 5ce0: ee952070 ed826600 bf0a7038 bf0a2dd8 00000001 bf0a6768 bf0a2f90 ed8943c0 [ 7.689511] 5d00: 00000000 c08eca68 ed826620 ed826620 00000000 ee952070 bf0bc034 ee952000 [ 7.689521] 5d20: ed826600 bf0bb080 ffffffed c0aa9e9c c0aa9dac ed826620 c16edf6c c168c2c8 [ 7.689531] 5d40: c16edf70 00000000 bf0bc034 0000000d 00000000 c08e268c bf0bb080 ed826600 [ 7.689541] 5d60: bf0bc034 ed826654 ed826620 bf0bc034 c164c8bc 00000000 00000001 00000000 [ 7.689553] 5d80: 00000028 c08e2948 00000000 bf0bc034 c08e2848 c08e0778 ee9f0a58 ed88bab4 [ 7.689563] 5da0: bf0bc034 ed90ba80 c168c1f0 c08e1934 bf0bb3bc c17045ac bf0bc034 c164c8bc [ 7.689574] 5dc0: bf0bc034 bf0bb3bc ed91f564 c08e34ec bf0bc000 c164c8bc bf0bc034 c0aa8dc4 [ 7.689584] 5de0: ffffe000 00000000 bf0bf000 ed91f600 ed91f564 c03021e4 00000001 00000000 [ 7.689595] 5e00: c166e040 8040003f ed853a80 bf0bc448 00000000 c1678174 ed853a80 f0f22000 [ 7.689605] 5e20: f0f21fff 8040003f 014000c0 ed91e700 ed91e700 c16d8e68 00000001 ed91e6c0 [ 7.689615] 5e40: bf0bc400 00000001 bf0bc400 ed91f564 00000001 00000000 00000028 c03c9a24 [ 7.689625] 5e60: 00000001 c03c8c94 ed8e5f50 ed8e5f50 00000001 bf0bc400 ed91f540 c03c8cb0 [ 7.689637] 5e80: bf0bc40c 00007fff bf0bc400 c03c60b0 00000000 bf0bc448 00000028 c0e09684 [ 7.689647] 5ea0: 00000002 bf0bc530 c1234bf8 bf0bc5dc bf0bc514 c10ebbe8 ffffe000 bf000000 [ 7.689657] 5ec0: 00011538 00000000 ed8e5f48 00000000 00000000 00000000 00000000 00000000 [ 7.689666] 5ee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 7.689676] 5f00: 00000000 00000000 7fffffff 00000000 00000013 b6e55a18 0000017b c0309104 [ 7.689686] 5f20: ed8e4000 00000000 00510af0 c03c9430 7fffffff 00000000 00000003 00000000 [ 7.689697] 5f40: 00000000 f0f0f000 00011538 00000000 f0f107b0 f0f0f000 00011538 f0f1fdb8 [ 7.689707] 5f60: f0f1fbe8 f0f1b974 00004000 000041e0 bf0bc3d0 00000001 00000000 000024c4 [ 7.689717] 5f80: 0000002d 0000002e 00000019 00000000 00000010 00000000 16894000 00000000 [ 7.689727] 5fa0: 00000000 c0308f20 16894000 00000000 00000013 b6e55a18 00000000 b6e5652c [ 7.689737] 5fc0: 16894000 00000000 00000000 0000017b 00020000 00508110 00000000 00510af0 [ 7.689748] 5fe0: bef68948 bef68938 b6e4d3d0 b6d32590 60000010 00000013 00000000 00000000 [ 7.689790] [] (m88ds3103_attach [m88ds3103]) from [] (dvbsky_s960c_attach+0x78/0x280 [dvb_usb_dvbsky]) [ 7.689821] [] (dvbsky_s960c_attach [dvb_usb_dvbsky]) from [] (dvb_usbv2_probe+0xa3c/0x1024 [dvb_usb_v2]) [ 7.689849] [] (dvb_usbv2_probe [dvb_usb_v2]) from [] (usb_probe_interface+0xf0/0x2a8) [ 7.689869] [] (usb_probe_interface) from [] (driver_probe_device+0x2f8/0x4b4) [ 7.689881] [] (driver_probe_device) from [] (__driver_attach+0x100/0x11c) [ 7.689895] [] (__driver_attach) from [] (bus_for_each_dev+0x4c/0x9c) [ 7.689909] [] (bus_for_each_dev) from [] (bus_add_driver+0x1c0/0x264) [ 7.689919] [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [ 7.689931] [] (driver_register) from [] (usb_register_driver+0x70/0x134) [ 7.689946] [] (usb_register_driver) from [] (do_one_initcall+0x44/0x168) [ 7.689963] [] (do_one_initcall) from [] (do_init_module+0x64/0x1f4) [ 7.689979] [] (do_init_module) from [] (load_module+0x20a0/0x25c8) [ 7.689993] [] (load_module) from [] (SyS_finit_module+0xb4/0xec) [ 7.690007] [] (SyS_finit_module) from [] (ret_fast_syscall+0x0/0x54) [ 7.690018] Code: bad PC value This may happen on normal circumstances, if, for some reason, the demod hangs and start returning an invalid chip ID: [ 10.394395] m88ds3103 3-0068: Unknown device. Chip_id=00 So, change the logic to cause probe to fail with -ENODEV, preventing the OOPS. Detected while testing DVB MMAP patches on Raspberry Pi 3 with DVBSky S960CI. Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb-frontends/m88ds3103.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index e0fe5bc9dbce..31f16105184c 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -1262,11 +1262,12 @@ static int m88ds3103_select(struct i2c_mux_core *muxc, u32 chan) * New users must use I2C client binding directly! */ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, - struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter) + struct i2c_adapter *i2c, + struct i2c_adapter **tuner_i2c_adapter) { struct i2c_client *client; struct i2c_board_info board_info; - struct m88ds3103_platform_data pdata; + struct m88ds3103_platform_data pdata = {}; pdata.clk = cfg->clock; pdata.i2c_wr_max = cfg->i2c_wr_max; @@ -1409,6 +1410,8 @@ static int m88ds3103_probe(struct i2c_client *client, case M88DS3103_CHIP_ID: break; default: + ret = -ENODEV; + dev_err(&client->dev, "Unknown device. Chip_id=%02x\n", dev->chip_id); goto err_kfree; } -- GitLab From ec69fa88f393ba1f1d4aca11ce31835a85d6d58d Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Fri, 16 Feb 2018 13:20:48 -0800 Subject: [PATCH 0194/1834] nospec: Allow index argument to have const-qualified type commit b98c6a160a057d5686a8c54c79cc6c8c94a7d0c8 upstream. The last expression in a statement expression need not be a bare variable, quoting gcc docs The last thing in the compound statement should be an expression followed by a semicolon; the value of this subexpression serves as the value of the entire construct. and we already use that in e.g. the min/max macros which end with a ternary expression. This way, we can allow index to have const-qualified type, which will in some cases avoid the need for introducing a local copy of index of non-const qualified type. That, in turn, can prevent readers not familiar with the internals of array_index_nospec from wondering about the seemingly redundant extra variable, and I think that's worthwhile considering how confusing the whole _nospec business is. The expression _i&_mask has type unsigned long (since that is the type of _mask, and the BUILD_BUG_ONs guarantee that _i will get promoted to that), so in order not to change the type of the whole expression, add a cast back to typeof(_i). Signed-off-by: Rasmus Villemoes Signed-off-by: Dan Williams Acked-by: Linus Torvalds Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Josh Poimboeuf Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/151881604837.17395.10812767547837568328.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/nospec.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/linux/nospec.h b/include/linux/nospec.h index fbc98e2c8228..132e3f5a2e0d 100644 --- a/include/linux/nospec.h +++ b/include/linux/nospec.h @@ -72,7 +72,6 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \ BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \ \ - _i &= _mask; \ - _i; \ + (typeof(_i)) (_i & _mask); \ }) #endif /* _LINUX_NOSPEC_H */ -- GitLab From 8e4c257afd19c2395bcca27565a6c5aba3374772 Mon Sep 17 00:00:00 2001 From: Ulf Magnusson Date: Mon, 5 Feb 2018 02:21:13 +0100 Subject: [PATCH 0195/1834] ARM: mvebu: Fix broken PL310_ERRATA_753970 selects commit 8aa36a8dcde3183d84db7b0d622ffddcebb61077 upstream. The MACH_ARMADA_375 and MACH_ARMADA_38X boards select ARM_ERRATA_753970, but it was renamed to PL310_ERRATA_753970 by commit fa0ce4035d48 ("ARM: 7162/1: errata: tidy up Kconfig options for PL310 errata workarounds"). Fix the selects to use the new name. Discovered with the https://github.com/ulfalizer/Kconfiglib/blob/master/examples/list_undefined.py script. Fixes: fa0ce4035d48 ("ARM: 7162/1: errata: tidy up Kconfig options for PL310 errata workarounds" cc: stable@vger.kernel.org Signed-off-by: Ulf Magnusson Signed-off-by: Gregory CLEMENT Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-mvebu/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig index 541647f57192..895c0746fe50 100644 --- a/arch/arm/mach-mvebu/Kconfig +++ b/arch/arm/mach-mvebu/Kconfig @@ -42,7 +42,7 @@ config MACH_ARMADA_375 depends on ARCH_MULTI_V7 select ARMADA_370_XP_IRQ select ARM_ERRATA_720789 - select ARM_ERRATA_753970 + select PL310_ERRATA_753970 select ARM_GIC select ARMADA_375_CLK select HAVE_ARM_SCU @@ -58,7 +58,7 @@ config MACH_ARMADA_38X bool "Marvell Armada 380/385 boards" depends on ARCH_MULTI_V7 select ARM_ERRATA_720789 - select ARM_ERRATA_753970 + select PL310_ERRATA_753970 select ARM_GIC select ARMADA_370_XP_IRQ select ARMADA_38X_CLK -- GitLab From aebf1b12fff4863b0e646420c8d752f08eb9f434 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 2 Feb 2018 16:07:34 +0100 Subject: [PATCH 0196/1834] ARM: kvm: fix building with gcc-8 commit 67870eb1204223598ea6d8a4467b482e9f5875b5 upstream. In banked-sr.c, we use a top-level '__asm__(".arch_extension virt")' statement to allow compilation of a multi-CPU kernel for ARMv6 and older ARMv7-A that don't normally support access to the banked registers. This is considered to be a programming error by the gcc developers and will no longer work in gcc-8, where we now get a build error: /tmp/cc4Qy7GR.s:34: Error: Banked registers are not available with this architecture. -- `mrs r3,SP_usr' /tmp/cc4Qy7GR.s:41: Error: Banked registers are not available with this architecture. -- `mrs r3,ELR_hyp' /tmp/cc4Qy7GR.s:55: Error: Banked registers are not available with this architecture. -- `mrs r3,SP_svc' /tmp/cc4Qy7GR.s:62: Error: Banked registers are not available with this architecture. -- `mrs r3,LR_svc' /tmp/cc4Qy7GR.s:69: Error: Banked registers are not available with this architecture. -- `mrs r3,SPSR_svc' /tmp/cc4Qy7GR.s:76: Error: Banked registers are not available with this architecture. -- `mrs r3,SP_abt' Passign the '-march-armv7ve' flag to gcc works, and is ok here, because we know the functions won't ever be called on pre-ARMv7VE machines. Unfortunately, older compiler versions (4.8 and earlier) do not understand that flag, so we still need to keep the asm around. Backporting to stable kernels (4.6+) is needed to allow those to be built with future compilers as well. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84129 Fixes: 33280b4cd1dc ("ARM: KVM: Add banked registers save/restore") Cc: stable@vger.kernel.org Signed-off-by: Arnd Bergmann Signed-off-by: Christoffer Dall Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/hyp/Makefile | 5 +++++ arch/arm/kvm/hyp/banked-sr.c | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/kvm/hyp/Makefile b/arch/arm/kvm/hyp/Makefile index 92eab1d51785..61049216e4d5 100644 --- a/arch/arm/kvm/hyp/Makefile +++ b/arch/arm/kvm/hyp/Makefile @@ -6,6 +6,8 @@ ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING KVM=../../../../virt/kvm +CFLAGS_ARMV7VE :=$(call cc-option, -march=armv7ve) + obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v2-sr.o obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/vgic-v3-sr.o obj-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hyp/timer-sr.o @@ -14,7 +16,10 @@ obj-$(CONFIG_KVM_ARM_HOST) += tlb.o obj-$(CONFIG_KVM_ARM_HOST) += cp15-sr.o obj-$(CONFIG_KVM_ARM_HOST) += vfp.o obj-$(CONFIG_KVM_ARM_HOST) += banked-sr.o +CFLAGS_banked-sr.o += $(CFLAGS_ARMV7VE) + obj-$(CONFIG_KVM_ARM_HOST) += entry.o obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o obj-$(CONFIG_KVM_ARM_HOST) += switch.o +CFLAGS_switch.o += $(CFLAGS_ARMV7VE) obj-$(CONFIG_KVM_ARM_HOST) += s2-setup.o diff --git a/arch/arm/kvm/hyp/banked-sr.c b/arch/arm/kvm/hyp/banked-sr.c index 111bda8cdebd..be4b8b0a40ad 100644 --- a/arch/arm/kvm/hyp/banked-sr.c +++ b/arch/arm/kvm/hyp/banked-sr.c @@ -20,6 +20,10 @@ #include +/* + * gcc before 4.9 doesn't understand -march=armv7ve, so we have to + * trick the assembler. + */ __asm__(".arch_extension virt"); void __hyp_text __banked_save_state(struct kvm_cpu_context *ctxt) -- GitLab From 2e112f3659838abc7113890f6c87914f0603f297 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 13 Feb 2018 15:36:00 +0100 Subject: [PATCH 0197/1834] KVM: mmu: Fix overlap between public and private memslots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit b28676bb8ae4569cced423dc2a88f7cb319d5379 upstream. Reported by syzkaller: pte_list_remove: ffff9714eb1f8078 0->BUG ------------[ cut here ]------------ kernel BUG at arch/x86/kvm/mmu.c:1157! invalid opcode: 0000 [#1] SMP RIP: 0010:pte_list_remove+0x11b/0x120 [kvm] Call Trace: drop_spte+0x83/0xb0 [kvm] mmu_page_zap_pte+0xcc/0xe0 [kvm] kvm_mmu_prepare_zap_page+0x81/0x4a0 [kvm] kvm_mmu_invalidate_zap_all_pages+0x159/0x220 [kvm] kvm_arch_flush_shadow_all+0xe/0x10 [kvm] kvm_mmu_notifier_release+0x6c/0xa0 [kvm] ? kvm_mmu_notifier_release+0x5/0xa0 [kvm] __mmu_notifier_release+0x79/0x110 ? __mmu_notifier_release+0x5/0x110 exit_mmap+0x15a/0x170 ? do_exit+0x281/0xcb0 mmput+0x66/0x160 do_exit+0x2c9/0xcb0 ? __context_tracking_exit.part.5+0x4a/0x150 do_group_exit+0x50/0xd0 SyS_exit_group+0x14/0x20 do_syscall_64+0x73/0x1f0 entry_SYSCALL64_slow_path+0x25/0x25 The reason is that when creates new memslot, there is no guarantee for new memslot not overlap with private memslots. This can be triggered by the following program: #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include long r[16]; int main() { void *p = valloc(0x4000); r[2] = open("/dev/kvm", 0); r[3] = ioctl(r[2], KVM_CREATE_VM, 0x0ul); uint64_t addr = 0xf000; ioctl(r[3], KVM_SET_IDENTITY_MAP_ADDR, &addr); r[6] = ioctl(r[3], KVM_CREATE_VCPU, 0x0ul); ioctl(r[3], KVM_SET_TSS_ADDR, 0x0ul); ioctl(r[6], KVM_RUN, 0); ioctl(r[6], KVM_RUN, 0); struct kvm_userspace_memory_region mr = { .slot = 0, .flags = KVM_MEM_LOG_DIRTY_PAGES, .guest_phys_addr = 0xf000, .memory_size = 0x4000, .userspace_addr = (uintptr_t) p }; ioctl(r[3], KVM_SET_USER_MEMORY_REGION, &mr); return 0; } This patch fixes the bug by not adding a new memslot even if it overlaps with private memslots. Reported-by: Dmitry Vyukov Cc: Paolo Bonzini Cc: Radim Krčmář Cc: Dmitry Vyukov Cc: Eric Biggers Cc: stable@vger.kernel.org Signed-off-by: Wanpeng Li --- virt/kvm/kvm_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 1b20768e781d..eaae7252f60c 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -976,8 +976,7 @@ int __kvm_set_memory_region(struct kvm *kvm, /* Check for overlaps */ r = -EEXIST; kvm_for_each_memslot(slot, __kvm_memslots(kvm, as_id)) { - if ((slot->id >= KVM_USER_MEM_SLOTS) || - (slot->id == id)) + if (slot->id == id) continue; if (!((base_gfn + npages <= slot->base_gfn) || (base_gfn >= slot->base_gfn + slot->npages))) -- GitLab From a175d5194a8597ae13c0240d560b4f575e406048 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Feb 2018 16:43:17 +0100 Subject: [PATCH 0198/1834] KVM/x86: Remove indirect MSR op calls from SPEC_CTRL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ecb586bd29c99fb4de599dec388658e74388daad upstream. Having a paravirt indirect call in the IBRS restore path is not a good idea, since we are trying to protect from speculative execution of bogus indirect branch targets. It is also slower, so use native_wrmsrl() on the vmentry path too. Signed-off-by: Paolo Bonzini Reviewed-by: Jim Mattson Cc: David Woodhouse Cc: KarimAllah Ahmed Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Radim Krčmář Cc: Thomas Gleixner Cc: kvm@vger.kernel.org Cc: stable@vger.kernel.org Fixes: d28b387fb74da95d69d2615732f50cceb38e9a4d Link: http://lkml.kernel.org/r/20180222154318.20361-2-pbonzini@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm.c | 7 ++++--- arch/x86/kvm/vmx.c | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index be644afab1bb..d4881ffb446d 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -4919,7 +4920,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) * being speculatively taken. */ if (svm->spec_ctrl) - wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl); + native_wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl); asm volatile ( "push %%" _ASM_BP "; \n\t" @@ -5029,10 +5030,10 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) * save it. */ if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)) - rdmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl); + svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); if (svm->spec_ctrl) - wrmsrl(MSR_IA32_SPEC_CTRL, 0); + native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); /* Eliminate branch target predictions from guest mode */ vmexit_fill_RSB(); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index c51aaac953b4..b78280bae3f4 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include "trace.h" @@ -8906,7 +8907,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) * being speculatively taken. */ if (vmx->spec_ctrl) - wrmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl); + native_wrmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl); vmx->__launched = vmx->loaded_vmcs->launched; asm( @@ -9042,10 +9043,10 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) * save it. */ if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)) - rdmsrl(MSR_IA32_SPEC_CTRL, vmx->spec_ctrl); + vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); if (vmx->spec_ctrl) - wrmsrl(MSR_IA32_SPEC_CTRL, 0); + native_wrmsrl(MSR_IA32_SPEC_CTRL, 0); /* Eliminate branch target predictions from guest mode */ vmexit_fill_RSB(); -- GitLab From f750e1518e9bb08626ae31d4ad9c0333878fcaa7 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Feb 2018 16:43:18 +0100 Subject: [PATCH 0199/1834] KVM/VMX: Optimize vmx_vcpu_run() and svm_vcpu_run() by marking the RDMSR path as unlikely() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 946fbbc13dce68902f64515b610eeb2a6c3d7a64 upstream. vmx_vcpu_run() and svm_vcpu_run() are large functions, and giving branch hints to the compiler can actually make a substantial cycle difference by keeping the fast path contiguous in memory. With this optimization, the retpoline-guest/retpoline-host case is about 50 cycles faster. Signed-off-by: Paolo Bonzini Reviewed-by: Jim Mattson Cc: David Woodhouse Cc: KarimAllah Ahmed Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Radim Krčmář Cc: Thomas Gleixner Cc: kvm@vger.kernel.org Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180222154318.20361-3-pbonzini@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm.c | 2 +- arch/x86/kvm/vmx.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index d4881ffb446d..24d2a3ee743f 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -5029,7 +5029,7 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu) * If the L02 MSR bitmap does not intercept the MSR, then we need to * save it. */ - if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)) + if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) svm->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); if (svm->spec_ctrl) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index b78280bae3f4..0f3bb4632310 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -9042,7 +9042,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) * If the L02 MSR bitmap does not intercept the MSR, then we need to * save it. */ - if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL)) + if (unlikely(!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))) vmx->spec_ctrl = native_read_msr(MSR_IA32_SPEC_CTRL); if (vmx->spec_ctrl) -- GitLab From 6213c714a580c34751f9501725369fc5e0fe71e5 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Mon, 2 Oct 2017 15:08:40 +0100 Subject: [PATCH 0200/1834] PCI/ASPM: Deal with missing root ports in link state handling commit ee8bdfb6568d86bb93f55f8d99c4c643e77304ee upstream. Even though it is unconventional, some PCIe host implementations omit the root ports entirely, and simply consist of a host bridge (which is not modeled as a device in the PCI hierarchy) and a link. When the downstream device is an endpoint, our current code does not seem to mind this unusual configuration. However, when PCIe switches are involved, the ASPM code assumes that any downstream switch port has a parent, and blindly dereferences the bus->parent->self field of the pci_dev struct to chain the downstream link state to the link state of the root port. Given that the root port is missing, the link is not modeled at all, and nor is the link state, and attempting to access it results in a NULL pointer dereference and a crash. Avoid this by allowing the link state chain to terminate at the downstream port if no root port exists. Signed-off-by: Ard Biesheuvel Signed-off-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pcie/aspm.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index b0916b126923..6643a7bc381c 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -526,10 +526,14 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev) /* * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe - * hierarchies. + * hierarchies. Note that some PCIe host implementations omit + * the root ports entirely, in which case a downstream port on + * a switch may become the root of the link state chain for all + * its subordinate endpoints. */ if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT || - pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) { + pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE || + !pdev->bus->parent->self) { link->root = link; } else { struct pcie_link_state *parent; -- GitLab From b6f93a1341fb166ea861aa37eeac492af3de837a Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Tue, 20 Jun 2017 19:14:30 -0400 Subject: [PATCH 0201/1834] dm io: fix duplicate bio completion due to missing ref count commit feb7695fe9fb83084aa29de0094774f4c9d4c9fc upstream. If only a subset of the devices associated with multiple regions support a given special operation (eg. DISCARD) then the dec_count() that is used to set error for the region must increment the io->count. Otherwise, when the dec_count() is called it can cause the dm-io caller's bio to be completed multiple times. As was reported against the dm-mirror target that had mirror legs with a mix of discard capabilities. Bug: https://bugzilla.kernel.org/show_bug.cgi?id=196077 Reported-by: Zhang Yi Signed-off-by: Mike Snitzer Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-io.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 0bf1a12e35fe..ee6045d6c0bb 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -302,6 +302,7 @@ static void do_region(int op, int op_flags, unsigned region, special_cmd_max_sectors = q->limits.max_write_same_sectors; if ((op == REQ_OP_DISCARD || op == REQ_OP_WRITE_SAME) && special_cmd_max_sectors == 0) { + atomic_inc(&io->count); dec_count(io, region, -EOPNOTSUPP); return; } -- GitLab From 5f1f00dfa593aa41cf1013e7535667c13d3122fc Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Sat, 27 Jan 2018 15:27:05 -0600 Subject: [PATCH 0202/1834] ARM: dts: LogicPD SOM-LV: Fix I2C1 pinmux commit 84c7efd607e7fb6933920322086db64654f669b2 upstream. The pinmuxing was missing for I2C1 which was causing intermittent issues with the PMIC which is connected to I2C1. The bootloader did not quite configure the I2C1 either, so when running at 2.6MHz, it was generating errors at times. This correctly sets the I2C1 pinmuxing so it can operate at 2.6MHz Fixes: ab8dd3aed011 ("ARM: DTS: Add minimal Support for Logic PD DM3730 SOM-LV") Signed-off-by: Adam Ford Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/logicpd-som-lv.dtsi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/logicpd-som-lv.dtsi b/arch/arm/boot/dts/logicpd-som-lv.dtsi index 4f2c5ec75714..e262fa9ef334 100644 --- a/arch/arm/boot/dts/logicpd-som-lv.dtsi +++ b/arch/arm/boot/dts/logicpd-som-lv.dtsi @@ -97,6 +97,8 @@ }; &i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; clock-frequency = <2600000>; twl: twl@48 { @@ -215,7 +217,12 @@ >; }; - + i2c1_pins: pinmux_i2c1_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ + OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */ + >; + }; }; &omap3_pmx_wkup { -- GitLab From c737c8d04d16c4259ced96fdd69e6664aa64d926 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Thu, 25 Jan 2018 14:10:37 -0600 Subject: [PATCH 0203/1834] ARM: dts: LogicPD Torpedo: Fix I2C1 pinmux commit 74402055a2d3ec998a1ded599e86185a27d9bbf4 upstream. The pinmuxing was missing for I2C1 which was causing intermittent issues with the PMIC which is connected to I2C1. The bootloader did not quite configure the I2C1 either, so when running at 2.6MHz, it was generating errors at time. This correctly sets the I2C1 pinmuxing so it can operate at 2.6MHz Fixes: 687c27676151 ("ARM: dts: Add minimal support for LogicPD Torpedo DM3730 devkit") Signed-off-by: Adam Ford Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/logicpd-torpedo-som.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi index efe53998c961..08f0a35dc0d1 100644 --- a/arch/arm/boot/dts/logicpd-torpedo-som.dtsi +++ b/arch/arm/boot/dts/logicpd-torpedo-som.dtsi @@ -100,6 +100,8 @@ }; &i2c1 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c1_pins>; clock-frequency = <2600000>; twl: twl@48 { @@ -207,6 +209,12 @@ OMAP3_CORE1_IOPAD(0x21b8, PIN_INPUT | MUX_MODE0) /* hsusb0_data7.hsusb0_data7 */ >; }; + i2c1_pins: pinmux_i2c1_pins { + pinctrl-single,pins = < + OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */ + OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */ + >; + }; }; &uart2 { -- GitLab From 027ba1a054f3da470acc45a885b88a04886c1fa9 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 29 Jun 2017 08:53:15 -0700 Subject: [PATCH 0204/1834] x86/mm: Give each mm TLB flush generation a unique ID commit f39681ed0f48498b80455095376f11535feea332 upstream. This adds two new variables to mmu_context_t: ctx_id and tlb_gen. ctx_id uniquely identifies the mm_struct and will never be reused. For a given mm_struct (and hence ctx_id), tlb_gen is a monotonic count of the number of times that a TLB flush has been requested. The pair (ctx_id, tlb_gen) can be used as an identifier for TLB flush actions and will be used in subsequent patches to reliably determine whether all needed TLB flushes have occurred on a given CPU. This patch is split out for ease of review. By itself, it has no real effect other than creating and updating the new variables. Signed-off-by: Andy Lutomirski Reviewed-by: Nadav Amit Reviewed-by: Thomas Gleixner Cc: Andrew Morton Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dave Hansen Cc: Linus Torvalds Cc: Mel Gorman Cc: Peter Zijlstra Cc: Rik van Riel Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/413a91c24dab3ed0caa5f4e4d017d87b0857f920.1498751203.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Tim Chen Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/mmu.h | 15 +++++++++++++-- arch/x86/include/asm/mmu_context.h | 5 +++++ arch/x86/mm/tlb.c | 2 ++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/mmu.h b/arch/x86/include/asm/mmu.h index 8b272a08d1a8..e2e09347ee3c 100644 --- a/arch/x86/include/asm/mmu.h +++ b/arch/x86/include/asm/mmu.h @@ -3,12 +3,18 @@ #include #include +#include /* - * The x86 doesn't have a mmu context, but - * we put the segment information here. + * x86 has arch-specific MMU state beyond what lives in mm_struct. */ typedef struct { + /* + * ctx_id uniquely identifies this mm_struct. A ctx_id will never + * be reused, and zero is not a valid ctx_id. + */ + u64 ctx_id; + #ifdef CONFIG_MODIFY_LDT_SYSCALL struct ldt_struct *ldt; #endif @@ -33,6 +39,11 @@ typedef struct { #endif } mm_context_t; +#define INIT_MM_CONTEXT(mm) \ + .context = { \ + .ctx_id = 1, \ + } + void leave_mm(int cpu); #endif /* _ASM_X86_MMU_H */ diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h index d23e35584f15..5a295bb97103 100644 --- a/arch/x86/include/asm/mmu_context.h +++ b/arch/x86/include/asm/mmu_context.h @@ -12,6 +12,9 @@ #include #include #include + +extern atomic64_t last_mm_ctx_id; + #ifndef CONFIG_PARAVIRT static inline void paravirt_activate_mm(struct mm_struct *prev, struct mm_struct *next) @@ -106,6 +109,8 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) static inline int init_new_context(struct task_struct *tsk, struct mm_struct *mm) { + mm->context.ctx_id = atomic64_inc_return(&last_mm_ctx_id); + #ifdef CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS if (cpu_feature_enabled(X86_FEATURE_OSPKE)) { /* pkey 0 is the default and always allocated */ diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 578973ade71b..fa74bf57a646 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -29,6 +29,8 @@ * Implement flush IPI by CALL_FUNCTION_VECTOR, Alex Shi */ +atomic64_t last_mm_ctx_id = ATOMIC64_INIT(1); + struct flush_tlb_info { struct mm_struct *flush_mm; unsigned long flush_start; -- GitLab From 2585e4b41cd690a3d40163b63fc4f7c68b1d8337 Mon Sep 17 00:00:00 2001 From: Tim Chen Date: Mon, 29 Jan 2018 22:04:47 +0000 Subject: [PATCH 0205/1834] x86/speculation: Use Indirect Branch Prediction Barrier in context switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 18bf3c3ea8ece8f03b6fc58508f2dfd23c7711c7 upstream. Flush indirect branches when switching into a process that marked itself non dumpable. This protects high value processes like gpg better, without having too high performance overhead. If done naïvely, we could switch to a kernel idle thread and then back to the original process, such as: process A -> idle -> process A In such scenario, we do not have to do IBPB here even though the process is non-dumpable, as we are switching back to the same process after a hiatus. To avoid the redundant IBPB, which is expensive, we track the last mm user context ID. The cost is to have an extra u64 mm context id to track the last mm we were using before switching to the init_mm used by idle. Avoiding the extra IBPB is probably worth the extra memory for this common scenario. For those cases where tlb_defer_switch_to_init_mm() returns true (non PCID), lazy tlb will defer switch to init_mm, so we will not be changing the mm for the process A -> idle -> process A switch. So IBPB will be skipped for this case. Thanks to the reviewers and Andy Lutomirski for the suggestion of using ctx_id which got rid of the problem of mm pointer recycling. Signed-off-by: Tim Chen Signed-off-by: David Woodhouse Signed-off-by: Thomas Gleixner Cc: ak@linux.intel.com Cc: karahmed@amazon.de Cc: arjan@linux.intel.com Cc: torvalds@linux-foundation.org Cc: linux@dominikbrodowski.net Cc: peterz@infradead.org Cc: bp@alien8.de Cc: luto@kernel.org Cc: pbonzini@redhat.com Link: https://lkml.kernel.org/r/1517263487-3708-1-git-send-email-dwmw@amazon.co.uk Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/tlbflush.h | 2 ++ arch/x86/mm/tlb.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index 94146f665a3c..99185a064978 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -68,6 +68,8 @@ static inline void invpcid_flush_all_nonglobals(void) struct tlb_state { struct mm_struct *active_mm; int state; + /* last user mm's ctx id */ + u64 last_ctx_id; /* * Access to this CR4 shadow and to H/W CR4 is protected by diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index fa74bf57a646..eac92e2d171b 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -106,6 +107,28 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, unsigned cpu = smp_processor_id(); if (likely(prev != next)) { + u64 last_ctx_id = this_cpu_read(cpu_tlbstate.last_ctx_id); + + /* + * Avoid user/user BTB poisoning by flushing the branch + * predictor when switching between processes. This stops + * one process from doing Spectre-v2 attacks on another. + * + * As an optimization, flush indirect branches only when + * switching into processes that disable dumping. This + * protects high value processes like gpg, without having + * too high performance overhead. IBPB is *expensive*! + * + * This will not flush branches when switching into kernel + * threads. It will also not flush if we switch to idle + * thread and back to the same process. It will flush if we + * switch to a different non-dumpable process. + */ + if (tsk && tsk->mm && + tsk->mm->context.ctx_id != last_ctx_id && + get_dumpable(tsk->mm) != SUID_DUMP_USER) + indirect_branch_prediction_barrier(); + if (IS_ENABLED(CONFIG_VMAP_STACK)) { /* * If our current stack is in vmalloc space and isn't @@ -120,6 +143,14 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next, set_pgd(pgd, init_mm.pgd[stack_pgd_index]); } + /* + * Record last user mm's context id, so we can avoid + * flushing branch buffer with IBPB if we switch back + * to the same user. + */ + if (next != &init_mm) + this_cpu_write(cpu_tlbstate.last_ctx_id, next->context.ctx_id); + this_cpu_write(cpu_tlbstate.state, TLBSTATE_OK); this_cpu_write(cpu_tlbstate.active_mm, next); -- GitLab From eb2593fbd643f68a557b62141106788242183954 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Sat, 3 Feb 2018 09:19:30 +1100 Subject: [PATCH 0206/1834] md: only allow remove_and_add_spares when no sync_thread running. commit 39772f0a7be3b3dc26c74ea13fe7847fd1522c8b upstream. The locking protocols in md assume that a device will never be removed from an array during resync/recovery/reshape. When that isn't happening, rcu or reconfig_mutex is needed to protect an rdev pointer while taking a refcount. When it is happening, that protection isn't needed. Unfortunately there are cases were remove_and_add_spares() is called when recovery might be happening: is state_store(), slot_store() and hot_remove_disk(). In each case, this is just an optimization, to try to expedite removal from the personality so the device can be removed from the array. If resync etc is happening, we just have to wait for md_check_recover to find a suitable time to call remove_and_add_spares(). This optimization and not essential so it doesn't matter if it fails. So change remove_and_add_spares() to abort early if resync/recovery/reshape is happening, unless it is called from md_check_recovery() as part of a newly started recovery. The parameter "this" is only NULL when called from md_check_recovery() so when it is NULL, there is no need to abort. As this can result in a NULL dereference, the fix is suitable for -stable. cc: yuyufen Cc: Tomasz Majchrzak Fixes: 8430e7e0af9a ("md: disconnect device from personality before trying to remove it.") Cc: stable@ver.kernel.org (v4.8+) Signed-off-by: NeilBrown Signed-off-by: Shaohua Li Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 8ebf1b97e1d2..27d8bb21e04f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8224,6 +8224,10 @@ static int remove_and_add_spares(struct mddev *mddev, int removed = 0; bool remove_some = false; + if (this && test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) + /* Mustn't remove devices when resync thread is running */ + return 0; + rdev_for_each(rdev, mddev) { if ((this == NULL || rdev == this) && rdev->raid_disk >= 0 && -- GitLab From e7b12efd7da92455f59f23dde01e80aaa8cdfcfa Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 21 Feb 2018 04:41:59 +0100 Subject: [PATCH 0207/1834] netlink: put module reference if dump start fails commit b87b6194be631c94785fe93398651e804ed43e28 upstream. Before, if cb->start() failed, the module reference would never be put, because cb->cb_running is intentionally false at this point. Users are generally annoyed by this because they can no longer unload modules that leak references. Also, it may be possible to tediously wrap a reference counter back to zero, especially since module.c still uses atomic_inc instead of refcount_inc. This patch expands the error path to simply call module_put if cb->start() fails. Fixes: 41c87425a1ac ("netlink: do not set cb_running if dump's start() errs") Signed-off-by: Jason A. Donenfeld Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e1c123d4cdda..c1f59a06da6f 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -2258,7 +2258,7 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, if (cb->start) { ret = cb->start(cb); if (ret) - goto error_unlock; + goto error_put; } nlk->cb_running = true; @@ -2278,6 +2278,8 @@ int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, */ return -EINTR; +error_put: + module_put(control->module); error_unlock: sock_put(sk); mutex_unlock(nlk->cb_mutex); -- GitLab From 59e162377323531cde25a9ee5651a993d1774563 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 7 Mar 2018 18:36:43 +0000 Subject: [PATCH 0208/1834] x86/apic/vector: Handle legacy irq data correctly The backport of upstream commit 45d55e7bac40 ("x86/apic/vector: Fix off by one in error path") missed to fixup the legacy interrupt data which is not longer available upstream. Handle legacy irq data correctly by clearing the legacy storage to prevent use after free. Fixes: 7fd133539289 ("x86/apic/vector: Fix off by one in error path") - 4.4.y Fixes: c557481a9491 ("x86/apic/vector: Fix off by one in error path") - 4.9.y Reported-by: Ben Hutchings Signed-off-by: Thomas Gleixner Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/apic/vector.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c index b5229abd1629..4922ab66fd29 100644 --- a/arch/x86/kernel/apic/vector.c +++ b/arch/x86/kernel/apic/vector.c @@ -93,8 +93,12 @@ static struct apic_chip_data *alloc_apic_chip_data(int node) return NULL; } -static void free_apic_chip_data(struct apic_chip_data *data) +static void free_apic_chip_data(unsigned int virq, struct apic_chip_data *data) { +#ifdef CONFIG_X86_IO_APIC + if (virq < nr_legacy_irqs()) + legacy_irq_data[virq] = NULL; +#endif if (data) { free_cpumask_var(data->domain); free_cpumask_var(data->old_domain); @@ -318,11 +322,7 @@ static void x86_vector_free_irqs(struct irq_domain *domain, apic_data = irq_data->chip_data; irq_domain_reset_irq_data(irq_data); raw_spin_unlock_irqrestore(&vector_lock, flags); - free_apic_chip_data(apic_data); -#ifdef CONFIG_X86_IO_APIC - if (virq + i < nr_legacy_irqs()) - legacy_irq_data[virq + i] = NULL; -#endif + free_apic_chip_data(virq + i, apic_data); } } } @@ -363,7 +363,7 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq, err = assign_irq_vector_policy(virq + i, node, data, info); if (err) { irq_data->chip_data = NULL; - free_apic_chip_data(data); + free_apic_chip_data(virq + i, data); goto error; } } -- GitLab From 9f32011496ba86d2f7992d06e9d40bea28cad66e Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 12 Feb 2018 17:15:40 +0800 Subject: [PATCH 0209/1834] bridge: check brport attr show in brport_show [ Upstream commit 1b12580af1d0677c3c3a19e35bfe5d59b03f737f ] Now br_sysfs_if file flush doesn't have attr show. To read it will cause kernel panic after users chmod u+r this file. Xiong found this issue when running the commands: ip link add br0 type bridge ip link add type veth ip link set veth0 master br0 chmod u+r /sys/devices/virtual/net/veth0/brport/flush timeout 3 cat /sys/devices/virtual/net/veth0/brport/flush kernel crashed with NULL a pointer dereference call trace. This patch is to fix it by return -EINVAL when brport_attr->show is null, just the same as the check for brport_attr->store in brport_store(). Fixes: 9cf637473c85 ("bridge: add sysfs hook to flush forwarding table") Reported-by: Xiong Zhou Signed-off-by: Xin Long Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/bridge/br_sysfs_if.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/bridge/br_sysfs_if.c b/net/bridge/br_sysfs_if.c index 8bd569695e76..abf711112418 100644 --- a/net/bridge/br_sysfs_if.c +++ b/net/bridge/br_sysfs_if.c @@ -230,6 +230,9 @@ static ssize_t brport_show(struct kobject *kobj, struct brport_attribute *brport_attr = to_brport_attr(attr); struct net_bridge_port *p = to_brport(kobj); + if (!brport_attr->show) + return -EINVAL; + return brport_attr->show(p, buf); } -- GitLab From def37b7db39147080a58041d97ad9120335c70c2 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Thu, 15 Feb 2018 09:46:03 +0100 Subject: [PATCH 0210/1834] fib_semantics: Don't match route with mismatching tclassid [ Upstream commit a8c6db1dfd1b1d18359241372bb204054f2c3174 ] In fib_nh_match(), if output interface or gateway are passed in the FIB configuration, we don't have to check next hops of multipath routes to conclude whether we have a match or not. However, we might still have routes with different realms matching the same output interface and gateway configuration, and this needs to cause the match to fail. Otherwise the first route inserted in the FIB will match, regardless of the realms: # ip route add 1.1.1.1 dev eth0 table 1234 realms 1/2 # ip route append 1.1.1.1 dev eth0 table 1234 realms 3/4 # ip route list table 1234 1.1.1.1 dev eth0 scope link realms 1/2 1.1.1.1 dev eth0 scope link realms 3/4 # ip route del 1.1.1.1 dev ens3 table 1234 realms 3/4 # ip route list table 1234 1.1.1.1 dev ens3 scope link realms 3/4 whereas route with realms 3/4 should have been deleted instead. Explicitly check for fc_flow passed in the FIB configuration (this comes from RTA_FLOW extracted by rtm_to_fib_config()) and fail matching if it differs from nh_tclassid. The handling of RTA_FLOW for multipath routes later in fib_nh_match() is still needed, as we can have multiple RTA_FLOW attributes that need to be matched against the tclassid of each next hop. v2: Check that fc_flow is set before discarding the match, so that the user can still select the first matching rule by not specifying any realm, as suggested by David Ahern. Reported-by: Jianlin Shi Signed-off-by: Stefano Brivio Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_semantics.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 38c1c979ecb1..7e7b7a3efa99 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -640,6 +640,11 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) fi->fib_nh, cfg)) return 1; } +#ifdef CONFIG_IP_ROUTE_CLASSID + if (cfg->fc_flow && + cfg->fc_flow != fi->fib_nh->nh_tclassid) + return 1; +#endif if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) return 0; -- GitLab From 188633598e26c2ee25d0e2efb0a2f061c5666db5 Mon Sep 17 00:00:00 2001 From: Denis Du Date: Sat, 24 Feb 2018 16:51:42 -0500 Subject: [PATCH 0211/1834] hdlc_ppp: carrier detect ok, don't turn off negotiation [ Upstream commit b6c3bad1ba83af1062a7ff6986d9edc4f3d7fc8e ] Sometimes when physical lines have a just good noise to make the protocol handshaking fail, but the carrier detect still good. Then after remove of the noise, nobody will trigger this protocol to be start again to cause the link to never come back. The fix is when the carrier is still on, not terminate the protocol handshaking. Signed-off-by: Denis Du Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/hdlc_ppp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 47fdb87d3567..8a9aced850be 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -574,7 +574,10 @@ static void ppp_timer(unsigned long arg) ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, 0, NULL); proto->restart_counter--; - } else + } else if (netif_carrier_ok(proto->dev)) + ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, + 0, NULL); + else ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0, 0, NULL); break; -- GitLab From c9a3046de72a9eb8fabe70ad3f1f0751152e9be6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 22 Feb 2018 16:55:34 +0100 Subject: [PATCH 0212/1834] ipv6 sit: work around bogus gcc-8 -Wrestrict warning [ Upstream commit ca79bec237f5809a7c3c59bd41cd0880aa889966 ] gcc-8 has a new warning that detects overlapping input and output arguments in memcpy(). It triggers for sit_init_net() calling ipip6_tunnel_clone_6rd(), which is actually correct: net/ipv6/sit.c: In function 'sit_init_net': net/ipv6/sit.c:192:3: error: 'memcpy' source argument is the same as destination [-Werror=restrict] The problem here is that the logic detecting the memcpy() arguments finds them to be the same, but the conditional that tests for the input and output of ipip6_tunnel_clone_6rd() to be identical is not a compile-time constant. We know that netdev_priv(t->dev) is the same as t for a tunnel device, and comparing "dev" directly here lets the compiler figure out as well that 'dev == sitn->fb_tunnel_dev' when called from sit_init_net(), so it no longer warns. This code is old, so Cc stable to make sure that we don't get the warning for older kernels built with new gcc. Cc: Martin Sebor Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83456 Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/sit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index db6d437002a6..d4d84da28672 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -176,7 +176,7 @@ static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) #ifdef CONFIG_IPV6_SIT_6RD struct ip_tunnel *t = netdev_priv(dev); - if (t->dev == sitn->fb_tunnel_dev) { + if (dev == sitn->fb_tunnel_dev) { ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0); t->ip6rd.relay_prefix = 0; t->ip6rd.prefixlen = 16; -- GitLab From 106dc9648aa0db7b13f0c19f06b0786312a79c63 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Mon, 12 Feb 2018 21:35:31 -0800 Subject: [PATCH 0213/1834] net: fix race on decreasing number of TX queues [ Upstream commit ac5b70198adc25c73fba28de4f78adcee8f6be0b ] netif_set_real_num_tx_queues() can be called when netdev is up. That usually happens when user requests change of number of channels/rings with ethtool -L. The procedure for changing the number of queues involves resetting the qdiscs and setting dev->num_tx_queues to the new value. When the new value is lower than the old one, extra care has to be taken to ensure ordering of accesses to the number of queues vs qdisc reset. Currently the queues are reset before new dev->num_tx_queues is assigned, leaving a window of time where packets can be enqueued onto the queues going down, leading to a likely crash in the drivers, since most drivers don't check if TX skbs are assigned to an active queue. Fixes: e6484930d7c7 ("net: allocate tx queues in register_netdevice") Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index 8898618bf341..272f84ad16e0 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2199,8 +2199,11 @@ EXPORT_SYMBOL(netif_set_xps_queue); */ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) { + bool disabling; int rc; + disabling = txq < dev->real_num_tx_queues; + if (txq < 1 || txq > dev->num_tx_queues) return -EINVAL; @@ -2216,15 +2219,19 @@ int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) if (dev->num_tc) netif_setup_tc(dev, txq); - if (txq < dev->real_num_tx_queues) { + dev->real_num_tx_queues = txq; + + if (disabling) { + synchronize_net(); qdisc_reset_all_tx_gt(dev, txq); #ifdef CONFIG_XPS netif_reset_xps_queues_gt(dev, txq); #endif } + } else { + dev->real_num_tx_queues = txq; } - dev->real_num_tx_queues = txq; return 0; } EXPORT_SYMBOL(netif_set_real_num_tx_queues); -- GitLab From 06f01887683ffe76f295df9c87efdcbdb25df1d0 Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Mon, 26 Feb 2018 16:13:43 +0100 Subject: [PATCH 0214/1834] net: ipv4: don't allow setting net.ipv4.route.min_pmtu below 68 [ Upstream commit c7272c2f1229125f74f22dcdd59de9bbd804f1c8 ] According to RFC 1191 sections 3 and 4, ICMP frag-needed messages indicating an MTU below 68 should be rejected: A host MUST never reduce its estimate of the Path MTU below 68 octets. and (talking about ICMP frag-needed's Next-Hop MTU field): This field will never contain a value less than 68, since every router "must be able to forward a datagram of 68 octets without fragmentation". Furthermore, by letting net.ipv4.route.min_pmtu be set to negative values, we can end up with a very large PMTU when (-1) is cast into u32. Let's also make ip_rt_min_pmtu a u32, since it's only ever compared to unsigned ints. Reported-by: Jianlin Shi Signed-off-by: Sabrina Dubroca Reviewed-by: Stefano Brivio Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/route.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7ac319222558..4c9fbf4f5905 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -126,10 +126,13 @@ static int ip_rt_redirect_silence __read_mostly = ((HZ / 50) << (9 + 1)); static int ip_rt_error_cost __read_mostly = HZ; static int ip_rt_error_burst __read_mostly = 5 * HZ; static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; -static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; +static u32 ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; static int ip_rt_min_advmss __read_mostly = 256; static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; + +static int ip_min_valid_pmtu __read_mostly = IPV4_MIN_MTU; + /* * Interface to generic destination cache. */ @@ -2772,7 +2775,8 @@ static struct ctl_table ipv4_route_table[] = { .data = &ip_rt_min_pmtu, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_dointvec, + .proc_handler = proc_dointvec_minmax, + .extra1 = &ip_min_valid_pmtu, }, { .procname = "min_adv_mss", -- GitLab From 59e105c4cf0640971f82077432d6c3269804f3e7 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 6 Feb 2018 14:48:32 +0100 Subject: [PATCH 0215/1834] netlink: ensure to loop over all netns in genlmsg_multicast_allns() [ Upstream commit cb9f7a9a5c96a773bbc9c70660dc600cfff82f82 ] Nowadays, nlmsg_multicast() returns only 0 or -ESRCH but this was not the case when commit 134e63756d5f was pushed. However, there was no reason to stop the loop if a netns does not have listeners. Returns -ESRCH only if there was no listeners in all netns. To avoid having the same problem in the future, I didn't take the assumption that nlmsg_multicast() returns only 0 or -ESRCH. Fixes: 134e63756d5f ("genetlink: make netns aware") CC: Johannes Berg Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/genetlink.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 49c28e8ef01b..11702016c900 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1103,6 +1103,7 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, { struct sk_buff *tmp; struct net *net, *prev = NULL; + bool delivered = false; int err; for_each_net_rcu(net) { @@ -1114,14 +1115,21 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, } err = nlmsg_multicast(prev->genl_sock, tmp, portid, group, flags); - if (err) + if (!err) + delivered = true; + else if (err != -ESRCH) goto error; } prev = net; } - return nlmsg_multicast(prev->genl_sock, skb, portid, group, flags); + err = nlmsg_multicast(prev->genl_sock, skb, portid, group, flags); + if (!err) + delivered = true; + else if (err != -ESRCH) + goto error; + return delivered ? 0 : -ESRCH; error: kfree_skb(skb); return err; -- GitLab From 3741c8fad871b77ccc31f2255047ac0e71b8cb15 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Fri, 2 Mar 2018 18:41:16 +0100 Subject: [PATCH 0216/1834] ppp: prevent unregistered channels from connecting to PPP units [ Upstream commit 77f840e3e5f09c6d7d727e85e6e08276dd813d11 ] PPP units don't hold any reference on the channels connected to it. It is the channel's responsibility to ensure that it disconnects from its unit before being destroyed. In practice, this is ensured by ppp_unregister_channel() disconnecting the channel from the unit before dropping a reference on the channel. However, it is possible for an unregistered channel to connect to a PPP unit: register a channel with ppp_register_net_channel(), attach a /dev/ppp file to it with ioctl(PPPIOCATTCHAN), unregister the channel with ppp_unregister_channel() and finally connect the /dev/ppp file to a PPP unit with ioctl(PPPIOCCONNECT). Once in this situation, the channel is only held by the /dev/ppp file, which can be released at anytime and free the channel without letting the parent PPP unit know. Then the ppp structure ends up with dangling pointers in its ->channels list. Prevent this scenario by forbidding unregistered channels from connecting to PPP units. This maintains the code logic by keeping ppp_unregister_channel() responsible from disconnecting the channel if necessary and avoids modification on the reference counting mechanism. This issue seems to predate git history (successfully reproduced on Linux 2.6.26 and earlier PPP commits are unrelated). Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/ppp_generic.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index fc4c2ccc3d22..114457921890 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -3157,6 +3157,15 @@ ppp_connect_channel(struct channel *pch, int unit) goto outl; ppp_lock(ppp); + spin_lock_bh(&pch->downl); + if (!pch->chan) { + /* Don't connect unregistered channels */ + spin_unlock_bh(&pch->downl); + ppp_unlock(ppp); + ret = -ENOTCONN; + goto outl; + } + spin_unlock_bh(&pch->downl); if (pch->file.hdrlen > ppp->file.hdrlen) ppp->file.hdrlen = pch->file.hdrlen; hdrlen = pch->file.hdrlen + 2; /* for protocol bytes */ -- GitLab From 5984901390079ef0c393cbd4db96392c0af7db9f Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Thu, 15 Feb 2018 20:18:43 +0300 Subject: [PATCH 0217/1834] udplite: fix partial checksum initialization [ Upstream commit 15f35d49c93f4fa9875235e7bf3e3783d2dd7a1b ] Since UDP-Lite is always using checksum, the following path is triggered when calculating pseudo header for it: udp4_csum_init() or udp6_csum_init() skb_checksum_init_zero_check() __skb_checksum_validate_complete() The problem can appear if skb->len is less than CHECKSUM_BREAK. In this particular case __skb_checksum_validate_complete() also invokes __skb_checksum_complete(skb). If UDP-Lite is using partial checksum that covers only part of a packet, the function will return bad checksum and the packet will be dropped. It can be fixed if we skip skb_checksum_init_zero_check() and only set the required pseudo header checksum for UDP-Lite with partial checksum before udp4_csum_init()/udp6_csum_init() functions return. Fixes: ed70fcfcee95 ("net: Call skb_checksum_init in IPv4") Fixes: e4f45b7f40bd ("net: Call skb_checksum_init in IPv6") Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/udplite.h | 1 + net/ipv4/udp.c | 5 +++++ net/ipv6/ip6_checksum.c | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/include/net/udplite.h b/include/net/udplite.h index 80761938b9a7..8228155b305e 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -62,6 +62,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) UDP_SKB_CB(skb)->cscov = cscov; if (skb->ip_summed == CHECKSUM_COMPLETE) skb->ip_summed = CHECKSUM_NONE; + skb->csum_valid = 0; } return 0; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index bef4a94ce1a0..4cd943096afa 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1713,6 +1713,11 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, err = udplite_checksum_init(skb, uh); if (err) return err; + + if (UDP_SKB_CB(skb)->partial_cov) { + skb->csum = inet_compute_pseudo(skb, proto); + return 0; + } } /* Note, we are only interested in != 0 or == 0, thus the diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c index c0cbcb259f5a..1dc023ca98fd 100644 --- a/net/ipv6/ip6_checksum.c +++ b/net/ipv6/ip6_checksum.c @@ -72,6 +72,11 @@ int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) err = udplite_checksum_init(skb, uh); if (err) return err; + + if (UDP_SKB_CB(skb)->partial_cov) { + skb->csum = ip6_compute_pseudo(skb, proto); + return 0; + } } /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) -- GitLab From 3812dda05c8d5c171970c2bcb7da5081f2392334 Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Mon, 5 Feb 2018 21:48:14 +0200 Subject: [PATCH 0218/1834] sctp: fix dst refcnt leak in sctp_v4_get_dst [ Upstream commit 4a31a6b19f9ddf498c81f5c9b089742b7472a6f8 ] Fix dst reference count leak in sctp_v4_get_dst() introduced in commit 410f03831 ("sctp: add routing output fallback"): When walking the address_list, successive ip_route_output_key() calls may return the same rt->dst with the reference incremented on each call. The code would not decrement the dst refcount when the dst pointer was identical from the previous iteration, causing the dst refcnt leak. Testcase: ip netns add TEST ip netns exec TEST ip link set lo up ip link add dummy0 type dummy ip link add dummy1 type dummy ip link add dummy2 type dummy ip link set dev dummy0 netns TEST ip link set dev dummy1 netns TEST ip link set dev dummy2 netns TEST ip netns exec TEST ip addr add 192.168.1.1/24 dev dummy0 ip netns exec TEST ip link set dummy0 up ip netns exec TEST ip addr add 192.168.1.2/24 dev dummy1 ip netns exec TEST ip link set dummy1 up ip netns exec TEST ip addr add 192.168.1.3/24 dev dummy2 ip netns exec TEST ip link set dummy2 up ip netns exec TEST sctp_test -H 192.168.1.2 -P 20002 -h 192.168.1.1 -p 20000 -s -B 192.168.1.3 ip netns del TEST In 4.4 and 4.9 kernels this results to: [ 354.179591] unregister_netdevice: waiting for lo to become free. Usage count = 1 [ 364.419674] unregister_netdevice: waiting for lo to become free. Usage count = 1 [ 374.663664] unregister_netdevice: waiting for lo to become free. Usage count = 1 [ 384.903717] unregister_netdevice: waiting for lo to become free. Usage count = 1 [ 395.143724] unregister_netdevice: waiting for lo to become free. Usage count = 1 [ 405.383645] unregister_netdevice: waiting for lo to become free. Usage count = 1 ... Fixes: 410f03831 ("sctp: add routing output fallback") Fixes: 0ca50d12f ("sctp: fix src address selection if using secondary addresses") Signed-off-by: Tommi Rantala Acked-by: Marcelo Ricardo Leitner Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/protocol.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 7b523e3f551f..fb7b7632316a 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -510,22 +510,20 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, if (IS_ERR(rt)) continue; - if (!dst) - dst = &rt->dst; - /* Ensure the src address belongs to the output * interface. */ odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr, false); if (!odev || odev->ifindex != fl4->flowi4_oif) { - if (&rt->dst != dst) + if (!dst) + dst = &rt->dst; + else dst_release(&rt->dst); continue; } - if (dst != &rt->dst) - dst_release(dst); + dst_release(dst); dst = &rt->dst; break; } -- GitLab From 804e337023e644c5d3ac5d23a9a9c2904e1331e3 Mon Sep 17 00:00:00 2001 From: Shalom Toledo Date: Thu, 1 Mar 2018 11:37:05 +0100 Subject: [PATCH 0219/1834] mlxsw: spectrum_switchdev: Check success of FDB add operation [ Upstream commit 0a8a1bf17e3af34f1f8d2368916a6327f8b3bfd5 ] Until now, we assumed that in case of error when adding FDB entries, the write operation will fail, but this is not the case. Instead, we need to check that the number of entries reported in the response is equal to the number of entries specified in the request. Fixes: 56ade8fe3fe1 ("mlxsw: spectrum: Add initial support for Spectrum ASIC") Reported-by: Ido Schimmel Signed-off-by: Shalom Toledo Reviewed-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- .../mellanox/mlxsw/spectrum_switchdev.c | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index 1e2c8eca3af1..bea9ae31a769 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -809,6 +809,7 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, bool dynamic) { char *sfd_pl; + u8 num_rec; int err; sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); @@ -818,9 +819,16 @@ static int __mlxsw_sp_port_fdb_uc_op(struct mlxsw_sp *mlxsw_sp, u8 local_port, mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); mlxsw_reg_sfd_uc_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), mac, fid, action, local_port); + num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); - kfree(sfd_pl); + if (err) + goto out; + + if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) + err = -EBUSY; +out: + kfree(sfd_pl); return err; } @@ -845,6 +853,7 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, bool adding, bool dynamic) { char *sfd_pl; + u8 num_rec; int err; sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); @@ -855,9 +864,16 @@ static int mlxsw_sp_port_fdb_uc_lag_op(struct mlxsw_sp *mlxsw_sp, u16 lag_id, mlxsw_reg_sfd_uc_lag_pack(sfd_pl, 0, mlxsw_sp_sfd_rec_policy(dynamic), mac, fid, MLXSW_REG_SFD_REC_ACTION_NOP, lag_vid, lag_id); + num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); - kfree(sfd_pl); + if (err) + goto out; + + if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) + err = -EBUSY; +out: + kfree(sfd_pl); return err; } @@ -891,6 +907,7 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, u16 fid, u16 mid, bool adding) { char *sfd_pl; + u8 num_rec; int err; sfd_pl = kmalloc(MLXSW_REG_SFD_LEN, GFP_KERNEL); @@ -900,7 +917,15 @@ static int mlxsw_sp_port_mdb_op(struct mlxsw_sp *mlxsw_sp, const char *addr, mlxsw_reg_sfd_pack(sfd_pl, mlxsw_sp_sfd_op(adding), 0); mlxsw_reg_sfd_mc_pack(sfd_pl, 0, addr, fid, MLXSW_REG_SFD_REC_ACTION_NOP, mid); + num_rec = mlxsw_reg_sfd_num_rec_get(sfd_pl); err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(sfd), sfd_pl); + if (err) + goto out; + + if (num_rec != mlxsw_reg_sfd_num_rec_get(sfd_pl)) + err = -EBUSY; + +out: kfree(sfd_pl); return err; } -- GitLab From 19d32133abf960fb49ebb423390f6d8b238423eb Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 8 Feb 2018 21:01:48 +0100 Subject: [PATCH 0220/1834] net: phy: fix phy_start to consider PHY_IGNORE_INTERRUPT [ Upstream commit 08f5138512180a479ce6b9d23b825c9f4cd3be77 ] This condition wasn't adjusted when PHY_IGNORE_INTERRUPT (-2) was added long ago. In case of PHY_IGNORE_INTERRUPT the MAC interrupt indicates also PHY state changes and we should do what the symbol says. Fixes: 84a527a41f38 ("net: phylib: fix interrupts re-enablement in phy_start") Signed-off-by: Heiner Kallweit Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 6e12401b5102..e2d9ca60e467 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -925,7 +925,7 @@ void phy_start(struct phy_device *phydev) break; case PHY_HALTED: /* make sure interrupts are re-enabled for the PHY */ - if (phydev->irq != PHY_POLL) { + if (phy_interrupt_is_valid(phydev)) { err = phy_enable_interrupts(phydev); if (err < 0) break; -- GitLab From 3efb90ae51210e4ba7d39f6cae297676541dc2d0 Mon Sep 17 00:00:00 2001 From: Ilya Lesokhin Date: Mon, 12 Feb 2018 12:57:04 +0200 Subject: [PATCH 0221/1834] tcp: Honor the eor bit in tcp_mtu_probe [ Upstream commit 808cf9e38cd7923036a99f459ccc8cf2955e47af ] Avoid SKB coalescing if eor bit is set in one of the relevant SKBs. Fixes: c134ecb87817 ("tcp: Make use of MSG_EOR in tcp_sendmsg") Signed-off-by: Ilya Lesokhin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_output.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 3d7b59ecc76c..b29f21fbce38 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1907,6 +1907,24 @@ static inline void tcp_mtu_check_reprobe(struct sock *sk) } } +static bool tcp_can_coalesce_send_queue_head(struct sock *sk, int len) +{ + struct sk_buff *skb, *next; + + skb = tcp_send_head(sk); + tcp_for_write_queue_from_safe(skb, next, sk) { + if (len <= skb->len) + break; + + if (unlikely(TCP_SKB_CB(skb)->eor)) + return false; + + len -= skb->len; + } + + return true; +} + /* Create a new MTU probe if we are ready. * MTU probe is regularly attempting to increase the path MTU by * deliberately sending larger packets. This discovers routing @@ -1979,6 +1997,9 @@ static int tcp_mtu_probe(struct sock *sk) return 0; } + if (!tcp_can_coalesce_send_queue_head(sk, probe_size)) + return -1; + /* We're allowed to probe. Build it now. */ nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false); if (!nskb) @@ -2014,6 +2035,10 @@ static int tcp_mtu_probe(struct sock *sk) /* We've eaten all the data from this skb. * Throw it away. */ TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags; + /* If this is the last SKB we copy and eor is set + * we need to propagate it to the new skb. + */ + TCP_SKB_CB(nskb)->eor = TCP_SKB_CB(skb)->eor; tcp_unlink_write_queue(skb, sk); sk_wmem_free_skb(sk, skb); } else { -- GitLab From 85924b81ecb078dfafa109eb9db90eff7d7a81a7 Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 22 Feb 2018 14:38:14 +0000 Subject: [PATCH 0222/1834] rxrpc: Fix send in rxrpc_send_data_packet() [ Upstream commit 93c62c45ed5fad1b87e3a45835b251cd68de9c46 ] All the kernel_sendmsg() calls in rxrpc_send_data_packet() need to send both parts of the iov[] buffer, but one of them does not. Fix it so that it does. Without this, short IPv6 rxrpc DATA packets may be seen that have the rxrpc header included, but no payload. Fixes: 5a924b8951f8 ("rxrpc: Don't store the rxrpc header in the Tx queue sk_buffs") Reported-by: Marc Dionne Signed-off-by: David Howells Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rxrpc/output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rxrpc/output.c b/net/rxrpc/output.c index 5dab1ff3a6c2..59d328603312 100644 --- a/net/rxrpc/output.c +++ b/net/rxrpc/output.c @@ -391,7 +391,7 @@ int rxrpc_send_data_packet(struct rxrpc_call *call, struct sk_buff *skb, (char *)&opt, sizeof(opt)); if (ret == 0) { ret = kernel_sendmsg(conn->params.local->socket, &msg, - iov, 1, iov[0].iov_len); + iov, 2, len); opt = IPV6_PMTUDISC_DO; kernel_setsockopt(conn->params.local->socket, -- GitLab From 45fa6615258e0c01e574333f2b2a94425788f3f2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Feb 2018 06:43:03 -0800 Subject: [PATCH 0223/1834] tcp_bbr: better deal with suboptimal GSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 350c9f484bde93ef229682eedd98cd5f74350f7f ] BBR uses tcp_tso_autosize() in an attempt to probe what would be the burst sizes and to adjust cwnd in bbr_target_cwnd() with following gold formula : /* Allow enough full-sized skbs in flight to utilize end systems. */ cwnd += 3 * bbr->tso_segs_goal; But GSO can be lacking or be constrained to very small units (ip link set dev ... gso_max_segs 2) What we really want is to have enough packets in flight so that both GSO and GRO are efficient. So in the case GSO is off or downgraded, we still want to have the same number of packets in flight as if GSO/TSO was fully operational, so that GRO can hopefully be working efficiently. To fix this issue, we make tcp_tso_autosize() unaware of sk->sk_gso_max_segs Only tcp_tso_segs() has to enforce the gso_max_segs limit. Tested: ethtool -K eth0 tso off gso off tc qd replace dev eth0 root pfifo_fast Before patch: for f in {1..5}; do ./super_netperf 1 -H lpaa24 -- -K bbr; done     691  (ss -temoi shows cwnd is stuck around 6 )     667     651     631     517 After patch : # for f in {1..5}; do ./super_netperf 1 -H lpaa24 -- -K bbr; done    1733 (ss -temoi shows cwnd is around 386 )    1778    1746    1781    1718 Fixes: 0f8782ea1497 ("tcp_bbr: add BBR congestion control") Signed-off-by: Eric Dumazet Reported-by: Oleksandr Natalenko Acked-by: Neal Cardwell Acked-by: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_output.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b29f21fbce38..a69606031e5f 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1580,7 +1580,7 @@ u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, */ segs = max_t(u32, bytes / mss_now, min_tso_segs); - return min_t(u32, segs, sk->sk_gso_max_segs); + return segs; } EXPORT_SYMBOL(tcp_tso_autosize); @@ -1592,8 +1592,10 @@ static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; u32 tso_segs = ca_ops->tso_segs_goal ? ca_ops->tso_segs_goal(sk) : 0; - return tso_segs ? : - tcp_tso_autosize(sk, mss_now, sysctl_tcp_min_tso_segs); + if (!tso_segs) + tso_segs = tcp_tso_autosize(sk, mss_now, + sysctl_tcp_min_tso_segs); + return min_t(u32, tso_segs, sk->sk_gso_max_segs); } /* Returns the portion of skb which can be sent right away */ -- GitLab From a818270c30685bc22033b1af2f7d72f72b052602 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Mon, 5 Feb 2018 15:10:35 +0300 Subject: [PATCH 0224/1834] sctp: fix dst refcnt leak in sctp_v6_get_dst() [ Upstream commit 957d761cf91cdbb175ad7d8f5472336a4d54dbf2 ] When going through the bind address list in sctp_v6_get_dst() and the previously found address is better ('matchlen > bmatchlen'), the code continues to the next iteration without releasing currently held destination. Fix it by releasing 'bdst' before continue to the next iteration, and instead of introducing one more '!IS_ERR(bdst)' check for dst_release(), move the already existed one right after ip6_dst_lookup_flow(), i.e. we shouldn't proceed further if we get an error for the route lookup. Fixes: dbc2b5e9a09e ("sctp: fix src address selection if using secondary addresses for ipv6") Signed-off-by: Alexey Kodanev Acked-by: Neil Horman Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/ipv6.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 5d015270e454..11f69d4c5619 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -324,8 +324,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); bdst = ip6_dst_lookup_flow(sk, fl6, final_p); - if (!IS_ERR(bdst) && - ipv6_chk_addr(dev_net(bdst->dev), + if (IS_ERR(bdst)) + continue; + + if (ipv6_chk_addr(dev_net(bdst->dev), &laddr->a.v6.sin6_addr, bdst->dev, 1)) { if (!IS_ERR_OR_NULL(dst)) dst_release(dst); @@ -334,8 +336,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, } bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); - if (matchlen > bmatchlen) + if (matchlen > bmatchlen) { + dst_release(bdst); continue; + } if (!IS_ERR_OR_NULL(dst)) dst_release(dst); -- GitLab From 8d072588de679ef1593f67d8d4de7184111efa4f Mon Sep 17 00:00:00 2001 From: Ursula Braun Date: Fri, 9 Feb 2018 11:03:49 +0100 Subject: [PATCH 0225/1834] s390/qeth: fix underestimated count of buffer elements [ Upstream commit 89271c65edd599207dd982007900506283c90ae3 ] For a memory range/skb where the last byte falls onto a page boundary (ie. 'end' is of the form xxx...xxx001), the PFN_UP() part of the calculation currently doesn't round up to the next PFN due to an off-by-one error. Thus qeth believes that the skb occupies one page less than it actually does, and may select a IO buffer that doesn't have enough spare buffer elements to fit all of the skb's data. HW detects this as a malformed buffer descriptor, and raises an exception which then triggers device recovery. Fixes: 2863c61334aa ("qeth: refactor calculation of SBALE count") Signed-off-by: Ursula Braun Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 9b5fc502f6a1..2fe218101c46 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -849,7 +849,7 @@ struct qeth_trap_id { */ static inline int qeth_get_elements_for_range(addr_t start, addr_t end) { - return PFN_UP(end - 1) - PFN_DOWN(start); + return PFN_UP(end) - PFN_DOWN(start); } static inline int qeth_get_micros(void) -- GitLab From 3c0718711177865020e89a714f062b6403ff78e5 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Fri, 9 Feb 2018 11:03:50 +0100 Subject: [PATCH 0226/1834] s390/qeth: fix SETIP command handling [ Upstream commit 1c5b2216fbb973a9410e0b06389740b5c1289171 ] send_control_data() applies some special handling to SETIP v4 IPA commands. But current code parses *all* command types for the SETIP command code. Limit the command code check to IPA commands. Fixes: 5b54e16f1a54 ("qeth: do not spin for SETIP ip assist command") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core.h | 5 +++++ drivers/s390/net/qeth_core_main.c | 14 ++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 2fe218101c46..403712bf1ddf 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -592,6 +592,11 @@ struct qeth_cmd_buffer { void (*callback) (struct qeth_channel *, struct qeth_cmd_buffer *); }; +static inline struct qeth_ipa_cmd *__ipa_cmd(struct qeth_cmd_buffer *iob) +{ + return (struct qeth_ipa_cmd *)(iob->data + IPA_PDU_HEADER_SIZE); +} + /** * definition of a qeth channel, used for read and write */ diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index df8f74cb1406..ca514e475096 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2050,7 +2050,7 @@ int qeth_send_control_data(struct qeth_card *card, int len, unsigned long flags; struct qeth_reply *reply = NULL; unsigned long timeout, event_timeout; - struct qeth_ipa_cmd *cmd; + struct qeth_ipa_cmd *cmd = NULL; QETH_CARD_TEXT(card, 2, "sendctl"); @@ -2077,10 +2077,13 @@ int qeth_send_control_data(struct qeth_card *card, int len, while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; qeth_prepare_control_data(card, len, iob); - if (IS_IPA(iob->data)) + if (IS_IPA(iob->data)) { + cmd = __ipa_cmd(iob); event_timeout = QETH_IPA_TIMEOUT; - else + } else { event_timeout = QETH_TIMEOUT; + } + timeout = jiffies + event_timeout; QETH_CARD_TEXT(card, 6, "noirqpnd"); @@ -2105,9 +2108,8 @@ int qeth_send_control_data(struct qeth_card *card, int len, /* we have only one long running ipassist, since we can ensure process context of this command we can sleep */ - cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); - if ((cmd->hdr.command == IPA_CMD_SETIP) && - (cmd->hdr.prot_version == QETH_PROT_IPV4)) { + if (cmd && cmd->hdr.command == IPA_CMD_SETIP && + cmd->hdr.prot_version == QETH_PROT_IPV4) { if (!wait_event_timeout(reply->wait_q, atomic_read(&reply->received), event_timeout)) goto time_err; -- GitLab From 797658d05e40486104312a28abf1ac37e6479e14 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:12 +0100 Subject: [PATCH 0227/1834] s390/qeth: fix overestimated count of buffer elements [ Upstream commit 12472af89632beb1ed8dea29d4efe208ca05b06a ] qeth_get_elements_for_range() doesn't know how to handle a 0-length range (ie. start == end), and returns 1 when it should return 0. Such ranges occur on TSO skbs, where the L2/L3/L4 headers (and thus all of the skb's linear data) are skipped when mapping the skb into regular buffer elements. This overestimation may cause several performance-related issues: 1. sub-optimal IO buffer selection, where the next buffer gets selected even though the skb would actually still fit into the current buffer. 2. forced linearization, if the element count for a non-linear skb exceeds QETH_MAX_BUFFER_ELEMENTS. Rather than modifying qeth_get_elements_for_range() and adding overhead to every caller, fix up those callers that are in risk of passing a 0-length range. Fixes: 2863c61334aa ("qeth: refactor calculation of SBALE count") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core_main.c | 10 ++++++---- drivers/s390/net/qeth_l3_main.c | 11 ++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index ca514e475096..fb0ba3c48e3d 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3854,10 +3854,12 @@ EXPORT_SYMBOL_GPL(qeth_get_elements_for_frags); int qeth_get_elements_no(struct qeth_card *card, struct sk_buff *skb, int extra_elems, int data_offset) { - int elements = qeth_get_elements_for_range( - (addr_t)skb->data + data_offset, - (addr_t)skb->data + skb_headlen(skb)) + - qeth_get_elements_for_frags(skb); + addr_t end = (addr_t)skb->data + skb_headlen(skb); + int elements = qeth_get_elements_for_frags(skb); + addr_t start = (addr_t)skb->data + data_offset; + + if (start != end) + elements += qeth_get_elements_for_range(start, end); if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { QETH_DBF_MESSAGE(2, "Invalid size of IP packet " diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 1487f8a0c575..34400ff018af 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2784,11 +2784,12 @@ static void qeth_tso_fill_header(struct qeth_card *card, static int qeth_l3_get_elements_no_tso(struct qeth_card *card, struct sk_buff *skb, int extra_elems) { - addr_t tcpdptr = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); - int elements = qeth_get_elements_for_range( - tcpdptr, - (addr_t)skb->data + skb_headlen(skb)) + - qeth_get_elements_for_frags(skb); + addr_t start = (addr_t)tcp_hdr(skb) + tcp_hdrlen(skb); + addr_t end = (addr_t)skb->data + skb_headlen(skb); + int elements = qeth_get_elements_for_frags(skb); + + if (start != end) + elements += qeth_get_elements_for_range(start, end); if ((elements + extra_elems) > QETH_MAX_BUFFER_ELEMENTS(card)) { QETH_DBF_MESSAGE(2, -- GitLab From 1537f144ac065b571c4d2c1969a389e138f06150 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:13 +0100 Subject: [PATCH 0228/1834] s390/qeth: fix IP removal on offline cards [ Upstream commit 98d823ab1fbdcb13abc25b420f9bb71bade42056 ] If the HW is not reachable, then none of the IPs in qeth's internal table has been registered with the HW yet. So when deleting such an IP, there's no need to stage it for deregistration - just drop it from the table. This fixes the "add-delete-add" scenario on an offline card, where the the second "add" merely increments the IP's use count. But as the IP is still set to DISP_ADDR_DELETE from the previous "delete" step, l3_recover_ip() won't register it with the HW when the card goes online. Fixes: 5f78e29ceebf ("qeth: optimize IP handling in rx_mode callback") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_l3_main.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 34400ff018af..e91693de86bb 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -259,12 +259,8 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) if (addr->in_progress) return -EINPROGRESS; - if (!qeth_card_hw_is_reachable(card)) { - addr->disp_flag = QETH_DISP_ADDR_DELETE; - return 0; - } - - rc = qeth_l3_deregister_addr_entry(card, addr); + if (qeth_card_hw_is_reachable(card)) + rc = qeth_l3_deregister_addr_entry(card, addr); hash_del(&addr->hnode); kfree(addr); @@ -406,11 +402,7 @@ static void qeth_l3_recover_ip(struct qeth_card *card) spin_lock_bh(&card->ip_lock); hash_for_each_safe(card->ip_htable, i, tmp, addr, hnode) { - if (addr->disp_flag == QETH_DISP_ADDR_DELETE) { - qeth_l3_deregister_addr_entry(card, addr); - hash_del(&addr->hnode); - kfree(addr); - } else if (addr->disp_flag == QETH_DISP_ADDR_ADD) { + if (addr->disp_flag == QETH_DISP_ADDR_ADD) { if (addr->proto == QETH_PROT_IPV4) { addr->in_progress = 1; spin_unlock_bh(&card->ip_lock); -- GitLab From 2a3db8370ae36bb884512e35bd559e07bf4148df Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:14 +0100 Subject: [PATCH 0229/1834] s390/qeth: fix double-free on IP add/remove race [ Upstream commit 14d066c3531a87f727968cacd85bd95c75f59843 ] Registering an IPv4 address with the HW takes quite a while, so we temporarily drop the ip_htable lock. Any concurrent add/remove of the same IP adjusts the IP's use count, and (on remove) is then blocked by addr->in_progress. After the register call has completed, we check the use count for concurrently attempted add/remove calls - and possibly straight-away deregister the IP again. This happens via l3_delete_ip(), which 1) looks up the queried IP in the htable (getting a reference to the *same* queried object), 2) deregisters the IP from the HW, and 3) frees the IP object. The caller in l3_add_ip() then does a second free on the same object. For this case, skip all the extra checks and lookups in l3_delete_ip() and just deregister & free the IP object ourselves. Fixes: 5f78e29ceebf ("qeth: optimize IP handling in rx_mode callback") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_l3_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index e91693de86bb..d7505a114d1d 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -323,7 +323,8 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) (rc == IPA_RC_LAN_OFFLINE)) { addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; if (addr->ref_counter < 1) { - qeth_l3_delete_ip(card, addr); + qeth_l3_deregister_addr_entry(card, addr); + hash_del(&addr->hnode); kfree(addr); } } else { -- GitLab From 058db71dd8d68973e3add8b5a355036ddc13b460 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:16 +0100 Subject: [PATCH 0230/1834] s390/qeth: fix IP address lookup for L3 devices [ Upstream commit c5c48c58b259bb8f0482398370ee539d7a12df3e ] Current code ("qeth_l3_ip_from_hash()") matches a queried address object against objects in the IP table by IP address, Mask/Prefix Length and MAC address ("qeth_l3_ipaddrs_is_equal()"). But what callers actually require is either a) "is this IP address registered" (ie. match by IP address only), before adding a new address. b) or "is this address object registered" (ie. match all relevant attributes), before deleting an address. Right now 1. the ADD path is too strict in its lookup, and eg. doesn't detect conflicts between an existing NORMAL address and a new VIPA address (because the NORMAL address will have mask != 0, while VIPA has a mask == 0), 2. the DELETE path is not strict enough, and eg. allows del_rxip() to delete a VIPA address as long as the IP address matches. Fix all this by adding helpers (_addr_match_ip() and _addr_match_all()) that do the appropriate checking. Note that the ADD path for NORMAL addresses is special, as qeth keeps track of how many times such an address is in use (and there is no immediate way of returning errors to the caller). So when a requested NORMAL address _fully_ matches an existing one, it's not considered a conflict and we merely increment the refcount. Fixes: 5f78e29ceebf ("qeth: optimize IP handling in rx_mode callback") Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_l3.h | 34 +++++++++++- drivers/s390/net/qeth_l3_main.c | 91 +++++++++++++++------------------ 2 files changed, 74 insertions(+), 51 deletions(-) diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index eedf9b01a496..573569474e44 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h @@ -39,8 +39,40 @@ struct qeth_ipaddr { unsigned int pfxlen; } a6; } u; - }; + +static inline bool qeth_l3_addr_match_ip(struct qeth_ipaddr *a1, + struct qeth_ipaddr *a2) +{ + if (a1->proto != a2->proto) + return false; + if (a1->proto == QETH_PROT_IPV6) + return ipv6_addr_equal(&a1->u.a6.addr, &a2->u.a6.addr); + return a1->u.a4.addr == a2->u.a4.addr; +} + +static inline bool qeth_l3_addr_match_all(struct qeth_ipaddr *a1, + struct qeth_ipaddr *a2) +{ + /* Assumes that the pair was obtained via qeth_l3_addr_find_by_ip(), + * so 'proto' and 'addr' match for sure. + * + * For ucast: + * - 'mac' is always 0. + * - 'mask'/'pfxlen' for RXIP/VIPA is always 0. For NORMAL, matching + * values are required to avoid mixups in takeover eligibility. + * + * For mcast, + * - 'mac' is mapped from the IP, and thus always matches. + * - 'mask'/'pfxlen' is always 0. + */ + if (a1->type != a2->type) + return false; + if (a1->proto == QETH_PROT_IPV6) + return a1->u.a6.pfxlen == a2->u.a6.pfxlen; + return a1->u.a4.mask == a2->u.a4.mask; +} + static inline u64 qeth_l3_ipaddr_hash(struct qeth_ipaddr *addr) { u64 ret = 0; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index d7505a114d1d..a668e6b71a29 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -154,6 +154,24 @@ int qeth_l3_string_to_ipaddr(const char *buf, enum qeth_prot_versions proto, return -EINVAL; } +static struct qeth_ipaddr *qeth_l3_find_addr_by_ip(struct qeth_card *card, + struct qeth_ipaddr *query) +{ + u64 key = qeth_l3_ipaddr_hash(query); + struct qeth_ipaddr *addr; + + if (query->is_multicast) { + hash_for_each_possible(card->ip_mc_htable, addr, hnode, key) + if (qeth_l3_addr_match_ip(addr, query)) + return addr; + } else { + hash_for_each_possible(card->ip_htable, addr, hnode, key) + if (qeth_l3_addr_match_ip(addr, query)) + return addr; + } + return NULL; +} + static void qeth_l3_convert_addr_to_bits(u8 *addr, u8 *bits, int len) { int i, j; @@ -207,34 +225,6 @@ static bool qeth_l3_is_addr_covered_by_ipato(struct qeth_card *card, return rc; } -inline int -qeth_l3_ipaddrs_is_equal(struct qeth_ipaddr *addr1, struct qeth_ipaddr *addr2) -{ - return addr1->proto == addr2->proto && - !memcmp(&addr1->u, &addr2->u, sizeof(addr1->u)) && - !memcmp(&addr1->mac, &addr2->mac, sizeof(addr1->mac)); -} - -static struct qeth_ipaddr * -qeth_l3_ip_from_hash(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) -{ - struct qeth_ipaddr *addr; - - if (tmp_addr->is_multicast) { - hash_for_each_possible(card->ip_mc_htable, addr, - hnode, qeth_l3_ipaddr_hash(tmp_addr)) - if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) - return addr; - } else { - hash_for_each_possible(card->ip_htable, addr, - hnode, qeth_l3_ipaddr_hash(tmp_addr)) - if (qeth_l3_ipaddrs_is_equal(tmp_addr, addr)) - return addr; - } - - return NULL; -} - int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) { int rc = 0; @@ -249,8 +239,8 @@ int qeth_l3_delete_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); } - addr = qeth_l3_ip_from_hash(card, tmp_addr); - if (!addr) + addr = qeth_l3_find_addr_by_ip(card, tmp_addr); + if (!addr || !qeth_l3_addr_match_all(addr, tmp_addr)) return -ENOENT; addr->ref_counter--; @@ -272,6 +262,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) { int rc = 0; struct qeth_ipaddr *addr; + char buf[40]; QETH_CARD_TEXT(card, 4, "addip"); @@ -282,8 +273,20 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) QETH_CARD_HEX(card, 4, ((char *)&tmp_addr->u.a6.addr) + 8, 8); } - addr = qeth_l3_ip_from_hash(card, tmp_addr); - if (!addr) { + addr = qeth_l3_find_addr_by_ip(card, tmp_addr); + if (addr) { + if (tmp_addr->type != QETH_IP_TYPE_NORMAL) + return -EADDRINUSE; + if (qeth_l3_addr_match_all(addr, tmp_addr)) { + addr->ref_counter++; + return 0; + } + qeth_l3_ipaddr_to_string(tmp_addr->proto, (u8 *)&tmp_addr->u, + buf); + dev_warn(&card->gdev->dev, + "Registering IP address %s failed\n", buf); + return -EADDRINUSE; + } else { addr = qeth_l3_get_addr_buffer(tmp_addr->proto); if (!addr) return -ENOMEM; @@ -331,11 +334,7 @@ int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) hash_del(&addr->hnode); kfree(addr); } - } else { - if (addr->type == QETH_IP_TYPE_NORMAL) - addr->ref_counter++; } - return rc; } @@ -719,12 +718,7 @@ int qeth_l3_add_vipa(struct qeth_card *card, enum qeth_prot_versions proto, return -ENOMEM; spin_lock_bh(&card->ip_lock); - - if (qeth_l3_ip_from_hash(card, ipaddr)) - rc = -EEXIST; - else - qeth_l3_add_ip(card, ipaddr); - + rc = qeth_l3_add_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); kfree(ipaddr); @@ -787,12 +781,7 @@ int qeth_l3_add_rxip(struct qeth_card *card, enum qeth_prot_versions proto, return -ENOMEM; spin_lock_bh(&card->ip_lock); - - if (qeth_l3_ip_from_hash(card, ipaddr)) - rc = -EEXIST; - else - qeth_l3_add_ip(card, ipaddr); - + rc = qeth_l3_add_ip(card, ipaddr); spin_unlock_bh(&card->ip_lock); kfree(ipaddr); @@ -1437,8 +1426,9 @@ qeth_l3_add_mc_to_hash(struct qeth_card *card, struct in_device *in4_dev) memcpy(tmp->mac, buf, sizeof(tmp->mac)); tmp->is_multicast = 1; - ipm = qeth_l3_ip_from_hash(card, tmp); + ipm = qeth_l3_find_addr_by_ip(card, tmp); if (ipm) { + /* for mcast, by-IP match means full match */ ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; } else { ipm = qeth_l3_get_addr_buffer(QETH_PROT_IPV4); @@ -1521,8 +1511,9 @@ qeth_l3_add_mc6_to_hash(struct qeth_card *card, struct inet6_dev *in6_dev) sizeof(struct in6_addr)); tmp->is_multicast = 1; - ipm = qeth_l3_ip_from_hash(card, tmp); + ipm = qeth_l3_find_addr_by_ip(card, tmp); if (ipm) { + /* for mcast, by-IP match means full match */ ipm->disp_flag = QETH_DISP_ADDR_DO_NOTHING; continue; } -- GitLab From f3d26ce9ce34c5d34a23db6ecd00e23dec82febc Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 27 Feb 2018 18:58:17 +0100 Subject: [PATCH 0231/1834] s390/qeth: fix IPA command submission race [ Upstream commit d22ffb5a712f9211ffd104c38fc17cbfb1b5e2b0 ] If multiple IPA commands are build & sent out concurrently, fill_ipacmd_header() may assign a seqno value to a command that's different from what send_control_data() later assigns to this command's reply. This is due to other commands passing through send_control_data(), and incrementing card->seqno.ipa along the way. So one IPA command has no reply that's waiting for its seqno, while some other IPA command has multiple reply objects waiting for it. Only one of those waiting replies wins, and the other(s) times out and triggers a recovery via send_ipa_cmd(). Fix this by making sure that the same seqno value is assigned to a command and its reply object. Do so immediately before submitting the command & while holding the irq_pending "lock", to produce nicely ascending seqnos. As a side effect, *all* IPA commands now use a reply object that's waiting for its actual seqno. Previously, early IPA commands that were submitted while the card was still DOWN used the "catch-all" IDX seqno. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core_main.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index fb0ba3c48e3d..cc28dda322b5 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -2064,25 +2064,26 @@ int qeth_send_control_data(struct qeth_card *card, int len, } reply->callback = reply_cb; reply->param = reply_param; - if (card->state == CARD_STATE_DOWN) - reply->seqno = QETH_IDX_COMMAND_SEQNO; - else - reply->seqno = card->seqno.ipa++; + init_waitqueue_head(&reply->wait_q); - spin_lock_irqsave(&card->lock, flags); - list_add_tail(&reply->list, &card->cmd_waiter_list); - spin_unlock_irqrestore(&card->lock, flags); QETH_DBF_HEX(CTRL, 2, iob->data, QETH_DBF_CTRL_LEN); while (atomic_cmpxchg(&card->write.irq_pending, 0, 1)) ; - qeth_prepare_control_data(card, len, iob); if (IS_IPA(iob->data)) { cmd = __ipa_cmd(iob); + cmd->hdr.seqno = card->seqno.ipa++; + reply->seqno = cmd->hdr.seqno; event_timeout = QETH_IPA_TIMEOUT; } else { + reply->seqno = QETH_IDX_COMMAND_SEQNO; event_timeout = QETH_TIMEOUT; } + qeth_prepare_control_data(card, len, iob); + + spin_lock_irqsave(&card->lock, flags); + list_add_tail(&reply->list, &card->cmd_waiter_list); + spin_unlock_irqrestore(&card->lock, flags); timeout = jiffies + event_timeout; @@ -2873,7 +2874,7 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, memset(cmd, 0, sizeof(struct qeth_ipa_cmd)); cmd->hdr.command = command; cmd->hdr.initiator = IPA_CMD_INITIATOR_HOST; - cmd->hdr.seqno = card->seqno.ipa; + /* cmd->hdr.seqno is set by qeth_send_control_data() */ cmd->hdr.adapter_type = qeth_get_ipa_adp_type(card->info.link_type); cmd->hdr.rel_adapter_no = (__u8) card->info.portno; if (card->options.layer2) -- GitLab From 9b7d723439a444ea578462f50054641a09c45023 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Fri, 9 Feb 2018 17:35:23 +0300 Subject: [PATCH 0232/1834] sctp: verify size of a new chunk in _sctp_make_chunk() [ Upstream commit 07f2c7ab6f8d0a7e7c5764c4e6cc9c52951b9d9c ] When SCTP makes INIT or INIT_ACK packet the total chunk length can exceed SCTP_MAX_CHUNK_LEN which leads to kernel panic when transmitting these packets, e.g. the crash on sending INIT_ACK: [ 597.804948] skbuff: skb_over_panic: text:00000000ffae06e4 len:120168 put:120156 head:000000007aa47635 data:00000000d991c2de tail:0x1d640 end:0xfec0 dev: ... [ 597.976970] ------------[ cut here ]------------ [ 598.033408] kernel BUG at net/core/skbuff.c:104! [ 600.314841] Call Trace: [ 600.345829] [ 600.371639] ? sctp_packet_transmit+0x2095/0x26d0 [sctp] [ 600.436934] skb_put+0x16c/0x200 [ 600.477295] sctp_packet_transmit+0x2095/0x26d0 [sctp] [ 600.540630] ? sctp_packet_config+0x890/0x890 [sctp] [ 600.601781] ? __sctp_packet_append_chunk+0x3b4/0xd00 [sctp] [ 600.671356] ? sctp_cmp_addr_exact+0x3f/0x90 [sctp] [ 600.731482] sctp_outq_flush+0x663/0x30d0 [sctp] [ 600.788565] ? sctp_make_init+0xbf0/0xbf0 [sctp] [ 600.845555] ? sctp_check_transmitted+0x18f0/0x18f0 [sctp] [ 600.912945] ? sctp_outq_tail+0x631/0x9d0 [sctp] [ 600.969936] sctp_cmd_interpreter.isra.22+0x3be1/0x5cb0 [sctp] [ 601.041593] ? sctp_sf_do_5_1B_init+0x85f/0xc30 [sctp] [ 601.104837] ? sctp_generate_t1_cookie_event+0x20/0x20 [sctp] [ 601.175436] ? sctp_eat_data+0x1710/0x1710 [sctp] [ 601.233575] sctp_do_sm+0x182/0x560 [sctp] [ 601.284328] ? sctp_has_association+0x70/0x70 [sctp] [ 601.345586] ? sctp_rcv+0xef4/0x32f0 [sctp] [ 601.397478] ? sctp6_rcv+0xa/0x20 [sctp] ... Here the chunk size for INIT_ACK packet becomes too big, mostly because of the state cookie (INIT packet has large size with many address parameters), plus additional server parameters. Later this chunk causes the panic in skb_put_data(): skb_packet_transmit() sctp_packet_pack() skb_put_data(nskb, chunk->skb->data, chunk->skb->len); 'nskb' (head skb) was previously allocated with packet->size from u16 'chunk->chunk_hdr->length'. As suggested by Marcelo we should check the chunk's length in _sctp_make_chunk() before trying to allocate skb for it and discard a chunk if its size bigger than SCTP_MAX_CHUNK_LEN. Signed-off-by: Alexey Kodanev Acked-by: Marcelo Ricardo Leitner Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/sm_make_chunk.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 9e9690b7afe1..fc67d356b5fa 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1373,9 +1373,14 @@ static struct sctp_chunk *_sctp_make_chunk(const struct sctp_association *asoc, sctp_chunkhdr_t *chunk_hdr; struct sk_buff *skb; struct sock *sk; + int chunklen; + + chunklen = SCTP_PAD4(sizeof(*chunk_hdr) + paylen); + if (chunklen > SCTP_MAX_CHUNK_LEN) + goto nodata; /* No need to allocate LL here, as this is only a chunk. */ - skb = alloc_skb(SCTP_PAD4(sizeof(sctp_chunkhdr_t) + paylen), gfp); + skb = alloc_skb(chunklen, gfp); if (!skb) goto nodata; -- GitLab From d77763dc70c4afa451b33f80013910d502bf3bb7 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 8 Mar 2018 18:36:16 +0000 Subject: [PATCH 0233/1834] net: mpls: Pull common label check into helper commit b7b386f42f079b25b942c756820e36c6bd09b2ca upstream. mpls_route_add and mpls_route_del have the same checks on the label. Move to a helper. Avoid duplicate extack messages in the next patch. Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- net/mpls/af_mpls.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index c5a5a6959c1b..3e8d1f6ac907 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -756,6 +756,19 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg, return err; } +static bool mpls_label_ok(struct net *net, unsigned int index) +{ + /* Reserved labels may not be set */ + if (index < MPLS_LABEL_FIRST_UNRESERVED) + return false; + + /* The full 20 bit range may not be supported. */ + if (index >= net->mpls.platform_labels) + return false; + + return true; +} + static int mpls_route_add(struct mpls_route_config *cfg) { struct mpls_route __rcu **platform_label; @@ -774,12 +787,7 @@ static int mpls_route_add(struct mpls_route_config *cfg) index = find_free_label(net); } - /* Reserved labels may not be set */ - if (index < MPLS_LABEL_FIRST_UNRESERVED) - goto errout; - - /* The full 20 bit range may not be supported. */ - if (index >= net->mpls.platform_labels) + if (!mpls_label_ok(net, index)) goto errout; /* Append makes no sense with mpls */ @@ -840,12 +848,7 @@ static int mpls_route_del(struct mpls_route_config *cfg) index = cfg->rc_label; - /* Reserved labels may not be removed */ - if (index < MPLS_LABEL_FIRST_UNRESERVED) - goto errout; - - /* The full 20 bit range may not be supported */ - if (index >= net->mpls.platform_labels) + if (!mpls_label_ok(net, index)) goto errout; mpls_route_update(net, index, NULL, &cfg->rc_nlinfo); @@ -1279,10 +1282,9 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh, &cfg->rc_label)) goto errout; - /* Reserved labels may not be set */ - if (cfg->rc_label < MPLS_LABEL_FIRST_UNRESERVED) + if (!mpls_label_ok(cfg->rc_nlinfo.nl_net, + cfg->rc_label)) goto errout; - break; } case RTA_VIA: -- GitLab From 93f3aff1d910c5363a42c2c18dec9939cb0d58c2 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 8 Mar 2018 18:39:24 +0000 Subject: [PATCH 0234/1834] mpls, nospec: Sanitize array index in mpls_label_ok() commit 3968523f855050b8195134da951b87c20bd66130 upstream. mpls_label_ok() validates that the 'platform_label' array index from a userspace netlink message payload is valid. Under speculation the mpls_label_ok() result may not resolve in the CPU pipeline until after the index is used to access an array element. Sanitize the index to zero to prevent userspace-controlled arbitrary out-of-bounds speculation, a precursor for a speculative execution side channel vulnerability. Cc: "David S. Miller" Cc: Eric W. Biederman Signed-off-by: Dan Williams Signed-off-by: David S. Miller [bwh: Backported to 4.4: - mpls_label_ok() doesn't take an extack parameter - Drop change in mpls_getroute()] Signed-off-by: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- net/mpls/af_mpls.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 3e8d1f6ac907..ffab94d61e1d 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -756,17 +757,20 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg, return err; } -static bool mpls_label_ok(struct net *net, unsigned int index) +static bool mpls_label_ok(struct net *net, unsigned int *index) { + bool is_ok = true; + /* Reserved labels may not be set */ - if (index < MPLS_LABEL_FIRST_UNRESERVED) - return false; + if (*index < MPLS_LABEL_FIRST_UNRESERVED) + is_ok = false; /* The full 20 bit range may not be supported. */ - if (index >= net->mpls.platform_labels) - return false; + if (is_ok && *index >= net->mpls.platform_labels) + is_ok = false; - return true; + *index = array_index_nospec(*index, net->mpls.platform_labels); + return is_ok; } static int mpls_route_add(struct mpls_route_config *cfg) @@ -787,7 +791,7 @@ static int mpls_route_add(struct mpls_route_config *cfg) index = find_free_label(net); } - if (!mpls_label_ok(net, index)) + if (!mpls_label_ok(net, &index)) goto errout; /* Append makes no sense with mpls */ @@ -848,7 +852,7 @@ static int mpls_route_del(struct mpls_route_config *cfg) index = cfg->rc_label; - if (!mpls_label_ok(net, index)) + if (!mpls_label_ok(net, &index)) goto errout; mpls_route_update(net, index, NULL, &cfg->rc_nlinfo); @@ -1283,7 +1287,7 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh, goto errout; if (!mpls_label_ok(cfg->rc_nlinfo.nl_net, - cfg->rc_label)) + &cfg->rc_label)) goto errout; break; } -- GitLab From 816cfeb77c0125c4943da725fc7f8b60d91b90a0 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 8 Mar 2018 16:17:32 +0100 Subject: [PATCH 0235/1834] bpf: fix wrong exposure of map_flags into fdinfo for lpm [ upstream commit a316338cb71a3260201490e615f2f6d5c0d8fb2c ] trie_alloc() always needs to have BPF_F_NO_PREALLOC passed in via attr->map_flags, since it does not support preallocation yet. We check the flag, but we never copy the flag into trie->map.map_flags, which is later on exposed into fdinfo and used by loaders such as iproute2. Latter uses this in bpf_map_selfcheck_pinned() to test whether a pinned map has the same spec as the one from the BPF obj file and if not, bails out, which is currently the case for lpm since it exposes always 0 as flags. Also copy over flags in array_map_alloc() and stack_map_alloc(). They always have to be 0 right now, but we should make sure to not miss to copy them over at a later point in time when we add actual flags for them to use. Fixes: b95a5c4db09b ("bpf: add a longest prefix match trie map implementation") Reported-by: Jarno Rajahalme Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller Signed-off-by: Daniel Borkmann Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/arraymap.c | 1 + kernel/bpf/stackmap.c | 1 + 2 files changed, 2 insertions(+) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 9a1e6ed7babc..3be357ab6596 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -107,6 +107,7 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) array->map.key_size = attr->key_size; array->map.value_size = attr->value_size; array->map.max_entries = attr->max_entries; + array->map.map_flags = attr->map_flags; array->elem_size = elem_size; if (!percpu) diff --git a/kernel/bpf/stackmap.c b/kernel/bpf/stackmap.c index be8519148c25..a2a232dec236 100644 --- a/kernel/bpf/stackmap.c +++ b/kernel/bpf/stackmap.c @@ -88,6 +88,7 @@ static struct bpf_map *stack_map_alloc(union bpf_attr *attr) smap->map.key_size = attr->key_size; smap->map.value_size = value_size; smap->map.max_entries = attr->max_entries; + smap->map.map_flags = attr->map_flags; smap->n_buckets = n_buckets; smap->map.pages = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; -- GitLab From 422baf61d4805a47456297a23e71d32f9f794658 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 8 Mar 2018 16:17:33 +0100 Subject: [PATCH 0236/1834] bpf: fix mlock precharge on arraymaps [ upstream commit 9c2d63b843a5c8a8d0559cc067b5398aa5ec3ffc ] syzkaller recently triggered OOM during percpu map allocation; while there is work in progress by Dennis Zhou to add __GFP_NORETRY semantics for percpu allocator under pressure, there seems also a missing bpf_map_precharge_memlock() check in array map allocation. Given today the actual bpf_map_charge_memlock() happens after the find_and_alloc_map() in syscall path, the bpf_map_precharge_memlock() is there to bail out early before we go and do the map setup work when we find that we hit the limits anyway. Therefore add this for array map as well. Fixes: 6c9059817432 ("bpf: pre-allocate hash map elements") Fixes: a10423b87a7e ("bpf: introduce BPF_MAP_TYPE_PERCPU_ARRAY map") Reported-by: syzbot+adb03f3f0bb57ce3acda@syzkaller.appspotmail.com Signed-off-by: Daniel Borkmann Cc: Dennis Zhou Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/arraymap.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 3be357ab6596..075ddb801422 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -48,8 +48,9 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) bool percpu = attr->map_type == BPF_MAP_TYPE_PERCPU_ARRAY; u32 elem_size, index_mask, max_entries; bool unpriv = !capable(CAP_SYS_ADMIN); + u64 cost, array_size, mask64; struct bpf_array *array; - u64 array_size, mask64; + int ret; /* check sanity of attributes */ if (attr->max_entries == 0 || attr->key_size != 4 || @@ -92,8 +93,19 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) array_size += (u64) max_entries * elem_size; /* make sure there is no u32 overflow later in round_up() */ - if (array_size >= U32_MAX - PAGE_SIZE) + cost = array_size; + if (cost >= U32_MAX - PAGE_SIZE) return ERR_PTR(-ENOMEM); + if (percpu) { + cost += (u64)attr->max_entries * elem_size * num_possible_cpus(); + if (cost >= U32_MAX - PAGE_SIZE) + return ERR_PTR(-ENOMEM); + } + cost = round_up(cost, PAGE_SIZE) >> PAGE_SHIFT; + + ret = bpf_map_precharge_memlock(cost); + if (ret < 0) + return ERR_PTR(ret); /* allocate all map elements and zero-initialize them */ array = bpf_map_area_alloc(array_size); @@ -108,20 +120,15 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr) array->map.value_size = attr->value_size; array->map.max_entries = attr->max_entries; array->map.map_flags = attr->map_flags; + array->map.pages = cost; array->elem_size = elem_size; - if (!percpu) - goto out; - - array_size += (u64) attr->max_entries * elem_size * num_possible_cpus(); - - if (array_size >= U32_MAX - PAGE_SIZE || - elem_size > PCPU_MIN_UNIT_SIZE || bpf_array_alloc_percpu(array)) { + if (percpu && + (elem_size > PCPU_MIN_UNIT_SIZE || + bpf_array_alloc_percpu(array))) { bpf_map_area_free(array); return ERR_PTR(-ENOMEM); } -out: - array->map.pages = round_up(array_size, PAGE_SIZE) >> PAGE_SHIFT; return &array->map; } -- GitLab From 017219b598b4804ae23eb1447d24da13030c3fb2 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 8 Mar 2018 16:17:34 +0100 Subject: [PATCH 0237/1834] bpf, x64: implement retpoline for tail call [ upstream commit a493a87f38cfa48caaa95c9347be2d914c6fdf29 ] Implement a retpoline [0] for the BPF tail call JIT'ing that converts the indirect jump via jmp %rax that is used to make the long jump into another JITed BPF image. Since this is subject to speculative execution, we need to control the transient instruction sequence here as well when CONFIG_RETPOLINE is set, and direct it into a pause + lfence loop. The latter aligns also with what gcc / clang emits (e.g. [1]). JIT dump after patch: # bpftool p d x i 1 0: (18) r2 = map[id:1] 2: (b7) r3 = 0 3: (85) call bpf_tail_call#12 4: (b7) r0 = 2 5: (95) exit With CONFIG_RETPOLINE: # bpftool p d j i 1 [...] 33: cmp %edx,0x24(%rsi) 36: jbe 0x0000000000000072 |* 38: mov 0x24(%rbp),%eax 3e: cmp $0x20,%eax 41: ja 0x0000000000000072 | 43: add $0x1,%eax 46: mov %eax,0x24(%rbp) 4c: mov 0x90(%rsi,%rdx,8),%rax 54: test %rax,%rax 57: je 0x0000000000000072 | 59: mov 0x28(%rax),%rax 5d: add $0x25,%rax 61: callq 0x000000000000006d |+ 66: pause | 68: lfence | 6b: jmp 0x0000000000000066 | 6d: mov %rax,(%rsp) | 71: retq | 72: mov $0x2,%eax [...] * relative fall-through jumps in error case + retpoline for indirect jump Without CONFIG_RETPOLINE: # bpftool p d j i 1 [...] 33: cmp %edx,0x24(%rsi) 36: jbe 0x0000000000000063 |* 38: mov 0x24(%rbp),%eax 3e: cmp $0x20,%eax 41: ja 0x0000000000000063 | 43: add $0x1,%eax 46: mov %eax,0x24(%rbp) 4c: mov 0x90(%rsi,%rdx,8),%rax 54: test %rax,%rax 57: je 0x0000000000000063 | 59: mov 0x28(%rax),%rax 5d: add $0x25,%rax 61: jmpq *%rax |- 63: mov $0x2,%eax [...] * relative fall-through jumps in error case - plain indirect jump as before [0] https://support.google.com/faqs/answer/7625886 [1] https://github.com/gcc-mirror/gcc/commit/a31e654fa107be968b802786d747e962c2fcdb2b Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 37 ++++++++++++++++++++++++++++ arch/x86/net/bpf_jit_comp.c | 9 ++++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 76b058533e47..81a1be326571 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -177,4 +177,41 @@ static inline void indirect_branch_prediction_barrier(void) } #endif /* __ASSEMBLY__ */ + +/* + * Below is used in the eBPF JIT compiler and emits the byte sequence + * for the following assembly: + * + * With retpolines configured: + * + * callq do_rop + * spec_trap: + * pause + * lfence + * jmp spec_trap + * do_rop: + * mov %rax,(%rsp) + * retq + * + * Without retpolines configured: + * + * jmp *%rax + */ +#ifdef CONFIG_RETPOLINE +# define RETPOLINE_RAX_BPF_JIT_SIZE 17 +# define RETPOLINE_RAX_BPF_JIT() \ + EMIT1_off32(0xE8, 7); /* callq do_rop */ \ + /* spec_trap: */ \ + EMIT2(0xF3, 0x90); /* pause */ \ + EMIT3(0x0F, 0xAE, 0xE8); /* lfence */ \ + EMIT2(0xEB, 0xF9); /* jmp spec_trap */ \ + /* do_rop: */ \ + EMIT4(0x48, 0x89, 0x04, 0x24); /* mov %rax,(%rsp) */ \ + EMIT1(0xC3); /* retq */ +#else +# define RETPOLINE_RAX_BPF_JIT_SIZE 2 +# define RETPOLINE_RAX_BPF_JIT() \ + EMIT2(0xFF, 0xE0); /* jmp *%rax */ +#endif + #endif /* _ASM_X86_NOSPEC_BRANCH_H_ */ diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7840331d3056..1f7ed2ed6ff7 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -12,6 +12,7 @@ #include #include #include +#include #include int bpf_jit_enable __read_mostly; @@ -281,7 +282,7 @@ static void emit_bpf_tail_call(u8 **pprog) EMIT2(0x89, 0xD2); /* mov edx, edx */ EMIT3(0x39, 0x56, /* cmp dword ptr [rsi + 16], edx */ offsetof(struct bpf_array, map.max_entries)); -#define OFFSET1 43 /* number of bytes to jump */ +#define OFFSET1 (41 + RETPOLINE_RAX_BPF_JIT_SIZE) /* number of bytes to jump */ EMIT2(X86_JBE, OFFSET1); /* jbe out */ label1 = cnt; @@ -290,7 +291,7 @@ static void emit_bpf_tail_call(u8 **pprog) */ EMIT2_off32(0x8B, 0x85, -STACKSIZE + 36); /* mov eax, dword ptr [rbp - 516] */ EMIT3(0x83, 0xF8, MAX_TAIL_CALL_CNT); /* cmp eax, MAX_TAIL_CALL_CNT */ -#define OFFSET2 32 +#define OFFSET2 (30 + RETPOLINE_RAX_BPF_JIT_SIZE) EMIT2(X86_JA, OFFSET2); /* ja out */ label2 = cnt; EMIT3(0x83, 0xC0, 0x01); /* add eax, 1 */ @@ -304,7 +305,7 @@ static void emit_bpf_tail_call(u8 **pprog) * goto out; */ EMIT3(0x48, 0x85, 0xC0); /* test rax,rax */ -#define OFFSET3 10 +#define OFFSET3 (8 + RETPOLINE_RAX_BPF_JIT_SIZE) EMIT2(X86_JE, OFFSET3); /* je out */ label3 = cnt; @@ -317,7 +318,7 @@ static void emit_bpf_tail_call(u8 **pprog) * rdi == ctx (1st arg) * rax == prog->bpf_func + prologue_size */ - EMIT2(0xFF, 0xE0); /* jmp rax */ + RETPOLINE_RAX_BPF_JIT(); /* out: */ BUILD_BUG_ON(cnt - label1 != OFFSET1); -- GitLab From 54c6d01b1a4fa674e70da842fef95382044dc1e4 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 8 Mar 2018 16:17:35 +0100 Subject: [PATCH 0238/1834] bpf, arm64: fix out of bounds access in tail call [ upstream commit 16338a9b3ac30740d49f5dfed81bac0ffa53b9c7 ] I recently noticed a crash on arm64 when feeding a bogus index into BPF tail call helper. The crash would not occur when the interpreter is used, but only in case of JIT. Output looks as follows: [ 347.007486] Unable to handle kernel paging request at virtual address fffb850e96492510 [...] [ 347.043065] [fffb850e96492510] address between user and kernel address ranges [ 347.050205] Internal error: Oops: 96000004 [#1] SMP [...] [ 347.190829] x13: 0000000000000000 x12: 0000000000000000 [ 347.196128] x11: fffc047ebe782800 x10: ffff808fd7d0fd10 [ 347.201427] x9 : 0000000000000000 x8 : 0000000000000000 [ 347.206726] x7 : 0000000000000000 x6 : 001c991738000000 [ 347.212025] x5 : 0000000000000018 x4 : 000000000000ba5a [ 347.217325] x3 : 00000000000329c4 x2 : ffff808fd7cf0500 [ 347.222625] x1 : ffff808fd7d0fc00 x0 : ffff808fd7cf0500 [ 347.227926] Process test_verifier (pid: 4548, stack limit = 0x000000007467fa61) [ 347.235221] Call trace: [ 347.237656] 0xffff000002f3a4fc [ 347.240784] bpf_test_run+0x78/0xf8 [ 347.244260] bpf_prog_test_run_skb+0x148/0x230 [ 347.248694] SyS_bpf+0x77c/0x1110 [ 347.251999] el0_svc_naked+0x30/0x34 [ 347.255564] Code: 9100075a d280220a 8b0a002a d37df04b (f86b694b) [...] In this case the index used in BPF r3 is the same as in r1 at the time of the call, meaning we fed a pointer as index; here, it had the value 0xffff808fd7cf0500 which sits in x2. While I found tail calls to be working in general (also for hitting the error cases), I noticed the following in the code emission: # bpftool p d j i 988 [...] 38: ldr w10, [x1,x10] 3c: cmp w2, w10 40: b.ge 0x000000000000007c <-- signed cmp 44: mov x10, #0x20 // #32 48: cmp x26, x10 4c: b.gt 0x000000000000007c 50: add x26, x26, #0x1 54: mov x10, #0x110 // #272 58: add x10, x1, x10 5c: lsl x11, x2, #3 60: ldr x11, [x10,x11] <-- faulting insn (f86b694b) 64: cbz x11, 0x000000000000007c [...] Meaning, the tests passed because commit ddb55992b04d ("arm64: bpf: implement bpf_tail_call() helper") was using signed compares instead of unsigned which as a result had the test wrongly passing. Change this but also the tail call count test both into unsigned and cap the index as u32. Latter we did as well in 90caccdd8cc0 ("bpf: fix bpf_tail_call() x64 JIT") and is needed in addition here, too. Tested on HiSilicon Hi1616. Result after patch: # bpftool p d j i 268 [...] 38: ldr w10, [x1,x10] 3c: add w2, w2, #0x0 40: cmp w2, w10 44: b.cs 0x0000000000000080 48: mov x10, #0x20 // #32 4c: cmp x26, x10 50: b.hi 0x0000000000000080 54: add x26, x26, #0x1 58: mov x10, #0x110 // #272 5c: add x10, x1, x10 60: lsl x11, x2, #3 64: ldr x11, [x10,x11] 68: cbz x11, 0x0000000000000080 [...] Fixes: ddb55992b04d ("arm64: bpf: implement bpf_tail_call() helper") Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/net/bpf_jit_comp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c index d8199e12fb6e..b47a26f4290c 100644 --- a/arch/arm64/net/bpf_jit_comp.c +++ b/arch/arm64/net/bpf_jit_comp.c @@ -234,8 +234,9 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) off = offsetof(struct bpf_array, map.max_entries); emit_a64_mov_i64(tmp, off, ctx); emit(A64_LDR32(tmp, r2, tmp), ctx); + emit(A64_MOV(0, r3, r3), ctx); emit(A64_CMP(0, r3, tmp), ctx); - emit(A64_B_(A64_COND_GE, jmp_offset), ctx); + emit(A64_B_(A64_COND_CS, jmp_offset), ctx); /* if (tail_call_cnt > MAX_TAIL_CALL_CNT) * goto out; @@ -243,7 +244,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) */ emit_a64_mov_i64(tmp, MAX_TAIL_CALL_CNT, ctx); emit(A64_CMP(1, tcc, tmp), ctx); - emit(A64_B_(A64_COND_GT, jmp_offset), ctx); + emit(A64_B_(A64_COND_HI, jmp_offset), ctx); emit(A64_ADD_I(1, tcc, tcc, 1), ctx); /* prog = array->ptrs[index]; -- GitLab From 2a8bc5316adc998951e8f726c31e231a6021eae2 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 8 Mar 2018 16:17:36 +0100 Subject: [PATCH 0239/1834] bpf: add schedule points in percpu arrays management [ upstream commit 32fff239de37ef226d5b66329dd133f64d63b22d ] syszbot managed to trigger RCU detected stalls in bpf_array_free_percpu() It takes time to allocate a huge percpu map, but even more time to free it. Since we run in process context, use cond_resched() to yield cpu if needed. Fixes: a10423b87a7e ("bpf: introduce BPF_MAP_TYPE_PERCPU_ARRAY map") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: Daniel Borkmann Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/arraymap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 075ddb801422..a38119e4a427 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -20,8 +20,10 @@ static void bpf_array_free_percpu(struct bpf_array *array) { int i; - for (i = 0; i < array->map.max_entries; i++) + for (i = 0; i < array->map.max_entries; i++) { free_percpu(array->pptrs[i]); + cond_resched(); + } } static int bpf_array_alloc_percpu(struct bpf_array *array) @@ -37,6 +39,7 @@ static int bpf_array_alloc_percpu(struct bpf_array *array) return -ENOMEM; } array->pptrs[i] = ptr; + cond_resched(); } return 0; -- GitLab From 2b70de4ea91bca18f6080f441fac9c500a7ec7c3 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 8 Mar 2018 16:17:37 +0100 Subject: [PATCH 0240/1834] bpf, ppc64: fix out of bounds access in tail call [ upstream commit d269176e766c71c998cb75b4ea8cbc321cc0019d ] While working on 16338a9b3ac3 ("bpf, arm64: fix out of bounds access in tail call") I noticed that ppc64 JIT is partially affected as well. While the bound checking is correctly performed as unsigned comparison, the register with the index value however, is never truncated into 32 bit space, so e.g. a index value of 0x100000000ULL with a map of 1 element would pass with PPC_CMPLW() whereas we later on continue with the full 64 bit register value. Therefore, as we do in interpreter and other JITs truncate the value to 32 bit initially in order to fix access. Fixes: ce0761419fae ("powerpc/bpf: Implement support for tail calls") Signed-off-by: Daniel Borkmann Reviewed-by: Naveen N. Rao Tested-by: Naveen N. Rao Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/net/bpf_jit_comp64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/net/bpf_jit_comp64.c b/arch/powerpc/net/bpf_jit_comp64.c index 0fe98a567125..be9d968244ad 100644 --- a/arch/powerpc/net/bpf_jit_comp64.c +++ b/arch/powerpc/net/bpf_jit_comp64.c @@ -245,6 +245,7 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 * goto out; */ PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries)); + PPC_RLWINM(b2p_index, b2p_index, 0, 0, 31); PPC_CMPLW(b2p_index, b2p[TMP_REG_1]); PPC_BCC(COND_GE, out); -- GitLab From 931dde83a2696d8794042ebbf724f60eda5983c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernesto=20A=2E=20Fern=C3=A1ndez?= Date: Wed, 2 Aug 2017 03:18:27 -0300 Subject: [PATCH 0241/1834] btrfs: preserve i_mode if __btrfs_set_acl() fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d7d824966530acfe32b94d1ed672e6fe1638cd68 upstream. When changing a file's acl mask, btrfs_set_acl() will first set the group bits of i_mode to the value of the mask, and only then set the actual extended attribute representing the new acl. If the second part fails (due to lack of space, for example) and the file had no acl attribute to begin with, the system will from now on assume that the mask permission bits are actual group permission bits, potentially granting access to the wrong users. Prevent this by restoring the original mode bits if __btrfs_set_acl fails. Signed-off-by: Ernesto A. Fernández Reviewed-by: David Sterba Signed-off-by: David Sterba Signed-off-by: Nikolay Borisov Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/acl.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c index 8d8370ddb6b2..1ba49ebe67da 100644 --- a/fs/btrfs/acl.c +++ b/fs/btrfs/acl.c @@ -114,13 +114,17 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans, int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) { int ret; + umode_t old_mode = inode->i_mode; if (type == ACL_TYPE_ACCESS && acl) { ret = posix_acl_update_mode(inode, &inode->i_mode, &acl); if (ret) return ret; } - return __btrfs_set_acl(NULL, inode, acl, type); + ret = __btrfs_set_acl(NULL, inode, acl, type); + if (ret) + inode->i_mode = old_mode; + return ret; } /* -- GitLab From b67416226a0cff3f49032de36906ad1ebe5694a0 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 11 Mar 2018 16:21:35 +0100 Subject: [PATCH 0242/1834] Linux 4.9.87 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e918d25e95bb..3043937a65d1 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 86 +SUBLEVEL = 87 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 97d7f1c7c0f0b91e299e87b94c40829c9e0fe47d Mon Sep 17 00:00:00 2001 From: Yunlong Song Date: Wed, 28 Feb 2018 20:31:52 +0800 Subject: [PATCH 0243/1834] FROMLIST: f2fs: don't put dentry page in pagecache into highmem Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: 975c5679a2d7 ("f2fs: don't put dentry page in pagecache into highmem") Previous dentry page uses highmem, which will cause panic in platforms using highmem (such as arm), since the address space of dentry pages from highmem directly goes into the decryption path via the function fscrypt_fname_disk_to_usr. But sg_init_one assumes the address is not from highmem, and then cause panic since it doesn't call kmap_high but kunmap_high is triggered at the end. To fix this problem in a simple way, this patch avoids to put dentry page in pagecache into highmem. Change-Id: Ia22ed1e5503e6c15d63e4ab3b02a747a47cbc9b1 Signed-off-by: Yunlong Song Reviewed-by: Chao Yu [Jaegeuk Kim: fix coding style] Signed-off-by: Jaegeuk Kim --- fs/f2fs/dir.c | 23 +++++------------------ fs/f2fs/f2fs.h | 6 ------ fs/f2fs/inline.c | 3 +-- fs/f2fs/inode.c | 2 +- fs/f2fs/namei.c | 32 ++++++++------------------------ fs/f2fs/recovery.c | 11 +++++------ include/linux/f2fs_fs.h | 1 - 7 files changed, 20 insertions(+), 58 deletions(-) diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 6ef3c8337f2d..a352ace5f7cd 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -94,14 +94,12 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page, struct f2fs_dir_entry *de; struct f2fs_dentry_ptr d; - dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page); + dentry_blk = (struct f2fs_dentry_block *)page_address(dentry_page); make_dentry_ptr_block(NULL, &d, dentry_blk); de = find_target_dentry(fname, namehash, max_slots, &d); if (de) *res_page = dentry_page; - else - kunmap(dentry_page); return de; } @@ -287,7 +285,6 @@ ino_t f2fs_inode_by_name(struct inode *dir, const struct qstr *qstr, de = f2fs_find_entry(dir, qstr, page); if (de) { res = le32_to_cpu(de->ino); - f2fs_dentry_kunmap(dir, *page); f2fs_put_page(*page, 0); } @@ -302,7 +299,6 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de, f2fs_wait_on_page_writeback(page, type, true); de->ino = cpu_to_le32(inode->i_ino); set_de_type(de, inode->i_mode); - f2fs_dentry_kunmap(dir, page); set_page_dirty(page); dir->i_mtime = dir->i_ctime = current_time(dir); @@ -350,13 +346,11 @@ static int make_empty_dir(struct inode *inode, if (IS_ERR(dentry_page)) return PTR_ERR(dentry_page); - dentry_blk = kmap_atomic(dentry_page); + dentry_blk = page_address(dentry_page); make_dentry_ptr_block(NULL, &d, dentry_blk); do_make_empty_dir(inode, parent, &d); - kunmap_atomic(dentry_blk); - set_page_dirty(dentry_page); f2fs_put_page(dentry_page, 1); return 0; @@ -547,13 +541,12 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, if (IS_ERR(dentry_page)) return PTR_ERR(dentry_page); - dentry_blk = kmap(dentry_page); + dentry_blk = page_address(dentry_page); bit_pos = room_for_filename(&dentry_blk->dentry_bitmap, slots, NR_DENTRY_IN_BLOCK); if (bit_pos < NR_DENTRY_IN_BLOCK) goto add_dentry; - kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } @@ -588,7 +581,6 @@ int f2fs_add_regular_entry(struct inode *dir, const struct qstr *new_name, if (inode) up_write(&F2FS_I(inode)->i_sem); - kunmap(dentry_page); f2fs_put_page(dentry_page, 1); return err; @@ -642,7 +634,6 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name, F2FS_I(dir)->task = NULL; } if (de) { - f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); err = -EEXIST; } else if (IS_ERR(page)) { @@ -730,7 +721,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, NR_DENTRY_IN_BLOCK, 0); - kunmap(page); /* kunmap - pair of f2fs_find_entry */ set_page_dirty(page); dir->i_ctime = dir->i_mtime = current_time(dir); @@ -775,7 +765,7 @@ bool f2fs_empty_dir(struct inode *dir) return false; } - dentry_blk = kmap_atomic(dentry_page); + dentry_blk = page_address(dentry_page); if (bidx == 0) bit_pos = 2; else @@ -783,7 +773,6 @@ bool f2fs_empty_dir(struct inode *dir) bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap, NR_DENTRY_IN_BLOCK, bit_pos); - kunmap_atomic(dentry_blk); f2fs_put_page(dentry_page, 1); @@ -901,19 +890,17 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx) } } - dentry_blk = kmap(dentry_page); + dentry_blk = page_address(dentry_page); make_dentry_ptr_block(inode, &d, dentry_blk); err = f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK, &fstr); if (err) { - kunmap(dentry_page); f2fs_put_page(dentry_page, 1); break; } - kunmap(dentry_page); f2fs_put_page(dentry_page, 1); } out_free: diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index a8434afa3549..e5d3e22629b3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2397,12 +2397,6 @@ static inline int f2fs_has_inline_dentry(struct inode *inode) return is_inode_flag_set(inode, FI_INLINE_DENTRY); } -static inline void f2fs_dentry_kunmap(struct inode *dir, struct page *page) -{ - if (!f2fs_has_inline_dentry(dir)) - kunmap(page); -} - static inline int is_file(struct inode *inode, int type) { return F2FS_I(inode)->i_advise & type; diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 364114ad2147..1925814ac675 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -387,7 +387,7 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage, f2fs_wait_on_page_writeback(page, DATA, true); zero_user_segment(page, MAX_INLINE_DATA(dir), PAGE_SIZE); - dentry_blk = kmap_atomic(page); + dentry_blk = page_address(page); make_dentry_ptr_inline(dir, &src, inline_dentry); make_dentry_ptr_block(dir, &dst, dentry_blk); @@ -404,7 +404,6 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage, memcpy(dst.dentry, src.dentry, SIZE_OF_DIR_ENTRY * src.max); memcpy(dst.filename, src.filename, src.max * F2FS_SLOT_LEN); - kunmap_atomic(dentry_blk); if (!PageUptodate(page)) SetPageUptodate(page); set_page_dirty(page); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 89c838bfb067..10be247ca421 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -328,7 +328,7 @@ struct inode *f2fs_iget(struct super_block *sb, unsigned long ino) inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); + inode_nohighmem(inode); } else if (S_ISLNK(inode->i_mode)) { if (f2fs_encrypted_inode(inode)) inode->i_op = &f2fs_encrypted_symlink_inode_operations; diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 070b3a71daa8..59e8dca77aa3 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -317,7 +317,6 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino) de = f2fs_find_entry(dir, &dot, &page); if (de) { - f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); } else if (IS_ERR(page)) { err = PTR_ERR(page); @@ -329,14 +328,12 @@ static int __recover_dot_dentries(struct inode *dir, nid_t pino) } de = f2fs_find_entry(dir, &dotdot, &page); - if (de) { - f2fs_dentry_kunmap(dir, page); + if (de) f2fs_put_page(page, 0); - } else if (IS_ERR(page)) { + else if (IS_ERR(page)) err = PTR_ERR(page); - } else { + else err = __f2fs_add_link(dir, &dotdot, NULL, pino, S_IFDIR); - } out: if (!err) clear_inode_flag(dir, FI_INLINE_DOTS); @@ -377,7 +374,6 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry, } ino = le32_to_cpu(de->ino); - f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); inode = f2fs_iget(dir->i_sb, ino); @@ -452,7 +448,6 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry) err = acquire_orphan_inode(sbi); if (err) { f2fs_unlock_op(sbi); - f2fs_dentry_kunmap(dir, page); f2fs_put_page(page, 0); goto fail; } @@ -613,7 +608,7 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) inode->i_op = &f2fs_dir_inode_operations; inode->i_fop = &f2fs_dir_operations; inode->i_mapping->a_ops = &f2fs_dblock_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO); + inode_nohighmem(inode); set_inode_flag(inode, FI_INC_LINK); f2fs_lock_op(sbi); @@ -927,13 +922,11 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, } if (old_dir_entry) { - if (old_dir != new_dir && !whiteout) { + if (old_dir != new_dir && !whiteout) f2fs_set_link(old_inode, old_dir_entry, old_dir_page, new_dir); - } else { - f2fs_dentry_kunmap(old_inode, old_dir_page); + else f2fs_put_page(old_dir_page, 0); - } f2fs_i_links_write(old_dir, false); } add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); @@ -946,20 +939,15 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, put_out_dir: f2fs_unlock_op(sbi); - if (new_page) { - f2fs_dentry_kunmap(new_dir, new_page); + if (new_page) f2fs_put_page(new_page, 0); - } out_whiteout: if (whiteout) iput(whiteout); out_dir: - if (old_dir_entry) { - f2fs_dentry_kunmap(old_inode, old_dir_page); + if (old_dir_entry) f2fs_put_page(old_dir_page, 0); - } out_old: - f2fs_dentry_kunmap(old_dir, old_page); f2fs_put_page(old_page, 0); out: return err; @@ -1101,19 +1089,15 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, return 0; out_new_dir: if (new_dir_entry) { - f2fs_dentry_kunmap(new_inode, new_dir_page); f2fs_put_page(new_dir_page, 0); } out_old_dir: if (old_dir_entry) { - f2fs_dentry_kunmap(old_inode, old_dir_page); f2fs_put_page(old_dir_page, 0); } out_new: - f2fs_dentry_kunmap(new_dir, new_page); f2fs_put_page(new_page, 0); out_old: - f2fs_dentry_kunmap(old_dir, old_page); f2fs_put_page(old_page, 0); out: return err; diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index b6d1ec620a8c..210de28c9cd2 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -144,7 +144,7 @@ static int recover_dentry(struct inode *inode, struct page *ipage, retry: de = __f2fs_find_entry(dir, &fname, &page); if (de && inode->i_ino == le32_to_cpu(de->ino)) - goto out_unmap_put; + goto out_put; if (de) { einode = f2fs_iget_retry(inode->i_sb, le32_to_cpu(de->ino)); @@ -153,19 +153,19 @@ static int recover_dentry(struct inode *inode, struct page *ipage, err = PTR_ERR(einode); if (err == -ENOENT) err = -EEXIST; - goto out_unmap_put; + goto out_put; } err = dquot_initialize(einode); if (err) { iput(einode); - goto out_unmap_put; + goto out_put; } err = acquire_orphan_inode(F2FS_I_SB(inode)); if (err) { iput(einode); - goto out_unmap_put; + goto out_put; } f2fs_delete_entry(de, page, dir, einode); iput(einode); @@ -180,8 +180,7 @@ static int recover_dentry(struct inode *inode, struct page *ipage, goto retry; goto out; -out_unmap_put: - f2fs_dentry_kunmap(dir, page); +out_put: f2fs_put_page(page, 0); out: if (file_enc_name(inode)) diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 58aecb60ea51..393b880afc9a 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -46,7 +46,6 @@ /* This flag is used by node and meta inodes, and by recovery */ #define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO) -#define GFP_F2FS_HIGH_ZERO (GFP_NOFS | __GFP_ZERO | __GFP_HIGHMEM) /* * For further optimization on multi-head logs, on-disk layout supports maximum -- GitLab From eb8925eb9389466687ac420445d8d7ab10eba5d2 Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Tue, 6 Dec 2016 16:25:02 -0500 Subject: [PATCH 0244/1834] UPSTREAM: netfilter: xt_bpf: support ebpf Add support for attaching an eBPF object by file descriptor. The iptables binary can be called with a path to an elf object or a pinned bpf object. Also pass the mode and path to the kernel to be able to return it later for iptables dump and save. Signed-off-by: Willem de Bruijn Signed-off-by: Pablo Neira Ayuso Signed-off-by: Chenbo Feng (cherry picked from commit 2c16d60332643e90d4fa244f4a706c454b8c7569) Change-Id: I31b8831a7ffd7c44985ee906ff194c1d934dafbe --- include/uapi/linux/netfilter/xt_bpf.h | 21 ++++++ net/netfilter/xt_bpf.c | 96 ++++++++++++++++++++++----- 2 files changed, 101 insertions(+), 16 deletions(-) diff --git a/include/uapi/linux/netfilter/xt_bpf.h b/include/uapi/linux/netfilter/xt_bpf.h index 1fad2c27ac32..b97725af2ac0 100644 --- a/include/uapi/linux/netfilter/xt_bpf.h +++ b/include/uapi/linux/netfilter/xt_bpf.h @@ -2,9 +2,11 @@ #define _XT_BPF_H #include +#include #include #define XT_BPF_MAX_NUM_INSTR 64 +#define XT_BPF_PATH_MAX (XT_BPF_MAX_NUM_INSTR * sizeof(struct sock_filter)) struct bpf_prog; @@ -16,4 +18,23 @@ struct xt_bpf_info { struct bpf_prog *filter __attribute__((aligned(8))); }; +enum xt_bpf_modes { + XT_BPF_MODE_BYTECODE, + XT_BPF_MODE_FD_PINNED, + XT_BPF_MODE_FD_ELF, +}; + +struct xt_bpf_info_v1 { + __u16 mode; + __u16 bpf_program_num_elem; + __s32 fd; + union { + struct sock_filter bpf_program[XT_BPF_MAX_NUM_INSTR]; + char path[XT_BPF_PATH_MAX]; + }; + + /* only used in the kernel */ + struct bpf_prog *filter __attribute__((aligned(8))); +}; + #endif /*_XT_BPF_H */ diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c index dffee9d47ec4..2dedaa23ab0a 100644 --- a/net/netfilter/xt_bpf.c +++ b/net/netfilter/xt_bpf.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -20,15 +21,15 @@ MODULE_LICENSE("GPL"); MODULE_ALIAS("ipt_bpf"); MODULE_ALIAS("ip6t_bpf"); -static int bpf_mt_check(const struct xt_mtchk_param *par) +static int __bpf_mt_check_bytecode(struct sock_filter *insns, __u16 len, + struct bpf_prog **ret) { - struct xt_bpf_info *info = par->matchinfo; struct sock_fprog_kern program; - program.len = info->bpf_program_num_elem; - program.filter = info->bpf_program; + program.len = len; + program.filter = insns; - if (bpf_prog_create(&info->filter, &program)) { + if (bpf_prog_create(ret, &program)) { pr_info("bpf: check failed: parse error\n"); return -EINVAL; } @@ -36,6 +37,42 @@ static int bpf_mt_check(const struct xt_mtchk_param *par) return 0; } +static int __bpf_mt_check_fd(int fd, struct bpf_prog **ret) +{ + struct bpf_prog *prog; + + prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_SOCKET_FILTER); + if (IS_ERR(prog)) + return PTR_ERR(prog); + + *ret = prog; + return 0; +} + +static int bpf_mt_check(const struct xt_mtchk_param *par) +{ + struct xt_bpf_info *info = par->matchinfo; + + return __bpf_mt_check_bytecode(info->bpf_program, + info->bpf_program_num_elem, + &info->filter); +} + +static int bpf_mt_check_v1(const struct xt_mtchk_param *par) +{ + struct xt_bpf_info_v1 *info = par->matchinfo; + + if (info->mode == XT_BPF_MODE_BYTECODE) + return __bpf_mt_check_bytecode(info->bpf_program, + info->bpf_program_num_elem, + &info->filter); + else if (info->mode == XT_BPF_MODE_FD_PINNED || + info->mode == XT_BPF_MODE_FD_ELF) + return __bpf_mt_check_fd(info->fd, &info->filter); + else + return -EINVAL; +} + static bool bpf_mt(const struct sk_buff *skb, struct xt_action_param *par) { const struct xt_bpf_info *info = par->matchinfo; @@ -43,31 +80,58 @@ static bool bpf_mt(const struct sk_buff *skb, struct xt_action_param *par) return BPF_PROG_RUN(info->filter, skb); } +static bool bpf_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) +{ + const struct xt_bpf_info_v1 *info = par->matchinfo; + + return !!bpf_prog_run_save_cb(info->filter, (struct sk_buff *) skb); +} + static void bpf_mt_destroy(const struct xt_mtdtor_param *par) { const struct xt_bpf_info *info = par->matchinfo; + + bpf_prog_destroy(info->filter); +} + +static void bpf_mt_destroy_v1(const struct xt_mtdtor_param *par) +{ + const struct xt_bpf_info_v1 *info = par->matchinfo; + bpf_prog_destroy(info->filter); } -static struct xt_match bpf_mt_reg __read_mostly = { - .name = "bpf", - .revision = 0, - .family = NFPROTO_UNSPEC, - .checkentry = bpf_mt_check, - .match = bpf_mt, - .destroy = bpf_mt_destroy, - .matchsize = sizeof(struct xt_bpf_info), - .me = THIS_MODULE, +static struct xt_match bpf_mt_reg[] __read_mostly = { + { + .name = "bpf", + .revision = 0, + .family = NFPROTO_UNSPEC, + .checkentry = bpf_mt_check, + .match = bpf_mt, + .destroy = bpf_mt_destroy, + .matchsize = sizeof(struct xt_bpf_info), + .me = THIS_MODULE, + }, + { + .name = "bpf", + .revision = 1, + .family = NFPROTO_UNSPEC, + .checkentry = bpf_mt_check_v1, + .match = bpf_mt_v1, + .destroy = bpf_mt_destroy_v1, + .matchsize = sizeof(struct xt_bpf_info_v1), + .me = THIS_MODULE, + }, }; static int __init bpf_mt_init(void) { - return xt_register_match(&bpf_mt_reg); + return xt_register_matches(bpf_mt_reg, ARRAY_SIZE(bpf_mt_reg)); } static void __exit bpf_mt_exit(void) { - xt_unregister_match(&bpf_mt_reg); + xt_unregister_matches(bpf_mt_reg, ARRAY_SIZE(bpf_mt_reg)); } module_init(bpf_mt_init); -- GitLab From 7e3c72f4c7e0507852044d25313efe9e6f4886ed Mon Sep 17 00:00:00 2001 From: Shmulik Ladkani Date: Mon, 9 Oct 2017 15:27:15 +0300 Subject: [PATCH 0245/1834] UPSTREAM: netfilter: xt_bpf: Fix XT_BPF_MODE_FD_PINNED mode of 'xt_bpf_info_v1' Commit 2c16d6033264 ("netfilter: xt_bpf: support ebpf") introduced support for attaching an eBPF object by an fd, with the 'bpf_mt_check_v1' ABI expecting the '.fd' to be specified upon each IPT_SO_SET_REPLACE call. However this breaks subsequent iptables calls: # iptables -A INPUT -m bpf --object-pinned /sys/fs/bpf/xxx -j ACCEPT # iptables -A INPUT -s 5.6.7.8 -j ACCEPT iptables: Invalid argument. Run `dmesg' for more information. That's because iptables works by loading existing rules using IPT_SO_GET_ENTRIES to userspace, then issuing IPT_SO_SET_REPLACE with the replacement set. However, the loaded 'xt_bpf_info_v1' has an arbitrary '.fd' number (from the initial "iptables -m bpf" invocation) - so when 2nd invocation occurs, userspace passes a bogus fd number, which leads to 'bpf_mt_check_v1' to fail. One suggested solution [1] was to hack iptables userspace, to perform a "entries fixup" immediatley after IPT_SO_GET_ENTRIES, by opening a new, process-local fd per every 'xt_bpf_info_v1' entry seen. However, in [2] both Pablo Neira Ayuso and Willem de Bruijn suggested to depricate the xt_bpf_info_v1 ABI dealing with pinned ebpf objects. This fix changes the XT_BPF_MODE_FD_PINNED behavior to ignore the given '.fd' and instead perform an in-kernel lookup for the bpf object given the provided '.path'. It also defines an alias for the XT_BPF_MODE_FD_PINNED mode, named XT_BPF_MODE_PATH_PINNED, to better reflect the fact that the user is expected to provide the path of the pinned object. Existing XT_BPF_MODE_FD_ELF behavior (non-pinned fd mode) is preserved. References: [1] https://marc.info/?l=netfilter-devel&m=150564724607440&w=2 [2] https://marc.info/?l=netfilter-devel&m=150575727129880&w=2 Reported-by: Rafael Buchbinder Signed-off-by: Shmulik Ladkani Acked-by: Willem de Bruijn Acked-by: Daniel Borkmann Signed-off-by: Pablo Neira Ayuso Signed-off-by: Chenbo Feng (cherry picked from commit 98589a0998b8b13c4a8fa1ccb0e62751a019faa5) Change-Id: Ia0d15a76823cca3afb38786a3d2c25c13ccf941d --- include/linux/bpf.h | 5 +++++ include/uapi/linux/netfilter/xt_bpf.h | 1 + kernel/bpf/inode.c | 1 + net/netfilter/xt_bpf.c | 22 ++++++++++++++++++++-- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 193c40e296fc..fd0010e08d89 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -333,6 +333,11 @@ static inline struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) { return ERR_PTR(-EOPNOTSUPP); } +static inline int bpf_obj_get_user(const char __user *pathname) +{ + return -EOPNOTSUPP; +} + #endif /* CONFIG_BPF_SYSCALL */ /* verifier prototypes for helper functions called from eBPF programs */ diff --git a/include/uapi/linux/netfilter/xt_bpf.h b/include/uapi/linux/netfilter/xt_bpf.h index b97725af2ac0..da161b56c79e 100644 --- a/include/uapi/linux/netfilter/xt_bpf.h +++ b/include/uapi/linux/netfilter/xt_bpf.h @@ -23,6 +23,7 @@ enum xt_bpf_modes { XT_BPF_MODE_FD_PINNED, XT_BPF_MODE_FD_ELF, }; +#define XT_BPF_MODE_PATH_PINNED XT_BPF_MODE_FD_PINNED struct xt_bpf_info_v1 { __u16 mode; diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index 2d23c32e9c4b..ebac0a948d4e 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -321,6 +321,7 @@ int bpf_obj_get_user(const char __user *pathname, int flags) putname(pname); return ret; } +EXPORT_SYMBOL_GPL(bpf_obj_get_user); static void bpf_evict_inode(struct inode *inode) { diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c index 2dedaa23ab0a..94fc79d9d0e0 100644 --- a/net/netfilter/xt_bpf.c +++ b/net/netfilter/xt_bpf.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -49,6 +50,22 @@ static int __bpf_mt_check_fd(int fd, struct bpf_prog **ret) return 0; } +static int __bpf_mt_check_path(const char *path, struct bpf_prog **ret) +{ + mm_segment_t oldfs = get_fs(); + int retval, fd; + + set_fs(KERNEL_DS); + fd = bpf_obj_get_user(path); + set_fs(oldfs); + if (fd < 0) + return fd; + + retval = __bpf_mt_check_fd(fd, ret); + sys_close(fd); + return retval; +} + static int bpf_mt_check(const struct xt_mtchk_param *par) { struct xt_bpf_info *info = par->matchinfo; @@ -66,9 +83,10 @@ static int bpf_mt_check_v1(const struct xt_mtchk_param *par) return __bpf_mt_check_bytecode(info->bpf_program, info->bpf_program_num_elem, &info->filter); - else if (info->mode == XT_BPF_MODE_FD_PINNED || - info->mode == XT_BPF_MODE_FD_ELF) + else if (info->mode == XT_BPF_MODE_FD_ELF) return __bpf_mt_check_fd(info->fd, &info->filter); + else if (info->mode == XT_BPF_MODE_PATH_PINNED) + return __bpf_mt_check_path(info->path, &info->filter); else return -EINVAL; } -- GitLab From 52447008883ef44f413521f883ebc8f03bf9b818 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Fri, 1 Dec 2017 01:46:07 +0100 Subject: [PATCH 0246/1834] UPSTREAM: netfilter: xt_bpf: add overflow checks Check whether inputs from userspace are too long (explicit length field too big or string not null-terminated) to avoid out-of-bounds reads. As far as I can tell, this can at worst lead to very limited kernel heap memory disclosure or oopses. This bug can be triggered by an unprivileged user even if the xt_bpf module is not loaded: iptables is available in network namespaces, and the xt_bpf module can be autoloaded. Triggering the bug with a classic BPF filter with fake length 0x1000 causes the following KASAN report: ================================================================== BUG: KASAN: slab-out-of-bounds in bpf_prog_create+0x84/0xf0 Read of size 32768 at addr ffff8801eff2c494 by task test/4627 CPU: 0 PID: 4627 Comm: test Not tainted 4.15.0-rc1+ #1 [...] Call Trace: dump_stack+0x5c/0x85 print_address_description+0x6a/0x260 kasan_report+0x254/0x370 ? bpf_prog_create+0x84/0xf0 memcpy+0x1f/0x50 bpf_prog_create+0x84/0xf0 bpf_mt_check+0x90/0xd6 [xt_bpf] [...] Allocated by task 4627: kasan_kmalloc+0xa0/0xd0 __kmalloc_node+0x47/0x60 xt_alloc_table_info+0x41/0x70 [x_tables] [...] The buggy address belongs to the object at ffff8801eff2c3c0 which belongs to the cache kmalloc-2048 of size 2048 The buggy address is located 212 bytes inside of 2048-byte region [ffff8801eff2c3c0, ffff8801eff2cbc0) [...] ================================================================== Fixes: e6f30c731718 ("netfilter: x_tables: add xt_bpf match") Signed-off-by: Jann Horn Signed-off-by: Pablo Neira Ayuso Signed-off-by: Chenbo Feng (cherry picked from commit 6ab405114b0b229151ef06f4e31c7834dd09d0c0) Change-Id: Ie066a9df84812853a9c9d2e51aa53646f4001542 --- net/netfilter/xt_bpf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c index 94fc79d9d0e0..6a091c14e257 100644 --- a/net/netfilter/xt_bpf.c +++ b/net/netfilter/xt_bpf.c @@ -27,6 +27,9 @@ static int __bpf_mt_check_bytecode(struct sock_filter *insns, __u16 len, { struct sock_fprog_kern program; + if (len > XT_BPF_MAX_NUM_INSTR) + return -EINVAL; + program.len = len; program.filter = insns; @@ -55,6 +58,9 @@ static int __bpf_mt_check_path(const char *path, struct bpf_prog **ret) mm_segment_t oldfs = get_fs(); int retval, fd; + if (strnlen(path, XT_BPF_PATH_MAX) == XT_BPF_PATH_MAX) + return -EINVAL; + set_fs(KERNEL_DS); fd = bpf_obj_get_user(path); set_fs(oldfs); -- GitLab From 7dc12f7d2f4c20f38c0a812c96db02c438cd5657 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 2 Dec 2017 20:20:38 -0500 Subject: [PATCH 0247/1834] BACKPORT: fix "netfilter: xt_bpf: Fix XT_BPF_MODE_FD_PINNED mode of 'xt_bpf_info_v1'" Descriptor table is a shared object; it's not a place where you can stick temporary references to files, especially when we don't need an opened file at all. Cc: stable@vger.kernel.org # v4.14 Fixes: 98589a0998b8 ("netfilter: xt_bpf: Fix XT_BPF_MODE_FD_PINNED mode of 'xt_bpf_info_v1'") Signed-off-by: Al Viro Signed-off-by: Chenbo Feng Removed the code related to function bpf_prog_get_ok() since it is not exsit in current android tree. (cherry picked from commit 040ee69226f8a96b7943645d68f41d5d44b5ff7d) Change-Id: If7a602128cdea4b4b50c8effb215c9bca7449515 --- include/linux/bpf.h | 8 ++++++++ kernel/bpf/inode.c | 37 ++++++++++++++++++++++++++++++++++++- net/netfilter/xt_bpf.c | 13 ++----------- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index fd0010e08d89..cd6aaf08324d 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -306,6 +306,9 @@ static inline void bpf_long_memcpy(void *dst, const void *src, u32 size) /* verify correctness of eBPF program */ int bpf_check(struct bpf_prog **fp, union bpf_attr *attr); + +struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type type); + #else static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl) { @@ -338,6 +341,11 @@ static inline int bpf_obj_get_user(const char __user *pathname) return -EOPNOTSUPP; } +static inline struct bpf_prog *bpf_prog_get_type_path(const char *name, + enum bpf_prog_type type) +{ + return ERR_PTR(-EOPNOTSUPP); +} #endif /* CONFIG_BPF_SYSCALL */ /* verifier prototypes for helper functions called from eBPF programs */ diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c index ebac0a948d4e..7e48fa609579 100644 --- a/kernel/bpf/inode.c +++ b/kernel/bpf/inode.c @@ -321,7 +321,42 @@ int bpf_obj_get_user(const char __user *pathname, int flags) putname(pname); return ret; } -EXPORT_SYMBOL_GPL(bpf_obj_get_user); + +static struct bpf_prog *__get_prog_inode(struct inode *inode, enum bpf_prog_type type) +{ + struct bpf_prog *prog; + int ret = inode_permission(inode, MAY_READ | MAY_WRITE); + if (ret) + return ERR_PTR(ret); + + if (inode->i_op == &bpf_map_iops) + return ERR_PTR(-EINVAL); + if (inode->i_op != &bpf_prog_iops) + return ERR_PTR(-EACCES); + + prog = inode->i_private; + + ret = security_bpf_prog(prog); + if (ret < 0) + return ERR_PTR(ret); + + return bpf_prog_inc(prog); +} + +struct bpf_prog *bpf_prog_get_type_path(const char *name, enum bpf_prog_type type) +{ + struct bpf_prog *prog; + struct path path; + int ret = kern_path(name, LOOKUP_FOLLOW, &path); + if (ret) + return ERR_PTR(ret); + prog = __get_prog_inode(d_backing_inode(path.dentry), type); + if (!IS_ERR(prog)) + touch_atime(&path); + path_put(&path); + return prog; +} +EXPORT_SYMBOL(bpf_prog_get_type_path); static void bpf_evict_inode(struct inode *inode) { diff --git a/net/netfilter/xt_bpf.c b/net/netfilter/xt_bpf.c index 6a091c14e257..a8df0a9d68e6 100644 --- a/net/netfilter/xt_bpf.c +++ b/net/netfilter/xt_bpf.c @@ -55,21 +55,12 @@ static int __bpf_mt_check_fd(int fd, struct bpf_prog **ret) static int __bpf_mt_check_path(const char *path, struct bpf_prog **ret) { - mm_segment_t oldfs = get_fs(); - int retval, fd; - if (strnlen(path, XT_BPF_PATH_MAX) == XT_BPF_PATH_MAX) return -EINVAL; - set_fs(KERNEL_DS); - fd = bpf_obj_get_user(path); - set_fs(oldfs); - if (fd < 0) - return fd; + *ret = bpf_prog_get_type_path(path, BPF_PROG_TYPE_SOCKET_FILTER); + return PTR_ERR_OR_ZERO(*ret); - retval = __bpf_mt_check_fd(fd, ret); - sys_close(fd); - return retval; } static int bpf_mt_check(const struct xt_mtchk_param *par) -- GitLab From 3a3a0844ac38928ce19ed45b38532f8f16422470 Mon Sep 17 00:00:00 2001 From: Sami Tolvanen Date: Wed, 14 Mar 2018 15:39:27 -0700 Subject: [PATCH 0248/1834] kbuild: fix --gc-sections Adds KEEP() to __ex_table, __param, and __bug_table. Bug: 67506682 Change-Id: I44ce1a541ac61b18c9ef5eb4749122f39ca7c755 Reported-by: Channagoud Kadabi Signed-off-by: Sami Tolvanen --- include/asm-generic/vmlinux.lds.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index f8f0e48d2aab..8236dbd48fa3 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -425,7 +425,7 @@ /* Built-in module parameters. */ \ __param : AT(ADDR(__param) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___param) = .; \ - *(__param) \ + KEEP(*(__param)) \ VMLINUX_SYMBOL(__stop___param) = .; \ } \ \ @@ -530,7 +530,7 @@ . = ALIGN(align); \ __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___ex_table) = .; \ - *(__ex_table) \ + KEEP(*(__ex_table)) \ VMLINUX_SYMBOL(__stop___ex_table) = .; \ } @@ -672,7 +672,7 @@ . = ALIGN(8); \ __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start___bug_table) = .; \ - *(__bug_table) \ + KEEP(*(__bug_table)) \ VMLINUX_SYMBOL(__stop___bug_table) = .; \ } #else -- GitLab From 08da675c9421b1a7df9aadee84640908390aeb3c Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 6 Feb 2018 15:36:03 -0800 Subject: [PATCH 0249/1834] BACKPORT: kasan: add compiler support for clang Patch series "kasan: support alloca, LLVM", v4. This patch (of 5): For now we can hard-code ASAN ABI level 5, since historical clang builds can't build the kernel anyway. We also need to emulate gcc's __SANITIZE_ADDRESS__ flag, or memset() calls won't be instrumented. Link: http://lkml.kernel.org/r/20171204191735.132544-2-paullawrence@google.com Signed-off-by: Greg Hackmann Signed-off-by: Paul Lawrence Acked-by: Andrey Ryabinin Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Masahiro Yamada Cc: Matthias Kaehlcke Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry-picked from 53a98ed73b848432a51631346b02049bb7fa039d) Change-Id: I4f694d1c06ad286e165d68938ff0f4348dc5fedf Signed-off-by: Paul Lawrence --- include/linux/compiler-clang.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index eeb2331e9fa3..026517d882c0 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -24,3 +24,11 @@ #define __nocfi __attribute__((no_sanitize("cfi"))) #endif + +/* all clang versions usable with the kernel support KASAN ABI version 5 */ +#define KASAN_ABI_VERSION 5 + +/* emulate gcc's __SANITIZE_ADDRESS__ flag */ +#if __has_feature(address_sanitizer) +#define __SANITIZE_ADDRESS__ +#endif -- GitLab From e2aa37088f954c90cb2fdce9b34cc38976569b80 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Tue, 6 Feb 2018 15:36:08 -0800 Subject: [PATCH 0250/1834] UPSTREAM: kasan/Makefile: support LLVM style asan parameters LLVM doesn't understand GCC-style paramters ("--param asan-foo=bar"), thus we currently we don't use inline/globals/stack instrumentation when building the kernel with clang. Add support for LLVM-style parameters ("-mllvm -asan-foo=bar") to enable all KASAN features. Link: http://lkml.kernel.org/r/20171204191735.132544-3-paullawrence@google.com Signed-off-by: Andrey Ryabinin Signed-off-by: Paul Lawrence Reviewed-by: Alexander Potapenko Cc: Dmitry Vyukov Cc: Greg Hackmann Cc: Masahiro Yamada Cc: Matthias Kaehlcke Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry-picked from 1a69e7ce8391a8bc808baf04e06d88ab4024ca47) Change-Id: I45293710522c70c031a9e2ea712c765c2fd86fc3 Signed-off-by: Paul Lawrence --- scripts/Makefile.kasan | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 37323b0df374..30a1e3628809 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -9,10 +9,7 @@ KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET) CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address -CFLAGS_KASAN := $(call cc-option, -fsanitize=kernel-address \ - -fasan-shadow-offset=$(KASAN_SHADOW_OFFSET) \ - --param asan-stack=1 --param asan-globals=1 \ - --param asan-instrumentation-with-call-threshold=$(call_threshold)) +cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1))) ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),) ifneq ($(CONFIG_COMPILE_TEST),y) @@ -20,12 +17,22 @@ ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),) -fsanitize=kernel-address is not supported by compiler) endif else - ifeq ($(CFLAGS_KASAN),) - ifneq ($(CONFIG_COMPILE_TEST),y) - $(warning CONFIG_KASAN: compiler does not support all options.\ - Trying minimal configuration) - endif - CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL) - endif + # -fasan-shadow-offset fails without -fsanitize + CFLAGS_KASAN_SHADOW := $(call cc-option, -fsanitize=kernel-address \ + -fasan-shadow-offset=$(KASAN_SHADOW_OFFSET), \ + $(call cc-option, -fsanitize=kernel-address \ + -mllvm -asan-mapping-offset=$(KASAN_SHADOW_OFFSET))) + + ifeq ($(strip $(CFLAGS_KASAN_SHADOW)),) + CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL) + else + # Now add all the compiler specific options that are valid standalone + CFLAGS_KASAN := $(CFLAGS_KASAN_SHADOW) \ + $(call cc-param,asan-globals=1) \ + $(call cc-param,asan-instrumentation-with-call-threshold=$(call_threshold)) \ + $(call cc-param,asan-stack=1) \ + $(call cc-param,asan-use-after-scope=1) + endif + endif endif -- GitLab From 9351dcdbf4eaa5301ebe4bf5ad916d496d0c8385 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 6 Feb 2018 15:36:11 -0800 Subject: [PATCH 0251/1834] UPSTREAM: kasan: support alloca() poisoning clang's AddressSanitizer implementation adds redzones on either side of alloca()ed buffers. These redzones are 32-byte aligned and at least 32 bytes long. __asan_alloca_poison() is passed the size and address of the allocated buffer, *excluding* the redzones on either side. The left redzone will always be to the immediate left of this buffer; but AddressSanitizer may need to add padding between the end of the buffer and the right redzone. If there are any 8-byte chunks inside this padding, we should poison those too. __asan_allocas_unpoison() is just passed the top and bottom of the dynamic stack area, so unpoisoning is simpler. Link: http://lkml.kernel.org/r/20171204191735.132544-4-paullawrence@google.com Signed-off-by: Greg Hackmann Signed-off-by: Paul Lawrence Acked-by: Andrey Ryabinin Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Masahiro Yamada Cc: Matthias Kaehlcke Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry-picked from 342061ee4ef3d80001d1ae494378f3979c861dba) Change-Id: I4f6d448735dbb80830f4cd6801d78885d1a7382b Signed-off-by: Paul Lawrence --- mm/kasan/kasan.c | 34 ++++++++++++++++++++++++++++++++++ mm/kasan/kasan.h | 8 ++++++++ mm/kasan/report.c | 4 ++++ scripts/Makefile.kasan | 3 ++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index 7a6d1a1f9894..08edb57b3d1b 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c @@ -794,6 +794,40 @@ void __asan_unpoison_stack_memory(const void *addr, size_t size) } EXPORT_SYMBOL(__asan_unpoison_stack_memory); +/* Emitted by compiler to poison alloca()ed objects. */ +void __asan_alloca_poison(unsigned long addr, size_t size) +{ + size_t rounded_up_size = round_up(size, KASAN_SHADOW_SCALE_SIZE); + size_t padding_size = round_up(size, KASAN_ALLOCA_REDZONE_SIZE) - + rounded_up_size; + size_t rounded_down_size = round_down(size, KASAN_SHADOW_SCALE_SIZE); + + const void *left_redzone = (const void *)(addr - + KASAN_ALLOCA_REDZONE_SIZE); + const void *right_redzone = (const void *)(addr + rounded_up_size); + + WARN_ON(!IS_ALIGNED(addr, KASAN_ALLOCA_REDZONE_SIZE)); + + kasan_unpoison_shadow((const void *)(addr + rounded_down_size), + size - rounded_down_size); + kasan_poison_shadow(left_redzone, KASAN_ALLOCA_REDZONE_SIZE, + KASAN_ALLOCA_LEFT); + kasan_poison_shadow(right_redzone, + padding_size + KASAN_ALLOCA_REDZONE_SIZE, + KASAN_ALLOCA_RIGHT); +} +EXPORT_SYMBOL(__asan_alloca_poison); + +/* Emitted by compiler to unpoison alloca()ed areas when the stack unwinds. */ +void __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom) +{ + if (unlikely(!stack_top || stack_top > stack_bottom)) + return; + + kasan_unpoison_shadow(stack_top, stack_bottom - stack_top); +} +EXPORT_SYMBOL(__asan_allocas_unpoison); + #ifdef CONFIG_MEMORY_HOTPLUG static int kasan_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index 1229298cce64..b857dc70d6a2 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -23,6 +23,14 @@ #define KASAN_STACK_PARTIAL 0xF4 #define KASAN_USE_AFTER_SCOPE 0xF8 +/* + * alloca redzone shadow values + */ +#define KASAN_ALLOCA_LEFT 0xCA +#define KASAN_ALLOCA_RIGHT 0xCB + +#define KASAN_ALLOCA_REDZONE_SIZE 32 + /* Don't break randconfig/all*config builds */ #ifndef KASAN_ABI_VERSION #define KASAN_ABI_VERSION 1 diff --git a/mm/kasan/report.c b/mm/kasan/report.c index 04bb1d3eb9ec..a3247975aaae 100644 --- a/mm/kasan/report.c +++ b/mm/kasan/report.c @@ -102,6 +102,10 @@ static const char *get_shadow_bug_type(struct kasan_access_info *info) case KASAN_USE_AFTER_SCOPE: bug_type = "use-after-scope"; break; + case KASAN_ALLOCA_LEFT: + case KASAN_ALLOCA_RIGHT: + bug_type = "alloca-out-of-bounds"; + break; } return bug_type; diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan index 30a1e3628809..8c69cd1a7776 100644 --- a/scripts/Makefile.kasan +++ b/scripts/Makefile.kasan @@ -31,7 +31,8 @@ else $(call cc-param,asan-globals=1) \ $(call cc-param,asan-instrumentation-with-call-threshold=$(call_threshold)) \ $(call cc-param,asan-stack=1) \ - $(call cc-param,asan-use-after-scope=1) + $(call cc-param,asan-use-after-scope=1) \ + $(call cc-param,asan-instrument-allocas=1) endif endif -- GitLab From a0ef47a66f3f1c76277518b796d26204691b6354 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 6 Feb 2018 15:36:16 -0800 Subject: [PATCH 0252/1834] UPSTREAM: kasan: add tests for alloca poisoning Link: http://lkml.kernel.org/r/20171204191735.132544-5-paullawrence@google.com Signed-off-by: Greg Hackmann Signed-off-by: Paul Lawrence Acked-by: Andrey Ryabinin Cc: Alexander Potapenko Cc: Dmitry Vyukov Cc: Masahiro Yamada Cc: Matthias Kaehlcke Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry-picked from 00a14294bb33af533f7ac002fb20623fdd8ea0d7) Change-Id: I2c3b607d67b4a788000c62ce920cfd603f42fa06 Signed-off-by: Paul Lawrence --- lib/test_kasan.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 0e70ecc12fe2..8fcad6191ade 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -440,6 +440,26 @@ static noinline void __init use_after_scope_test(void) p[1023] = 1; } +static noinline void __init kasan_alloca_oob_left(void) +{ + volatile int i = 10; + char alloca_array[i]; + char *p = alloca_array - 1; + + pr_info("out-of-bounds to left on alloca\n"); + *(volatile char *)p; +} + +static noinline void __init kasan_alloca_oob_right(void) +{ + volatile int i = 10; + char alloca_array[i]; + char *p = alloca_array + i; + + pr_info("out-of-bounds to right on alloca\n"); + *(volatile char *)p; +} + static int __init kmalloc_tests_init(void) { /* @@ -469,6 +489,8 @@ static int __init kmalloc_tests_init(void) kmem_cache_oob(); kasan_stack_oob(); kasan_global_oob(); + kasan_alloca_oob_left(); + kasan_alloca_oob_right(); ksize_unpoisons_memory(); copy_user_test(); use_after_scope_test(); -- GitLab From d6f27745679a1f446e82d33ee59238dac1f54c5d Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Tue, 6 Feb 2018 15:36:20 -0800 Subject: [PATCH 0253/1834] UPSTREAM: kasan: add functions for unpoisoning stack variables As a code-size optimization, LLVM builds since r279383 may bulk-manipulate the shadow region when (un)poisoning large memory blocks. This requires new callbacks that simply do an uninstrumented memset(). This fixes linking the Clang-built kernel when using KASAN. [arnd@arndb.de: add declarations for internal functions] Link: http://lkml.kernel.org/r/20180105094112.2690475-1-arnd@arndb.de [fengguang.wu@intel.com: __asan_set_shadow_00 can be static] Link: http://lkml.kernel.org/r/20171223125943.GA74341@lkp-ib03 [ghackmann@google.com: fix memset() parameters, and tweak commit message to describe new callbacks] Link: http://lkml.kernel.org/r/20171204191735.132544-6-paullawrence@google.com Signed-off-by: Alexander Potapenko Signed-off-by: Greg Hackmann Signed-off-by: Paul Lawrence Signed-off-by: Fengguang Wu Signed-off-by: Arnd Bergmann Acked-by: Andrey Ryabinin Cc: Dmitry Vyukov Cc: Masahiro Yamada Cc: Matthias Kaehlcke Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds (cherry-picked from d321599cf6b861beefe92327476b617435c7fc4a) Change-Id: I3bd77aa0dac7447c3436c8b12e5e84d06f062206 Signed-off-by: Paul Lawrence --- mm/kasan/kasan.c | 15 +++++++++++++++ mm/kasan/kasan.h | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c index 08edb57b3d1b..ab47d93a766f 100644 --- a/mm/kasan/kasan.c +++ b/mm/kasan/kasan.c @@ -828,6 +828,21 @@ void __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom) } EXPORT_SYMBOL(__asan_allocas_unpoison); +/* Emitted by the compiler to [un]poison local variables. */ +#define DEFINE_ASAN_SET_SHADOW(byte) \ + void __asan_set_shadow_##byte(const void *addr, size_t size) \ + { \ + __memset((void *)addr, 0x##byte, size); \ + } \ + EXPORT_SYMBOL(__asan_set_shadow_##byte) + +DEFINE_ASAN_SET_SHADOW(00); +DEFINE_ASAN_SET_SHADOW(f1); +DEFINE_ASAN_SET_SHADOW(f2); +DEFINE_ASAN_SET_SHADOW(f3); +DEFINE_ASAN_SET_SHADOW(f5); +DEFINE_ASAN_SET_SHADOW(f8); + #ifdef CONFIG_MEMORY_HOTPLUG static int kasan_mem_notifier(struct notifier_block *nb, unsigned long action, void *data) diff --git a/mm/kasan/kasan.h b/mm/kasan/kasan.h index b857dc70d6a2..d9cf9e2cc782 100644 --- a/mm/kasan/kasan.h +++ b/mm/kasan/kasan.h @@ -120,4 +120,48 @@ static inline void quarantine_reduce(void) { } static inline void quarantine_remove_cache(struct kmem_cache *cache) { } #endif +/* + * Exported functions for interfaces called from assembly or from generated + * code. Declarations here to avoid warning about missing declarations. + */ +asmlinkage void kasan_unpoison_task_stack_below(const void *watermark); +void __asan_register_globals(struct kasan_global *globals, size_t size); +void __asan_unregister_globals(struct kasan_global *globals, size_t size); +void __asan_loadN(unsigned long addr, size_t size); +void __asan_storeN(unsigned long addr, size_t size); +void __asan_handle_no_return(void); +void __asan_poison_stack_memory(const void *addr, size_t size); +void __asan_unpoison_stack_memory(const void *addr, size_t size); +void __asan_alloca_poison(unsigned long addr, size_t size); +void __asan_allocas_unpoison(const void *stack_top, const void *stack_bottom); + +void __asan_load1(unsigned long addr); +void __asan_store1(unsigned long addr); +void __asan_load2(unsigned long addr); +void __asan_store2(unsigned long addr); +void __asan_load4(unsigned long addr); +void __asan_store4(unsigned long addr); +void __asan_load8(unsigned long addr); +void __asan_store8(unsigned long addr); +void __asan_load16(unsigned long addr); +void __asan_store16(unsigned long addr); + +void __asan_load1_noabort(unsigned long addr); +void __asan_store1_noabort(unsigned long addr); +void __asan_load2_noabort(unsigned long addr); +void __asan_store2_noabort(unsigned long addr); +void __asan_load4_noabort(unsigned long addr); +void __asan_store4_noabort(unsigned long addr); +void __asan_load8_noabort(unsigned long addr); +void __asan_store8_noabort(unsigned long addr); +void __asan_load16_noabort(unsigned long addr); +void __asan_store16_noabort(unsigned long addr); + +void __asan_set_shadow_00(const void *addr, size_t size); +void __asan_set_shadow_f1(const void *addr, size_t size); +void __asan_set_shadow_f2(const void *addr, size_t size); +void __asan_set_shadow_f3(const void *addr, size_t size); +void __asan_set_shadow_f5(const void *addr, size_t size); +void __asan_set_shadow_f8(const void *addr, size_t size); + #endif -- GitLab From fc8bd0f6ffec17b56bca32b4dfa6ab0f1b7b4b29 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Thu, 15 Mar 2018 19:37:16 -0700 Subject: [PATCH 0254/1834] ANDROID: sdcardfs: fix lock issue on 32 bit/SMP architectures Fixes: a92bb8d6eac3 ("ANDROID: sdcardfs: Hold i_mutex for i_size_write") Change-Id: If7f2ed90f59c552b9ef9262b0f6aaed394f68784 Signed-off-by: Daniel Rosenberg Bug: 73287721 --- fs/sdcardfs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c index 2879d1291a11..1461254f301d 100644 --- a/fs/sdcardfs/file.c +++ b/fs/sdcardfs/file.c @@ -414,7 +414,7 @@ ssize_t sdcardfs_write_iter(struct kiocb *iocb, struct iov_iter *iter) fsstack_copy_inode_size(inode, file_inode(lower_file)); fsstack_copy_attr_times(inode, file_inode(lower_file)); if (sizeof(loff_t) > sizeof(long)) - inode_lock(inode); + inode_unlock(inode); } out: return err; -- GitLab From e126e3eaa219534530bedadb21d16482d538e344 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 7 Mar 2018 14:49:09 +0200 Subject: [PATCH 0255/1834] RDMA/ucma: Limit possible option size commit 6a21dfc0d0db7b7e0acedce67ca533a6eb19283c upstream. Users of ucma are supposed to provide size of option level, in most paths it is supposed to be equal to u8 or u16, but it is not the case for the IB path record, where it can be multiple of struct ib_path_rec_data. This patch takes simplest possible approach and prevents providing values more than possible to allocate. Reported-by: syzbot+a38b0e9f694c379ca7ce@syzkaller.appspotmail.com Fixes: 7ce86409adcd ("RDMA/ucma: Allow user space to set service type") Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 9520154f1d7c..dcca8c400646 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1275,6 +1275,9 @@ static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, if (IS_ERR(ctx)) return PTR_ERR(ctx); + if (unlikely(cmd.optval > KMALLOC_MAX_SIZE)) + return -EINVAL; + optval = memdup_user((void __user *) (unsigned long) cmd.optval, cmd.optlen); if (IS_ERR(optval)) { -- GitLab From b063d53d7a1d209da183d72ac0fda85a449d5810 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 7 Mar 2018 18:49:16 +0200 Subject: [PATCH 0256/1834] RDMA/ucma: Check that user doesn't overflow QP state commit a5880b84430316e3e1c1f5d23aa32ec6000cc717 upstream. The QP state is limited and declared in enum ib_qp_state, but ucma user was able to supply any possible (u32) value. Reported-by: syzbot+0df1ab766f8924b1edba@syzkaller.appspotmail.com Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index dcca8c400646..6840d3c5cd64 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1139,6 +1139,9 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; + if (cmd.qp_state > IB_QPS_ERR) + return -EINVAL; + ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); -- GitLab From 1bb454527e18b04437c41b2b4dfe31678fb4146d Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 7 Mar 2018 15:29:09 +0200 Subject: [PATCH 0257/1834] RDMA/mlx5: Fix integer overflow while resizing CQ commit 28e9091e3119933c38933cb8fc48d5618eb784c8 upstream. The user can provide very large cqe_size which will cause to integer overflow as it can be seen in the following UBSAN warning: ======================================================================= UBSAN: Undefined behaviour in drivers/infiniband/hw/mlx5/cq.c:1192:53 signed integer overflow: 64870 * 65536 cannot be represented in type 'int' CPU: 0 PID: 267 Comm: syzkaller605279 Not tainted 4.15.0+ #90 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0xde/0x164 ? dma_virt_map_sg+0x22c/0x22c ubsan_epilogue+0xe/0x81 handle_overflow+0x1f3/0x251 ? __ubsan_handle_negate_overflow+0x19b/0x19b ? lock_acquire+0x440/0x440 mlx5_ib_resize_cq+0x17e7/0x1e40 ? cyc2ns_read_end+0x10/0x10 ? native_read_msr_safe+0x6c/0x9b ? cyc2ns_read_end+0x10/0x10 ? mlx5_ib_modify_cq+0x220/0x220 ? sched_clock_cpu+0x18/0x200 ? lookup_get_idr_uobject+0x200/0x200 ? rdma_lookup_get_uobject+0x145/0x2f0 ib_uverbs_resize_cq+0x207/0x3e0 ? ib_uverbs_ex_create_cq+0x250/0x250 ib_uverbs_write+0x7f9/0xef0 ? cyc2ns_read_end+0x10/0x10 ? print_irqtrace_events+0x280/0x280 ? ib_uverbs_ex_create_cq+0x250/0x250 ? uverbs_devnode+0x110/0x110 ? sched_clock_cpu+0x18/0x200 ? do_raw_spin_trylock+0x100/0x100 ? __lru_cache_add+0x16e/0x290 __vfs_write+0x10d/0x700 ? uverbs_devnode+0x110/0x110 ? kernel_read+0x170/0x170 ? sched_clock_cpu+0x18/0x200 ? security_file_permission+0x93/0x260 vfs_write+0x1b0/0x550 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x1e/0x8b RIP: 0033:0x433549 RSP: 002b:00007ffe63bd1ea8 EFLAGS: 00000217 ======================================================================= Cc: syzkaller Cc: # 3.13 Fixes: bde51583f49b ("IB/mlx5: Add support for resize CQ") Reported-by: Noa Osherovich Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/cq.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index fcd04b881ec1..9cdcff77b9a8 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -1117,7 +1117,12 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, if (ucmd.reserved0 || ucmd.reserved1) return -EINVAL; - umem = ib_umem_get(context, ucmd.buf_addr, entries * ucmd.cqe_size, + /* check multiplication overflow */ + if (ucmd.cqe_size && SIZE_MAX / ucmd.cqe_size <= entries - 1) + return -EINVAL; + + umem = ib_umem_get(context, ucmd.buf_addr, + (size_t)ucmd.cqe_size * entries, IB_ACCESS_LOCAL_WRITE, 1); if (IS_ERR(umem)) { err = PTR_ERR(umem); -- GitLab From 84e1a8afc7dba0bca8986faba01032e46eae82f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20Br=C3=BCns?= Date: Sun, 31 Dec 2017 23:34:54 +0100 Subject: [PATCH 0258/1834] drm/i915: Try EDID bitbanging on HDMI after failed read MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 90024a5951029685acc5396258f1b0de9b23cf4a upstream. The ACK/NACK implementation as found in e.g. the G965 has the falling clock edge and the release of the data line after the ACK for the received byte happen at the same time. This is conformant with the I2C specification, which allows a zero hold time, see footnote [3]: "A device must internally provide a hold time of at least 300 ns for the SDA signal (with respect to the V IH(min) of the SCL signal) to bridge the undefined region of the falling edge of SCL." Some HDMI-to-VGA converters apparently fail to adhere to this requirement and latch SDA at the falling clock edge, so instead of an ACK sometimes a NACK is read and the slave (i.e. the EDID ROM) ends the transfer. The bitbanging releases the data line for the ACK only 1/4 bit time after the falling clock edge, so a slave will see the correct value no matter if it samples at the rising or the falling clock edge or in the center. Fallback to bitbanging is already done for the CRT connector. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92685 Signed-off-by: Stefan Brüns Cc: stable@vger.kernel.org Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/a39f080b-81a5-4c93-b3f7-7cb0a58daca3@rwthex-w2-a.rwth-ad.de (cherry picked from commit cfb926e148e99acc02351d72e8b85e32b5f786ef) Signed-off-by: Rodrigo Vivi Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/intel_hdmi.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 13c306173f27..0c935dede9f4 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1452,12 +1452,20 @@ intel_hdmi_set_edid(struct drm_connector *connector) struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector); struct edid *edid; bool connected = false; + struct i2c_adapter *i2c; intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); - edid = drm_get_edid(connector, - intel_gmbus_get_adapter(dev_priv, - intel_hdmi->ddc_bus)); + i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus); + + edid = drm_get_edid(connector, i2c); + + if (!edid && !intel_gmbus_is_forced_bit(i2c)) { + DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n"); + intel_gmbus_force_bit(i2c, true); + edid = drm_get_edid(connector, i2c); + intel_gmbus_force_bit(i2c, false); + } intel_hdmi_dp_dual_mode_detect(connector, edid != NULL); -- GitLab From 8f16e7d01b5f4f149d3cd7d5bf38a3e53792acf6 Mon Sep 17 00:00:00 2001 From: "himanshu.madhani@cavium.com" Date: Mon, 12 Feb 2018 10:28:14 -0800 Subject: [PATCH 0259/1834] scsi: qla2xxx: Fix NULL pointer crash due to active timer for ABTS commit 1514839b366417934e2f1328edb50ed1e8a719f5 upstream. This patch fixes NULL pointer crash due to active timer running for abort IOCB. From crash dump analysis it was discoverd that get_next_timer_interrupt() encountered a corrupted entry on the timer list. #9 [ffff95e1f6f0fd40] page_fault at ffffffff914fe8f8 [exception RIP: get_next_timer_interrupt+440] RIP: ffffffff90ea3088 RSP: ffff95e1f6f0fdf0 RFLAGS: 00010013 RAX: ffff95e1f6451028 RBX: 000218e2389e5f40 RCX: 00000001232ad600 RDX: 0000000000000001 RSI: ffff95e1f6f0fdf0 RDI: 0000000001232ad6 RBP: ffff95e1f6f0fe40 R8: ffff95e1f6451188 R9: 0000000000000001 R10: 0000000000000016 R11: 0000000000000016 R12: 00000001232ad5f6 R13: ffff95e1f6450000 R14: ffff95e1f6f0fdf8 R15: ffff95e1f6f0fe10 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 Looking at the assembly of get_next_timer_interrupt(), address came from %r8 (ffff95e1f6451188) which is pointing to list_head with single entry at ffff95e5ff621178. 0xffffffff90ea307a : mov (%r8),%rdx 0xffffffff90ea307d : cmp %r8,%rdx 0xffffffff90ea3080 : je 0xffffffff90ea30a7 0xffffffff90ea3082 : nopw 0x0(%rax,%rax,1) 0xffffffff90ea3088 : testb $0x1,0x18(%rdx) crash> rd ffff95e1f6451188 10 ffff95e1f6451188: ffff95e5ff621178 ffff95e5ff621178 x.b.....x.b..... ffff95e1f6451198: ffff95e1f6451198 ffff95e1f6451198 ..E.......E..... ffff95e1f64511a8: ffff95e1f64511a8 ffff95e1f64511a8 ..E.......E..... ffff95e1f64511b8: ffff95e77cf509a0 ffff95e77cf509a0 ...|.......|.... ffff95e1f64511c8: ffff95e1f64511c8 ffff95e1f64511c8 ..E.......E..... crash> rd ffff95e5ff621178 10 ffff95e5ff621178: 0000000000000001 ffff95e15936aa00 ..........6Y.... ffff95e5ff621188: 0000000000000000 00000000ffffffff ................ ffff95e5ff621198: 00000000000000a0 0000000000000010 ................ ffff95e5ff6211a8: ffff95e5ff621198 000000000000000c ..b............. ffff95e5ff6211b8: 00000f5800000000 ffff95e751f8d720 ....X... ..Q.... ffff95e5ff621178 belongs to freed mempool object at ffff95e5ff621080. CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE ffff95dc7fd74d00 mnt_cache 384 19785 24948 594 16k SLAB MEMORY NODE TOTAL ALLOCATED FREE ffffdc5dabfd8800 ffff95e5ff620000 1 42 29 13 FREE / [ALLOCATED] ffff95e5ff621080 (cpu 6 cache) Examining the contents of that memory reveals a pointer to a constant string in the driver, "abort\0", which is set by qla24xx_async_abort_cmd(). crash> rd ffffffffc059277c 20 ffffffffc059277c: 6e490074726f6261 0074707572726574 abort.Interrupt. ffffffffc059278c: 00676e696c6c6f50 6920726576697244 Polling.Driver i ffffffffc059279c: 646f6d207325206e 6974736554000a65 n %s mode..Testi ffffffffc05927ac: 636976656420676e 786c252074612065 ng device at %lx ffffffffc05927bc: 6b63656843000a2e 646f727020676e69 ...Checking prod ffffffffc05927cc: 6f20444920746375 0a2e706968632066 uct ID of chip.. ffffffffc05927dc: 5120646e756f4600 204130303232414c .Found QLA2200A ffffffffc05927ec: 43000a2e70696843 20676e696b636568 Chip...Checking ffffffffc05927fc: 65786f626c69616d 6c636e69000a2e73 mailboxes...incl ffffffffc059280c: 756e696c2f656475 616d2d616d642f78 ude/linux/dma-ma crash> struct -ox srb_iocb struct srb_iocb { union { struct {...} logio; struct {...} els_logo; struct {...} tmf; struct {...} fxiocb; struct {...} abt; struct ct_arg ctarg; struct {...} mbx; struct {...} nack; [0x0 ] } u; [0xb8] struct timer_list timer; [0x108] void (*timeout)(void *); } SIZE: 0x110 crash> ! bc ibase=16 obase=10 B8+40 F8 The object is a srb_t, and at offset 0xf8 within that structure (i.e. ffff95e5ff621080 + f8 -> ffff95e5ff621178) is a struct timer_list. Cc: #4.4+ Fixes: 4440e46d5db7 ("[SCSI] qla2xxx: Add IOCB Abort command asynchronous handling.") Signed-off-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 8f12f6baa6b8..4441a559f139 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -369,6 +369,7 @@ qla24xx_abort_sp_done(void *data, void *ptr, int res) srb_t *sp = (srb_t *)ptr; struct srb_iocb *abt = &sp->u.iocb_cmd; + del_timer(&sp->u.iocb_cmd.timer); complete(&abt->u.abt.comp); } -- GitLab From e9ca26c52280da324f5b4511ace7eb074f616920 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 16 Jan 2018 16:53:24 +0100 Subject: [PATCH 0260/1834] drm/i915: Always call to intel_display_set_init_power() in resume_early. commit d13a8479f3584613b6aacbb793eae64578b8f69a upstream. intel_power_domains_init_hw() calls set_init_power, but when using runtime power management this call is skipped. This prevents hw readout from taking place. Signed-off-by: Maarten Lankhorst Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=104172 Link: https://patchwork.freedesktop.org/patch/msgid/20180116155324.75120-1-maarten.lankhorst@linux.intel.com Fixes: bc87229f323e ("drm/i915/skl: enable PC9/10 power states during suspend-to-idle") Cc: Nivedita Swaminathan Cc: Imre Deak Cc: Patrik Jakobsson Cc: Jani Nikula Cc: Joonas Lahtinen Cc: Rodrigo Vivi Cc: # v4.5+ Reviewed-by: Imre Deak (cherry picked from commit ac25dfed15d470d7f23dd817e965b54aa3f94a1e) Signed-off-by: Rodrigo Vivi Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/i915/i915_drv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 7513e7678263..bae62cf934cf 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1703,6 +1703,8 @@ static int i915_drm_resume_early(struct drm_device *dev) if (IS_BROXTON(dev_priv) || !(dev_priv->suspended_to_idle && dev_priv->csr.dmc_payload)) intel_power_domains_init_hw(dev_priv, true); + else + intel_display_set_init_power(dev_priv, true); enable_rpm_wakeref_asserts(dev_priv); -- GitLab From 225ce6d7f2133071973c3fd5a006d58dd750a5a5 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 11 Feb 2018 10:38:28 +0100 Subject: [PATCH 0261/1834] workqueue: Allow retrieval of current task's work struct commit 27d4ee03078aba88c5e07dcc4917e8d01d046f38 upstream. Introduce a helper to retrieve the current task's work struct if it is a workqueue worker. This allows us to fix a long-standing deadlock in several DRM drivers wherein the ->runtime_suspend callback waits for a specific worker to finish and that worker in turn calls a function which waits for runtime suspend to finish. That function is invoked from multiple call sites and waiting for runtime suspend to finish is the correct thing to do except if it's executing in the context of the worker. Cc: Lai Jiangshan Cc: Dave Airlie Cc: Ben Skeggs Cc: Alex Deucher Acked-by: Tejun Heo Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/2d8f603074131eb87e588d2b803a71765bd3a2fd.1518338788.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- include/linux/workqueue.h | 1 + kernel/workqueue.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 1061add575d2..1def337b16d4 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -453,6 +453,7 @@ extern bool cancel_delayed_work_sync(struct delayed_work *dwork); extern void workqueue_set_max_active(struct workqueue_struct *wq, int max_active); +extern struct work_struct *current_work(void); extern bool current_is_workqueue_rescuer(void); extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); extern unsigned int work_busy(struct work_struct *work); diff --git a/kernel/workqueue.c b/kernel/workqueue.c index ebfea5f94b66..664aebc50fe3 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -4129,6 +4129,22 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) } EXPORT_SYMBOL_GPL(workqueue_set_max_active); +/** + * current_work - retrieve %current task's work struct + * + * Determine if %current task is a workqueue worker and what it's working on. + * Useful to find out the context that the %current task is running in. + * + * Return: work struct if %current task is a workqueue worker, %NULL otherwise. + */ +struct work_struct *current_work(void) +{ + struct worker *worker = current_wq_worker(); + + return worker ? worker->current_work : NULL; +} +EXPORT_SYMBOL(current_work); + /** * current_is_workqueue_rescuer - is %current workqueue rescuer? * -- GitLab From d006d9047c483f1cb0963cd4794d46eb2ff3fd07 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 14 Feb 2018 06:41:25 +0100 Subject: [PATCH 0262/1834] drm: Allow determining if current task is output poll worker commit 25c058ccaf2ebbc3e250ec1e199e161f91fe27d4 upstream. Introduce a helper to determine if the current task is an output poll worker. This allows us to fix a long-standing deadlock in several DRM drivers wherein the ->runtime_suspend callback waits for the output poll worker to finish and the worker in turn calls a ->detect callback which waits for runtime suspend to finish. The ->detect callback is invoked from multiple call sites and waiting for runtime suspend to finish is the correct thing to do except if it's executing in the context of the worker. v2: Expand kerneldoc to specifically mention deadlock between output poll worker and autosuspend worker as use case. (Lyude) Cc: Dave Airlie Cc: Ben Skeggs Cc: Alex Deucher Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/3549ce32e7f1467102e70d3e9cbf70c46bfe108e.1518593424.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_probe_helper.c | 20 ++++++++++++++++++++ include/drm/drm_crtc_helper.h | 1 + 2 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 276474d13763..d7822bef1986 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -460,6 +460,26 @@ static void output_poll_execute(struct work_struct *work) schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); } +/** + * drm_kms_helper_is_poll_worker - is %current task an output poll worker? + * + * Determine if %current task is an output poll worker. This can be used + * to select distinct code paths for output polling versus other contexts. + * + * One use case is to avoid a deadlock between the output poll worker and + * the autosuspend worker wherein the latter waits for polling to finish + * upon calling drm_kms_helper_poll_disable(), while the former waits for + * runtime suspend to finish upon calling pm_runtime_get_sync() in a + * connector ->detect hook. + */ +bool drm_kms_helper_is_poll_worker(void) +{ + struct work_struct *work = current_work(); + + return work && work->func == output_poll_execute; +} +EXPORT_SYMBOL(drm_kms_helper_is_poll_worker); + /** * drm_kms_helper_poll_disable - disable output polling * @dev: drm_device diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 982c299e435a..642d0597bb73 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -74,5 +74,6 @@ extern void drm_kms_helper_hotplug_event(struct drm_device *dev); extern void drm_kms_helper_poll_disable(struct drm_device *dev); extern void drm_kms_helper_poll_enable(struct drm_device *dev); extern void drm_kms_helper_poll_enable_locked(struct drm_device *dev); +extern bool drm_kms_helper_is_poll_worker(void); #endif -- GitLab From 24f82eef049e4caba0fbf6831dbc1dd255d97967 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 11 Feb 2018 10:38:28 +0100 Subject: [PATCH 0263/1834] drm/nouveau: Fix deadlock on runtime suspend commit d61a5c1063515e855bedb1b81e20e50b0ac3541e upstream. nouveau's ->runtime_suspend hook calls drm_kms_helper_poll_disable(), which waits for the output poll worker to finish if it's running. The output poll worker meanwhile calls pm_runtime_get_sync() in nouveau_connector_detect() which waits for the ongoing suspend to finish, causing a deadlock. Fix by not acquiring a runtime PM ref if nouveau_connector_detect() is called in the output poll worker's context. This is safe because the poll worker is only enabled while runtime active and we know that ->runtime_suspend waits for it to finish. Other contexts calling nouveau_connector_detect() do require a runtime PM ref, these comprise: status_store() drm sysfs interface ->fill_modes drm callback drm_fb_helper_probe_connector_modes() drm_mode_getconnector() nouveau_connector_hotplug() nouveau_display_hpd_work() nv17_tv_set_property() Stack trace for posterity: INFO: task kworker/0:1:58 blocked for more than 120 seconds. Workqueue: events output_poll_execute [drm_kms_helper] Call Trace: schedule+0x28/0x80 rpm_resume+0x107/0x6e0 __pm_runtime_resume+0x47/0x70 nouveau_connector_detect+0x7e/0x4a0 [nouveau] nouveau_connector_detect_lvds+0x132/0x180 [nouveau] drm_helper_probe_detect_ctx+0x85/0xd0 [drm_kms_helper] output_poll_execute+0x11e/0x1c0 [drm_kms_helper] process_one_work+0x184/0x380 worker_thread+0x2e/0x390 INFO: task kworker/0:2:252 blocked for more than 120 seconds. Workqueue: pm pm_runtime_work Call Trace: schedule+0x28/0x80 schedule_timeout+0x1e3/0x370 wait_for_completion+0x123/0x190 flush_work+0x142/0x1c0 nouveau_pmops_runtime_suspend+0x7e/0xd0 [nouveau] pci_pm_runtime_suspend+0x5c/0x180 vga_switcheroo_runtime_suspend+0x1e/0xa0 __rpm_callback+0xc1/0x200 rpm_callback+0x1f/0x70 rpm_suspend+0x13c/0x640 pm_runtime_work+0x6e/0x90 process_one_work+0x184/0x380 worker_thread+0x2e/0x390 Bugzilla: https://bugs.archlinux.org/task/53497 Bugzilla: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=870523 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=70388#c33 Fixes: 5addcf0a5f0f ("nouveau: add runtime PM support (v0.9)") Cc: stable@vger.kernel.org # v3.12+: 27d4ee03078a: workqueue: Allow retrieval of current task's work struct Cc: stable@vger.kernel.org # v3.12+: 25c058ccaf2e: drm: Allow determining if current task is output poll worker Cc: Ben Skeggs Cc: Dave Airlie Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/b7d2cbb609a80f59ccabfdf479b9d5907c603ea1.1518338789.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_connector.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index c1084088f9e4..56c288f78d8a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -271,9 +271,15 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) nv_connector->edid = NULL; } - ret = pm_runtime_get_sync(connector->dev->dev); - if (ret < 0 && ret != -EACCES) - return conn_status; + /* Outputs are only polled while runtime active, so acquiring a + * runtime PM ref here is unnecessary (and would deadlock upon + * runtime suspend because it waits for polling to finish). + */ + if (!drm_kms_helper_is_poll_worker()) { + ret = pm_runtime_get_sync(connector->dev->dev); + if (ret < 0 && ret != -EACCES) + return conn_status; + } nv_encoder = nouveau_connector_ddc_detect(connector); if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { @@ -348,8 +354,10 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return conn_status; } -- GitLab From bacc51c36ebdc39013c12d02cc9090e387c768ac Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 11 Feb 2018 10:38:28 +0100 Subject: [PATCH 0264/1834] drm/radeon: Fix deadlock on runtime suspend commit 15734feff2bdac24aa3266c437cffa42851990e3 upstream. radeon's ->runtime_suspend hook calls drm_kms_helper_poll_disable(), which waits for the output poll worker to finish if it's running. The output poll worker meanwhile calls pm_runtime_get_sync() in radeon's ->detect hooks, which waits for the ongoing suspend to finish, causing a deadlock. Fix by not acquiring a runtime PM ref if the ->detect hooks are called in the output poll worker's context. This is safe because the poll worker is only enabled while runtime active and we know that ->runtime_suspend waits for it to finish. Stack trace for posterity: INFO: task kworker/0:3:31847 blocked for more than 120 seconds Workqueue: events output_poll_execute [drm_kms_helper] Call Trace: schedule+0x3c/0x90 rpm_resume+0x1e2/0x690 __pm_runtime_resume+0x3f/0x60 radeon_lvds_detect+0x39/0xf0 [radeon] output_poll_execute+0xda/0x1e0 [drm_kms_helper] process_one_work+0x14b/0x440 worker_thread+0x48/0x4a0 INFO: task kworker/2:0:10493 blocked for more than 120 seconds. Workqueue: pm pm_runtime_work Call Trace: schedule+0x3c/0x90 schedule_timeout+0x1b3/0x240 wait_for_common+0xc2/0x180 wait_for_completion+0x1d/0x20 flush_work+0xfc/0x1a0 __cancel_work_timer+0xa5/0x1d0 cancel_delayed_work_sync+0x13/0x20 drm_kms_helper_poll_disable+0x1f/0x30 [drm_kms_helper] radeon_pmops_runtime_suspend+0x3d/0xa0 [radeon] pci_pm_runtime_suspend+0x61/0x1a0 vga_switcheroo_runtime_suspend+0x21/0x70 __rpm_callback+0x32/0x70 rpm_callback+0x24/0x80 rpm_suspend+0x12b/0x640 pm_runtime_work+0x6f/0xb0 process_one_work+0x14b/0x440 worker_thread+0x48/0x4a0 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94147 Fixes: 10ebc0bc0934 ("drm/radeon: add runtime PM support (v2)") Cc: stable@vger.kernel.org # v3.13+: 27d4ee03078a: workqueue: Allow retrieval of current task's work struct Cc: stable@vger.kernel.org # v3.13+: 25c058ccaf2e: drm: Allow determining if current task is output poll worker Cc: Ismo Toijala Cc: Alex Deucher Cc: Dave Airlie Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/64ea02c44f91dda19bc563902b97bbc699040392.1518338789.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 74 ++++++++++++++-------- 1 file changed, 49 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 27affbde058c..af0d7fd5706b 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -897,9 +897,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -922,8 +924,12 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) /* check acpi lid status ??? */ radeon_connector_update_scratch_regs(connector, ret); - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } + return ret; } @@ -1037,9 +1043,11 @@ radeon_vga_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } encoder = radeon_best_single_encoder(connector); if (!encoder) @@ -1106,8 +1114,10 @@ radeon_vga_detect(struct drm_connector *connector, bool force) radeon_connector_update_scratch_regs(connector, ret); out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -1171,9 +1181,11 @@ radeon_tv_detect(struct drm_connector *connector, bool force) if (!radeon_connector->dac_load_detect) return ret; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } encoder = radeon_best_single_encoder(connector); if (!encoder) @@ -1185,8 +1197,12 @@ radeon_tv_detect(struct drm_connector *connector, bool force) if (ret == connector_status_connected) ret = radeon_connector_analog_encoder_conflict_solve(connector, encoder, ret, false); radeon_connector_update_scratch_regs(connector, ret); - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } + return ret; } @@ -1249,9 +1265,11 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; bool dret = false, broken_edid = false; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (radeon_connector->detected_hpd_without_ddc) { force = true; @@ -1434,8 +1452,10 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) } exit: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -1686,9 +1706,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dig_connector->is_mst) return connector_status_disconnected; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (!force && radeon_check_hpd_status_unchanged(connector)) { ret = connector->status; @@ -1775,8 +1797,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force) } out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } -- GitLab From 3a7c3cab42a05d8a1428eb0186a8757b50e85202 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Sun, 11 Feb 2018 10:38:28 +0100 Subject: [PATCH 0265/1834] drm/amdgpu: Fix deadlock on runtime suspend commit aa0aad57909eb321746325951d66af88a83bc956 upstream. amdgpu's ->runtime_suspend hook calls drm_kms_helper_poll_disable(), which waits for the output poll worker to finish if it's running. The output poll worker meanwhile calls pm_runtime_get_sync() in amdgpu's ->detect hooks, which waits for the ongoing suspend to finish, causing a deadlock. Fix by not acquiring a runtime PM ref if the ->detect hooks are called in the output poll worker's context. This is safe because the poll worker is only enabled while runtime active and we know that ->runtime_suspend waits for it to finish. Fixes: d38ceaf99ed0 ("drm/amdgpu: add core driver (v4)") Cc: stable@vger.kernel.org # v4.2+: 27d4ee03078a: workqueue: Allow retrieval of current task's work struct Cc: stable@vger.kernel.org # v4.2+: 25c058ccaf2e: drm: Allow determining if current task is output poll worker Cc: Alex Deucher Tested-by: Mike Lothian Reviewed-by: Lyude Paul Signed-off-by: Lukas Wunner Link: https://patchwork.freedesktop.org/patch/msgid/4c9bf72aacae1eef062bd134cd112e0770a7f121.1518338789.git.lukas@wunner.de Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/amd/amdgpu/amdgpu_connectors.c | 58 ++++++++++++------- 1 file changed, 38 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index 086aa5c9c634..c82b04b24bf9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -739,9 +739,11 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (encoder) { struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); @@ -760,8 +762,12 @@ amdgpu_connector_lvds_detect(struct drm_connector *connector, bool force) /* check acpi lid status ??? */ amdgpu_connector_update_scratch_regs(connector, ret); - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } + return ret; } @@ -871,9 +877,11 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } encoder = amdgpu_connector_best_single_encoder(connector); if (!encoder) @@ -927,8 +935,10 @@ amdgpu_connector_vga_detect(struct drm_connector *connector, bool force) amdgpu_connector_update_scratch_regs(connector, ret); out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -991,9 +1001,11 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) enum drm_connector_status ret = connector_status_disconnected; bool dret = false, broken_edid = false; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { ret = connector->status; @@ -1118,8 +1130,10 @@ amdgpu_connector_dvi_detect(struct drm_connector *connector, bool force) amdgpu_connector_update_scratch_regs(connector, ret); exit: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } @@ -1362,9 +1376,11 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) struct drm_encoder *encoder = amdgpu_connector_best_single_encoder(connector); int r; - r = pm_runtime_get_sync(connector->dev->dev); - if (r < 0) - return connector_status_disconnected; + if (!drm_kms_helper_is_poll_worker()) { + r = pm_runtime_get_sync(connector->dev->dev); + if (r < 0) + return connector_status_disconnected; + } if (!force && amdgpu_connector_check_hpd_status_unchanged(connector)) { ret = connector->status; @@ -1432,8 +1448,10 @@ amdgpu_connector_dp_detect(struct drm_connector *connector, bool force) amdgpu_connector_update_scratch_regs(connector, ret); out: - pm_runtime_mark_last_busy(connector->dev->dev); - pm_runtime_put_autosuspend(connector->dev->dev); + if (!drm_kms_helper_is_poll_worker()) { + pm_runtime_mark_last_busy(connector->dev->dev); + pm_runtime_put_autosuspend(connector->dev->dev); + } return ret; } -- GitLab From 5bf82a32ac88ce9dcf118159fb3743dff29f096f Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Tue, 27 Feb 2018 18:20:53 +0800 Subject: [PATCH 0266/1834] drm/amdgpu: Notify sbios device ready before send request commit 1bced75f4ab04bec55aecb57d99435dc6d0ae5a0 upstream. it is required if a platform supports PCIe root complex core voltage reduction. After receiving this notification, SBIOS can apply default PCIe root complex power policy. Reviewed-by: Alex Deucher Signed-off-by: Rex Zhu Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 5796539a0bcb..648ecf69bad5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -540,6 +540,9 @@ int amdgpu_acpi_pcie_performance_request(struct amdgpu_device *adev, size_t size; u32 retry = 3; + if (amdgpu_acpi_pcie_notify_device_ready(adev)) + return -EINVAL; + /* Get the device handle */ handle = ACPI_HANDLE(&adev->pdev->dev); if (!handle) -- GitLab From a32168f9ba6e5e1f02548696528530808c7cb78b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Mar 2018 11:03:27 -0500 Subject: [PATCH 0267/1834] drm/radeon: fix KV harvesting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0b58d90f89545e021d188c289fa142e5ff9e708b upstream. Always set the graphics values to the max for the asic type. E.g., some 1 RB chips are actually 1 RB chips, others are actually harvested 2 RB chips. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=99353 Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/cik.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index edee6a5f4da9..b99f3e59011c 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3244,35 +3244,8 @@ static void cik_gpu_init(struct radeon_device *rdev) case CHIP_KAVERI: rdev->config.cik.max_shader_engines = 1; rdev->config.cik.max_tile_pipes = 4; - if ((rdev->pdev->device == 0x1304) || - (rdev->pdev->device == 0x1305) || - (rdev->pdev->device == 0x130C) || - (rdev->pdev->device == 0x130F) || - (rdev->pdev->device == 0x1310) || - (rdev->pdev->device == 0x1311) || - (rdev->pdev->device == 0x131C)) { - rdev->config.cik.max_cu_per_sh = 8; - rdev->config.cik.max_backends_per_se = 2; - } else if ((rdev->pdev->device == 0x1309) || - (rdev->pdev->device == 0x130A) || - (rdev->pdev->device == 0x130D) || - (rdev->pdev->device == 0x1313) || - (rdev->pdev->device == 0x131D)) { - rdev->config.cik.max_cu_per_sh = 6; - rdev->config.cik.max_backends_per_se = 2; - } else if ((rdev->pdev->device == 0x1306) || - (rdev->pdev->device == 0x1307) || - (rdev->pdev->device == 0x130B) || - (rdev->pdev->device == 0x130E) || - (rdev->pdev->device == 0x1315) || - (rdev->pdev->device == 0x1318) || - (rdev->pdev->device == 0x131B)) { - rdev->config.cik.max_cu_per_sh = 4; - rdev->config.cik.max_backends_per_se = 1; - } else { - rdev->config.cik.max_cu_per_sh = 3; - rdev->config.cik.max_backends_per_se = 1; - } + rdev->config.cik.max_cu_per_sh = 8; + rdev->config.cik.max_backends_per_se = 2; rdev->config.cik.max_sh_per_se = 1; rdev->config.cik.max_texture_channel_caches = 4; rdev->config.cik.max_gprs = 256; -- GitLab From 74d5d735a75b5d018c8275d899b023f1fab26598 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 1 Mar 2018 11:05:31 -0500 Subject: [PATCH 0268/1834] drm/amdgpu: fix KV harvesting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 545b0bcde7fbd3ee408fa842ea0731451dc4bd0a upstream. Always set the graphics values to the max for the asic type. E.g., some 1 RB chips are actually 1 RB chips, others are actually harvested 2 RB chips. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=99353 Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 30 ++------------------------- 1 file changed, 2 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 71116da9e782..e040a896179c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -4475,34 +4475,8 @@ static void gfx_v7_0_gpu_early_init(struct amdgpu_device *adev) case CHIP_KAVERI: adev->gfx.config.max_shader_engines = 1; adev->gfx.config.max_tile_pipes = 4; - if ((adev->pdev->device == 0x1304) || - (adev->pdev->device == 0x1305) || - (adev->pdev->device == 0x130C) || - (adev->pdev->device == 0x130F) || - (adev->pdev->device == 0x1310) || - (adev->pdev->device == 0x1311) || - (adev->pdev->device == 0x131C)) { - adev->gfx.config.max_cu_per_sh = 8; - adev->gfx.config.max_backends_per_se = 2; - } else if ((adev->pdev->device == 0x1309) || - (adev->pdev->device == 0x130A) || - (adev->pdev->device == 0x130D) || - (adev->pdev->device == 0x1313) || - (adev->pdev->device == 0x131D)) { - adev->gfx.config.max_cu_per_sh = 6; - adev->gfx.config.max_backends_per_se = 2; - } else if ((adev->pdev->device == 0x1306) || - (adev->pdev->device == 0x1307) || - (adev->pdev->device == 0x130B) || - (adev->pdev->device == 0x130E) || - (adev->pdev->device == 0x1315) || - (adev->pdev->device == 0x131B)) { - adev->gfx.config.max_cu_per_sh = 4; - adev->gfx.config.max_backends_per_se = 1; - } else { - adev->gfx.config.max_cu_per_sh = 3; - adev->gfx.config.max_backends_per_se = 1; - } + adev->gfx.config.max_cu_per_sh = 8; + adev->gfx.config.max_backends_per_se = 2; adev->gfx.config.max_sh_per_se = 1; adev->gfx.config.max_texture_channel_caches = 4; adev->gfx.config.max_gprs = 256; -- GitLab From 957cfa6f9bdec9fde07d034f94a44b708e3bf09b Mon Sep 17 00:00:00 2001 From: James Zhu Date: Tue, 6 Mar 2018 14:43:50 -0500 Subject: [PATCH 0269/1834] drm/amdgpu:Correct max uvd handles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 0e5ee33d2a54e4c55fe92857f23e1cbb0440d6de upstream. Max uvd handles should use adev->uvd.max_handles instead of AMDGPU_MAX_UVD_HANDLES here. Signed-off-by: James Zhu Reviewed-by: Leo Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index e3281cacc586..b7715d6a0252 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -277,7 +277,7 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) if (atomic_read(&adev->uvd.handles[i])) break; - if (i == AMDGPU_MAX_UVD_HANDLES) + if (i == adev->uvd.max_handles) return 0; cancel_delayed_work_sync(&adev->uvd.idle_work); -- GitLab From eea86015a5400f94ab8858e1cc7d90ea3639c447 Mon Sep 17 00:00:00 2001 From: James Zhu Date: Tue, 6 Mar 2018 14:52:35 -0500 Subject: [PATCH 0270/1834] drm/amdgpu:Always save uvd vcpu_bo in VM Mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit f8bee6135e167f5b35b7789c74c2956dad14d0d5 upstream. When UVD is in VM mode, there is not uvd handle exchanged, uvd.handles are always 0. So vcpu_bo always need save, Otherwise amdgpu driver will fail during suspend/resume. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=105021 Signed-off-by: James Zhu Reviewed-by: Leo Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index b7715d6a0252..5caf517eec9f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -273,12 +273,15 @@ int amdgpu_uvd_suspend(struct amdgpu_device *adev) if (adev->uvd.vcpu_bo == NULL) return 0; - for (i = 0; i < adev->uvd.max_handles; ++i) - if (atomic_read(&adev->uvd.handles[i])) - break; + /* only valid for physical mode */ + if (adev->asic_type < CHIP_POLARIS10) { + for (i = 0; i < adev->uvd.max_handles; ++i) + if (atomic_read(&adev->uvd.handles[i])) + break; - if (i == adev->uvd.max_handles) - return 0; + if (i == adev->uvd.max_handles) + return 0; + } cancel_delayed_work_sync(&adev->uvd.idle_work); -- GitLab From 4bd523ffe14578c9d840ec59e640cc4757ff37d2 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 27 Sep 2017 17:15:15 -0700 Subject: [PATCH 0271/1834] MIPS: BMIPS: Do not mask IPIs during suspend commit 06a3f0c9f2725f5d7c63c4203839373c9bd00c28 upstream. Commit a3e6c1eff548 ("MIPS: IRQ: Fix disable_irq on CPU IRQs") fixes an issue where disable_irq did not actually disable the irq. The bug caused our IPIs to not be disabled, which actually is the correct behavior. With the addition of commit a3e6c1eff548 ("MIPS: IRQ: Fix disable_irq on CPU IRQs"), the IPIs were getting disabled going into suspend, thus schedule_ipi() was not being called. This caused deadlocks where schedulable task were not being scheduled and other cpus were waiting for them to do something. Add the IRQF_NO_SUSPEND flag so an irq_disable will not be called on the IPIs during suspend. Signed-off-by: Justin Chen Fixes: a3e6c1eff548 ("MIPS: IRQ: Fix disabled_irq on CPU IRQs") Cc: Florian Fainelli Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/17385/ [jhogan@kernel.org: checkpatch: wrap long lines and fix commit refs] Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/smp-bmips.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c index 47c9646f93b3..d4a293b68249 100644 --- a/arch/mips/kernel/smp-bmips.c +++ b/arch/mips/kernel/smp-bmips.c @@ -166,11 +166,11 @@ static void bmips_prepare_cpus(unsigned int max_cpus) return; } - if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, - "smp_ipi0", NULL)) + if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, + IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi0", NULL)) panic("Can't request IPI0 interrupt"); - if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, IRQF_PERCPU, - "smp_ipi1", NULL)) + if (request_irq(IPI1_IRQ, bmips_ipi_interrupt, + IRQF_PERCPU | IRQF_NO_SUSPEND, "smp_ipi1", NULL)) panic("Can't request IPI1 interrupt"); } -- GitLab From 407795ea0ead051a6d3263054a5eb28b97840394 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Feb 2018 17:50:12 +0000 Subject: [PATCH 0272/1834] MIPS: ath25: Check for kzalloc allocation failure commit 1b22b4b28fd5fbc51855219e3238b3ab81da8466 upstream. Currently there is no null check on a failed allocation of board_data, and hence a null pointer dereference will occurr. Fix this by checking for the out of memory null pointer. Fixes: a7473717483e ("MIPS: ath25: add board configuration detection") Signed-off-by: Colin Ian King Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: # 3.19+ Patchwork: https://patchwork.linux-mips.org/patch/18657/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/ath25/board.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/ath25/board.c b/arch/mips/ath25/board.c index 9ab48ff80c1c..6d11ae581ea7 100644 --- a/arch/mips/ath25/board.c +++ b/arch/mips/ath25/board.c @@ -135,6 +135,8 @@ int __init ath25_find_config(phys_addr_t base, unsigned long size) } board_data = kzalloc(BOARD_CONFIG_BUFSZ, GFP_KERNEL); + if (!board_data) + goto error; ath25_board.config = (struct ath25_boarddata *)board_data; memcpy_fromio(board_data, bcfg, 0x100); if (broken_boarddata) { -- GitLab From a9fbf7a26088fb2765b1d41cb44da8e39128959c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Feb 2018 18:08:53 +0000 Subject: [PATCH 0273/1834] MIPS: OCTEON: irq: Check for null return on kzalloc allocation commit 902f4d067a50ccf645a58dd5fb1d113b6e0f9b5b upstream. The allocation of host_data is not null checked, leading to a null pointer dereference if the allocation fails. Fix this by adding a null check and return with -ENOMEM. Fixes: 64b139f97c01 ("MIPS: OCTEON: irq: add CIB and other fixes") Signed-off-by: Colin Ian King Acked-by: David Daney Cc: Ralf Baechle Cc: "Steven J. Hill" Cc: linux-mips@linux-mips.org Cc: # 4.0+ Patchwork: https://patchwork.linux-mips.org/patch/18658/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/cavium-octeon/octeon-irq.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index c1eb1ff7c800..6ed1ded87b8f 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -2277,6 +2277,8 @@ static int __init octeon_irq_init_cib(struct device_node *ciu_node, } host_data = kzalloc(sizeof(*host_data), GFP_KERNEL); + if (!host_data) + return -ENOMEM; raw_spin_lock_init(&host_data->lock); addr = of_get_address(ciu_node, 0, NULL, NULL); -- GitLab From 236ff4dd7cf973076ab46ff62bb6d0087d0f7ed1 Mon Sep 17 00:00:00 2001 From: Zhang Bo Date: Mon, 5 Feb 2018 14:56:21 -0800 Subject: [PATCH 0274/1834] Input: matrix_keypad - fix race when disabling interrupts commit ea4f7bd2aca9f68470e9aac0fc9432fd180b1fe7 upstream. If matrix_keypad_stop() is executing and the keypad interrupt is triggered, disable_row_irqs() may be called by both matrix_keypad_interrupt() and matrix_keypad_stop() at the same time, causing interrupts to be disabled twice and the keypad being "stuck" after resuming. Take lock when setting keypad->stopped to ensure that ISR will not race with matrix_keypad_stop() disabling interrupts. Signed-off-by: Zhang Bo Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/keyboard/matrix_keypad.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 7f12b6579f82..795fa353de7c 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -216,8 +216,10 @@ static void matrix_keypad_stop(struct input_dev *dev) { struct matrix_keypad *keypad = input_get_drvdata(dev); + spin_lock_irq(&keypad->lock); keypad->stopped = true; - mb(); + spin_unlock_irq(&keypad->lock); + flush_work(&keypad->work.work); /* * matrix_keypad_scan() will leave IRQs enabled; -- GitLab From c0fac97933c1da286e770e1cf5d4419191401fdc Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Fri, 9 Mar 2018 08:36:36 -0700 Subject: [PATCH 0275/1834] loop: Fix lost writes caused by missing flag commit 1d037577c323e5090ce281e96bc313ab2eee5be2 upstream. The following commit: commit aa4d86163e4e ("block: loop: switch to VFS ITER_BVEC") replaced __do_lo_send_write(), which used ITER_KVEC iterators, with lo_write_bvec() which uses ITER_BVEC iterators. In this change, though, the WRITE flag was lost: - iov_iter_kvec(&from, ITER_KVEC | WRITE, &kvec, 1, len); + iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len); This flag is necessary for the DAX case because we make decisions based on whether or not the iterator is a READ or a WRITE in dax_iomap_actor() and in dax_iomap_rw(). We end up going through this path in configurations where we combine a PMEM device with 4k sectors, a loopback device and DAX. The consequence of this missed flag is that what we intend as a write actually turns into a read in the DAX code, so no data is ever written. The very simplest test case is to create a loopback device and try and write a small string to it, then hexdump a few bytes of the device to see if the write took. Without this patch you read back all zeros, with this you read back the string you wrote. For XFS this causes us to fail or panic during the following xfstests: xfs/074 xfs/078 xfs/216 xfs/217 xfs/250 For ext4 we have a similar issue where writes never happen, but we don't currently have any xfstests that use loopback and show this issue. Fix this by restoring the WRITE flag argument to iov_iter_bvec(). This causes the xfstests to all pass. Cc: Al Viro Cc: stable@vger.kernel.org Fixes: commit aa4d86163e4e ("block: loop: switch to VFS ITER_BVEC") Reviewed-by: Christoph Hellwig Reviewed-by: Ming Lei Signed-off-by: Ross Zwisler Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 402254d26247..68bfcef24701 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -263,7 +263,7 @@ static int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) struct iov_iter i; ssize_t bw; - iov_iter_bvec(&i, ITER_BVEC, bvec, 1, bvec->bv_len); + iov_iter_bvec(&i, ITER_BVEC | WRITE, bvec, 1, bvec->bv_len); file_start_write(file); bw = vfs_iter_write(file, &i, ppos); -- GitLab From 4c5579483bd56aab3e009c8dac047b2051947299 Mon Sep 17 00:00:00 2001 From: Tiwei Bie Date: Fri, 23 Feb 2018 19:41:30 +0800 Subject: [PATCH 0276/1834] virtio_ring: fix num_free handling in error case commit e82df670235138575b37ff0ec24412a471efd97f upstream. The vq->vq.num_free hasn't been changed when error happens, so it shouldn't be changed when handling the error. Fixes: 780bc7903a32 ("virtio_ring: Support DMA APIs") Cc: Andy Lutomirski Cc: Michael S. Tsirkin Cc: stable@vger.kernel.org Signed-off-by: Tiwei Bie Signed-off-by: Michael S. Tsirkin Signed-off-by: Greg Kroah-Hartman --- drivers/virtio/virtio_ring.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 489bfc61cf30..8977f40ea441 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -423,8 +423,6 @@ static inline int virtqueue_add(struct virtqueue *_vq, i = vq->vring.desc[i].next; } - vq->vq.num_free += total_sg; - if (indirect) kfree(desc); -- GitLab From 6687863c4e45b4f6bf2a65d9eece23f494c1b06f Mon Sep 17 00:00:00 2001 From: David Hildenbrand Date: Tue, 6 Mar 2018 14:27:58 +0100 Subject: [PATCH 0277/1834] KVM: s390: fix memory overwrites when not using SCA entries commit f07afa0462b76a5b9c4f3a43d5ac24fdb86a90c2 upstream. Even if we don't have extended SCA support, we can have more than 64 CPUs if we don't enable any HW features that might use the SCA entries. Now, this works just fine, but we missed a return, which is why we would actually store the SCA entries. If we have more than 64 CPUs, this means writing outside of the basic SCA - bad. Let's fix this. This allows > 64 CPUs when running nested (under vSIE) without random crashes. Fixes: a6940674c384 ("KVM: s390: allow 255 VCPUs when sca entries aren't used") Reported-by: Christian Borntraeger Tested-by: Christian Borntraeger Signed-off-by: David Hildenbrand Message-Id: <20180306132758.21034-1-david@redhat.com> Cc: stable@vger.kernel.org Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger Signed-off-by: Greg Kroah-Hartman --- arch/s390/kvm/kvm-s390.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 5ba494ed18c1..a70ff09b4982 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1601,6 +1601,7 @@ static void sca_add_vcpu(struct kvm_vcpu *vcpu) /* we still need the basic sca for the ipte control */ vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32); vcpu->arch.sie_block->scaol = (__u32)(__u64)sca; + return; } read_lock(&vcpu->kvm->arch.sca_lock); if (vcpu->kvm->arch.use_esca) { -- GitLab From 333cdd174ca62f1640cc04eebb96adc2d76be599 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 8 Mar 2018 11:02:46 +0000 Subject: [PATCH 0278/1834] kbuild: Handle builtin dtb file names containing hyphens commit 55fe6da9efba102866e2fb5b40b04b6a4b26c19e upstream. cmd_dt_S_dtb constructs the assembly source to incorporate a devicetree FDT (that is, the .dtb file) as binary data in the kernel image. This assembly source contains labels before and after the binary data. The label names incorporate the file name of the corresponding .dtb file. Hyphens are not legal characters in labels, so .dtb files built into the kernel with hyphens in the file name result in errors like the following: bcm3368-netgear-cvg834g.dtb.S: Assembler messages: bcm3368-netgear-cvg834g.dtb.S:5: Error: : no such section bcm3368-netgear-cvg834g.dtb.S:5: Error: junk at end of line, first unrecognized character is `-' bcm3368-netgear-cvg834g.dtb.S:6: Error: unrecognized opcode `__dtb_bcm3368-netgear-cvg834g_begin:' bcm3368-netgear-cvg834g.dtb.S:8: Error: unrecognized opcode `__dtb_bcm3368-netgear-cvg834g_end:' bcm3368-netgear-cvg834g.dtb.S:9: Error: : no such section bcm3368-netgear-cvg834g.dtb.S:9: Error: junk at end of line, first unrecognized character is `-' Fix this by updating cmd_dt_S_dtb to transform all hyphens from the file name to underscores when constructing the labels. As of v4.16-rc2, 1139 .dts files across ARM64, ARM, MIPS and PowerPC contain hyphens in their names, but the issue only currently manifests on Broadcom MIPS platforms, as that is the only place where such files are built into the kernel. For example when CONFIG_DT_NETGEAR_CVG834G=y, or on BMIPS kernels when the dtbs target is used (in the latter case it admittedly shouldn't really build all the dtb.o files, but thats a separate issue). Fixes: 695835511f96 ("MIPS: BMIPS: rename bcm96358nb4ser to bcm6358-neufbox4-sercom") Signed-off-by: James Hogan Reviewed-by: Frank Rowand Cc: Rob Herring Cc: Michal Marek Cc: Ralf Baechle Cc: Florian Fainelli Cc: Kevin Cernekee Cc: # 4.9+ Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- scripts/Makefile.lib | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 0a07f9014944..ae0f9ab1a70d 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -290,11 +290,11 @@ cmd_dt_S_dtb= \ echo '\#include '; \ echo '.section .dtb.init.rodata,"a"'; \ echo '.balign STRUCT_ALIGNMENT'; \ - echo '.global __dtb_$(*F)_begin'; \ - echo '__dtb_$(*F)_begin:'; \ + echo '.global __dtb_$(subst -,_,$(*F))_begin'; \ + echo '__dtb_$(subst -,_,$(*F))_begin:'; \ echo '.incbin "$<" '; \ - echo '__dtb_$(*F)_end:'; \ - echo '.global __dtb_$(*F)_end'; \ + echo '__dtb_$(subst -,_,$(*F))_end:'; \ + echo '.global __dtb_$(subst -,_,$(*F))_end'; \ echo '.balign STRUCT_ALIGNMENT'; \ ) > $@ -- GitLab From e749262f1dcdf70687a432df29a6d70b6b0246a7 Mon Sep 17 00:00:00 2001 From: Sergey Gorenko Date: Sun, 25 Feb 2018 13:39:48 +0200 Subject: [PATCH 0279/1834] IB/mlx5: Fix incorrect size of klms in the memory region commit da343b6d90e11132f1e917d865d88ee35d6e6d00 upstream. The value of mr->ndescs greater than mr->max_descs is set in the function mlx5_ib_sg_to_klms() if sg_nents is greater than mr->max_descs. This is an invalid value and it causes the following error when registering mr: mlx5_0:dump_cqe:276:(pid 193): dump error cqe 00000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000030: 00 00 00 00 0f 00 78 06 25 00 00 8b 08 1e 8f d3 Cc: # 4.5 Fixes: b005d3164713 ("mlx5: Add arbitrary sg list support") Signed-off-by: Sergey Gorenko Tested-by: Laurence Oberman Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index c7d5786d366b..7e466f031e30 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1821,7 +1821,6 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, mr->ibmr.iova = sg_dma_address(sg) + sg_offset; mr->ibmr.length = 0; - mr->ndescs = sg_nents; for_each_sg(sgl, sg, sg_nents, i) { if (unlikely(i >= mr->max_descs)) @@ -1833,6 +1832,7 @@ mlx5_ib_sg_to_klms(struct mlx5_ib_mr *mr, sg_offset = 0; } + mr->ndescs = i; if (sg_offset_p) *sg_offset_p = sg_offset; -- GitLab From 35d9c9eac24fefeb01a8d74959785bd249f3aeb7 Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Mon, 5 Mar 2018 13:41:54 -0800 Subject: [PATCH 0280/1834] bcache: fix crashes in duplicate cache device register commit cc40daf91bdddbba72a4a8cd0860640e06668309 upstream. Kernel crashed when register a duplicate cache device, the call trace is bellow: [ 417.643790] CPU: 1 PID: 16886 Comm: bcache-register Tainted: G W OE 4.15.5-amd64-preempt-sysrq-20171018 #2 [ 417.643861] Hardware name: LENOVO 20ERCTO1WW/20ERCTO1WW, BIOS N1DET41W (1.15 ) 12/31/2015 [ 417.643870] RIP: 0010:bdevname+0x13/0x1e [ 417.643876] RSP: 0018:ffffa3aa9138fd38 EFLAGS: 00010282 [ 417.643884] RAX: 0000000000000000 RBX: ffff8c8f2f2f8000 RCX: ffffd6701f8 c7edf [ 417.643890] RDX: ffffa3aa9138fd88 RSI: ffffa3aa9138fd88 RDI: 00000000000 00000 [ 417.643895] RBP: ffffa3aa9138fde0 R08: ffffa3aa9138fae8 R09: 00000000000 1850e [ 417.643901] R10: ffff8c8eed34b271 R11: ffff8c8eed34b250 R12: 00000000000 00000 [ 417.643906] R13: ffffd6701f78f940 R14: ffff8c8f38f80000 R15: ffff8c8ea7d 90000 [ 417.643913] FS: 00007fde7e66f500(0000) GS:ffff8c8f61440000(0000) knlGS: 0000000000000000 [ 417.643919] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 417.643925] CR2: 0000000000000314 CR3: 00000007e6fa0001 CR4: 00000000003 606e0 [ 417.643931] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 00000000000 00000 [ 417.643938] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 00000000000 00400 [ 417.643946] Call Trace: [ 417.643978] register_bcache+0x1117/0x1270 [bcache] [ 417.643994] ? slab_pre_alloc_hook+0x15/0x3c [ 417.644001] ? slab_post_alloc_hook.isra.44+0xa/0x1a [ 417.644013] ? kernfs_fop_write+0xf6/0x138 [ 417.644020] kernfs_fop_write+0xf6/0x138 [ 417.644031] __vfs_write+0x31/0xcc [ 417.644043] ? current_kernel_time64+0x10/0x36 [ 417.644115] ? __audit_syscall_entry+0xbf/0xe3 [ 417.644124] vfs_write+0xa5/0xe2 [ 417.644133] SyS_write+0x5c/0x9f [ 417.644144] do_syscall_64+0x72/0x81 [ 417.644161] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 417.644169] RIP: 0033:0x7fde7e1c1974 [ 417.644175] RSP: 002b:00007fff13009a38 EFLAGS: 00000246 ORIG_RAX: 0000000 000000001 [ 417.644183] RAX: ffffffffffffffda RBX: 0000000001658280 RCX: 00007fde7e1c 1974 [ 417.644188] RDX: 000000000000000a RSI: 0000000001658280 RDI: 000000000000 0001 [ 417.644193] RBP: 000000000000000a R08: 0000000000000003 R09: 000000000000 0077 [ 417.644198] R10: 000000000000089e R11: 0000000000000246 R12: 000000000000 0001 [ 417.644203] R13: 000000000000000a R14: 7fffffffffffffff R15: 000000000000 0000 [ 417.644213] Code: c7 c2 83 6f ee 98 be 20 00 00 00 48 89 df e8 6c 27 3b 0 0 48 89 d8 5b c3 0f 1f 44 00 00 48 8b 47 70 48 89 f2 48 8b bf 80 00 00 00 <8 b> b0 14 03 00 00 e9 73 ff ff ff 0f 1f 44 00 00 48 8b 47 40 39 [ 417.644302] RIP: bdevname+0x13/0x1e RSP: ffffa3aa9138fd38 [ 417.644306] CR2: 0000000000000314 When registering duplicate cache device in register_cache(), after failure on calling register_cache_set(), bch_cache_release() will be called, then bdev will be freed, so bdevname(bdev, name) caused kernel crash. Since bch_cache_release() will free bdev, so in this patch we make sure bdev being freed if register_cache() fail, and do not free bdev again in register_bcache() when register_cache() fail. Signed-off-by: Tang Junhui Reported-by: Marc MERLIN Tested-by: Michael Lyle Reviewed-by: Michael Lyle Cc: Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/super.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 28ce342348a9..62f9f743c365 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1182,7 +1182,7 @@ static void register_bdev(struct cache_sb *sb, struct page *sb_page, return; err: - pr_notice("error opening %s: %s", bdevname(bdev, name), err); + pr_notice("error %s: %s", bdevname(bdev, name), err); bcache_device_stop(&dc->disk); } @@ -1853,6 +1853,8 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, const char *err = NULL; /* must be set for any error case */ int ret = 0; + bdevname(bdev, name); + memcpy(&ca->sb, sb, sizeof(struct cache_sb)); ca->bdev = bdev; ca->bdev->bd_holder = ca; @@ -1863,11 +1865,12 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, ca->sb_bio.bi_io_vec[0].bv_page = sb_page; get_page(sb_page); - if (blk_queue_discard(bdev_get_queue(ca->bdev))) + if (blk_queue_discard(bdev_get_queue(bdev))) ca->discard = CACHE_DISCARD(&ca->sb); ret = cache_alloc(ca); if (ret != 0) { + blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); if (ret == -ENOMEM) err = "cache_alloc(): -ENOMEM"; else @@ -1890,14 +1893,14 @@ static int register_cache(struct cache_sb *sb, struct page *sb_page, goto out; } - pr_info("registered cache device %s", bdevname(bdev, name)); + pr_info("registered cache device %s", name); out: kobject_put(&ca->kobj); err: if (err) - pr_notice("error opening %s: %s", bdevname(bdev, name), err); + pr_notice("error %s: %s", name, err); return ret; } @@ -1986,6 +1989,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, if (err) goto err_close; + err = "failed to register device"; if (SB_IS_BDEV(sb)) { struct cached_dev *dc = kzalloc(sizeof(*dc), GFP_KERNEL); if (!dc) @@ -2000,7 +2004,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, goto err_close; if (register_cache(sb, sb_page, bdev, ca) != 0) - goto err_close; + goto err; } out: if (sb_page) @@ -2013,7 +2017,7 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr, err_close: blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); err: - pr_info("error opening %s: %s", path, err); + pr_info("error %s: %s", path, err); ret = -EINVAL; goto out; } -- GitLab From d4f80945828c025e43273cc094f09fb6fe353dbf Mon Sep 17 00:00:00 2001 From: Michael Lyle Date: Mon, 5 Mar 2018 13:41:55 -0800 Subject: [PATCH 0281/1834] bcache: don't attach backing with duplicate UUID commit 86755b7a96faed57f910f9e6b8061e019ac1ec08 upstream. This can happen e.g. during disk cloning. This is an incomplete fix: it does not catch duplicate UUIDs earlier when things are still unattached. It does not unregister the device. Further changes to cope better with this are planned but conflict with Coly's ongoing improvements to handling device errors. In the meantime, one can manually stop the device after this has happened. Attempts to attach a duplicate device result in: [ 136.372404] loop: module loaded [ 136.424461] bcache: register_bdev() registered backing device loop0 [ 136.424464] bcache: bch_cached_dev_attach() Tried to attach loop0 but duplicate UUID already attached My test procedure is: dd if=/dev/sdb1 of=imgfile bs=1024 count=262144 losetup -f imgfile Signed-off-by: Michael Lyle Reviewed-by: Tang Junhui Cc: Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/super.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 62f9f743c365..c61341c84d2d 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -937,6 +937,7 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) uint32_t rtime = cpu_to_le32(get_seconds()); struct uuid_entry *u; char buf[BDEVNAME_SIZE]; + struct cached_dev *exist_dc, *t; bdevname(dc->bdev, buf); @@ -960,6 +961,16 @@ int bch_cached_dev_attach(struct cached_dev *dc, struct cache_set *c) return -EINVAL; } + /* Check whether already attached */ + list_for_each_entry_safe(exist_dc, t, &c->cached_devs, list) { + if (!memcmp(dc->sb.uuid, exist_dc->sb.uuid, 16)) { + pr_err("Tried to attach %s but duplicate UUID already attached", + buf); + + return -EINVAL; + } + } + u = uuid_find(c, dc->sb.uuid); if (u && -- GitLab From 2cc98fddf0f4a746071e098075a832fbec4bbfff Mon Sep 17 00:00:00 2001 From: Seunghun Han Date: Tue, 6 Mar 2018 15:21:43 +0100 Subject: [PATCH 0282/1834] x86/MCE: Serialize sysfs changes commit b3b7c4795ccab5be71f080774c45bbbcc75c2aaf upstream. The check_interval file in /sys/devices/system/machinecheck/machinecheck directory is a global timer value for MCE polling. If it is changed by one CPU, mce_restart() broadcasts the event to other CPUs to delete and restart the MCE polling timer and __mcheck_cpu_init_timer() reinitializes the mce_timer variable. If more than one CPU writes a specific value to the check_interval file concurrently, mce_timer is not protected from such concurrent accesses and all kinds of explosions happen. Since only root can write to those sysfs variables, the issue is not a big deal security-wise. However, concurrent writes to these configuration variables is void of reason so the proper thing to do is to serialize the access with a mutex. Boris: - Make store_int_with_restart() use device_store_ulong() to filter out negative intervals - Limit min interval to 1 second - Correct locking - Massage commit message Signed-off-by: Seunghun Han Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Cc: Greg Kroah-Hartman Cc: Tony Luck Cc: linux-edac Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/20180302202706.9434-1-kkamagui@gmail.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index fe5cd6ea1f0e..684d9fd191e0 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -61,6 +61,9 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex); smp_load_acquire(&(p)); \ }) +/* sysfs synchronization */ +static DEFINE_MUTEX(mce_sysfs_mutex); + #define CREATE_TRACE_POINTS #include @@ -2308,6 +2311,7 @@ static ssize_t set_ignore_ce(struct device *s, if (kstrtou64(buf, 0, &new) < 0) return -EINVAL; + mutex_lock(&mce_sysfs_mutex); if (mca_cfg.ignore_ce ^ !!new) { if (new) { /* disable ce features */ @@ -2320,6 +2324,8 @@ static ssize_t set_ignore_ce(struct device *s, on_each_cpu(mce_enable_ce, (void *)1, 1); } } + mutex_unlock(&mce_sysfs_mutex); + return size; } @@ -2332,6 +2338,7 @@ static ssize_t set_cmci_disabled(struct device *s, if (kstrtou64(buf, 0, &new) < 0) return -EINVAL; + mutex_lock(&mce_sysfs_mutex); if (mca_cfg.cmci_disabled ^ !!new) { if (new) { /* disable cmci */ @@ -2343,6 +2350,8 @@ static ssize_t set_cmci_disabled(struct device *s, on_each_cpu(mce_enable_ce, NULL, 1); } } + mutex_unlock(&mce_sysfs_mutex); + return size; } @@ -2350,8 +2359,19 @@ static ssize_t store_int_with_restart(struct device *s, struct device_attribute *attr, const char *buf, size_t size) { - ssize_t ret = device_store_int(s, attr, buf, size); + unsigned long old_check_interval = check_interval; + ssize_t ret = device_store_ulong(s, attr, buf, size); + + if (check_interval == old_check_interval) + return ret; + + if (check_interval < 1) + check_interval = 1; + + mutex_lock(&mce_sysfs_mutex); mce_restart(); + mutex_unlock(&mce_sysfs_mutex); + return ret; } -- GitLab From 9ed6e56e4fef2896b601c5f06b70e64f15ff9499 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 28 Feb 2018 10:39:04 +0200 Subject: [PATCH 0283/1834] perf tools: Fix trigger class trigger_on() commit de19e5c3c51fdb1ff20d0f61d099db902ff7494b upstream. trigger_on() means that the trigger is available but not ready, however trigger_on() was making it ready. That can segfault if the signal comes before trigger_ready(). e.g. (USR2 signal delivery not shown) $ perf record -e intel_pt//u -S sleep 1 perf: Segmentation fault Obtained 16 stack frames. /home/ahunter/bin/perf(sighandler_dump_stack+0x40) [0x4ec550] /lib/x86_64-linux-gnu/libc.so.6(+0x36caf) [0x7fa76411acaf] /home/ahunter/bin/perf(perf_evsel__disable+0x26) [0x4b9dd6] /home/ahunter/bin/perf() [0x43a45b] /lib/x86_64-linux-gnu/libc.so.6(+0x36caf) [0x7fa76411acaf] /lib/x86_64-linux-gnu/libc.so.6(__xstat64+0x15) [0x7fa7641d2cc5] /home/ahunter/bin/perf() [0x4ec6c9] /home/ahunter/bin/perf() [0x4ec73b] /home/ahunter/bin/perf() [0x4ec73b] /home/ahunter/bin/perf() [0x4ec73b] /home/ahunter/bin/perf() [0x4eca15] /home/ahunter/bin/perf(machine__create_kernel_maps+0x257) [0x4f0b77] /home/ahunter/bin/perf(perf_session__new+0xc0) [0x4f86f0] /home/ahunter/bin/perf(cmd_record+0x722) [0x43c132] /home/ahunter/bin/perf() [0x4a11ae] /home/ahunter/bin/perf(main+0x5d4) [0x427fb4] Note, for testing purposes, this is hard to hit unless you add some sleep() in builtin-record.c before record__open(). Signed-off-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Wang Nan Cc: stable@vger.kernel.org Fixes: 3dcc4436fa6f ("perf tools: Introduce trigger class") Link: http://lkml.kernel.org/r/1519807144-30694-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/trigger.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h index e97d7016d771..ce7e6e5c1cea 100644 --- a/tools/perf/util/trigger.h +++ b/tools/perf/util/trigger.h @@ -11,7 +11,7 @@ * States and transits: * * - * OFF--(on)--> READY --(hit)--> HIT + * OFF--> ON --> READY --(hit)--> HIT * ^ | * | (ready) * | | @@ -26,8 +26,9 @@ struct trigger { volatile enum { TRIGGER_ERROR = -2, TRIGGER_OFF = -1, - TRIGGER_READY = 0, - TRIGGER_HIT = 1, + TRIGGER_ON = 0, + TRIGGER_READY = 1, + TRIGGER_HIT = 2, } state; const char *name; }; @@ -49,7 +50,7 @@ static inline bool trigger_is_error(struct trigger *t) static inline void trigger_on(struct trigger *t) { TRIGGER_WARN_ONCE(t, TRIGGER_OFF); - t->state = TRIGGER_READY; + t->state = TRIGGER_ON; } static inline void trigger_ready(struct trigger *t) -- GitLab From 502a2780ac1113064e550c17d6852b4fb921ee9b Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Mon, 26 Feb 2018 09:35:01 -0500 Subject: [PATCH 0284/1834] x86/spectre_v2: Don't check microcode versions when running under hypervisors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 36268223c1e9981d6cfc33aff8520b3bde4b8114 upstream. As: 1) It's known that hypervisors lie about the environment anyhow (host mismatch) 2) Even if the hypervisor (Xen, KVM, VMWare, etc) provided a valid "correct" value, it all gets to be very murky when migration happens (do you provide the "new" microcode of the machine?). And in reality the cloud vendors are the ones that should make sure that the microcode that is running is correct and we should just sing lalalala and trust them. Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: Thomas Gleixner Reviewed-by: Paolo Bonzini Cc: Wanpeng Li Cc: kvm Cc: Krčmář Cc: Borislav Petkov CC: "H. Peter Anvin" CC: stable@vger.kernel.org Link: https://lkml.kernel.org/r/20180226213019.GE9497@char.us.oracle.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/intel.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 6ed206bd9071..768042530af2 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -103,6 +103,13 @@ static bool bad_spectre_microcode(struct cpuinfo_x86 *c) { int i; + /* + * We know that the hypervisor lie to us on the microcode version so + * we may as well hope that it is running the correct version. + */ + if (cpu_has(c, X86_FEATURE_HYPERVISOR)) + return false; + for (i = 0; i < ARRAY_SIZE(spectre_bad_microcodes); i++) { if (c->x86_model == spectre_bad_microcodes[i].model && c->x86_stepping == spectre_bad_microcodes[i].stepping) -- GitLab From f8521dba646dfa3401521967cbfd7f54a1c4c76f Mon Sep 17 00:00:00 2001 From: Benjamin Berg Date: Wed, 14 Feb 2018 13:29:39 +0100 Subject: [PATCH 0285/1834] ALSA: hda/realtek: Limit mic boost on T480 commit 85981dfd6b0a0fd9ed87ca4a525981b67c21f098 upstream. The internal mic boost on the T480 is too high. Fix this by applying the ALC269_FIXUP_LIMIT_INT_MIC_BOOST fixup to the machine to limit the gain. Signed-off-by: Benjamin Berg Tested-by: Benjamin Berg Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 974b74e91ef0..dc8185bf2f0f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5788,6 +5788,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), -- GitLab From b992e8f506f808a8df7f4fd1745e0c9461dadb6c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 Mar 2018 12:14:17 +0100 Subject: [PATCH 0286/1834] ALSA: hda/realtek - Fix dock line-out volume on Dell Precision 7520 commit e312a869cd726c698a75caca0d9e5c22fd3f1534 upstream. The dock line-out pin (NID 0x17 of ALC3254 codec) on Dell Precision 7520 may route to three different DACs, 0x02, 0x03 and 0x06. The first two DACS have the volume amp controls while the last one doesn't. And unfortunately, the auto-parser assigns this pin to DAC3, resulting in the non-working volume control for the line out. Fix it by disabling the routing to DAC3 on the corresponding pin. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199029 Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index dc8185bf2f0f..d019fa511f23 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4760,6 +4760,16 @@ static void alc298_fixup_speaker_volume(struct hda_codec *codec, } } +/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */ +static void alc295_fixup_disable_dac3(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + hda_nid_t conn[2] = { 0x02, 0x03 }; + snd_hda_override_conn_list(codec, 0x17, 2, conn); + } +} + /* Hook to update amp GPIO4 for automute */ static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec, struct hda_jack_callback *jack) @@ -4909,6 +4919,7 @@ enum { ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, ALC255_FIXUP_DELL_SPK_NOISE, ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC295_FIXUP_DISABLE_DAC3, ALC280_FIXUP_HP_HEADSET_MIC, ALC221_FIXUP_HP_FRONT_MIC, ALC292_FIXUP_TPT460, @@ -5601,6 +5612,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, }, + [ALC295_FIXUP_DISABLE_DAC3] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc295_fixup_disable_dac3, + }, [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -5664,6 +5679,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME), + SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3), SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER), SND_PCI_QUIRK(0x1028, 0x082a, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), -- GitLab From 5191f41745f84eee6f95dd834635dcb83a36926e Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Thu, 8 Mar 2018 13:17:54 +0100 Subject: [PATCH 0287/1834] ALSA: hda/realtek - Make dock sound work on ThinkPad L570 commit e4c07b3b66b7d6a24c2fe3b1ddeff5cd9b378b3a upstream. One version of Lenovo Thinkpad T570 did not use ALC298 (like other Kaby Lake devices). Instead it uses ALC292. In order to make the Lenovo dock working with that codec the dock quirk for ALC292 will be used. Signed-off-by: Dennis Wassenberg Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d019fa511f23..cd427ea8861d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5801,6 +5801,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460), SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK), -- GitLab From 0d7252d33dcb8e79d3d46da96e43ce3d56f29c2e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 5 Mar 2018 22:00:55 +0100 Subject: [PATCH 0288/1834] ALSA: seq: Don't allow resizing pool in use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit d85739367c6d56e475c281945c68fdb05ca74b4c upstream. This is a fix for a (sort of) fallout in the recent commit d15d662e89fc ("ALSA: seq: Fix racy pool initializations") for CVE-2018-1000004. As the pool resize deletes the existing cells, it may lead to a race when another thread is writing concurrently, eventually resulting a UAF. A simple workaround is not to allow the pool resizing when the pool is in use. It's an invalid behavior in anyway. Fixes: d15d662e89fc ("ALSA: seq: Fix racy pool initializations") Reported-by: 范龙飞 Reported-by: Nicolai Stange Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_clientmgr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 0b408617b2c9..ec4d42b5116f 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1835,6 +1835,9 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client, (! snd_seq_write_pool_allocated(client) || info->output_pool != client->pool->size)) { if (snd_seq_write_pool_allocated(client)) { + /* is the pool in use? */ + if (atomic_read(&client->pool->counter)) + return -EBUSY; /* remove all existing cells */ snd_seq_pool_mark_closing(client->pool); snd_seq_queue_client_leave_cells(client->number); -- GitLab From ec0011620b81d701151b10e108e6cd9e374f8759 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 5 Mar 2018 22:06:09 +0100 Subject: [PATCH 0289/1834] ALSA: seq: More protection for concurrent write and ioctl races MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7bd80091567789f1c0cb70eb4737aac8bcd2b6b9 upstream. This patch is an attempt for further hardening against races between the concurrent write and ioctls. The previous fix d15d662e89fc ("ALSA: seq: Fix racy pool initializations") covered the race of the pool initialization at writer and the pool resize ioctl by the client->ioctl_mutex (CVE-2018-1000004). However, basically this mutex should be applied more widely to the whole write operation for avoiding the unexpected pool operations by another thread. The only change outside snd_seq_write() is the additional mutex argument to helper functions, so that we can unlock / relock the given mutex temporarily during schedule() call for blocking write. Fixes: d15d662e89fc ("ALSA: seq: Fix racy pool initializations") Reported-by: 范龙飞 Reported-by: Nicolai Stange Reviewed-and-tested-by: Nicolai Stange Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_clientmgr.c | 18 +++++++++++------- sound/core/seq/seq_fifo.c | 2 +- sound/core/seq/seq_memory.c | 14 ++++++++++---- sound/core/seq/seq_memory.h | 3 ++- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index ec4d42b5116f..799ad3e1d24b 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -906,7 +906,8 @@ int snd_seq_dispatch_event(struct snd_seq_event_cell *cell, int atomic, int hop) static int snd_seq_client_enqueue_event(struct snd_seq_client *client, struct snd_seq_event *event, struct file *file, int blocking, - int atomic, int hop) + int atomic, int hop, + struct mutex *mutexp) { struct snd_seq_event_cell *cell; int err; @@ -944,7 +945,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client, return -ENXIO; /* queue is not allocated */ /* allocate an event cell */ - err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, file); + err = snd_seq_event_dup(client->pool, event, &cell, !blocking || atomic, + file, mutexp); if (err < 0) return err; @@ -1013,12 +1015,11 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, return -ENXIO; /* allocate the pool now if the pool is not allocated yet */ + mutex_lock(&client->ioctl_mutex); if (client->pool->size > 0 && !snd_seq_write_pool_allocated(client)) { - mutex_lock(&client->ioctl_mutex); err = snd_seq_pool_init(client->pool); - mutex_unlock(&client->ioctl_mutex); if (err < 0) - return -ENOMEM; + goto out; } /* only process whole events */ @@ -1069,7 +1070,7 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, /* ok, enqueue it */ err = snd_seq_client_enqueue_event(client, &event, file, !(file->f_flags & O_NONBLOCK), - 0, 0); + 0, 0, &client->ioctl_mutex); if (err < 0) break; @@ -1080,6 +1081,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, written += len; } + out: + mutex_unlock(&client->ioctl_mutex); return written ? written : err; } @@ -2262,7 +2265,8 @@ static int kernel_client_enqueue(int client, struct snd_seq_event *ev, if (! cptr->accept_output) result = -EPERM; else /* send it */ - result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, atomic, hop); + result = snd_seq_client_enqueue_event(cptr, ev, file, blocking, + atomic, hop, NULL); snd_seq_client_unlock(cptr); return result; diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 3490d21ab9e7..9acbed1ac982 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -123,7 +123,7 @@ int snd_seq_fifo_event_in(struct snd_seq_fifo *f, return -EINVAL; snd_use_lock_use(&f->use_lock); - err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL); /* always non-blocking */ + err = snd_seq_event_dup(f->pool, event, &cell, 1, NULL, NULL); /* always non-blocking */ if (err < 0) { if ((err == -ENOMEM) || (err == -EAGAIN)) atomic_inc(&f->overflow); diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 5847c4475bf3..4c8cbcd89887 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -221,7 +221,8 @@ void snd_seq_cell_free(struct snd_seq_event_cell * cell) */ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, struct snd_seq_event_cell **cellp, - int nonblock, struct file *file) + int nonblock, struct file *file, + struct mutex *mutexp) { struct snd_seq_event_cell *cell; unsigned long flags; @@ -245,7 +246,11 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&pool->output_sleep, &wait); spin_unlock_irq(&pool->lock); + if (mutexp) + mutex_unlock(mutexp); schedule(); + if (mutexp) + mutex_lock(mutexp); spin_lock_irq(&pool->lock); remove_wait_queue(&pool->output_sleep, &wait); /* interrupted? */ @@ -288,7 +293,7 @@ static int snd_seq_cell_alloc(struct snd_seq_pool *pool, */ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, struct snd_seq_event_cell **cellp, int nonblock, - struct file *file) + struct file *file, struct mutex *mutexp) { int ncells, err; unsigned int extlen; @@ -305,7 +310,7 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, if (ncells >= pool->total_elements) return -ENOMEM; - err = snd_seq_cell_alloc(pool, &cell, nonblock, file); + err = snd_seq_cell_alloc(pool, &cell, nonblock, file, mutexp); if (err < 0) return err; @@ -331,7 +336,8 @@ int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, int size = sizeof(struct snd_seq_event); if (len < size) size = len; - err = snd_seq_cell_alloc(pool, &tmp, nonblock, file); + err = snd_seq_cell_alloc(pool, &tmp, nonblock, file, + mutexp); if (err < 0) goto __error; if (cell->event.data.ext.ptr == NULL) diff --git a/sound/core/seq/seq_memory.h b/sound/core/seq/seq_memory.h index 32f959c17786..3abe306c394a 100644 --- a/sound/core/seq/seq_memory.h +++ b/sound/core/seq/seq_memory.h @@ -66,7 +66,8 @@ struct snd_seq_pool { void snd_seq_cell_free(struct snd_seq_event_cell *cell); int snd_seq_event_dup(struct snd_seq_pool *pool, struct snd_seq_event *event, - struct snd_seq_event_cell **cellp, int nonblock, struct file *file); + struct snd_seq_event_cell **cellp, int nonblock, + struct file *file, struct mutex *mutexp); /* return number of unused (free) cells */ static inline int snd_seq_unused_cells(struct snd_seq_pool *pool) -- GitLab From 5614f3a69d8b43776960595a7bc8e9d4802c0fdc Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Thu, 8 Mar 2018 15:49:03 +0100 Subject: [PATCH 0290/1834] ALSA: hda: add dock and led support for HP EliteBook 820 G3 commit aea808172018ca01abf53db808323aed23281835 upstream. This patch adds missing initialisation for HP 2013 UltraSlim Dock Line-In/Out PINs and activates keyboard mute/micmute leds for HP EliteBook 820 G3 Signed-off-by: Dennis Wassenberg Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 2c3065c1f3fb..aff4097c6903 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -849,6 +849,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), -- GitLab From 5b8dce7403a4b13d5ef1a4d87a6591bba44f4165 Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Thu, 8 Mar 2018 15:49:24 +0100 Subject: [PATCH 0291/1834] ALSA: hda: add dock and led support for HP ProBook 640 G2 commit 099fd6ca0ad25bc19c5ade2ea4b25b8fadaa11b3 upstream. This patch adds missing initialisation for HP 2013 UltraSlim Dock Line-In/Out PINs and activates keyboard mute/micmute leds for HP ProBook 640 G2 Signed-off-by: Dennis Wassenberg Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index aff4097c6903..b3851b991120 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -850,6 +850,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK), + SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), -- GitLab From 244a6d39d68b3729cf63a2d7b137c7e975e83300 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 16 Feb 2018 13:20:42 -0800 Subject: [PATCH 0292/1834] nospec: Kill array_index_nospec_mask_check() commit 1d91c1d2c80cb70e2e553845e278b87a960c04da upstream. There are multiple problems with the dynamic sanity checking in array_index_nospec_mask_check(): * It causes unnecessary overhead in the 32-bit case since integer sized @index values will no longer cause the check to be compiled away like in the 64-bit case. * In the 32-bit case it may trigger with user controllable input when the expectation is that should only trigger during development of new kernel enabling. * The macro reuses the input parameter in multiple locations which is broken if someone passes an expression like 'index++' to array_index_nospec(). Reported-by: Linus Torvalds Signed-off-by: Dan Williams Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Josh Poimboeuf Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Link: http://lkml.kernel.org/r/151881604278.17395.6605847763178076520.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/nospec.h | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/include/linux/nospec.h b/include/linux/nospec.h index 132e3f5a2e0d..172a19dc35ab 100644 --- a/include/linux/nospec.h +++ b/include/linux/nospec.h @@ -29,26 +29,6 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, } #endif -/* - * Warn developers about inappropriate array_index_nospec() usage. - * - * Even if the CPU speculates past the WARN_ONCE branch, the - * sign bit of @index is taken into account when generating the - * mask. - * - * This warning is compiled out when the compiler can infer that - * @index and @size are less than LONG_MAX. - */ -#define array_index_mask_nospec_check(index, size) \ -({ \ - if (WARN_ONCE(index > LONG_MAX || size > LONG_MAX, \ - "array_index_nospec() limited to range of [0, LONG_MAX]\n")) \ - _mask = 0; \ - else \ - _mask = array_index_mask_nospec(index, size); \ - _mask; \ -}) - /* * array_index_nospec - sanitize an array index after a bounds check * @@ -67,7 +47,7 @@ static inline unsigned long array_index_mask_nospec(unsigned long index, ({ \ typeof(index) _i = (index); \ typeof(size) _s = (size); \ - unsigned long _mask = array_index_mask_nospec_check(_i, _s); \ + unsigned long _mask = array_index_mask_nospec(_i, _s); \ \ BUILD_BUG_ON(sizeof(_i) > sizeof(long)); \ BUILD_BUG_ON(sizeof(_s) > sizeof(long)); \ -- GitLab From 6310a11fce7b9c5c0ac7654f40d6fcc9f48a1240 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 16 Feb 2018 13:20:54 -0800 Subject: [PATCH 0293/1834] nospec: Include dependency commit eb6174f6d1be16b19cfa43dac296bfed003ce1a6 upstream. The nospec.h header expects the per-architecture header file to optionally define array_index_mask_nospec(). Include that dependency to prevent inadvertent fallback to the default array_index_mask_nospec() implementation. The default implementation may not provide a full mitigation on architectures that perform data value speculation. Reported-by: Christian Borntraeger Signed-off-by: Dan Williams Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-arch@vger.kernel.org Link: http://lkml.kernel.org/r/151881605404.17395.1341935530792574707.stgit@dwillia2-desk3.amr.corp.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- include/linux/nospec.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/nospec.h b/include/linux/nospec.h index 172a19dc35ab..e791ebc65c9c 100644 --- a/include/linux/nospec.h +++ b/include/linux/nospec.h @@ -5,6 +5,7 @@ #ifndef _LINUX_NOSPEC_H #define _LINUX_NOSPEC_H +#include /** * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise -- GitLab From afb9851d3d1b10e8445196a8be449193568d27ae Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 19 Feb 2018 10:50:56 +0000 Subject: [PATCH 0294/1834] Revert "x86/retpoline: Simplify vmexit_fill_RSB()" commit d1c99108af3c5992640aa2afa7d2e88c3775c06e upstream. This reverts commit 1dde7415e99933bb7293d6b2843752cbdb43ec11. By putting the RSB filling out of line and calling it, we waste one RSB slot for returning from the function itself, which means one fewer actual function call we can make if we're doing the Skylake abomination of call-depth counting. It also changed the number of RSB stuffings we do on vmexit from 32, which was correct, to 16. Let's just stop with the bikeshedding; it didn't actually *fix* anything anyway. Signed-off-by: David Woodhouse Acked-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: arjan.van.de.ven@intel.com Cc: bp@alien8.de Cc: dave.hansen@intel.com Cc: jmattson@google.com Cc: karahmed@amazon.de Cc: kvm@vger.kernel.org Cc: pbonzini@redhat.com Cc: rkrcmar@redhat.com Link: http://lkml.kernel.org/r/1519037457-7643-4-git-send-email-dwmw@amazon.co.uk Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/entry/entry_32.S | 3 +- arch/x86/entry/entry_64.S | 3 +- arch/x86/include/asm/asm-prototypes.h | 3 -- arch/x86/include/asm/nospec-branch.h | 70 ++++++++++++++++++++++++--- arch/x86/lib/Makefile | 1 - arch/x86/lib/retpoline.S | 56 --------------------- 6 files changed, 65 insertions(+), 71 deletions(-) diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S index f5434b4670c1..a76dc738ec61 100644 --- a/arch/x86/entry/entry_32.S +++ b/arch/x86/entry/entry_32.S @@ -237,8 +237,7 @@ ENTRY(__switch_to_asm) * exist, overwrite the RSB with entries which capture * speculative execution to prevent attack. */ - /* Clobbers %ebx */ - FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW + FILL_RETURN_BUFFER %ebx, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW #endif /* restore callee-saved registers */ diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 8d7e4d48db0d..58610fe93f5d 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -331,8 +331,7 @@ ENTRY(__switch_to_asm) * exist, overwrite the RSB with entries which capture * speculative execution to prevent attack. */ - /* Clobbers %rbx */ - FILL_RETURN_BUFFER RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW + FILL_RETURN_BUFFER %r12, RSB_CLEAR_LOOPS, X86_FEATURE_RSB_CTXSW #endif /* restore callee-saved registers */ diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h index 166654218329..5a25ada75aeb 100644 --- a/arch/x86/include/asm/asm-prototypes.h +++ b/arch/x86/include/asm/asm-prototypes.h @@ -37,7 +37,4 @@ INDIRECT_THUNK(dx) INDIRECT_THUNK(si) INDIRECT_THUNK(di) INDIRECT_THUNK(bp) -asmlinkage void __fill_rsb(void); -asmlinkage void __clear_rsb(void); - #endif /* CONFIG_RETPOLINE */ diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 81a1be326571..dace2de39699 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -8,6 +8,50 @@ #include #include +/* + * Fill the CPU return stack buffer. + * + * Each entry in the RSB, if used for a speculative 'ret', contains an + * infinite 'pause; lfence; jmp' loop to capture speculative execution. + * + * This is required in various cases for retpoline and IBRS-based + * mitigations for the Spectre variant 2 vulnerability. Sometimes to + * eliminate potentially bogus entries from the RSB, and sometimes + * purely to ensure that it doesn't get empty, which on some CPUs would + * allow predictions from other (unwanted!) sources to be used. + * + * We define a CPP macro such that it can be used from both .S files and + * inline assembly. It's possible to do a .macro and then include that + * from C via asm(".include ") but let's not go there. + */ + +#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */ +#define RSB_FILL_LOOPS 16 /* To avoid underflow */ + +/* + * Google experimented with loop-unrolling and this turned out to be + * the optimal version — two calls, each with their own speculation + * trap should their return address end up getting used, in a loop. + */ +#define __FILL_RETURN_BUFFER(reg, nr, sp) \ + mov $(nr/2), reg; \ +771: \ + call 772f; \ +773: /* speculation trap */ \ + pause; \ + lfence; \ + jmp 773b; \ +772: \ + call 774f; \ +775: /* speculation trap */ \ + pause; \ + lfence; \ + jmp 775b; \ +774: \ + dec reg; \ + jnz 771b; \ + add $(BITS_PER_LONG/8) * nr, sp; + #ifdef __ASSEMBLY__ /* @@ -78,10 +122,17 @@ #endif .endm -/* This clobbers the BX register */ -.macro FILL_RETURN_BUFFER nr:req ftr:req + /* + * A simpler FILL_RETURN_BUFFER macro. Don't make people use the CPP + * monstrosity above, manually. + */ +.macro FILL_RETURN_BUFFER reg:req nr:req ftr:req #ifdef CONFIG_RETPOLINE - ALTERNATIVE "", "call __clear_rsb", \ftr + ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE "jmp .Lskip_rsb_\@", \ + __stringify(__FILL_RETURN_BUFFER(\reg,\nr,%_ASM_SP)) \ + \ftr +.Lskip_rsb_\@: #endif .endm @@ -156,10 +207,15 @@ extern char __indirect_thunk_end[]; static inline void vmexit_fill_RSB(void) { #ifdef CONFIG_RETPOLINE - alternative_input("", - "call __fill_rsb", - X86_FEATURE_RETPOLINE, - ASM_NO_INPUT_CLOBBER(_ASM_BX, "memory")); + unsigned long loops; + + asm volatile (ANNOTATE_NOSPEC_ALTERNATIVE + ALTERNATIVE("jmp 910f", + __stringify(__FILL_RETURN_BUFFER(%0, RSB_CLEAR_LOOPS, %1)), + X86_FEATURE_RETPOLINE) + "910:" + : "=r" (loops), ASM_CALL_CONSTRAINT + : : "memory" ); #endif } diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 4ad7c4dd311c..6bf1898ddf49 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -26,7 +26,6 @@ lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o lib-$(CONFIG_RANDOMIZE_BASE) += kaslr.o lib-$(CONFIG_RETPOLINE) += retpoline.o -OBJECT_FILES_NON_STANDARD_retpoline.o :=y obj-y += msr.o msr-reg.o msr-reg-export.o hweight.o diff --git a/arch/x86/lib/retpoline.S b/arch/x86/lib/retpoline.S index 480edc3a5e03..c909961e678a 100644 --- a/arch/x86/lib/retpoline.S +++ b/arch/x86/lib/retpoline.S @@ -7,7 +7,6 @@ #include #include #include -#include .macro THUNK reg .section .text.__x86.indirect_thunk @@ -47,58 +46,3 @@ GENERATE_THUNK(r13) GENERATE_THUNK(r14) GENERATE_THUNK(r15) #endif - -/* - * Fill the CPU return stack buffer. - * - * Each entry in the RSB, if used for a speculative 'ret', contains an - * infinite 'pause; lfence; jmp' loop to capture speculative execution. - * - * This is required in various cases for retpoline and IBRS-based - * mitigations for the Spectre variant 2 vulnerability. Sometimes to - * eliminate potentially bogus entries from the RSB, and sometimes - * purely to ensure that it doesn't get empty, which on some CPUs would - * allow predictions from other (unwanted!) sources to be used. - * - * Google experimented with loop-unrolling and this turned out to be - * the optimal version - two calls, each with their own speculation - * trap should their return address end up getting used, in a loop. - */ -.macro STUFF_RSB nr:req sp:req - mov $(\nr / 2), %_ASM_BX - .align 16 -771: - call 772f -773: /* speculation trap */ - pause - lfence - jmp 773b - .align 16 -772: - call 774f -775: /* speculation trap */ - pause - lfence - jmp 775b - .align 16 -774: - dec %_ASM_BX - jnz 771b - add $((BITS_PER_LONG/8) * \nr), \sp -.endm - -#define RSB_FILL_LOOPS 16 /* To avoid underflow */ - -ENTRY(__fill_rsb) - STUFF_RSB RSB_FILL_LOOPS, %_ASM_SP - ret -END(__fill_rsb) -EXPORT_SYMBOL_GPL(__fill_rsb) - -#define RSB_CLEAR_LOOPS 32 /* To forcibly overwrite all entries */ - -ENTRY(__clear_rsb) - STUFF_RSB RSB_CLEAR_LOOPS, %_ASM_SP - ret -END(__clear_rsb) -EXPORT_SYMBOL_GPL(__clear_rsb) -- GitLab From a27ede1bedcb21b8514f9bd9fcfc37773b816701 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 19 Feb 2018 10:50:54 +0000 Subject: [PATCH 0295/1834] x86/speculation: Use IBRS if available before calling into firmware commit dd84441a797150dcc49298ec95c459a8891d8bb1 upstream. Retpoline means the kernel is safe because it has no indirect branches. But firmware isn't, so use IBRS for firmware calls if it's available. Block preemption while IBRS is set, although in practice the call sites already had to be doing that. Ignore hpwdt.c for now. It's taking spinlocks and calling into firmware code, from an NMI handler. I don't want to touch that with a bargepole. Signed-off-by: David Woodhouse Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: arjan.van.de.ven@intel.com Cc: bp@alien8.de Cc: dave.hansen@intel.com Cc: jmattson@google.com Cc: karahmed@amazon.de Cc: kvm@vger.kernel.org Cc: pbonzini@redhat.com Cc: rkrcmar@redhat.com Link: http://lkml.kernel.org/r/1519037457-7643-2-git-send-email-dwmw@amazon.co.uk Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/apm.h | 6 +++++ arch/x86/include/asm/cpufeatures.h | 1 + arch/x86/include/asm/efi.h | 17 ++++++++++-- arch/x86/include/asm/nospec-branch.h | 39 +++++++++++++++++++++------- arch/x86/kernel/cpu/bugs.c | 12 ++++++++- 5 files changed, 63 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/apm.h b/arch/x86/include/asm/apm.h index 93eebc636c76..46e40aeae446 100644 --- a/arch/x86/include/asm/apm.h +++ b/arch/x86/include/asm/apm.h @@ -6,6 +6,8 @@ #ifndef _ASM_X86_MACH_DEFAULT_APM_H #define _ASM_X86_MACH_DEFAULT_APM_H +#include + #ifdef APM_ZERO_SEGS # define APM_DO_ZERO_SEGS \ "pushl %%ds\n\t" \ @@ -31,6 +33,7 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, * N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ + firmware_restrict_branch_speculation_start(); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -43,6 +46,7 @@ static inline void apm_bios_call_asm(u32 func, u32 ebx_in, u32 ecx_in, "=S" (*esi) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); + firmware_restrict_branch_speculation_end(); } static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, @@ -55,6 +59,7 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, * N.B. We do NOT need a cld after the BIOS call * because we always save and restore the flags. */ + firmware_restrict_branch_speculation_start(); __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" @@ -67,6 +72,7 @@ static inline bool apm_bios_call_simple_asm(u32 func, u32 ebx_in, "=S" (si) : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); + firmware_restrict_branch_speculation_end(); return error; } diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index 8eb23f5cf7f4..ed7a1d2c4235 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -203,6 +203,7 @@ #define X86_FEATURE_KAISER ( 7*32+31) /* CONFIG_PAGE_TABLE_ISOLATION w/o nokaiser */ #define X86_FEATURE_USE_IBPB ( 7*32+21) /* "" Indirect Branch Prediction Barrier enabled */ +#define X86_FEATURE_USE_IBRS_FW ( 7*32+22) /* "" Use IBRS during runtime firmware calls */ /* Virtualization flags: Linux defined, word 8 */ #define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */ diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h index 389d700b961e..9df22bb07f7f 100644 --- a/arch/x86/include/asm/efi.h +++ b/arch/x86/include/asm/efi.h @@ -5,6 +5,7 @@ #include #include #include +#include /* * We map the EFI regions needed for runtime services non-contiguously, @@ -35,8 +36,18 @@ extern unsigned long asmlinkage efi_call_phys(void *, ...); -#define arch_efi_call_virt_setup() kernel_fpu_begin() -#define arch_efi_call_virt_teardown() kernel_fpu_end() +#define arch_efi_call_virt_setup() \ +({ \ + kernel_fpu_begin(); \ + firmware_restrict_branch_speculation_start(); \ +}) + +#define arch_efi_call_virt_teardown() \ +({ \ + firmware_restrict_branch_speculation_end(); \ + kernel_fpu_end(); \ +}) + /* * Wrap all the virtual calls in a way that forces the parameters on the stack. @@ -72,6 +83,7 @@ struct efi_scratch { efi_sync_low_kernel_mappings(); \ preempt_disable(); \ __kernel_fpu_begin(); \ + firmware_restrict_branch_speculation_start(); \ \ if (efi_scratch.use_pgd) { \ efi_scratch.prev_cr3 = read_cr3(); \ @@ -90,6 +102,7 @@ struct efi_scratch { __flush_tlb_all(); \ } \ \ + firmware_restrict_branch_speculation_end(); \ __kernel_fpu_end(); \ preempt_enable(); \ }) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index dace2de39699..031840a848d2 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -219,17 +219,38 @@ static inline void vmexit_fill_RSB(void) #endif } +#define alternative_msr_write(_msr, _val, _feature) \ + asm volatile(ALTERNATIVE("", \ + "movl %[msr], %%ecx\n\t" \ + "movl %[val], %%eax\n\t" \ + "movl $0, %%edx\n\t" \ + "wrmsr", \ + _feature) \ + : : [msr] "i" (_msr), [val] "i" (_val) \ + : "eax", "ecx", "edx", "memory") + static inline void indirect_branch_prediction_barrier(void) { - asm volatile(ALTERNATIVE("", - "movl %[msr], %%ecx\n\t" - "movl %[val], %%eax\n\t" - "movl $0, %%edx\n\t" - "wrmsr", - X86_FEATURE_USE_IBPB) - : : [msr] "i" (MSR_IA32_PRED_CMD), - [val] "i" (PRED_CMD_IBPB) - : "eax", "ecx", "edx", "memory"); + alternative_msr_write(MSR_IA32_PRED_CMD, PRED_CMD_IBPB, + X86_FEATURE_USE_IBPB); +} + +/* + * With retpoline, we must use IBRS to restrict branch prediction + * before calling into firmware. + */ +static inline void firmware_restrict_branch_speculation_start(void) +{ + preempt_disable(); + alternative_msr_write(MSR_IA32_SPEC_CTRL, SPEC_CTRL_IBRS, + X86_FEATURE_USE_IBRS_FW); +} + +static inline void firmware_restrict_branch_speculation_end(void) +{ + alternative_msr_write(MSR_IA32_SPEC_CTRL, 0, + X86_FEATURE_USE_IBRS_FW); + preempt_enable(); } #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index baddc9ed3454..b8b0b6e78371 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -299,6 +299,15 @@ static void __init spectre_v2_select_mitigation(void) setup_force_cpu_cap(X86_FEATURE_USE_IBPB); pr_info("Spectre v2 mitigation: Enabling Indirect Branch Prediction Barrier\n"); } + + /* + * Retpoline means the kernel is safe because it has no indirect + * branches. But firmware isn't, so use IBRS to protect that. + */ + if (boot_cpu_has(X86_FEATURE_IBRS)) { + setup_force_cpu_cap(X86_FEATURE_USE_IBRS_FW); + pr_info("Enabling Restricted Speculation for firmware calls\n"); + } } #undef pr_fmt @@ -325,8 +334,9 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, c if (!boot_cpu_has_bug(X86_BUG_SPECTRE_V2)) return sprintf(buf, "Not affected\n"); - return sprintf(buf, "%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], + return sprintf(buf, "%s%s%s%s\n", spectre_v2_strings[spectre_v2_enabled], boot_cpu_has(X86_FEATURE_USE_IBPB) ? ", IBPB" : "", + boot_cpu_has(X86_FEATURE_USE_IBRS_FW) ? ", IBRS_FW" : "", spectre_v2_module_string()); } #endif -- GitLab From 6123a6becd80a9bb146ff9562095a9e54429fe01 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 19 Feb 2018 10:50:57 +0000 Subject: [PATCH 0296/1834] x86/retpoline: Support retpoline builds with Clang commit 87358710c1fb4f1bf96bbe2349975ff9953fc9b2 upstream. Signed-off-by: David Woodhouse Reviewed-by: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: arjan.van.de.ven@intel.com Cc: bp@alien8.de Cc: dave.hansen@intel.com Cc: jmattson@google.com Cc: karahmed@amazon.de Cc: kvm@vger.kernel.org Cc: pbonzini@redhat.com Cc: rkrcmar@redhat.com Link: http://lkml.kernel.org/r/1519037457-7643-5-git-send-email-dwmw@amazon.co.uk Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/Makefile | 5 ++++- include/linux/compiler-clang.h | 5 +++++ include/linux/compiler-gcc.h | 4 ++++ include/linux/init.h | 8 ++++---- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index cd22cb8ebd42..b60996184fa4 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -184,7 +184,10 @@ KBUILD_AFLAGS += $(mflags-y) # Avoid indirect branches in kernel to deal with Spectre ifdef CONFIG_RETPOLINE - RETPOLINE_CFLAGS += $(call cc-option,-mindirect-branch=thunk-extern -mindirect-branch-register) + RETPOLINE_CFLAGS_GCC := -mindirect-branch=thunk-extern -mindirect-branch-register + RETPOLINE_CFLAGS_CLANG := -mretpoline-external-thunk + + RETPOLINE_CFLAGS += $(call cc-option,$(RETPOLINE_CFLAGS_GCC),$(call cc-option,$(RETPOLINE_CFLAGS_CLANG))) ifneq ($(RETPOLINE_CFLAGS),) KBUILD_CFLAGS += $(RETPOLINE_CFLAGS) -DRETPOLINE endif diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h index de179993e039..01225b0059b1 100644 --- a/include/linux/compiler-clang.h +++ b/include/linux/compiler-clang.h @@ -15,3 +15,8 @@ * with any version that can compile the kernel */ #define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) + +/* Clang doesn't have a way to turn it off per-function, yet. */ +#ifdef __noretpoline +#undef __noretpoline +#endif diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index eb0ed31193a3..a1b1de17455c 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -88,6 +88,10 @@ #define __weak __attribute__((weak)) #define __alias(symbol) __attribute__((alias(#symbol))) +#ifdef RETPOLINE +#define __noretpoline __attribute__((indirect_branch("keep"))) +#endif + /* * it doesn't make sense on ARM (currently the only user of __naked) * to trace naked functions because then mcount is called without diff --git a/include/linux/init.h b/include/linux/init.h index 8e346d1bd837..683508f6bb4e 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -5,10 +5,10 @@ #include /* Built-in __init functions needn't be compiled with retpoline */ -#if defined(RETPOLINE) && !defined(MODULE) -#define __noretpoline __attribute__((indirect_branch("keep"))) +#if defined(__noretpoline) && !defined(MODULE) +#define __noinitretpoline __noretpoline #else -#define __noretpoline +#define __noinitretpoline #endif /* These macros are used to mark some functions or @@ -46,7 +46,7 @@ /* These are for everybody (although not all archs will actually discard it in modules) */ -#define __init __section(.init.text) __cold notrace __latent_entropy __noretpoline +#define __init __section(.init.text) __cold notrace __latent_entropy __noinitretpoline #define __initdata __section(.init.data) #define __initconst __section(.init.rodata) #define __exitdata __section(.exit.data) -- GitLab From a65655d40c823528a4f9a86e137a4909f1dfa649 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 17 Jan 2018 22:34:34 +0100 Subject: [PATCH 0297/1834] x86/speculation, objtool: Annotate indirect calls/jumps for objtool commit 9e0e3c5130e949c389caabc8033e9799b129e429 upstream. Annotate the indirect calls/jumps in the CALL_NOSPEC/JUMP_NOSPEC alternatives. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: David Woodhouse Acked-by: Thomas Gleixner Acked-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Linus Torvalds Cc: Peter Zijlstra Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 031840a848d2..29e8f30a3b63 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -67,6 +67,18 @@ .popsection .endm +/* + * This should be used immediately before an indirect jump/call. It tells + * objtool the subsequent indirect jump/call is vouched safe for retpoline + * builds. + */ +.macro ANNOTATE_RETPOLINE_SAFE + .Lannotate_\@: + .pushsection .discard.retpoline_safe + _ASM_PTR .Lannotate_\@ + .popsection +.endm + /* * These are the bare retpoline primitives for indirect jmp and call. * Do not use these directly; they only exist to make the ALTERNATIVE @@ -103,9 +115,9 @@ .macro JMP_NOSPEC reg:req #ifdef CONFIG_RETPOLINE ANNOTATE_NOSPEC_ALTERNATIVE - ALTERNATIVE_2 __stringify(jmp *\reg), \ + ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; jmp *\reg), \ __stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \ - __stringify(lfence; jmp *\reg), X86_FEATURE_RETPOLINE_AMD + __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; jmp *\reg), X86_FEATURE_RETPOLINE_AMD #else jmp *\reg #endif @@ -114,9 +126,9 @@ .macro CALL_NOSPEC reg:req #ifdef CONFIG_RETPOLINE ANNOTATE_NOSPEC_ALTERNATIVE - ALTERNATIVE_2 __stringify(call *\reg), \ + ALTERNATIVE_2 __stringify(ANNOTATE_RETPOLINE_SAFE; call *\reg), \ __stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\ - __stringify(lfence; call *\reg), X86_FEATURE_RETPOLINE_AMD + __stringify(lfence; ANNOTATE_RETPOLINE_SAFE; call *\reg), X86_FEATURE_RETPOLINE_AMD #else call *\reg #endif @@ -144,6 +156,12 @@ ".long 999b - .\n\t" \ ".popsection\n\t" +#define ANNOTATE_RETPOLINE_SAFE \ + "999:\n\t" \ + ".pushsection .discard.retpoline_safe\n\t" \ + _ASM_PTR " 999b\n\t" \ + ".popsection\n\t" + #if defined(CONFIG_X86_64) && defined(RETPOLINE) /* @@ -153,6 +171,7 @@ # define CALL_NOSPEC \ ANNOTATE_NOSPEC_ALTERNATIVE \ ALTERNATIVE( \ + ANNOTATE_RETPOLINE_SAFE \ "call *%[thunk_target]\n", \ "call __x86_indirect_thunk_%V[thunk_target]\n", \ X86_FEATURE_RETPOLINE) -- GitLab From f7d3a80ffe97fb089368c64a39a472e67ba790c1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 16 Jan 2018 10:38:09 +0100 Subject: [PATCH 0298/1834] x86/boot, objtool: Annotate indirect jump in secondary_startup_64() commit bd89004f6305cbf7352238f61da093207ee518d6 upstream. The objtool retpoline validation found this indirect jump. Seeing how it's on CPU bringup before we run userspace it should be safe, annotate it. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: David Woodhouse Acked-by: Thomas Gleixner Acked-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Linus Torvalds Cc: Peter Zijlstra Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/head_64.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 67cd7c1b99da..9d72cf547c88 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -22,6 +22,7 @@ #include #include "../entry/calling.h" #include +#include #ifdef CONFIG_PARAVIRT #include @@ -200,6 +201,7 @@ ENTRY(secondary_startup_64) /* Ensure I am executing from virtual addresses */ movq $1f, %rax + ANNOTATE_RETPOLINE_SAFE jmp *%rax 1: -- GitLab From e21257ad836df1ae91c37a7c6f99eddf7d97148e Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Wed, 21 Feb 2018 09:20:37 +0100 Subject: [PATCH 0299/1834] x86/speculation: Move firmware_restrict_branch_speculation_*() from C to CPP commit d72f4e29e6d84b7ec02ae93088aa459ac70e733b upstream. firmware_restrict_branch_speculation_*() recently started using preempt_enable()/disable(), but those are relatively high level primitives and cause build failures on some 32-bit builds. Since we want to keep low level, convert them to macros to avoid header hell... Cc: David Woodhouse Cc: Thomas Gleixner Cc: Linus Torvalds Cc: Peter Zijlstra Cc: arjan.van.de.ven@intel.com Cc: bp@alien8.de Cc: dave.hansen@intel.com Cc: jmattson@google.com Cc: karahmed@amazon.de Cc: kvm@vger.kernel.org Cc: pbonzini@redhat.com Cc: rkrcmar@redhat.com Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 29e8f30a3b63..d0dabeae0505 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -257,20 +257,22 @@ static inline void indirect_branch_prediction_barrier(void) /* * With retpoline, we must use IBRS to restrict branch prediction * before calling into firmware. + * + * (Implemented as CPP macros due to header hell.) */ -static inline void firmware_restrict_branch_speculation_start(void) -{ - preempt_disable(); - alternative_msr_write(MSR_IA32_SPEC_CTRL, SPEC_CTRL_IBRS, - X86_FEATURE_USE_IBRS_FW); -} +#define firmware_restrict_branch_speculation_start() \ +do { \ + preempt_disable(); \ + alternative_msr_write(MSR_IA32_SPEC_CTRL, SPEC_CTRL_IBRS, \ + X86_FEATURE_USE_IBRS_FW); \ +} while (0) -static inline void firmware_restrict_branch_speculation_end(void) -{ - alternative_msr_write(MSR_IA32_SPEC_CTRL, 0, - X86_FEATURE_USE_IBRS_FW); - preempt_enable(); -} +#define firmware_restrict_branch_speculation_end() \ +do { \ + alternative_msr_write(MSR_IA32_SPEC_CTRL, 0, \ + X86_FEATURE_USE_IBRS_FW); \ + preempt_enable(); \ +} while (0) #endif /* __ASSEMBLY__ */ -- GitLab From bb6155123c9caae207b45fa979554736ba5528ed Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 17 Jan 2018 16:58:11 +0100 Subject: [PATCH 0300/1834] x86/paravirt, objtool: Annotate indirect calls commit 3010a0663fd949d122eca0561b06b0a9453f7866 upstream. Paravirt emits indirect calls which get flagged by objtool retpoline checks, annotate it away because all these indirect calls will be patched out before we start userspace. This patching happens through alternative_instructions() -> apply_paravirt() -> pv_init_ops.patch() which will eventually end up in paravirt_patch_default(). This function _will_ write direct alternatives. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: David Woodhouse Acked-by: Thomas Gleixner Acked-by: Josh Poimboeuf Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Linus Torvalds Cc: Peter Zijlstra Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/paravirt.h | 16 ++++++++++++---- arch/x86/include/asm/paravirt_types.h | 5 ++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index ce932812f142..24af8b1de438 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -6,6 +6,7 @@ #ifdef CONFIG_PARAVIRT #include #include +#include #include @@ -869,23 +870,27 @@ extern void default_banner(void); #define INTERRUPT_RETURN \ PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_iret), CLBR_NONE, \ - jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_iret)) + ANNOTATE_RETPOLINE_SAFE; \ + jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_iret);) #define DISABLE_INTERRUPTS(clobbers) \ PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_disable), clobbers, \ PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ + ANNOTATE_RETPOLINE_SAFE; \ call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_disable); \ PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) #define ENABLE_INTERRUPTS(clobbers) \ PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_irq_enable), clobbers, \ PV_SAVE_REGS(clobbers | CLBR_CALLEE_SAVE); \ + ANNOTATE_RETPOLINE_SAFE; \ call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable); \ PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);) #ifdef CONFIG_X86_32 #define GET_CR0_INTO_EAX \ push %ecx; push %edx; \ + ANNOTATE_RETPOLINE_SAFE; \ call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \ pop %edx; pop %ecx #else /* !CONFIG_X86_32 */ @@ -907,11 +912,13 @@ extern void default_banner(void); */ #define SWAPGS \ PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_swapgs), CLBR_NONE, \ - call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs) \ + ANNOTATE_RETPOLINE_SAFE; \ + call PARA_INDIRECT(pv_cpu_ops+PV_CPU_swapgs); \ ) #define GET_CR2_INTO_RAX \ - call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2) + ANNOTATE_RETPOLINE_SAFE; \ + call PARA_INDIRECT(pv_mmu_ops+PV_MMU_read_cr2); #define PARAVIRT_ADJUST_EXCEPTION_FRAME \ PARA_SITE(PARA_PATCH(pv_irq_ops, PV_IRQ_adjust_exception_frame), \ @@ -921,7 +928,8 @@ extern void default_banner(void); #define USERGS_SYSRET64 \ PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret64), \ CLBR_NONE, \ - jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64)) + ANNOTATE_RETPOLINE_SAFE; \ + jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret64);) #endif /* CONFIG_X86_32 */ #endif /* __ASSEMBLY__ */ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 0f400c0e4979..04b79712b09c 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -42,6 +42,7 @@ #include #include #include +#include struct page; struct thread_struct; @@ -391,7 +392,9 @@ int paravirt_disable_iospace(void); * offset into the paravirt_patch_template structure, and can therefore be * freely converted back into a structure offset. */ -#define PARAVIRT_CALL "call *%c[paravirt_opptr];" +#define PARAVIRT_CALL \ + ANNOTATE_RETPOLINE_SAFE \ + "call *%c[paravirt_opptr];" /* * These macros are intended to wrap calls through one of the paravirt -- GitLab From 3f55635c749e6fce40e1d7f547398c1269edb68f Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Mon, 23 Oct 2017 16:46:16 -0600 Subject: [PATCH 0301/1834] watchdog: hpwdt: SMBIOS check commit c42cbe41727a138905a28f8e0b00c147be77ee93 upstream. This corrects: commit cce78da76601 ("watchdog: hpwdt: Add check for UEFI bits") The test on HPE SMBIOS extension type 219 record "Misc Features" bits for UEFI support is incorrect. The definition of the Misc Features bits in the HPE SMBIOS OEM Extensions specification (and related firmware) was changed to use a different pair of bits to represent UEFI supported. Howerver, a corresponding change to Linux was missed. Current code/platform work because the iCRU test is working. But purpose of cce78da766 is to ensure correct functionality on future systems where iCRU isn't supported. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/hpwdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 70c7194e2810..fed1aed85ea6 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -700,7 +700,7 @@ static void dmi_find_icru(const struct dmi_header *dm, void *dummy) smbios_proliant_ptr = (struct smbios_proliant_info *) dm; if (smbios_proliant_ptr->misc_features & 0x01) is_icru = 1; - if (smbios_proliant_ptr->misc_features & 0x408) + if (smbios_proliant_ptr->misc_features & 0x1400) is_uefi = 1; } } -- GitLab From c387231337fbc4633bd7f42fca8d05e9ee5c18a8 Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Mon, 23 Oct 2017 16:46:17 -0600 Subject: [PATCH 0302/1834] watchdog: hpwdt: Check source of NMI commit 838534e50e2e5c1e644e30ab6cb28da88eb31368 upstream. Do not claim the NMI (i.e. return NMI_DONE) if the source of the NMI isn't the iLO watchdog or debug. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/hpwdt.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index fed1aed85ea6..9a001c14819a 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -52,6 +52,7 @@ static char expect_release; static unsigned long hpwdt_is_open; static void __iomem *pci_mem_addr; /* the PCI-memory address */ +static unsigned long __iomem *hpwdt_nmistat; static unsigned long __iomem *hpwdt_timer_reg; static unsigned long __iomem *hpwdt_timer_con; @@ -474,6 +475,11 @@ static int hpwdt_time_left(void) return TICKS_TO_SECS(ioread16(hpwdt_timer_reg)); } +static int hpwdt_my_nmi(void) +{ + return ioread8(hpwdt_nmistat) & 0x6; +} + #ifdef CONFIG_HPWDT_NMI_DECODING /* * NMI Handler @@ -486,6 +492,9 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) if (!hpwdt_nmi_decoding) return NMI_DONE; + if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi()) + return NMI_DONE; + spin_lock_irqsave(&rom_lock, rom_pl); if (!die_nmi_called && !is_icru && !is_uefi) asminline_call(&cmn_regs, cru_rom_addr); @@ -842,6 +851,7 @@ static int hpwdt_init_one(struct pci_dev *dev, retval = -ENOMEM; goto error_pci_iomap; } + hpwdt_nmistat = pci_mem_addr + 0x6e; hpwdt_timer_reg = pci_mem_addr + 0x70; hpwdt_timer_con = pci_mem_addr + 0x72; -- GitLab From 6cda76dc3f86d5dc6839cd894a9465a13eb91501 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 6 Dec 2017 22:02:37 +0100 Subject: [PATCH 0303/1834] watchdog: hpwdt: fix unused variable warning commit aeebc6ba88ba3758ad95467ff6191fabf2074c13 upstream. The new hpwdt_my_nmi() function is used conditionally, which produces a harmless warning in some configurations: drivers/watchdog/hpwdt.c:478:12: error: 'hpwdt_my_nmi' defined but not used [-Werror=unused-function] This moves it inside of the #ifdef that protects its caller, to silence the warning. Fixes: 621174a92851 ("watchdog: hpwdt: Check source of NMI") Signed-off-by: Arnd Bergmann Reviewed-by: Jerry Hoemann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/hpwdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 9a001c14819a..7f6cb3a93c54 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -475,12 +475,12 @@ static int hpwdt_time_left(void) return TICKS_TO_SECS(ioread16(hpwdt_timer_reg)); } +#ifdef CONFIG_HPWDT_NMI_DECODING static int hpwdt_my_nmi(void) { return ioread8(hpwdt_nmistat) & 0x6; } -#ifdef CONFIG_HPWDT_NMI_DECODING /* * NMI Handler */ -- GitLab From 25d576732bc52416497734610b9324b3ceaf17ce Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Sun, 25 Feb 2018 20:22:20 -0700 Subject: [PATCH 0304/1834] watchdog: hpwdt: Remove legacy NMI sourcing. commit 2b3d89b402b085b08498e896c65267a145bed486 upstream. Gen8 and prior Proliant systems supported the "CRU" interface to firmware. This interfaces allows linux to "call back" into firmware to source the cause of an NMI. This feature isn't fully utilized as the actual source of the NMI isn't printed, the driver only indicates that the source couldn't be determined when the call fails. With the advent of Gen9, iCRU replaces the CRU. The call back feature is no longer available in firmware. To be compatible and not attempt to call back into firmware on system not supporting CRU, the SMBIOS table is consulted to determine if it is safe to make the call back or not. This results in about half of the driver code being devoted to either making CRU calls or determing if it is safe to make CRU calls. As noted, the driver isn't really using the results of the CRU calls. Furthermore, as a consequence of the Spectre security issue, the BIOS/EFI calls are being wrapped into Spectre-disabling section. Removing the call back in hpwdt_pretimeout assists in this effort. As the CRU sourcing of the NMI isn't required for handling the NMI and there are security concerns with making the call back, remove the legacy (pre Gen9) NMI sourcing and the DMI code to determine if the system had the CRU interface. Signed-off-by: Jerry Hoemann Acked-by: Ingo Molnar Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/hpwdt.c | 501 +-------------------------------------- 1 file changed, 9 insertions(+), 492 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 7f6cb3a93c54..b0a158073abd 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -28,16 +28,7 @@ #include #include #include -#ifdef CONFIG_HPWDT_NMI_DECODING -#include -#include -#include -#include -#include -#include -#endif /* CONFIG_HPWDT_NMI_DECODING */ #include -#include #define HPWDT_VERSION "1.4.0" #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) @@ -48,6 +39,9 @@ static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ static unsigned int reload; /* the computed soft_margin */ static bool nowayout = WATCHDOG_NOWAYOUT; +#ifdef CONFIG_HPWDT_NMI_DECODING +static unsigned int allow_kdump = 1; +#endif static char expect_release; static unsigned long hpwdt_is_open; @@ -63,373 +57,6 @@ static const struct pci_device_id hpwdt_devices[] = { }; MODULE_DEVICE_TABLE(pci, hpwdt_devices); -#ifdef CONFIG_HPWDT_NMI_DECODING -#define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ -#define CRU_BIOS_SIGNATURE_VALUE 0x55524324 -#define PCI_BIOS32_PARAGRAPH_LEN 16 -#define PCI_ROM_BASE1 0x000F0000 -#define ROM_SIZE 0x10000 - -struct bios32_service_dir { - u32 signature; - u32 entry_point; - u8 revision; - u8 length; - u8 checksum; - u8 reserved[5]; -}; - -/* type 212 */ -struct smbios_cru64_info { - u8 type; - u8 byte_length; - u16 handle; - u32 signature; - u64 physical_address; - u32 double_length; - u32 double_offset; -}; -#define SMBIOS_CRU64_INFORMATION 212 - -/* type 219 */ -struct smbios_proliant_info { - u8 type; - u8 byte_length; - u16 handle; - u32 power_features; - u32 omega_features; - u32 reserved; - u32 misc_features; -}; -#define SMBIOS_ICRU_INFORMATION 219 - - -struct cmn_registers { - union { - struct { - u8 ral; - u8 rah; - u16 rea2; - }; - u32 reax; - } u1; - union { - struct { - u8 rbl; - u8 rbh; - u8 reb2l; - u8 reb2h; - }; - u32 rebx; - } u2; - union { - struct { - u8 rcl; - u8 rch; - u16 rec2; - }; - u32 recx; - } u3; - union { - struct { - u8 rdl; - u8 rdh; - u16 red2; - }; - u32 redx; - } u4; - - u32 resi; - u32 redi; - u16 rds; - u16 res; - u32 reflags; -} __attribute__((packed)); - -static unsigned int hpwdt_nmi_decoding; -static unsigned int allow_kdump = 1; -static unsigned int is_icru; -static unsigned int is_uefi; -static DEFINE_SPINLOCK(rom_lock); -static void *cru_rom_addr; -static struct cmn_registers cmn_regs; - -extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, - unsigned long *pRomEntry); - -#ifdef CONFIG_X86_32 -/* --32 Bit Bios------------------------------------------------------------ */ - -#define HPWDT_ARCH 32 - -asm(".text \n\t" - ".align 4 \n\t" - ".globl asminline_call \n" - "asminline_call: \n\t" - "pushl %ebp \n\t" - "movl %esp, %ebp \n\t" - "pusha \n\t" - "pushf \n\t" - "push %es \n\t" - "push %ds \n\t" - "pop %es \n\t" - "movl 8(%ebp),%eax \n\t" - "movl 4(%eax),%ebx \n\t" - "movl 8(%eax),%ecx \n\t" - "movl 12(%eax),%edx \n\t" - "movl 16(%eax),%esi \n\t" - "movl 20(%eax),%edi \n\t" - "movl (%eax),%eax \n\t" - "push %cs \n\t" - "call *12(%ebp) \n\t" - "pushf \n\t" - "pushl %eax \n\t" - "movl 8(%ebp),%eax \n\t" - "movl %ebx,4(%eax) \n\t" - "movl %ecx,8(%eax) \n\t" - "movl %edx,12(%eax) \n\t" - "movl %esi,16(%eax) \n\t" - "movl %edi,20(%eax) \n\t" - "movw %ds,24(%eax) \n\t" - "movw %es,26(%eax) \n\t" - "popl %ebx \n\t" - "movl %ebx,(%eax) \n\t" - "popl %ebx \n\t" - "movl %ebx,28(%eax) \n\t" - "pop %es \n\t" - "popf \n\t" - "popa \n\t" - "leave \n\t" - "ret \n\t" - ".previous"); - - -/* - * cru_detect - * - * Routine Description: - * This function uses the 32-bit BIOS Service Directory record to - * search for a $CRU record. - * - * Return Value: - * 0 : SUCCESS - * <0 : FAILURE - */ -static int cru_detect(unsigned long map_entry, - unsigned long map_offset) -{ - void *bios32_map; - unsigned long *bios32_entrypoint; - unsigned long cru_physical_address; - unsigned long cru_length; - unsigned long physical_bios_base = 0; - unsigned long physical_bios_offset = 0; - int retval = -ENODEV; - - bios32_map = ioremap(map_entry, (2 * PAGE_SIZE)); - - if (bios32_map == NULL) - return -ENODEV; - - bios32_entrypoint = bios32_map + map_offset; - - cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; - - set_memory_x((unsigned long)bios32_map, 2); - asminline_call(&cmn_regs, bios32_entrypoint); - - if (cmn_regs.u1.ral != 0) { - pr_warn("Call succeeded but with an error: 0x%x\n", - cmn_regs.u1.ral); - } else { - physical_bios_base = cmn_regs.u2.rebx; - physical_bios_offset = cmn_regs.u4.redx; - cru_length = cmn_regs.u3.recx; - cru_physical_address = - physical_bios_base + physical_bios_offset; - - /* If the values look OK, then map it in. */ - if ((physical_bios_base + physical_bios_offset)) { - cru_rom_addr = - ioremap(cru_physical_address, cru_length); - if (cru_rom_addr) { - set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, - (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT); - retval = 0; - } - } - - pr_debug("CRU Base Address: 0x%lx\n", physical_bios_base); - pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset); - pr_debug("CRU Length: 0x%lx\n", cru_length); - pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr); - } - iounmap(bios32_map); - return retval; -} - -/* - * bios_checksum - */ -static int bios_checksum(const char __iomem *ptr, int len) -{ - char sum = 0; - int i; - - /* - * calculate checksum of size bytes. This should add up - * to zero if we have a valid header. - */ - for (i = 0; i < len; i++) - sum += ptr[i]; - - return ((sum == 0) && (len > 0)); -} - -/* - * bios32_present - * - * Routine Description: - * This function finds the 32-bit BIOS Service Directory - * - * Return Value: - * 0 : SUCCESS - * <0 : FAILURE - */ -static int bios32_present(const char __iomem *p) -{ - struct bios32_service_dir *bios_32_ptr; - int length; - unsigned long map_entry, map_offset; - - bios_32_ptr = (struct bios32_service_dir *) p; - - /* - * Search for signature by checking equal to the swizzled value - * instead of calling another routine to perform a strcmp. - */ - if (bios_32_ptr->signature == PCI_BIOS32_SD_VALUE) { - length = bios_32_ptr->length * PCI_BIOS32_PARAGRAPH_LEN; - if (bios_checksum(p, length)) { - /* - * According to the spec, we're looking for the - * first 4KB-aligned address below the entrypoint - * listed in the header. The Service Directory code - * is guaranteed to occupy no more than 2 4KB pages. - */ - map_entry = bios_32_ptr->entry_point & ~(PAGE_SIZE - 1); - map_offset = bios_32_ptr->entry_point - map_entry; - - return cru_detect(map_entry, map_offset); - } - } - return -ENODEV; -} - -static int detect_cru_service(void) -{ - char __iomem *p, *q; - int rc = -1; - - /* - * Search from 0x0f0000 through 0x0fffff, inclusive. - */ - p = ioremap(PCI_ROM_BASE1, ROM_SIZE); - if (p == NULL) - return -ENOMEM; - - for (q = p; q < p + ROM_SIZE; q += 16) { - rc = bios32_present(q); - if (!rc) - break; - } - iounmap(p); - return rc; -} -/* ------------------------------------------------------------------------- */ -#endif /* CONFIG_X86_32 */ -#ifdef CONFIG_X86_64 -/* --64 Bit Bios------------------------------------------------------------ */ - -#define HPWDT_ARCH 64 - -asm(".text \n\t" - ".align 4 \n\t" - ".globl asminline_call \n\t" - ".type asminline_call, @function \n\t" - "asminline_call: \n\t" - FRAME_BEGIN - "pushq %rax \n\t" - "pushq %rbx \n\t" - "pushq %rdx \n\t" - "pushq %r12 \n\t" - "pushq %r9 \n\t" - "movq %rsi, %r12 \n\t" - "movq %rdi, %r9 \n\t" - "movl 4(%r9),%ebx \n\t" - "movl 8(%r9),%ecx \n\t" - "movl 12(%r9),%edx \n\t" - "movl 16(%r9),%esi \n\t" - "movl 20(%r9),%edi \n\t" - "movl (%r9),%eax \n\t" - "call *%r12 \n\t" - "pushfq \n\t" - "popq %r12 \n\t" - "movl %eax, (%r9) \n\t" - "movl %ebx, 4(%r9) \n\t" - "movl %ecx, 8(%r9) \n\t" - "movl %edx, 12(%r9) \n\t" - "movl %esi, 16(%r9) \n\t" - "movl %edi, 20(%r9) \n\t" - "movq %r12, %rax \n\t" - "movl %eax, 28(%r9) \n\t" - "popq %r9 \n\t" - "popq %r12 \n\t" - "popq %rdx \n\t" - "popq %rbx \n\t" - "popq %rax \n\t" - FRAME_END - "ret \n\t" - ".previous"); - -/* - * dmi_find_cru - * - * Routine Description: - * This function checks whether or not a SMBIOS/DMI record is - * the 64bit CRU info or not - */ -static void dmi_find_cru(const struct dmi_header *dm, void *dummy) -{ - struct smbios_cru64_info *smbios_cru64_ptr; - unsigned long cru_physical_address; - - if (dm->type == SMBIOS_CRU64_INFORMATION) { - smbios_cru64_ptr = (struct smbios_cru64_info *) dm; - if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) { - cru_physical_address = - smbios_cru64_ptr->physical_address + - smbios_cru64_ptr->double_offset; - cru_rom_addr = ioremap(cru_physical_address, - smbios_cru64_ptr->double_length); - set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, - smbios_cru64_ptr->double_length >> PAGE_SHIFT); - } - } -} - -static int detect_cru_service(void) -{ - cru_rom_addr = NULL; - - dmi_walk(dmi_find_cru, NULL); - - /* if cru_rom_addr has been set then we found a CRU service */ - return ((cru_rom_addr != NULL) ? 0 : -ENODEV); -} -/* ------------------------------------------------------------------------- */ -#endif /* CONFIG_X86_64 */ -#endif /* CONFIG_HPWDT_NMI_DECODING */ /* * Watchdog operations @@ -486,30 +113,12 @@ static int hpwdt_my_nmi(void) */ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) { - unsigned long rom_pl; - static int die_nmi_called; - - if (!hpwdt_nmi_decoding) - return NMI_DONE; - if ((ulReason == NMI_UNKNOWN) && !hpwdt_my_nmi()) return NMI_DONE; - spin_lock_irqsave(&rom_lock, rom_pl); - if (!die_nmi_called && !is_icru && !is_uefi) - asminline_call(&cmn_regs, cru_rom_addr); - die_nmi_called = 1; - spin_unlock_irqrestore(&rom_lock, rom_pl); - if (allow_kdump) hpwdt_stop(); - if (!is_icru && !is_uefi) { - if (cmn_regs.u1.ral == 0) { - nmi_panic(regs, "An NMI occurred, but unable to determine source.\n"); - return NMI_HANDLED; - } - } nmi_panic(regs, "An NMI occurred. Depending on your system the reason " "for the NMI is logged in any one of the following " "resources:\n" @@ -675,84 +284,11 @@ static struct miscdevice hpwdt_miscdev = { * Init & Exit */ -#ifdef CONFIG_HPWDT_NMI_DECODING -#ifdef CONFIG_X86_LOCAL_APIC -static void hpwdt_check_nmi_decoding(struct pci_dev *dev) -{ - /* - * If nmi_watchdog is turned off then we can turn on - * our nmi decoding capability. - */ - hpwdt_nmi_decoding = 1; -} -#else -static void hpwdt_check_nmi_decoding(struct pci_dev *dev) -{ - dev_warn(&dev->dev, "NMI decoding is disabled. " - "Your kernel does not support a NMI Watchdog.\n"); -} -#endif /* CONFIG_X86_LOCAL_APIC */ - -/* - * dmi_find_icru - * - * Routine Description: - * This function checks whether or not we are on an iCRU-based server. - * This check is independent of architecture and needs to be made for - * any ProLiant system. - */ -static void dmi_find_icru(const struct dmi_header *dm, void *dummy) -{ - struct smbios_proliant_info *smbios_proliant_ptr; - - if (dm->type == SMBIOS_ICRU_INFORMATION) { - smbios_proliant_ptr = (struct smbios_proliant_info *) dm; - if (smbios_proliant_ptr->misc_features & 0x01) - is_icru = 1; - if (smbios_proliant_ptr->misc_features & 0x1400) - is_uefi = 1; - } -} static int hpwdt_init_nmi_decoding(struct pci_dev *dev) { +#ifdef CONFIG_HPWDT_NMI_DECODING int retval; - - /* - * On typical CRU-based systems we need to map that service in - * the BIOS. For 32 bit Operating Systems we need to go through - * the 32 Bit BIOS Service Directory. For 64 bit Operating - * Systems we get that service through SMBIOS. - * - * On systems that support the new iCRU service all we need to - * do is call dmi_walk to get the supported flag value and skip - * the old cru detect code. - */ - dmi_walk(dmi_find_icru, NULL); - if (!is_icru && !is_uefi) { - - /* - * We need to map the ROM to get the CRU service. - * For 32 bit Operating Systems we need to go through the 32 Bit - * BIOS Service Directory - * For 64 bit Operating Systems we get that service through SMBIOS. - */ - retval = detect_cru_service(); - if (retval < 0) { - dev_warn(&dev->dev, - "Unable to detect the %d Bit CRU Service.\n", - HPWDT_ARCH); - return retval; - } - - /* - * We know this is the only CRU call we need to make so lets keep as - * few instructions as possible once the NMI comes in. - */ - cmn_regs.u1.rah = 0x0D; - cmn_regs.u1.ral = 0x02; - } - /* * Only one function can register for NMI_UNKNOWN */ @@ -780,44 +316,25 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev) dev_warn(&dev->dev, "Unable to register a die notifier (err=%d).\n", retval); - if (cru_rom_addr) - iounmap(cru_rom_addr); return retval; +#endif /* CONFIG_HPWDT_NMI_DECODING */ + return 0; } static void hpwdt_exit_nmi_decoding(void) { +#ifdef CONFIG_HPWDT_NMI_DECODING unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); unregister_nmi_handler(NMI_SERR, "hpwdt"); unregister_nmi_handler(NMI_IO_CHECK, "hpwdt"); - if (cru_rom_addr) - iounmap(cru_rom_addr); -} -#else /* !CONFIG_HPWDT_NMI_DECODING */ -static void hpwdt_check_nmi_decoding(struct pci_dev *dev) -{ -} - -static int hpwdt_init_nmi_decoding(struct pci_dev *dev) -{ - return 0; +#endif } -static void hpwdt_exit_nmi_decoding(void) -{ -} -#endif /* CONFIG_HPWDT_NMI_DECODING */ - static int hpwdt_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { int retval; - /* - * Check if we can do NMI decoding or not - */ - hpwdt_check_nmi_decoding(dev); - /* * First let's find out if we are on an iLO2+ server. We will * not run on a legacy ASM box. @@ -922,6 +439,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" #ifdef CONFIG_HPWDT_NMI_DECODING module_param(allow_kdump, int, 0); MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); -#endif /* !CONFIG_HPWDT_NMI_DECODING */ +#endif /* CONFIG_HPWDT_NMI_DECODING */ module_pci_driver(hpwdt_driver); -- GitLab From c20eb490e7381c83f99922831cb74a6730d40ce0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 6 Dec 2017 14:17:17 +0100 Subject: [PATCH 0305/1834] ARM: omap2: hide omap3_save_secure_ram on non-OMAP3 builds commit 863204cfdae98626a92535ac928ad79f4d6b74ff upstream. In configurations without CONFIG_OMAP3 but with secure RAM support, we now run into a link failure: arch/arm/mach-omap2/omap-secure.o: In function `omap3_save_secure_ram': omap-secure.c:(.text+0x130): undefined reference to `save_secure_ram_context' The omap3_save_secure_ram() function is only called from the OMAP34xx power management code, so we can simply hide that function in the appropriate #ifdef. Fixes: d09220a887f7 ("ARM: OMAP2+: Fix SRAM virt to phys translation for save_secure_ram_context") Acked-by: Tony Lindgren Tested-by: Dan Murphy Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/omap-secure.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-omap2/omap-secure.c b/arch/arm/mach-omap2/omap-secure.c index 9ff92050053c..fa7f308c9027 100644 --- a/arch/arm/mach-omap2/omap-secure.c +++ b/arch/arm/mach-omap2/omap-secure.c @@ -73,6 +73,7 @@ phys_addr_t omap_secure_ram_mempool_base(void) return omap_secure_memblock_base; } +#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM) u32 omap3_save_secure_ram(void __iomem *addr, int size) { u32 ret; @@ -91,6 +92,7 @@ u32 omap3_save_secure_ram(void __iomem *addr, int size) return ret; } +#endif /** * rx51_secure_dispatcher: Routine to dispatch secure PPA API calls -- GitLab From c9763bfc7d27dca13d4b6ac93207b98cbd46dda8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 13 Feb 2017 15:45:59 -0800 Subject: [PATCH 0306/1834] Input: tca8418_keypad - remove double read of key event register commit 9dd46c02532a6bed6240101ecf4bbc407f8c6adf upstream. There is no need to tread the same register twice in a row. Fixes: ea4348c8462a ("Input: tca8418_keypad - hide gcc-4.9 -Wmaybe-un ...") Signed-off-by: Dmitry Torokhov Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/input/keyboard/tca8418_keypad.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 3048ef3e3e16..a5e8998047fe 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -189,8 +189,6 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) input_event(input, EV_MSC, MSC_SCAN, code); input_report_key(input, keymap[code], state); - /* Read for next loop */ - error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); } while (1); input_sync(input); -- GitLab From b323768e610b3108bd8ad48329f420d91e7b336b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 4 May 2017 12:20:17 -0300 Subject: [PATCH 0307/1834] tc358743: fix register i2c_rd/wr function fix commit f2c61f98e0b5f8b53b8fb860e5dcdd661bde7d0b upstream. The below mentioned fix contains a small but severe bug, fix it to make the driver work again. Fixes: 3538aa6ecfb2 ("[media] tc358743: fix register i2c_rd/wr functions") Cc: Hans Verkuil Cc: Mauro Carvalho Chehab Signed-off-by: Philipp Zabel Acked-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/tc358743.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 26d999c812c9..0f572bff64f5 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -222,7 +222,7 @@ static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, u8 mask, u8 val) { - i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 2) & mask) | val, 2); + i2c_wrreg(sd, reg, (i2c_rdreg(sd, reg, 1) & mask) | val, 1); } static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) -- GitLab From f506da51bdf6602ec942f25d682a4de9b59760da Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 7 Feb 2018 13:46:25 +0100 Subject: [PATCH 0308/1834] netfilter: add back stackpointer size checks commit 57ebd808a97d7c5b1e1afb937c2db22beba3c1f8 upstream. The rationale for removing the check is only correct for rulesets generated by ip(6)tables. In iptables, a jump can only occur to a user-defined chain, i.e. because we size the stack based on number of user-defined chains we cannot exceed stack size. However, the underlying binary format has no such restriction, and the validation step only ensures that the jump target is a valid rule start point. IOW, its possible to build a rule blob that has no user-defined chains but does contain a jump. If this happens, no jump stack gets allocated and crash occurs because no jumpstack was allocated. Fixes: 7814b6ec6d0d6 ("netfilter: xtables: don't save/restore jumpstack offset") Reported-by: syzbot+e783f671527912cd9403@syzkaller.appspotmail.com Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/arp_tables.c | 4 ++++ net/ipv4/netfilter/ip_tables.c | 7 ++++++- net/ipv6/netfilter/ip6_tables.c | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 697538464e6e..ad1c49ed2987 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -261,6 +261,10 @@ unsigned int arpt_do_table(struct sk_buff *skb, } if (table_base + v != arpt_next_entry(e)) { + if (unlikely(stackidx >= private->stacksize)) { + verdict = NF_DROP; + break; + } jumpstack[stackidx++] = e; } diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 7c00ce90adb8..a3c5433bb76f 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -345,8 +345,13 @@ ipt_do_table(struct sk_buff *skb, continue; } if (table_base + v != ipt_next_entry(e) && - !(e->ip.flags & IPT_F_GOTO)) + !(e->ip.flags & IPT_F_GOTO)) { + if (unlikely(stackidx >= private->stacksize)) { + verdict = NF_DROP; + break; + } jumpstack[stackidx++] = e; + } e = get_entry(table_base, v); continue; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 55aacea24396..3d95b070cdad 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -376,6 +376,10 @@ ip6t_do_table(struct sk_buff *skb, } if (table_base + v != ip6t_next_entry(e) && !(e->ipv6.flags & IP6T_F_GOTO)) { + if (unlikely(stackidx >= private->stacksize)) { + verdict = NF_DROP; + break; + } jumpstack[stackidx++] = e; } -- GitLab From af4b424a412b7f7a8ba2e9f1af9b6920a60130b4 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Mon, 12 Feb 2018 18:49:39 +0100 Subject: [PATCH 0309/1834] netfilter: x_tables: fix missing timer initialization in xt_LED commit 10414014bc085aac9f787a5890b33b5605fbcfc4 upstream. syzbot reported that xt_LED may try to use the ledinternal->timer without previously initializing it: ------------[ cut here ]------------ kernel BUG at kernel/time/timer.c:958! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 1 PID: 1826 Comm: kworker/1:2 Not tainted 4.15.0+ #306 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Workqueue: ipv6_addrconf addrconf_dad_work RIP: 0010:__mod_timer kernel/time/timer.c:958 [inline] RIP: 0010:mod_timer+0x7d6/0x13c0 kernel/time/timer.c:1102 RSP: 0018:ffff8801d24fe9f8 EFLAGS: 00010293 RAX: ffff8801d25246c0 RBX: ffff8801aec6cb50 RCX: ffffffff816052c6 RDX: 0000000000000000 RSI: 00000000fffbd14b RDI: ffff8801aec6cb68 RBP: ffff8801d24fec98 R08: 0000000000000000 R09: 1ffff1003a49fd6c R10: ffff8801d24feb28 R11: 0000000000000005 R12: dffffc0000000000 R13: ffff8801d24fec70 R14: 00000000fffbd14b R15: ffff8801af608f90 FS: 0000000000000000(0000) GS:ffff8801db500000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000206d6fd0 CR3: 0000000006a22001 CR4: 00000000001606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: led_tg+0x1db/0x2e0 net/netfilter/xt_LED.c:75 ip6t_do_table+0xc2a/0x1a30 net/ipv6/netfilter/ip6_tables.c:365 ip6table_raw_hook+0x65/0x80 net/ipv6/netfilter/ip6table_raw.c:42 nf_hook_entry_hookfn include/linux/netfilter.h:120 [inline] nf_hook_slow+0xba/0x1a0 net/netfilter/core.c:483 nf_hook.constprop.27+0x3f6/0x830 include/linux/netfilter.h:243 NF_HOOK include/linux/netfilter.h:286 [inline] ndisc_send_skb+0xa51/0x1370 net/ipv6/ndisc.c:491 ndisc_send_ns+0x38a/0x870 net/ipv6/ndisc.c:633 addrconf_dad_work+0xb9e/0x1320 net/ipv6/addrconf.c:4008 process_one_work+0xbbf/0x1af0 kernel/workqueue.c:2113 worker_thread+0x223/0x1990 kernel/workqueue.c:2247 kthread+0x33c/0x400 kernel/kthread.c:238 ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:429 Code: 85 2a 0b 00 00 4d 8b 3c 24 4d 85 ff 75 9f 4c 8b bd 60 fd ff ff e8 bb 57 10 00 65 ff 0d 94 9a a1 7e e9 d9 fc ff ff e8 aa 57 10 00 <0f> 0b e8 a3 57 10 00 e9 14 fb ff ff e8 99 57 10 00 4c 89 bd 70 RIP: __mod_timer kernel/time/timer.c:958 [inline] RSP: ffff8801d24fe9f8 RIP: mod_timer+0x7d6/0x13c0 kernel/time/timer.c:1102 RSP: ffff8801d24fe9f8 ---[ end trace f661ab06f5dd8b3d ]--- The ledinternal struct can be shared between several different xt_LED targets, but the related timer is currently initialized only if the first target requires it. Fix it by unconditionally initializing the timer struct. v1 -> v2: call del_timer_sync() unconditionally, too. Fixes: 268cb38e1802 ("netfilter: x_tables: add LED trigger target") Reported-by: syzbot+10c98dc5725c6c8fc7fb@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/xt_LED.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/netfilter/xt_LED.c b/net/netfilter/xt_LED.c index 3ba31c194cce..0858fe17e14a 100644 --- a/net/netfilter/xt_LED.c +++ b/net/netfilter/xt_LED.c @@ -141,10 +141,11 @@ static int led_tg_check(const struct xt_tgchk_param *par) goto exit_alloc; } - /* See if we need to set up a timer */ - if (ledinfo->delay > 0) - setup_timer(&ledinternal->timer, led_timeout_callback, - (unsigned long)ledinternal); + /* Since the letinternal timer can be shared between multiple targets, + * always set it up, even if the current target does not need it + */ + setup_timer(&ledinternal->timer, led_timeout_callback, + (unsigned long)ledinternal); list_add_tail(&ledinternal->list, &xt_led_triggers); @@ -181,8 +182,7 @@ static void led_tg_destroy(const struct xt_tgdtor_param *par) list_del(&ledinternal->list); - if (ledinfo->delay > 0) - del_timer_sync(&ledinternal->timer); + del_timer_sync(&ledinternal->timer); led_trigger_unregister(&ledinternal->netfilter_led_trigger); -- GitLab From 7d105756b4eecf95905eff37001d61ac70049d72 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Wed, 14 Feb 2018 17:21:19 +0100 Subject: [PATCH 0310/1834] netfilter: nat: cope with negative port range commit db57ccf0f2f4624b4c4758379f8165277504fbd7 upstream. syzbot reported a division by 0 bug in the netfilter nat code: divide error: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 1 PID: 4168 Comm: syzkaller034710 Not tainted 4.16.0-rc1+ #309 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:nf_nat_l4proto_unique_tuple+0x291/0x530 net/netfilter/nf_nat_proto_common.c:88 RSP: 0018:ffff8801b2466778 EFLAGS: 00010246 RAX: 000000000000f153 RBX: ffff8801b2466dd8 RCX: ffff8801b2466c7c RDX: 0000000000000000 RSI: ffff8801b2466c58 RDI: ffff8801db5293ac RBP: ffff8801b24667d8 R08: ffff8801b8ba6dc0 R09: ffffffff88af5900 R10: ffff8801b24666f0 R11: 0000000000000000 R12: 000000002990f153 R13: 0000000000000001 R14: 0000000000000000 R15: ffff8801b2466c7c FS: 00000000017e3880(0000) GS:ffff8801db500000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000208fdfe4 CR3: 00000001b5340002 CR4: 00000000001606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: dccp_unique_tuple+0x40/0x50 net/netfilter/nf_nat_proto_dccp.c:30 get_unique_tuple+0xc28/0x1c10 net/netfilter/nf_nat_core.c:362 nf_nat_setup_info+0x1c2/0xe00 net/netfilter/nf_nat_core.c:406 nf_nat_redirect_ipv6+0x306/0x730 net/netfilter/nf_nat_redirect.c:124 redirect_tg6+0x7f/0xb0 net/netfilter/xt_REDIRECT.c:34 ip6t_do_table+0xc2a/0x1a30 net/ipv6/netfilter/ip6_tables.c:365 ip6table_nat_do_chain+0x65/0x80 net/ipv6/netfilter/ip6table_nat.c:41 nf_nat_ipv6_fn+0x594/0xa80 net/ipv6/netfilter/nf_nat_l3proto_ipv6.c:302 nf_nat_ipv6_local_fn+0x33/0x5d0 net/ipv6/netfilter/nf_nat_l3proto_ipv6.c:407 ip6table_nat_local_fn+0x2c/0x40 net/ipv6/netfilter/ip6table_nat.c:69 nf_hook_entry_hookfn include/linux/netfilter.h:120 [inline] nf_hook_slow+0xba/0x1a0 net/netfilter/core.c:483 nf_hook include/linux/netfilter.h:243 [inline] NF_HOOK include/linux/netfilter.h:286 [inline] ip6_xmit+0x10ec/0x2260 net/ipv6/ip6_output.c:277 inet6_csk_xmit+0x2fc/0x580 net/ipv6/inet6_connection_sock.c:139 dccp_transmit_skb+0x9ac/0x10f0 net/dccp/output.c:142 dccp_connect+0x369/0x670 net/dccp/output.c:564 dccp_v6_connect+0xe17/0x1bf0 net/dccp/ipv6.c:946 __inet_stream_connect+0x2d4/0xf00 net/ipv4/af_inet.c:620 inet_stream_connect+0x58/0xa0 net/ipv4/af_inet.c:684 SYSC_connect+0x213/0x4a0 net/socket.c:1639 SyS_connect+0x24/0x30 net/socket.c:1620 do_syscall_64+0x282/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x26/0x9b RIP: 0033:0x441c69 RSP: 002b:00007ffe50cc0be8 EFLAGS: 00000217 ORIG_RAX: 000000000000002a RAX: ffffffffffffffda RBX: ffffffffffffffff RCX: 0000000000441c69 RDX: 000000000000001c RSI: 00000000208fdfe4 RDI: 0000000000000003 RBP: 00000000006cc018 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000538 R11: 0000000000000217 R12: 0000000000403590 R13: 0000000000403620 R14: 0000000000000000 R15: 0000000000000000 Code: 48 89 f0 83 e0 07 83 c0 01 38 d0 7c 08 84 d2 0f 85 46 02 00 00 48 8b 45 c8 44 0f b7 20 e8 88 97 04 fd 31 d2 41 0f b7 c4 4c 89 f9 <41> f7 f6 48 c1 e9 03 48 b8 00 00 00 00 00 fc ff df 0f b6 0c 01 RIP: nf_nat_l4proto_unique_tuple+0x291/0x530 net/netfilter/nf_nat_proto_common.c:88 RSP: ffff8801b2466778 The problem is that currently we don't have any check on the configured port range. A port range == -1 triggers the bug, while other negative values may require a very long time to complete the following loop. This commit addresses the issue swapping the two ends on negative ranges. The check is performed in nf_nat_l4proto_unique_tuple() since the nft nat loads the port values from nft registers at runtime. v1 -> v2: use the correct 'Fixes' tag v2 -> v3: update commit message, drop unneeded READ_ONCE() Fixes: 5b1158e909ec ("[NETFILTER]: Add NAT support for nf_conntrack") Reported-by: syzbot+8012e198bd037f4871e5@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_nat_proto_common.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/netfilter/nf_nat_proto_common.c b/net/netfilter/nf_nat_proto_common.c index fbce552a796e..7d7466dbf663 100644 --- a/net/netfilter/nf_nat_proto_common.c +++ b/net/netfilter/nf_nat_proto_common.c @@ -41,7 +41,7 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, const struct nf_conn *ct, u16 *rover) { - unsigned int range_size, min, i; + unsigned int range_size, min, max, i; __be16 *portptr; u_int16_t off; @@ -71,7 +71,10 @@ void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, } } else { min = ntohs(range->min_proto.all); - range_size = ntohs(range->max_proto.all) - min + 1; + max = ntohs(range->max_proto.all); + if (unlikely(max < min)) + swap(max, min); + range_size = max - min + 1; } if (range->flags & NF_NAT_RANGE_PROTO_RANDOM) { -- GitLab From 034ad9d2eadf3d6696674b46d1e497adc14f92c3 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 16 Feb 2018 19:36:28 -0800 Subject: [PATCH 0311/1834] netfilter: IDLETIMER: be syzkaller friendly commit cfc2c740533368b96e2be5e0a4e8c3cace7d9814 upstream. We had one report from syzkaller [1] First issue is that INIT_WORK() should be done before mod_timer() or we risk timer being fired too soon, even with a 1 second timer. Second issue is that we need to reject too big info->timeout to avoid overflows in msecs_to_jiffies(info->timeout * 1000), or risk looping, if result after overflow is 0. [1] WARNING: CPU: 1 PID: 5129 at kernel/workqueue.c:1444 __queue_work+0xdf4/0x1230 kernel/workqueue.c:1444 Kernel panic - not syncing: panic_on_warn set ... CPU: 1 PID: 5129 Comm: syzkaller159866 Not tainted 4.16.0-rc1+ #230 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x257 lib/dump_stack.c:53 panic+0x1e4/0x41c kernel/panic.c:183 __warn+0x1dc/0x200 kernel/panic.c:547 report_bug+0x211/0x2d0 lib/bug.c:184 fixup_bug.part.11+0x37/0x80 arch/x86/kernel/traps.c:178 fixup_bug arch/x86/kernel/traps.c:247 [inline] do_error_trap+0x2d7/0x3e0 arch/x86/kernel/traps.c:296 do_invalid_op+0x1b/0x20 arch/x86/kernel/traps.c:315 invalid_op+0x22/0x40 arch/x86/entry/entry_64.S:988 RIP: 0010:__queue_work+0xdf4/0x1230 kernel/workqueue.c:1444 RSP: 0018:ffff8801db507538 EFLAGS: 00010006 RAX: ffff8801aeb46080 RBX: ffff8801db530200 RCX: ffffffff81481404 RDX: 0000000000000100 RSI: ffffffff86b42640 RDI: 0000000000000082 RBP: ffff8801db507758 R08: 1ffff1003b6a0de5 R09: 000000000000000c R10: ffff8801db5073f0 R11: 0000000000000020 R12: 1ffff1003b6a0eb6 R13: ffff8801b1067ae0 R14: 00000000000001f8 R15: dffffc0000000000 queue_work_on+0x16a/0x1c0 kernel/workqueue.c:1488 queue_work include/linux/workqueue.h:488 [inline] schedule_work include/linux/workqueue.h:546 [inline] idletimer_tg_expired+0x44/0x60 net/netfilter/xt_IDLETIMER.c:116 call_timer_fn+0x228/0x820 kernel/time/timer.c:1326 expire_timers kernel/time/timer.c:1363 [inline] __run_timers+0x7ee/0xb70 kernel/time/timer.c:1666 run_timer_softirq+0x4c/0x70 kernel/time/timer.c:1692 __do_softirq+0x2d7/0xb85 kernel/softirq.c:285 invoke_softirq kernel/softirq.c:365 [inline] irq_exit+0x1cc/0x200 kernel/softirq.c:405 exiting_irq arch/x86/include/asm/apic.h:541 [inline] smp_apic_timer_interrupt+0x16b/0x700 arch/x86/kernel/apic/apic.c:1052 apic_timer_interrupt+0xa9/0xb0 arch/x86/entry/entry_64.S:829 RIP: 0010:arch_local_irq_restore arch/x86/include/asm/paravirt.h:777 [inline] RIP: 0010:__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:160 [inline] RIP: 0010:_raw_spin_unlock_irqrestore+0x5e/0xba kernel/locking/spinlock.c:184 RSP: 0018:ffff8801c20173c8 EFLAGS: 00000282 ORIG_RAX: ffffffffffffff12 RAX: dffffc0000000000 RBX: 0000000000000282 RCX: 0000000000000006 RDX: 1ffffffff0d592cd RSI: 1ffff10035d68d23 RDI: 0000000000000282 RBP: ffff8801c20173d8 R08: 1ffff10038402e47 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff8820e5c8 R13: ffff8801b1067ad8 R14: ffff8801aea7c268 R15: ffff8801aea7c278 __debug_object_init+0x235/0x1040 lib/debugobjects.c:378 debug_object_init+0x17/0x20 lib/debugobjects.c:391 __init_work+0x2b/0x60 kernel/workqueue.c:506 idletimer_tg_create net/netfilter/xt_IDLETIMER.c:152 [inline] idletimer_tg_checkentry+0x691/0xb00 net/netfilter/xt_IDLETIMER.c:213 xt_check_target+0x22c/0x7d0 net/netfilter/x_tables.c:850 check_target net/ipv6/netfilter/ip6_tables.c:533 [inline] find_check_entry.isra.7+0x935/0xcf0 net/ipv6/netfilter/ip6_tables.c:575 translate_table+0xf52/0x1690 net/ipv6/netfilter/ip6_tables.c:744 do_replace net/ipv6/netfilter/ip6_tables.c:1160 [inline] do_ip6t_set_ctl+0x370/0x5f0 net/ipv6/netfilter/ip6_tables.c:1686 nf_sockopt net/netfilter/nf_sockopt.c:106 [inline] nf_setsockopt+0x67/0xc0 net/netfilter/nf_sockopt.c:115 ipv6_setsockopt+0x10b/0x130 net/ipv6/ipv6_sockglue.c:927 udpv6_setsockopt+0x45/0x80 net/ipv6/udp.c:1422 sock_common_setsockopt+0x95/0xd0 net/core/sock.c:2976 SYSC_setsockopt net/socket.c:1850 [inline] SyS_setsockopt+0x189/0x360 net/socket.c:1829 do_syscall_64+0x282/0x940 arch/x86/entry/common.c:287 Fixes: 0902b469bd25 ("netfilter: xtables: idletimer target implementation") Signed-off-by: Eric Dumazet Reported-by: syzkaller Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/netfilter/xt_IDLETIMER.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index daf45da448fa..bb5d6a058fb7 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -147,11 +147,11 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) (unsigned long) info->timer); info->timer->refcnt = 1; + INIT_WORK(&info->timer->work, idletimer_tg_work); + mod_timer(&info->timer->timer, msecs_to_jiffies(info->timeout * 1000) + jiffies); - INIT_WORK(&info->timer->work, idletimer_tg_work); - return 0; out_free_attr: @@ -192,7 +192,10 @@ static int idletimer_tg_checkentry(const struct xt_tgchk_param *par) pr_debug("timeout value is zero\n"); return -EINVAL; } - + if (info->timeout >= INT_MAX / 1000) { + pr_debug("timeout value is too big\n"); + return -EINVAL; + } if (info->label[0] == '\0' || strnlen(info->label, MAX_IDLETIMER_LABEL_SIZE) == MAX_IDLETIMER_LABEL_SIZE) { -- GitLab From 21ff147189ff0692d203282c1dced02f83dcf785 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 19 Feb 2018 01:24:15 +0100 Subject: [PATCH 0312/1834] netfilter: ebtables: CONFIG_COMPAT: don't trust userland offsets commit b71812168571fa55e44cdd0254471331b9c4c4c6 upstream. We need to make sure the offsets are not out of range of the total size. Also check that they are in ascending order. The WARN_ON triggered by syzkaller (it sets panic_on_warn) is changed to also bail out, no point in continuing parsing. Briefly tested with simple ruleset of -A INPUT --limit 1/s' --log plus jump to custom chains using 32bit ebtables binary. Reported-by: Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/bridge/netfilter/ebtables.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index f5c11bbe27db..5a89a4ac86ef 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -2031,7 +2031,9 @@ static int ebt_size_mwt(struct compat_ebt_entry_mwt *match32, if (match_kern) match_kern->match_size = ret; - WARN_ON(type == EBT_COMPAT_TARGET && size_left); + if (WARN_ON(type == EBT_COMPAT_TARGET && size_left)) + return -EINVAL; + match32 = (struct compat_ebt_entry_mwt *) buf; } @@ -2087,6 +2089,15 @@ static int size_entry_mwt(struct ebt_entry *entry, const unsigned char *base, * * offsets are relative to beginning of struct ebt_entry (i.e., 0). */ + for (i = 0; i < 4 ; ++i) { + if (offsets[i] >= *total) + return -EINVAL; + if (i == 0) + continue; + if (offsets[i-1] > offsets[i]) + return -EINVAL; + } + for (i = 0, j = 1 ; j < 4 ; j++, i++) { struct compat_ebt_entry_mwt *match32; unsigned int size; -- GitLab From 280ef7b83b3220e12ee72857b35465f79670b33b Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 19 Feb 2018 03:01:45 +0100 Subject: [PATCH 0313/1834] netfilter: bridge: ebt_among: add missing match size checks commit c4585a2823edf4d1326da44d1524ecbfda26bb37 upstream. ebt_among is special, it has a dynamic match size and is exempt from the central size checks. Therefore it must check that the size of the match structure provided from userspace is sane by making sure em->match_size is at least the minimum size of the expected structure. The module has such a check, but its only done after accessing a structure that might be out of bounds. tested with: ebtables -A INPUT ... \ --among-dst fe:fe:fe:fe:fe:fe --among-dst fe:fe:fe:fe:fe:fe --among-src fe:fe:fe:fe:ff:f,fe:fe:fe:fe:fe:fb,fe:fe:fe:fe:fc:fd,fe:fe:fe:fe:fe:fd,fe:fe:fe:fe:fe:fe --among-src fe:fe:fe:fe:ff:f,fe:fe:fe:fe:fe:fa,fe:fe:fe:fe:fe:fd,fe:fe:fe:fe:fe:fe,fe:fe:fe:fe:fe:fe Reported-by: Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/bridge/netfilter/ebt_among.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c index 9024283d2bca..9637a681bdda 100644 --- a/net/bridge/netfilter/ebt_among.c +++ b/net/bridge/netfilter/ebt_among.c @@ -172,18 +172,35 @@ ebt_among_mt(const struct sk_buff *skb, struct xt_action_param *par) return true; } +static bool poolsize_invalid(const struct ebt_mac_wormhash *w) +{ + return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple)); +} + static int ebt_among_mt_check(const struct xt_mtchk_param *par) { const struct ebt_among_info *info = par->matchinfo; const struct ebt_entry_match *em = container_of(par->matchinfo, const struct ebt_entry_match, data); - int expected_length = sizeof(struct ebt_among_info); + unsigned int expected_length = sizeof(struct ebt_among_info); const struct ebt_mac_wormhash *wh_dst, *wh_src; int err; + if (expected_length > em->match_size) + return -EINVAL; + wh_dst = ebt_among_wh_dst(info); - wh_src = ebt_among_wh_src(info); + if (poolsize_invalid(wh_dst)) + return -EINVAL; + expected_length += ebt_mac_wormhash_size(wh_dst); + if (expected_length > em->match_size) + return -EINVAL; + + wh_src = ebt_among_wh_src(info); + if (poolsize_invalid(wh_src)) + return -EINVAL; + expected_length += ebt_mac_wormhash_size(wh_src); if (em->match_size != EBT_ALIGN(expected_length)) { -- GitLab From 60962e98c38a563b22df67b3e55fd88837d53b83 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 19 Feb 2018 08:10:17 +0100 Subject: [PATCH 0314/1834] netfilter: ipv6: fix use-after-free Write in nf_nat_ipv6_manip_pkt commit b078556aecd791b0e5cb3a59f4c3a14273b52121 upstream. l4proto->manip_pkt() can cause reallocation of skb head so pointer to the ipv6 header must be reloaded. Reported-and-tested-by: Fixes: 58a317f1061c89 ("netfilter: ipv6: add IPv6 NAT support") Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c index e0be97e636a4..322c7657165b 100644 --- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c @@ -99,6 +99,10 @@ static bool nf_nat_ipv6_manip_pkt(struct sk_buff *skb, !l4proto->manip_pkt(skb, &nf_nat_l3proto_ipv6, iphdroff, hdroff, target, maniptype)) return false; + + /* must reload, offset might have changed */ + ipv6h = (void *)skb->data + iphdroff; + manip_addr: if (maniptype == NF_NAT_MANIP_SRC) ipv6h->saddr = target->src.u3.in6; -- GitLab From 61346e20c0017abf77bd133f80c35ca9224fbd96 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 22 Nov 2016 14:44:17 +0100 Subject: [PATCH 0315/1834] netfilter: x_tables: pass xt_counters struct instead of packet counter commit 4d31eef5176df06f218201bc9c0ce40babb41660 upstream. On SMP we overload the packet counter (unsigned long) to contain percpu offset. Hide this from callers and pass xt_counters address instead. Preparation patch to allocate the percpu counters in page-sized batch chunks. Signed-off-by: Florian Westphal Acked-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/x_tables.h | 6 +----- net/ipv4/netfilter/arp_tables.c | 4 ++-- net/ipv4/netfilter/ip_tables.c | 4 ++-- net/ipv6/netfilter/ip6_tables.c | 5 ++--- net/netfilter/x_tables.c | 9 +++++++++ 5 files changed, 16 insertions(+), 12 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 2ad1a2b289b5..dfd56c13883f 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -402,11 +402,7 @@ static inline unsigned long xt_percpu_counter_alloc(void) return 0; } -static inline void xt_percpu_counter_free(u64 pcnt) -{ - if (nr_cpu_ids > 1) - free_percpu((void __percpu *) (unsigned long) pcnt); -} +void xt_percpu_counter_free(struct xt_counters *cnt); static inline struct xt_counters * xt_get_this_cpu_counter(struct xt_counters *cnt) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index ad1c49ed2987..bfdd29a0b0ba 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -447,7 +447,7 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) err: module_put(t->u.kernel.target->me); out: - xt_percpu_counter_free(e->counters.pcnt); + xt_percpu_counter_free(&e->counters); return ret; } @@ -527,7 +527,7 @@ static inline void cleanup_entry(struct arpt_entry *e) if (par.target->destroy != NULL) par.target->destroy(&par); module_put(par.target->me); - xt_percpu_counter_free(e->counters.pcnt); + xt_percpu_counter_free(&e->counters); } /* Checks and translates the user-supplied table segment (held in diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a3c5433bb76f..1cf5070129ae 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -591,7 +591,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, cleanup_match(ematch, net); } - xt_percpu_counter_free(e->counters.pcnt); + xt_percpu_counter_free(&e->counters); return ret; } @@ -679,7 +679,7 @@ cleanup_entry(struct ipt_entry *e, struct net *net) if (par.target->destroy != NULL) par.target->destroy(&par); module_put(par.target->me); - xt_percpu_counter_free(e->counters.pcnt); + xt_percpu_counter_free(&e->counters); } /* Checks and translates the user-supplied table segment (held in diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 3d95b070cdad..3117c17ed0db 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -620,7 +620,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, cleanup_match(ematch, net); } - xt_percpu_counter_free(e->counters.pcnt); + xt_percpu_counter_free(&e->counters); return ret; } @@ -707,8 +707,7 @@ static void cleanup_entry(struct ip6t_entry *e, struct net *net) if (par.target->destroy != NULL) par.target->destroy(&par); module_put(par.target->me); - - xt_percpu_counter_free(e->counters.pcnt); + xt_percpu_counter_free(&e->counters); } /* Checks and translates the user-supplied table segment (held in diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index e47ade305a46..4ef619d16d81 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1619,6 +1619,15 @@ void xt_proto_fini(struct net *net, u_int8_t af) } EXPORT_SYMBOL_GPL(xt_proto_fini); +void xt_percpu_counter_free(struct xt_counters *counters) +{ + unsigned long pcnt = counters->pcnt; + + if (nr_cpu_ids > 1) + free_percpu((void __percpu *)pcnt); +} +EXPORT_SYMBOL_GPL(xt_percpu_counter_free); + static int __net_init xt_net_init(struct net *net) { int i; -- GitLab From dac4448faf499b2597536aecfdb46eeace17a243 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 22 Nov 2016 14:44:18 +0100 Subject: [PATCH 0316/1834] netfilter: x_tables: pass xt_counters struct to counter allocator commit f28e15bacedd444608e25421c72eb2cf4527c9ca upstream. Keeps some noise away from a followup patch. Signed-off-by: Florian Westphal Acked-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/x_tables.h | 27 +-------------------------- net/ipv4/netfilter/arp_tables.c | 5 +---- net/ipv4/netfilter/ip_tables.c | 5 +---- net/ipv6/netfilter/ip6_tables.c | 5 +---- net/netfilter/x_tables.c | 30 ++++++++++++++++++++++++++++++ 5 files changed, 34 insertions(+), 38 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index dfd56c13883f..58f37f8a3d8b 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -376,32 +376,7 @@ static inline unsigned long ifname_compare_aligned(const char *_a, } -/* On SMP, ip(6)t_entry->counters.pcnt holds address of the - * real (percpu) counter. On !SMP, its just the packet count, - * so nothing needs to be done there. - * - * xt_percpu_counter_alloc returns the address of the percpu - * counter, or 0 on !SMP. We force an alignment of 16 bytes - * so that bytes/packets share a common cache line. - * - * Hence caller must use IS_ERR_VALUE to check for error, this - * allows us to return 0 for single core systems without forcing - * callers to deal with SMP vs. NONSMP issues. - */ -static inline unsigned long xt_percpu_counter_alloc(void) -{ - if (nr_cpu_ids > 1) { - void __percpu *res = __alloc_percpu(sizeof(struct xt_counters), - sizeof(struct xt_counters)); - - if (res == NULL) - return -ENOMEM; - - return (__force unsigned long) res; - } - - return 0; -} +bool xt_percpu_counter_alloc(struct xt_counters *counters); void xt_percpu_counter_free(struct xt_counters *cnt); static inline struct xt_counters * diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index bfdd29a0b0ba..6f116d384c01 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -423,13 +423,10 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) { struct xt_entry_target *t; struct xt_target *target; - unsigned long pcnt; int ret; - pcnt = xt_percpu_counter_alloc(); - if (IS_ERR_VALUE(pcnt)) + if (!xt_percpu_counter_alloc(&e->counters)) return -ENOMEM; - e->counters.pcnt = pcnt; t = arpt_get_target(e); target = xt_request_find_target(NFPROTO_ARP, t->u.user.name, diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 1cf5070129ae..021ddf17d000 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -548,12 +548,9 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, unsigned int j; struct xt_mtchk_param mtpar; struct xt_entry_match *ematch; - unsigned long pcnt; - pcnt = xt_percpu_counter_alloc(); - if (IS_ERR_VALUE(pcnt)) + if (!xt_percpu_counter_alloc(&e->counters)) return -ENOMEM; - e->counters.pcnt = pcnt; j = 0; mtpar.net = net; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 3117c17ed0db..d70b302b2f21 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -578,12 +578,9 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, unsigned int j; struct xt_mtchk_param mtpar; struct xt_entry_match *ematch; - unsigned long pcnt; - pcnt = xt_percpu_counter_alloc(); - if (IS_ERR_VALUE(pcnt)) + if (!xt_percpu_counter_alloc(&e->counters)) return -ENOMEM; - e->counters.pcnt = pcnt; j = 0; mtpar.net = net; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 4ef619d16d81..9736743e747c 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1619,6 +1619,36 @@ void xt_proto_fini(struct net *net, u_int8_t af) } EXPORT_SYMBOL_GPL(xt_proto_fini); +/** + * xt_percpu_counter_alloc - allocate x_tables rule counter + * + * @counter: pointer to counter struct inside the ip(6)/arpt_entry struct + * + * On SMP, the packet counter [ ip(6)t_entry->counters.pcnt ] will then + * contain the address of the real (percpu) counter. + * + * Rule evaluation needs to use xt_get_this_cpu_counter() helper + * to fetch the real percpu counter. + * + * returns false on error. + */ +bool xt_percpu_counter_alloc(struct xt_counters *counter) +{ + void __percpu *res; + + if (nr_cpu_ids <= 1) + return true; + + res = __alloc_percpu(sizeof(struct xt_counters), + sizeof(struct xt_counters)); + if (!res) + return false; + + counter->pcnt = (__force unsigned long)res; + return true; +} +EXPORT_SYMBOL_GPL(xt_percpu_counter_alloc); + void xt_percpu_counter_free(struct xt_counters *counters) { unsigned long pcnt = counters->pcnt; -- GitLab From db6a0cbeb940898dd56167241f68972b50890566 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 22 Nov 2016 14:44:19 +0100 Subject: [PATCH 0317/1834] netfilter: x_tables: pack percpu counter allocations commit ae0ac0ed6fcf5af3be0f63eb935f483f44a402d2 upstream. instead of allocating each xt_counter individually, allocate 4k chunks and then use these for counter allocation requests. This should speed up rule evaluation by increasing data locality, also speeds up ruleset loading because we reduce calls to the percpu allocator. As Eric points out we can't use PAGE_SIZE, page_allocator would fail on arches with 64k page size. Suggested-by: Eric Dumazet Signed-off-by: Florian Westphal Acked-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/x_tables.h | 7 +++++- net/ipv4/netfilter/arp_tables.c | 9 +++++--- net/ipv4/netfilter/ip_tables.c | 9 +++++--- net/ipv6/netfilter/ip6_tables.c | 9 +++++--- net/netfilter/x_tables.c | 34 ++++++++++++++++++++++-------- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 58f37f8a3d8b..9bfeb88fb940 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -375,8 +375,13 @@ static inline unsigned long ifname_compare_aligned(const char *_a, return ret; } +struct xt_percpu_counter_alloc_state { + unsigned int off; + const char __percpu *mem; +}; -bool xt_percpu_counter_alloc(struct xt_counters *counters); +bool xt_percpu_counter_alloc(struct xt_percpu_counter_alloc_state *state, + struct xt_counters *counter); void xt_percpu_counter_free(struct xt_counters *cnt); static inline struct xt_counters * diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 6f116d384c01..d35815e5967b 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -419,13 +419,14 @@ static inline int check_target(struct arpt_entry *e, const char *name) } static inline int -find_check_entry(struct arpt_entry *e, const char *name, unsigned int size) +find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, + struct xt_percpu_counter_alloc_state *alloc_state) { struct xt_entry_target *t; struct xt_target *target; int ret; - if (!xt_percpu_counter_alloc(&e->counters)) + if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) return -ENOMEM; t = arpt_get_target(e); @@ -533,6 +534,7 @@ static inline void cleanup_entry(struct arpt_entry *e) static int translate_table(struct xt_table_info *newinfo, void *entry0, const struct arpt_replace *repl) { + struct xt_percpu_counter_alloc_state alloc_state = { 0 }; struct arpt_entry *iter; unsigned int *offsets; unsigned int i; @@ -595,7 +597,8 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, /* Finally, each sanity check must pass */ i = 0; xt_entry_foreach(iter, entry0, newinfo->size) { - ret = find_check_entry(iter, repl->name, repl->size); + ret = find_check_entry(iter, repl->name, repl->size, + &alloc_state); if (ret != 0) break; ++i; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 021ddf17d000..e78f6521823f 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -540,7 +540,8 @@ static int check_target(struct ipt_entry *e, struct net *net, const char *name) static int find_check_entry(struct ipt_entry *e, struct net *net, const char *name, - unsigned int size) + unsigned int size, + struct xt_percpu_counter_alloc_state *alloc_state) { struct xt_entry_target *t; struct xt_target *target; @@ -549,7 +550,7 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name, struct xt_mtchk_param mtpar; struct xt_entry_match *ematch; - if (!xt_percpu_counter_alloc(&e->counters)) + if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) return -ENOMEM; j = 0; @@ -685,6 +686,7 @@ static int translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, const struct ipt_replace *repl) { + struct xt_percpu_counter_alloc_state alloc_state = { 0 }; struct ipt_entry *iter; unsigned int *offsets; unsigned int i; @@ -744,7 +746,8 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, /* Finally, each sanity check must pass */ i = 0; xt_entry_foreach(iter, entry0, newinfo->size) { - ret = find_check_entry(iter, net, repl->name, repl->size); + ret = find_check_entry(iter, net, repl->name, repl->size, + &alloc_state); if (ret != 0) break; ++i; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index d70b302b2f21..e26becc9a43d 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -570,7 +570,8 @@ static int check_target(struct ip6t_entry *e, struct net *net, const char *name) static int find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, - unsigned int size) + unsigned int size, + struct xt_percpu_counter_alloc_state *alloc_state) { struct xt_entry_target *t; struct xt_target *target; @@ -579,7 +580,7 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name, struct xt_mtchk_param mtpar; struct xt_entry_match *ematch; - if (!xt_percpu_counter_alloc(&e->counters)) + if (!xt_percpu_counter_alloc(alloc_state, &e->counters)) return -ENOMEM; j = 0; @@ -713,6 +714,7 @@ static int translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, const struct ip6t_replace *repl) { + struct xt_percpu_counter_alloc_state alloc_state = { 0 }; struct ip6t_entry *iter; unsigned int *offsets; unsigned int i; @@ -772,7 +774,8 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, /* Finally, each sanity check must pass */ i = 0; xt_entry_foreach(iter, entry0, newinfo->size) { - ret = find_check_entry(iter, net, repl->name, repl->size); + ret = find_check_entry(iter, net, repl->name, repl->size, + &alloc_state); if (ret != 0) break; ++i; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 9736743e747c..ac26b71d900e 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -39,6 +39,8 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module"); +#define XT_PCPU_BLOCK_SIZE 4096 + struct compat_delta { unsigned int offset; /* offset in kernel */ int delta; /* delta in 32bit user land */ @@ -1622,6 +1624,7 @@ EXPORT_SYMBOL_GPL(xt_proto_fini); /** * xt_percpu_counter_alloc - allocate x_tables rule counter * + * @state: pointer to xt_percpu allocation state * @counter: pointer to counter struct inside the ip(6)/arpt_entry struct * * On SMP, the packet counter [ ip(6)t_entry->counters.pcnt ] will then @@ -1630,21 +1633,34 @@ EXPORT_SYMBOL_GPL(xt_proto_fini); * Rule evaluation needs to use xt_get_this_cpu_counter() helper * to fetch the real percpu counter. * + * To speed up allocation and improve data locality, a 4kb block is + * allocated. + * + * xt_percpu_counter_alloc_state contains the base address of the + * allocated page and the current sub-offset. + * * returns false on error. */ -bool xt_percpu_counter_alloc(struct xt_counters *counter) +bool xt_percpu_counter_alloc(struct xt_percpu_counter_alloc_state *state, + struct xt_counters *counter) { - void __percpu *res; + BUILD_BUG_ON(XT_PCPU_BLOCK_SIZE < (sizeof(*counter) * 2)); if (nr_cpu_ids <= 1) return true; - res = __alloc_percpu(sizeof(struct xt_counters), - sizeof(struct xt_counters)); - if (!res) - return false; - - counter->pcnt = (__force unsigned long)res; + if (!state->mem) { + state->mem = __alloc_percpu(XT_PCPU_BLOCK_SIZE, + XT_PCPU_BLOCK_SIZE); + if (!state->mem) + return false; + } + counter->pcnt = (__force unsigned long)(state->mem + state->off); + state->off += sizeof(*counter); + if (state->off > (XT_PCPU_BLOCK_SIZE - sizeof(*counter))) { + state->mem = NULL; + state->off = 0; + } return true; } EXPORT_SYMBOL_GPL(xt_percpu_counter_alloc); @@ -1653,7 +1669,7 @@ void xt_percpu_counter_free(struct xt_counters *counters) { unsigned long pcnt = counters->pcnt; - if (nr_cpu_ids > 1) + if (nr_cpu_ids > 1 && (pcnt & (XT_PCPU_BLOCK_SIZE - 1)) == 0) free_percpu((void __percpu *)pcnt); } EXPORT_SYMBOL_GPL(xt_percpu_counter_free); -- GitLab From b496b24aa586e4b528b4ac4f39362bc94f502b6d Mon Sep 17 00:00:00 2001 From: Tahsin Erdogan Date: Sat, 5 Aug 2017 22:41:42 -0400 Subject: [PATCH 0318/1834] ext4: inplace xattr block update fails to deduplicate blocks commit ec00022030da5761518476096626338bd67df57a upstream. When an xattr block has a single reference, block is updated inplace and it is reinserted to the cache. Later, a cache lookup is performed to see whether an existing block has the same contents. This cache lookup will most of the time return the just inserted entry so deduplication is not achieved. Running the following test script will produce two xattr blocks which can be observed in "File ACL: " line of debugfs output: mke2fs -b 1024 -I 128 -F -O extent /dev/sdb 1G mount /dev/sdb /mnt/sdb touch /mnt/sdb/{x,y} setfattr -n user.1 -v aaa /mnt/sdb/x setfattr -n user.2 -v bbb /mnt/sdb/x setfattr -n user.1 -v aaa /mnt/sdb/y setfattr -n user.2 -v bbb /mnt/sdb/y debugfs -R 'stat x' /dev/sdb | cat debugfs -R 'stat y' /dev/sdb | cat This patch defers the reinsertion to the cache so that we can locate other blocks with the same contents. Signed-off-by: Tahsin Erdogan Signed-off-by: Theodore Ts'o Reviewed-by: Andreas Dilger Signed-off-by: Tommi Rantala Signed-off-by: Greg Kroah-Hartman --- fs/ext4/xattr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 3eeed8f0aa06..3fadfabcac39 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c @@ -837,8 +837,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, if (!IS_LAST_ENTRY(s->first)) ext4_xattr_rehash(header(s->base), s->here); - ext4_xattr_cache_insert(ext4_mb_cache, - bs->bh); } ext4_xattr_block_csum_set(inode, bs->bh); unlock_buffer(bs->bh); @@ -959,6 +957,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, } else if (bs->bh && s->base == bs->bh->b_data) { /* We were modifying this block in-place. */ ea_bdebug(bs->bh, "keeping this block"); + ext4_xattr_cache_insert(ext4_mb_cache, bs->bh); new_bh = bs->bh; get_bh(new_bh); } else { -- GitLab From cde0b3af90c7edc198956a45a66e5fc92bd04b6c Mon Sep 17 00:00:00 2001 From: Clay McClure Date: Thu, 21 Sep 2017 19:01:34 -0700 Subject: [PATCH 0319/1834] ubi: Fix race condition between ubi volume creation and udev commit a51a0c8d213594bc094cb8e54aad0cb6d7f7b9a6 upstream. Similar to commit 714fb87e8bc0 ("ubi: Fix race condition between ubi device creation and udev"), we should make the volume active before registering it. Signed-off-by: Clay McClure Cc: Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/vmt.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 7ac78c13dd1c..1bcb25bc35ef 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -265,6 +265,12 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vol->last_eb_bytes = vol->usable_leb_size; } + /* Make volume "available" before it becomes accessible via sysfs */ + spin_lock(&ubi->volumes_lock); + ubi->volumes[vol_id] = vol; + ubi->vol_count += 1; + spin_unlock(&ubi->volumes_lock); + /* Register character device for the volume */ cdev_init(&vol->cdev, &ubi_vol_cdev_operations); vol->cdev.owner = THIS_MODULE; @@ -304,11 +310,6 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) if (err) goto out_sysfs; - spin_lock(&ubi->volumes_lock); - ubi->volumes[vol_id] = vol; - ubi->vol_count += 1; - spin_unlock(&ubi->volumes_lock); - ubi_volume_notify(ubi, vol, UBI_VOLUME_ADDED); self_check_volumes(ubi); return err; @@ -328,6 +329,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) out_cdev: cdev_del(&vol->cdev); out_mapping: + spin_lock(&ubi->volumes_lock); + ubi->volumes[vol_id] = NULL; + ubi->vol_count -= 1; + spin_unlock(&ubi->volumes_lock); if (do_free) ubi_eba_destroy_table(eba_tbl); out_acc: -- GitLab From 05d42c517250653f53e296e3d59d0b0db1a87296 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 4 Dec 2017 14:45:10 -0800 Subject: [PATCH 0320/1834] scsi: qla2xxx: Replace fcport alloc with qla2x00_alloc_fcport commit 063b36d6b0ad74c748d536f5cb47bac2f850a0fa upstream. Current code manually allocate an fcport structure that is not properly initialize. Replace kzalloc with qla2x00_alloc_fcport, so that all fields are initialized. Also set set scan flag to port found Cc: Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 59059ffbb98c..11f45cb99892 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -5789,7 +5789,7 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, fc_port_t *fcport; int rc; - fcport = kzalloc(sizeof(*fcport), GFP_KERNEL); + fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); if (!fcport) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf06f, "qla_target(%d): Allocation of tmp FC port failed", -- GitLab From fb1f410daf56ecab5c33c9685c868b43023ea833 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 6 Mar 2018 12:47:08 -0500 Subject: [PATCH 0321/1834] NFS: Fix an incorrect type in struct nfs_direct_req commit d9ee65539d3eabd9ade46cca1780e3309ad0f907 upstream. The start offset needs to be of type loff_t. Fixed: 5fadeb47dcc5c ("nfs: count DIO good bytes correctly with mirroring") Cc: stable@vger.kernel.org # v4.0+ Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/direct.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 1ac1593aded3..1ab91124a93e 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c @@ -86,10 +86,10 @@ struct nfs_direct_req { struct nfs_direct_mirror mirrors[NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX]; int mirror_count; + loff_t io_start; /* Start offset for I/O */ ssize_t count, /* bytes actually processed */ max_count, /* max expected count */ bytes_left, /* bytes left to be sent */ - io_start, /* start of IO */ error; /* any reported error */ struct completion completion; /* wait for i/o completion */ -- GitLab From 2a28923bb5b8a0a485c7a3a424e6a2c9f01038a3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 7 Mar 2018 15:22:31 -0500 Subject: [PATCH 0322/1834] NFS: Fix unstable write completion commit c4f24df942a181699c5bab01b8e5e82b925f77f3 upstream. We do want to respect the FLUSH_SYNC argument to nfs_commit_inode() to ensure that all outstanding COMMIT requests to the inode in question are complete. Currently we may exit early from both nfs_commit_inode() and nfs_write_inode() even if there are COMMIT requests in flight, or unstable writes on the commit list. In order to get the right semantics w.r.t. sync_inode(), we don't need to have nfs_commit_inode() reset the inode dirty flags when called from nfs_wb_page() and/or nfs_wb_all(). We just need to ensure that nfs_write_inode() leaves them in the right state if there are outstanding commits, or stable pages. Reported-by: Scott Mayhew Fixes: dc4fd9ab01ab ("nfs: don't wait on commit in nfs_commit_inode()...") Cc: stable@vger.kernel.org # v4.14+ Signed-off-by: Trond Myklebust Signed-off-by: Greg Kroah-Hartman --- fs/nfs/write.c | 83 ++++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 9a3b3820306d..a8b786a648cd 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c @@ -1847,40 +1847,43 @@ int nfs_generic_commit_list(struct inode *inode, struct list_head *head, return status; } -int nfs_commit_inode(struct inode *inode, int how) +static int __nfs_commit_inode(struct inode *inode, int how, + struct writeback_control *wbc) { LIST_HEAD(head); struct nfs_commit_info cinfo; int may_wait = how & FLUSH_SYNC; - int error = 0; - int res; + int ret, nscan; nfs_init_cinfo_from_inode(&cinfo, inode); nfs_commit_begin(cinfo.mds); - res = nfs_scan_commit(inode, &head, &cinfo); - if (res) - error = nfs_generic_commit_list(inode, &head, how, &cinfo); + for (;;) { + ret = nscan = nfs_scan_commit(inode, &head, &cinfo); + if (ret <= 0) + break; + ret = nfs_generic_commit_list(inode, &head, how, &cinfo); + if (ret < 0) + break; + ret = 0; + if (wbc && wbc->sync_mode == WB_SYNC_NONE) { + if (nscan < wbc->nr_to_write) + wbc->nr_to_write -= nscan; + else + wbc->nr_to_write = 0; + } + if (nscan < INT_MAX) + break; + cond_resched(); + } nfs_commit_end(cinfo.mds); - if (res == 0) - return res; - if (error < 0) - goto out_error; - if (!may_wait) - goto out_mark_dirty; - error = wait_on_commit(cinfo.mds); - if (error < 0) - return error; - return res; -out_error: - res = error; - /* Note: If we exit without ensuring that the commit is complete, - * we must mark the inode as dirty. Otherwise, future calls to - * sync_inode() with the WB_SYNC_ALL flag set will fail to ensure - * that the data is on the disk. - */ -out_mark_dirty: - __mark_inode_dirty(inode, I_DIRTY_DATASYNC); - return res; + if (ret || !may_wait) + return ret; + return wait_on_commit(cinfo.mds); +} + +int nfs_commit_inode(struct inode *inode, int how) +{ + return __nfs_commit_inode(inode, how, NULL); } EXPORT_SYMBOL_GPL(nfs_commit_inode); @@ -1890,11 +1893,11 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) int flags = FLUSH_SYNC; int ret = 0; - /* no commits means nothing needs to be done */ - if (!nfsi->commit_info.ncommit) - return ret; - if (wbc->sync_mode == WB_SYNC_NONE) { + /* no commits means nothing needs to be done */ + if (!nfsi->commit_info.ncommit) + goto check_requests_outstanding; + /* Don't commit yet if this is a non-blocking flush and there * are a lot of outstanding writes for this mapping. */ @@ -1905,16 +1908,16 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) flags = 0; } - ret = nfs_commit_inode(inode, flags); - if (ret >= 0) { - if (wbc->sync_mode == WB_SYNC_NONE) { - if (ret < wbc->nr_to_write) - wbc->nr_to_write -= ret; - else - wbc->nr_to_write = 0; - } - return 0; - } + ret = __nfs_commit_inode(inode, flags, wbc); + if (!ret) { + if (flags & FLUSH_SYNC) + return 0; + } else if (nfsi->commit_info.ncommit) + goto out_mark_dirty; + +check_requests_outstanding: + if (!atomic_read(&nfsi->commit_info.rpcs_out)) + return ret; out_mark_dirty: __mark_inode_dirty(inode, I_DIRTY_DATASYNC); return ret; -- GitLab From cd696744d6d71fbb8b5f2728b25afb51cc3811d7 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 3 Nov 2017 07:58:54 -0500 Subject: [PATCH 0323/1834] x86/module: Detect and skip invalid relocations commit eda9cec4c9a12208a6f69fbe68f72a6311d50032 upstream. There have been some cases where external tooling (e.g., kpatch-build) creates a corrupt relocation which targets the wrong address. This is a silent failure which can corrupt memory in unexpected places. On x86, the bytes of data being overwritten by relocations are always initialized to zero beforehand. Use that knowledge to add sanity checks to detect such cases before they corrupt memory. Signed-off-by: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: jeyu@kernel.org Cc: live-patching@vger.kernel.org Link: http://lkml.kernel.org/r/37450d6c6225e54db107fba447ce9e56e5f758e9.1509713553.git.jpoimboe@redhat.com [ Restructured the messages, as it's unclear whether the relocation or the target is corrupted. ] Signed-off-by: Ingo Molnar Cc: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/module.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 477ae806c2fa..87f30a8138f0 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -171,19 +171,27 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, case R_X86_64_NONE: break; case R_X86_64_64: + if (*(u64 *)loc != 0) + goto invalid_relocation; *(u64 *)loc = val; break; case R_X86_64_32: + if (*(u32 *)loc != 0) + goto invalid_relocation; *(u32 *)loc = val; if (val != *(u32 *)loc) goto overflow; break; case R_X86_64_32S: + if (*(s32 *)loc != 0) + goto invalid_relocation; *(s32 *)loc = val; if ((s64)val != *(s32 *)loc) goto overflow; break; case R_X86_64_PC32: + if (*(u32 *)loc != 0) + goto invalid_relocation; val -= (u64)loc; *(u32 *)loc = val; #if 0 @@ -199,6 +207,11 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, } return 0; +invalid_relocation: + pr_err("x86/modules: Skipping invalid relocation target, existing value is nonzero for type %d, loc %p, val %Lx\n", + (int)ELF64_R_TYPE(rel[i].r_info), loc, val); + return -ENOEXEC; + overflow: pr_err("overflow in relocation type %d val %Lx\n", (int)ELF64_R_TYPE(rel[i].r_info), val); -- GitLab From 941bfd125c78713649eefb338e52300585fd6ec7 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 7 Feb 2018 14:20:09 -0800 Subject: [PATCH 0324/1834] x86: Treat R_X86_64_PLT32 as R_X86_64_PC32 commit b21ebf2fb4cde1618915a97cc773e287ff49173e upstream. On i386, there are 2 types of PLTs, PIC and non-PIC. PIE and shared objects must use PIC PLT. To use PIC PLT, you need to load _GLOBAL_OFFSET_TABLE_ into EBX first. There is no need for that on x86-64 since x86-64 uses PC-relative PLT. On x86-64, for 32-bit PC-relative branches, we can generate PLT32 relocation, instead of PC32 relocation, which can also be used as a marker for 32-bit PC-relative branches. Linker can always reduce PLT32 relocation to PC32 if function is defined locally. Local functions should use PC32 relocation. As far as Linux kernel is concerned, R_X86_64_PLT32 can be treated the same as R_X86_64_PC32 since Linux kernel doesn't use PLT. R_X86_64_PLT32 for 32-bit PC-relative branches has been enabled in binutils master branch which will become binutils 2.31. [ hjl is working on having better documentation on this all, but a few more notes from him: "PLT32 relocation is used as marker for PC-relative branches. Because of EBX, it looks odd to generate PLT32 relocation on i386 when EBX doesn't have GOT. As for symbol resolution, PLT32 and PC32 relocations are almost interchangeable. But when linker sees PLT32 relocation against a protected symbol, it can resolved locally at link-time since it is used on a branch instruction. Linker can't do that for PC32 relocation" but for the kernel use, the two are basically the same, and this commit gets things building and working with the current binutils master - Linus ] Signed-off-by: H.J. Lu Signed-off-by: Linus Torvalds Cc: Matthias Kaehlcke Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/machine_kexec_64.c | 1 + arch/x86/kernel/module.c | 1 + arch/x86/tools/relocs.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 8c1f218926d7..a5784a14f8d1 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c @@ -524,6 +524,7 @@ int arch_kexec_apply_relocations_add(const Elf64_Ehdr *ehdr, goto overflow; break; case R_X86_64_PC32: + case R_X86_64_PLT32: value -= (u64)address; *(u32 *)location = value; break; diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 87f30a8138f0..19977d2f97fb 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -190,6 +190,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, goto overflow; break; case R_X86_64_PC32: + case R_X86_64_PLT32: if (*(u32 *)loc != 0) goto invalid_relocation; val -= (u64)loc; diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c index 73eb7fd4aec4..5b6c8486a0be 100644 --- a/arch/x86/tools/relocs.c +++ b/arch/x86/tools/relocs.c @@ -769,9 +769,12 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym, break; case R_X86_64_PC32: + case R_X86_64_PLT32: /* * PC relative relocations don't need to be adjusted unless * referencing a percpu symbol. + * + * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32. */ if (is_percpu_sym(sym, symname)) add_reloc(&relocs32neg, offset); -- GitLab From d156461370d52eacca83404d6ed40ce4288af088 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 16 Feb 2018 11:58:54 -0200 Subject: [PATCH 0325/1834] ASoC: sgtl5000: Fix suspend/resume commit a8992973edbb2555e956b90f6fe97c4bc14d761d upstream. Commit 8419caa72702 ("ASoC: sgtl5000: Do not disable regulators in SND_SOC_BIAS_OFF") causes the sgtl5000 to fail after a suspend/resume sequence: Playing WAVE '/media/a2002011001-e02.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo aplay: pcm_write:2051: write error: Input/output error The problem is caused by the fact that the aforementioned commit dropped the cache handling, so re-introduce the register map resync to fix the problem. Suggested-by: Mark Brown Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown Cc: Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/sgtl5000.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 1589325855bc..3dba5550a665 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -774,15 +774,26 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, static int sgtl5000_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct sgtl5000_priv *sgtl = snd_soc_codec_get_drvdata(codec); + int ret; + switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_STANDBY: + regcache_cache_only(sgtl->regmap, false); + ret = regcache_sync(sgtl->regmap); + if (ret) { + regcache_cache_only(sgtl->regmap, true); + return ret; + } + snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_REFTOP_POWERUP, SGTL5000_REFTOP_POWERUP); break; case SND_SOC_BIAS_OFF: + regcache_cache_only(sgtl->regmap, true); snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, SGTL5000_REFTOP_POWERUP, 0); break; -- GitLab From 24a401dd0fb61b2edc8209ed9577c35f4f25f7fc Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 18 Feb 2018 23:01:44 +0100 Subject: [PATCH 0326/1834] ASoC: rt5651: Fix regcache sync errors on resume commit 2d30e9494f1ea320aaaad0cff9ddd92c87eac355 upstream. The ALC5651 does not like multi-write accesses, avoid them. This fixes: rt5651 i2c-10EC5651:00: Unable to sync registers 0x27-0x28. -121 Errors on resume (and all registers after the registers in the error not being synced). Signed-off-by: Hans de Goede Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/rt5651.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index f5d34153e21f..f0c9e2562474 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1736,6 +1736,7 @@ static const struct regmap_config rt5651_regmap = { .num_reg_defaults = ARRAY_SIZE(rt5651_reg), .ranges = rt5651_ranges, .num_ranges = ARRAY_SIZE(rt5651_ranges), + .use_single_rw = true, }; #if defined(CONFIG_OF) -- GitLab From 4afade73b70a47b17718133d0421c03b6ec8d10b Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 15 Feb 2018 13:02:27 +0100 Subject: [PATCH 0327/1834] serial: sh-sci: prevent lockup on full TTY buffers commit 7842055bfce4bf0170d0f61df8b2add8399697be upstream. When the TTY buffers fill up to the configured maximum, a system lockup occurs: [ 598.820128] INFO: rcu_preempt detected stalls on CPUs/tasks: [ 598.825796] 0-...!: (1 GPs behind) idle=5a6/2/0 softirq=1974/1974 fqs=1 [ 598.832577] (detected by 3, t=62517 jiffies, g=296, c=295, q=126) [ 598.838755] Task dump for CPU 0: [ 598.841977] swapper/0 R running task 0 0 0 0x00000022 [ 598.849023] Call trace: [ 598.851476] __switch_to+0x98/0xb0 [ 598.854870] (null) This can be prevented by doing a dummy read of the RX data register. This issue affects both HSCIF and SCIF ports. Reported for R-Car H3 ES2.0; reproduced and fixed on H3 ES1.1. Probably affects other R-Car platforms as well. Reported-by: Yoshihiro Shimoda Signed-off-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Cc: stable Tested-by: Nguyen Viet Dung Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 15eaea53b3df..a55c94dfefd2 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -935,6 +935,8 @@ static void sci_receive_chars(struct uart_port *port) /* Tell the rest of the system the news. New characters! */ tty_flip_buffer_push(tport); } else { + /* TTY buffers full; read from RX reg to prevent lockup */ + serial_port_in(port, SCxRDR); serial_port_in(port, SCxSR); /* dummy read */ sci_clear_SCxSR(port, SCxSR_RDxF_CLEAR(port)); } -- GitLab From 85afaf5e2e7c354a60d06ad6ffbd10f5d28bf0e9 Mon Sep 17 00:00:00 2001 From: Jonas Danielsson Date: Mon, 29 Jan 2018 12:39:15 +0100 Subject: [PATCH 0328/1834] tty/serial: atmel: add new version check for usart commit fd63a8903a2c40425a9811c3371dd4d0f42c0ad3 upstream. On our at91sam9260 based board the usart0 and usart1 ports report their versions (ATMEL_US_VERSION) as 0x10302. This version is not included in the current checks in the driver. Signed-off-by: Jonas Danielsson Acked-by: Richard Genoud Acked-by: Nicolas Ferre Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 4d079cdaa7a3..addb287cacea 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1780,6 +1780,7 @@ static void atmel_get_ip_name(struct uart_port *port) switch (version) { case 0x302: case 0x10213: + case 0x10302: dev_dbg(port->dev, "This version is usart\n"); atmel_port->has_frac_baudrate = true; atmel_port->has_hw_timer = true; -- GitLab From 438fd54e0527633facedaf195db2755cca28bffd Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 6 Mar 2018 15:04:24 +0100 Subject: [PATCH 0329/1834] uas: fix comparison for error code commit 9a513c905bb95bef79d96feb08621c1ec8d8c4bb upstream. A typo broke the comparison. Fixes: cbeef22fd611 ("usb: uas: unconditionally bring back host after reset") Signed-off-by: Oliver Neukum CC: stable@kernel.org Acked-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 6891e9092775..a96dcc660d0f 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1076,7 +1076,7 @@ static int uas_post_reset(struct usb_interface *intf) return 0; err = uas_configure_endpoints(devinfo); - if (err && err != ENODEV) + if (err && err != -ENODEV) shost_printk(KERN_ERR, shost, "%s: alloc streams error %d after reset", __func__, err); -- GitLab From 137cb4fd3f57dc39666c68f0e0b948ac83480201 Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Thu, 15 Feb 2018 15:13:42 -0500 Subject: [PATCH 0330/1834] staging: comedi: fix comedi_nsamples_left. commit a42ae5905140c324362fe5036ae1dbb16e4d359c upstream. A rounding error was causing comedi_nsamples_left to return the wrong value when nsamples was not a multiple of the scan length. Cc: # v4.4+ Signed-off-by: Frank Mori Hess Reviewed-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index a5bf2cc165c0..1736248bc5b8 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -484,8 +484,7 @@ unsigned int comedi_nsamples_left(struct comedi_subdevice *s, struct comedi_cmd *cmd = &async->cmd; if (cmd->stop_src == TRIG_COUNT) { - unsigned int nscans = nsamples / cmd->scan_end_arg; - unsigned int scans_left = __comedi_nscans_left(s, nscans); + unsigned int scans_left = __comedi_nscans_left(s, cmd->stop_arg); unsigned int scan_pos = comedi_bytes_to_samples(s, async->scan_progress); unsigned long long samples_left = 0; -- GitLab From 1d47c874cd72dec1fabff5ecdb766d364467ff56 Mon Sep 17 00:00:00 2001 From: Joel Fernandes Date: Fri, 16 Feb 2018 11:02:01 -0800 Subject: [PATCH 0331/1834] staging: android: ashmem: Fix lockdep issue during llseek commit cb57469c9573f6018cd1302953dd45d6e05aba7b upstream. ashmem_mutex create a chain of dependencies like so: (1) mmap syscall -> mmap_sem -> (acquired) ashmem_mmap ashmem_mutex (try to acquire) (block) (2) llseek syscall -> ashmem_llseek -> ashmem_mutex -> (acquired) inode_lock -> inode->i_rwsem (try to acquire) (block) (3) getdents -> iterate_dir -> inode_lock -> inode->i_rwsem (acquired) copy_to_user -> mmap_sem (try to acquire) There is a lock ordering created between mmap_sem and inode->i_rwsem causing a lockdep splat [2] during a syzcaller test, this patch fixes the issue by unlocking the mutex earlier. Functionally that's Ok since we don't need to protect vfs_llseek. [1] https://patchwork.kernel.org/patch/10185031/ [2] https://lkml.org/lkml/2018/1/10/48 Acked-by: Todd Kjos Cc: Arve Hjonnevag Cc: stable@vger.kernel.org Reported-by: syzbot+8ec30bb7bf1a981a2012@syzkaller.appspotmail.com Signed-off-by: Joel Fernandes Acked-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index d08324998933..db100154f85c 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -343,24 +343,23 @@ static loff_t ashmem_llseek(struct file *file, loff_t offset, int origin) mutex_lock(&ashmem_mutex); if (asma->size == 0) { - ret = -EINVAL; - goto out; + mutex_unlock(&ashmem_mutex); + return -EINVAL; } if (!asma->file) { - ret = -EBADF; - goto out; + mutex_unlock(&ashmem_mutex); + return -EBADF; } + mutex_unlock(&ashmem_mutex); + ret = vfs_llseek(asma->file, offset, origin); if (ret < 0) - goto out; + return ret; /** Copy f_pos from backing file, since f_ops->llseek() sets it */ file->f_pos = asma->file->f_pos; - -out: - mutex_unlock(&ashmem_mutex); return ret; } -- GitLab From 3fad4ea9283da98cd02d7b30e7a5e96e0a414ae1 Mon Sep 17 00:00:00 2001 From: Teijo Kinnunen Date: Thu, 1 Mar 2018 19:34:29 +0200 Subject: [PATCH 0332/1834] USB: storage: Add JMicron bridge 152d:2567 to unusual_devs.h commit 5126a504b63d82785eaece3a9c30c660b313785a upstream. This USB-SATA controller seems to be similar with JMicron bridge 152d:2566 already on the list. Adding it here fixes "Invalid field in cdb" errors. Signed-off-by: Teijo Kinnunen Cc: stable@vger.kernel.org Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/unusual_devs.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index b605115eb47a..ca3a5d430ae1 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2137,6 +2137,13 @@ UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BROKEN_FUA ), +/* Reported by Teijo Kinnunen */ +UNUSUAL_DEV( 0x152d, 0x2567, 0x0117, 0x0117, + "JMicron", + "USB to ATA/ATAPI Bridge", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BROKEN_FUA ), + /* Reported-by George Cherian */ UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999, "JMicron", -- GitLab From b7661e9af851da7f5cba97749591080f78dacbca Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 22 Feb 2018 17:39:17 +0000 Subject: [PATCH 0333/1834] usbip: vudc: fix null pointer dereference on udc->lock commit df3334c223a033f562645712e832ca4cbb326bbf upstream. Currently the driver attempts to spin lock on udc->lock before a NULL pointer check is performed on udc, hence there is a potential null pointer dereference on udc->lock. Fix this by moving the null check on udc before the lock occurs. Fixes: ea6873a45a22 ("usbip: vudc: Add SysFS infrastructure for VUDC") Signed-off-by: Colin Ian King Acked-by: Shuah Khan Reviewed-by: Krzysztof Opasiak Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usbip/vudc_sysfs.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/usbip/vudc_sysfs.c b/drivers/usb/usbip/vudc_sysfs.c index 0f98f2c7475f..7efa374a4970 100644 --- a/drivers/usb/usbip/vudc_sysfs.c +++ b/drivers/usb/usbip/vudc_sysfs.c @@ -117,10 +117,14 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, if (rv != 0) return -EINVAL; + if (!udc) { + dev_err(dev, "no device"); + return -ENODEV; + } spin_lock_irqsave(&udc->lock, flags); /* Don't export what we don't have */ - if (!udc || !udc->driver || !udc->pullup) { - dev_err(dev, "no device or gadget not bound"); + if (!udc->driver || !udc->pullup) { + dev_err(dev, "gadget not bound"); ret = -ENODEV; goto unlock; } -- GitLab From b2708e1e30e02ef4170266d20d90774cce4419e8 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Tue, 6 Mar 2018 09:38:49 +0100 Subject: [PATCH 0334/1834] usb: quirks: add control message delay for 1b1c:1b20 commit cb88a0588717ba6c756cb5972d75766b273a6817 upstream. Corsair Strafe RGB keyboard does not respond to usb control messages sometimes and hence generates timeouts. Commit de3af5bf259d ("usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard") tried to fix those timeouts by adding USB_QUIRK_DELAY_INIT. Unfortunately, even with this quirk timeouts of usb_control_msg() can still be seen, but with a lower frequency (approx. 1 out of 15): [ 29.103520] usb 1-8: string descriptor 0 read error: -110 [ 34.363097] usb 1-8: can't set config #1, error -110 Adding further delays to different locations where usb control messages are issued just moves the timeouts to other locations, e.g.: [ 35.400533] usbhid 1-8:1.0: can't add hid device: -110 [ 35.401014] usbhid: probe of 1-8:1.0 failed with error -110 The only way to reliably avoid those issues is having a pause after each usb control message. In approx. 200 boot cycles no more timeouts were seen. Addionaly, keep USB_QUIRK_DELAY_INIT as it turned out to be necessary to have the delay in hub_port_connect() after hub_port_init(). The overall boot time seems not to be influenced by these additional delays, even on fast machines and lightweight distributions. Fixes: de3af5bf259d ("usb: quirks: add delay init quirk for Corsair Strafe RGB keyboard") Cc: stable@vger.kernel.org Signed-off-by: Danilo Krummrich Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/message.c | 4 ++++ drivers/usb/core/quirks.c | 3 ++- include/linux/usb/quirks.h | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 4c388451f31f..9cb66475c211 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -148,6 +148,10 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout); + /* Linger a bit, prior to the next control message. */ + if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG) + msleep(200); + kfree(dr); return ret; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 774c97bb1c08..4f1c6f8d4352 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -229,7 +229,8 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x1b1c, 0x1b13), .driver_info = USB_QUIRK_DELAY_INIT }, /* Corsair Strafe RGB */ - { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT | + USB_QUIRK_DELAY_CTRL_MSG }, /* Corsair K70 LUX */ { USB_DEVICE(0x1b1c, 0x1b36), .driver_info = USB_QUIRK_DELAY_INIT }, diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index de2a722fe3cf..ea4f81c2a6d5 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -56,4 +56,7 @@ */ #define USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL BIT(11) +/* Device needs a pause after every control message. */ +#define USB_QUIRK_DELAY_CTRL_MSG BIT(13) + #endif /* __LINUX_USB_QUIRKS_H */ -- GitLab From 63f3bac3bedcf415d789ff3ae8fb1361e4ab104e Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Fri, 9 Mar 2018 00:21:14 -0600 Subject: [PATCH 0335/1834] usb: usbmon: Read text within supplied buffer size commit a5f596830e27e15f7a0ecd6be55e433d776986d8 upstream. This change fixes buffer overflows and silent data corruption with the usbmon device driver text file read operations. Signed-off-by: Fredrik Noring Signed-off-by: Pete Zaitcev Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/mon/mon_text.c | 126 +++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 48 deletions(-) diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index e59334b09c41..f8ac59e0158d 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -83,6 +83,8 @@ struct mon_reader_text { wait_queue_head_t wait; int printf_size; + size_t printf_offset; + size_t printf_togo; char *printf_buf; struct mutex printf_lock; @@ -374,75 +376,103 @@ static int mon_text_open(struct inode *inode, struct file *file) return rc; } -/* - * For simplicity, we read one record in one system call and throw out - * what does not fit. This means that the following does not work: - * dd if=/dbg/usbmon/0t bs=10 - * Also, we do not allow seeks and do not bother advancing the offset. - */ +static ssize_t mon_text_copy_to_user(struct mon_reader_text *rp, + char __user * const buf, const size_t nbytes) +{ + const size_t togo = min(nbytes, rp->printf_togo); + + if (copy_to_user(buf, &rp->printf_buf[rp->printf_offset], togo)) + return -EFAULT; + rp->printf_togo -= togo; + rp->printf_offset += togo; + return togo; +} + +/* ppos is not advanced since the llseek operation is not permitted. */ static ssize_t mon_text_read_t(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) + size_t nbytes, loff_t *ppos) { struct mon_reader_text *rp = file->private_data; struct mon_event_text *ep; struct mon_text_ptr ptr; + ssize_t ret; - ep = mon_text_read_wait(rp, file); - if (IS_ERR(ep)) - return PTR_ERR(ep); mutex_lock(&rp->printf_lock); - ptr.cnt = 0; - ptr.pbuf = rp->printf_buf; - ptr.limit = rp->printf_size; - - mon_text_read_head_t(rp, &ptr, ep); - mon_text_read_statset(rp, &ptr, ep); - ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, - " %d", ep->length); - mon_text_read_data(rp, &ptr, ep); - - if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) - ptr.cnt = -EFAULT; + + if (rp->printf_togo == 0) { + + ep = mon_text_read_wait(rp, file); + if (IS_ERR(ep)) { + mutex_unlock(&rp->printf_lock); + return PTR_ERR(ep); + } + ptr.cnt = 0; + ptr.pbuf = rp->printf_buf; + ptr.limit = rp->printf_size; + + mon_text_read_head_t(rp, &ptr, ep); + mon_text_read_statset(rp, &ptr, ep); + ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, + " %d", ep->length); + mon_text_read_data(rp, &ptr, ep); + + rp->printf_togo = ptr.cnt; + rp->printf_offset = 0; + + kmem_cache_free(rp->e_slab, ep); + } + + ret = mon_text_copy_to_user(rp, buf, nbytes); mutex_unlock(&rp->printf_lock); - kmem_cache_free(rp->e_slab, ep); - return ptr.cnt; + return ret; } +/* ppos is not advanced since the llseek operation is not permitted. */ static ssize_t mon_text_read_u(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) + size_t nbytes, loff_t *ppos) { struct mon_reader_text *rp = file->private_data; struct mon_event_text *ep; struct mon_text_ptr ptr; + ssize_t ret; - ep = mon_text_read_wait(rp, file); - if (IS_ERR(ep)) - return PTR_ERR(ep); mutex_lock(&rp->printf_lock); - ptr.cnt = 0; - ptr.pbuf = rp->printf_buf; - ptr.limit = rp->printf_size; - mon_text_read_head_u(rp, &ptr, ep); - if (ep->type == 'E') { - mon_text_read_statset(rp, &ptr, ep); - } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { - mon_text_read_isostat(rp, &ptr, ep); - mon_text_read_isodesc(rp, &ptr, ep); - } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { - mon_text_read_intstat(rp, &ptr, ep); - } else { - mon_text_read_statset(rp, &ptr, ep); + if (rp->printf_togo == 0) { + + ep = mon_text_read_wait(rp, file); + if (IS_ERR(ep)) { + mutex_unlock(&rp->printf_lock); + return PTR_ERR(ep); + } + ptr.cnt = 0; + ptr.pbuf = rp->printf_buf; + ptr.limit = rp->printf_size; + + mon_text_read_head_u(rp, &ptr, ep); + if (ep->type == 'E') { + mon_text_read_statset(rp, &ptr, ep); + } else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) { + mon_text_read_isostat(rp, &ptr, ep); + mon_text_read_isodesc(rp, &ptr, ep); + } else if (ep->xfertype == USB_ENDPOINT_XFER_INT) { + mon_text_read_intstat(rp, &ptr, ep); + } else { + mon_text_read_statset(rp, &ptr, ep); + } + ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, + " %d", ep->length); + mon_text_read_data(rp, &ptr, ep); + + rp->printf_togo = ptr.cnt; + rp->printf_offset = 0; + + kmem_cache_free(rp->e_slab, ep); } - ptr.cnt += snprintf(ptr.pbuf + ptr.cnt, ptr.limit - ptr.cnt, - " %d", ep->length); - mon_text_read_data(rp, &ptr, ep); - if (copy_to_user(buf, rp->printf_buf, ptr.cnt)) - ptr.cnt = -EFAULT; + ret = mon_text_copy_to_user(rp, buf, nbytes); mutex_unlock(&rp->printf_lock); - kmem_cache_free(rp->e_slab, ep); - return ptr.cnt; + return ret; } static struct mon_event_text *mon_text_read_wait(struct mon_reader_text *rp, -- GitLab From dddf4650cf649d741a83d6cac148718171ab60d6 Mon Sep 17 00:00:00 2001 From: Xinyong Date: Fri, 2 Mar 2018 19:20:07 +0800 Subject: [PATCH 0336/1834] usb: gadget: f_fs: Fix use-after-free in ffs_fs_kill_sb() commit 1a087f032111a88e826877449dfb93ceb22b78b9 upstream. When I debug a kernel crash issue in funcitonfs, found ffs_data.ref overflowed, While functionfs is unmounting, ffs_data is put twice. Commit 43938613c6fd ("drivers, usb: convert ffs_data.ref from atomic_t to refcount_t") can avoid refcount overflow, but that is risk some situations. So no need put ffs data in ffs_fs_kill_sb, already put in ffs_data_closed. The issue can be reproduced in Mediatek mt6763 SoC, ffs for ADB device. KASAN enabled configuration reports use-after-free errro. BUG: KASAN: use-after-free in refcount_dec_and_test+0x14/0xe0 at addr ffffffc0579386a0 Read of size 4 by task umount/4650 ==================================================== BUG kmalloc-512 (Tainted: P W O ): kasan: bad access detected ----------------------------------------------------------------------------- INFO: Allocated in ffs_fs_mount+0x194/0x844 age=22856 cpu=2 pid=566 alloc_debug_processing+0x1ac/0x1e8 ___slab_alloc.constprop.63+0x640/0x648 __slab_alloc.isra.57.constprop.62+0x24/0x34 kmem_cache_alloc_trace+0x1a8/0x2bc ffs_fs_mount+0x194/0x844 mount_fs+0x6c/0x1d0 vfs_kern_mount+0x50/0x1b4 do_mount+0x258/0x1034 INFO: Freed in ffs_data_put+0x25c/0x320 age=0 cpu=3 pid=4650 free_debug_processing+0x22c/0x434 __slab_free+0x2d8/0x3a0 kfree+0x254/0x264 ffs_data_put+0x25c/0x320 ffs_data_closed+0x124/0x15c ffs_fs_kill_sb+0xb8/0x110 deactivate_locked_super+0x6c/0x98 deactivate_super+0xb0/0xbc INFO: Object 0xffffffc057938600 @offset=1536 fp=0x (null) ...... Call trace: [] dump_backtrace+0x0/0x250 [] show_stack+0x14/0x1c [] dump_stack+0xa0/0xc8 [] print_trailer+0x158/0x260 [] object_err+0x3c/0x40 [] kasan_report_error+0x2a8/0x754 [] kasan_report+0x5c/0x60 [] __asan_load4+0x70/0x88 [] refcount_dec_and_test+0x14/0xe0 [] ffs_data_put+0x80/0x320 [] ffs_fs_kill_sb+0xc8/0x110 [] deactivate_locked_super+0x6c/0x98 [] deactivate_super+0xb0/0xbc [] cleanup_mnt+0x64/0xec [] __cleanup_mnt+0x10/0x18 [] task_work_run+0xcc/0x124 [] do_notify_resume+0x60/0x70 [] work_pending+0x10/0x14 Cc: stable@vger.kernel.org Signed-off-by: Xinyong Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_fs.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 48f52138bb1a..071346973dd6 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1522,7 +1522,6 @@ ffs_fs_kill_sb(struct super_block *sb) if (sb->s_fs_info) { ffs_release_dev(sb->s_fs_info); ffs_data_closed(sb->s_fs_info); - ffs_data_put(sb->s_fs_info); } } -- GitLab From 46d16d6e758b3ff34ad8641e1b4e736ffd9a44ac Mon Sep 17 00:00:00 2001 From: Nikola Ciprich Date: Tue, 13 Feb 2018 15:04:46 +0100 Subject: [PATCH 0337/1834] serial: 8250_pci: Add Brainboxes UC-260 4 port serial device commit 9f2068f35729948bde84d87a40d135015911345d upstream. Add PCI ids for two variants of Brainboxes UC-260 quad port PCI serial cards. Suggested-by: Andy Shevchenko Signed-off-by: Nikola Ciprich Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index b80ea872b039..e82b3473b6b8 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -5099,6 +5099,17 @@ static struct pci_device_id serial_pci_tbl[] = { { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0dc0 */ pbn_b2_4_115200 }, + /* + * BrainBoxes UC-260 + */ + { PCI_VENDOR_ID_INTASHIELD, 0x0D21, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b2_4_115200 }, + { PCI_VENDOR_ID_INTASHIELD, 0x0E34, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, + pbn_b2_4_115200 }, /* * Perle PCI-RAS cards */ -- GitLab From fbe1ad9742d3e20e403fa09083d815e20fbf0e9b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Sat, 3 Feb 2018 12:27:23 +0100 Subject: [PATCH 0338/1834] serial: core: mark port as initialized in autoconfig commit 714569064adee3c114a2a6490735b94abe269068 upstream. This is a followup on 44117a1d1732 ("serial: core: mark port as initialized after successful IRQ change"). Nikola has been using autoconfig via setserial and reported a crash similar to what I fixed in the earlier mentioned commit. Here I do the same fixup for the autoconfig. I wasn't sure that this is the right approach. Nikola confirmed that it fixes his crash. Fixes: b3b576461864 ("tty: serial_core: convert uart_open to use tty_port_open") Link: http://lkml.kernel.org/r/20180131072000.GD1853@localhost.localdomain Reported-by: Nikola Ciprich Tested-by: Nikola Ciprich Cc: Signed-off-by: Sebastian Andrzej Siewior Tested-by: Nikola Ciprich Acked-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 23973a8124fc..6cbd46c565f8 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1135,6 +1135,8 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state) uport->ops->config_port(uport, flags); ret = uart_startup(tty, state, 1); + if (ret == 0) + tty_port_set_initialized(port, true); if (ret > 0) ret = 0; } -- GitLab From bd0d673023edfeaedf57b68e39e7795cdcee4e45 Mon Sep 17 00:00:00 2001 From: Greentime Hu Date: Tue, 13 Feb 2018 17:09:08 +0800 Subject: [PATCH 0339/1834] earlycon: add reg-offset to physical address before mapping commit 1f66dd36bb18437397ea0d7882c52f7e3c476e15 upstream. It will get the wrong virtual address because port->mapbase is not added the correct reg-offset yet. We have to update it before earlycon_map() is called Signed-off-by: Greentime Hu Acked-by: Arnd Bergmann Cc: Peter Hurley Cc: stable@vger.kernel.org Fixes: 088da2a17619 ("of: earlycon: Initialize port fields from DT properties") Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/earlycon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index c3651540e1ba..3b31fd8863eb 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -253,11 +253,12 @@ int __init of_setup_earlycon(const struct earlycon_id *match, } port->mapbase = addr; port->uartclk = BASE_BAUD * 16; - port->membase = earlycon_map(port->mapbase, SZ_4K); val = of_get_flat_dt_prop(node, "reg-offset", NULL); if (val) port->mapbase += be32_to_cpu(*val); + port->membase = earlycon_map(port->mapbase, SZ_4K); + val = of_get_flat_dt_prop(node, "reg-shift", NULL); if (val) port->regshift = be32_to_cpu(*val); -- GitLab From 0e2bc507f242e10c544243b53d8613133cd741d9 Mon Sep 17 00:00:00 2001 From: Koen Vandeputte Date: Wed, 7 Mar 2018 10:46:39 -0600 Subject: [PATCH 0340/1834] PCI: dwc: Fix enumeration end when reaching root subordinate commit fc110ebdd014dd1368c98e7685b47789c31fab42 upstream. The subordinate value indicates the highest bus number which can be reached downstream though a certain device. Commit a20c7f36bd3d ("PCI: Do not allocate more buses than available in parent") ensures that downstream devices cannot assign busnumbers higher than the upstream device subordinate number, which was indeed illogical. By default, dw_pcie_setup_rc() inits the Root Complex subordinate to a value of 0x01. Due to this combined with above commit, enumeration stops digging deeper downstream as soon as bus num 0x01 has been assigned, which is always the case for a bridge device. This results in all devices behind a bridge bus remaining undetected, as these would be connected to bus 0x02 or higher. Fix this by initializing the RC to a subordinate value of 0xff, which is not altering hardware behaviour in any way, but informs probing function pci_scan_bridge() later on which reads this value back from register. The following nasty errors during boot are also fixed by this: pci_bus 0000:02: busn_res: can not insert [bus 02-ff] under [bus 01] (conflicts with (null) [bus 01]) ... pci_bus 0000:03: [bus 03] partially hidden behind bridge 0000:01 [bus 01] ... pci_bus 0000:04: [bus 04] partially hidden behind bridge 0000:01 [bus 01] ... pci_bus 0000:05: [bus 05] partially hidden behind bridge 0000:01 [bus 01] pci_bus 0000:02: busn_res: [bus 02-ff] end is updated to 05 pci_bus 0000:02: busn_res: can not insert [bus 02-05] under [bus 01] (conflicts with (null) [bus 01]) pci_bus 0000:02: [bus 02-05] partially hidden behind bridge 0000:01 [bus 01] Fixes: a20c7f36bd3d ("PCI: Do not allocate more buses than available in parent") Tested-by: Niklas Cassel Tested-by: Fabio Estevam Tested-by: Sebastian Reichel Signed-off-by: Koen Vandeputte Signed-off-by: Lorenzo Pieralisi Signed-off-by: Bjorn Helgaas Reviewed-by: Mika Westerberg Acked-by: Lucas Stach Cc: stable@vger.kernel.org # v4.15+ Cc: Binghui Wang Cc: Jesper Nilsson Cc: Jianguo Sun Cc: Jingoo Han Cc: Kishon Vijay Abraham I Cc: Lucas Stach Cc: Mika Westerberg Cc: Minghuan Lian Cc: Mingkai Hu Cc: Murali Karicheri Cc: Pratyush Anand Cc: Richard Zhu Cc: Roy Zang Cc: Shawn Guo Cc: Stanimir Varbanov Cc: Thomas Petazzoni Cc: Xiaowei Song Cc: Zhou Wang [fabio: adapted to the file location of 4.9 kernel] Signed-off-by: Fabio Estevam Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pcie-designware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index af8f6e92e885..b3a87159e457 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -861,7 +861,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) /* setup bus numbers */ val = dw_pcie_readl_rc(pp, PCI_PRIMARY_BUS); val &= 0xff000000; - val |= 0x00010100; + val |= 0x00ff0100; dw_pcie_writel_rc(pp, PCI_PRIMARY_BUS, val); /* setup command register */ -- GitLab From 46e076f0dad02f5c445a5c27adbd3f06147e33ed Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 18 Mar 2018 11:18:56 +0100 Subject: [PATCH 0341/1834] Linux 4.9.88 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3043937a65d1..1512ebceffda 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 87 +SUBLEVEL = 88 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 71df7bbae4d8f500dffc855d064ce41c2408c52d Mon Sep 17 00:00:00 2001 From: Yisheng Xie Date: Wed, 28 Feb 2018 14:59:22 +0800 Subject: [PATCH 0342/1834] staging: android: ashmem: Fix possible deadlock in ashmem_ioctl ashmem_mutex may create a chain of dependencies like: CPU0 CPU1 mmap syscall ioctl syscall -> mmap_sem (acquired) -> ashmem_ioctl -> ashmem_mmap -> ashmem_mutex (acquired) -> ashmem_mutex (try to acquire) -> copy_from_user -> mmap_sem (try to acquire) There is a lock odering problem between mmap_sem and ashmem_mutex causing a lockdep splat[1] during a syzcaller test. This patch fixes the problem by move copy_from_user out of ashmem_mutex. [1] https://www.spinics.net/lists/kernel/msg2733200.html Fixes: ce8a3a9e76d0 (staging: android: ashmem: Fix a race condition in pin ioctls) Reported-by: syzbot+d7a918a7a8e1c952bc36@syzkaller.appspotmail.com Signed-off-by: Yisheng Xie Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 511eab8c466c..f4ffac437d93 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -710,16 +710,14 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, size_t pgstart, pgend; int ret = -EINVAL; + if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) + return -EFAULT; + mutex_lock(&ashmem_mutex); if (unlikely(!asma->file)) goto out_unlock; - if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) { - ret = -EFAULT; - goto out_unlock; - } - /* per custom, you can pass zero for len to mean "everything onward" */ if (!pin.len) pin.len = PAGE_ALIGN(asma->size) - pin.offset; -- GitLab From 7bd2d0c746f1fac2fb7f2ee972767cbc8be60962 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 3 Feb 2017 17:19:07 +0800 Subject: [PATCH 0343/1834] blkcg: fix double free of new_blkg in blkcg_init_queue commit 9b54d816e00425c3a517514e0d677bb3cec49258 upstream. If blkg_create fails, new_blkg passed as an argument will be freed by blkg_create, so there is no need to free it again. Signed-off-by: Hou Tao Signed-off-by: Jens Axboe Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- block/blk-cgroup.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index b08ccbb9393a..6cd839c1f507 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -1078,10 +1078,8 @@ int blkcg_init_queue(struct request_queue *q) if (preloaded) radix_tree_preload_end(); - if (IS_ERR(blkg)) { - blkg_free(new_blkg); + if (IS_ERR(blkg)) return PTR_ERR(blkg); - } q->root_blkg = blkg; q->root_rl.blkg = blkg; -- GitLab From 3ec4b846a5dda7fe983015e6310c3d551b029329 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Fri, 17 Feb 2017 12:51:19 -0800 Subject: [PATCH 0344/1834] Input: tsc2007 - check for presence and power down tsc2007 during probe [ Upstream commit 934df23171e7c5b71d937104d4957891c39748ff ] 1. check if chip is really present and don't succeed if it isn't. 2. if it succeeds, power down the chip until accessed Signed-off-by: H. Nikolaus Schaller Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/tsc2007.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 5d0cd51c6f41..a4b7b4c3d27b 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -455,6 +455,14 @@ static int tsc2007_probe(struct i2c_client *client, tsc2007_stop(ts); + /* power down the chip (TSC2007_SETUP does not ACK on I2C) */ + err = tsc2007_xfer(ts, PWRDOWN); + if (err < 0) { + dev_err(&client->dev, + "Failed to setup chip: %d\n", err); + return err; /* usually, chip does not respond */ + } + err = input_register_device(input_dev); if (err) { dev_err(&client->dev, -- GitLab From b0119cd440cbe54e82f2a1b2e62ba9b38231fe2f Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 7 Feb 2017 01:40:05 +0100 Subject: [PATCH 0345/1834] perf stat: Issue a HW watchdog disable hint [ Upstream commit 02d492e5dcb72c004d213756eb87c9d62a6d76a7 ] When using perf stat on an AMD F15h system with the default hw events attributes, some of the events don't get counted: Performance counter stats for 'sleep 1': 0.749208 task-clock (msec) # 0.001 CPUs utilized 1 context-switches # 0.001 M/sec 0 cpu-migrations # 0.000 K/sec 54 page-faults # 0.072 M/sec 1,122,815 cycles # 1.499 GHz 286,740 stalled-cycles-frontend # 25.54% frontend cycles idle stalled-cycles-backend (0.00%) ^^^^^^^^^^^^ instructions (0.00%) ^^^^^^^^^^^^ branches (0.00%) branch-misses (0.00%) 1.001550070 seconds time elapsed The reason is that we have the HW watchdog consuming one PMU counter and when perf tries to schedule 6 events on 6 counters and some of those counters are constrained to only a specific subset of PMCs by the hardware, the event scheduling fails. So issue a hint to disable the HW watchdog around a perf stat session. Committer note: Testing it... # perf stat -d usleep 1 Performance counter stats for 'usleep 1': 1.180203 task-clock (msec) # 0.490 CPUs utilized 1 context-switches # 0.847 K/sec 0 cpu-migrations # 0.000 K/sec 54 page-faults # 0.046 M/sec 184,754 cycles # 0.157 GHz 714,553 instructions # 3.87 insn per cycle 154,661 branches # 131.046 M/sec 7,247 branch-misses # 4.69% of all branches 219,984 L1-dcache-loads # 186.395 M/sec 17,600 L1-dcache-load-misses # 8.00% of all L1-dcache hits (90.16%) LLC-loads (0.00%) LLC-load-misses (0.00%) 0.002406823 seconds time elapsed Some events weren't counted. Try disabling the NMI watchdog: echo 0 > /proc/sys/kernel/nmi_watchdog perf stat ... echo 1 > /proc/sys/kernel/nmi_watchdog # Signed-off-by: Borislav Petkov Acked-by: Ingo Molnar Tested-by: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Robert Richter Cc: Vince Weaver Link: http://lkml.kernel.org/r/20170211183218.ijnvb5f7ciyuunx4@pd.tnic Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-stat.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 688dea7cb08f..c241167c76c9 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -146,6 +146,7 @@ static aggr_get_id_t aggr_get_id; static bool append_file; static const char *output_name; static int output_fd; +static int print_free_counters_hint; struct perf_stat { bool record; @@ -1109,6 +1110,9 @@ static void printout(int id, int nr, struct perf_evsel *counter, double uval, counter->supported ? CNTR_NOT_COUNTED : CNTR_NOT_SUPPORTED, csv_sep); + if (counter->supported) + print_free_counters_hint = 1; + fprintf(stat_config.output, "%-*s%s", csv_output ? 0 : unit_width, counter->unit, csv_sep); @@ -1477,6 +1481,13 @@ static void print_footer(void) avg_stats(&walltime_nsecs_stats)); } fprintf(output, "\n\n"); + + if (print_free_counters_hint) + fprintf(output, +"Some events weren't counted. Try disabling the NMI watchdog:\n" +" echo 0 > /proc/sys/kernel/nmi_watchdog\n" +" perf stat ...\n" +" echo 1 > /proc/sys/kernel/nmi_watchdog\n"); } static void print_counters(struct timespec *ts, int argc, const char **argv) -- GitLab From 74cf9ab7d1de72a022519991a9b27ea1510c4c9f Mon Sep 17 00:00:00 2001 From: Varsha Rao Date: Sat, 25 Feb 2017 17:53:58 +0530 Subject: [PATCH 0346/1834] staging: speakup: Replace BUG_ON() with WARN_ON(). [ Upstream commit d351c2db5420bb17dcd2d9aac7ddb5f64c6d04b3 ] BUG_ON() is replaced with WARN_ON() and EINVAL is returned, when WARN_ON() is true. This fixes the following checkpatch issue: Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON(). Signed-off-by: Varsha Rao Reviewed-by: Samuel Thibault Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/kobjects.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c index e744aa9730ff..dea018cba094 100644 --- a/drivers/staging/speakup/kobjects.c +++ b/drivers/staging/speakup/kobjects.c @@ -834,7 +834,9 @@ static ssize_t message_show(struct kobject *kobj, struct msg_group_t *group = spk_find_msg_group(attr->attr.name); unsigned long flags; - BUG_ON(!group); + if (WARN_ON(!group)) + return -EINVAL; + spin_lock_irqsave(&speakup_info.spinlock, flags); retval = message_show_helper(buf, group->start, group->end); spin_unlock_irqrestore(&speakup_info.spinlock, flags); @@ -846,7 +848,9 @@ static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr, { struct msg_group_t *group = spk_find_msg_group(attr->attr.name); - BUG_ON(!group); + if (WARN_ON(!group)) + return -EINVAL; + return message_store_helper(buf, count, group); } -- GitLab From 8f6cd2d0c0f37b272833d88604ce7f82fd05b167 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 28 Feb 2017 11:47:33 +0000 Subject: [PATCH 0347/1834] staging: wilc1000: add check for kmalloc allocation failure. [ Upstream commit 6cc0c259d034c6ab48f4e12f505213988e73d380 ] Add a sanity check that wid.val has been allocated, fixes a null pointer deference on stamac when calling ether_add_copy. Detected by CoverityScan, CID#1369537 ("Dereference null return value") Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/host_interface.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/wilc1000/host_interface.c b/drivers/staging/wilc1000/host_interface.c index 6ab7443eabde..6326375b76ab 100644 --- a/drivers/staging/wilc1000/host_interface.c +++ b/drivers/staging/wilc1000/host_interface.c @@ -1930,6 +1930,8 @@ static s32 Handle_Get_InActiveTime(struct wilc_vif *vif, wid.type = WID_STR; wid.size = ETH_ALEN; wid.val = kmalloc(wid.size, GFP_KERNEL); + if (!wid.val) + return -ENOMEM; stamac = wid.val; memcpy(stamac, strHostIfStaInactiveT->mac, ETH_ALEN); -- GitLab From 953468bda711fe7ab68235a9a4ae3ca67698736f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Valtteri=20Heikkil=C3=A4?= Date: Tue, 14 Feb 2017 23:14:32 +0000 Subject: [PATCH 0348/1834] HID: reject input outside logical range only if null state is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3f3752705dbd50b66b66ad7b4d54fe33d2f746ed ] This patch fixes an issue in drivers/hid/hid-input.c where USB HID control null state flag is not checked upon rejecting inputs outside logical minimum-maximum range. The check should be made according to USB HID specification 1.11, section 6.2.2.5, p.31. The fix will resolve issues with some game controllers, such as: https://bugzilla.kernel.org/show_bug.cgi?id=68621 [tk@the-tk.com: shortened and fixed spelling in commit message] Signed-off-by: Valtteri Heikkilä Signed-off-by: Tomasz Kramkowski Acked-By: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index fb9ace1cef8b..76f2527fbc60 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1156,6 +1156,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct * don't specify logical min and max. */ if ((field->flags & HID_MAIN_ITEM_VARIABLE) && + (field->flags & HID_MAIN_ITEM_NULL_STATE) && (field->logical_minimum < field->logical_maximum) && (value < field->logical_minimum || value > field->logical_maximum)) { -- GitLab From 23c475fa7124f1174d417cd378e6b4d363856081 Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Mon, 27 Feb 2017 17:33:30 -0300 Subject: [PATCH 0349/1834] drm: qxl: Don't alloc fbdev if emulation is not supported [ Upstream commit 861078381ba56b56808113736000d9e7ead349c8 ] If fbdev emulation is disabled, the QXL shutdown path will try to clean a framebuffer that wasn't initialized, hitting the Oops below. The problem is that even when FBDEV_EMULATION is disabled we allocate the qfbdev strutucture, but we don't initialize it. The fix is to stop allocating the memory, since it won't be used. This allows the existing verification in the cleanup hook to do it's job preventing the oops. Now that we don't allocate the unused fbdev structure, we need to be careful when dereferencing it in the PM suspend hook. [ 24.284684] BUG: unable to handle kernel NULL pointer dereference at 00000000000002e0 [ 24.285627] IP: mutex_lock+0x18/0x30 [ 24.286049] PGD 78cdf067 [ 24.286050] PUD 7940f067 [ 24.286344] PMD 0 [ 24.286649] [ 24.287072] Oops: 0002 [#1] SMP [ 24.287422] Modules linked in: qxl [ 24.287806] CPU: 0 PID: 2328 Comm: bash Not tainted 4.10.0-rc5+ #97 [ 24.288515] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.9.3-20161025_171302-gandalf 04/01/2014 [ 24.289681] task: ffff88007c4c0000 task.stack: ffffc90001b58000 [ 24.290354] RIP: 0010:mutex_lock+0x18/0x30 [ 24.290812] RSP: 0018:ffffc90001b5bcb0 EFLAGS: 00010246 [ 24.291401] RAX: 0000000000000000 RBX: 00000000000002e0 RCX: 0000000000000000 [ 24.292209] RDX: ffff88007c4c0000 RSI: 0000000000000001 RDI: 00000000000002e0 [ 24.292987] RBP: ffffc90001b5bcb8 R08: fffffffffffffffe R09: 0000000000000001 [ 24.293797] R10: ffff880078d80b80 R11: 0000000000011400 R12: 0000000000000000 [ 24.294601] R13: 00000000000002e0 R14: ffffffffa0009c28 R15: 0000000000000060 [ 24.295439] FS: 00007f30e3acbb40(0000) GS:ffff88007fc00000(0000) knlGS:0000000000000000 [ 24.296364] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 24.296997] CR2: 00000000000002e0 CR3: 0000000078c7b000 CR4: 00000000000006f0 [ 24.297813] Call Trace: [ 24.298097] drm_framebuffer_cleanup+0x1f/0x70 [ 24.298612] qxl_fbdev_fini+0x68/0x90 [qxl] [ 24.299074] qxl_modeset_fini+0xd/0x30 [qxl] [ 24.299562] qxl_pci_remove+0x22/0x50 [qxl] [ 24.300025] pci_device_remove+0x34/0xb0 [ 24.300507] device_release_driver_internal+0x150/0x200 [ 24.301082] device_release_driver+0xd/0x10 [ 24.301587] unbind_store+0x108/0x150 [ 24.301993] drv_attr_store+0x20/0x30 [ 24.302402] sysfs_kf_write+0x32/0x40 [ 24.302827] kernfs_fop_write+0x108/0x190 [ 24.303269] __vfs_write+0x23/0x120 [ 24.303678] ? security_file_permission+0x36/0xb0 [ 24.304193] ? rw_verify_area+0x49/0xb0 [ 24.304636] vfs_write+0xb0/0x190 [ 24.305004] SyS_write+0x41/0xa0 [ 24.305362] entry_SYSCALL_64_fastpath+0x1a/0xa9 [ 24.305887] RIP: 0033:0x7f30e31d9620 [ 24.306285] RSP: 002b:00007ffc54b47e68 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 [ 24.307128] RAX: ffffffffffffffda RBX: 00007f30e3497600 RCX: 00007f30e31d9620 [ 24.307928] RDX: 000000000000000d RSI: 0000000000da2008 RDI: 0000000000000001 [ 24.308727] RBP: 000000000070bc60 R08: 00007f30e3498760 R09: 00007f30e3acbb40 [ 24.309504] R10: 0000000000000073 R11: 0000000000000246 R12: 0000000000000001 [ 24.310295] R13: 0000000000000000 R14: 0000000000000000 R15: 00007ffc54b47f34 [ 24.311095] Code: 0e 01 e9 7b fe ff ff 66 90 66 2e 0f 1f 84 00 00 00 00 00 55 48 89 e5 53 48 89 fb e8 83 e8 ff ff 65 48 8b 14 25 40 c4 00 00 31 c0 <3e> 48 0f b1 13 48 85 c0 74 08 48 89 df e8 66 fd ff ff 5b 5d c3 [ 24.313182] RIP: mutex_lock+0x18/0x30 RSP: ffffc90001b5bcb0 [ 24.313811] CR2: 00000000000002e0 [ 24.314208] ---[ end trace 29669c1593cae14b ]--- Signed-off-by: Gabriel Krisman Bertazi Link: http://patchwork.freedesktop.org/patch/msgid/20170227203330.18542-1-krisman@collabora.co.uk Signed-off-by: Gerd Hoffmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/qxl/qxl_fb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index 2cd879a4ae15..cdbb6e625f05 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -387,9 +387,11 @@ static const struct drm_fb_helper_funcs qxl_fb_helper_funcs = { int qxl_fbdev_init(struct qxl_device *qdev) { + int ret = 0; + +#ifdef CONFIG_DRM_FBDEV_EMULATION struct qxl_fbdev *qfbdev; int bpp_sel = 32; /* TODO: parameter from somewhere? */ - int ret; qfbdev = kzalloc(sizeof(struct qxl_fbdev), GFP_KERNEL); if (!qfbdev) @@ -423,6 +425,8 @@ int qxl_fbdev_init(struct qxl_device *qdev) drm_fb_helper_fini(&qfbdev->helper); free: kfree(qfbdev); +#endif + return ret; } @@ -438,6 +442,9 @@ void qxl_fbdev_fini(struct qxl_device *qdev) void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state) { + if (!qdev->mode_info.qfbdev) + return; + drm_fb_helper_set_suspend(&qdev->mode_info.qfbdev->helper, state); } -- GitLab From 88787c040211d0a809c71c444e05208d825ad614 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Mar 2017 17:40:40 +0100 Subject: [PATCH 0350/1834] ARM: dts: r8a7791: Remove unit-address and reg from integrated cache [ Upstream commit 5d6a2165abd4635ecf5ece3d02fe8677f00d32c5 ] The Cortex-A15 cache controller is an integrated controller, and thus the device node representing it should not have a unit-addresses or reg property. Fixes: 6f9314ce258c8504 ("ARM: dts: r8a7791: Fix W=1 dtc warnings") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7791.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 162b55c665a3..64749080e639 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -74,9 +74,8 @@ next-level-cache = <&L2_CA15>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7791_PD_CA15_SCU>; cache-unified; cache-level = <2>; -- GitLab From ba2f98696ad210f01d86751f3b3898c062d44d8a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Mar 2017 17:40:41 +0100 Subject: [PATCH 0351/1834] ARM: dts: r8a7792: Remove unit-address and reg from integrated cache [ Upstream commit a0504f0880c11da301dc2b5a5135bd02376e367e ] The Cortex-A15 cache controller is an integrated controller, and thus the device node representing it should not have a unit-addresses or reg property. Fixes: 7c4163aae3d8e5b9 ("ARM: dts: r8a7792: initial SoC device tree") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7792.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/r8a7792.dtsi b/arch/arm/boot/dts/r8a7792.dtsi index 713141d38b3e..0b50c6766867 100644 --- a/arch/arm/boot/dts/r8a7792.dtsi +++ b/arch/arm/boot/dts/r8a7792.dtsi @@ -58,9 +58,8 @@ next-level-cache = <&L2_CA15>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; cache-unified; cache-level = <2>; power-domains = <&sysc R8A7792_PD_CA15_SCU>; -- GitLab From c62dc6051d854d99202d2fdced543e8706a6c219 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Mar 2017 17:40:42 +0100 Subject: [PATCH 0352/1834] ARM: dts: r8a7793: Remove unit-address and reg from integrated cache [ Upstream commit beffa8872a3680ef804eb0320ec77037170f4686 ] The Cortex-A15 cache controller is an integrated controller, and thus the device node representing it should not have a unit-addresses or reg property. Fixes: ad53f5f00b095a0d ("ARM: dts: r8a7793: Fix W=1 dtc warnings") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7793.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi index 8d02aacf2892..bd7ee309f509 100644 --- a/arch/arm/boot/dts/r8a7793.dtsi +++ b/arch/arm/boot/dts/r8a7793.dtsi @@ -65,9 +65,8 @@ power-domains = <&sysc R8A7793_PD_CA15_CPU1>; }; - L2_CA15: cache-controller@0 { + L2_CA15: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7793_PD_CA15_SCU>; cache-unified; cache-level = <2>; -- GitLab From b54a9bb7efdf146aa8a643f3ac40784394198333 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 6 Mar 2017 17:40:43 +0100 Subject: [PATCH 0353/1834] ARM: dts: r8a7794: Remove unit-address and reg from integrated cache [ Upstream commit 65d0b7ed40f8a3a41a0ac5ed5ca4d1874c6aaf2d ] The Cortex-A7 cache controller is an integrated controller, and thus the device node representing it should not have a unit-addresses or reg property. Fixes: 34ea4b4a827b4ee7 ("ARM: dts: r8a7794: Fix W=1 dtc warnings") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7794.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi index 7e860d3737ff..6c0150dcf146 100644 --- a/arch/arm/boot/dts/r8a7794.dtsi +++ b/arch/arm/boot/dts/r8a7794.dtsi @@ -56,9 +56,8 @@ next-level-cache = <&L2_CA7>; }; - L2_CA7: cache-controller@0 { + L2_CA7: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7794_PD_CA7_SCU>; cache-unified; cache-level = <2>; -- GitLab From 3aa10f5387fa55a94f312524e11e05d972ad06cd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 3 Mar 2017 14:18:17 +0100 Subject: [PATCH 0354/1834] arm64: dts: r8a7796: Remove unit-address and reg from integrated cache [ Upstream commit 57a4fd420c6e8a04b6a87ff24d34250cd7c48f15 ] The Cortex-A57 cache controller is an integrated controller, and thus the device node representing it should not have a unit-addresses or reg property. Fixes: 1561f20760ec96db ("arm64: dts: r8a7796: Add Renesas R8A7796 SoC support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/boot/dts/renesas/r8a7796.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/renesas/r8a7796.dtsi b/arch/arm64/boot/dts/renesas/r8a7796.dtsi index 9217da983525..53d03cb144e4 100644 --- a/arch/arm64/boot/dts/renesas/r8a7796.dtsi +++ b/arch/arm64/boot/dts/renesas/r8a7796.dtsi @@ -36,9 +36,8 @@ enable-method = "psci"; }; - L2_CA57: cache-controller@0 { + L2_CA57: cache-controller-0 { compatible = "cache"; - reg = <0>; power-domains = <&sysc R8A7796_PD_CA57_SCU>; cache-unified; cache-level = <2>; -- GitLab From 7c4b9440c5c3490fb702ff3029f3e54ee9a2be91 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 17 Feb 2017 11:13:25 +0800 Subject: [PATCH 0355/1834] drm/sun4i: Fix up error path cleanup for master bind function [ Upstream commit 9d56defb44b15427f4342c543a70fb7886fc06f5 ] The master bind function calls numerous drm functions which initialize underlying structures. It also tries to bind the various components of the display pipeline, some of which may add additional drm objects. This patch adds proper cleanup functions in the error path of the master bind function. This requires the patch "drm/sun4i: Move drm_mode_config_cleanup call to main driver", which splits out drm_mode_config_cleanup from sun4i_framebuffer_free so we can call it separately. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/sun4i/sun4i_drv.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 1feec34ca9dd..9e77fc034e0a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -145,7 +145,7 @@ static int sun4i_drv_bind(struct device *dev) ret = component_bind_all(drm->dev, drm); if (ret) { dev_err(drm->dev, "Couldn't bind all pipelines components\n"); - goto free_drm; + goto cleanup_mode_config; } /* Create our layers */ @@ -153,7 +153,7 @@ static int sun4i_drv_bind(struct device *dev) if (IS_ERR(drv->layers)) { dev_err(drm->dev, "Couldn't create the planes\n"); ret = PTR_ERR(drv->layers); - goto free_drm; + goto cleanup_mode_config; } /* Create our CRTC */ @@ -161,7 +161,7 @@ static int sun4i_drv_bind(struct device *dev) if (!drv->crtc) { dev_err(drm->dev, "Couldn't create the CRTC\n"); ret = -EINVAL; - goto free_drm; + goto cleanup_mode_config; } drm->irq_enabled = true; @@ -173,7 +173,7 @@ static int sun4i_drv_bind(struct device *dev) if (IS_ERR(drv->fbdev)) { dev_err(drm->dev, "Couldn't create our framebuffer\n"); ret = PTR_ERR(drv->fbdev); - goto free_drm; + goto cleanup_mode_config; } /* Enable connectors polling */ @@ -181,10 +181,16 @@ static int sun4i_drv_bind(struct device *dev) ret = drm_dev_register(drm, 0); if (ret) - goto free_drm; + goto finish_poll; return 0; +finish_poll: + drm_kms_helper_poll_fini(drm); + sun4i_framebuffer_free(drm); +cleanup_mode_config: + drm_mode_config_cleanup(drm); + drm_vblank_cleanup(drm); free_drm: drm_dev_unref(drm); return ret; -- GitLab From c1315eea94ea76395918d6f5e9285de82ca023f7 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 23 Feb 2017 16:05:34 +0800 Subject: [PATCH 0356/1834] drm/sun4i: Set drm_crtc.port to the underlying TCON's output port node [ Upstream commit 7544860733d158e3edbf309f27e79e258c8f66bd ] The way drm_of_find_possible_crtcs works is it tries to match the remote-endpoint of the given node's various endpoints to all the crtc's .port field. Thus we need to set drm_crtc.port to the output port node of the underlying TCON. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/sun4i/sun4i_crtc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 4a192210574f..caba0311c86c 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -136,5 +137,9 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm) drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs); + /* Set crtc.port to output port node of the tcon */ + scrtc->crtc.port = of_graph_get_port_by_id(drv->tcon->dev->of_node, + 1); + return scrtc; } -- GitLab From 5d2db0dbb1939cbd08c02e225795459fdfccc948 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 8 Mar 2017 13:52:06 +0200 Subject: [PATCH 0357/1834] ath10k: fix a warning during channel switch with multiple vaps [ Upstream commit c73f8c00330f59ce9b1ace9ff698aca83390d358 ] Doing a channel switch via hostapd_cli seems to update the new channel context for each VAP's appropriately as below in 'ath10k_mac_update_vif_chan', hence we can safely suppress the warning that shows up during this operation and dump the warning only if no vaps are available for channel switch hostapd_cli -i wlan0 chan_switch 5 5200 OK ath10k_pci : mac chanctx switch n_vifs 3 mode 1 ath10k_pci : mac chanctx switch vdev_id 2 freq 5180->5200 width 0->0 ath10k_pci : mac chanctx switch vdev_id 1 freq 5180->5200 width 0->0 ath10k_pci : mac chanctx switch vdev_id 0 freq 5180->5200 width 0->0 Call Trace: WARNING: backports-20161201-3.14.77-9ab3068/drivers/net/wireless/ath/ath10k/mac.c:7126 [] (warn_slowpath_null) from [] (ath10k_reconfig_complete+0xe4/0x25c [ath10k_core]) [] (ath10k_reconfig_complete [ath10k_core]) [] (ath10k_mac_vif_ap_csa_work+0x214/0x370 [ath10k_core]) [] (ath10k_mac_op_change_chanctx+0x108/0x128 [ath10k_core]) [] (ieee80211_recalc_chanctx_min_def+0x30c/0x430 [mac80211]) [] (ieee80211_recalc_smps_chanctx+0x2ec/0x840 [mac80211]) [] (ieee80211_vif_use_reserved_context+0x7c/0xf8 [mac80211]) [] (ieee80211_vif_use_reserved_context [mac80211]) [] (ieee80211_csa_finalize_work+0x5c/0x88 [mac80211]) Fixes: d7bf4b4aba05 ("ath10k: fix ar->rx_channel updating logic") Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 17ab8efdac35..696b90270615 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -7070,7 +7070,7 @@ ath10k_mac_update_rx_channel(struct ath10k *ar, lockdep_assert_held(&ar->data_lock); WARN_ON(ctx && vifs); - WARN_ON(vifs && n_vifs != 1); + WARN_ON(vifs && !n_vifs); /* FIXME: Sort of an optimization and a workaround. Peers and vifs are * on a linked list now. Doing a lookup peer -> vif -> chanctx for each -- GitLab From 4d2c5e9a5a4d64d416ff30a0f29994b6341b22b6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 9 Mar 2017 18:05:24 +0800 Subject: [PATCH 0358/1834] drm/sun4i: Fix TCON clock and regmap initialization sequence [ Upstream commit 4c7f16d14a33a9cfb4af9cb780d8a73bcca64a92 ] The TCON driver calls sun4i_tcon_init_regmap and sun4i_tcon_init_clocks in its bind function. The former creates a regmap and writes to several register to clear its configuration to a known default. The latter initializes various clocks. This includes enabling the bus clock for register access and creating the dotclock. In order for the first step's writes to work, the bus clock must be enabled which is done in the second step. but the dotclock's ops use the regmap created in the first step. Rearrange the function calls such that the clocks are initialized before the regmap, and split out the dot clock creation to after the regmap is initialized. Fixes: 9026e0d122ac ("drm: Add Allwinner A10 Display Engine support") Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index c6afb2448655..f2975a1525be 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -336,12 +336,11 @@ static int sun4i_tcon_init_clocks(struct device *dev, } } - return sun4i_dclk_create(dev, tcon); + return 0; } static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon) { - sun4i_dclk_free(tcon); clk_disable_unprepare(tcon->clk); } @@ -506,22 +505,28 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return ret; } + ret = sun4i_tcon_init_clocks(dev, tcon); + if (ret) { + dev_err(dev, "Couldn't init our TCON clocks\n"); + goto err_assert_reset; + } + ret = sun4i_tcon_init_regmap(dev, tcon); if (ret) { dev_err(dev, "Couldn't init our TCON regmap\n"); - goto err_assert_reset; + goto err_free_clocks; } - ret = sun4i_tcon_init_clocks(dev, tcon); + ret = sun4i_dclk_create(dev, tcon); if (ret) { - dev_err(dev, "Couldn't init our TCON clocks\n"); - goto err_assert_reset; + dev_err(dev, "Couldn't create our TCON dot clock\n"); + goto err_free_clocks; } ret = sun4i_tcon_init_irq(dev, tcon); if (ret) { dev_err(dev, "Couldn't init our TCON interrupts\n"); - goto err_free_clocks; + goto err_free_dotclock; } ret = sun4i_rgb_init(drm); @@ -530,6 +535,8 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, return 0; +err_free_dotclock: + sun4i_dclk_free(tcon); err_free_clocks: sun4i_tcon_free_clocks(tcon); err_assert_reset: @@ -542,6 +549,7 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master, { struct sun4i_tcon *tcon = dev_get_drvdata(dev); + sun4i_dclk_free(tcon); sun4i_tcon_free_clocks(tcon); } -- GitLab From bae359c00b391644ebf813ee3dfb17549e09b5ef Mon Sep 17 00:00:00 2001 From: Prarit Bhargava Date: Thu, 26 Jan 2017 14:07:47 -0500 Subject: [PATCH 0359/1834] PCI/MSI: Stop disabling MSI/MSI-X in pci_device_shutdown() [ Upstream commit fda78d7a0ead144f4b2cdb582dcba47911f4952c ] The pci_bus_type .shutdown method, pci_device_shutdown(), is called from device_shutdown() in the kernel restart and shutdown paths. Previously, pci_device_shutdown() called pci_msi_shutdown() and pci_msix_shutdown(). This disables MSI and MSI-X, which causes the device to fall back to raising interrupts via INTx. But the driver is still bound to the device, it doesn't know about this change, and it likely doesn't have an INTx handler, so these INTx interrupts cause "nobody cared" warnings like this: irq 16: nobody cared (try booting with the "irqpoll" option) CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.8.2-1.el7_UNSUPPORTED.x86_64 #1 Hardware name: Hewlett-Packard HP Z820 Workstation/158B, BIOS J63 v03.90 06/ ... The MSI disabling code was added by d52877c7b1af ("pci/irq: let pci_device_shutdown to call pci_msi_shutdown v2") because a driver left MSI enabled and kdump failed because the kexeced kernel wasn't prepared to receive the MSI interrupts. Subsequent commits 1851617cd2da ("PCI/MSI: Disable MSI at enumeration even if kernel doesn't support MSI") and e80e7edc55ba ("PCI/MSI: Initialize MSI capability for all architectures") changed the kexeced kernel to disable all MSIs itself so it no longer depends on the crashed kernel to clean up after itself. Stop disabling MSI/MSI-X in pci_device_shutdown(). This resolves the "nobody cared" unhandled IRQ issue above. It also allows PCI serial devices, which may rely on the MSI interrupts, to continue outputting messages during reboot/shutdown. [bhelgaas: changelog, drop pci_msi_shutdown() and pci_msix_shutdown() calls altogether] Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=187351 Signed-off-by: Prarit Bhargava Signed-off-by: Bjorn Helgaas CC: Alex Williamson CC: David Arcari CC: Myron Stowe CC: Lukas Wunner CC: Keith Busch CC: Mika Westerberg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 802997e2ddcc..d81ad841dc0c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -463,8 +463,6 @@ static void pci_device_shutdown(struct device *dev) if (drv && drv->shutdown) drv->shutdown(pci_dev); - pci_msi_shutdown(pci_dev); - pci_msix_shutdown(pci_dev); /* * If this is a kexec reboot, turn off Bus Master bit on the -- GitLab From b243aa88a72263289f962844e8665157a53669d1 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 6 Mar 2017 19:46:14 +0100 Subject: [PATCH 0360/1834] selinux: check for address length in selinux_socket_bind() [ Upstream commit e2f586bd83177d22072b275edd4b8b872daba924 ] KMSAN (KernelMemorySanitizer, a new error detection tool) reports use of uninitialized memory in selinux_socket_bind(): ================================================================== BUG: KMSAN: use of unitialized memory inter: 0 CPU: 3 PID: 1074 Comm: packet2 Tainted: G B 4.8.0-rc6+ #1916 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 0000000000000000 ffff8800882ffb08 ffffffff825759c8 ffff8800882ffa48 ffffffff818bf551 ffffffff85bab870 0000000000000092 ffffffff85bab550 0000000000000000 0000000000000092 00000000bb0009bb 0000000000000002 Call Trace: [< inline >] __dump_stack lib/dump_stack.c:15 [] dump_stack+0x238/0x290 lib/dump_stack.c:51 [] kmsan_report+0x276/0x2e0 mm/kmsan/kmsan.c:1008 [] __msan_warning+0x5b/0xb0 mm/kmsan/kmsan_instr.c:424 [] selinux_socket_bind+0xf41/0x1080 security/selinux/hooks.c:4288 [] security_socket_bind+0x1ec/0x240 security/security.c:1240 [] SYSC_bind+0x358/0x5f0 net/socket.c:1366 [] SyS_bind+0x82/0xa0 net/socket.c:1356 [] do_syscall_64+0x58/0x70 arch/x86/entry/common.c:292 [] entry_SYSCALL64_slow_path+0x25/0x25 arch/x86/entry/entry_64.o:? chained origin: 00000000ba6009bb [] save_stack_trace+0x27/0x50 arch/x86/kernel/stacktrace.c:67 [< inline >] kmsan_save_stack_with_flags mm/kmsan/kmsan.c:322 [< inline >] kmsan_save_stack mm/kmsan/kmsan.c:337 [] kmsan_internal_chain_origin+0x118/0x1e0 mm/kmsan/kmsan.c:530 [] __msan_set_alloca_origin4+0xc3/0x130 mm/kmsan/kmsan_instr.c:380 [] SYSC_bind+0x129/0x5f0 net/socket.c:1356 [] SyS_bind+0x82/0xa0 net/socket.c:1356 [] do_syscall_64+0x58/0x70 arch/x86/entry/common.c:292 [] return_from_SYSCALL_64+0x0/0x6a arch/x86/entry/entry_64.o:? origin description: ----address@SYSC_bind (origin=00000000b8c00900) ================================================================== (the line numbers are relative to 4.8-rc6, but the bug persists upstream) , when I run the following program as root: ======================================================= #include #include #include int main(int argc, char *argv[]) { struct sockaddr addr; int size = 0; if (argc > 1) { size = atoi(argv[1]); } memset(&addr, 0, sizeof(addr)); int fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); bind(fd, &addr, size); return 0; } ======================================================= (for different values of |size| other error reports are printed). This happens because bind() unconditionally copies |size| bytes of |addr| to the kernel, leaving the rest uninitialized. Then security_socket_bind() reads the IP address bytes, including the uninitialized ones, to determine the port, or e.g. pass them further to sel_netnode_find(), which uses them to calculate a hash. Signed-off-by: Alexander Potapenko Acked-by: Eric Dumazet [PM: fixed some whitespace damage] Signed-off-by: Paul Moore Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- security/selinux/hooks.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c2da45ae5b2a..b8278f3af9da 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4328,10 +4328,18 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in u32 sid, node_perm; if (family == PF_INET) { + if (addrlen < sizeof(struct sockaddr_in)) { + err = -EINVAL; + goto out; + } addr4 = (struct sockaddr_in *)address; snum = ntohs(addr4->sin_port); addrp = (char *)&addr4->sin_addr.s_addr; } else { + if (addrlen < SIN6_LEN_RFC2133) { + err = -EINVAL; + goto out; + } addr6 = (struct sockaddr_in6 *)address; snum = ntohs(addr6->sin6_port); addrp = (char *)&addr6->sin6_addr.s6_addr; -- GitLab From 45142b2857789947a5f3d0e5fdfbb93ecac9eaf0 Mon Sep 17 00:00:00 2001 From: Dmitry Safonov Date: Mon, 6 Mar 2017 17:17:20 +0300 Subject: [PATCH 0361/1834] x86/mm: Make mmap(MAP_32BIT) work correctly [ Upstream commit 3e6ef9c80946f781fc25e8490c9875b1d2b61158 ] mmap(MAP_32BIT) is broken due to the dependency on the TIF_ADDR32 thread flag. For 64bit applications MAP_32BIT will force legacy bottom-up allocations and the 1GB address space restriction even if the application issued a compat syscall, which should not be subject of these restrictions. For 32bit applications, which issue 64bit syscalls the newly introduced mmap base separation into 64-bit and compat bases changed the behaviour because now a 64-bit mapping is returned, but due to the TIF_ADDR32 dependency MAP_32BIT is ignored. Before the separation a 32-bit mapping was returned, so the MAP_32BIT handling was irrelevant. Replace the check for TIF_ADDR32 with a check for the compat syscall. That solves both the 64-bit issuing a compat syscall and the 32-bit issuing a 64-bit syscall problems. [ tglx: Massaged changelog ] Signed-off-by: Dmitry Safonov Cc: 0x7f454c46@gmail.com Cc: linux-mm@kvack.org Cc: Andy Lutomirski Cc: Cyrill Gorcunov Cc: Borislav Petkov Cc: "Kirill A. Shutemov" Link: http://lkml.kernel.org/r/20170306141721.9188-5-dsafonov@virtuozzo.com Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/sys_x86_64.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/x86/kernel/sys_x86_64.c b/arch/x86/kernel/sys_x86_64.c index 1119414ab419..1d4e7fd3e66d 100644 --- a/arch/x86/kernel/sys_x86_64.c +++ b/arch/x86/kernel/sys_x86_64.c @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -100,7 +101,7 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, static void find_start_end(unsigned long flags, unsigned long *begin, unsigned long *end) { - if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) { + if (!in_compat_syscall() && (flags & MAP_32BIT)) { /* This is usually used needed to map code in small model, so it needs to be in the first 31bit. Limit it to that. This means we need to move the @@ -175,7 +176,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, return addr; /* for MAP_32BIT mappings we force the legacy mmap base */ - if (!test_thread_flag(TIF_ADDR32) && (flags & MAP_32BIT)) + if (!in_compat_syscall() && (flags & MAP_32BIT)) goto bottomup; /* requesting a specific address */ -- GitLab From 56eac6842374eea81ce30147124cc005d491d722 Mon Sep 17 00:00:00 2001 From: Changbin Du Date: Mon, 13 Mar 2017 16:31:48 +0800 Subject: [PATCH 0362/1834] perf sort: Fix segfault with basic block 'cycles' sort dimension [ Upstream commit 4b0b3aa6a2756e6115fdf275c521e4552a7082f3 ] Skip the sample which doesn't have branch_info to avoid segmentation fault: The fault can be reproduced by: perf record -a perf report -F cycles Signed-off-by: Changbin Du Tested-by: Arnaldo Carvalho de Melo Cc: Andi Kleen Cc: Peter Zijlstra Fixes: 0e332f033a82 ("perf tools: Add support for cycles, weight branch_info field") Link: http://lkml.kernel.org/r/20170313083148.23568-1-changbin.du@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/sort.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 452e15a10dd2..031e64ce7156 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -846,6 +846,9 @@ static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, static int64_t sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) { + if (!left->branch_info || !right->branch_info) + return cmp_null(left->branch_info, right->branch_info); + return left->branch_info->flags.cycles - right->branch_info->flags.cycles; } @@ -853,6 +856,8 @@ sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { + if (!he->branch_info) + return scnprintf(bf, size, "%-.*s", width, "N/A"); if (he->branch_info->flags.cycles == 0) return repsep_snprintf(bf, size, "%-*s", width, "-"); return repsep_snprintf(bf, size, "%-*hd", width, -- GitLab From fdfc3fa74511d687dbf626248b671cbe861c7c04 Mon Sep 17 00:00:00 2001 From: Xunlei Pang Date: Mon, 13 Mar 2017 10:50:19 +0100 Subject: [PATCH 0363/1834] x86/mce: Handle broadcasted MCE gracefully with kexec [ Upstream commit 5bc329503e8191c91c4c40836f062ef771d8ba83 ] When we are about to kexec a crash kernel and right then and there a broadcasted MCE fires while we're still in the first kernel and while the other CPUs remain in a holding pattern, the #MC handler of the first kernel will timeout and then panic due to never completing MCE synchronization. Handle this in a similar way as to when the CPUs are offlined when that broadcasted MCE happens. [ Boris: rewrote commit message and comments. ] Suggested-by: Borislav Petkov Signed-off-by: Xunlei Pang Signed-off-by: Borislav Petkov Acked-by: Tony Luck Cc: Naoya Horiguchi Cc: kexec@lists.infradead.org Cc: linux-edac Link: http://lkml.kernel.org/r/1487857012-9059-1-git-send-email-xlpang@redhat.com Link: http://lkml.kernel.org/r/20170313095019.19351-1-bp@alien8.de Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/reboot.h | 1 + arch/x86/kernel/cpu/mcheck/mce.c | 18 ++++++++++++++++-- arch/x86/kernel/reboot.c | 5 +++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h index 2cb1cc253d51..fc62ba8dce93 100644 --- a/arch/x86/include/asm/reboot.h +++ b/arch/x86/include/asm/reboot.h @@ -15,6 +15,7 @@ struct machine_ops { }; extern struct machine_ops machine_ops; +extern int crashing_cpu; void native_machine_crash_shutdown(struct pt_regs *regs); void native_machine_shutdown(void); diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 684d9fd191e0..88a996d80ca6 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "mce-internal.h" @@ -1081,9 +1082,22 @@ void do_machine_check(struct pt_regs *regs, long error_code) * on Intel. */ int lmce = 1; + int cpu = smp_processor_id(); - /* If this CPU is offline, just bail out. */ - if (cpu_is_offline(smp_processor_id())) { + /* + * Cases where we avoid rendezvous handler timeout: + * 1) If this CPU is offline. + * + * 2) If crashing_cpu was set, e.g. we're entering kdump and we need to + * skip those CPUs which remain looping in the 1st kernel - see + * crash_nmi_callback(). + * + * Note: there still is a small window between kexec-ing and the new, + * kdump kernel establishing a new #MC handler where a broadcasted MCE + * might not get handled properly. + */ + if (cpu_is_offline(cpu) || + (crashing_cpu != -1 && crashing_cpu != cpu)) { u64 mcgstatus; mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index ce020a69bba9..03f21dbfaa9d 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -769,10 +769,11 @@ void machine_crash_shutdown(struct pt_regs *regs) #endif +/* This is the CPU performing the emergency shutdown work. */ +int crashing_cpu = -1; + #if defined(CONFIG_SMP) -/* This keeps a track of which one is crashing cpu. */ -static int crashing_cpu; static nmi_shootdown_cb shootdown_callback; static atomic_t waiting_for_crash_ipi; -- GitLab From 41beba9840d7967ac4b6636b42bad6af3fb18fa5 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Wed, 8 Mar 2017 19:03:03 +0100 Subject: [PATCH 0364/1834] eventpoll.h: fix epoll event masks [ Upstream commit 6f051e4a685b768f3704c7c069aa1edee3010622 ] [resend due to me forgetting to cc: linux-api the first time around I posted these back on Feb 23] From: Greg Kroah-Hartman When userspace tries to use these defines, it complains that it needs to be an unsigned 1 that is shifted, so libc implementations have to create their own version. Fix this by defining it properly so that libcs can just use the kernel uapi header. Reported-by: Elliott Hughes Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/eventpoll.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/eventpoll.h b/include/uapi/linux/eventpoll.h index bc96b14dfb2c..f4d5c998cc2b 100644 --- a/include/uapi/linux/eventpoll.h +++ b/include/uapi/linux/eventpoll.h @@ -40,7 +40,7 @@ #define EPOLLRDHUP 0x00002000 /* Set exclusive wakeup mode for the target file descriptor */ -#define EPOLLEXCLUSIVE (1 << 28) +#define EPOLLEXCLUSIVE (1U << 28) /* * Request the handling of system wakeup events so as to prevent system suspends @@ -52,13 +52,13 @@ * * Requires CAP_BLOCK_SUSPEND */ -#define EPOLLWAKEUP (1 << 29) +#define EPOLLWAKEUP (1U << 29) /* Set the One Shot behaviour for the target file descriptor */ -#define EPOLLONESHOT (1 << 30) +#define EPOLLONESHOT (1U << 30) /* Set the Edge Triggered behaviour for the target file descriptor */ -#define EPOLLET (1 << 31) +#define EPOLLET (1U << 31) /* * On x86-64 make the 64bit structure have the same alignment as the -- GitLab From 6297c56c5e7fe3dd1ade273774f3ffc8451b6d71 Mon Sep 17 00:00:00 2001 From: Aaron Salter Date: Fri, 2 Dec 2016 12:33:02 -0800 Subject: [PATCH 0365/1834] i40e: Acquire NVM lock before reads on all devices [ Upstream commit 96a39aed25e6559b160786117df124084feb9080 ] Acquire NVM lock before reads on all devices. Previously, locks were only used for X722 and later. Fixes an issue where simultaneous X710 NVM accesses were interfering with each other. Change-ID: If570bb7acf958cef58725ec2a2011cead6f80638 Signed-off-by: Aaron Salter Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 954efe3118db..abe290bfc638 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -292,14 +292,14 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, { enum i40e_status_code ret_code = 0; - if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) { - ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); - if (!ret_code) { + ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ); + if (!ret_code) { + if (hw->flags & I40E_HW_FLAG_AQ_SRCTL_ACCESS_ENABLE) { ret_code = i40e_read_nvm_word_aq(hw, offset, data); - i40e_release_nvm(hw); + } else { + ret_code = i40e_read_nvm_word_srctl(hw, offset, data); } - } else { - ret_code = i40e_read_nvm_word_srctl(hw, offset, data); + i40e_release_nvm(hw); } return ret_code; } -- GitLab From daf88438c5a30b24b784a3b7cb95a780d733dc12 Mon Sep 17 00:00:00 2001 From: Lihong Yang Date: Mon, 30 Jan 2017 12:29:32 -0800 Subject: [PATCH 0366/1834] i40e: fix ethtool to get EEPROM data from X722 interface [ Upstream commit c271dd6c391b535226cf1a81aaad9f33cb5899d3 ] Currently ethtool -e will error out with a X722 interface as its EEPROM has a scope limit at offset 0x5B9FFF. This patch fixes the issue by setting the EEPROM length to the scope limit to avoid NVM read failure beyond that. Change-ID: I0b7d4dd6c7f2a57cace438af5dffa0f44c229372 Signed-off-by: Lihong Yang Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 92bc8846f1ba..f4569461dcb8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1135,6 +1135,11 @@ static int i40e_get_eeprom_len(struct net_device *netdev) struct i40e_hw *hw = &np->vsi->back->hw; u32 val; +#define X722_EEPROM_SCOPE_LIMIT 0x5B9FFF + if (hw->mac.type == I40E_MAC_X722) { + val = X722_EEPROM_SCOPE_LIMIT + 1; + return val; + } val = (rd32(hw, I40E_GLPCI_LBARCTRL) & I40E_GLPCI_LBARCTRL_FL_SIZE_MASK) >> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT; -- GitLab From ceb6ef4e333e064307a79877c7b23b891a8d95ff Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 15 Mar 2017 10:17:13 -0700 Subject: [PATCH 0367/1834] perf tools: Make perf_event__synthesize_mmap_events() scale [ Upstream commit 88b897a30c525c2eee6e7f16e1e8d0f18830845e ] This patch significantly improves the execution time of perf_event__synthesize_mmap_events() when running perf record on systems where processes have lots of threads. It just happens that cat /proc/pid/maps support uses a O(N^2) algorithm to generate each map line in the maps file. If you have 1000 threads, then you have necessarily 1000 stacks. For each vma, you need to check if it corresponds to a thread's stack. With a large number of threads, this can take a very long time. I have seen latencies >> 10mn. As of today, perf does not use the fact that a mapping is a stack, therefore we can work around the issue by using /proc/pid/tasks/pid/maps. This entry does not try to map a vma to stack and is thus much faster with no loss of functonality. The proc-map-timeout logic is kept in case users still want some upper limit. In V2, we fix the file path from /proc/pid/tasks/pid/maps to actual /proc/pid/task/pid/maps, tasks -> task. Thanks Arnaldo for catching this. Committer note: This problem seems to have been elliminated in the kernel since commit : b18cb64ead40 ("fs/proc: Stop trying to report thread stacks"). Signed-off-by: Stephane Eranian Acked-by: Jiri Olsa Cc: Andy Lutomirski Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170315135059.GC2177@redhat.com Link: http://lkml.kernel.org/r/1489598233-25586-1-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 8ab0d7da956b..663192395780 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -255,8 +255,8 @@ int perf_event__synthesize_mmap_events(struct perf_tool *tool, if (machine__is_default_guest(machine)) return 0; - snprintf(filename, sizeof(filename), "%s/proc/%d/maps", - machine->root_dir, pid); + snprintf(filename, sizeof(filename), "%s/proc/%d/task/%d/maps", + machine->root_dir, pid, pid); fp = fopen(filename, "r"); if (fp == NULL) { -- GitLab From f0dd1b26deb476853f0f8ae87695a73e348f5ca8 Mon Sep 17 00:00:00 2001 From: Al Cooper Date: Thu, 9 Mar 2017 10:51:18 -0800 Subject: [PATCH 0368/1834] ARM: brcmstb: Enable ZONE_DMA for non 64-bit capable peripherals [ Upstream commit 3c51b9c7f1fae00c25f1e34da649a288e3fea1ae ] Some Host Controller hardware blocks, like the OHCI, EHCI and SDIO controllers, have hardware blocks that are not capable of doing 64 bit DMA. These host controllers fail on boards with >3GB of memory because the memory above 3GB is located physically >= 0x100000000 and can only be accessed using 64 DMA. The way Linux is currently configured for BRCMSTB systems, the memory given to drivers for DMA through functions like dma_alloc_coherent() comes from CMA memory and CMA memory is taken from the top of physical memory. When these drivers get a DMA buffer with an address >=0x100000000, they end up dropping the upper 32 bit of the address causing the hardware to DMA to incorrect memory, typically BMEM (custom memory carveout). This issue was discovered on a BCM97449SSV_DDR4 system with 4GB or memory. The fix is to enable CONFIG_ZONE_DMA. On ARM systems this makes sure that all DMA memory is located within the first 32 bits of address space. Signed-off-by: Al Cooper Signed-off-by: Florian Fainelli Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-bcm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig index a0e66d8200c5..403db76e3497 100644 --- a/arch/arm/mach-bcm/Kconfig +++ b/arch/arm/mach-bcm/Kconfig @@ -199,6 +199,7 @@ config ARCH_BRCMSTB select BRCMSTB_L2_IRQ select BCM7120_L2_IRQ select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE + select ZONE_DMA if ARM_LPAE select SOC_BRCMSTB select SOC_BUS help -- GitLab From c82b5831a27319b7f3793bdd17145b3551963d21 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 15 Mar 2017 13:27:16 -0700 Subject: [PATCH 0369/1834] drivers: net: xgene: Fix hardware checksum setting [ Upstream commit e026e700d940a1ea3d3bc84d92ac668b1f015462 ] This patch fixes the hardware checksum settings by properly program the classifier. Otherwise, packet may be received with checksum error on X-Gene1 SoC. Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/apm/xgene/xgene_enet_hw.c | 1 + drivers/net/ethernet/apm/xgene/xgene_enet_hw.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c index 5390ae89136c..71611bd6384b 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c @@ -560,6 +560,7 @@ static void xgene_enet_cle_bypass(struct xgene_enet_pdata *pdata, xgene_enet_rd_csr(pdata, CLE_BYPASS_REG0_0_ADDR, &cb); cb |= CFG_CLE_BYPASS_EN0; CFG_CLE_IP_PROTOCOL0_SET(&cb, 3); + CFG_CLE_IP_HDR_LEN_SET(&cb, 0); xgene_enet_wr_csr(pdata, CLE_BYPASS_REG0_0_ADDR, cb); xgene_enet_rd_csr(pdata, CLE_BYPASS_REG1_0_ADDR, &cb); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 06e598c8bc16..c82faf1a88b8 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -163,6 +163,7 @@ enum xgene_enet_rm { #define CFG_RXCLK_MUXSEL0_SET(dst, val) xgene_set_bits(dst, val, 26, 3) #define CFG_CLE_IP_PROTOCOL0_SET(dst, val) xgene_set_bits(dst, val, 16, 2) +#define CFG_CLE_IP_HDR_LEN_SET(dst, val) xgene_set_bits(dst, val, 8, 5) #define CFG_CLE_DSTQID0_SET(dst, val) xgene_set_bits(dst, val, 0, 12) #define CFG_CLE_FPSEL0_SET(dst, val) xgene_set_bits(dst, val, 16, 4) #define CFG_MACMODE_SET(dst, val) xgene_set_bits(dst, val, 18, 2) -- GitLab From 054221c210227e3b8b325c1459443518eeea2cd1 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 15 Mar 2017 13:27:15 -0700 Subject: [PATCH 0370/1834] drivers: net: phy: xgene: Fix mdio write [ Upstream commit 4b72436dc3dd2457056b22d6f147777368c869fa ] This patches fixes a typo in the argument to xgene_enet_wr_mdio_csr(). Signed-off-by: Quan Nguyen Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mdio-xgene.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c index 8eb077b677f6..39be3b82608f 100644 --- a/drivers/net/phy/mdio-xgene.c +++ b/drivers/net/phy/mdio-xgene.c @@ -232,7 +232,7 @@ static int xgene_xfi_mdio_write(struct mii_bus *bus, int phy_id, val = SET_VAL(HSTPHYADX, phy_id) | SET_VAL(HSTREGADX, reg) | SET_VAL(HSTMIIMWRDAT, data); - xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, data); + xgene_enet_wr_mdio_csr(addr, MIIM_FIELD_ADDR, val); val = HSTLDCMD | SET_VAL(HSTMIIMCMD, MIIM_CMD_LEGACY_WRITE); xgene_enet_wr_mdio_csr(addr, MIIM_COMMAND_ADDR, val); -- GitLab From 67622b81288413e28fca6d94338c66a0b08797a5 Mon Sep 17 00:00:00 2001 From: Quan Nguyen Date: Wed, 15 Mar 2017 13:27:17 -0700 Subject: [PATCH 0371/1834] drivers: net: xgene: Fix wrong logical operation [ Upstream commit 11623fce0f9afef30c45e3f2120b063de3809a8f ] This patch fixes the wrong logical OR operation by changing it to bit-wise OR operation. Fixes: 3bb502f83080 ("drivers: net: xgene: fix statistics counters race condition") Signed-off-by: Iyappan Subramanian Signed-off-by: Quan Nguyen Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/apm/xgene/xgene_enet_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 8158d4698734..de1546a63a7f 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -537,9 +537,9 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, buf_pool->rx_skb[skb_index] = NULL; /* checking for error */ - status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) || + status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) | GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); - if (unlikely(status > 2)) { + if (unlikely(status)) { dev_kfree_skb_any(skb); xgene_enet_parse_error(rx_ring, netdev_priv(rx_ring->ndev), status); -- GitLab From 671eeac5358a15b9bb69d146ef5a3d4d54eb7b5b Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 15 Mar 2017 13:27:18 -0700 Subject: [PATCH 0372/1834] drivers: net: xgene: Fix Rx checksum validation logic [ Upstream commit 0a0400c3094b5d5cedd479ddbf1329de74c09c4b ] This patch fixes Rx checksum validation logic and adds NETIF_F_RXCSUM flag. Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/apm/xgene/xgene_enet_main.c | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index de1546a63a7f..651f308cdc60 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -505,14 +505,24 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } -static void xgene_enet_skip_csum(struct sk_buff *skb) +static void xgene_enet_rx_csum(struct sk_buff *skb) { + struct net_device *ndev = skb->dev; struct iphdr *iph = ip_hdr(skb); - if (!ip_is_fragment(iph) || - (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } + if (!(ndev->features & NETIF_F_RXCSUM)) + return; + + if (skb->protocol != htons(ETH_P_IP)) + return; + + if (ip_is_fragment(iph)) + return; + + if (iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP) + return; + + skb->ip_summed = CHECKSUM_UNNECESSARY; } static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, @@ -555,10 +565,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, skb_checksum_none_assert(skb); skb->protocol = eth_type_trans(skb, ndev); - if (likely((ndev->features & NETIF_F_IP_CSUM) && - skb->protocol == htons(ETH_P_IP))) { - xgene_enet_skip_csum(skb); - } + xgene_enet_rx_csum(skb); rx_ring->rx_packets++; rx_ring->rx_bytes += datalen; @@ -1725,7 +1732,7 @@ static int xgene_enet_probe(struct platform_device *pdev) xgene_enet_setup_ops(pdata); if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { - ndev->features |= NETIF_F_TSO; + ndev->features |= NETIF_F_TSO | NETIF_F_RXCSUM; spin_lock_init(&pdata->mss_lock); } ndev->hw_features = ndev->features; -- GitLab From 80ec67573b9508bce7f10a80f01b78fb7c9cb1c2 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 15 Mar 2017 20:40:25 +0000 Subject: [PATCH 0373/1834] drm: Defer disabling the vblank IRQ until the next interrupt (for instant-off) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 608b20506941969ea30d8c08dc9ae02bb87dbf7d ] On vblank instant-off systems, we can get into a situation where the cost of enabling and disabling the vblank IRQ around a drmWaitVblank query dominates. And with the advent of even deeper hardware sleep state, touching registers becomes ever more expensive. However, we know that if the user wants the current vblank counter, they are also very likely to immediately queue a vblank wait and so we can keep the interrupt around and only turn it off if we have no further vblank requests queued within the interrupt interval. After vblank event delivery, this patch adds a shadow of one vblank where the interrupt is kept alive for the user to query and queue another vblank event. Similarly, if the user is using blocking drmWaitVblanks, the interrupt will be disabled on the IRQ following the wait completion. However, if the user is simply querying the current vblank counter and timestamp, the interrupt will be disabled after every IRQ and the user will enabled it again on the first query following the IRQ. v2: Mario Kleiner - After testing this, one more thing that would make sense is to move the disable block at the end of drm_handle_vblank() instead of at the top. Turns out that if high precision timestaming is disabled or doesn't work for some reason (as can be simulated by echo 0 > /sys/module/drm/parameters/timestamp_precision_usec), then with your delayed disable code at its current place, the vblank counter won't increment anymore at all for instant queries, ie. with your other "instant query" patches. Clients which repeatedly query the counter and wait for it to progress will simply hang, spinning in an endless query loop. There's that comment in vblank_disable_and_save: "* Skip this step if there isn't any high precision timestamp * available. In that case we can't account for this and just * hope for the best. */ With the disable happening after leading edge of vblank (== hw counter increment already happened) but before the vblank counter/timestamp handling in drm_handle_vblank, that step is needed to keep the counter progressing, so skipping it is bad. Now without high precision timestamping support, a kms driver must not set dev->vblank_disable_immediate = true, as this would cause problems for clients, so this shouldn't matter, but it would be good to still make this robust against a future kms driver which might have unreliable high precision timestamping, e.g., high precision timestamping that intermittently doesn't work. v3: Patch before coffee needs extra coffee. Testcase: igt/kms_vblank Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Daniel Vetter Cc: Michel Dänzer Cc: Laurent Pinchart Cc: Dave Airlie , Cc: Mario Kleiner Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20170315204027.20160-1-chris@chris-wilson.co.uk Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_irq.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index 48a6167f5e7b..00c815a7c414 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1202,9 +1202,9 @@ static void drm_vblank_put(struct drm_device *dev, unsigned int pipe) if (atomic_dec_and_test(&vblank->refcount)) { if (drm_vblank_offdelay == 0) return; - else if (dev->vblank_disable_immediate || drm_vblank_offdelay < 0) + else if (drm_vblank_offdelay < 0) vblank_disable_fn((unsigned long)vblank); - else + else if (!dev->vblank_disable_immediate) mod_timer(&vblank->disable_timer, jiffies + ((drm_vblank_offdelay * HZ)/1000)); } @@ -1819,6 +1819,16 @@ bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe) wake_up(&vblank->queue); drm_handle_vblank_events(dev, pipe); + /* With instant-off, we defer disabling the interrupt until after + * we finish processing the following vblank. The disable has to + * be last (after drm_handle_vblank_events) so that the timestamp + * is always accurate. + */ + if (dev->vblank_disable_immediate && + drm_vblank_offdelay > 0 && + !atomic_read(&vblank->refcount)) + vblank_disable_fn((unsigned long)vblank); + spin_unlock_irqrestore(&dev->event_lock, irqflags); return true; -- GitLab From 6a528ebdf3ce081204854cea4b33aea37539b9c4 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 22 Feb 2017 21:03:11 +0530 Subject: [PATCH 0374/1834] ath10k: disallow DFS simulation if DFS channel is not enabled [ Upstream commit ca07baab0b1e627ae1d4a55d190fb1c9d32a3445 ] If DFS is not enabled in hostapd (ieee80211h=0) DFS channels shall not be available for use even though the hardware may have the capability to support DFS. With this configuration (DFS disabled in hostapd) trying to bring up ath10k device in DFS channel for AP mode fails and trying to simulate DFS in ath10k debugfs results in a warning in cfg80211 complaining invalid channel and this should be avoided in the driver itself rather than false propogating RADAR detection to mac80211/cfg80211. Fix this by checking for the first vif 'is_started' state(should work for client mode as well) as all the vifs shall be configured for the same channel sys/kernel/debug/ieee80211/phy1/ath10k# echo 1 > dfs_simulate_radar WARNING: at net/wireless/chan.c:265 cfg80211_radar_event+0x24/0x60 Workqueue: phy0 ieee80211_dfs_radar_detected_work [mac80211] [] (warn_slowpath_null) from [] (cfg80211_radar_event+0x24/0x60 [cfg80211]) [] (cfg80211_radar_event [cfg80211]) from [] (ieee80211_dfs_radar_detected_work+0x94/0xa0 [mac80211]) [] (ieee80211_dfs_radar_detected_work [mac80211]) from [] (process_one_work+0x20c/0x32c) WARNING: at net/wireless/nl80211.c:2488 nl80211_get_mpath+0x13c/0x4cc Workqueue: phy0 ieee80211_dfs_radar_detected_work [mac80211] [] (warn_slowpath_null) from [] (cfg80211_radar_event+0x24/0x60 [cfg80211]) [] (cfg80211_radar_event [cfg80211]) from [] (ieee80211_dfs_radar_detected_work+0x94/0xa0 [mac80211]) [] (ieee80211_dfs_radar_detected_work [mac80211]) from [] (process_one_work+0x20c/0x32c) Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/debug.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 82a4c67f3672..6aa2b93497dd 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1942,6 +1942,15 @@ static ssize_t ath10k_write_simulate_radar(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; + struct ath10k_vif *arvif; + + /* Just check for for the first vif alone, as all the vifs will be + * sharing the same channel and if the channel is disabled, all the + * vifs will share the same 'is_started' state. + */ + arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list); + if (!arvif->is_started) + return -EINVAL; ieee80211_radar_detected(ar->hw); -- GitLab From 84b63638ca812f02f9fc79ee358146f9f8d310ab Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 8 Mar 2017 18:03:32 +0530 Subject: [PATCH 0375/1834] ath10k: fix fetching channel during potential radar detection [ Upstream commit a28f6f27a88f047f03f04b9246ca260ebc91455e ] Fetch target operating channel during potential radar detection when the interface is just brought up, but no channel is assigned from userspace. In this scenario rx_channel may not be having a valid pointer hence fetch the target operating channel to avoid warnings as below which can be triggered by the commands with DFS testing over longer run comamnds: iw wlan1 set type mesh ifconfig wlan1 up (valid tgt_oper_chan only) iw wlan1 cac trigger freq 5260 HT20 (valid rx_channel, tgt_oper_chan) iw wlan1 cac trigger freq 5280 HT20 iw wlan1 cac trigger freq 5300 HT20 Once the CAC expires, current channel context will be removed and we are only left with the fallback option of using 'target operating channel' Firmware and driver log: ath: phy1: DFS: radar found on freq=5300: id=1, pri=1125, count=5, count_false=4 ath: phy1: DFS: radar found on freq=5260: id=5, pri=3151, count=6, count_false=11 ath: phy1: DFS: radar found on freq=5280: id=1, pri=1351, count=6, count_false=4 ath: phy1: DFS: radar found on freq=5300: id=1, pri=1125, count=5, count_false=4 ath10k_pci 0001:01:00.0: failed to derive channel for radar pulse, treating as radar ath10k_pci 0001:01:00.0: failed to derive channel for radar pulse, treating as radar Call trace: WARNING: CPU: 1 PID: 2145 at backports-20161201-3.14.77-9ab3068/net/wireless/chan.c:265 cfg80211_set_dfs_state+0x3c/0x88 [cfg80211]() Workqueue: phy1 ieee80211_dfs_radar_detected_work [mac80211] [] (warn_slowpath_null) from [] (cfg80211_set_dfs_state+0x3c/0x88 [cfg80211]) [] (cfg80211_set_dfs_state [cfg80211]) from [] (cfg80211_radar_event+0xc4/0x140 [cfg80211]) [] (cfg80211_radar_event [cfg80211]) from [] (ieee80211_dfs_radar_detected_work+0xa8/0xb4 [mac80211]) [] (ieee80211_dfs_radar_detected_work [mac80211]) from [] (process_one_work+0x298/0x4a4) Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/wmi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 54df425bb0fc..e518b640aad0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3638,6 +3638,11 @@ static void ath10k_dfs_radar_report(struct ath10k *ar, spin_lock_bh(&ar->data_lock); ch = ar->rx_channel; + + /* fetch target operating channel during channel change */ + if (!ch) + ch = ar->tgt_oper_chan; + spin_unlock_bh(&ar->data_lock); if (!ch) { -- GitLab From e6e868c7504502cda721c0a814d3eac2594760f0 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 14 Mar 2017 12:05:07 +0100 Subject: [PATCH 0376/1834] usb: misc: lvs: fix race condition in disconnect handling [ Upstream commit c4ba329cabca7c839ab48fb58b5bcc2582951a48 ] There is a small window during which the an URB may remain active after disconnect has returned. If in that case already freed memory may be accessed and executed. The fix is to poison the URB befotre the work is flushed. Signed-off-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/misc/lvstest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index d3d124753266..bd6e06ef88ac 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -433,6 +433,7 @@ static void lvs_rh_disconnect(struct usb_interface *intf) struct lvs_rh *lvs = usb_get_intfdata(intf); sysfs_remove_group(&intf->dev.kobj, &lvs_attr_group); + usb_poison_urb(lvs->urb); /* used in scheduled work */ flush_work(&lvs->rh_work); usb_free_urb(lvs->urb); } -- GitLab From 056a442ef49544193148f7a449a1e72cb0d9635e Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 4 Mar 2017 09:43:51 +0000 Subject: [PATCH 0377/1834] ARM: bcm2835: Enable missing CMA settings for VC4 driver [ Upstream commit bdd3c25423cb42171446940bca0946e0443e1a84 ] Currently bcm2835_defconfig has CMA disabled which makes the HDMI output on a Raspberry Pi 1 stop working during boot: fb: switching to vc4drmfb from simple Console: switching to colour dummy device 80x30 [drm] Initialized vc4 0.0.0 20140616 for soc:gpu on minor 0 [drm] Supports vblank timestamp caching Rev 2 (21.10.2013). [drm] Driver supports precise vblank timestamp query. vc4-drm soc:gpu: failed to allocate buffer with size 9216000 vc4-drm soc:gpu: Failed to set initial hw configuration. So enable CMA and DMA_CMA in bcm2835_defconfig. Signed-off-by: Stefan Wahren Fixes: 4400d9ac05ee ("ARM: bcm2835: Enable the VC4 graphics driver in the defconfig") Reviewed-by: Eric Anholt Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/configs/bcm2835_defconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig index 79de828e49ad..e32b0550a338 100644 --- a/arch/arm/configs/bcm2835_defconfig +++ b/arch/arm/configs/bcm2835_defconfig @@ -1,6 +1,5 @@ # CONFIG_LOCALVERSION_AUTO is not set CONFIG_SYSVIPC=y -CONFIG_FHANDLE=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_BSD_PROCESS_ACCT=y @@ -32,6 +31,7 @@ CONFIG_PREEMPT_VOLUNTARY=y CONFIG_AEABI=y CONFIG_KSM=y CONFIG_CLEANCACHE=y +CONFIG_CMA=y CONFIG_SECCOMP=y CONFIG_KEXEC=y CONFIG_CRASH_DUMP=y @@ -52,6 +52,7 @@ CONFIG_MAC80211=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set +CONFIG_DMA_CMA=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_SCSI_CONSTANTS=y @@ -62,7 +63,6 @@ CONFIG_USB_NET_SMSC95XX=y CONFIG_ZD1211RW=y CONFIG_INPUT_EVDEV=y # CONFIG_LEGACY_PTYS is not set -# CONFIG_DEVKMEM is not set CONFIG_SERIAL_AMBA_PL011=y CONFIG_SERIAL_AMBA_PL011_CONSOLE=y CONFIG_TTY_PRINTK=y -- GitLab From 09bcb120a27be242f35432ddb671ba11786d8790 Mon Sep 17 00:00:00 2001 From: Steve Lin Date: Thu, 16 Mar 2017 11:48:58 -0400 Subject: [PATCH 0378/1834] net: ethernet: bgmac: Allow MAC address to be specified in DTB [ Upstream commit 2f771399a3a2c371c140ff33544a583c6fbc5fd9 ] Allows the BCMA version of the bgmac driver to obtain MAC address from the device tree. If no MAC address is specified there, then the previous behavior (obtaining MAC address from SPROM) is used. Signed-off-by: Steve Lin Reviewed-by: Florian Fainelli Acked-by: Jon Mason Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bgmac-bcma.c | 39 +++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac-bcma.c b/drivers/net/ethernet/broadcom/bgmac-bcma.c index c16ec3a51876..1ee11b600645 100644 --- a/drivers/net/ethernet/broadcom/bgmac-bcma.c +++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "bgmac.h" static inline bool bgmac_is_bcm4707_family(struct bcma_device *core) @@ -96,7 +97,7 @@ static int bgmac_probe(struct bcma_device *core) struct ssb_sprom *sprom = &core->bus->sprom; struct mii_bus *mii_bus; struct bgmac *bgmac; - u8 *mac; + const u8 *mac = NULL; int err; bgmac = kzalloc(sizeof(*bgmac), GFP_KERNEL); @@ -110,21 +111,27 @@ static int bgmac_probe(struct bcma_device *core) bcma_set_drvdata(core, bgmac); - switch (core->core_unit) { - case 0: - mac = sprom->et0mac; - break; - case 1: - mac = sprom->et1mac; - break; - case 2: - mac = sprom->et2mac; - break; - default: - dev_err(bgmac->dev, "Unsupported core_unit %d\n", - core->core_unit); - err = -ENOTSUPP; - goto err; + if (bgmac->dev->of_node) + mac = of_get_mac_address(bgmac->dev->of_node); + + /* If no MAC address assigned via device tree, check SPROM */ + if (!mac) { + switch (core->core_unit) { + case 0: + mac = sprom->et0mac; + break; + case 1: + mac = sprom->et1mac; + break; + case 2: + mac = sprom->et2mac; + break; + default: + dev_err(bgmac->dev, "Unsupported core_unit %d\n", + core->core_unit); + err = -ENOTSUPP; + goto err; + } } ether_addr_copy(bgmac->mac_addr, mac); -- GitLab From 3649d93cb4e9df98d48a3860a6da7575478f0dd9 Mon Sep 17 00:00:00 2001 From: Nik Unger Date: Mon, 13 Mar 2017 10:16:58 -0700 Subject: [PATCH 0379/1834] netem: apply correct delay when rate throttling [ Upstream commit 5080f39e8c72e01cf37e8359023e7018e2a4901e ] I recently reported on the netem list that iperf network benchmarks show unexpected results when a bandwidth throttling rate has been configured for netem. Specifically: 1) The measured link bandwidth *increases* when a higher delay is added 2) The measured link bandwidth appears higher than the specified limit 3) The measured link bandwidth for the same very slow settings varies significantly across machines The issue can be reproduced by using tc to configure netem with a 512kbit rate and various (none, 1us, 50ms, 100ms, 200ms) delays on a veth pair between network namespaces, and then using iperf (or any other network benchmarking tool) to test throughput. Complete detailed instructions are in the original email chain here: https://lists.linuxfoundation.org/pipermail/netem/2017-February/001672.html There appear to be two underlying bugs causing these effects: - The first issue causes long delays when the rate is slow and no delay is configured (e.g., "rate 512kbit"). This is because SKBs are not orphaned when no delay is configured, so orphaning does not occur until *after* the rate-induced delay has been applied. For this reason, adding a tiny delay (e.g., "rate 512kbit delay 1us") dramatically increases the measured bandwidth. - The second issue is that rate-induced delays are not correctly applied, allowing SKB delays to occur in parallel. The indended approach is to compute the delay for an SKB and to add this delay to the end of the current queue. However, the code does not detect existing SKBs in the queue due to improperly testing sch->q.qlen, which is nonzero even when packets exist only in the rbtree. Consequently, new SKBs do not wait for the current queue to empty. When packet delays vary significantly (e.g., if packet sizes are different), then this also causes unintended reordering. I modified the code to expect a delay (and orphan the SKB) when a rate is configured. I also added some defensive tests that correctly find the latest scheduled delivery time, even if it is (unexpectedly) for a packet in sch->q. I have tested these changes on the latest kernel (4.11.0-rc1+) and the iperf / ping test results are as expected. Signed-off-by: Nik Unger Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sched/sch_netem.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 9f7b380cf0a3..c73d58872cf8 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -462,7 +462,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, /* If a delay is expected, orphan the skb. (orphaning usually takes * place at TX completion time, so _before_ the link transit delay) */ - if (q->latency || q->jitter) + if (q->latency || q->jitter || q->rate) skb_orphan_partial(skb); /* @@ -530,21 +530,31 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, now = psched_get_time(); if (q->rate) { - struct sk_buff *last; + struct netem_skb_cb *last = NULL; + + if (sch->q.tail) + last = netem_skb_cb(sch->q.tail); + if (q->t_root.rb_node) { + struct sk_buff *t_skb; + struct netem_skb_cb *t_last; + + t_skb = netem_rb_to_skb(rb_last(&q->t_root)); + t_last = netem_skb_cb(t_skb); + if (!last || + t_last->time_to_send > last->time_to_send) { + last = t_last; + } + } - if (sch->q.qlen) - last = sch->q.tail; - else - last = netem_rb_to_skb(rb_last(&q->t_root)); if (last) { /* * Last packet in queue is reference point (now), * calculate this time bonus and subtract * from delay. */ - delay -= netem_skb_cb(last)->time_to_send - now; + delay -= last->time_to_send - now; delay = max_t(psched_tdiff_t, 0, delay); - now = netem_skb_cb(last)->time_to_send; + now = last->time_to_send; } delay += packet_len_2_sched_time(qdisc_pkt_len(skb), q); -- GitLab From d5721f4b3423bb669ad04114a03fa60085c078e1 Mon Sep 17 00:00:00 2001 From: Yazen Ghannam Date: Wed, 15 Mar 2017 12:30:55 -0500 Subject: [PATCH 0380/1834] x86/mce: Init some CPU features early [ Upstream commit 5204bf17031b69fa5faa4dc80a9dc1e2446d74f9 ] When the MCA banks in __mcheck_cpu_init_generic() are polled for leftover errors logged during boot or from the previous boot, its required to have CPU features detected sufficiently so that the reading out and handling of those early errors is done correctly. If those features are not available, the decoding may miss some information and get incomplete errors logged. For example, on SMCA systems the MCA_IPID and MCA_SYND registers are not logged and MCA_ADDR is not masked appropriately. To cure that, do a subset of the basic feature detection early while the rest happens in its usual place in __mcheck_cpu_init_vendor(). Signed-off-by: Yazen Ghannam Cc: Tony Luck Cc: linux-edac Cc: x86-ml Link: http://lkml.kernel.org/r/1489599055-20756-1-git-send-email-Yazen.Ghannam@amd.com [ Massage commit message and simplify. ] Signed-off-by: Borislav Petkov Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/mcheck/mce.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c index 88a996d80ca6..7bbd50fa72ad 100644 --- a/arch/x86/kernel/cpu/mcheck/mce.c +++ b/arch/x86/kernel/cpu/mcheck/mce.c @@ -1695,30 +1695,35 @@ static int __mcheck_cpu_ancient_init(struct cpuinfo_x86 *c) return 0; } -static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) +/* + * Init basic CPU features needed for early decoding of MCEs. + */ +static void __mcheck_cpu_init_early(struct cpuinfo_x86 *c) { - switch (c->x86_vendor) { - case X86_VENDOR_INTEL: - mce_intel_feature_init(c); - mce_adjust_timer = cmci_intel_adjust_timer; - break; - - case X86_VENDOR_AMD: { + if (c->x86_vendor == X86_VENDOR_AMD) { mce_flags.overflow_recov = !!cpu_has(c, X86_FEATURE_OVERFLOW_RECOV); mce_flags.succor = !!cpu_has(c, X86_FEATURE_SUCCOR); mce_flags.smca = !!cpu_has(c, X86_FEATURE_SMCA); - /* - * Install proper ops for Scalable MCA enabled processors - */ if (mce_flags.smca) { msr_ops.ctl = smca_ctl_reg; msr_ops.status = smca_status_reg; msr_ops.addr = smca_addr_reg; msr_ops.misc = smca_misc_reg; } - mce_amd_feature_init(c); + } +} +static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) +{ + switch (c->x86_vendor) { + case X86_VENDOR_INTEL: + mce_intel_feature_init(c); + mce_adjust_timer = cmci_intel_adjust_timer; + break; + + case X86_VENDOR_AMD: { + mce_amd_feature_init(c); break; } @@ -1804,6 +1809,7 @@ void mcheck_cpu_init(struct cpuinfo_x86 *c) machine_check_vector = do_machine_check; + __mcheck_cpu_init_early(c); __mcheck_cpu_init_generic(); __mcheck_cpu_init_vendor(c); __mcheck_cpu_init_clear_banks(); -- GitLab From a124c8751f2288ef328fba9544634af9a4021d9f Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 20 Mar 2017 18:30:59 +0100 Subject: [PATCH 0381/1834] omapfb: dss: Handle return errors in dss_init_ports() [ Upstream commit 0348aaa34412e24ebe622a2b1b013e68d6ae5412 ] dss_init_ports() is not handling return errors from dpi_init_port() and sdi_init_port(). It is also always returning 0 currently which results in part of error handling code in dss_bind() being unused. Fix dss_init_ports() to handle return errors from dpi_init_port() and sdi_init_port(). Signed-off-by: Arvind Yadav Cc: tomi.valkeinen@ti.com [b.zolnierkie: fail early on errors, minor fixups] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/omap2/omapfb/dss/dss.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dss.c b/drivers/video/fbdev/omap2/omapfb/dss/dss.c index 47d7f69ad9ad..48c6500c24e1 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dss.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dss.c @@ -941,11 +941,13 @@ static int dss_init_features(struct platform_device *pdev) return 0; } +static void dss_uninit_ports(struct platform_device *pdev); + static int dss_init_ports(struct platform_device *pdev) { struct device_node *parent = pdev->dev.of_node; struct device_node *port; - int r; + int r, ret = 0; if (parent == NULL) return 0; @@ -972,17 +974,21 @@ static int dss_init_ports(struct platform_device *pdev) switch (port_type) { case OMAP_DISPLAY_TYPE_DPI: - dpi_init_port(pdev, port); + ret = dpi_init_port(pdev, port); break; case OMAP_DISPLAY_TYPE_SDI: - sdi_init_port(pdev, port); + ret = sdi_init_port(pdev, port); break; default: break; } - } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); + } while (!ret && + (port = omapdss_of_get_next_port(parent, port)) != NULL); - return 0; + if (ret) + dss_uninit_ports(pdev); + + return ret; } static void dss_uninit_ports(struct platform_device *pdev) -- GitLab From f49cfde843314302a2dc7913e6a3183585a92d60 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Wed, 8 Mar 2017 12:29:07 +0530 Subject: [PATCH 0382/1834] perf probe: Fix concat_probe_trace_events [ Upstream commit f0a30dca5f84fe8048271799b56677ac2279de66 ] '*ntevs' contains number of elements present in 'tevs' array. If there are no elements in array, 'tevs2' can be directly assigned to 'tevs' without allocating more space. So the condition should be '*ntevs == 0' not 'ntevs == 0'. Signed-off-by: Ravi Bangoria Acked-by: Masami Hiramatsu Cc: Alexander Shishkin Cc: Peter Zijlstra Fixes: 42bba263eb58 ("perf probe: Allow wildcard for cached events") Link: http://lkml.kernel.org/r/20170308065908.4128-1-ravi.bangoria@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/probe-event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 6a6f44dd594b..4d2e22f8bd94 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -3060,7 +3060,7 @@ concat_probe_trace_events(struct probe_trace_event **tevs, int *ntevs, struct probe_trace_event *new_tevs; int ret = 0; - if (ntevs == 0) { + if (*ntevs == 0) { *tevs = *tevs2; *ntevs = ntevs2; *tevs2 = NULL; -- GitLab From 7fd66ee795c6fce0897a5731ec011b17eef63901 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Fri, 17 Mar 2017 16:16:32 +0800 Subject: [PATCH 0383/1834] perf probe: Return errno when not hitting any event [ Upstream commit 70946723eeb859466f026274b29c6196e39149c4 ] On old perf, when using 'perf probe -d' to delete an inexistent event, it returns errno, eg, -bash-4.3# perf probe -d xxx || echo $? Info: Event "*:xxx" does not exist. Error: Failed to delete events. 255 But now perf_del_probe_events() will always set ret = 0, different from previous del_perf_probe_events(). After this, it returns errno again, eg, -bash-4.3# ./perf probe -d xxx || echo $? "xxx" does not hit any event. Error: Failed to delete events. 254 And it is more appropriate to return -ENOENT instead of -EPERM. Signed-off-by: Kefeng Wang Acked-by: Masami Hiramatsu Cc: Hanjun Guo Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Wang Nan Fixes: dddc7ee32fa1 ("perf probe: Fix an error when deleting probes successfully") Link: http://lkml.kernel.org/r/1489738592-61011-1-git-send-email-wangkefeng.wang@huawei.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-probe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index f87996b0cb29..9a250c71840e 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -442,9 +442,9 @@ static int perf_del_probe_events(struct strfilter *filter) } if (ret == -ENOENT && ret2 == -ENOENT) - pr_debug("\"%s\" does not hit any event.\n", str); - /* Note that this is silently ignored */ - ret = 0; + pr_warning("\"%s\" does not hit any event.\n", str); + else + ret = 0; error: if (kfd >= 0) -- GitLab From 3582c4b4df1d7f2ff219b6367976e31d7dfbada1 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Tue, 14 Mar 2017 13:29:13 +0000 Subject: [PATCH 0384/1834] HID: clamp input to logical range if no null state [ Upstream commit c3883fe06488a483658ba5d849b70e49bee15e7c ] This patch fixes an issue in drivers/hid/hid-input.c where values outside of the logical range are not clamped when "null state" bit of the input control is not set. This was discussed on the lists [1] and this change stems from the fact due to the ambiguity of the HID specification it might be appropriate to follow Microsoft's own interpretation of the specification. As noted in Microsoft's documentation [2] in the section titled "Required HID usages for digitizers" it is noted that values reported outside the logical range "will be considered as invalid data and the value will be changed to the nearest boundary value (logical min/max)." This patch fixes an issue where the (1292:4745) Innomedia INNEX GENESIS/ATARI reports out of range values for its X and Y axis of the DPad which, due to the null state bit being unset, are forwarded to userspace as is. Now these values will get clamped to the logical range before being forwarded to userspace. This device was also used to test this patch. This patch expands on commit 3f3752705dbd ("HID: reject input outside logical range only if null state is set"). [1]: http://lkml.kernel.org/r/20170307131036.GA853@gaia.local [2]: https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp Signed-off-by: Tomasz Kramkowski Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 76f2527fbc60..40233315d5f5 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1149,19 +1149,26 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct /* * Ignore out-of-range values as per HID specification, - * section 5.10 and 6.2.25. + * section 5.10 and 6.2.25, when NULL state bit is present. + * When it's not, clamp the value to match Microsoft's input + * driver as mentioned in "Required HID usages for digitizers": + * https://msdn.microsoft.com/en-us/library/windows/hardware/dn672278(v=vs.85).asp * * The logical_minimum < logical_maximum check is done so that we * don't unintentionally discard values sent by devices which * don't specify logical min and max. */ if ((field->flags & HID_MAIN_ITEM_VARIABLE) && - (field->flags & HID_MAIN_ITEM_NULL_STATE) && - (field->logical_minimum < field->logical_maximum) && - (value < field->logical_minimum || - value > field->logical_maximum)) { - dbg_hid("Ignoring out-of-range value %x\n", value); - return; + (field->logical_minimum < field->logical_maximum)) { + if (field->flags & HID_MAIN_ITEM_NULL_STATE && + (value < field->logical_minimum || + value > field->logical_maximum)) { + dbg_hid("Ignoring out-of-range value %x\n", value); + return; + } + value = clamp(value, + field->logical_minimum, + field->logical_maximum); } /* -- GitLab From 4c484f758c180c6f8374fada0d9872fe8557e41d Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Wed, 15 Mar 2017 17:41:14 -0700 Subject: [PATCH 0385/1834] net/8021q: create device with all possible features in wanted_features [ Upstream commit 88997e4208aea117627898e5f6f9801cf3cd42d2 ] wanted_features is a set of features which have to be enabled if a hardware allows that. Currently when a vlan device is created, its wanted_features is set to current features of its base device. The problem is that the base device can get new features and they are not propagated to vlan-s of this device. If we look at bonding devices, they doesn't have this problem and this patch suggests to fix this issue by the same way how it works for bonding devices. We meet this problem, when we try to create a vlan device over a bonding device. When a system are booting, real devices require time to be initialized, so bonding devices created without slaves, then vlan devices are created and only then ethernet devices are added to the bonding device. As a result we have vlan devices with disabled scatter-gather. * create a bonding device $ ip link add bond0 type bond $ ethtool -k bond0 | grep scatter scatter-gather: off tx-scatter-gather: off [requested on] tx-scatter-gather-fraglist: off [requested on] * create a vlan device $ ip link add link bond0 name bond0.10 type vlan id 10 $ ethtool -k bond0.10 | grep scatter scatter-gather: off tx-scatter-gather: off tx-scatter-gather-fraglist: off * Add a slave device to bond0 $ ip link set dev eth0 master bond0 And now we can see that the bond0 device has got the scatter-gather feature, but the bond0.10 hasn't got it. [root@laptop linux-task-diag]# ethtool -k bond0 | grep scatter scatter-gather: on tx-scatter-gather: on tx-scatter-gather-fraglist: on [root@laptop linux-task-diag]# ethtool -k bond0.10 | grep scatter scatter-gather: off tx-scatter-gather: off tx-scatter-gather-fraglist: off With this patch the vlan device will get all new features from the bonding device. Here is a call trace how features which are set in this patch reach dev->wanted_features. register_netdevice vlan_dev_init ... dev->hw_features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | NETIF_F_ALL_FCOE; dev->features |= dev->hw_features; ... dev->wanted_features = dev->features & dev->hw_features; __netdev_update_features(dev); vlan_dev_fix_features ... Cc: Alexey Kuznetsov Cc: Patrick McHardy Cc: "David S. Miller" Signed-off-by: Andrei Vagin Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/8021q/vlan_dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index fbfacd51aa34..767144128b95 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -562,8 +562,7 @@ static int vlan_dev_init(struct net_device *dev) NETIF_F_HIGHDMA | NETIF_F_SCTP_CRC | NETIF_F_ALL_FCOE; - dev->features |= real_dev->vlan_features | NETIF_F_LLTX | - NETIF_F_GSO_SOFTWARE; + dev->features |= dev->hw_features | NETIF_F_LLTX; dev->gso_max_size = real_dev->gso_max_size; dev->gso_max_segs = real_dev->gso_max_segs; if (dev->features & NETIF_F_VLAN_FEATURES) -- GitLab From 814e2b3462083ab336a4cc1d442f272ab8165d24 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 18 Mar 2017 17:40:01 +0100 Subject: [PATCH 0386/1834] ARM: dts: Adjust moxart IRQ controller and flags [ Upstream commit c2a736b698008d296c5010ec39077eeb5796109f ] The moxart interrupt line flags were not respected in previous driver: instead of assigning them per-consumer, a fixes mask was set in the controller. With the migration to a standard Faraday driver we need to set up and handle the consumer flags correctly. Also remove the Moxart-specific flags when switching to using real consumer flags. Extend the register window to 0x100 bytes as we may have a few more registers in there and it doesn't hurt. Tested-by: Jonas Jensen Signed-off-by: Jonas Jensen Signed-off-by: Linus Walleij Signed-off-by: Olof Johansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/moxart-uc7112lx.dts | 2 +- arch/arm/boot/dts/moxart.dtsi | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/moxart-uc7112lx.dts b/arch/arm/boot/dts/moxart-uc7112lx.dts index 10d088df0c35..4a962a26482d 100644 --- a/arch/arm/boot/dts/moxart-uc7112lx.dts +++ b/arch/arm/boot/dts/moxart-uc7112lx.dts @@ -6,7 +6,7 @@ */ /dts-v1/; -/include/ "moxart.dtsi" +#include "moxart.dtsi" / { model = "MOXA UC-7112-LX"; diff --git a/arch/arm/boot/dts/moxart.dtsi b/arch/arm/boot/dts/moxart.dtsi index 1fd27ed65a01..64f2f44235d0 100644 --- a/arch/arm/boot/dts/moxart.dtsi +++ b/arch/arm/boot/dts/moxart.dtsi @@ -6,6 +6,7 @@ */ /include/ "skeleton.dtsi" +#include / { compatible = "moxa,moxart"; @@ -36,8 +37,8 @@ ranges; intc: interrupt-controller@98800000 { - compatible = "moxa,moxart-ic"; - reg = <0x98800000 0x38>; + compatible = "moxa,moxart-ic", "faraday,ftintc010"; + reg = <0x98800000 0x100>; interrupt-controller; #interrupt-cells = <2>; interrupt-mask = <0x00080000>; @@ -59,7 +60,7 @@ timer: timer@98400000 { compatible = "moxa,moxart-timer"; reg = <0x98400000 0x42>; - interrupts = <19 1>; + interrupts = <19 IRQ_TYPE_EDGE_FALLING>; clocks = <&clk_apb>; }; @@ -80,7 +81,7 @@ dma: dma@90500000 { compatible = "moxa,moxart-dma"; reg = <0x90500080 0x40>; - interrupts = <24 0>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH>; #dma-cells = <1>; }; @@ -93,7 +94,7 @@ sdhci: sdhci@98e00000 { compatible = "moxa,moxart-sdhci"; reg = <0x98e00000 0x5C>; - interrupts = <5 0>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; clocks = <&clk_apb>; dmas = <&dma 5>, <&dma 5>; @@ -120,7 +121,7 @@ mac0: mac@90900000 { compatible = "moxa,moxart-mac"; reg = <0x90900000 0x90>; - interrupts = <25 0>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH>; phy-handle = <ðphy0>; phy-mode = "mii"; status = "disabled"; @@ -129,7 +130,7 @@ mac1: mac@92000000 { compatible = "moxa,moxart-mac"; reg = <0x92000000 0x90>; - interrupts = <27 0>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH>; phy-handle = <ðphy1>; phy-mode = "mii"; status = "disabled"; @@ -138,7 +139,7 @@ uart0: uart@98200000 { compatible = "ns16550a"; reg = <0x98200000 0x20>; - interrupts = <31 8>; + interrupts = <31 IRQ_TYPE_LEVEL_HIGH>; reg-shift = <2>; reg-io-width = <4>; clock-frequency = <14745600>; -- GitLab From 82ca25fbd07c8572526ef6e584c09a4260b610c3 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Sun, 19 Mar 2017 13:08:20 +0200 Subject: [PATCH 0387/1834] qed: Always publish VF link from leading hwfn [ Upstream commit e50728effe1126eae39445ba144078b1305b7047 ] The link information exists only on the leading hwfn, but some of its derivatives [e.g., min/max rate] need to be configured for each hwfn. When re-basing the VF link view, use the leading hwfn information as basis for all existing hwfns to allow said configurations to stick. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_sriov.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_sriov.c b/drivers/net/ethernet/qlogic/qed/qed_sriov.c index d2d6621fe0e5..48bc5c151336 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sriov.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sriov.c @@ -3573,6 +3573,7 @@ static int qed_get_vf_config(struct qed_dev *cdev, void qed_inform_vf_link_state(struct qed_hwfn *hwfn) { + struct qed_hwfn *lead_hwfn = QED_LEADING_HWFN(hwfn->cdev); struct qed_mcp_link_capabilities caps; struct qed_mcp_link_params params; struct qed_mcp_link_state link; @@ -3589,9 +3590,15 @@ void qed_inform_vf_link_state(struct qed_hwfn *hwfn) if (!vf_info) continue; - memcpy(¶ms, qed_mcp_get_link_params(hwfn), sizeof(params)); - memcpy(&link, qed_mcp_get_link_state(hwfn), sizeof(link)); - memcpy(&caps, qed_mcp_get_link_capabilities(hwfn), + /* Only hwfn0 is actually interested in the link speed. + * But since only it would receive an MFW indication of link, + * need to take configuration from it - otherwise things like + * rate limiting for hwfn1 VF would not work. + */ + memcpy(¶ms, qed_mcp_get_link_params(lead_hwfn), + sizeof(params)); + memcpy(&link, qed_mcp_get_link_state(lead_hwfn), sizeof(link)); + memcpy(&caps, qed_mcp_get_link_capabilities(lead_hwfn), sizeof(caps)); /* Modify link according to the VF's configured link state */ -- GitLab From 58a1452cef23409aa42b67acf5c3e4284f88dba3 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 13 Mar 2017 13:36:10 +0100 Subject: [PATCH 0388/1834] s390/topology: fix typo in early topology code [ Upstream commit 4fd4dd8bffb112d1e6549e0ff09e9fa3c8cc2b96 ] Use MACHINE_FLAG_TOPOLOGY instead of MACHINE_HAS_TOPOLOGY when clearing the bit that indicates if the machine provides topology information (and if it should be used). Currently works anyway. Fixes: 68cc795d1933 ("s390/topology: make "topology=off" parameter work") Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/early.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 29d87444a655..62578989c74d 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -372,7 +372,7 @@ static int __init topology_setup(char *str) rc = kstrtobool(str, &enabled); if (!rc && !enabled) - S390_lowcore.machine_flags &= ~MACHINE_HAS_TOPOLOGY; + S390_lowcore.machine_flags &= ~MACHINE_FLAG_TOPOLOGY; return rc; } early_param("topology", topology_setup); -- GitLab From 84f876e346377a3ff16775781879981d8eb1aaf6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Mon, 13 Mar 2017 13:44:21 +0100 Subject: [PATCH 0389/1834] zd1211rw: fix NULL-deref at probe [ Upstream commit ca260ece6a57dc7d751e0685f51fa2c55d851873 ] Make sure to check the number of endpoints to avoid dereferencing a NULL-pointer or accessing memory beyond the endpoint array should a malicious device lack the expected endpoints. Fixes: a1030e92c150 ("[PATCH] zd1211rw: Convert installer CDROM device into WLAN device") Cc: Daniel Drake Signed-off-by: Johan Hovold Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/zydas/zd1211rw/zd_usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index c5effd6c6be9..01ca1d57b3d9 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -1278,6 +1278,9 @@ static int eject_installer(struct usb_interface *intf) u8 bulk_out_ep; int r; + if (iface_desc->desc.bNumEndpoints < 2) + return -ENODEV; + /* Find bulk out endpoint */ for (r = 1; r >= 0; r--) { endpoint = &iface_desc->endpoint[r].desc; -- GitLab From 1fb9c2f41e199e97b811981901d9de4a9d7729bf Mon Sep 17 00:00:00 2001 From: Andreas Pape Date: Mon, 5 Sep 2016 13:20:29 +0200 Subject: [PATCH 0390/1834] batman-adv: handle race condition for claims between gateways [ Upstream commit a3a5129e122709306cfa6409781716c2933df99b ] Consider the following situation which has been found in a test setup: Gateway B has claimed client C and gateway A has the same backbone network as B. C sends a broad- or multicast to B and directly after this packet decides to send another packet to A due to a better TQ value. B will forward the broad-/multicast into the backbone as it is the responsible gw and after that A will claim C as it has been chosen by C as the best gateway. If it now happens that A claims C before it has received the broad-/multicast forwarded by B (due to backbone topology or due to some delay in B when forwarding the packet) we get a critical situation: in the current code A will immediately unclaim C when receiving the multicast due to the roaming client scenario although the position of C has not changed in the mesh. If this happens the multi-/broadcast forwarded by B will be sent back into the mesh by A and we have looping packets until one of the gateways claims C again. In order to prevent this, unclaiming of a client due to the roaming client scenario is only done after a certain time is expired after the last claim of the client. 100 ms are used here, which should be slow enough for big backbones and slow gateways but fast enough not to break the roaming client use case. Acked-by: Simon Wunderlich Signed-off-by: Andreas Pape [sven@narfation.org: fix conflicts with current version] Signed-off-by: Sven Eckelmann Signed-off-by: Simon Wunderlich Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/batman-adv/bridge_loop_avoidance.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index e7f690b571ea..5419b1214abd 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -1964,10 +1964,22 @@ bool batadv_bla_tx(struct batadv_priv *bat_priv, struct sk_buff *skb, /* if yes, the client has roamed and we have * to unclaim it. */ - batadv_handle_unclaim(bat_priv, primary_if, - primary_if->net_dev->dev_addr, - ethhdr->h_source, vid); - goto allow; + if (batadv_has_timed_out(claim->lasttime, 100)) { + /* only unclaim if the last claim entry is + * older than 100 ms to make sure we really + * have a roaming client here. + */ + batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_tx(): Roaming client %pM detected. Unclaim it.\n", + ethhdr->h_source); + batadv_handle_unclaim(bat_priv, primary_if, + primary_if->net_dev->dev_addr, + ethhdr->h_source, vid); + goto allow; + } else { + batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla_tx(): Race for claim %pM detected. Drop packet.\n", + ethhdr->h_source); + goto handled; + } } /* check if it is a multicast/broadcast frame */ -- GitLab From 6ba32c648a9fc27993330632e84c4cbdceef5d57 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 16 Jan 2017 14:28:39 -0600 Subject: [PATCH 0391/1834] of: fix of_device_get_modalias returned length when truncating buffers [ Upstream commit bcf54d5385abaea9c8026aae6f4eeb348671a52d ] If the length of the modalias is greater than the buffer size, then the modalias is truncated. However the untruncated length is returned which will cause an error. Fix this to return the truncated length. If an error in the case was desired, then then we should just return -ENOMEM. The reality is no device will ever have 4KB of compatible strings to hit this case. Signed-off-by: Rob Herring Cc: Frank Rowand Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/of/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index f7a970120055..3cda60c036f9 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -223,7 +223,7 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) str[i] = '_'; } - return tsize; + return repend; } EXPORT_SYMBOL_GPL(of_device_get_modalias); -- GitLab From 078c1a50e189829e0279764f245970a3d2b461fd Mon Sep 17 00:00:00 2001 From: Anton Sviridenko Date: Thu, 9 Mar 2017 10:46:18 -0300 Subject: [PATCH 0392/1834] solo6x10: release vb2 buffers in solo_stop_streaming() [ Upstream commit 6e4c8480bd2eb95309ad3c875e11d2cad98f9188 ] Fixes warning that appears in dmesg after closing V4L2 userspace application that plays video from the display device (first device from V4L2 device nodes provided by solo, usually /dev/video0 when no other V4L2 devices are present). Encoder device nodes are not affected. Can be reproduced by starting and closing ffplay -f video4linux2 /dev/video0 [ 8130.281251] ------------[ cut here ]------------ [ 8130.281256] WARNING: CPU: 1 PID: 20414 at drivers/media/v4l2-core/videobuf2-core.c:1651 __vb2_queue_cancel+0x14b/0x230 [ 8130.281257] Modules linked in: ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat solo6x10 x86_pkg_temp_thermal vboxpci(O) vboxnetadp(O) vboxnetflt(O) vboxdrv(O) [ 8130.281264] CPU: 1 PID: 20414 Comm: ffplay Tainted: G O 4.10.0-gentoo #1 [ 8130.281264] Hardware name: ASUS All Series/B85M-E, BIOS 2301 03/30/2015 [ 8130.281265] Call Trace: [ 8130.281267] dump_stack+0x4f/0x72 [ 8130.281270] __warn+0xc7/0xf0 [ 8130.281271] warn_slowpath_null+0x18/0x20 [ 8130.281272] __vb2_queue_cancel+0x14b/0x230 [ 8130.281273] vb2_core_streamoff+0x23/0x90 [ 8130.281275] vb2_streamoff+0x24/0x50 [ 8130.281276] vb2_ioctl_streamoff+0x3d/0x50 [ 8130.281278] v4l_streamoff+0x15/0x20 [ 8130.281279] __video_do_ioctl+0x25e/0x2f0 [ 8130.281280] video_usercopy+0x279/0x520 [ 8130.281282] ? v4l_enum_fmt+0x1330/0x1330 [ 8130.281285] ? unmap_region+0xdf/0x110 [ 8130.281285] video_ioctl2+0x10/0x20 [ 8130.281286] v4l2_ioctl+0xce/0xe0 [ 8130.281289] do_vfs_ioctl+0x8b/0x5b0 [ 8130.281290] ? __fget+0x72/0xa0 [ 8130.281291] SyS_ioctl+0x74/0x80 [ 8130.281294] entry_SYSCALL_64_fastpath+0x13/0x94 [ 8130.281295] RIP: 0033:0x7ff86fee6b27 [ 8130.281296] RSP: 002b:00007ffe467f6a08 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 8130.281297] RAX: ffffffffffffffda RBX: 00000000d1a4d788 RCX: 00007ff86fee6b27 [ 8130.281297] RDX: 00007ffe467f6a14 RSI: 0000000040045613 RDI: 0000000000000006 [ 8130.281298] RBP: 000000000373f8d0 R08: 00000000ffffffff R09: 00007ff860001140 [ 8130.281298] R10: 0000000000000243 R11: 0000000000000246 R12: 0000000000000000 [ 8130.281299] R13: 00000000000000a0 R14: 00007ffe467f6530 R15: 0000000001f32228 [ 8130.281300] ---[ end trace 00695dc96be646e7 ]--- Signed-off-by: Anton Sviridenko Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/solo6x10/solo6x10-v4l2.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index b4be47969b6b..e17d6b945c07 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -341,6 +341,17 @@ static void solo_stop_streaming(struct vb2_queue *q) struct solo_dev *solo_dev = vb2_get_drv_priv(q); solo_stop_thread(solo_dev); + + spin_lock(&solo_dev->slock); + while (!list_empty(&solo_dev->vidq_active)) { + struct solo_vb2_buf *buf = list_entry( + solo_dev->vidq_active.next, + struct solo_vb2_buf, list); + + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + spin_unlock(&solo_dev->slock); INIT_LIST_HEAD(&solo_dev->vidq_active); } -- GitLab From 86b684fcd6fe24586263e978aba79d136511f0b8 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 22 Mar 2017 14:32:32 -0700 Subject: [PATCH 0393/1834] x86/boot/32: Defer resyncing initial_page_table until per-cpu is set up [ Upstream commit 23b2a4ddebdd17fad265b4bb77256c2e4ec37dee ] The x86 smpboot trampoline expects initial_page_table to have the GDT mapped. If the GDT ends up in a virtually mapped per-cpu page, then it won't be in the page tables at all until perc-pu areas are set up. The result will be a triple fault the first time that the CPU attempts to access the GDT after LGDT loads the perc-pu GDT. This appears to be an old bug, but somehow the GDT fixmap rework is triggering it. This seems to have something to do with the memory layout. Signed-off-by: Andy Lutomirski Cc: Ard Biesheuvel Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Garnier Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/a553264a5972c6a86f9b5caac237470a0c74a720.1490218061.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/setup.c | 15 --------------- arch/x86/kernel/setup_percpu.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 6b55012d02a3..d1a214287fe3 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1200,21 +1200,6 @@ void __init setup_arch(char **cmdline_p) kasan_init(); -#ifdef CONFIG_X86_32 - /* sync back kernel address range */ - clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, - swapper_pg_dir + KERNEL_PGD_BOUNDARY, - KERNEL_PGD_PTRS); - - /* - * sync back low identity map too. It is used for example - * in the 32-bit EFI stub. - */ - clone_pgd_range(initial_page_table, - swapper_pg_dir + KERNEL_PGD_BOUNDARY, - min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); -#endif - tboot_probe(); map_vsyscall(); diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 2bbd27f89802..bbba27269fdd 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -287,4 +287,25 @@ void __init setup_per_cpu_areas(void) /* Setup cpu initialized, callin, callout masks */ setup_cpu_local_masks(); + +#ifdef CONFIG_X86_32 + /* + * Sync back kernel address range. We want to make sure that + * all kernel mappings, including percpu mappings, are available + * in the smpboot asm. We can't reliably pick up percpu + * mappings using vmalloc_fault(), because exception dispatch + * needs percpu data. + */ + clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + + /* + * sync back low identity map too. It is used for example + * in the 32-bit EFI stub. + */ + clone_pgd_range(initial_page_table, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); +#endif } -- GitLab From 3dda4b42a8f971d3d3896f14ca5f7185a29ae067 Mon Sep 17 00:00:00 2001 From: Satish Kharat Date: Tue, 28 Feb 2017 16:14:56 -0800 Subject: [PATCH 0394/1834] scsi: fnic: Fix for "Number of Active IOs" in fnicstats becoming negative [ Upstream commit 7ef539c88d7d394410d547c9f082d477093a2a22 ] Fixing the IO stats update (Active IOs and IO completion) to prevent "Number of Active IOs" from becoming negative in the fnistats output. Signed-off-by: Satish Kharat Signed-off-by: Sesidhar Baddela Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/fnic/fnic_scsi.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 44dd372aa7d3..c056b8111ad2 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1127,12 +1127,6 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, else CMD_ABTS_STATUS(sc) = hdr_status; - atomic64_dec(&fnic_stats->io_stats.active_ios); - if (atomic64_read(&fnic->io_cmpl_skip)) - atomic64_dec(&fnic->io_cmpl_skip); - else - atomic64_inc(&fnic_stats->io_stats.io_completions); - if (!(CMD_FLAGS(sc) & (FNIC_IO_ABORTED | FNIC_IO_DONE))) atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls); @@ -1173,6 +1167,11 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, (((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc))); sc->scsi_done(sc); + atomic64_dec(&fnic_stats->io_stats.active_ios); + if (atomic64_read(&fnic->io_cmpl_skip)) + atomic64_dec(&fnic->io_cmpl_skip); + else + atomic64_inc(&fnic_stats->io_stats.io_completions); } } @@ -1962,6 +1961,11 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) /* Call SCSI completion function to complete the IO */ sc->result = (DID_ABORT << 16); sc->scsi_done(sc); + atomic64_dec(&fnic_stats->io_stats.active_ios); + if (atomic64_read(&fnic->io_cmpl_skip)) + atomic64_dec(&fnic->io_cmpl_skip); + else + atomic64_inc(&fnic_stats->io_stats.io_completions); } fnic_abort_cmd_end: -- GitLab From 2f1b0a81b1b39e8eb2a79b667fc17bf76f24b788 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 15 Mar 2017 16:58:36 -0500 Subject: [PATCH 0395/1834] scsi: ipr: Fix missed EH wakeup [ Upstream commit 66a0d59cdd12546ddf01d229de28b07ccf6d637f ] Following a command abort or device reset, ipr's EH handlers wait for the commands getting aborted to get sent back from the adapter prior to returning from the EH handler. This fixes up some cases where the completion handler was not getting called, which would have resulted in the EH thread waiting until it timed out, greatly extending EH time. Signed-off-by: Brian King Reviewed-by: Wendy Xiong Tested-by: Wendy Xiong Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ipr.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 532474109624..c5bc41d97f84 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -836,8 +836,10 @@ static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) qc->err_mask |= AC_ERR_OTHER; sata_port->ioasa.status |= ATA_BUSY; - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); ata_qc_complete(qc); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -5947,8 +5949,10 @@ static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) res->in_erp = 0; } scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -6338,8 +6342,10 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, } scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); } /** @@ -6365,8 +6371,10 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) scsi_dma_unmap(scsi_cmd); spin_lock_irqsave(ipr_cmd->hrrq->lock, lock_flags); - list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); scsi_cmd->scsi_done(scsi_cmd); + if (ipr_cmd->eh_comp) + complete(ipr_cmd->eh_comp); + list_add_tail(&ipr_cmd->queue, &ipr_cmd->hrrq->hrrq_free_q); spin_unlock_irqrestore(ipr_cmd->hrrq->lock, lock_flags); } else { spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); -- GitLab From bc88d1bee232c2a514877dd078ed2fd42cde959f Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Wed, 15 Jun 2016 19:29:50 -0300 Subject: [PATCH 0396/1834] media: i2c/soc_camera: fix ov6650 sensor getting wrong clock [ Upstream commit 54449af0e0b2ea43a8166611c95b730c850c3184 ] After changes to v4l2_clk API introduced in v4.1 by commits a37462b919 '[media] V4L: remove clock name from v4l2_clk API' and 4f528afcfb '[media] V4L: add CCF support to the v4l2_clk API', ov6650 sensor stopped responding because v4l2_clk_get(), still called with depreciated V4L2 clock name "mclk", started to return respective CCF clock instead of the V4l2 one registered by soc_camera. Fix it by calling v4l2_clk_get() with NULL clock name. Created and tested on Amstrad Delta against Linux-4.7-rc3 with omap1_camera fixes. Signed-off-by: Janusz Krzysztofik Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/soc_camera/ov6650.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 4bf2995e1cb8..8f85910eda5d 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -1033,7 +1033,7 @@ static int ov6650_probe(struct i2c_client *client, priv->code = MEDIA_BUS_FMT_YUYV8_2X8; priv->colorspace = V4L2_COLORSPACE_JPEG; - priv->clk = v4l2_clk_get(&client->dev, "mclk"); + priv->clk = v4l2_clk_get(&client->dev, NULL); if (IS_ERR(priv->clk)) { ret = PTR_ERR(priv->clk); goto eclkget; -- GitLab From ae0258a81896f9a26b1a84102fe71dd71662b727 Mon Sep 17 00:00:00 2001 From: David Engraf Date: Fri, 17 Feb 2017 08:51:03 +0100 Subject: [PATCH 0397/1834] timers, sched_clock: Update timeout for clock wrap [ Upstream commit 1b8955bc5ac575009835e371ae55e7f3af2197a9 ] The scheduler clock framework may not use the correct timeout for the clock wrap. This happens when a new clock driver calls sched_clock_register() after the kernel called sched_clock_postinit(). In this case the clock wrap timeout is too long thus sched_clock_poll() is called too late and the clock already wrapped. On my ARM system the scheduler was no longer scheduling any other task than the idle task because the sched_clock() wrapped. Signed-off-by: David Engraf Signed-off-by: John Stultz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/time/sched_clock.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c index a26036d37a38..382b159d8592 100644 --- a/kernel/time/sched_clock.c +++ b/kernel/time/sched_clock.c @@ -205,6 +205,11 @@ sched_clock_register(u64 (*read)(void), int bits, unsigned long rate) update_clock_read_data(&rd); + if (sched_clock_timer.function != NULL) { + /* update timeout for clock wrap */ + hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL); + } + r = rate; if (r >= 4000000) { r /= 1000000; -- GitLab From 00c001fbdad55884d4316f528ffc6a0017ca88dd Mon Sep 17 00:00:00 2001 From: Tom Hromatka Date: Wed, 4 Jan 2017 15:28:04 -0700 Subject: [PATCH 0398/1834] sysrq: Reset the watchdog timers while displaying high-resolution timers [ Upstream commit 0107042768658fea9f5f5a9c00b1c90f5dab6a06 ] On systems with a large number of CPUs, running sysrq- can cause watchdog timeouts. There are two slow sections of code in the sysrq- path in timer_list.c. 1. print_active_timers() - This function is called by print_cpu() and contains a slow goto loop. On a machine with hundreds of CPUs, this loop took approximately 100ms for the first CPU in a NUMA node. (Subsequent CPUs in the same node ran much quicker.) The total time to print all of the CPUs is ultimately long enough to trigger the soft lockup watchdog. 2. print_tickdevice() - This function outputs a large amount of textual information. This function also took approximately 100ms per CPU. Since sysrq- is not a performance critical path, there should be no harm in touching the nmi watchdog in both slow sections above. Touching it in just one location was insufficient on systems with hundreds of CPUs as occasional timeouts were still observed during testing. This issue was observed on an Oracle T7 machine with 128 CPUs, but I anticipate it may affect other systems with similarly large numbers of CPUs. Signed-off-by: Tom Hromatka Reviewed-by: Rob Gardner Signed-off-by: John Stultz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/time/timer_list.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index ba7d8b288bb3..ef4f16e81283 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -96,6 +97,9 @@ print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, next_one: i = 0; + + touch_nmi_watchdog(); + raw_spin_lock_irqsave(&base->cpu_base->lock, flags); curr = timerqueue_getnext(&base->active); @@ -207,6 +211,8 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu) { struct clock_event_device *dev = td->evtdev; + touch_nmi_watchdog(); + SEQ_printf(m, "Tick Device: mode: %d\n", td->mode); if (cpu < 0) SEQ_printf(m, "Broadcast device\n"); -- GitLab From 997de25b0aa87077afd340d4f7aae9903ac8fb6d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 23 Mar 2017 13:33:12 -0700 Subject: [PATCH 0399/1834] Input: qt1070 - add OF device ID table [ Upstream commit cf5cd9d4480a87da78768718cac194a71079b5cb ] The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. The compatible strings don't have a vendor prefix because that's how it's used currently, and changing this will be a Device Tree ABI break. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/keyboard/qt1070.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index 5a5778729e37..76bb51309a78 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -274,9 +274,18 @@ static const struct i2c_device_id qt1070_id[] = { }; MODULE_DEVICE_TABLE(i2c, qt1070_id); +#ifdef CONFIG_OF +static const struct of_device_id qt1070_of_match[] = { + { .compatible = "qt1070", }, + { }, +}; +MODULE_DEVICE_TABLE(of, qt1070_of_match); +#endif + static struct i2c_driver qt1070_driver = { .driver = { .name = "qt1070", + .of_match_table = of_match_ptr(qt1070_of_match), .pm = &qt1070_pm_ops, }, .id_table = qt1070_id, -- GitLab From ae34475dfc0d6ad8c0b5cb25ab43a612ef223fb6 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 23 Mar 2017 10:39:40 +0100 Subject: [PATCH 0400/1834] sched: act_csum: don't mangle TCP and UDP GSO packets [ Upstream commit add641e7dee31b36aee83412c29e39dd1f5e0c9c ] after act_csum computes the checksum on skbs carrying GSO TCP/UDP packets, subsequent segmentation fails because skb_needs_check(skb, true) returns true. Because of that, skb_warn_bad_offload() is invoked and the following message is displayed: WARNING: CPU: 3 PID: 28 at net/core/dev.c:2553 skb_warn_bad_offload+0xf0/0xfd <...> [] skb_warn_bad_offload+0xf0/0xfd [] __skb_gso_segment+0xec/0x110 [] validate_xmit_skb+0x12d/0x2b0 [] validate_xmit_skb_list+0x42/0x70 [] sch_direct_xmit+0xd0/0x1b0 [] __qdisc_run+0x120/0x270 [] __dev_queue_xmit+0x23d/0x690 [] dev_queue_xmit+0x10/0x20 Since GSO is able to compute checksum on individual segments of such skbs, we can simply skip mangling the packet. Signed-off-by: Davide Caratti Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sched/act_csum.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index e0defcef376d..24a0c66394a0 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -180,6 +180,9 @@ static int tcf_csum_ipv4_tcp(struct sk_buff *skb, unsigned int ihl, struct tcphdr *tcph; const struct iphdr *iph; + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) + return 1; + tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); if (tcph == NULL) return 0; @@ -201,6 +204,9 @@ static int tcf_csum_ipv6_tcp(struct sk_buff *skb, unsigned int ihl, struct tcphdr *tcph; const struct ipv6hdr *ip6h; + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) + return 1; + tcph = tcf_csum_skb_nextlayer(skb, ihl, ipl, sizeof(*tcph)); if (tcph == NULL) return 0; @@ -224,6 +230,9 @@ static int tcf_csum_ipv4_udp(struct sk_buff *skb, unsigned int ihl, const struct iphdr *iph; u16 ul; + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP) + return 1; + /* * Support both UDP and UDPLITE checksum algorithms, Don't use * udph->len to get the real length without any protocol check, @@ -277,6 +286,9 @@ static int tcf_csum_ipv6_udp(struct sk_buff *skb, unsigned int ihl, const struct ipv6hdr *ip6h; u16 ul; + if (skb_is_gso(skb) && skb_shinfo(skb)->gso_type & SKB_GSO_UDP) + return 1; + /* * Support both UDP and UDPLITE checksum algorithms, Don't use * udph->len to get the real length without any protocol check, -- GitLab From fd15bade786ee8d2db6fe45b5b7784a1ec9ca2b7 Mon Sep 17 00:00:00 2001 From: Long Li Date: Thu, 23 Mar 2017 14:58:10 -0700 Subject: [PATCH 0401/1834] PCI: hv: Properly handle PCI bus remove [ Upstream commit d3a78d8bf759d8848339dcc367c4c1678b57a08b ] hv_pci_devices_present() is called in hv_pci_remove() when we remove a PCI device from the host, e.g., by disabling SR-IOV on a device. In hv_pci_remove(), the bus is already removed before the call, so we don't need to rescan the bus in the workqueue scheduled from hv_pci_devices_present(). By introducing bus state hv_pcibus_removed, we can avoid this situation. Reported-by: Xiaofeng Wang Signed-off-by: Long Li Signed-off-by: Bjorn Helgaas Acked-by: K. Y. Srinivasan Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-hyperv.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index dafb4cdb2b7f..43aa630f419a 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -351,6 +351,7 @@ enum hv_pcibus_state { hv_pcibus_init = 0, hv_pcibus_probed, hv_pcibus_installed, + hv_pcibus_removed, hv_pcibus_maximum }; @@ -1489,13 +1490,24 @@ static void pci_devices_present_work(struct work_struct *work) put_pcichild(hpdev, hv_pcidev_ref_initial); } - /* Tell the core to rescan bus because there may have been changes. */ - if (hbus->state == hv_pcibus_installed) { + switch(hbus->state) { + case hv_pcibus_installed: + /* + * Tell the core to rescan bus + * because there may have been changes. + */ pci_lock_rescan_remove(); pci_scan_child_bus(hbus->pci_bus); pci_unlock_rescan_remove(); - } else { + break; + + case hv_pcibus_init: + case hv_pcibus_probed: survey_child_resources(hbus); + break; + + default: + break; } up(&hbus->enum_sem); @@ -2170,6 +2182,7 @@ static int hv_pci_probe(struct hv_device *hdev, hbus = kzalloc(sizeof(*hbus), GFP_KERNEL); if (!hbus) return -ENOMEM; + hbus->state = hv_pcibus_init; /* * The PCI bus "domain" is what is called "segment" in ACPI and @@ -2312,6 +2325,7 @@ static int hv_pci_remove(struct hv_device *hdev) pci_stop_root_bus(hbus->pci_bus); pci_remove_root_bus(hbus->pci_bus); pci_unlock_rescan_remove(); + hbus->state = hv_pcibus_removed; } ret = hv_send_resources_released(hdev); -- GitLab From 422fcc97747961709f9faa97b5d1f3f4305b67b8 Mon Sep 17 00:00:00 2001 From: Long Li Date: Thu, 23 Mar 2017 14:58:32 -0700 Subject: [PATCH 0402/1834] PCI: hv: Lock PCI bus on device eject [ Upstream commit 414428c5da1c71986727c2fa5cdf1ed071e398d7 ] A PCI_EJECT message can arrive at the same time we are calling pci_scan_child_bus() in the workqueue for the previous PCI_BUS_RELATIONS message or in create_root_hv_pci_bus(). In this case we could potentially modify the bus from multiple places. Properly lock the bus access. Thanks Dexuan Cui for pointing out the race condition in create_root_hv_pci_bus(). Reported-by: Xiaofeng Wang Signed-off-by: Long Li Signed-off-by: Bjorn Helgaas Acked-by: K. Y. Srinivasan Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/host/pci-hyperv.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 43aa630f419a..d392a55ec0a9 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -1206,9 +1206,11 @@ static int create_root_hv_pci_bus(struct hv_pcibus_device *hbus) hbus->pci_bus->msi = &hbus->msi_chip; hbus->pci_bus->msi->dev = &hbus->hdev->device; + pci_lock_rescan_remove(); pci_scan_child_bus(hbus->pci_bus); pci_bus_assign_resources(hbus->pci_bus); pci_bus_add_devices(hbus->pci_bus); + pci_unlock_rescan_remove(); hbus->state = hv_pcibus_installed; return 0; } @@ -1597,8 +1599,10 @@ static void hv_eject_device_work(struct work_struct *work) pdev = pci_get_domain_bus_and_slot(hpdev->hbus->sysdata.domain, 0, wslot); if (pdev) { + pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(pdev); pci_dev_put(pdev); + pci_unlock_rescan_remove(); } memset(&ctxt, 0, sizeof(ctxt)); -- GitLab From 28fdd86eb53f36eea98de4cd50441f92d60281c9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 22 Mar 2017 04:02:43 +0000 Subject: [PATCH 0403/1834] ASoC: rcar: ssi: don't set SSICR.CKDV = 000 with SSIWSR.CONT [ Upstream commit 6b8530cc056efd4a11b034ca5b1e9f7e9563f553 ] R-Car Datasheet is indicating "SSICR.CKDV = 000 is invalid when SSIWSR.WS_MODE = 1 or SSIWSR.CONT = 1". Current driver will set CONT, thus, we shouldn't use CKDV = 000. This patch fixup it. Reported-by: Hiroyuki Yokoyama Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/sh/rcar/ssi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index a9a43acce30e..fefa6ad5de8b 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -232,6 +232,15 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, */ for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { + /* + * It will set SSIWSR.CONT here, but SSICR.CKDV = 000 + * with it is not allowed. (SSIWSR.WS_MODE with + * SSICR.CKDV = 000 is not allowed either). + * Skip it. See SSICR.CKDV + */ + if (j == 0) + continue; + /* * this driver is assuming that * system word is 32bit x chan -- GitLab From 84353d9d99cf6793f6f28e948f2973681d63806c Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 22 Mar 2017 09:18:26 +0900 Subject: [PATCH 0404/1834] spi: omap2-mcspi: poll OMAP2_MCSPI_CHSTAT_RXS for PIO transfer [ Upstream commit 812613591cb652344186c4cd912304ed02138566 ] When running the spi-loopback-test with slower clock rate like 10 KHz, the test for 251 bytes transfer was failed. This failure triggered an spi-omap2-mcspi's error message "DMA RX last word empty". This message means that PIO for reading the remaining bytes due to the DMA transfer length reduction is failed. This problem can be fixed by polling OMAP2_MCSPI_CHSTAT_RXS bit in channel status register to wait until the receive buffer register is filled. Cc: Mark Brown Signed-off-by: Akinobu Mita Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-omap2-mcspi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index d5157b2222ce..a47cf638460a 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -454,6 +454,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, int elements = 0; int word_len, element_count; struct omap2_mcspi_cs *cs = spi->controller_state; + void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; + mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; count = xfer->len; @@ -549,8 +551,8 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, if (l & OMAP2_MCSPI_CHCONF_TURBO) { elements--; - if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { + if (!mcspi_wait_for_reg_bit(chstat_reg, + OMAP2_MCSPI_CHSTAT_RXS)) { u32 w; w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); @@ -568,8 +570,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, return count; } } - if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) - & OMAP2_MCSPI_CHSTAT_RXS)) { + if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) { u32 w; w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); -- GitLab From 694f219a606f80811ea384044b9845c80d688bb3 Mon Sep 17 00:00:00 2001 From: Gao Feng Date: Fri, 24 Mar 2017 07:05:12 +0800 Subject: [PATCH 0405/1834] tcp: sysctl: Fix a race to avoid unexpected 0 window from space [ Upstream commit c48367427a39ea0b85c7cf018fe4256627abfd9e ] Because sysctl_tcp_adv_win_scale could be changed any time, so there is one race in tcp_win_from_space. For example, 1.sysctl_tcp_adv_win_scale<=0 (sysctl_tcp_adv_win_scale is negative now) 2.space>>(-sysctl_tcp_adv_win_scale) (sysctl_tcp_adv_win_scale is postive now) As a result, tcp_win_from_space returns 0. It is unexpected. Certainly if the compiler put the sysctl_tcp_adv_win_scale into one register firstly, then use the register directly, it would be ok. But we could not depend on the compiler behavior. Signed-off-by: Gao Feng Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/net/tcp.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index caf35e062639..18f029bcb8c7 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1265,9 +1265,11 @@ void tcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, static inline int tcp_win_from_space(int space) { - return sysctl_tcp_adv_win_scale<=0 ? - (space>>(-sysctl_tcp_adv_win_scale)) : - space - (space>>sysctl_tcp_adv_win_scale); + int tcp_adv_win_scale = sysctl_tcp_adv_win_scale; + + return tcp_adv_win_scale <= 0 ? + (space>>(-tcp_adv_win_scale)) : + space - (space>>tcp_adv_win_scale); } /* Note: caller must be prepared to deal with negative returns */ -- GitLab From 61ed2d27b87fe5b01fa867492e75495b96a41456 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Thu, 16 Mar 2017 23:12:09 -0700 Subject: [PATCH 0406/1834] dmaengine: imx-sdma: add 1ms delay to ensure SDMA channel is stopped [ Upstream commit 7f3ff14b7eb1ffad132117f08a1973b48e653d43 ] sdma_disable_channel() cannot ensure dma is stopped to access module's FIFOs. There is chance SDMA core is running and accessing BD when disable of corresponding channel, this may cause sometimes even after call of .sdma_disable_channel(), SDMA core still be running and accessing module's FIFOs. According to NXP R&D team a delay of one BD SDMA cost time (maximum is 1ms) should be added after disable of the channel bit, to ensure SDMA core has really been stopped after SDMA clients call .device_terminate_all. This patch introduces adds a new function sdma_disable_channel_with_delay() which simply adds 1ms delay after call sdma_disable_channel(), and set it as .device_terminate_all. Signed-off-by: Jiada Wang Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/dma/imx-sdma.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index d1651a50c349..21726a270fc4 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -937,6 +937,21 @@ static int sdma_disable_channel(struct dma_chan *chan) return 0; } +static int sdma_disable_channel_with_delay(struct dma_chan *chan) +{ + sdma_disable_channel(chan); + + /* + * According to NXP R&D team a delay of one BD SDMA cost time + * (maximum is 1ms) should be added after disable of the channel + * bit, to ensure SDMA core has really been stopped after SDMA + * clients call .device_terminate_all. + */ + mdelay(1); + + return 0; +} + static void sdma_set_watermarklevel_for_p2p(struct sdma_channel *sdmac) { struct sdma_engine *sdma = sdmac->sdma; @@ -1828,7 +1843,7 @@ static int sdma_probe(struct platform_device *pdev) sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg; sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic; sdma->dma_device.device_config = sdma_config; - sdma->dma_device.device_terminate_all = sdma_disable_channel; + sdma->dma_device.device_terminate_all = sdma_disable_channel_with_delay; sdma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); sdma->dma_device.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); sdma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); -- GitLab From c582696e096064d43d953fd576712d95fcab6702 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 3 Aug 2016 14:16:15 +0300 Subject: [PATCH 0407/1834] usb: dwc3: make sure UX_EXIT_PX is cleared [ Upstream commit 1966b8657d058ecb95031809b607bf3fd1e01c10 ] This bit is only supposed to be used with known buggy PHYs, however some platforms might erroneously set it. In order to avoid it, let's make sure this bit is always cleared. If some PHY needs this, we will need to add a quirk flag. Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.c | 6 ++++++ drivers/usb/dwc3/core.h | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index fea446900cad..a0c2b8b6edd0 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -463,6 +463,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)); + /* + * Make sure UX_EXIT_PX is cleared as that causes issues with some + * PHYs. Also, this bit is not supposed to be used in normal operation. + */ + reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX; + /* * Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY * to '0' during coreConsultant configuration. So default value diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 884c43714456..bc3678e9dcb1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -223,6 +223,7 @@ #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) #define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29) #define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28) +#define DWC3_GUSB3PIPECTL_UX_EXIT_PX (1 << 27) #define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24) #define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19) #define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7) -- GitLab From 9ad2abe6d02c34d7212cead081a7c4b9155be46e Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Mon, 30 Jan 2017 20:44:39 +0200 Subject: [PATCH 0408/1834] ARM: dts: bcm2835: add index to the ethernet alias [ Upstream commit 10b6c0c2e2bb8cd1be682f8d36ef597e3419cb88 ] An alias name should have an index number even when it is the only of its type. This allows U-Boot to add the local-mac-address property. Otherwise U-Boot skips the alias. Fixes: 6a93792774 ("ARM: bcm2835: dt: Add the ethernet to the device trees") Signed-off-by: Baruch Siach Acked-by: Lubomir Rintel Reviewed-by: Eric Anholt Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi | 2 +- arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi b/arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi index 12c981e51134..9a0599f711ff 100644 --- a/arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi +++ b/arch/arm/boot/dts/bcm283x-rpi-smsc9512.dtsi @@ -1,6 +1,6 @@ / { aliases { - ethernet = ðernet; + ethernet0 = ðernet; }; }; diff --git a/arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi b/arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi index 3f0a56ebcf1f..dc7ae776db5f 100644 --- a/arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi +++ b/arch/arm/boot/dts/bcm283x-rpi-smsc9514.dtsi @@ -1,6 +1,6 @@ / { aliases { - ethernet = ðernet; + ethernet0 = ðernet; }; }; -- GitLab From 58f8d0c05a734ff4071db3f2cf444570ce69236f Mon Sep 17 00:00:00 2001 From: Taeung Song Date: Mon, 27 Mar 2017 16:10:36 +0900 Subject: [PATCH 0409/1834] perf annotate: Fix a bug following symbolic link of a build-id file [ Upstream commit 6ebd2547dd24daf95a21b2bc59931de8502afcc3 ] It is wrong way to read link name from a build-id file. Because a build-id file is not anymore a symbolic link but build-id directory of it is symbolic link, so fix it. For example, if build-id file name gotten from dso__build_id_filename() is as below, /root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1/elf To correctly read link name of build-id, use the build-id dir path that is a symbolic link, instead of the above build-id file name like below. /root/.debug/.build-id/4f/75c7d197c951659d1c1b8b5fd49bcdf8f3f8b1 Signed-off-by: Taeung Song Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/1490598638-13947-2-git-send-email-treeze.taeung@gmail.com Fixes: 01412261d994 ("perf buildid-cache: Use path/to/bin/buildid/elf instead of path/to/bin/buildid") Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/annotate.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 430d039d0079..a38227eb5450 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1250,6 +1250,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil { char linkname[PATH_MAX]; char *build_id_filename; + char *build_id_path = NULL; if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && !dso__is_kcore(dso)) @@ -1265,8 +1266,14 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil goto fallback; } + build_id_path = strdup(filename); + if (!build_id_path) + return -1; + + dirname(build_id_path); + if (dso__is_kcore(dso) || - readlink(filename, linkname, sizeof(linkname)) < 0 || + readlink(build_id_path, linkname, sizeof(linkname)) < 0 || strstr(linkname, DSO__NAME_KALLSYMS) || access(filename, R_OK)) { fallback: @@ -1278,6 +1285,7 @@ static int dso__disassemble_filename(struct dso *dso, char *filename, size_t fil __symbol__join_symfs(filename, filename_size, dso->long_name); } + free(build_id_path); return 0; } -- GitLab From da1a974e27c7aea0b1859be3774ea7577f4ffd95 Mon Sep 17 00:00:00 2001 From: Tommi Rantala Date: Wed, 22 Mar 2017 15:06:20 +0200 Subject: [PATCH 0410/1834] perf buildid: Do not assume that readlink() returns a null terminated string [ Upstream commit 5a2342111c68e623e27ee7ea3d0492d8dad6bda0 ] Valgrind was complaining: $ valgrind ./perf list >/dev/null ==11643== Memcheck, a memory error detector ==11643== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==11643== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info ==11643== Command: ./perf list ==11643== ==11643== Conditional jump or move depends on uninitialised value(s) ==11643== at 0x4C30620: rindex (vg_replace_strmem.c:199) ==11643== by 0x49DAA9: build_id_cache__origname (build-id.c:198) ==11643== by 0x49E1C7: build_id_cache__valid_id (build-id.c:222) ==11643== by 0x49E1C7: build_id_cache__list_all (build-id.c:507) ==11643== by 0x4B9C8F: print_sdt_events (parse-events.c:2067) ==11643== by 0x4BB0B3: print_events (parse-events.c:2313) ==11643== by 0x439501: cmd_list (builtin-list.c:53) ==11643== by 0x497150: run_builtin (perf.c:359) ==11643== by 0x428CE0: handle_internal_command (perf.c:421) ==11643== by 0x428CE0: run_argv (perf.c:467) ==11643== by 0x428CE0: main (perf.c:614) [...] Additionally, a zero length result from readlink() is not very interesting. Signed-off-by: Tommi Rantala Cc: Alexander Shishkin Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170322130624.21881-3-tommi.t.rantala@nokia.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/build-id.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index e528c40739cc..993ef2762508 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c @@ -182,13 +182,17 @@ char *build_id_cache__origname(const char *sbuild_id) char buf[PATH_MAX]; char *ret = NULL, *p; size_t offs = 5; /* == strlen("../..") */ + ssize_t len; linkname = build_id_cache__linkname(sbuild_id, NULL, 0); if (!linkname) return NULL; - if (readlink(linkname, buf, PATH_MAX) < 0) + len = readlink(linkname, buf, sizeof(buf) - 1); + if (len <= 0) goto out; + buf[len] = '\0'; + /* The link should be "../../" */ p = strrchr(buf, '/'); /* Cut off the "/" */ if (p && (p > buf + offs)) { -- GitLab From 55b22830b97ecccafc58df9a0f9824ece3add663 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Tue, 21 Feb 2017 15:55:41 -0800 Subject: [PATCH 0411/1834] i40e/i40evf: Fix use after free in Rx cleanup path [ Upstream commit 741b8b832a57402380be79d7d11a59eaf57fff3b ] We need to reset skb back to NULL when we have freed it in the Rx cleanup path. I found one spot where this wasn't occurring so this patch fixes it. Change-ID: Iaca68934200732cd4a63eb0bd83b539c95f8c4dd Signed-off-by: Alexander Duyck Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 1 + drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 28b640fa2e35..2e12ccf73dba 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -1820,6 +1820,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) */ if (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) { dev_kfree_skb_any(skb); + skb = NULL; continue; } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 90ebc5ac16fd..7bfed441c466 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1262,6 +1262,7 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) */ if (unlikely(i40e_test_staterr(rx_desc, BIT(I40E_RXD_QW1_ERROR_SHIFT)))) { dev_kfree_skb_any(skb); + skb = NULL; continue; } -- GitLab From 13cc05b621bfde13f6afa5ccbc8e5bd88f26399b Mon Sep 17 00:00:00 2001 From: Jitendra Bhivare Date: Fri, 24 Mar 2017 14:11:40 +0530 Subject: [PATCH 0412/1834] scsi: be2iscsi: Check tag in beiscsi_mccq_compl_wait [ Upstream commit eb419229be58dc6d4a3a814116a265908e088c39 ] scsi host12: BS_1377 : mgmt_invalidate_connection Failed for cid=256 BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: [] __list_add+0xf/0xc0 PGD 0 Oops: 0000 [#1] SMP Modules linked in: ... CPU: 9 PID: 1542 Comm: iscsid Tainted: G ------------ T 3.10.0-514.el7.x86_64 #1 Hardware name: HP ProLiant DL360 Gen9/ProLiant DL360 Gen9, BIOS P89 09/12/2016 task: ffff88076f310fb0 ti: ffff88076bba8000 task.ti: ffff88076bba8000 RIP: 0010:[] [] __list_add+0xf/0xc0 RSP: 0018:ffff88076bbab8e8 EFLAGS: 00010046 RAX: 0000000000000246 RBX: ffff88076bbab990 RCX: 0000000000000000 RDX: 0000000000000000 RSI: ffff880468badf58 RDI: ffff88076bbab990 RBP: ffff88076bbab900 R08: 0000000000000246 R09: 00000000000020de R10: 0000000000000000 R11: ffff88076bbab5be R12: 0000000000000000 R13: ffff880468badf58 R14: 000000000001adb0 R15: ffff88076f310fb0 FS: 00007f377124a880(0000) GS:ffff88046fa40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000008 CR3: 0000000771318000 CR4: 00000000001407e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Stack: ffff88076bbab990 ffff880468badf50 0000000000000001 ffff88076bbab938 ffffffff810b128b 0000000000000246 00000000cf9b7040 ffff880468bac7a0 0000000000000000 ffff880468bac7a0 ffff88076bbab9d0 ffffffffa05a6ea3 Call Trace: [] prepare_to_wait+0x7b/0x90 [] beiscsi_mccq_compl_wait+0x153/0x330 [be2iscsi] [] ? wake_up_atomic_t+0x30/0x30 [] beiscsi_ep_disconnect+0x91/0x2d0 [be2iscsi] [] iscsi_if_ep_disconnect.isra.14+0x5a/0x70 [scsi_transport_iscsi] [] iscsi_if_recv_msg+0x113b/0x14a0 [scsi_transport_iscsi] [] ? __kmalloc_node_track_caller+0x58/0x290 [] iscsi_if_rx+0x8e/0x1f0 [scsi_transport_iscsi] [] netlink_unicast+0xed/0x1b0 [] netlink_sendmsg+0x31e/0x690 [] ? netlink_rcv_wake+0x44/0x60 [] ? netlink_recvmsg+0x1e3/0x450 beiscsi_mccq_compl_wait gets called even when MCC tag allocation failed for mgmt_invalidate_connection. mcc_wait is not initialized for tag 0 so causes crash in prepare_to_wait. Signed-off-by: Jitendra Bhivare Reviewed-by: Tomas Henzl Reviewed-by: Chris Leech Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/be2iscsi/be_cmds.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c index be65da2988fb..838edbba8aec 100644 --- a/drivers/scsi/be2iscsi/be_cmds.c +++ b/drivers/scsi/be2iscsi/be_cmds.c @@ -246,6 +246,12 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, { int rc = 0; + if (!tag || tag > MAX_MCC_CMD) { + __beiscsi_log(phba, KERN_ERR, + "BC_%d : invalid tag %u\n", tag); + return -EINVAL; + } + if (beiscsi_hba_in_error(phba)) { clear_bit(MCC_TAG_STATE_RUNNING, &phba->ctrl.ptag_state[tag].tag_state); -- GitLab From 3a8649e6c5b28b4bb72ce94a9b1967ffdd70481d Mon Sep 17 00:00:00 2001 From: Shikhar Dogra Date: Mon, 27 Mar 2017 16:16:44 -0700 Subject: [PATCH 0413/1834] driver: (adm1275) set the m,b and R coefficients correctly for power [ Upstream commit 6faecba0b3da7b617bf72bef422bf0d3bb6dfe7d ] Seems like coefficient values for m, b and R under power have been put in the wrong order. Rearranging them properly to get correct values of coefficients for power. For specs, please refer to table 7 (page 35) on http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1075.pdf Fixes: 904b296f308d ("hwmon: (adm1275) Introduce configuration data structure for coeffcients") Signed-off-by: Shikhar Dogra Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/pmbus/adm1275.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c index 3baa4f4a8c5e..d659a02647d4 100644 --- a/drivers/hwmon/pmbus/adm1275.c +++ b/drivers/hwmon/pmbus/adm1275.c @@ -101,8 +101,8 @@ static const struct coefficients adm1075_coefficients[] = { [0] = { 27169, 0, -1 }, /* voltage */ [1] = { 806, 20475, -1 }, /* current, irange25 */ [2] = { 404, 20475, -1 }, /* current, irange50 */ - [3] = { 0, -1, 8549 }, /* power, irange25 */ - [4] = { 0, -1, 4279 }, /* power, irange50 */ + [3] = { 8549, 0, -1 }, /* power, irange25 */ + [4] = { 4279, 0, -1 }, /* power, irange50 */ }; static const struct coefficients adm1275_coefficients[] = { -- GitLab From 851eb3187617dcaacf6162626dd750850d5abef1 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Mon, 27 Mar 2017 11:37:35 -0700 Subject: [PATCH 0414/1834] bonding: make speed, duplex setting consistent with link state [ Upstream commit c4adfc822bf5d8e97660b6114b5a8892530ce8cb ] bond_update_speed_duplex() retrieves speed and duplex settings. There is a possibility of failure in retrieving these values but caller has to assume it's always successful. This leads to having inconsistent slave link settings. If these (speed, duplex) values cannot be retrieved, then keeping the link UP causes problems. The updated bond_update_speed_duplex() returns 0 on success if it retrieves sane values for speed and duplex. On failure it returns 1 and marks the link down. Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 63d61c084815..6b4b43319ffa 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -371,9 +371,10 @@ int bond_set_carrier(struct bonding *bond) /* Get link speed and duplex from the slave's base driver * using ethtool. If for some reason the call fails or the * values are invalid, set speed and duplex to -1, - * and return. + * and return. Return 1 if speed or duplex settings are + * UNKNOWN; 0 otherwise. */ -static void bond_update_speed_duplex(struct slave *slave) +static int bond_update_speed_duplex(struct slave *slave) { struct net_device *slave_dev = slave->dev; struct ethtool_link_ksettings ecmd; @@ -383,24 +384,27 @@ static void bond_update_speed_duplex(struct slave *slave) slave->duplex = DUPLEX_UNKNOWN; res = __ethtool_get_link_ksettings(slave_dev, &ecmd); - if (res < 0) - return; - - if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) - return; - + if (res < 0) { + slave->link = BOND_LINK_DOWN; + return 1; + } + if (ecmd.base.speed == 0 || ecmd.base.speed == ((__u32)-1)) { + slave->link = BOND_LINK_DOWN; + return 1; + } switch (ecmd.base.duplex) { case DUPLEX_FULL: case DUPLEX_HALF: break; default: - return; + slave->link = BOND_LINK_DOWN; + return 1; } slave->speed = ecmd.base.speed; slave->duplex = ecmd.base.duplex; - return; + return 0; } const char *bond_slave_link_status(s8 link) -- GitLab From 5bf86f30e2a2648cff3346ace5d26208d6a3e001 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Fri, 24 Mar 2017 14:13:05 +0300 Subject: [PATCH 0415/1834] mm: Fix false-positive VM_BUG_ON() in page_cache_{get,add}_speculative() [ Upstream commit 591a3d7c09fa08baff48ad86c2347dbd28a52753 ] 0day testing by Fengguang Wu triggered this crash while running Trinity: kernel BUG at include/linux/pagemap.h:151! ... CPU: 0 PID: 458 Comm: trinity-c0 Not tainted 4.11.0-rc2-00251-g2947ba0 #1 ... Call Trace: __get_user_pages_fast() get_user_pages_fast() get_futex_key() futex_requeue() do_futex() SyS_futex() do_syscall_64() entry_SYSCALL64_slow_path() It' VM_BUG_ON() due to false-negative in_atomic(). We call page_cache_get_speculative() with disabled local interrupts. It should be atomic enough. So let's check for disabled interrupts in the VM_BUG_ON() condition too, to resolve this. ( This got triggered by the conversion of the x86 GUP code to the generic GUP code. ) Reported-by: Fengguang Wu Signed-off-by: Kirill A. Shutemov Cc: Andrew Morton Cc: Aneesh Kumar K.V Cc: Kirill A. Shutemov Cc: LKP Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20170324114709.pcytvyb3d6ajux33@black.fi.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/pagemap.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 7dbe9148b2f8..35f4c4d9c405 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -148,7 +148,7 @@ static inline int page_cache_get_speculative(struct page *page) #ifdef CONFIG_TINY_RCU # ifdef CONFIG_PREEMPT_COUNT - VM_BUG_ON(!in_atomic()); + VM_BUG_ON(!in_atomic() && !irqs_disabled()); # endif /* * Preempt must be disabled here - we rely on rcu_read_lock doing @@ -186,7 +186,7 @@ static inline int page_cache_add_speculative(struct page *page, int count) #if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU) # ifdef CONFIG_PREEMPT_COUNT - VM_BUG_ON(!in_atomic()); + VM_BUG_ON(!in_atomic() && !irqs_disabled()); # endif VM_BUG_ON_PAGE(page_count(page) == 0, page); page_ref_add(page, count); -- GitLab From 90a6ae1eadf11e73fe4c6dbaa0fbd888bb1b48d4 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 22 Mar 2017 21:30:27 +0900 Subject: [PATCH 0416/1834] ALSA: firewire-lib: add a quirk of packet without valid EOH in CIP format [ Upstream commit 2128f78f75a36a34dfef0e127273c2f820c5c904 ] In IEC 61883-1, when two quadlets CIP header is used, the most significant bit in second CIP header stands. However, packets from units with MOTU protocol version 3 have a quirk without this flag. Current packet streaming layer handles this as protocol error. This commit adds a new enumeration constant for this quirk, to handle MOTU protocol version 3. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/firewire/amdtp-stream.c | 5 +++-- sound/firewire/amdtp-stream.h | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/firewire/amdtp-stream.c b/sound/firewire/amdtp-stream.c index 9741757436be..d0ad61f563e2 100644 --- a/sound/firewire/amdtp-stream.c +++ b/sound/firewire/amdtp-stream.c @@ -471,8 +471,9 @@ static int handle_in_packet(struct amdtp_stream *s, * This module supports 'Two-quadlet CIP header with SYT field'. * For convenience, also check FMT field is AM824 or not. */ - if (((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) || - ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) { + if ((((cip_header[0] & CIP_EOH_MASK) == CIP_EOH) || + ((cip_header[1] & CIP_EOH_MASK) != CIP_EOH)) && + (!(s->flags & CIP_HEADER_WITHOUT_EOH))) { dev_info_ratelimited(&s->unit->device, "Invalid CIP header for AMDTP: %08X:%08X\n", cip_header[0], cip_header[1]); diff --git a/sound/firewire/amdtp-stream.h b/sound/firewire/amdtp-stream.h index f7c054bc9d92..8136bd20c8b1 100644 --- a/sound/firewire/amdtp-stream.h +++ b/sound/firewire/amdtp-stream.h @@ -29,6 +29,8 @@ * @CIP_JUMBO_PAYLOAD: Only for in-stream. The number of data blocks in an * packet is larger than IEC 61883-6 defines. Current implementation * allows 5 times as large as IEC 61883-6 defines. + * @CIP_HEADER_WITHOUT_EOH: Only for in-stream. CIP Header doesn't include + * valid EOH. */ enum cip_flags { CIP_NONBLOCKING = 0x00, @@ -39,6 +41,7 @@ enum cip_flags { CIP_SKIP_DBC_ZERO_CHECK = 0x10, CIP_EMPTY_HAS_WRONG_DBC = 0x20, CIP_JUMBO_PAYLOAD = 0x40, + CIP_HEADER_WITHOUT_EOH = 0x80, }; /** -- GitLab From dab825106b376cc8f3c4e948175c23cf383566da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Mar 2017 12:45:30 +0200 Subject: [PATCH 0417/1834] ARM: dts: r8a7794: Add DU1 clock to device tree commit 1764f8081f1524bf629e0744b277db751281ff56 upstream. Add the missing module clock for the second channel of the display unit. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7794.dtsi | 8 +++++--- include/dt-bindings/clock/r8a7794-clock.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi index 6c0150dcf146..1d65dd0a3f93 100644 --- a/arch/arm/boot/dts/r8a7794.dtsi +++ b/arch/arm/boot/dts/r8a7794.dtsi @@ -1261,19 +1261,21 @@ clocks = <&mp_clk>, <&hp_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&zs_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&zx_clk>; + <&zx_clk>, <&zx_clk>; #clock-cells = <1>; clock-indices = < R8A7794_CLK_EHCI R8A7794_CLK_HSUSB R8A7794_CLK_HSCIF2 R8A7794_CLK_SCIF5 R8A7794_CLK_SCIF4 R8A7794_CLK_HSCIF1 R8A7794_CLK_HSCIF0 R8A7794_CLK_SCIF3 R8A7794_CLK_SCIF2 R8A7794_CLK_SCIF1 - R8A7794_CLK_SCIF0 R8A7794_CLK_DU0 + R8A7794_CLK_SCIF0 + R8A7794_CLK_DU1 R8A7794_CLK_DU0 >; clock-output-names = "ehci", "hsusb", "hscif2", "scif5", "scif4", "hscif1", "hscif0", - "scif3", "scif2", "scif1", "scif0", "du0"; + "scif3", "scif2", "scif1", "scif0", + "du1", "du0"; }; mstp8_clks: mstp8_clks@e6150990 { compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks"; diff --git a/include/dt-bindings/clock/r8a7794-clock.h b/include/dt-bindings/clock/r8a7794-clock.h index 88e64846cf37..cdeafd9cab07 100644 --- a/include/dt-bindings/clock/r8a7794-clock.h +++ b/include/dt-bindings/clock/r8a7794-clock.h @@ -81,6 +81,7 @@ #define R8A7794_CLK_SCIF2 19 #define R8A7794_CLK_SCIF1 20 #define R8A7794_CLK_SCIF0 21 +#define R8A7794_CLK_DU1 23 #define R8A7794_CLK_DU0 24 /* MSTP8 */ -- GitLab From 27b7275721c498befcb57b5936c79f88366f78eb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Mar 2017 12:45:31 +0200 Subject: [PATCH 0418/1834] ARM: dts: r8a7794: Correct clock of DU1 [ Upstream commit 89675f36c9e17512812b9d14d9824f8ef92782c3 ] The second channel of the display unit uses a different module clock than the first channel. Fixes: 46c4f13d04d729fa ("ARM: shmobile: r8a7794: Add DU node to device tree") Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7794.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi index 1d65dd0a3f93..d8f4ca85ed3f 100644 --- a/arch/arm/boot/dts/r8a7794.dtsi +++ b/arch/arm/boot/dts/r8a7794.dtsi @@ -916,7 +916,7 @@ interrupts = , ; clocks = <&mstp7_clks R8A7794_CLK_DU0>, - <&mstp7_clks R8A7794_CLK_DU0>; + <&mstp7_clks R8A7794_CLK_DU1>; clock-names = "du.0", "du.1"; status = "disabled"; -- GitLab From 0030b37be54786e156df0ce8ad99b4c1ead682aa Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Mar 2017 12:45:33 +0200 Subject: [PATCH 0419/1834] ARM: dts: silk: Correct clock of DU1 [ Upstream commit 403fe77e22eb72c962c3889efc9d4fa62e454737 ] The second channel of the display unit uses a different module clock than the first channel. Fixes: 84e734f497cd48f6 ("ARM: dts: silk: add DU DT support") Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7794-silk.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts index cf880ac06f4b..8874451fb914 100644 --- a/arch/arm/boot/dts/r8a7794-silk.dts +++ b/arch/arm/boot/dts/r8a7794-silk.dts @@ -425,7 +425,7 @@ status = "okay"; clocks = <&mstp7_clks R8A7794_CLK_DU0>, - <&mstp7_clks R8A7794_CLK_DU0>, + <&mstp7_clks R8A7794_CLK_DU1>, <&x2_clk>, <&x3_clk>; clock-names = "du.0", "du.1", "dclkin.0", "dclkin.1"; -- GitLab From 94b3df54ad6d451a0158681758a0996947b5134d Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 27 Mar 2017 10:51:36 -0700 Subject: [PATCH 0420/1834] blk-throttle: make sure expire time isn't too big [ Upstream commit 06cceedcca67a93ac7f7aa93bbd9980c7496d14e ] cgroup could be throttled to a limit but when all cgroups cross high limit, queue enters a higher state and so the group should be throttled to a higher limit. It's possible the cgroup is sleeping because of throttle and other cgroups don't dispatch IO any more. In this case, nobody can trigger current downgrade/upgrade logic. To fix this issue, we could either set up a timer to wakeup the cgroup if other cgroups are idle or make sure this cgroup doesn't sleep too long. Setting up a timer means we must change the timer very frequently. This patch chooses the latter. Making cgroup sleep time not too big wouldn't change cgroup bps/iops, but could make it wakeup more frequently, which isn't a big issue because throtl_slice * 8 is already quite big. Signed-off-by: Shaohua Li Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-throttle.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/block/blk-throttle.c b/block/blk-throttle.c index a3ea8260c94c..3a4c9a3c1427 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -499,6 +499,17 @@ static void throtl_dequeue_tg(struct throtl_grp *tg) static void throtl_schedule_pending_timer(struct throtl_service_queue *sq, unsigned long expires) { + unsigned long max_expire = jiffies + 8 * throtl_slice; + + /* + * Since we are adjusting the throttle limit dynamically, the sleep + * time calculated according to previous limit might be invalid. It's + * possible the cgroup sleep time is very long and no other cgroups + * have IO running so notify the limit changes. Make sure the cgroup + * doesn't sleep too long to avoid the missed notification. + */ + if (time_after(expires, max_expire)) + expires = max_expire; mod_timer(&sq->pending_timer, expires); throtl_log(sq, "schedule timer. delay=%lu jiffies=%lu", expires - jiffies, jiffies); -- GitLab From e2afbcdeb61503683b16cf90b98da187f33c6d39 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 27 Mar 2017 16:54:12 -0700 Subject: [PATCH 0421/1834] regulator: core: Limit propagation of parent voltage count and list [ Upstream commit fd086045559d90cd7854818b4c60a7119eda6231 ] Commit 26988efe11b1 ("regulator: core: Allow to get voltage count and list from parent") introduces the propagation of the parent voltage count and list for regulators that don't provide this information themselves. The goal is to support simple switch regulators, however as a side effect normal continuous regulators can leak details of their supplies and provide consumers with inconsistent information. Limit the propagation of the voltage count and list to switch regulators. Fixes: 26988efe11b1 ("regulator: core: Allow to get voltage count and list from parent") Signed-off-by: Matthias Kaehlcke Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/core.c | 9 +++++++-- include/linux/regulator/driver.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9403245503de..178fcda12cec 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2465,7 +2465,7 @@ static int _regulator_list_voltage(struct regulator *regulator, ret = ops->list_voltage(rdev, selector); if (lock) mutex_unlock(&rdev->mutex); - } else if (rdev->supply) { + } else if (rdev->is_switch && rdev->supply) { ret = _regulator_list_voltage(rdev->supply, selector, lock); } else { return -EINVAL; @@ -2523,7 +2523,7 @@ int regulator_count_voltages(struct regulator *regulator) if (rdev->desc->n_voltages) return rdev->desc->n_voltages; - if (!rdev->supply) + if (!rdev->is_switch || !rdev->supply) return -EINVAL; return regulator_count_voltages(rdev->supply); @@ -4049,6 +4049,11 @@ regulator_register(const struct regulator_desc *regulator_desc, mutex_unlock(®ulator_list_mutex); } + if (!rdev->desc->ops->get_voltage && + !rdev->desc->ops->list_voltage && + !rdev->desc->fixed_uV) + rdev->is_switch = true; + ret = device_register(&rdev->dev); if (ret != 0) { put_device(&rdev->dev); diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 37b532410528..3c3786df044c 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -425,6 +425,8 @@ struct regulator_dev { struct regulator_enable_gpio *ena_pin; unsigned int ena_gpio_state:1; + unsigned int is_switch:1; + /* time when this regulator was disabled last time */ unsigned long last_off_jiffy; }; -- GitLab From 73f2c66447bb1514518879f7e260636eba7376ff Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 29 Mar 2017 16:37:51 -0300 Subject: [PATCH 0422/1834] perf trace: Handle unpaired raw_syscalls:sys_exit event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit fd2b2975149f5f7099693027cece81b16842964a ] Which may happen when we start a tracing session and a thread is waiting for something like "poll" to return, in which case we better print "?" both for the syscall entry timestamp and for the duration. E.g.: Tracing existing mutt session: # perf trace -p `pidof mutt` ? ( ? ): mutt/17135 ... [continued]: poll()) = 1 0.027 ( 0.013 ms): mutt/17135 read(buf: 0x7ffcb3c42cef, count: 1) = 1 0.047 ( 0.008 ms): mutt/17135 poll(ufds: 0x7ffcb3c42c50, nfds: 1, timeout_msecs: 1000) = 1 0.059 ( 0.008 ms): mutt/17135 read(buf: 0x7ffcb3c42cef, count: 1) = 1 Before it would print a large number because we'd do: ttrace->entry_time - trace->base_time And entry_time would be 0, while base_time would be the timestamp for the first event 'perf trace' reads, oops. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Luis Claudio Gonçalves Cc: Namhyung Kim Cc: Wang Nan Link: http://lkml.kernel.org/n/tip-wbcb93ofva2qdjd5ltn5eeqq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-trace.c | 43 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 21f8a81797a0..4c596ba310cb 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -822,12 +822,21 @@ struct syscall { void **arg_parm; }; -static size_t fprintf_duration(unsigned long t, FILE *fp) +/* + * We need to have this 'calculated' boolean because in some cases we really + * don't know what is the duration of a syscall, for instance, when we start + * a session and some threads are waiting for a syscall to finish, say 'poll', + * in which case all we can do is to print "( ? ) for duration and for the + * start timestamp. + */ +static size_t fprintf_duration(unsigned long t, bool calculated, FILE *fp) { double duration = (double)t / NSEC_PER_MSEC; size_t printed = fprintf(fp, "("); - if (duration >= 1.0) + if (!calculated) + printed += fprintf(fp, " ? "); + else if (duration >= 1.0) printed += color_fprintf(fp, PERF_COLOR_RED, "%6.3f ms", duration); else if (duration >= 0.01) printed += color_fprintf(fp, PERF_COLOR_YELLOW, "%6.3f ms", duration); @@ -1030,13 +1039,27 @@ static bool trace__filter_duration(struct trace *trace, double t) return t < (trace->duration_filter * NSEC_PER_MSEC); } -static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) +static size_t __trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) { double ts = (double)(tstamp - trace->base_time) / NSEC_PER_MSEC; return fprintf(fp, "%10.3f ", ts); } +/* + * We're handling tstamp=0 as an undefined tstamp, i.e. like when we are + * using ttrace->entry_time for a thread that receives a sys_exit without + * first having received a sys_enter ("poll" issued before tracing session + * starts, lost sys_enter exit due to ring buffer overflow). + */ +static size_t trace__fprintf_tstamp(struct trace *trace, u64 tstamp, FILE *fp) +{ + if (tstamp > 0) + return __trace__fprintf_tstamp(trace, tstamp, fp); + + return fprintf(fp, " ? "); +} + static bool done = false; static bool interrupted = false; @@ -1047,10 +1070,10 @@ static void sig_handler(int sig) } static size_t trace__fprintf_entry_head(struct trace *trace, struct thread *thread, - u64 duration, u64 tstamp, FILE *fp) + u64 duration, bool duration_calculated, u64 tstamp, FILE *fp) { size_t printed = trace__fprintf_tstamp(trace, tstamp, fp); - printed += fprintf_duration(duration, fp); + printed += fprintf_duration(duration, duration_calculated, fp); if (trace->multiple_threads) { if (trace->show_comm) @@ -1452,7 +1475,7 @@ static int trace__printf_interrupted_entry(struct trace *trace, struct perf_samp duration = sample->time - ttrace->entry_time; - printed = trace__fprintf_entry_head(trace, trace->current, duration, ttrace->entry_time, trace->output); + printed = trace__fprintf_entry_head(trace, trace->current, duration, true, ttrace->entry_time, trace->output); printed += fprintf(trace->output, "%-70s) ...\n", ttrace->entry_str); ttrace->entry_pending = false; @@ -1499,7 +1522,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, if (sc->is_exit) { if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { - trace__fprintf_entry_head(trace, thread, 1, ttrace->entry_time, trace->output); + trace__fprintf_entry_head(trace, thread, 0, false, ttrace->entry_time, trace->output); fprintf(trace->output, "%-70s)\n", ttrace->entry_str); } } else { @@ -1547,6 +1570,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, { long ret; u64 duration = 0; + bool duration_calculated = false; struct thread *thread; int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0; struct syscall *sc = trace__syscall_info(trace, evsel, id); @@ -1577,6 +1601,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, duration = sample->time - ttrace->entry_time; if (trace__filter_duration(trace, duration)) goto out; + duration_calculated = true; } else if (trace->duration_filter) goto out; @@ -1592,7 +1617,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, if (trace->summary_only) goto out; - trace__fprintf_entry_head(trace, thread, duration, ttrace->entry_time, trace->output); + trace__fprintf_entry_head(trace, thread, duration, duration_calculated, ttrace->entry_time, trace->output); if (ttrace->entry_pending) { fprintf(trace->output, "%-70s", ttrace->entry_str); @@ -1855,7 +1880,7 @@ static int trace__pgfault(struct trace *trace, thread__find_addr_location(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al); - trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output); + trace__fprintf_entry_head(trace, thread, 0, true, sample->time, trace->output); fprintf(trace->output, "%sfault [", evsel->attr.config == PERF_COUNT_SW_PAGE_FAULTS_MAJ ? -- GitLab From 68c2353e3bebd9337d3f38cbbaf9699647e0b765 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 21 Mar 2017 10:59:50 -0400 Subject: [PATCH 0423/1834] f2fs: relax node version check for victim data in gc [ Upstream commit c13ff37e359bb3eacf4e1760dcea8d9760aa7459 ] - has_not_enough_free_secs node_secs: 0 dent_secs: 0 freed:0 free_segments:103 reserved:104 - f2fs_gc - get_victim_by_default alloc_mode 0, gc_mode 1, max_search 2672, offset 4654, ofs_unit 1 - do_garbage_collect start_segno 3976, end_segno 3977 type 0 - is_alive nid 22797, blkaddr 2131882, ofs_in_node 0, version 0x8/0x0 - gc_data_segment 766, segno 3976, block 512/426 not alive So, this patch fixes subtle corrupted case where node version does not match to summary version which results in infinite loop by gc. Reported-by: Yunlei He Signed-off-by: Jaegeuk Kim Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/f2fs/gc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 34a69e7ed90b..17ab23f64bba 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -538,8 +538,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, get_node_info(sbi, nid, dni); if (sum->version != dni->version) { - f2fs_put_page(node_page, 1); - return false; + f2fs_msg(sbi->sb, KERN_WARNING, + "%s: valid data with mismatched node version.", + __func__); + set_sbi_flag(sbi, SBI_NEED_FSCK); } *nofs = ofs_of_node(node_page); -- GitLab From 508126005146f7a8d0c44c2acd02f0fce1665ccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolai=20H=C3=A4hnle?= Date: Tue, 14 Feb 2017 09:37:12 +0100 Subject: [PATCH 0424/1834] drm/ttm: never add BO that failed to validate to the LRU list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit c2c139cf435b18939204800fa72c53a7207bdd68 ] Fixes a potential race condition in amdgpu that looks as follows: Task 1: attempt ttm_bo_init, but ttm_bo_validate fails Task 1: add BO to global list anyway Task 2: grabs hold of the BO, waits on its reservation lock Task 1: releases its reference of the BO; never gives up the reservation lock The patch "drm/amdgpu: fix a potential deadlock in amdgpu_bo_create_restricted()" attempts to fix that by releasing the reservation lock in amdgpu code; unfortunately, it introduces a use-after-free when this race _doesn't_ happen. This patch should fix the race properly by never adding the BO to the global list in the first place. Cc: zhoucm1 Signed-off-by: Nicolai Hähnle Tested-by: Samuel Pitoiset Reviewed-by: Christian König Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/ttm/ttm_bo.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index d09276ec7e90..52a2a1a75682 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1209,18 +1209,20 @@ int ttm_bo_init(struct ttm_bo_device *bdev, if (likely(!ret)) ret = ttm_bo_validate(bo, placement, interruptible, false); - if (!resv) { + if (!resv) ttm_bo_unreserve(bo); - } else if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { + if (unlikely(ret)) { + ttm_bo_unref(&bo); + return ret; + } + + if (resv && !(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { spin_lock(&bo->glob->lru_lock); ttm_bo_add_to_lru(bo); spin_unlock(&bo->glob->lru_lock); } - if (unlikely(ret)) - ttm_bo_unref(&bo); - return ret; } EXPORT_SYMBOL(ttm_bo_init); -- GitLab From 8c989a6803e4e235cd50d789a7ebe6fad10f747d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 29 Mar 2017 10:45:44 -0700 Subject: [PATCH 0425/1834] bonding: refine bond_fold_stats() wrap detection [ Upstream commit 142c6594acbcc32391af9c15f8cd65c6c177698f ] Some device drivers reset their stats at down/up events, possibly fooling bonding stats, since they operate with relative deltas. It is nearly not possible to fix drivers, since some of them compute the tx/rx counters based on per rx/tx queue stats, and the queues can be reconfigured (ethtool -L) between the down/up sequence. Lets avoid accumulating 'negative' values that render bonding stats useless. It is better to lose small deltas, assuming the bonding stats are fetched at a reasonable frequency. Fixes: 5f0c5f73e5ef ("bonding: make global bonding stats more reliable") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 6b4b43319ffa..c3f3096b24ae 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3331,12 +3331,17 @@ static void bond_fold_stats(struct rtnl_link_stats64 *_res, for (i = 0; i < sizeof(*_res) / sizeof(u64); i++) { u64 nv = new[i]; u64 ov = old[i]; + s64 delta = nv - ov; /* detects if this particular field is 32bit only */ if (((nv | ov) >> 32) == 0) - res[i] += (u32)nv - (u32)ov; - else - res[i] += nv - ov; + delta = (s64)(s32)((u32)nv - (u32)ov); + + /* filter anomalies, some drivers reset their stats + * at down/up events. + */ + if (delta > 0) + res[i] += delta; } } -- GitLab From aad6ccac0e4fddcfd1b04a2cbd95b550c59da23e Mon Sep 17 00:00:00 2001 From: Manish Jaggi Date: Thu, 30 Mar 2017 18:47:14 -0500 Subject: [PATCH 0426/1834] PCI: Apply Cavium ACS quirk only to CN81xx/CN83xx/CN88xx devices [ Upstream commit b77d537d00d08fcf0bf641cd3491dd7df0ad1475 ] Only apply the Cavium ACS quirk to devices with ID in the range 0xa000-0xa0ff. These are the on-chip PCI devices for CN81xx/CN83xx/CN88xx. Fixes: b404bcfbf035 ("PCI: Add ACS quirk for all Cavium devices") Reported-by: Alex Williamson Signed-off-by: Manish Jaggi Acked-by: David Daney Acked-by: Alex Williamson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 0c9edc9d7c44..4c9fb8b323e8 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -4104,6 +4104,9 @@ static int pci_quirk_cavium_acs(struct pci_dev *dev, u16 acs_flags) */ acs_flags &= ~(PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_SV | PCI_ACS_UF); + if (!((dev->device >= 0xa000) && (dev->device <= 0xa0ff))) + return -ENOTTY; + return acs_flags ? 0 : 1; } -- GitLab From 66db324639335681f510ee8720d22ac237412564 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Tue, 21 Mar 2017 22:59:56 +0530 Subject: [PATCH 0427/1834] powerpc/mm/hugetlb: Filter out hugepage size not supported by page table layout [ Upstream commit a525108cf1cc14651602d678da38fa627a76a724 ] Without this if firmware reports 1MB page size support we will crash trying to use 1MB as hugetlb page size. echo 300 > /sys/kernel/mm/hugepages/hugepages-1024kB/nr_hugepages kernel BUG at ./arch/powerpc/include/asm/hugetlb.h:19! ..... .... [c0000000e2c27b30] c00000000029dae8 .hugetlb_fault+0x638/0xda0 [c0000000e2c27c30] c00000000026fb64 .handle_mm_fault+0x844/0x1d70 [c0000000e2c27d70] c00000000004805c .do_page_fault+0x3dc/0x7c0 [c0000000e2c27e30] c00000000000ac98 handle_page_fault+0x10/0x30 With fix, we don't enable 1MB as hugepage size. bash-4.2# cd /sys/kernel/mm/hugepages/ bash-4.2# ls hugepages-16384kB hugepages-16777216kB Signed-off-by: Aneesh Kumar K.V Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/hugetlbpage.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index a5d3ecdabc44..035dfb65df4b 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c @@ -765,6 +765,24 @@ static int __init add_huge_page_size(unsigned long long size) if ((mmu_psize = shift_to_mmu_psize(shift)) < 0) return -EINVAL; +#ifdef CONFIG_PPC_BOOK3S_64 + /* + * We need to make sure that for different page sizes reported by + * firmware we only add hugetlb support for page sizes that can be + * supported by linux page table layout. + * For now we have + * Radix: 2M + * Hash: 16M and 16G + */ + if (radix_enabled()) { + if (mmu_psize != MMU_PAGE_2M) + return -EINVAL; + } else { + if (mmu_psize != MMU_PAGE_16M && mmu_psize != MMU_PAGE_16G) + return -EINVAL; + } +#endif + BUG_ON(mmu_psize_defs[mmu_psize].shift != shift); /* Return if huge page size has already been setup */ -- GitLab From ca9c60742b20452b821ac69ad4115d0a681597a3 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Sun, 26 Mar 2017 22:47:36 +0200 Subject: [PATCH 0428/1834] braille-console: Fix value returned by _braille_console_setup [ Upstream commit 2ed2b8621be2708c0f6d61fe9841e9ad8b9753f0 ] commit bbeddf52adc1 ("printk: move braille console support into separate braille.[ch] files") introduced _braille_console_setup() to outline the braille initialization code. There was however some confusion over the value it was supposed to return. commit 2cfe6c4ac7ee ("printk: Fix return of braille_register_console()") tried to fix it but failed to. This fixes and documents the returned value according to the use in printk.c: non-zero return means a parsing error, and thus this console configuration should be ignored. Signed-off-by: Samuel Thibault Cc: Aleksey Makarov Cc: Joe Perches Cc: Ming Lei Cc: Steven Rostedt Acked-by: Petr Mladek Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/printk/braille.c | 15 ++++++++------- kernel/printk/braille.h | 13 ++++++++++--- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/kernel/printk/braille.c b/kernel/printk/braille.c index d5760c42f042..61d41ca41844 100644 --- a/kernel/printk/braille.c +++ b/kernel/printk/braille.c @@ -2,12 +2,13 @@ #include #include +#include #include #include "console_cmdline.h" #include "braille.h" -char *_braille_console_setup(char **str, char **brl_options) +int _braille_console_setup(char **str, char **brl_options) { if (!strncmp(*str, "brl,", 4)) { *brl_options = ""; @@ -15,14 +16,14 @@ char *_braille_console_setup(char **str, char **brl_options) } else if (!strncmp(*str, "brl=", 4)) { *brl_options = *str + 4; *str = strchr(*brl_options, ','); - if (!*str) + if (!*str) { pr_err("need port name after brl=\n"); - else - *((*str)++) = 0; - } else - return NULL; + return -EINVAL; + } + *((*str)++) = 0; + } - return *str; + return 0; } int diff --git a/kernel/printk/braille.h b/kernel/printk/braille.h index 769d771145c8..749a6756843a 100644 --- a/kernel/printk/braille.h +++ b/kernel/printk/braille.h @@ -9,7 +9,14 @@ braille_set_options(struct console_cmdline *c, char *brl_options) c->brl_options = brl_options; } -char * +/* + * Setup console according to braille options. + * Return -EINVAL on syntax error, 0 on success (or no braille option was + * actually given). + * Modifies str to point to the serial options + * Sets brl_options to the parsed braille options. + */ +int _braille_console_setup(char **str, char **brl_options); int @@ -25,10 +32,10 @@ braille_set_options(struct console_cmdline *c, char *brl_options) { } -static inline char * +static inline int _braille_console_setup(char **str, char **brl_options) { - return NULL; + return 0; } static inline int -- GitLab From 399a4f3c2b3f0c1812a04a4a9994ced8d1704c3d Mon Sep 17 00:00:00 2001 From: Sinclair Yeh Date: Thu, 23 Mar 2017 14:28:21 -0700 Subject: [PATCH 0429/1834] drm/vmwgfx: Fixes to vmwgfx_fb [ Upstream commit aa74f0687cfe998e59b20d6454f45e8aa4403c45 ] 1. When unsetting a mode, num_connector should be set to zero 2. The pixel_format field needs to be initialized as newer DRM internal functions checks this field 3. Take the drm_modeset_lock_all() because vmw_fb_kms_detach() can change current mode Signed-off-by: Sinclair Yeh Reviewed-by: Thomas Hellstrom Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_fb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index d2d93959b119..aec6e9eef489 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -433,7 +433,7 @@ static int vmw_fb_kms_detach(struct vmw_fb_par *par, set.y = 0; set.mode = NULL; set.fb = NULL; - set.num_connectors = 1; + set.num_connectors = 0; set.connectors = &par->con; ret = drm_mode_set_config_internal(&set); if (ret) { @@ -821,7 +821,9 @@ int vmw_fb_off(struct vmw_private *vmw_priv) flush_delayed_work(&par->local_work); mutex_lock(&par->bo_mutex); + drm_modeset_lock_all(vmw_priv->dev); (void) vmw_fb_kms_detach(par, true, false); + drm_modeset_unlock_all(vmw_priv->dev); mutex_unlock(&par->bo_mutex); return 0; -- GitLab From 441f5af65244dd6585f1c364f1f4fbd00aacb64b Mon Sep 17 00:00:00 2001 From: Felix Manlunas Date: Wed, 29 Mar 2017 17:56:43 -0700 Subject: [PATCH 0430/1834] vxlan: vxlan dev should inherit lowerdev's gso_max_size [ Upstream commit d6acfeb17d030bb3907e77c048b0e7783ad8e5a9 ] vxlan dev currently ignores lowerdev's gso_max_size, which adversely affects TSO performance of liquidio if it's the lowerdev. Egress TCP packets' skb->len often exceed liquidio's advertised gso_max_size. This may happen on other NIC drivers. Fix it by assigning lowerdev's gso_max_size to that of vxlan dev. Might as well do likewise for gso_max_segs. Single flow TSO throughput of liquidio as lowerdev (using iperf3): Before the patch: 139 Mbps After the patch : 8.68 Gbps Percent increase: 6,144 % Signed-off-by: Felix Manlunas Signed-off-by: Satanand Burla Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/vxlan.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 983e941bdf29..50570d779b01 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2912,6 +2912,11 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, return -EINVAL; } + if (lowerdev) { + dev->gso_max_size = lowerdev->gso_max_size; + dev->gso_max_segs = lowerdev->gso_max_segs; + } + if (conf->mtu) { err = __vxlan_change_mtu(dev, lowerdev, dst, conf->mtu, false); if (err) -- GitLab From c95acb7bbefb4267c8df48b963d977262268de0a Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 26 Oct 2016 11:00:12 +0200 Subject: [PATCH 0431/1834] NFC: nfcmrvl: Include unaligned.h instead of access_ok.h [ Upstream commit d916d923724d59cde99ee588f15eec59dd863bbd ] Including linux/unaligned/access_ok.h causes the allmodconfig build on ia64 (and maybe others) to fail with the following warnings: include/linux/unaligned/access_ok.h:7:19: error: redefinition of 'get_unaligned_le16' include/linux/unaligned/access_ok.h:12:19: error: redefinition of 'get_unaligned_le32' include/linux/unaligned/access_ok.h:17:19: error: redefinition of 'get_unaligned_le64' include/linux/unaligned/access_ok.h:22:19: error: redefinition of 'get_unaligned_be16' include/linux/unaligned/access_ok.h:27:19: error: redefinition of 'get_unaligned_be32' include/linux/unaligned/access_ok.h:32:19: error: redefinition of 'get_unaligned_be64' include/linux/unaligned/access_ok.h:37:20: error: redefinition of 'put_unaligned_le16' include/linux/unaligned/access_ok.h:42:20: error: redefinition of 'put_unaligned_le32' include/linux/unaligned/access_ok.h:42:20: error: redefinition of 'put_unaligned_le64' include/linux/unaligned/access_ok.h:42:20: error: redefinition of 'put_unaligned_be16' include/linux/unaligned/access_ok.h:42:20: error: redefinition of 'put_unaligned_be32' include/linux/unaligned/access_ok.h:42:20: error: redefinition of 'put_unaligned_be64' Fix these by including asm/unaligned.h instead and leave it up to the architecture to decide how to implement unaligned accesses. Fixes: 3194c6870158 ("NFC: nfcmrvl: add firmware download support") Reported-by: kbuild test robot Link: https://lkml.org/lkml/2016/10/22/247 Cc: Vincent Cuissard Signed-off-by: Tobias Klauser Signed-off-by: Samuel Ortiz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nfc/nfcmrvl/fw_dnld.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c index af62c4c854f3..b4f31dad40d6 100644 --- a/drivers/nfc/nfcmrvl/fw_dnld.c +++ b/drivers/nfc/nfcmrvl/fw_dnld.c @@ -17,7 +17,7 @@ */ #include -#include +#include #include #include #include -- GitLab From 8f2c9f6c575969c7d5336cae0c73f7f45ffbfd73 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 8 Mar 2017 08:22:37 +0300 Subject: [PATCH 0432/1834] NFC: nfcmrvl: double free on error path [ Upstream commit ca42fb9e52d155547e6cf18cf26bce3e1a6af4ea ] The nci_spi_send() function calls kfree_skb(skb) on both error and success so this extra kfree_skb() is a double free. Fixes: caf6e49bf6d0 ("NFC: nfcmrvl: add spi driver") Signed-off-by: Dan Carpenter Signed-off-by: Samuel Ortiz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nfc/nfcmrvl/spi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/nfc/nfcmrvl/spi.c b/drivers/nfc/nfcmrvl/spi.c index a7faa0bcc01e..fc8e78a29d77 100644 --- a/drivers/nfc/nfcmrvl/spi.c +++ b/drivers/nfc/nfcmrvl/spi.c @@ -96,10 +96,9 @@ static int nfcmrvl_spi_nci_send(struct nfcmrvl_private *priv, /* Send the SPI packet */ err = nci_spi_send(drv_data->nci_spi, &drv_data->handshake_completion, skb); - if (err != 0) { + if (err) nfc_err(priv->dev, "spi_send failed %d", err); - kfree_skb(skb); - } + return err; } -- GitLab From 14c63f375b9a94cb39f9b8a669a9d6e530e6bfa9 Mon Sep 17 00:00:00 2001 From: Andrey Rusalin Date: Wed, 28 Dec 2016 20:10:57 +0300 Subject: [PATCH 0433/1834] NFC: pn533: change order of free_irq and dev unregistration [ Upstream commit 068a496c4525c638ffab56449d905b88ef97fe32 ] Change order of free_irq and dev unregistration. It fixes situation when device already unregistered and an interrupt happens and nobody can handle it. Signed-off-by: Andrey Rusalin Signed-off-by: Samuel Ortiz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nfc/pn533/i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nfc/pn533/i2c.c b/drivers/nfc/pn533/i2c.c index 1dc89248e58e..11d78b43cf76 100644 --- a/drivers/nfc/pn533/i2c.c +++ b/drivers/nfc/pn533/i2c.c @@ -242,10 +242,10 @@ static int pn533_i2c_remove(struct i2c_client *client) dev_dbg(&client->dev, "%s\n", __func__); - pn533_unregister_device(phy->priv); - free_irq(client->irq, phy); + pn533_unregister_device(phy->priv); + return 0; } -- GitLab From 75280515507bb41a2d7a52971f3a60070060b364 Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Thu, 30 Mar 2017 14:16:09 -0700 Subject: [PATCH 0434/1834] ARM: dts: r7s72100: fix ethernet clock parent [ Upstream commit 91a7c50cb4fabfba218549dfa84356069918bfbf ] Technically, the Ethernet block is run off the 133MHz Bus (B) clock, not the 33MHz Peripheral 0 (P0) clock. Fixes: 969244f9c720 ("ARM: dts: r7s72100: add ethernet clock to device tree") Signed-off-by: Chris Brandt Reviewed-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r7s72100.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi index fb9ef9ca120e..959e3edf367b 100644 --- a/arch/arm/boot/dts/r7s72100.dtsi +++ b/arch/arm/boot/dts/r7s72100.dtsi @@ -112,7 +112,7 @@ #clock-cells = <1>; compatible = "renesas,r7s72100-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0xfcfe0430 4>; - clocks = <&p0_clk>; + clocks = <&b_clk>; clock-indices = ; clock-output-names = "ether"; }; -- GitLab From 26cd77067fb3839393807760330177a7f1b90344 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 3 Apr 2017 11:45:41 +0200 Subject: [PATCH 0435/1834] ARM: dts: r8a7790: Correct parent of SSI[0-9] clocks [ Upstream commit d13d4e063d4a08eb1686e890e9183dde709871bf ] The SSI-ALL gate clock is located in between the P clock and the individual SSI[0-9] clocks, hence the former should be listed as their parent. Fixes: bcde372254386872 ("ARM: shmobile: r8a7790: add MSTP10 support on DTSI") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7790.dtsi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi index b6c6410ca384..262a51205aee 100644 --- a/arch/arm/boot/dts/r8a7790.dtsi +++ b/arch/arm/boot/dts/r8a7790.dtsi @@ -1437,8 +1437,11 @@ compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, + <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&mstp10_clks R8A7790_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, <&mstp10_clks R8A7790_CLK_SCU_ALL>, -- GitLab From dc65685aa3a488d1944c7870ef8838dd86867e3d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 3 Apr 2017 11:45:42 +0200 Subject: [PATCH 0436/1834] ARM: dts: r8a7791: Correct parent of SSI[0-9] clocks [ Upstream commit 16fe68dcab5702a024d85229ff7e98979cb701a5 ] The SSI-ALL gate clock is located in between the P clock and the individual SSI[0-9] clocks, hence the former should be listed as their parent. Fixes: ee9141522dcf13f8 ("ARM: shmobile: r8a7791: add MSTP10 support on DTSI") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7791.dtsi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi index 64749080e639..59405ebdce01 100644 --- a/arch/arm/boot/dts/r8a7791.dtsi +++ b/arch/arm/boot/dts/r8a7791.dtsi @@ -1437,8 +1437,11 @@ compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, + <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&mstp10_clks R8A7791_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, <&mstp10_clks R8A7791_CLK_SCU_ALL>, -- GitLab From 8131f4ddbdee477da77683cdac7e28684dfb423d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 3 Apr 2017 11:45:43 +0200 Subject: [PATCH 0437/1834] ARM: dts: r8a7793: Correct parent of SSI[0-9] clocks [ Upstream commit 1cd9028027c7a7c10b774df698c3cfafec6aa67d ] The SSI-ALL gate clock is located in between the P clock and the individual SSI[0-9] clocks, hence the former should be listed as their parent. Fixes: 072d326542e49187 ("ARM: dts: r8a7793: add MSTP10 clocks to device tree") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7793.dtsi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/r8a7793.dtsi b/arch/arm/boot/dts/r8a7793.dtsi index bd7ee309f509..e9625cb3bbaa 100644 --- a/arch/arm/boot/dts/r8a7793.dtsi +++ b/arch/arm/boot/dts/r8a7793.dtsi @@ -1234,8 +1234,11 @@ compatible = "renesas,r8a7793-mstp-clocks", "renesas,cpg-mstp-clocks"; reg = <0 0xe6150998 0 4>, <0 0xe61509a8 0 4>; clocks = <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, - <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&p_clk>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, + <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&mstp10_clks R8A7793_CLK_SSI_ALL>, <&p_clk>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, <&mstp10_clks R8A7793_CLK_SCU_ALL>, -- GitLab From a61cd7e00d99f1c2bc6d6932d5e46a48419e233a Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Mon, 3 Apr 2017 16:41:02 +1000 Subject: [PATCH 0438/1834] powerpc: Avoid taking a data miss on every userspace instruction miss [ Upstream commit a7a9dcd882a67b68568868b988289fce5ffd8419 ] Early on in do_page_fault() we call store_updates_sp(), regardless of the type of exception. For an instruction miss this doesn't make sense, because we only use this information to detect if a data miss is the result of a stack expansion instruction or not. Worse still, it results in a data miss within every userspace instruction miss handler, because we try and load the very instruction we are about to install a pte for! A simple exec microbenchmark runs 6% faster on POWER8 with this fix: #include #include #include int main(int argc, char *argv[]) { unsigned long left = atol(argv[1]); char leftstr[16]; if (left-- == 0) return 0; sprintf(leftstr, "%ld", left); execlp(argv[0], argv[0], leftstr, NULL); perror("exec failed\n"); return 0; } Pass the number of iterations on the command line (eg 10000) and time how long it takes to execute. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index d0b137d96df1..9376e8e53bfa 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -294,7 +294,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address, * can result in fault, which will cause a deadlock when called with * mmap_sem held */ - if (user_mode(regs)) + if (!is_exec && user_mode(regs)) store_update_sp = store_updates_sp(regs); if (user_mode(regs)) -- GitLab From 9c1e8b472b48421e8a698bd63cda283960ef5279 Mon Sep 17 00:00:00 2001 From: lipeng Date: Sat, 1 Apr 2017 12:03:39 +0100 Subject: [PATCH 0439/1834] net: hns: Correct HNS RSS key set function [ Upstream commit 64ec10dc2ab8ef5bc6e76b1d4bc8203c08a6da1e ] This patch fixes below ethtool configuration error: localhost:~ # ethtool -X eth0 hkey XX:XX:XX... Cannot set Rx flow hash configuration: Operation not supported Signed-off-by: lipeng Reviewed-by: Yisen Zhuang Signed-off-by: Salil Mehta Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/hisilicon/hns/hns_ae_adapt.c | 23 +++++++++++-------- .../net/ethernet/hisilicon/hns/hns_ethtool.c | 9 ++++---- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c index 2d0cb609adc3..b7c8433a7a37 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ae_adapt.c @@ -773,8 +773,9 @@ static int hns_ae_get_rss(struct hnae_handle *handle, u32 *indir, u8 *key, memcpy(key, ppe_cb->rss_key, HNS_PPEV2_RSS_KEY_SIZE); /* update the current hash->queue mappings from the shadow RSS table */ - memcpy(indir, ppe_cb->rss_indir_table, - HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir)); + if (indir) + memcpy(indir, ppe_cb->rss_indir_table, + HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir)); return 0; } @@ -785,15 +786,19 @@ static int hns_ae_set_rss(struct hnae_handle *handle, const u32 *indir, struct hns_ppe_cb *ppe_cb = hns_get_ppe_cb(handle); /* set the RSS Hash Key if specififed by the user */ - if (key) - hns_ppe_set_rss_key(ppe_cb, (u32 *)key); + if (key) { + memcpy(ppe_cb->rss_key, key, HNS_PPEV2_RSS_KEY_SIZE); + hns_ppe_set_rss_key(ppe_cb, ppe_cb->rss_key); + } - /* update the shadow RSS table with user specified qids */ - memcpy(ppe_cb->rss_indir_table, indir, - HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir)); + if (indir) { + /* update the shadow RSS table with user specified qids */ + memcpy(ppe_cb->rss_indir_table, indir, + HNS_PPEV2_RSS_IND_TBL_SIZE * sizeof(*indir)); - /* now update the hardware */ - hns_ppe_set_indir_table(ppe_cb, ppe_cb->rss_indir_table); + /* now update the hardware */ + hns_ppe_set_indir_table(ppe_cb, ppe_cb->rss_indir_table); + } return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 87d5c94b2810..8490cba230bd 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -1243,6 +1243,7 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key, { struct hns_nic_priv *priv = netdev_priv(netdev); struct hnae_ae_ops *ops; + int ret; if (AE_IS_VER1(priv->enet_ver)) { netdev_err(netdev, @@ -1252,12 +1253,10 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key, ops = priv->ae_handle->dev->ops; - /* currently hfunc can only be Toeplitz hash */ - if (key || - (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)) + if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) { + netdev_err(netdev, "Invalid hfunc!\n"); return -EOPNOTSUPP; - if (!indir) - return 0; + } return ops->set_rss(priv->ae_handle, indir, key, hfunc); } -- GitLab From 6e09b864df341b5c9321593514f173d8a049952b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 2 Apr 2017 20:20:47 +0200 Subject: [PATCH 0440/1834] net/faraday: Add missing include of of.h [ Upstream commit d39004ab136ebb6949a7dda9d24376f3d6209295 ] Breaking the include loop netdevice.h, dsa.h, devlink.h broke this driver, it depends on includes brought in by these headers. Adding linux/of.h fixes it. Fixes: ed0e39e97d34 ("net: break include loop netdevice.h, dsa.h, devlink.h") Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/faraday/ftgmac100.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 262587240c86..0437149f5939 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include -- GitLab From d45d7c94f8acb226a626840b378d2a5bba3758c4 Mon Sep 17 00:00:00 2001 From: Michal Kalderon Date: Mon, 3 Apr 2017 12:21:10 +0300 Subject: [PATCH 0441/1834] qed: Fix TM block ILT allocation [ Upstream commit 44531ba45dbf3c23cc7ae0934ec9b33ef340ac56 ] When configuring the HW timers block we should set the number of CIDs up until the last CID that require timers, instead of only those CIDs whose protocol needs timers support. Today, the protocols that require HW timers' support have their CIDs before any other protocol, but that would change in future [when we add iWARP support]. Signed-off-by: Michal Kalderon Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_cxt.c | 32 ++++++++++++++++++----- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c index ed014bdbbabd..457e30427535 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c @@ -271,16 +271,34 @@ struct qed_tm_iids { u32 per_vf_tids; }; -static void qed_cxt_tm_iids(struct qed_cxt_mngr *p_mngr, +static void qed_cxt_tm_iids(struct qed_hwfn *p_hwfn, + struct qed_cxt_mngr *p_mngr, struct qed_tm_iids *iids) { - u32 i, j; - - for (i = 0; i < MAX_CONN_TYPES; i++) { + bool tm_vf_required = false; + bool tm_required = false; + int i, j; + + /* Timers is a special case -> we don't count how many cids require + * timers but what's the max cid that will be used by the timer block. + * therefore we traverse in reverse order, and once we hit a protocol + * that requires the timers memory, we'll sum all the protocols up + * to that one. + */ + for (i = MAX_CONN_TYPES - 1; i >= 0; i--) { struct qed_conn_type_cfg *p_cfg = &p_mngr->conn_cfg[i]; - if (tm_cid_proto(i)) { + if (tm_cid_proto(i) || tm_required) { + if (p_cfg->cid_count) + tm_required = true; + iids->pf_cids += p_cfg->cid_count; + } + + if (tm_cid_proto(i) || tm_vf_required) { + if (p_cfg->cids_per_vf) + tm_vf_required = true; + iids->per_vf_cids += p_cfg->cids_per_vf; } } @@ -696,7 +714,7 @@ int qed_cxt_cfg_ilt_compute(struct qed_hwfn *p_hwfn) /* TM PF */ p_cli = &p_mngr->clients[ILT_CLI_TM]; - qed_cxt_tm_iids(p_mngr, &tm_iids); + qed_cxt_tm_iids(p_hwfn, p_mngr, &tm_iids); total = tm_iids.pf_cids + tm_iids.pf_tids_total; if (total) { p_blk = &p_cli->pf_blks[0]; @@ -1591,7 +1609,7 @@ static void qed_tm_init_pf(struct qed_hwfn *p_hwfn) u8 i; memset(&tm_iids, 0, sizeof(tm_iids)); - qed_cxt_tm_iids(p_mngr, &tm_iids); + qed_cxt_tm_iids(p_hwfn, p_mngr, &tm_iids); /* @@@TBD No pre-scan for now */ -- GitLab From 0e6661b400404028aed71e80b785a3a42b1d85e1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 23 Mar 2017 15:56:13 +0100 Subject: [PATCH 0442/1834] rtmutex: Fix PI chain order integrity [ Upstream commit e0aad5b44ff5d28ac1d6ae70cdf84ca228e889dc ] rt_mutex_waiter::prio is a copy of task_struct::prio which is updated during the PI chain walk, such that the PI chain order isn't messed up by (asynchronous) task state updates. Currently rt_mutex_waiter_less() uses task state for deadline tasks; this is broken, since the task state can, as said above, change asynchronously, causing the RB tree order to change without actual tree update -> FAIL. Fix this by also copying the deadline into the rt_mutex_waiter state and updating it along with its prio field. Ideally we would also force PI chain updates whenever DL tasks update their deadline parameter, but for first approximation this is less broken than it was. Signed-off-by: Peter Zijlstra (Intel) Cc: juri.lelli@arm.com Cc: bigeasy@linutronix.de Cc: xlpang@redhat.com Cc: rostedt@goodmis.org Cc: mathieu.desnoyers@efficios.com Cc: jdesfossez@efficios.com Cc: bristot@redhat.com Link: http://lkml.kernel.org/r/20170323150216.403992539@infradead.org Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/locking/rtmutex.c | 29 +++++++++++++++++++++++++++-- kernel/locking/rtmutex_common.h | 1 + 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 2c49d76f96c3..196cc460e38d 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -236,8 +236,7 @@ rt_mutex_waiter_less(struct rt_mutex_waiter *left, * then right waiter has a dl_prio() too. */ if (dl_prio(left->prio)) - return dl_time_before(left->task->dl.deadline, - right->task->dl.deadline); + return dl_time_before(left->deadline, right->deadline); return 0; } @@ -704,7 +703,26 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, /* [7] Requeue the waiter in the lock waiter tree. */ rt_mutex_dequeue(lock, waiter); + + /* + * Update the waiter prio fields now that we're dequeued. + * + * These values can have changed through either: + * + * sys_sched_set_scheduler() / sys_sched_setattr() + * + * or + * + * DL CBS enforcement advancing the effective deadline. + * + * Even though pi_waiters also uses these fields, and that tree is only + * updated in [11], we can do this here, since we hold [L], which + * serializes all pi_waiters access and rb_erase() does not care about + * the values of the node being removed. + */ waiter->prio = task->prio; + waiter->deadline = task->dl.deadline; + rt_mutex_enqueue(lock, waiter); /* [8] Release the task */ @@ -831,6 +849,8 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task, static int try_to_take_rt_mutex(struct rt_mutex *lock, struct task_struct *task, struct rt_mutex_waiter *waiter) { + lockdep_assert_held(&lock->wait_lock); + /* * Before testing whether we can acquire @lock, we set the * RT_MUTEX_HAS_WAITERS bit in @lock->owner. This forces all @@ -958,6 +978,8 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, struct rt_mutex *next_lock; int chain_walk = 0, res; + lockdep_assert_held(&lock->wait_lock); + /* * Early deadlock detection. We really don't want the task to * enqueue on itself just to untangle the mess later. It's not @@ -975,6 +997,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock, waiter->task = task; waiter->lock = lock; waiter->prio = task->prio; + waiter->deadline = task->dl.deadline; /* Get the top priority waiter on the lock */ if (rt_mutex_has_waiters(lock)) @@ -1080,6 +1103,8 @@ static void remove_waiter(struct rt_mutex *lock, struct task_struct *owner = rt_mutex_owner(lock); struct rt_mutex *next_lock; + lockdep_assert_held(&lock->wait_lock); + raw_spin_lock(¤t->pi_lock); rt_mutex_dequeue(lock, waiter); current->pi_blocked_on = NULL; diff --git a/kernel/locking/rtmutex_common.h b/kernel/locking/rtmutex_common.h index e317e1cbb3eb..50848b460851 100644 --- a/kernel/locking/rtmutex_common.h +++ b/kernel/locking/rtmutex_common.h @@ -33,6 +33,7 @@ struct rt_mutex_waiter { struct rt_mutex *deadlock_lock; #endif int prio; + u64 deadline; }; /* -- GitLab From b5fa6d91433740c1a4e44e860e088fa10dbcca45 Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Fri, 24 Mar 2017 17:14:05 +0100 Subject: [PATCH 0443/1834] printk: Correctly handle preemption in console_unlock() [ Upstream commit 257ab443118bffc7fdcef38f49cf59be68a3e362 ] Some console drivers code calls console_conditional_schedule() that looks at @console_may_schedule. The value must be cleared when the drivers are called from console_unlock() with interrupts disabled. But rescheduling is fine when the same code is called, for example, from tty operations where the console semaphore is taken via console_lock(). This is why @console_may_schedule is cleared before calling console drivers. The original value is stored to decide if we could sleep between lines. Now, @console_may_schedule is not cleared when we call console_trylock() and jump back to the "again" goto label. This has become a problem, since the commit 6b97a20d3a7909daa066 ("printk: set may_schedule for some of console_trylock() callers"). @console_may_schedule might get enabled now. There is also the opposite problem. console_lock() can be called only from preemptive context. It can always enable scheduling in the console code. But console_trylock() is not able to detect it when CONFIG_PREEMPT_COUNT is disabled. Therefore we should use the original @console_may_schedule value after re-acquiring the console semaphore in console_unlock(). This patch solves both problems by moving the "again" goto label. Alternative solution was to clear and restore the value around call_console_drivers(). Then console_conditional_schedule() could be used also inside console_unlock(). But there was a potential race with console_flush_on_panic() as reported by Sergey Senozhatsky. That function should be called only where there is only one CPU and with interrupts disabled. But better be on the safe side because stopping CPUs might fail. Fixes: 6b97a20d3a7909 ("printk: set may_schedule for some of console_trylock() callers") Link: http://lkml.kernel.org/r/1490372045-22288-1-git-send-email-pmladek@suse.com Suggested-by: Tetsuo Handa Cc: Steven Rostedt Cc: Peter Zijlstra Cc: Andrew Morton Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-fbdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Sergey Senozhatsky Signed-off-by: Petr Mladek Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/printk/printk.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 9c5b231684d0..ab6855a4218b 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2342,7 +2342,7 @@ void console_unlock(void) } /* - * Console drivers are called under logbuf_lock, so + * Console drivers are called with interrupts disabled, so * @console_may_schedule should be cleared before; however, we may * end up dumping a lot of lines, for example, if called from * console registration path, and should invoke cond_resched() @@ -2350,11 +2350,15 @@ void console_unlock(void) * scheduling stall on a slow console leading to RCU stall and * softlockup warnings which exacerbate the issue with more * messages practically incapacitating the system. + * + * console_trylock() is not able to detect the preemptive + * context reliably. Therefore the value must be stored before + * and cleared after the the "again" goto label. */ do_cond_resched = console_may_schedule; +again: console_may_schedule = 0; -again: /* * We released the console_sem lock, so we need to recheck if * cpu is online and (if not) is there at least one CON_ANYTIME -- GitLab From a24c058d89cb18c861c2dcad92f808bb40fdd03e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 10 Feb 2017 13:30:35 +0200 Subject: [PATCH 0444/1834] drm: rcar-du: Handle event when disabling CRTCs [ Upstream commit 6dd47cfd03a058d08b8caffb06194aa0eb109cf1 ] The driver currently handles vblank events only when updating planes on a CRTC. The atomic update API however allows requesting an event when disabling a CRTC. This currently leads to event objects being leaked in the kernel and to events not being sent out. Fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 3322b157106d..1c4d95dea887 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -512,6 +512,13 @@ static void rcar_du_crtc_disable(struct drm_crtc *crtc) rcar_du_crtc_stop(rcrtc); rcar_du_crtc_put(rcrtc); + spin_lock_irq(&crtc->dev->event_lock); + if (crtc->state->event) { + drm_crtc_send_vblank_event(crtc, crtc->state->event); + crtc->state->event = NULL; + } + spin_unlock_irq(&crtc->dev->event_lock); + rcrtc->outputs = 0; } -- GitLab From 7322cf6294aa867a86926b7441105e938c6f26b3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 3 Apr 2017 11:55:19 +0200 Subject: [PATCH 0445/1834] ARM: dts: koelsch: Correct clock frequency of X2 DU clock input MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit ebf06af55c7594ed1fc18469a5cddf911c40e687 ] The X2 crystal oscillator on the Koelsch development board provides a 74.25 MHz clock, not a 148.5 MHz clock. Fixes: cd21cb46e14aae3a ("ARM: shmobile: koelsch: Add DU external pixel clocks to DT") Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Tested-by: Niklas Söderlund Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7791-koelsch.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts index f8a7d090fd01..12841e9bab98 100644 --- a/arch/arm/boot/dts/r8a7791-koelsch.dts +++ b/arch/arm/boot/dts/r8a7791-koelsch.dts @@ -279,7 +279,7 @@ x2_clk: x2-clock { compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <148500000>; + clock-frequency = <74250000>; }; x13_clk: x13-clock { -- GitLab From 304c1e93c0206bd62ba828824ec0e09b79a2e05f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 5 Apr 2017 14:09:48 +0200 Subject: [PATCH 0446/1834] reiserfs: Make cancel_old_flush() reliable [ Upstream commit 71b0576bdb862e964a82c73327cdd1a249c53e67 ] Currently canceling of delayed work that flushes old data using cancel_old_flush() does not prevent work from being requeued. Thus in theory new work can be queued after cancel_old_flush() from reiserfs_freeze() has run. This will become larger problem once flush_old_commits() can requeue the work itself. Fix the problem by recording in sbi->work_queue that flushing work is canceled and should not be requeued. Signed-off-by: Jan Kara Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/journal.c | 2 +- fs/reiserfs/reiserfs.h | 1 + fs/reiserfs/super.c | 21 +++++++++++++++------ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index bc2dde2423c2..76108185854e 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -1959,7 +1959,7 @@ static int do_journal_release(struct reiserfs_transaction_handle *th, * will be requeued because superblock is being shutdown and doesn't * have MS_ACTIVE set. */ - cancel_delayed_work_sync(&REISERFS_SB(sb)->old_work); + reiserfs_cancel_old_flush(sb); /* wait for all commits to finish */ cancel_delayed_work_sync(&SB_JOURNAL(sb)->j_work); diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index 5dcf3ab83886..6ca00471afbf 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h @@ -2948,6 +2948,7 @@ int reiserfs_allocate_list_bitmaps(struct super_block *s, struct reiserfs_list_bitmap *, unsigned int); void reiserfs_schedule_old_flush(struct super_block *s); +void reiserfs_cancel_old_flush(struct super_block *s); void add_save_link(struct reiserfs_transaction_handle *th, struct inode *inode, int truncate); int remove_save_link(struct inode *inode, int truncate); diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index e101d70d2327..dec6c93044fa 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -90,7 +90,9 @@ static void flush_old_commits(struct work_struct *work) s = sbi->s_journal->j_work_sb; spin_lock(&sbi->old_work_lock); - sbi->work_queued = 0; + /* Avoid clobbering the cancel state... */ + if (sbi->work_queued == 1) + sbi->work_queued = 0; spin_unlock(&sbi->old_work_lock); reiserfs_sync_fs(s, 1); @@ -117,21 +119,22 @@ void reiserfs_schedule_old_flush(struct super_block *s) spin_unlock(&sbi->old_work_lock); } -static void cancel_old_flush(struct super_block *s) +void reiserfs_cancel_old_flush(struct super_block *s) { struct reiserfs_sb_info *sbi = REISERFS_SB(s); - cancel_delayed_work_sync(&REISERFS_SB(s)->old_work); spin_lock(&sbi->old_work_lock); - sbi->work_queued = 0; + /* Make sure no new flushes will be queued */ + sbi->work_queued = 2; spin_unlock(&sbi->old_work_lock); + cancel_delayed_work_sync(&REISERFS_SB(s)->old_work); } static int reiserfs_freeze(struct super_block *s) { struct reiserfs_transaction_handle th; - cancel_old_flush(s); + reiserfs_cancel_old_flush(s); reiserfs_write_lock(s); if (!(s->s_flags & MS_RDONLY)) { @@ -152,7 +155,13 @@ static int reiserfs_freeze(struct super_block *s) static int reiserfs_unfreeze(struct super_block *s) { + struct reiserfs_sb_info *sbi = REISERFS_SB(s); + reiserfs_allow_writes(s); + spin_lock(&sbi->old_work_lock); + /* Allow old_work to run again */ + sbi->work_queued = 0; + spin_unlock(&sbi->old_work_lock); return 0; } @@ -2194,7 +2203,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) if (sbi->commit_wq) destroy_workqueue(sbi->commit_wq); - cancel_delayed_work_sync(&REISERFS_SB(s)->old_work); + reiserfs_cancel_old_flush(s); reiserfs_free_bitmap_cache(s); if (SB_BUFFER_WITH_SB(s)) -- GitLab From 6073a164923809f024963bf1177e3780bc669ae7 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 4 Apr 2017 15:26:30 -0400 Subject: [PATCH 0447/1834] ASoC: rt5677: Add OF device ID table [ Upstream commit 7b87463edf3e2c16d72eeea3d1cf3c12bb5487c6 ] The driver doesn't have a struct of_device_id table but supported devices are registered via Device Trees. This is working on the assumption that a I2C device registered via OF will always match a legacy I2C device ID and that the MODALIAS reported will always be of the form i2c:. But this could change in the future so the correct approach is to have an OF device ID table if the devices are registered via OF. Before this patch: $ modinfo sound/soc/codecs/snd-soc-rt5677.ko | grep alias alias: i2c:RT5677CE:00 alias: i2c:rt5676 alias: i2c:rt5677 After this patch: $ modinfo sound/soc/codecs/snd-soc-rt5677.ko | grep alias alias: of:N*T*Crealtek,rt5677C* alias: of:N*T*Crealtek,rt5677 alias: i2c:RT5677CE:00 alias: i2c:rt5676 alias: i2c:rt5677 Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/rt5677.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index abc802a5a479..65ac4518ad06 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5035,6 +5035,12 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); +static const struct of_device_id rt5677_of_match[] = { + { .compatible = "realtek,rt5677", }, + { } +}; +MODULE_DEVICE_TABLE(of, rt5677_of_match); + static const struct acpi_gpio_params plug_det_gpio = { RT5677_GPIO_PLUG_DET, 0, false }; static const struct acpi_gpio_params mic_present_gpio = { RT5677_GPIO_MIC_PRESENT_L, 0, false }; static const struct acpi_gpio_params headphone_enable_gpio = { RT5677_GPIO_HP_AMP_SHDN_L, 0, false }; @@ -5294,6 +5300,7 @@ static int rt5677_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = "rt5677", + .of_match_table = rt5677_of_match, }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, -- GitLab From f530c1f0025213f9942297e7ddc6f1b838b7deba Mon Sep 17 00:00:00 2001 From: Easwar Hariharan Date: Mon, 20 Mar 2017 17:25:42 -0700 Subject: [PATCH 0448/1834] IB/hfi1: Check for QSFP presence before attempting reads [ Upstream commit fb897ad315643e5dc1092a115b3cec914b66df9d ] Attempting to read the status of a QSFP cable creates noise in the logs and misses out on setting an appropriate Offline/Disabled Reason if the cable is not plugged in. Check for this prior to attempting the read and attendant retries. Fixes: 673b975f1fba ("IB/hfi1: Add QSFP sanity pre-check") Reviewed-by: Dennis Dalessandro Signed-off-by: Easwar Hariharan Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/chip.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 4682909b021b..3be62ef154d1 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -9489,8 +9489,11 @@ static int test_qsfp_read(struct hfi1_pportdata *ppd) int ret; u8 status; - /* report success if not a QSFP */ - if (ppd->port_type != PORT_TYPE_QSFP) + /* + * Report success if not a QSFP or, if it is a QSFP, but the cable is + * not present + */ + if (ppd->port_type != PORT_TYPE_QSFP || !qsfp_mod_present(ppd)) return 0; /* read byte 2, the status byte */ -- GitLab From ea5ac4090686a015d8ae0f461c30cd079dab2c21 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 2 Apr 2017 23:48:24 +0900 Subject: [PATCH 0449/1834] ALSA: firewire-digi00x: add support for console models of Digi00x series [ Upstream commit 13e005f9f933a35b5e55c9d36f151efe2a8383ec ] Digi00x series includes two types of unit; rack and console. As long as reading information on config rom of Digi 002 console, 'MODEL_ID' field has a different value from the one on Digi 002 rack. We've already got a test report from users with Digi 003 rack. We can assume that console type and rack type has different value in the field. This commit adds a device entry for console type. For following commits, this commit also adds a member to 'struct snd_digi00x' to identify console type. $ cd linux-firewire-utils/src $ python2 ./crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 0404f9d0 bus_info_length 4, crc_length 4, crc 63952 404 31333934 bus_name "1394" 408 60647002 irmc 0, cmc 1, isc 1, bmc 0, cyc_clk_acc 100, max_rec 7 (256) 40c 00a07e00 company_id 00a07e | 410 00a30000 device_id 0000a30000 | EUI-64 00a07e0000a30000 root directory ----------------------------------------------------------------- 414 00058a39 directory_length 5, crc 35385 418 0c0043a0 node capabilities 41c 04000001 hardware version 420 0300a07e vendor 424 81000007 --> descriptor leaf at 440 428 d1000001 --> unit directory at 42c unit directory at 42c ----------------------------------------------------------------- 42c 00046674 directory_length 4, crc 26228 430 120000a3 specifier id 434 13000001 version 438 17000001 model 43c 81000007 --> descriptor leaf at 458 descriptor leaf at 440 ----------------------------------------------------------------- 440 00055913 leaf_length 5, crc 22803 444 000050f2 descriptor_type 00, specifier_ID 50f2 448 80000000 44c 44696769 450 64657369 454 676e0000 descriptor leaf at 458 ----------------------------------------------------------------- 458 0004a6fd leaf_length 4, crc 42749 45c 00000000 textual descriptor 460 00000000 minimal ASCII 464 44696769 "Digi" 468 20303032 " 002" Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/firewire/digi00x/digi00x.c | 13 +++++++++++-- sound/firewire/digi00x/digi00x.h | 1 + 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/sound/firewire/digi00x/digi00x.c b/sound/firewire/digi00x/digi00x.c index cc4776c6ded3..1f5e1d23f31a 100644 --- a/sound/firewire/digi00x/digi00x.c +++ b/sound/firewire/digi00x/digi00x.c @@ -13,7 +13,8 @@ MODULE_AUTHOR("Takashi Sakamoto "); MODULE_LICENSE("GPL v2"); #define VENDOR_DIGIDESIGN 0x00a07e -#define MODEL_DIGI00X 0x000002 +#define MODEL_CONSOLE 0x000001 +#define MODEL_RACK 0x000002 static int name_card(struct snd_dg00x *dg00x) { @@ -129,6 +130,8 @@ static int snd_dg00x_probe(struct fw_unit *unit, spin_lock_init(&dg00x->lock); init_waitqueue_head(&dg00x->hwdep_wait); + dg00x->is_console = entry->model_id == MODEL_CONSOLE; + /* Allocate and register this sound card later. */ INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration); snd_fw_schedule_registration(unit, &dg00x->dwork); @@ -183,7 +186,13 @@ static const struct ieee1394_device_id snd_dg00x_id_table[] = { .match_flags = IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID, .vendor_id = VENDOR_DIGIDESIGN, - .model_id = MODEL_DIGI00X, + .model_id = MODEL_CONSOLE, + }, + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = VENDOR_DIGIDESIGN, + .model_id = MODEL_RACK, }, {} }; diff --git a/sound/firewire/digi00x/digi00x.h b/sound/firewire/digi00x/digi00x.h index 2cd465c0caae..43bcb0ce69c0 100644 --- a/sound/firewire/digi00x/digi00x.h +++ b/sound/firewire/digi00x/digi00x.h @@ -60,6 +60,7 @@ struct snd_dg00x { /* For asynchronous MIDI controls. */ struct snd_rawmidi_substream *in_control; struct snd_fw_async_midi_port out_control; + bool is_console; }; #define DG00X_ADDR_BASE 0xffffe0000000ull -- GitLab From 6818b4da096857cea8d9143cd3e0eeeb602ad862 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sun, 2 Apr 2017 23:48:25 +0900 Subject: [PATCH 0450/1834] ALSA: firewire-digi00x: handle all MIDI messages on streaming packets [ Upstream commit 8820a4cf0cb4cd5c6540a9a18b2cedbdfd5a6891 ] At a commit 9dc5d31cdceb ("ALSA: firewire-digi00x: handle MIDI messages in isochronous packets"), a functionality to handle MIDI messages on isochronous packet was supported. But this includes some of my misunderstanding. This commit is to fix them. For digi00x series, first data channel of data blocks in rx/tx packet includes MIDI messages. The data channel has 0x80 in 8 bit of its MSB, however it's against IEC 61883-6. Unique data format is applied: - Upper 4 bits of LSB represent port number. - 0x0: port 1. - 0x2: port 2. - 0xe: console port. - Lower 4 bits of LSB represent the number of included MIDI message bytes; 0x0/0x1/0x2. - Two bytes of middle of this data channel have MIDI bytes. Especially, MIDI messages from/to console surface are also transferred by isochronous packets, as well as physical MIDI ports. Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/firewire/digi00x/amdtp-dot.c | 55 ++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/sound/firewire/digi00x/amdtp-dot.c b/sound/firewire/digi00x/amdtp-dot.c index b3cffd01a19f..a4688545339c 100644 --- a/sound/firewire/digi00x/amdtp-dot.c +++ b/sound/firewire/digi00x/amdtp-dot.c @@ -28,6 +28,9 @@ */ #define MAX_MIDI_RX_BLOCKS 8 +/* 3 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) + 1. */ +#define MAX_MIDI_PORTS 3 + /* * The double-oh-three algorithm was discovered by Robin Gareus and Damien * Zammit in 2012, with reverse-engineering for Digi 003 Rack. @@ -42,10 +45,8 @@ struct amdtp_dot { unsigned int pcm_channels; struct dot_state state; - unsigned int midi_ports; - /* 2 = MAX(DOT_MIDI_IN_PORTS, DOT_MIDI_OUT_PORTS) */ - struct snd_rawmidi_substream *midi[2]; - int midi_fifo_used[2]; + struct snd_rawmidi_substream *midi[MAX_MIDI_PORTS]; + int midi_fifo_used[MAX_MIDI_PORTS]; int midi_fifo_limit; void (*transfer_samples)(struct amdtp_stream *s, @@ -124,8 +125,8 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, return -EBUSY; /* - * A first data channel is for MIDI conformant data channel, the rest is - * Multi Bit Linear Audio data channel. + * A first data channel is for MIDI messages, the rest is Multi Bit + * Linear Audio data channel. */ err = amdtp_stream_set_parameters(s, rate, pcm_channels + 1); if (err < 0) @@ -135,11 +136,6 @@ int amdtp_dot_set_parameters(struct amdtp_stream *s, unsigned int rate, p->pcm_channels = pcm_channels; - if (s->direction == AMDTP_IN_STREAM) - p->midi_ports = DOT_MIDI_IN_PORTS; - else - p->midi_ports = DOT_MIDI_OUT_PORTS; - /* * We do not know the actual MIDI FIFO size of most devices. Just * assume two bytes, i.e., one byte can be received over the bus while @@ -281,13 +277,25 @@ static void write_midi_messages(struct amdtp_stream *s, __be32 *buffer, b = (u8 *)&buffer[0]; len = 0; - if (port < p->midi_ports && + if (port < MAX_MIDI_PORTS && midi_ratelimit_per_packet(s, port) && p->midi[port] != NULL) len = snd_rawmidi_transmit(p->midi[port], b + 1, 2); if (len > 0) { - b[3] = (0x10 << port) | len; + /* + * Upper 4 bits of LSB represent port number. + * - 0000b: physical MIDI port 1. + * - 0010b: physical MIDI port 2. + * - 1110b: console MIDI port. + */ + if (port == 2) + b[3] = 0xe0; + else if (port == 1) + b[3] = 0x20; + else + b[3] = 0x00; + b[3] |= len; midi_use_bytes(s, port, len); } else { b[1] = 0; @@ -309,11 +317,22 @@ static void read_midi_messages(struct amdtp_stream *s, __be32 *buffer, for (f = 0; f < data_blocks; f++) { b = (u8 *)&buffer[0]; - port = b[3] >> 4; - len = b[3] & 0x0f; - if (port < p->midi_ports && p->midi[port] && len > 0) - snd_rawmidi_receive(p->midi[port], b + 1, len); + len = b[3] & 0x0f; + if (len > 0) { + /* + * Upper 4 bits of LSB represent port number. + * - 0000b: physical MIDI port 1. Use port 0. + * - 1110b: console MIDI port. Use port 2. + */ + if (b[3] >> 4 > 0) + port = 2; + else + port = 0; + + if (port < MAX_MIDI_PORTS && p->midi[port]) + snd_rawmidi_receive(p->midi[port], b + 1, len); + } buffer += s->data_block_quadlets; } @@ -364,7 +383,7 @@ void amdtp_dot_midi_trigger(struct amdtp_stream *s, unsigned int port, { struct amdtp_dot *p = s->protocol; - if (port < p->midi_ports) + if (port < MAX_MIDI_PORTS) ACCESS_ONCE(p->midi[port]) = midi; } -- GitLab From 1f7b46d22802e7adefd2c4f3d13773cb8cb35b92 Mon Sep 17 00:00:00 2001 From: Phil Turnbull Date: Wed, 23 Nov 2016 13:33:58 -0500 Subject: [PATCH 0451/1834] fm10k: correctly check if interface is removed [ Upstream commit 540fca35e38d15777b310f450f63f056e63039f5 ] FM10K_REMOVED expects a hardware address, not a 'struct fm10k_hw'. Fixes: 5cb8db4a4cbc ("fm10k: Add support for VF") Signed-off-by: Phil Turnbull Tested-by: Krishneil Singh Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c index 5241e0873397..7041d83d48bf 100644 --- a/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c +++ b/drivers/net/ethernet/intel/fm10k/fm10k_ethtool.c @@ -942,7 +942,7 @@ static void fm10k_self_test(struct net_device *dev, memset(data, 0, sizeof(*data) * FM10K_TEST_LEN); - if (FM10K_REMOVED(hw)) { + if (FM10K_REMOVED(hw->hw_addr)) { netif_err(interface, drv, dev, "Interface removed - test blocked\n"); eth_test->flags |= ETH_TEST_FL_FAILED; -- GitLab From d4894a600657ccf2d58ebf9af37a69b0a756f773 Mon Sep 17 00:00:00 2001 From: Thor Thayer Date: Wed, 5 Apr 2017 13:01:02 -0500 Subject: [PATCH 0452/1834] EDAC, altera: Fix peripheral warnings for Cyclone5 [ Upstream commit 25b223ddfe2a557307c05fe673e09d94ae950877 ] The peripherals' RAS functionality only exist on the Arria10 SoCFPGA. The Cyclone5 initialization generates EDAC warnings when the peripherals aren't found in the device tree. Fix by checking for Arria10 in the init functions. Signed-off-by: Thor Thayer Cc: linux-edac Link: http://lkml.kernel.org/r/1491415262-5018-1-git-send-email-thor.thayer@linux.intel.com Signed-off-by: Borislav Petkov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/edac/altera_edac.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 58d3e2b39b5b..61262a7a5c3a 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1020,13 +1020,23 @@ altr_init_a10_ecc_block(struct device_node *np, u32 irq_mask, return ret; } +static int socfpga_is_a10(void) +{ + return of_machine_is_compatible("altr,socfpga-arria10"); +} + static int validate_parent_available(struct device_node *np); static const struct of_device_id altr_edac_a10_device_of_match[]; static int __init __maybe_unused altr_init_a10_ecc_device_type(char *compat) { int irq; - struct device_node *child, *np = of_find_compatible_node(NULL, NULL, - "altr,socfpga-a10-ecc-manager"); + struct device_node *child, *np; + + if (!socfpga_is_a10()) + return -ENODEV; + + np = of_find_compatible_node(NULL, NULL, + "altr,socfpga-a10-ecc-manager"); if (!np) { edac_printk(KERN_ERR, EDAC_DEVICE, "ECC Manager not found\n"); return -ENODEV; @@ -1542,8 +1552,12 @@ static const struct edac_device_prv_data a10_sdmmceccb_data = { static int __init socfpga_init_sdmmc_ecc(void) { int rc = -ENODEV; - struct device_node *child = of_find_compatible_node(NULL, NULL, - "altr,socfpga-sdmmc-ecc"); + struct device_node *child; + + if (!socfpga_is_a10()) + return -ENODEV; + + child = of_find_compatible_node(NULL, NULL, "altr,socfpga-sdmmc-ecc"); if (!child) { edac_printk(KERN_WARNING, EDAC_DEVICE, "SDMMC node not found\n"); return -ENODEV; -- GitLab From 7cd70b3f8ce3ee9ff06bebbbdeb87e38f26ec1aa Mon Sep 17 00:00:00 2001 From: Mauricio Faria de Oliveira Date: Wed, 5 Apr 2017 12:18:19 -0300 Subject: [PATCH 0453/1834] scsi: ses: don't get power status of SES device slot on probe [ Upstream commit 75106523f39751390b5789b36ee1d213b3af1945 ] The commit 08024885a2a3 ("ses: Add power_status to SES device slot") introduced the 'power_status' attribute to enclosure components and the associated callbacks. There are 2 callbacks available to get the power status of a device: 1) ses_get_power_status() for 'struct enclosure_component_callbacks' 2) get_component_power_status() for the sysfs device attribute (these are available for kernel-space and user-space, respectively.) However, despite both methods being available to get power status on demand, that commit also introduced a call to get power status in ses_enclosure_data_process(). This dramatically increased the total probe time for SCSI devices on larger configurations, because ses_enclosure_data_process() is called several times during the SCSI devices probe and loops over the component devices (but that is another problem, another patch). That results in a tremendous continuous hammering of SCSI Receive Diagnostics commands to the enclosure-services device, which does delay the total probe time for the SCSI devices __significantly__: Originally, ~34 minutes on a system attached to ~170 disks: [ 9214.490703] mpt3sas version 13.100.00.00 loaded ... [11256.580231] scsi 17:0:177:0: qdepth(16), tagged(1), simple(0), ordered(0), scsi_level(6), cmd_que(1) With this patch, it decreased to ~2.5 minutes -- a 13.6x faster [ 1002.992533] mpt3sas version 13.100.00.00 loaded ... [ 1151.978831] scsi 11:0:177:0: qdepth(16), tagged(1), simple(0), ordered(0), scsi_level(6), cmd_que(1) Back to the commit discussion.. on the ses_get_power_status() call introduced in ses_enclosure_data_process(): impact of removing it. That may possibly be in place to initialize the power status value on device probe. However, those 2 functions available to retrieve that value _do_ automatically refresh/update it. So the potential benefit would be a direct access of the 'power_status' field which does not use the callbacks... But the only reader of 'struct enclosure_component::power_status' is the get_component_power_status() callback for sysfs attribute, and it _does_ check for and call the .get_power_status callback, (which indeed is defined and implemented by that commit), so the power status value is, again, automatically updated. So, the remaining potential for a direct/non-callback access to the power_status attribute would be out-of-tree modules -- well, for those, if they are for whatever reason interested in values that are set during device probe and not up-to-date by the time they need it.. well, that would be curious. Well, to handle that more properly, set the initial power state value to '-1' (i.e., uninitialized) instead of '1' (power 'on'), and check for it in that callback which may do an direct access to the field value _if_ a callback function is not defined. Signed-off-by: Mauricio Faria de Oliveira Fixes: 08024885a2a3 ("ses: Add power_status to SES device slot") Reviewed-by: Dan Williams Reviewed-by: Song Liu Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/enclosure.c | 7 ++++++- drivers/scsi/ses.c | 1 - 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index cc91f7b3d90c..eb29113e0bac 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -148,7 +148,7 @@ enclosure_register(struct device *dev, const char *name, int components, for (i = 0; i < components; i++) { edev->component[i].number = -1; edev->component[i].slot = -1; - edev->component[i].power_status = 1; + edev->component[i].power_status = -1; } mutex_lock(&container_list_lock); @@ -600,6 +600,11 @@ static ssize_t get_component_power_status(struct device *cdev, if (edev->cb->get_power_status) edev->cb->get_power_status(edev, ecomp); + + /* If still uninitialized, the callback failed or does not exist. */ + if (ecomp->power_status == -1) + return (edev->cb->get_power_status) ? -EIO : -ENOTTY; + return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off"); } diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 50adabbb5808..f1cdf32d7514 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -548,7 +548,6 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, ecomp = &edev->component[components++]; if (!IS_ERR(ecomp)) { - ses_get_power_status(edev, ecomp); if (addl_desc_ptr) ses_process_descriptor( ecomp, -- GitLab From b07b26448103a94bd6353a38af0e039488201c23 Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Wed, 5 Apr 2017 21:20:11 +0300 Subject: [PATCH 0454/1834] qed: Correct MSI-x for storage [ Upstream commit 2f78227874754b1e10cd348fd6e7693b0dabb3f6 ] When qedr is enabled, qed would try dividing the msi-x vectors between L2 and RoCE, starting with L2 and providing it with sufficient vectors for its queues. Problem is qed would also do that for storage partitions, and as those don't need queues it would lead qed to award those partitions with 0 msi-x vectors, causing them to believe theye're using INTa and preventing them from operating. Fixes: 51ff17251c9c ("qed: Add support for RoCE hw init") Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 333c7442e48a..dba3fbe4800e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -711,7 +711,8 @@ static int qed_slowpath_setup_int(struct qed_dev *cdev, cdev->int_params.fp_msix_cnt = cdev->int_params.out.num_vectors - cdev->num_hwfns; - if (!IS_ENABLED(CONFIG_QED_RDMA)) + if (!IS_ENABLED(CONFIG_QED_RDMA) || + QED_LEADING_HWFN(cdev)->hw_info.personality != QED_PCI_ETH_ROCE) return 0; for_each_hwfn(cdev, i) -- GitLab From d55a55bc8889f360a686e91fe740048cb7733da6 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Thu, 6 Apr 2017 06:55:24 -0700 Subject: [PATCH 0455/1834] apparmor: Make path_max parameter readonly [ Upstream commit 622f6e3265707ebf02ba776ac6e68003bcc31213 ] The path_max parameter determines the max size of buffers allocated but it should not be setable at run time. If can be used to cause an oops root@ubuntu:~# echo 16777216 > /sys/module/apparmor/parameters/path_max root@ubuntu:~# cat /sys/module/apparmor/parameters/path_max Killed [ 122.141911] BUG: unable to handle kernel paging request at ffff880080945fff [ 122.143497] IP: [] d_absolute_path+0x44/0xa0 [ 122.144742] PGD 220c067 PUD 0 [ 122.145453] Oops: 0002 [#1] SMP [ 122.146204] Modules linked in: vmw_vsock_vmci_transport vsock ppdev vmw_balloon snd_ens1371 btusb snd_ac97_codec gameport snd_rawmidi btrtl snd_seq_device ac97_bus btbcm btintel snd_pcm input_leds bluetooth snd_timer snd joydev soundcore serio_raw coretemp shpchp nfit parport_pc i2c_piix4 8250_fintek vmw_vmci parport mac_hid ib_iser rdma_cm iw_cm ib_cm ib_sa ib_mad ib_core ib_addr iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi autofs4 btrfs raid10 raid456 async_raid6_recov async_memcpy async_pq async_xor async_tx xor raid6_pq libcrc32c raid1 raid0 multipath linear hid_generic usbhid hid crct10dif_pclmul crc32_pclmul ghash_clmulni_intel aesni_intel aes_x86_64 lrw gf128mul glue_helper ablk_helper cryptd vmwgfx psmouse mptspi ttm mptscsih drm_kms_helper mptbase syscopyarea scsi_transport_spi sysfillrect [ 122.163365] ahci sysimgblt e1000 fb_sys_fops libahci drm pata_acpi fjes [ 122.164747] CPU: 3 PID: 1501 Comm: bash Not tainted 4.4.0-59-generic #80-Ubuntu [ 122.166250] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 07/02/2015 [ 122.168611] task: ffff88003496aa00 ti: ffff880076474000 task.ti: ffff880076474000 [ 122.170018] RIP: 0010:[] [] d_absolute_path+0x44/0xa0 [ 122.171525] RSP: 0018:ffff880076477b90 EFLAGS: 00010206 [ 122.172462] RAX: ffff880080945fff RBX: 0000000000000000 RCX: 0000000001000000 [ 122.173709] RDX: 0000000000ffffff RSI: ffff880080946000 RDI: ffff8800348a1010 [ 122.174978] RBP: ffff880076477bb8 R08: ffff880076477c80 R09: 0000000000000000 [ 122.176227] R10: 00007ffffffff000 R11: ffff88007f946000 R12: ffff88007f946000 [ 122.177496] R13: ffff880076477c80 R14: ffff8800348a1010 R15: ffff8800348a2400 [ 122.178745] FS: 00007fd459eb4700(0000) GS:ffff88007b6c0000(0000) knlGS:0000000000000000 [ 122.180176] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 122.181186] CR2: ffff880080945fff CR3: 0000000073422000 CR4: 00000000001406e0 [ 122.182469] Stack: [ 122.182843] 00ffffff00000001 ffff880080946000 0000000000000000 0000000000000000 [ 122.184409] 00000000570f789c ffff880076477c30 ffffffff81385671 ffff88007a2e7a58 [ 122.185810] 0000000000000000 ffff880076477c88 01000000008a1000 0000000000000000 [ 122.187231] Call Trace: [ 122.187680] [] aa_path_name+0x81/0x370 [ 122.188637] [] profile_transition+0xbd/0xb80 [ 122.190181] [] ? zone_statistics+0x7c/0xa0 [ 122.191674] [] apparmor_bprm_set_creds+0x9b0/0xac0 [ 122.193288] [] ? ext4_xattr_get+0x81/0x220 [ 122.194793] [] ? ext4_xattr_security_get+0x1c/0x30 [ 122.196392] [] ? get_vfs_caps_from_disk+0x69/0x110 [ 122.198004] [] ? mnt_may_suid+0x3f/0x50 [ 122.199737] [] ? cap_bprm_set_creds+0xa3/0x600 [ 122.201377] [] security_bprm_set_creds+0x33/0x50 [ 122.203024] [] prepare_binprm+0x85/0x190 [ 122.204515] [] do_execveat_common.isra.33+0x485/0x710 [ 122.206200] [] SyS_execve+0x3a/0x50 [ 122.207615] [] stub_execve+0x5/0x5 [ 122.208978] [] ? entry_SYSCALL_64_fastpath+0x16/0x71 [ 122.210615] Code: f8 31 c0 48 63 c2 83 ea 01 48 c7 45 e8 00 00 00 00 48 01 c6 85 d2 48 c7 45 f0 00 00 00 00 48 89 75 e0 89 55 dc 78 0c 48 8d 46 ff 46 ff 00 48 89 45 e0 48 8d 55 e0 48 8d 4d dc 48 8d 75 e8 e8 [ 122.217320] RIP [] d_absolute_path+0x44/0xa0 [ 122.218860] RSP [ 122.219919] CR2: ffff880080945fff [ 122.220936] ---[ end trace 506cdbd85eb6c55e ]--- Reported-by: Tetsuo Handa Signed-off-by: John Johansen Signed-off-by: James Morris Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- security/apparmor/lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 7d3a98b2d55a..02cc952b86aa 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c @@ -707,7 +707,7 @@ module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR); /* Maximum pathname length before accesses will start getting rejected */ unsigned int aa_g_path_max = 2 * PATH_MAX; -module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR); +module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); /* Determines how paranoid loading of policy is and how much verification * on the loaded policy is done. -- GitLab From 79a6866647f91c27af165aa1223d305b2c118e44 Mon Sep 17 00:00:00 2001 From: Nate Watterson Date: Fri, 7 Apr 2017 01:36:20 -0400 Subject: [PATCH 0456/1834] iommu/iova: Fix underflow bug in __alloc_and_insert_iova_range [ Upstream commit 5016bdb796b3726eec043ca0ce3be981f712c756 ] Normally, calling alloc_iova() using an iova_domain with insufficient pfns remaining between start_pfn and dma_limit will fail and return a NULL pointer. Unexpectedly, if such a "full" iova_domain contains an iova with pfn_lo == 0, the alloc_iova() call will instead succeed and return an iova containing invalid pfns. This is caused by an underflow bug in __alloc_and_insert_iova_range() that occurs after walking the "full" iova tree when the search ends at the iova with pfn_lo == 0 and limit_pfn is then adjusted to be just below that (-1). This (now huge) limit_pfn gives the impression that a vast amount of space is available between it and start_pfn and thus a new iova is allocated with the invalid pfn_hi value, 0xFFF.... . To rememdy this, a check is introduced to ensure that adjustments to limit_pfn will not underflow. This issue has been observed in the wild, and is easily reproduced with the following sample code. struct iova_domain *iovad = kzalloc(sizeof(*iovad), GFP_KERNEL); struct iova *rsvd_iova, *good_iova, *bad_iova; unsigned long limit_pfn = 3; unsigned long start_pfn = 1; unsigned long va_size = 2; init_iova_domain(iovad, SZ_4K, start_pfn, limit_pfn); rsvd_iova = reserve_iova(iovad, 0, 0); good_iova = alloc_iova(iovad, va_size, limit_pfn, true); bad_iova = alloc_iova(iovad, va_size, limit_pfn, true); Prior to the patch, this yielded: *rsvd_iova == {0, 0} /* Expected */ *good_iova == {2, 3} /* Expected */ *bad_iova == {-2, -1} /* Oh no... */ After the patch, bad_iova is NULL as expected since inadequate space remains between limit_pfn and start_pfn after allocating good_iova. Signed-off-by: Nate Watterson Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/iova.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index e23001bfcfee..f106fd9782bf 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -138,7 +138,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, break; /* found a free slot */ } adjust_limit_pfn: - limit_pfn = curr_iova->pfn_lo - 1; + limit_pfn = curr_iova->pfn_lo ? (curr_iova->pfn_lo - 1) : 0; move_left: prev = curr; curr = rb_prev(curr); -- GitLab From b0d7b1af256cedf0cd1af08c32c56279e15b601e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 26 Mar 2017 23:51:24 +0200 Subject: [PATCH 0457/1834] kvm/svm: Setup MCG_CAP on AMD properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 74f169090b6f36b867c9df0454366dd9af6f62d1 ] MCG_CAP[63:9] bits are reserved on AMD. However, on an AMD guest, this MSR returns 0x100010a. More specifically, bit 24 is set, which is simply wrong. That bit is MCG_SER_P and is present only on Intel. Thus, clean up the reserved bits in order not to confuse guests. Signed-off-by: Borislav Petkov Cc: Joerg Roedel Cc: Paolo Bonzini Cc: Radim Krčmář Signed-off-by: Paolo Bonzini Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 24d2a3ee743f..8c99f2fbae80 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -5449,6 +5449,12 @@ static inline void avic_post_state_restore(struct kvm_vcpu *vcpu) avic_handle_ldr_update(vcpu); } +static void svm_setup_mce(struct kvm_vcpu *vcpu) +{ + /* [63:9] are reserved. */ + vcpu->arch.mcg_cap &= 0x1ff; +} + static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled, @@ -5564,6 +5570,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .pmu_ops = &amd_pmu_ops, .deliver_posted_interrupt = svm_deliver_avic_intr, .update_pi_irte = svm_update_pi_irte, + .setup_mce = svm_setup_mce, }; static int __init svm_init(void) -- GitLab From afd9ccdd1422d0c1b2e19afbcab7780026114f76 Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Wed, 5 Apr 2017 09:14:40 -0700 Subject: [PATCH 0458/1834] kvm: nVMX: Disallow userspace-injected exceptions in guest mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 28d06353881939703c34d82a1465136af176c620 ] The userspace exception injection API and code path are entirely unprepared for exceptions that might cause a VM-exit from L2 to L1, so the best course of action may be to simply disallow this for now. 1. The API provides no mechanism for userspace to specify the new DR6 bits for a #DB exception or the new CR2 value for a #PF exception. Presumably, userspace is expected to modify these registers directly with KVM_SET_SREGS before the next KVM_RUN ioctl. However, in the event that L1 intercepts the exception, these registers should not be changed. Instead, the new values should be provided in the exit_qualification field of vmcs12 (Intel SDM vol 3, section 27.1). 2. In the case of a userspace-injected #DB, inject_pending_event() clears DR7.GD before calling vmx_queue_exception(). However, in the event that L1 intercepts the exception, this is too early, because DR7.GD should not be modified by a #DB that causes a VM-exit directly (Intel SDM vol 3, section 27.1). 3. If the injected exception is a #PF, nested_vmx_check_exception() doesn't properly check whether or not L1 is interested in the associated error code (using the #PF error code mask and match fields from vmcs12). It may either return 0 when it should call nested_vmx_vmexit() or vice versa. 4. nested_vmx_check_exception() assumes that it is dealing with a hardware-generated exception intercept from L2, with some of the relevant details (the VM-exit interruption-information and the exit qualification) live in vmcs02. For userspace-injected exceptions, this is not the case. 5. prepare_vmcs12() assumes that when its exit_intr_info argument specifies valid information with a valid error code that it can VMREAD the VM-exit interruption error code from vmcs02. For userspace-injected exceptions, this is not the case. Signed-off-by: Jim Mattson Signed-off-by: Radim Krčmář Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/x86.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4b19ec1da22d..3aaaf305420d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3070,7 +3070,8 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu, return -EINVAL; if (events->exception.injected && - (events->exception.nr > 31 || events->exception.nr == NMI_VECTOR)) + (events->exception.nr > 31 || events->exception.nr == NMI_VECTOR || + is_guest_mode(vcpu))) return -EINVAL; /* INITs are latched while in SMM */ -- GitLab From b8c231ebced08cc005e164ad841cc6395596189e Mon Sep 17 00:00:00 2001 From: Liam Beguin Date: Fri, 7 Apr 2017 17:03:24 +0200 Subject: [PATCH 0459/1834] video: ARM CLCD: fix dma allocation size [ Upstream commit 9a1c779e6b06855e41099caa6f15b3b584dfa88c ] This patch forces the frambuffer size to be aligned on kernel pages. During the board startup, the splash screed did appear; the "ts_test" program or our application were not able to start. The following error message was reported: error: failed to map framebuffer device to memory. LinuxFB: driver cannot connect The issue was discovered, on the LPC32xx platform, during the migration of the LCD definition from the board file to the device tree. Signed-off-by: Liam Beguin Signed-off-by: Sylvain Lemieux Cc: Vladimir Zapolskiy Cc: Russell King Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/amba-clcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c index ec2671d98abc..89880b70cc28 100644 --- a/drivers/video/fbdev/amba-clcd.c +++ b/drivers/video/fbdev/amba-clcd.c @@ -892,8 +892,8 @@ static int clcdfb_of_dma_setup(struct clcd_fb *fb) if (err) return err; - framesize = fb->panel->mode.xres * fb->panel->mode.yres * - fb->panel->bpp / 8; + framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres * + fb->panel->bpp / 8); fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize, &dma, GFP_KERNEL); if (!fb->fb.screen_base) -- GitLab From 7d6140b4de8b7e41f5cc9fab01fd7a91f72108f9 Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Wed, 29 Mar 2017 15:00:54 +1100 Subject: [PATCH 0460/1834] drm/radeon: Fail fb creation from imported dma-bufs. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a294043b2fbd8de69d161457ed0c7a4026bbfa5a ] Any use of the framebuffer will migrate it to VRAM, which is not sensible for an imported dma-buf. v2: Use DRM_DEBUG_KMS to prevent userspace accidentally spamming dmesg. Reviewed-by: Michel Dänzer Reviewed-by: Christian König Signed-off-by: Christopher James Halse Rogers CC: amd-gfx@lists.freedesktop.org Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index cdb8cb568c15..ca1caf405832 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1352,6 +1352,12 @@ radeon_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOENT); } + /* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */ + if (obj->import_attach) { + DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n"); + return ERR_PTR(-EINVAL); + } + radeon_fb = kzalloc(sizeof(*radeon_fb), GFP_KERNEL); if (radeon_fb == NULL) { drm_gem_object_unreference_unlocked(obj); -- GitLab From 3820303837014a00e40e69f9a648aed6cc78f92a Mon Sep 17 00:00:00 2001 From: Christopher James Halse Rogers Date: Wed, 29 Mar 2017 15:02:11 +1100 Subject: [PATCH 0461/1834] drm/amdgpu: Fail fb creation from imported dma-bufs. (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 1769152ac64b0b07583f696b621624df2ca4c840 ] Any use of the framebuffer will migrate it to VRAM, which is not sensible for an imported dma-buf. v2: Use DRM_DEBUG_KMS to prevent userspace accidentally spamming dmesg. Reviewed-by: Michel Dänzer Reviewed-by: Christian König Signed-off-by: Christopher James Halse Rogers CC: amd-gfx@lists.freedesktop.org Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_display.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 083e2b429872..15a2d8f3725d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -533,6 +533,12 @@ amdgpu_user_framebuffer_create(struct drm_device *dev, return ERR_PTR(-ENOENT); } + /* Handle is imported dma-buf, so cannot be migrated to VRAM for scanout */ + if (obj->import_attach) { + DRM_DEBUG_KMS("Cannot create framebuffer from imported dma_buf\n"); + return ERR_PTR(-EINVAL); + } + amdgpu_fb = kzalloc(sizeof(*amdgpu_fb), GFP_KERNEL); if (amdgpu_fb == NULL) { drm_gem_object_unreference_unlocked(obj); -- GitLab From 543a1817e58005b5db834a5aa60a78d9095cad81 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Thu, 6 Apr 2017 20:31:20 +0800 Subject: [PATCH 0462/1834] drm/rockchip: vop: Enable pm domain before vop_initial [ Upstream commit 5e570373c015b60a68828b1cd9d475cb33d3be4b ] We're trying to access vop registers here, so need to make sure the pm domain is on. Normally it should be enabled by the bootloader, but there's no guarantee of it. And if we wanna do unbind/bind, it would also cause the device to hang. And this patch also does these: 1/ move vop_initial to the end of vop_bind for eaiser error handling. 2/ correct the err_put_pm_runtime of vop_enable. Signed-off-by: Jeffy Chen Signed-off-by: Sean Paul Link: http://patchwork.freedesktop.org/patch/msgid/1491481885-13775-8-git-send-email-jeffy.chen@rock-chips.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 29 +++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c7eba305c488..6e3c4acb16ac 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -503,7 +503,7 @@ static int vop_enable(struct drm_crtc *crtc) ret = pm_runtime_get_sync(vop->dev); if (ret < 0) { dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); - goto err_put_pm_runtime; + return ret; } ret = clk_enable(vop->hclk); @@ -1348,10 +1348,16 @@ static int vop_initial(struct vop *vop) return PTR_ERR(vop->dclk); } + ret = pm_runtime_get_sync(vop->dev); + if (ret < 0) { + dev_err(vop->dev, "failed to get pm runtime: %d\n", ret); + return ret; + } + ret = clk_prepare(vop->dclk); if (ret < 0) { dev_err(vop->dev, "failed to prepare dclk\n"); - return ret; + goto err_put_pm_runtime; } /* Enable both the hclk and aclk to setup the vop */ @@ -1411,6 +1417,8 @@ static int vop_initial(struct vop *vop) vop->is_enabled = false; + pm_runtime_put_sync(vop->dev); + return 0; err_disable_aclk: @@ -1419,6 +1427,8 @@ static int vop_initial(struct vop *vop) clk_disable_unprepare(vop->hclk); err_unprepare_dclk: clk_unprepare(vop->dclk); +err_put_pm_runtime: + pm_runtime_put_sync(vop->dev); return ret; } @@ -1519,12 +1529,6 @@ static int vop_bind(struct device *dev, struct device *master, void *data) if (!vop->regsbak) return -ENOMEM; - ret = vop_initial(vop); - if (ret < 0) { - dev_err(&pdev->dev, "cannot initial vop dev - err %d\n", ret); - return ret; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "cannot find irq for vop\n"); @@ -1551,8 +1555,17 @@ static int vop_bind(struct device *dev, struct device *master, void *data) pm_runtime_enable(&pdev->dev); + ret = vop_initial(vop); + if (ret < 0) { + dev_err(&pdev->dev, "cannot initial vop dev - err %d\n", ret); + goto err_disable_pm_runtime; + } + return 0; +err_disable_pm_runtime: + pm_runtime_disable(&pdev->dev); + vop_destroy_crtc(vop); err_enable_irq: enable_irq(vop->irq); /* To balance out the disable_irq above */ return ret; -- GitLab From a9a100b20d71c2a2a959418bebdb651379f99b6a Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Tue, 4 Apr 2017 12:40:16 -0700 Subject: [PATCH 0463/1834] i40e: only register client on iWarp-capable devices [ Upstream commit 004eb614c4d2fcc12a98714fd887a860582f203a ] The client interface is only intended for use on devices that support iWarp. Only register with the client if this is the case. This fixes a panic when loading i40iw on X710 devices. Signed-off-by: Mitch Williams Reported-by: Stefan Assmann Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40e/i40e_main.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index becffd15c092..57c7456a5751 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -11142,10 +11142,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) round_jiffies(jiffies + pf->service_timer_period)); /* add this PF to client device list and launch a client service task */ - err = i40e_lan_add_device(pf); - if (err) - dev_info(&pdev->dev, "Failed to add PF to client API service list: %d\n", - err); + if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + err = i40e_lan_add_device(pf); + if (err) + dev_info(&pdev->dev, "Failed to add PF to client API service list: %d\n", + err); + } #ifdef I40E_FCOE /* create FCoE interface */ @@ -11323,10 +11325,11 @@ static void i40e_remove(struct pci_dev *pdev) i40e_vsi_release(pf->vsi[pf->lan_vsi]); /* remove attached clients */ - ret_code = i40e_lan_del_device(pf); - if (ret_code) { - dev_warn(&pdev->dev, "Failed to delete client device: %d\n", - ret_code); + if (pf->flags & I40E_FLAG_IWARP_ENABLED) { + ret_code = i40e_lan_del_device(pf); + if (ret_code) + dev_warn(&pdev->dev, "Failed to delete client device: %d\n", + ret_code); } /* shutdown and destroy the HMC */ -- GitLab From b1a579996f63e2b6a88e8360953884bb6f965ced Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Mon, 27 Mar 2017 11:09:33 -0600 Subject: [PATCH 0464/1834] coresight: Fixes coresight DT parse to get correct output port ID. [ Upstream commit eeedc5421dd3b51de73e6106405c5c77f920f281 ] Corrected to get the port numbering to allow programmable replicator driver to operate correctly. By convention, CoreSight devices number ports, not endpoints in the .dts files:- port { reg endpoint { } } Existing code read endpoint number - always 0x0, rather than the correct port number. Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/of_coresight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/of_coresight.c b/drivers/hwtracing/coresight/of_coresight.c index 629e031b7456..09142e99e915 100644 --- a/drivers/hwtracing/coresight/of_coresight.c +++ b/drivers/hwtracing/coresight/of_coresight.c @@ -149,7 +149,7 @@ struct coresight_platform_data *of_get_coresight_platform_data( continue; /* The local out port number */ - pdata->outports[i] = endpoint.id; + pdata->outports[i] = endpoint.port; /* * Get a handle on the remote port and parent -- GitLab From ad8d41ba596be6c054e5956b145fa223a5bb8b37 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 28 Mar 2017 11:57:27 +0200 Subject: [PATCH 0465/1834] lkdtm: turn off kcov for lkdtm_rodata_do_nothing: [ Upstream commit 7064dc7fc13b2994d33ae540ffb7a3a05ac463bf ] I ran into a link error on ARM64 for lkdtm_rodata_do_nothing: drivers/misc/built-in.o: In function `lkdtm_rodata_do_nothing': :(.rodata+0x68c8): relocation truncated to fit: R_AARCH64_CALL26 against symbol `__sanitizer_cov_trace_pc' defined in .text section in kernel/built-in.o I did not analyze this further, but my theory is that we would need a trampoline to call __sanitizer_cov_trace_pc(), but the linker (correctly) only adds trampolines for callers in executable sections. Disabling KCOV for this one file avoids the build failure with no other practical downsides I can think of. The problem can only happen on kernels that contain both kcov and lkdtm, so if we want to backport this, it should be in the earliest version that has both (v4.8). Fixes: 5c9a8750a640 ("kernel: add kcov code coverage") Fixes: 9a49a528dcf3 ("lkdtm: add function for testing .rodata section") Signed-off-by: Arnd Bergmann Acked-by: Dmitry Vyukov Acked-by: Kees Cook Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 31983366090a..2bf79ba4a39e 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -61,6 +61,8 @@ lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o +KCOV_INSTRUMENT_lkdtm_rodata.o := n + OBJCOPYFLAGS := OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ --set-section-flags .text=alloc,readonly \ -- GitLab From 7d257fe12895703db6a7f0b47b2fe2a918512310 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Sat, 1 Apr 2017 19:42:09 +0000 Subject: [PATCH 0466/1834] tty: amba-pl011: Fix spurious TX interrupts [ Upstream commit 7d05587c9e0e4611650bb403812e2d492c178a9f ] On SMP systems, we see a lot of spurious TX interrupts when a program generates a steady stream of output to the pl011 UART. The problem can be easily seen when one CPU generates the output while another CPU handles the pl011 interrupts, and the rate of output is low enough not to fill the TX FIFO. The problem seems to be: -- CPU a -- -- CPU b -- (take port lock) pl011_start_tx pl011_start_tx_pio enable TXIM in REG_IMSC -> causes uart tx intr (pl011_int) pl011_tx_chars pl011_int ...tx chars, all done... (wait for port lock) pl011_stop_tx . disable TXIM . (release port lock) -> (take port lock) check for TXIM, not enabled (release port lock) return IRQ_NONE Enabling the TXIM in pl011_start_tx_pio() causes the interrupt to be generated and delivered to CPU b, even though pl011_tx_chars() is able to complete the TX and then disable the tx interrupt. Fix this by enabling TXIM only after pl011_tx_chars, if it is needed. pl011_tx_chars will return a boolean indicating whether the TX interrupts have to be enabled. Debugged-by: Vijaya Kumar Signed-off-by: Jayachandran C Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index e2c33b9528d8..b42d7f1c9089 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1302,14 +1302,15 @@ static void pl011_stop_tx(struct uart_port *port) pl011_dma_tx_stop(uap); } -static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); +static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); /* Start TX with programmed I/O only (no DMA) */ static void pl011_start_tx_pio(struct uart_amba_port *uap) { - uap->im |= UART011_TXIM; - pl011_write(uap->im, uap, REG_IMSC); - pl011_tx_chars(uap, false); + if (pl011_tx_chars(uap, false)) { + uap->im |= UART011_TXIM; + pl011_write(uap->im, uap, REG_IMSC); + } } static void pl011_start_tx(struct uart_port *port) @@ -1389,25 +1390,26 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, return true; } -static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) +/* Returns true if tx interrupts have to be (kept) enabled */ +static bool pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) { struct circ_buf *xmit = &uap->port.state->xmit; int count = uap->fifosize >> 1; if (uap->port.x_char) { if (!pl011_tx_char(uap, uap->port.x_char, from_irq)) - return; + return true; uap->port.x_char = 0; --count; } if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { pl011_stop_tx(&uap->port); - return; + return false; } /* If we are using DMA mode, try to send some characters. */ if (pl011_dma_tx_irq(uap)) - return; + return true; do { if (likely(from_irq) && count-- == 0) @@ -1422,8 +1424,11 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&uap->port); - if (uart_circ_empty(xmit)) + if (uart_circ_empty(xmit)) { pl011_stop_tx(&uap->port); + return false; + } + return true; } static void pl011_modem_status(struct uart_amba_port *uap) -- GitLab From 57a84887bc773d937bc87a558ffdf2f21f91c786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 4 Apr 2017 11:18:51 +0200 Subject: [PATCH 0467/1834] serial: imx: setup DCEDTE early and ensure DCD and RI irqs to be off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e61c38d85b7392e033ee03bca46f1d6006156175 ] If the UART is operated in DTE mode and UCR3_DCD or UCR3_RI are 1 (which is the reset default) and the opposite side pulls the respective line to its active level the irq triggers after it is requested in .probe. These irqs were already disabled in .startup but this might be too late. Also setup of the UFCR_DCEDTE bit (currently done in .set_termios) is done very late which is critical as it also controls direction of some pins. So setup UFCR_DCEDTE earlier (in .probe) and also disable the broken irqs in DTE mode there before requesting irqs. Acked-by: Lucas Stach Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 521a6e450755..f575a33974fa 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1316,19 +1316,10 @@ static int imx_startup(struct uart_port *port) if (!is_imx1_uart(sport)) { temp = readl(sport->port.membase + UCR3); - /* - * The effect of RI and DCD differs depending on the UFCR_DCEDTE - * bit. In DCE mode they control the outputs, in DTE mode they - * enable the respective irqs. At least the DCD irq cannot be - * cleared on i.MX25 at least, so it's not usable and must be - * disabled. I don't have test hardware to check if RI has the - * same problem but I consider this likely so it's disabled for - * now, too. - */ - temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | - UCR3_DTRDEN | UCR3_RI | UCR3_DCD; + temp |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD; if (sport->dte_mode) + /* disable broken interrupts */ temp &= ~(UCR3_RI | UCR3_DCD); writel(temp, sport->port.membase + UCR3); @@ -1583,8 +1574,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, ufcr = readl(sport->port.membase + UFCR); ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); - if (sport->dte_mode) - ufcr |= UFCR_DCEDTE; writel(ufcr, sport->port.membase + UFCR); writel(num, sport->port.membase + UBIR); @@ -2149,6 +2138,27 @@ static int serial_imx_probe(struct platform_device *pdev) UCR1_TXMPTYEN | UCR1_RTSDEN); writel_relaxed(reg, sport->port.membase + UCR1); + if (!is_imx1_uart(sport) && sport->dte_mode) { + /* + * The DCEDTE bit changes the direction of DSR, DCD, DTR and RI + * and influences if UCR3_RI and UCR3_DCD changes the level of RI + * and DCD (when they are outputs) or enables the respective + * irqs. So set this bit early, i.e. before requesting irqs. + */ + writel(UFCR_DCEDTE, sport->port.membase + UFCR); + + /* + * Disable UCR3_RI and UCR3_DCD irqs. They are also not + * enabled later because they cannot be cleared + * (confirmed on i.MX25) which makes them unusable. + */ + writel(IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR, + sport->port.membase + UCR3); + + } else { + writel(0, sport->port.membase + UFCR); + } + clk_disable_unprepare(sport->clk_ipg); /* -- GitLab From e50c396af21ca45061f8550563825c8b84556075 Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 14 Mar 2017 14:21:43 -0700 Subject: [PATCH 0468/1834] MIPS: BPF: Quit clobbering callee saved registers in JIT code. [ Upstream commit 1ef0910cfd681f0bd0b81f8809935b2006e9cfb9 ] If bpf_needs_clear_a() returns true, only actually clear it if it is ever used. If it is not used, we don't save and restore it, so the clearing has the nasty side effect of clobbering caller state. Also, don't emit stack pointer adjustment instructions if the adjustment amount is zero. Signed-off-by: David Daney Cc: James Hogan Cc: Alexei Starovoitov Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/15745/ Signed-off-by: Ralf Baechle Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/net/bpf_jit.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c index 49a2e2226fee..248603739198 100644 --- a/arch/mips/net/bpf_jit.c +++ b/arch/mips/net/bpf_jit.c @@ -526,7 +526,8 @@ static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset) u32 sflags, tmp_flags; /* Adjust the stack pointer */ - emit_stack_offset(-align_sp(offset), ctx); + if (offset) + emit_stack_offset(-align_sp(offset), ctx); tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT; /* sflags is essentially a bitmap */ @@ -578,7 +579,8 @@ static void restore_bpf_jit_regs(struct jit_ctx *ctx, emit_load_stack_reg(r_ra, r_sp, real_off, ctx); /* Restore the sp and discard the scrach memory */ - emit_stack_offset(align_sp(offset), ctx); + if (offset) + emit_stack_offset(align_sp(offset), ctx); } static unsigned int get_stack_depth(struct jit_ctx *ctx) @@ -625,8 +627,14 @@ static void build_prologue(struct jit_ctx *ctx) if (ctx->flags & SEEN_X) emit_jit_reg_move(r_X, r_zero, ctx); - /* Do not leak kernel data to userspace */ - if (bpf_needs_clear_a(&ctx->skf->insns[0])) + /* + * Do not leak kernel data to userspace, we only need to clear + * r_A if it is ever used. In fact if it is never used, we + * will not save/restore it, so clearing it in this case would + * corrupt the state of the caller. + */ + if (bpf_needs_clear_a(&ctx->skf->insns[0]) && + (ctx->flags & SEEN_A)) emit_jit_reg_move(r_A, r_zero, ctx); } -- GitLab From 5b52c8c195c43981557474528fa0b9340b3176ca Mon Sep 17 00:00:00 2001 From: David Daney Date: Tue, 14 Mar 2017 14:21:44 -0700 Subject: [PATCH 0469/1834] MIPS: BPF: Fix multiple problems in JIT skb access helpers. [ Upstream commit a81507c79f4ae9a0f9fb1054b59b62a090620dd9 ] o Socket data is unsigned, so use unsigned accessors instructions. o Fix path result pointer generation arithmetic. o Fix half-word byte swapping code for unsigned semantics. Signed-off-by: David Daney Cc: James Hogan Cc: Alexei Starovoitov Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Cc: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/15747/ Signed-off-by: Ralf Baechle Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/net/bpf_jit_asm.S | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/mips/net/bpf_jit_asm.S b/arch/mips/net/bpf_jit_asm.S index 5d2e0c8d29c0..88a2075305d1 100644 --- a/arch/mips/net/bpf_jit_asm.S +++ b/arch/mips/net/bpf_jit_asm.S @@ -90,18 +90,14 @@ FEXPORT(sk_load_half_positive) is_offset_in_header(2, half) /* Offset within header boundaries */ PTR_ADDU t1, $r_skb_data, offset - .set reorder - lh $r_A, 0(t1) - .set noreorder + lhu $r_A, 0(t1) #ifdef CONFIG_CPU_LITTLE_ENDIAN # if defined(__mips_isa_rev) && (__mips_isa_rev >= 2) - wsbh t0, $r_A - seh $r_A, t0 + wsbh $r_A, $r_A # else - sll t0, $r_A, 24 - andi t1, $r_A, 0xff00 - sra t0, t0, 16 - srl t1, t1, 8 + sll t0, $r_A, 8 + srl t1, $r_A, 8 + andi t0, t0, 0xff00 or $r_A, t0, t1 # endif #endif @@ -115,7 +111,7 @@ FEXPORT(sk_load_byte_positive) is_offset_in_header(1, byte) /* Offset within header boundaries */ PTR_ADDU t1, $r_skb_data, offset - lb $r_A, 0(t1) + lbu $r_A, 0(t1) jr $r_ra move $r_ret, zero END(sk_load_byte) @@ -139,6 +135,11 @@ FEXPORT(sk_load_byte_positive) * (void *to) is returned in r_s0 * */ +#ifdef CONFIG_CPU_LITTLE_ENDIAN +#define DS_OFFSET(SIZE) (4 * SZREG) +#else +#define DS_OFFSET(SIZE) ((4 * SZREG) + (4 - SIZE)) +#endif #define bpf_slow_path_common(SIZE) \ /* Quick check. Are we within reasonable boundaries? */ \ LONG_ADDIU $r_s1, $r_skb_len, -SIZE; \ @@ -150,7 +151,7 @@ FEXPORT(sk_load_byte_positive) PTR_LA t0, skb_copy_bits; \ PTR_S $r_ra, (5 * SZREG)($r_sp); \ /* Assign low slot to a2 */ \ - move a2, $r_sp; \ + PTR_ADDIU a2, $r_sp, DS_OFFSET(SIZE); \ jalr t0; \ /* Reset our destination slot (DS but it's ok) */ \ INT_S zero, (4 * SZREG)($r_sp); \ -- GitLab From 198142acc08546013a45f1aebcaf72a68561dcd8 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Mon, 13 Mar 2017 16:36:35 +0100 Subject: [PATCH 0470/1834] MIPS: r2-on-r6-emu: Fix BLEZL and BGTZL identification [ Upstream commit 5bba7aa4958e271c3ffceb70d47d3206524cf489 ] Fix the problem of inaccurate identification of instructions BLEZL and BGTZL in R2 emulation code by making sure all necessary encoding specifications are met. Previously, certain R6 instructions could be identified as BLEZL or BGTZL. R2 emulation routine didn't take into account that both BLEZL and BGTZL instructions require their rt field (bits 20 to 16 of instruction encoding) to be 0, and that, at same time, if the value in that field is not 0, the encoding may represent a legitimate MIPS R6 instruction. This means that a problem could occur after emulation optimization, when emulation routine tried to pipeline emulation, picked up a next candidate, and subsequently misrecognized an R6 instruction as BLEZL or BGTZL. It should be said that for single pass strategy, the problem does not happen because CPU doesn't trap on branch-compacts which share opcode space with BLEZL/BGTZL (but have rt field != 0, of course). Signed-off-by: Leonid Yegoshin Signed-off-by: Miodrag Dinic Signed-off-by: Aleksandar Markovic Reported-by: Douglas Leung Reviewed-by: Paul Burton Cc: james.hogan@imgtec.com Cc: petar.jovanovic@imgtec.com Cc: goran.ferenc@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15456/ Signed-off-by: Ralf Baechle Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-r2-to-r6-emul.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index d8227f289d7f..9a46e52864a1 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -1096,10 +1096,20 @@ int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31) } break; - case beql_op: - case bnel_op: case blezl_op: case bgtzl_op: + /* + * For BLEZL and BGTZL, rt field must be set to 0. If this + * is not the case, this may be an encoding of a MIPS R6 + * instruction, so return to CPU execution if this occurs + */ + if (MIPSInst_RT(inst)) { + err = SIGILL; + break; + } + /* fall through */ + case beql_op: + case bnel_op: if (delay_slot(regs)) { err = SIGILL; break; -- GitLab From c86742fc38993fd42672c55cec0ae537279e3fbb Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Mon, 13 Mar 2017 16:36:36 +0100 Subject: [PATCH 0471/1834] MIPS: r2-on-r6-emu: Clear BLTZALL and BGEZALL debugfs counters [ Upstream commit 411dac79cc2ed80f7e348ccc23eb4d8b0ba9f6d5 ] Add missing clearing of BLTZALL and BGEZALL emulation counters in function mipsr2_stats_clear_show(). Previously, it was not possible to reset BLTZALL and BGEZALL emulation counters - their value remained the same even after explicit request via debugfs. As far as other related counters are concerned, they all seem to be properly cleared. This change affects debugfs operation only, core R2 emulation functionality is not affected. Signed-off-by: Aleksandar Markovic Reviewed-by: Paul Burton Cc: james.hogan@imgtec.com Cc: leonid.yegoshin@imgtec.com Cc: douglas.leung@imgtec.com Cc: petar.jovanovic@imgtec.com Cc: miodrag.dinic@imgtec.com Cc: goran.ferenc@imgtec.com Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15517/ Signed-off-by: Ralf Baechle Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/kernel/mips-r2-to-r6-emul.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index 9a46e52864a1..9a4aed652736 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -2339,6 +2339,8 @@ static int mipsr2_stats_clear_show(struct seq_file *s, void *unused) __this_cpu_write((mipsr2bremustats).bgezl, 0); __this_cpu_write((mipsr2bremustats).bltzll, 0); __this_cpu_write((mipsr2bremustats).bgezll, 0); + __this_cpu_write((mipsr2bremustats).bltzall, 0); + __this_cpu_write((mipsr2bremustats).bgezall, 0); __this_cpu_write((mipsr2bremustats).bltzal, 0); __this_cpu_write((mipsr2bremustats).bgezal, 0); __this_cpu_write((mipsr2bremustats).beql, 0); -- GitLab From 735b0f043d484a535a7a8f57157e32bade8ae1ef Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Fri, 6 Jan 2017 10:15:28 -0200 Subject: [PATCH 0472/1834] v4l: vsp1: Prevent multiple streamon race commencing pipeline early [ Upstream commit 4461c84b52b4a952c657505ef7e4e06b016783df ] With multiple inputs through the BRU it is feasible for the streams to race each other at stream-on. Multiple VIDIOC_STREAMON calls racing each other could have process N-1 skipping over the pipeline setup section and then start the pipeline early, if videobuf2 has already enqueued buffers to the driver for process N but not called the .start_streaming() operation yet In the case of the video pipelines, this can present two serious issues. 1) A null-dereference if the pipe->dl is committed at the same time as the vsp1_video_setup_pipeline() is processing 2) A hardware hang, where a display list is committed without having called vsp1_video_setup_pipeline() first Repair this issue, by ensuring that only the stream which configures the pipeline is able to start it. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/vsp1/vsp1_video.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index d351b9c768d2..743aa0febc09 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -792,6 +792,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) { struct vsp1_video *video = vb2_get_drv_priv(vq); struct vsp1_pipeline *pipe = video->rwpf->pipe; + bool start_pipeline = false; unsigned long flags; int ret; @@ -802,11 +803,23 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count) mutex_unlock(&pipe->lock); return ret; } + + start_pipeline = true; } pipe->stream_count++; mutex_unlock(&pipe->lock); + /* + * vsp1_pipeline_ready() is not sufficient to establish that all streams + * are prepared and the pipeline is configured, as multiple streams + * can race through streamon with buffers already queued; Therefore we + * don't even attempt to start the pipeline until the last stream has + * called through here. + */ + if (!start_pipeline) + return 0; + spin_lock_irqsave(&pipe->irqlock, flags); if (vsp1_pipeline_ready(pipe)) vsp1_video_pipeline_run(pipe); -- GitLab From d7928e10b468c465b597d738bc93e30aa4b34dff Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Mon, 27 Feb 2017 10:40:34 -0300 Subject: [PATCH 0473/1834] v4l: vsp1: Register pipe with output WPF [ Upstream commit 1531a208ed861e4bd287444f9466ffcf98383de2 ] The DRM object does not register the pipe with the WPF object. This is used internally throughout the driver as a means of accessing the pipe. As such this breaks operations which require access to the pipe from WPF interrupts. Register the pipe inside the WPF object after it has been declared as the output. Fixes: ff7e97c94d9f ("[media] v4l: vsp1: Store pipeline pointer in rwpf") Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/vsp1/vsp1_drm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c index cd209dccff1b..8e2aa3f8e52f 100644 --- a/drivers/media/platform/vsp1/vsp1_drm.c +++ b/drivers/media/platform/vsp1/vsp1_drm.c @@ -596,6 +596,7 @@ int vsp1_drm_init(struct vsp1_device *vsp1) pipe->bru = &vsp1->bru->entity; pipe->lif = &vsp1->lif->entity; pipe->output = vsp1->wpf[0]; + pipe->output->pipe = pipe; return 0; } -- GitLab From f9ab125d20efab348f5652d3cf80c8cc9bb0c960 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Stehl=C3=A9?= Date: Sun, 9 Apr 2017 22:05:05 +0200 Subject: [PATCH 0474/1834] regulator: isl9305: fix array size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 0c08aaf873174c95e674cf21ffcd041c589d2e5b ] ISL9305_MAX_REGULATOR is the last index used to access the init_data[] array, so we need to add one to this last index to obtain the necessary array size. This fixes the following smatch error: drivers/regulator/isl9305.c:160 isl9305_i2c_probe() error: buffer overflow 'pdata->init_data' 3 <= 3 Fixes: dec38b5ce6a9edb4 ("regulator: isl9305: Add Intersil ISL9305/H driver") Signed-off-by: Vincent Stehlé Cc: Mark Brown Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/platform_data/isl9305.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/platform_data/isl9305.h b/include/linux/platform_data/isl9305.h index 1419133fa69e..4ac1a070af0a 100644 --- a/include/linux/platform_data/isl9305.h +++ b/include/linux/platform_data/isl9305.h @@ -24,7 +24,7 @@ struct regulator_init_data; struct isl9305_pdata { - struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR]; + struct regulator_init_data *init_data[ISL9305_MAX_REGULATOR + 1]; }; #endif -- GitLab From b42b97a5657f49c51f523f691e8a867708a38b80 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 3 Apr 2017 12:11:32 +1000 Subject: [PATCH 0475/1834] md/raid6: Fix anomily when recovering a single device in RAID6. [ Upstream commit 7471fb77ce4dc4cb81291189947fcdf621a97987 ] When recoverying a single missing/failed device in a RAID6, those stripes where the Q block is on the missing device are handled a bit differently. In these cases it is easy to check that the P block is correct, so we do. This results in the P block be destroy. Consequently the P block needs to be read a second time in order to compute Q. This causes lots of seeks and hurts performance. It shouldn't be necessary to re-read P as it can be computed from the DATA. But we only compute blocks on missing devices, since c337869d9501 ("md: do not compute parity unless it is on a failed drive"). So relax the change made in that commit to allow computing of the P block in a RAID6 which it is the only missing that block. This makes RAID6 recovery run much faster as the disk just "before" the recovering device is no longer seeking back-and-forth. Reported-by-tested-by: Brad Campbell Reviewed-by: Dan Williams Signed-off-by: NeilBrown Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 475a7a1bcfe0..4493be50fc6a 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3391,9 +3391,20 @@ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, BUG_ON(test_bit(R5_Wantcompute, &dev->flags)); BUG_ON(test_bit(R5_Wantread, &dev->flags)); BUG_ON(sh->batch_head); + + /* + * In the raid6 case if the only non-uptodate disk is P + * then we already trusted P to compute the other failed + * drives. It is safe to compute rather than re-read P. + * In other cases we only compute blocks from failed + * devices, otherwise check/repair might fail to detect + * a real inconsistency. + */ + if ((s->uptodate == disks - 1) && + ((sh->qd_idx >= 0 && sh->pd_idx == disk_idx) || (s->failed && (disk_idx == s->failed_num[0] || - disk_idx == s->failed_num[1]))) { + disk_idx == s->failed_num[1])))) { /* have disk failed, and we're requested to fetch it; * do compute it */ -- GitLab From 1f8fe98e0e096728a47bda7bf9a632b3e89970b5 Mon Sep 17 00:00:00 2001 From: Zhilong Liu Date: Mon, 10 Apr 2017 14:15:55 +0800 Subject: [PATCH 0476/1834] md.c:didn't unlock the mddev before return EINVAL in array_size_store [ Upstream commit b670883bb9e55ba63a278d83e034faefc01ce2cf ] md.c: it needs to release the mddev lock before the array_size_store() returns. Fixes: ab5a98b132fd ("md-cluster: change array_sectors and update size are not supported") Signed-off-by: Zhilong Liu Reviewed-by: Guoqing Jiang Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/md.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 27d8bb21e04f..a7bc70334f0e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4826,8 +4826,10 @@ array_size_store(struct mddev *mddev, const char *buf, size_t len) return err; /* cluster raid doesn't support change array_sectors */ - if (mddev_is_clustered(mddev)) + if (mddev_is_clustered(mddev)) { + mddev_unlock(mddev); return -EINVAL; + } if (strncmp(buf, "default", 7) == 0) { if (mddev->pers) -- GitLab From 708def5dbf38803b4f6cc370c494f15f15a46aa4 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 3 Apr 2017 12:05:55 +1000 Subject: [PATCH 0477/1834] powerpc/nohash: Fix use of mmu_has_feature() in setup_initial_memory_limit() [ Upstream commit 4868e3508d1934d28961f940ed6b9f1e347ab52c ] setup_initial_memory_limit() is called from early_init_devtree(), which runs prior to feature patching. If the kernel is built with CONFIG_JUMP_LABEL=y and CONFIG_JUMP_LABEL_FEATURE_CHECKS=y then we will potentially get the wrong value. If we also have CONFIG_JUMP_LABEL_FEATURE_CHECK_DEBUG=y we get a warning and backtrace: Warning! mmu_has_feature() used prior to jump label init! CPU: 0 PID: 0 Comm: swapper Not tainted 4.11.0-rc4-gccN-next-20170331-g6af2434 #1 Call Trace: [c000000000fc3d50] [c000000000a26c30] .dump_stack+0xa8/0xe8 (unreliable) [c000000000fc3de0] [c00000000002e6b8] .setup_initial_memory_limit+0xa4/0x104 [c000000000fc3e60] [c000000000d5c23c] .early_init_devtree+0xd0/0x2f8 [c000000000fc3f00] [c000000000d5d3b0] .early_setup+0x90/0x11c [c000000000fc3f90] [c000000000000520] start_here_multiplatform+0x68/0x80 Fix it by using early_mmu_has_feature(). Fixes: c12e6f24d413 ("powerpc: Add option to use jump label for mmu_has_feature()") Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/mm/tlb_nohash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/mm/tlb_nohash.c b/arch/powerpc/mm/tlb_nohash.c index 050badc0ebd3..0b50019505a5 100644 --- a/arch/powerpc/mm/tlb_nohash.c +++ b/arch/powerpc/mm/tlb_nohash.c @@ -751,7 +751,7 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base, * avoid going over total available memory just in case... */ #ifdef CONFIG_PPC_FSL_BOOK3E - if (mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { + if (early_mmu_has_feature(MMU_FTR_TYPE_FSL_E)) { unsigned long linear_sz; unsigned int num_cams; -- GitLab From 813bd8c7e5a0a02c6f9bb332d5b44ec20db02ab0 Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 13 Feb 2017 20:08:08 -0800 Subject: [PATCH 0478/1834] usb: dwc2: Make sure we disconnect the gadget state [ Upstream commit dad3f793f20fbb5c0c342f0f5a0bdf69a4d76089 ] I had seen some odd behavior with HiKey's usb-gadget interface that I finally seemed to have chased down. Basically every other time I plugged in the OTG port, the gadget interface would properly initialize. The other times, I'd get a big WARN_ON in dwc2_hsotg_init_fifo() about the fifo_map not being clear. Ends up if we don't disconnect the gadget state, the fifo-map doesn't get cleared properly, which causes WARN_ON messages and also results in the device not properly being setup as a gadget every other time the OTG port is connected. So this patch adds a call to dwc2_hsotg_disconnect() in the reset path so the state is properly cleared. With it, the gadget interface initializes properly on every plug in. Cc: Wei Xu Cc: Guodong Xu Cc: Amit Pundir Cc: Rob Herring Cc: John Youn Cc: Douglas Anderson Cc: Chen Yu Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Acked-by: John Youn Signed-off-by: John Stultz Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index df5a06578005..dfc0566bb155 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3220,6 +3220,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work) dwc2_core_init(hsotg, false); dwc2_enable_global_interrupts(hsotg); spin_lock_irqsave(&hsotg->lock, flags); + dwc2_hsotg_disconnect(hsotg); dwc2_hsotg_core_init_disconnected(hsotg, false); spin_unlock_irqrestore(&hsotg->lock, flags); dwc2_hsotg_core_connect(hsotg); -- GitLab From d9586e4a882a054e1abd41f3eeb224ecb94e2632 Mon Sep 17 00:00:00 2001 From: Yuyang Du Date: Fri, 24 Mar 2017 04:06:11 +0800 Subject: [PATCH 0479/1834] usb: gadget: dummy_hcd: Fix wrong power status bit clear/reset in dummy_hub_control() [ Upstream commit 9f20dfb44d03745d0d3cef2ffb3abf8d8024fa61 ] This fixes the commit: 1cd8fd2887e1 ("usb: gadget: dummy_hcd: add SuperSpeed support"). In the case of ClearPortFeature and USB_PORT_FEAT_POWER, simply clear the right bit regardless of what the wValue is. Acked-by: Alan Stern Signed-off-by: Yuyang Du Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/dummy_hcd.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index b62a3de65075..ff4d6cac7ac0 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2103,16 +2103,13 @@ static int dummy_hub_control( } break; case USB_PORT_FEAT_POWER: - if (hcd->speed == HCD_USB3) { - if (dum_hcd->port_status & USB_PORT_STAT_POWER) - dev_dbg(dummy_dev(dum_hcd), - "power-off\n"); - } else - if (dum_hcd->port_status & - USB_SS_PORT_STAT_POWER) - dev_dbg(dummy_dev(dum_hcd), - "power-off\n"); - /* FALLS THROUGH */ + dev_dbg(dummy_dev(dum_hcd), "power-off\n"); + if (hcd->speed == HCD_USB3) + dum_hcd->port_status &= ~USB_SS_PORT_STAT_POWER; + else + dum_hcd->port_status &= ~USB_PORT_STAT_POWER; + set_link_state(dum_hcd); + break; default: dum_hcd->port_status &= ~(1 << wValue); set_link_state(dum_hcd); @@ -2283,14 +2280,13 @@ static int dummy_hub_control( if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) != 0) { dum_hcd->port_status |= (1 << wValue); - set_link_state(dum_hcd); } } else if ((dum_hcd->port_status & USB_PORT_STAT_POWER) != 0) { dum_hcd->port_status |= (1 << wValue); - set_link_state(dum_hcd); } + set_link_state(dum_hcd); } break; case GetPortErrorCount: -- GitLab From 02db6c7024e15904e508070455cdefd1f73a859d Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Fri, 7 Apr 2017 20:08:52 +0800 Subject: [PATCH 0480/1834] perf evsel: Return exact sub event which failed with EPERM for wildcards [ Upstream commit 32ccb130f5325abc81b32b1a538390f46e4860f6 ] The kernel has a special check for a specific irq_vectors trace event. TRACE_EVENT_PERF_PERM(irq_work_exit, is_sampling_event(p_event) ? -EPERM : 0); The perf-record fails for this irq_vectors event when it is present, like when using a wildcard: root@skl:/tmp# perf record -a -e irq_vectors:* sleep 2 Error: You may not have permission to collect system-wide stats. Consider tweaking /proc/sys/kernel/perf_event_paranoid, which controls use of the performance events system by unprivileged users (without CAP_SYS_ADMIN). The current value is 2: -1: Allow use of (almost) all events by all users >= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK >= 1: Disallow CPU event access by users without CAP_SYS_ADMIN >= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN To make this setting permanent, edit /etc/sysctl.conf too, e.g.: kernel.perf_event_paranoid = -1 This patch prints out the exact sub event that failed with EPERM for wildcards to help in understanding what went wrong when this event is present: After the patch: root@skl:/tmp# perf record -a -e irq_vectors:* sleep 2 Error: No permission to enable irq_vectors:irq_work_exit event. You may not have permission to collect system-wide stats. ...... Committer notes: So we have a lot of irq_vectors events: [root@jouet ~]# perf list irq_vectors:* List of pre-defined events (to be used in -e): irq_vectors:call_function_entry [Tracepoint event] irq_vectors:call_function_exit [Tracepoint event] irq_vectors:call_function_single_entry [Tracepoint event] irq_vectors:call_function_single_exit [Tracepoint event] irq_vectors:deferred_error_apic_entry [Tracepoint event] irq_vectors:deferred_error_apic_exit [Tracepoint event] irq_vectors:error_apic_entry [Tracepoint event] irq_vectors:error_apic_exit [Tracepoint event] irq_vectors:irq_work_entry [Tracepoint event] irq_vectors:irq_work_exit [Tracepoint event] irq_vectors:local_timer_entry [Tracepoint event] irq_vectors:local_timer_exit [Tracepoint event] irq_vectors:reschedule_entry [Tracepoint event] irq_vectors:reschedule_exit [Tracepoint event] irq_vectors:spurious_apic_entry [Tracepoint event] irq_vectors:spurious_apic_exit [Tracepoint event] irq_vectors:thermal_apic_entry [Tracepoint event] irq_vectors:thermal_apic_exit [Tracepoint event] irq_vectors:threshold_apic_entry [Tracepoint event] irq_vectors:threshold_apic_exit [Tracepoint event] irq_vectors:x86_platform_ipi_entry [Tracepoint event] irq_vectors:x86_platform_ipi_exit [Tracepoint event] # And some may be sampled: [root@jouet ~]# perf record -e irq_vectors:local* sleep 20s [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.020 MB perf.data (2 samples) ] [root@jouet ~]# perf report -D | egrep 'stats:|events:' Aggregated stats: TOTAL events: 155 MMAP events: 144 COMM events: 2 EXIT events: 1 SAMPLE events: 2 MMAP2 events: 4 FINISHED_ROUND events: 1 TIME_CONV events: 1 irq_vectors:local_timer_entry stats: TOTAL events: 1 SAMPLE events: 1 irq_vectors:local_timer_exit stats: TOTAL events: 1 SAMPLE events: 1 [root@jouet ~]# But, as shown in the tracepoint definition at the start of this message, some, like "irq_vectors:irq_work_exit", may not be sampled, just counted, i.e. if we try to sample, as when using 'perf record', we get an error: [root@jouet ~]# perf record -e irq_vectors:irq_work_exit Error: You may not have permission to collect system-wide stats. Consider tweaking /proc/sys/kernel/perf_event_paranoid, The error message is misleading, this patch will help in pointing out what is the event causing such an error, but the error message needs improvement, i.e. we need to figure out a way to check if a tracepoint is counting only, like this one, when all we can do is to count it with 'perf stat', at most printing the delta using interval printing, as in: [root@jouet ~]# perf stat -I 5000 -e irq_vectors:irq_work_* # time counts unit events 5.000168871 0 irq_vectors:irq_work_entry 5.000168871 0 irq_vectors:irq_work_exit 10.000676730 0 irq_vectors:irq_work_entry 10.000676730 0 irq_vectors:irq_work_exit 15.001122415 0 irq_vectors:irq_work_entry 15.001122415 0 irq_vectors:irq_work_exit 20.001298051 0 irq_vectors:irq_work_entry 20.001298051 0 irq_vectors:irq_work_exit 25.001485020 1 irq_vectors:irq_work_entry 25.001485020 1 irq_vectors:irq_work_exit 30.001658706 0 irq_vectors:irq_work_entry 30.001658706 0 irq_vectors:irq_work_exit ^C 32.045711878 0 irq_vectors:irq_work_entry 32.045711878 0 irq_vectors:irq_work_exit [root@jouet ~]# But at least, when we use a wildcard, this patch helps a bit. Signed-off-by: Yao Jin Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1491566932-503-1-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/evsel.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 8bc271141d9d..539724c7d30b 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2400,11 +2400,17 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, int err, char *msg, size_t size) { char sbuf[STRERR_BUFSIZE]; + int printed = 0; switch (err) { case EPERM: case EACCES: - return scnprintf(msg, size, + if (err == EPERM) + printed = scnprintf(msg, size, + "No permission to enable %s event.\n\n", + perf_evsel__name(evsel)); + + return scnprintf(msg + printed, size - printed, "You may not have permission to collect %sstats.\n\n" "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n" "which controls use of the performance events system by\n" -- GitLab From 3efaebb3bbc1a5d702ed0a943b91cd14f78d0bab Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 14 Dec 2016 13:48:04 +0100 Subject: [PATCH 0481/1834] iwlwifi: mvm: fix RX SKB header size and align it properly [ Upstream commit 5cddd05c9cbe420436799716d009bc0372ef8268 ] When receiving a frame, we currently pull in sizeof(*hdr) plus some extra (crypto/snap), which is too much, most headers aren't actually sizeof(*hdr) since that takes into account the 4-address format but doesn't take into account QoS. As a result, a typical frame will have 4 bytes of the payload in the SKB header already. Fix this by calculating the correct header length, and now that we have that, align the end of the SKB header to a multiple of 4 so that the IP header will be aligned properly when pulled in. Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/mvm/rx.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 0e60e38b2acf..b78e60eb600f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -104,7 +104,20 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, u8 crypt_len, struct iwl_rx_cmd_buffer *rxb) { - unsigned int hdrlen, fraglen; + unsigned int hdrlen = ieee80211_hdrlen(hdr->frame_control); + unsigned int fraglen; + + /* + * The 'hdrlen' (plus the 8 bytes for the SNAP and the crypt_len, + * but those are all multiples of 4 long) all goes away, but we + * want the *end* of it, which is going to be the start of the IP + * header, to be aligned when it gets pulled in. + * The beginning of the skb->data is aligned on at least a 4-byte + * boundary after allocation. Everything here is aligned at least + * on a 2-byte boundary so we can just take hdrlen & 3 and pad by + * the result. + */ + skb_reserve(skb, hdrlen & 3); /* If frame is small enough to fit in skb->head, pull it completely. * If not, only pull ieee80211_hdr (including crypto if present, and @@ -118,8 +131,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, * If the latter changes (there are efforts in the standards group * to do so) we should revisit this and ieee80211_data_to_8023(). */ - hdrlen = (len <= skb_tailroom(skb)) ? len : - sizeof(*hdr) + crypt_len + 8; + hdrlen = (len <= skb_tailroom(skb)) ? len : hdrlen + crypt_len + 8; memcpy(skb_put(skb, hdrlen), hdr, hdrlen); fraglen = len - hdrlen; -- GitLab From 80e1caf00d148ff8034861551d41faa6c537df8c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 11 Apr 2017 09:39:49 +0100 Subject: [PATCH 0482/1834] drivers/perf: arm_pmu: handle no platform_device [ Upstream commit 7654137071fa706e5c91f4f27bc2a5cd7e435a9b ] In armpmu_dispatch_irq() we look at arm_pmu::plat_device to acquire platdata, so that we can defer to platform-specific IRQ handling, required on some 32-bit parts. With the advent of ACPI we won't always have a platform_device, and so we must avoid trying to dereference fields from it. This patch fixes up armpmu_dispatch_irq() to avoid doing so, introducing a new armpmu_get_platdata() helper. Signed-off-by: Mark Rutland Tested-by: Jeremy Linton Cc: Will Deacon Signed-off-by: Will Deacon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/perf/arm_pmu.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index b37b57294566..af82edc7fa5c 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -322,10 +322,16 @@ validate_group(struct perf_event *event) return 0; } +static struct arm_pmu_platdata *armpmu_get_platdata(struct arm_pmu *armpmu) +{ + struct platform_device *pdev = armpmu->plat_device; + + return pdev ? dev_get_platdata(&pdev->dev) : NULL; +} + static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) { struct arm_pmu *armpmu; - struct platform_device *plat_device; struct arm_pmu_platdata *plat; int ret; u64 start_clock, finish_clock; @@ -337,8 +343,8 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) * dereference. */ armpmu = *(void **)dev; - plat_device = armpmu->plat_device; - plat = dev_get_platdata(&plat_device->dev); + + plat = armpmu_get_platdata(armpmu); start_clock = sched_clock(); if (plat && plat->handle_irq) -- GitLab From d9f8b1cc5aa6453a5735c216cb80c6c00da20926 Mon Sep 17 00:00:00 2001 From: David Carrillo-Cisneros Date: Mon, 10 Apr 2017 13:14:27 -0700 Subject: [PATCH 0483/1834] perf inject: Copy events when reordering events in pipe mode [ Upstream commit 1e0d4f0200e4dbdfc38d818f329d8a0955f7c6f5 ] __perf_session__process_pipe_events reuses the same memory buffer to process all events in the pipe. When reordering is needed (e.g. -b option), events are not immediately flushed, but kept around until reordering is possible, causing memory corruption. The problem is usually observed by a "Unknown sample error" output. It can easily be reproduced by: perf record -o - noploop | perf inject -b > output Committer testing: Before: $ perf record -o - stress -t 2 -c 2 | perf inject -b > /dev/null stress: info: [8297] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd stress: info: [8297] successful run completed in 2s [ perf record: Woken up 3 times to write data ] [ perf record: Captured and wrote 0.000 MB - ] Warning: Found 1 unknown events! Is this an older tool processing a perf.data file generated by a more recent tool? If that is not the case, consider reporting to linux-kernel@vger.kernel.org. $ After: $ perf record -o - stress -t 2 -c 2 | perf inject -b > /dev/null stress: info: [9027] dispatching hogs: 2 cpu, 0 io, 0 vm, 0 hdd stress: info: [9027] successful run completed in 2s [ perf record: Woken up 3 times to write data ] [ perf record: Captured and wrote 0.000 MB - ] no symbols found in /usr/bin/stress, maybe install a debug package? no symbols found in /usr/bin/stress, maybe install a debug package? $ Signed-off-by: David Carrillo-Cisneros Tested-by: Arnaldo Carvalho de Melo Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: He Kuang Cc: Masami Hiramatsu Cc: Paul Turner Cc: Peter Zijlstra Cc: Simon Que Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/20170410201432.24807-3-davidcc@google.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/ordered-events.c | 3 ++- tools/perf/util/session.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index fe84df1875aa..e70e935b1841 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c @@ -79,7 +79,7 @@ static union perf_event *dup_event(struct ordered_events *oe, static void free_dup_event(struct ordered_events *oe, union perf_event *event) { - if (oe->copy_on_queue) { + if (event && oe->copy_on_queue) { oe->cur_alloc_size -= event->header.size; free(event); } @@ -150,6 +150,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve list_move(&event->list, &oe->cache); oe->nr_events--; free_dup_event(oe, event->event); + event->event = NULL; } int ordered_events__queue(struct ordered_events *oe, union perf_event *event, diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 5d61242a6e64..97b4822fe7f0 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1628,6 +1628,7 @@ static int __perf_session__process_pipe_events(struct perf_session *session) buf = malloc(cur_size); if (!buf) return -errno; + ordered_events__set_copy_on_queue(oe, true); more: event = buf; err = readn(fd, event, sizeof(struct perf_event_header)); -- GitLab From 8c4e5168dd2776147acb4a94f941508809262365 Mon Sep 17 00:00:00 2001 From: Fugang Duan Date: Tue, 11 Apr 2017 19:13:06 +0800 Subject: [PATCH 0484/1834] net: fec: add phy-reset-gpios PROBE_DEFER check [ Upstream commit 9269e5560b261eb9ee157497890dc0948db76cf8 ] Many boards use i2c/spi expander gpio as phy-reset-gpios and these gpios maybe registered after fec port, driver should check the return value of .of_get_named_gpio(). Signed-off-by: Fugang Duan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/fec_main.c | 26 ++++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 917091871259..dd6e07c748f5 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3209,7 +3209,7 @@ static int fec_enet_init(struct net_device *ndev) } #ifdef CONFIG_OF -static void fec_reset_phy(struct platform_device *pdev) +static int fec_reset_phy(struct platform_device *pdev) { int err, phy_reset; bool active_high = false; @@ -3217,7 +3217,7 @@ static void fec_reset_phy(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; if (!np) - return; + return 0; of_property_read_u32(np, "phy-reset-duration", &msec); /* A sane reset duration should not be longer than 1s */ @@ -3225,8 +3225,10 @@ static void fec_reset_phy(struct platform_device *pdev) msec = 1; phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); - if (!gpio_is_valid(phy_reset)) - return; + if (phy_reset == -EPROBE_DEFER) + return phy_reset; + else if (!gpio_is_valid(phy_reset)) + return 0; active_high = of_property_read_bool(np, "phy-reset-active-high"); @@ -3235,7 +3237,7 @@ static void fec_reset_phy(struct platform_device *pdev) "phy-reset"); if (err) { dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err); - return; + return err; } if (msec > 20) @@ -3244,14 +3246,17 @@ static void fec_reset_phy(struct platform_device *pdev) usleep_range(msec * 1000, msec * 1000 + 1000); gpio_set_value_cansleep(phy_reset, !active_high); + + return 0; } #else /* CONFIG_OF */ -static void fec_reset_phy(struct platform_device *pdev) +static int fec_reset_phy(struct platform_device *pdev) { /* * In case of platform probe, the reset has been done * by machine code. */ + return 0; } #endif /* CONFIG_OF */ @@ -3422,6 +3427,7 @@ fec_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to enable phy regulator: %d\n", ret); + clk_disable_unprepare(fep->clk_ipg); goto failed_regulator; } } else { @@ -3434,7 +3440,9 @@ fec_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - fec_reset_phy(pdev); + ret = fec_reset_phy(pdev); + if (ret) + goto failed_reset; if (fep->bufdesc_ex) fec_ptp_init(pdev); @@ -3495,8 +3503,10 @@ fec_probe(struct platform_device *pdev) fec_ptp_stop(pdev); if (fep->reg_phy) regulator_disable(fep->reg_phy); +failed_reset: + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); failed_regulator: - clk_disable_unprepare(fep->clk_ipg); failed_clk_ipg: fec_enet_clk_enable(ndev, false); failed_clk: -- GitLab From 4c885c35463fac9e11055ce447de05bc996b4c4c Mon Sep 17 00:00:00 2001 From: David Carrillo-Cisneros Date: Mon, 10 Apr 2017 13:14:30 -0700 Subject: [PATCH 0485/1834] perf session: Don't rely on evlist in pipe mode [ Upstream commit 0973ad97c187e06aece61f685b9c3b2d93290a73 ] Session sets a number parameters that rely on evlist. These parameters are not used in pipe-mode and should not be set, since evlist is unavailable. Fix that. Signed-off-by: David Carrillo-Cisneros Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: He Kuang Cc: Masami Hiramatsu Cc: Paul Turner Cc: Peter Zijlstra Cc: Simon Que Cc: Stephane Eranian Cc: Wang Nan Link: http://lkml.kernel.org/r/20170410201432.24807-6-davidcc@google.com [ Check if file != NULL in perf_session__new(), like when used by builtin-top.c ] Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/session.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 97b4822fe7f0..7e0573e55a35 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -139,8 +139,14 @@ struct perf_session *perf_session__new(struct perf_data_file *file, if (perf_session__open(session) < 0) goto out_close; - perf_session__set_id_hdr_size(session); - perf_session__set_comm_exec(session); + /* + * set session attributes that are present in perf.data + * but not in pipe-mode. + */ + if (!file->is_pipe) { + perf_session__set_id_hdr_size(session); + perf_session__set_comm_exec(session); + } } } else { session->machines.host.env = &perf_env; @@ -155,7 +161,11 @@ struct perf_session *perf_session__new(struct perf_data_file *file, pr_warning("Cannot read kernel map\n"); } - if (tool && tool->ordering_requires_timestamps && + /* + * In pipe-mode, evlist is empty until PERF_RECORD_HEADER_ATTR is + * processed, so perf_evlist__sample_id_all is not meaningful here. + */ + if ((!file || !file->is_pipe) && tool && tool->ordering_requires_timestamps && tool->ordered_events && !perf_evlist__sample_id_all(session->evlist)) { dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n"); tool->ordered_events = false; -- GitLab From 5d7601dcb29d4b51cc32da4a744533f524a6fc8a Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 24 Mar 2017 17:44:06 +1100 Subject: [PATCH 0486/1834] vfio/powerpc/spapr_tce: Enforce IOMMU type compatibility check [ Upstream commit 1282ba7fc28dbc66c3f0e4aaafaaa228361d1ae5 ] The existing SPAPR TCE driver advertises both VFIO_SPAPR_TCE_IOMMU and VFIO_SPAPR_TCE_v2_IOMMU types to the userspace and the userspace usually picks the v2. Normally the userspace would create a container, attach an IOMMU group to it and only then set the IOMMU type (which would normally be v2). However a specific IOMMU group may not support v2, in other words it may not implement set_window/unset_window/take_ownership/ release_ownership and such a group should not be attached to a v2 container. This adds extra checks that a new group can do what the selected IOMMU type suggests. The userspace can then test the return value from ioctl(VFIO_SET_IOMMU, VFIO_SPAPR_TCE_v2_IOMMU) and try VFIO_SPAPR_TCE_IOMMU. Signed-off-by: Alexey Kardashevskiy Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/vfio_iommu_spapr_tce.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 59b3f62a2d64..87ad0d72d8a9 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -1332,8 +1332,16 @@ static int tce_iommu_attach_group(void *iommu_data, if (!table_group->ops || !table_group->ops->take_ownership || !table_group->ops->release_ownership) { + if (container->v2) { + ret = -EPERM; + goto unlock_exit; + } ret = tce_iommu_take_ownership(container, table_group); } else { + if (!container->v2) { + ret = -EPERM; + goto unlock_exit; + } ret = tce_iommu_take_ownership_ddw(container, table_group); if (!tce_groups_attached(container) && !container->tables[0]) container->def_window_pending = true; -- GitLab From bab8ac1b274eb835a6ac33501dbd010fc0262822 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 27 Mar 2017 14:23:40 +1100 Subject: [PATCH 0487/1834] vfio/spapr_tce: Check kzalloc() return when preregistering memory [ Upstream commit 3393af24b665cb0aea7353b05e522b03ab1e7d73 ] This adds missing checking for kzalloc() return value. Fixes: 4b6fad7097f8 ("powerpc/mm/iommu, vfio/spapr: Put pages on VFIO container shutdown") Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/vfio_iommu_spapr_tce.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 87ad0d72d8a9..70c748a5fbcc 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -195,6 +195,11 @@ static long tce_iommu_register_pages(struct tce_container *container, return ret; tcemem = kzalloc(sizeof(*tcemem), GFP_KERNEL); + if (!tcemem) { + mm_iommu_put(container->mm, mem); + return -ENOMEM; + } + tcemem->mem = mem; list_add(&tcemem->next, &container->prereg_list); -- GitLab From 602f933e0314b6ec4fca46e57127a08f917ed7c5 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 7 Apr 2017 09:34:15 +0200 Subject: [PATCH 0488/1834] scsi: sg: check for valid direction before starting the request [ Upstream commit 28676d869bbb5257b5f14c0c95ad3af3a7019dd5 ] Check for a valid direction before starting the request, otherwise we risk running into an assertion in the scsi midlayer checking for valid requests. [mkp: fixed typo] Signed-off-by: Johannes Thumshirn Link: http://www.spinics.net/lists/linux-scsi/msg104400.html Reported-by: Dmitry Vyukov Signed-off-by: Hannes Reinecke Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index cd9537ddc19f..6b6064dc3467 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -663,18 +663,14 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) * is a non-zero input_size, so emit a warning. */ if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - static char cmd[TASK_COMM_LEN]; - if (strcmp(current->comm, cmd)) { - printk_ratelimited(KERN_WARNING - "sg_write: data in/out %d/%d bytes " - "for SCSI command 0x%x-- guessing " - "data in;\n program %s not setting " - "count and/or reply_len properly\n", - old_hdr.reply_len - (int)SZ_SG_HEADER, - input_size, (unsigned int) cmnd[0], - current->comm); - strcpy(cmd, current->comm); - } + printk_ratelimited(KERN_WARNING + "sg_write: data in/out %d/%d bytes " + "for SCSI command 0x%x-- guessing " + "data in;\n program %s not setting " + "count and/or reply_len properly\n", + old_hdr.reply_len - (int)SZ_SG_HEADER, + input_size, (unsigned int) cmnd[0], + current->comm); } k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); return (k < 0) ? k : count; @@ -753,6 +749,29 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, return count; } +static bool sg_is_valid_dxfer(sg_io_hdr_t *hp) +{ + switch (hp->dxfer_direction) { + case SG_DXFER_NONE: + if (hp->dxferp || hp->dxfer_len > 0) + return false; + return true; + case SG_DXFER_TO_DEV: + case SG_DXFER_FROM_DEV: + case SG_DXFER_TO_FROM_DEV: + if (!hp->dxferp || hp->dxfer_len == 0) + return false; + return true; + case SG_DXFER_UNKNOWN: + if ((!hp->dxferp && hp->dxfer_len) || + (hp->dxferp && hp->dxfer_len == 0)) + return false; + return true; + default: + return false; + } +} + static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char *cmnd, int timeout, int blocking) @@ -773,6 +792,9 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, "sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) cmnd[0], (int) hp->cmd_len)); + if (!sg_is_valid_dxfer(hp)) + return -EINVAL; + k = sg_start_req(srp, cmnd); if (k) { SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, -- GitLab From ae9b6ae2e77947534e255903627cc62746ea77e2 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 7 Apr 2017 09:34:17 +0200 Subject: [PATCH 0489/1834] scsi: sg: close race condition in sg_remove_sfp_usercontext() [ Upstream commit 97d27b0dd015e980ade63fda111fd1353276e28b ] sg_remove_sfp_usercontext() is clearing any sg requests, but needs to take 'rq_list_lock' when modifying the list. Reported-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Reviewed-by: Johannes Thumshirn Tested-by: Johannes Thumshirn Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 6b6064dc3467..e6333cae8550 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -524,6 +524,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) } else count = (old_hdr->result == 0) ? 0 : -EIO; sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); retval = count; free_old_hdr: kfree(old_hdr); @@ -564,6 +565,7 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) } err_out: err2 = sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return err ? : err2 ? : count; } @@ -800,6 +802,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sfp->parentdp, "sg_common_write: start_req err=%d\n", k)); sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return k; /* probably out of space --> ENOMEM */ } if (atomic_read(&sdp->detaching)) { @@ -812,6 +815,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, } sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); return -ENODEV; } @@ -1302,6 +1306,7 @@ sg_rq_end_io_usercontext(struct work_struct *work) struct sg_fd *sfp = srp->parentfp; sg_finish_rem_req(srp); + sg_remove_request(sfp, srp); kref_put(&sfp->f_ref, sg_remove_sfp); } @@ -1846,8 +1851,6 @@ sg_finish_rem_req(Sg_request *srp) else sg_remove_scat(sfp, req_schp); - sg_remove_request(sfp, srp); - return ret; } @@ -2194,12 +2197,17 @@ sg_remove_sfp_usercontext(struct work_struct *work) struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work); struct sg_device *sdp = sfp->parentdp; Sg_request *srp; + unsigned long iflags; /* Cleanup any responses which were never read(). */ + write_lock_irqsave(&sfp->rq_list_lock, iflags); while (!list_empty(&sfp->rq_list)) { srp = list_first_entry(&sfp->rq_list, Sg_request, entry); sg_finish_rem_req(srp); + list_del(&srp->entry); + srp->parentfp = NULL; } + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (sfp->reserve.bufflen > 0) { SCSI_LOG_TIMEOUT(6, sg_printk(KERN_INFO, sdp, -- GitLab From 1ab6efa2d4d6e785e6701fd319cc3044ede2fadf Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Wed, 12 Apr 2017 09:54:00 +0530 Subject: [PATCH 0490/1834] ALSA: hda: Add Geminilake id to SKL_PLUS [ Upstream commit 12ee4022f67f8854061b46e5c0a7ad6258ab66c2 ] Geminilake is Skylake family platform. So add it's id to skl_plus check. Fixes: 126cfa2f5e15 ("ALSA: hda: Add Geminilake HDMI codec ID") Signed-off-by: Subhransu S. Prusty Cc: Senthilnathan Veppur Cc: Vinod Koul Cc: Takashi Iwai Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_intel.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ceb162a9dcfd..688f3144d949 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -369,8 +369,10 @@ enum { #define IS_KBL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d71) #define IS_KBL_H(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa2f0) #define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98) +#define IS_GLK(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x3198) #define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci)) || \ - IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci) + IS_KBL(pci) || IS_KBL_LP(pci) || IS_KBL_H(pci) || \ + IS_GLK(pci) static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", -- GitLab From 96d0c4c4674705677ee6dbfecc468da439dadf01 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 29 Mar 2017 13:56:56 +0900 Subject: [PATCH 0491/1834] kprobes/x86: Fix kprobe-booster not to boost far call instructions [ Upstream commit bd0b90676c30fe640e7ead919b3e38846ac88ab7 ] Fix the kprobe-booster not to boost far call instruction, because a call may store the address in the single-step execution buffer to the stack, which should be modified after single stepping. Currently, this instruction will be filtered as not boostable in resume_execution(), so this is not a critical issue. Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Andrey Ryabinin Cc: Anil S Keshavamurthy Cc: Borislav Petkov Cc: Brian Gerst Cc: David S . Miller Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Ye Xiaolong Link: http://lkml.kernel.org/r/149076340615.22469.14066273186134229909.stgit@devbox Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/kprobes/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index b55d07b9d530..808ee7f566f8 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -199,6 +199,8 @@ int can_boost(kprobe_opcode_t *opcodes, void *addr) return (opcode != 0x62 && opcode != 0x67); case 0x70: return 0; /* can't boost conditional jump */ + case 0x90: + return opcode != 0x9a; /* can't boost call far */ case 0xc0: /* can't boost software-interruptions */ return (0xc1 < opcode && opcode < 0xcc) || opcode == 0xcf; -- GitLab From d0cab8cae1618e9c6d4b16560321c57ed1321bac Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Wed, 29 Mar 2017 14:02:46 +0900 Subject: [PATCH 0492/1834] kprobes/x86: Set kprobes pages read-only [ Upstream commit d0381c81c2f782fa2131178d11e0cfb23d50d631 ] Set the pages which is used for kprobes' singlestep buffer and optprobe's trampoline instruction buffer to readonly. This can prevent unexpected (or unintended) instruction modification. This also passes rodata_test as below. Without this patch, rodata_test shows a warning: WARNING: CPU: 0 PID: 1 at arch/x86/mm/dump_pagetables.c:235 note_page+0x7a9/0xa20 x86/mm: Found insecure W+X mapping at address ffffffffa0000000/0xffffffffa0000000 With this fix, no W+X pages are found: x86/mm: Checked W+X mappings: passed, no W+X pages found. rodata_test: all tests were successful Reported-by: Andrey Ryabinin Signed-off-by: Masami Hiramatsu Cc: Ananth N Mavinakayanahalli Cc: Anil S Keshavamurthy Cc: Borislav Petkov Cc: Brian Gerst Cc: David S . Miller Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Ye Xiaolong Link: http://lkml.kernel.org/r/149076375592.22469.14174394514338612247.stgit@devbox Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/kprobes/core.c | 4 ++++ arch/x86/kernel/kprobes/opt.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index 808ee7f566f8..b8d3f1b60331 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -409,6 +409,8 @@ static int arch_copy_kprobe(struct kprobe *p) { int ret; + set_memory_rw((unsigned long)p->ainsn.insn & PAGE_MASK, 1); + /* Copy an instruction with recovering if other optprobe modifies it.*/ ret = __copy_instruction(p->ainsn.insn, p->addr); if (!ret) @@ -423,6 +425,8 @@ static int arch_copy_kprobe(struct kprobe *p) else p->ainsn.boostable = -1; + set_memory_ro((unsigned long)p->ainsn.insn & PAGE_MASK, 1); + /* Check whether the instruction modifies Interrupt Flag or not */ p->ainsn.if_modifier = is_IF_modifier(p->ainsn.insn); diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index dc20da1c78f0..fa671b90c374 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -371,6 +371,7 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, } buf = (u8 *)op->optinsn.insn; + set_memory_rw((unsigned long)buf & PAGE_MASK, 1); /* Copy instructions into the out-of-line buffer */ ret = copy_optimized_instructions(buf + TMPL_END_IDX, op->kp.addr); @@ -393,6 +394,8 @@ int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, synthesize_reljump(buf + TMPL_END_IDX + op->optinsn.size, (u8 *)op->kp.addr + op->optinsn.size); + set_memory_ro((unsigned long)buf & PAGE_MASK, 1); + flush_icache_range((unsigned long) buf, (unsigned long) buf + TMPL_END_IDX + op->optinsn.size + RELATIVEJUMP_SIZE); -- GitLab From 99f3e3b0a8dbbf72173b18fe8b8df625c94cc7df Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 7 Apr 2017 15:04:00 +0530 Subject: [PATCH 0493/1834] pwm: tegra: Increase precision in PWM rate calculation [ Upstream commit 250b76f43f57d578ebff5e7211eb2c73aa5cd6ca ] The rate of the PWM calculated as follows: hz = NSEC_PER_SEC / period_ns; rate = (rate + (hz / 2)) / hz; This has the precision loss in lower PWM rate. Change this to have more precision as: hz = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC * 100, period_ns); rate = DIV_ROUND_CLOSEST(rate * 100, hz) Example: 1. period_ns = 16672000, PWM clock rate is 200 KHz. Based on old formula hz = NSEC_PER_SEC / period_ns = 1000000000ul/16672000 = 59 (59.98) rate = (200K + 59/2)/59 = 3390 Based on new method: hz = 5998 rate = DIV_ROUND_CLOSE(200000*100, 5998) = 3334 If we measure the PWM signal rate, we will get more accurate period with rate value of 3334 instead of 3390. 2. period_ns = 16803898, PWM clock rate is 200 KHz. Based on old formula: hz = 59, rate = 3390 Based on new formula: hz = 5951, rate = 3360 The PWM signal rate of 3360 is more near to requested period than 3333. Signed-off-by: Laxman Dewangan Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pwm/pwm-tegra.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index e4647840cd6e..7e8906d6ab7a 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -76,6 +76,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, struct tegra_pwm_chip *pc = to_tegra_pwm_chip(chip); unsigned long long c = duty_ns; unsigned long rate, hz; + unsigned long long ns100 = NSEC_PER_SEC; u32 val = 0; int err; @@ -95,9 +96,11 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * cycles at the PWM clock rate will take period_ns nanoseconds. */ rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH; - hz = NSEC_PER_SEC / period_ns; - rate = (rate + (hz / 2)) / hz; + /* Consider precision in PWM_SCALE_WIDTH rate calculation */ + ns100 *= 100; + hz = DIV_ROUND_CLOSEST_ULL(ns100, period_ns); + rate = DIV_ROUND_CLOSEST(rate * 100, hz); /* * Since the actual PWM divider is the register's frequency divider -- GitLab From 59665fc5e5f5ff1275d1adb4fa63ec1a707e7e89 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 23 Mar 2017 13:13:40 +0530 Subject: [PATCH 0494/1834] clk: qcom: msm8996: Fix the vfe1 powerdomain name [ Upstream commit a62ca337b36e31621b582cbe8f17d9404a48e120 ] Fix a typo which caused both vfe0 and vfe1 powerdomains to be named as vfe0. Signed-off-by: Rajendra Nayak Fixes: 7e824d507909 ("clk: qcom: gdsc: Add mmcc gdscs for msm8996 family") Signed-off-by: Stephen Boyd Signed-off-by: Michael Turquette Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/qcom/mmcc-msm8996.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/qcom/mmcc-msm8996.c b/drivers/clk/qcom/mmcc-msm8996.c index ca97e1151797..3b171bef913a 100644 --- a/drivers/clk/qcom/mmcc-msm8996.c +++ b/drivers/clk/qcom/mmcc-msm8996.c @@ -2984,7 +2984,7 @@ static struct gdsc vfe1_gdsc = { .cxcs = (unsigned int []){ 0x36ac }, .cxc_count = 1, .pd = { - .name = "vfe0", + .name = "vfe1", }, .parent = &camss_gdsc.pd, .pwrsts = PWRSTS_OFF_ON, -- GitLab From f3fa28a381b8a61cd2f3631936e6aa6c48363cb9 Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Fri, 10 Mar 2017 11:34:46 +0000 Subject: [PATCH 0495/1834] Bluetooth: Avoid bt_accept_unlink() double unlinking [ Upstream commit 27bfbc21a0c0f711fa5382de026c7c0700c9ea28 ] There is a race condition between a thread calling bt_accept_dequeue() and a different thread calling bt_accept_unlink(). Protection against concurrency is implemented using sk locking. However, sk locking causes serialisation of the bt_accept_dequeue() and bt_accept_unlink() threads. This serialisation can cause bt_accept_dequeue() to obtain the sk from the parent list but becomes blocked waiting for the sk lock held by the bt_accept_unlink() thread. bt_accept_unlink() unlinks sk and this thread releases the sk lock unblocking bt_accept_dequeue() which potentially runs bt_accept_unlink() again on the same sk causing a crash. The attempt to double unlink the same sk from the parent list can cause a NULL pointer dereference crash due to bt_sk(sk)->parent becoming NULL on the first unlink, followed by the second unlink trying to execute bt_sk(sk)->parent->sk_ack_backlog-- in bt_accept_unlink() which crashes. When sk is in the parent list, bt_sk(sk)->parent will be not be NULL. When sk is removed from the parent list, bt_sk(sk)->parent is set to NULL. Therefore, add a defensive check for bt_sk(sk)->parent not being NULL to ensure that sk is still in the parent list after the sk lock has been taken in bt_accept_dequeue(). If bt_sk(sk)->parent is detected as being NULL then restart the loop so that the loop variables are refreshed to use the latest values. This is necessary as list_for_each_entry_safe() is not thread safe so causing a risk of an infinite loop occurring as sk could point to itself. In addition, in bt_accept_dequeue() increase the sk reference count to protect against early freeing of sk. Early freeing can be possible if the bt_accept_unlink() thread calls l2cap_sock_kill() or rfcomm_sock_kill() functions before bt_accept_dequeue() gets the sk lock. For test purposes, the probability of failure can be increased by putting a msleep of 1 second in bt_accept_dequeue() between getting the sk and waiting for the sk lock. This exposes the fact that the loop list_for_each_entry_safe(p, n, &bt_sk(parent)->accept_q) is not safe from threads that unlink sk from the list in parallel with the loop which can cause sk to become stale within the loop. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/af_bluetooth.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 1aff2da9bc74..5d3698170004 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -163,6 +163,9 @@ void bt_accept_enqueue(struct sock *parent, struct sock *sk) } EXPORT_SYMBOL(bt_accept_enqueue); +/* Calling function must hold the sk lock. + * bt_sk(sk)->parent must be non-NULL meaning sk is in the parent list. + */ void bt_accept_unlink(struct sock *sk) { BT_DBG("sk %p state %d", sk, sk->sk_state); @@ -181,11 +184,32 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) BT_DBG("parent %p", parent); +restart: list_for_each_entry_safe(s, n, &bt_sk(parent)->accept_q, accept_q) { sk = (struct sock *)s; + /* Prevent early freeing of sk due to unlink and sock_kill */ + sock_hold(sk); lock_sock(sk); + /* Check sk has not already been unlinked via + * bt_accept_unlink() due to serialisation caused by sk locking + */ + if (!bt_sk(sk)->parent) { + BT_DBG("sk %p, already unlinked", sk); + release_sock(sk); + sock_put(sk); + + /* Restart the loop as sk is no longer in the list + * and also avoid a potential infinite loop because + * list_for_each_entry_safe() is not thread safe. + */ + goto restart; + } + + /* sk is safely in the parent list so reduce reference count */ + sock_put(sk); + /* FIXME: Is this check still needed */ if (sk->sk_state == BT_CLOSED) { bt_accept_unlink(sk); -- GitLab From b7ac7e479ae38810bc06fb662fe6e7e1ac7df3cf Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Tue, 28 Mar 2017 23:10:54 -0700 Subject: [PATCH 0496/1834] Bluetooth: 6lowpan: fix delay work init in add_peer_chan() [ Upstream commit d2891c4d071d807f01cc911dc42a68f4568d65cf ] When adding 6lowpan devices very rapidly we sometimes see a crash: [23122.306615] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 4.9.0-43-arm64 #1 Debian 4.9.9.linaro.43-1 [23122.315400] Hardware name: HiKey Development Board (DT) [23122.320623] task: ffff800075443080 task.stack: ffff800075484000 [23122.326551] PC is at expire_timers+0x70/0x150 [23122.330907] LR is at run_timer_softirq+0xa0/0x1a0 [23122.335616] pc : [] lr : [] pstate: 600001c5 This was due to add_peer_chan() unconditionally initializing the lowpan_btle_dev->notify_peers delayed work structure, even if the lowpan_btle_dev passed into add_peer_chan() had previously been initialized. Normally, this would go unnoticed as the delayed work timer is set for 100 msec, however when calling add_peer_chan() faster than 100 msec it clears out a previously queued delay work causing the crash above. To fix this, let add_peer_chan() know when a new lowpan_btle_dev is passed in so that it only performs the delay work initialization when needed. Signed-off-by: Michael Scott Acked-by: Jukka Rissanen Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/6lowpan.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index 1904a93f47d5..de7b82ece499 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -755,7 +755,8 @@ static void set_ip_addr_bits(u8 addr_type, u8 *addr) } static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, - struct lowpan_btle_dev *dev) + struct lowpan_btle_dev *dev, + bool new_netdev) { struct lowpan_peer *peer; @@ -786,7 +787,8 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, spin_unlock(&devices_lock); /* Notifying peers about us needs to be done without locks held */ - INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); + if (new_netdev) + INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers); schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100)); return peer->chan; @@ -843,6 +845,7 @@ static int setup_netdev(struct l2cap_chan *chan, struct lowpan_btle_dev **dev) static inline void chan_ready_cb(struct l2cap_chan *chan) { struct lowpan_btle_dev *dev; + bool new_netdev = false; dev = lookup_dev(chan->conn); @@ -853,12 +856,13 @@ static inline void chan_ready_cb(struct l2cap_chan *chan) l2cap_chan_del(chan, -ENOENT); return; } + new_netdev = true; } if (!try_module_get(THIS_MODULE)) return; - add_peer_chan(chan, dev); + add_peer_chan(chan, dev, new_netdev); ifup(dev->netdev); } -- GitLab From 6335d2350f4273c5ed4ff82929958ebf8b635aa2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 13 Apr 2017 10:31:16 +0200 Subject: [PATCH 0497/1834] mac80211_hwsim: use per-interface power level [ Upstream commit 1d5e9f80ab021e3e1f9436627a4ad07a143ccb2c ] When channel contexts are used, there's no global power level (the power_level is always 0). Use the per-interface TX power in mac80211_hwsim to have a proper setting for both cases. This fixes the bgscan_simple and bgscan_learn test cases when the number of channels advertised by hwsim is >1 by default. Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mac80211_hwsim.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 61e85eac706a..3757036af93e 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -552,8 +552,6 @@ struct mac80211_hwsim_data { /* wmediumd portid responsible for netgroup of this radio */ u32 wmediumd; - int power_level; - /* difference between this hw's clock and the real clock, in usecs */ s64 tsf_offset; s64 bcn_delta; @@ -1208,7 +1206,9 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, if (info->control.rates[0].flags & IEEE80211_TX_RC_SHORT_GI) rx_status.flag |= RX_FLAG_SHORT_GI; /* TODO: simulate real signal strength (and optional packet loss) */ - rx_status.signal = data->power_level - 50; + rx_status.signal = -50; + if (info->control.vif) + rx_status.signal += info->control.vif->bss_conf.txpower; if (data->ps != PS_DISABLED) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); @@ -1607,7 +1607,6 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) WARN_ON(data->channel && data->use_chanctx); - data->power_level = conf->power_level; if (!data->started || !data->beacon_int) tasklet_hrtimer_cancel(&data->beacon_timer); else if (!hrtimer_is_queued(&data->beacon_timer.timer)) { @@ -2212,7 +2211,6 @@ static const char mac80211_hwsim_gstrings_stats[][ETH_GSTRING_LEN] = { "d_tx_failed", "d_ps_mode", "d_group", - "d_tx_power", }; #define MAC80211_HWSIM_SSTATS_LEN ARRAY_SIZE(mac80211_hwsim_gstrings_stats) @@ -2249,7 +2247,6 @@ static void mac80211_hwsim_get_et_stats(struct ieee80211_hw *hw, data[i++] = ar->tx_failed; data[i++] = ar->ps; data[i++] = ar->group; - data[i++] = ar->power_level; WARN_ON(i != MAC80211_HWSIM_SSTATS_LEN); } -- GitLab From 0a83f6943ae16a73a3f6af5c89f2a453129406f4 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Tue, 4 Apr 2017 22:22:56 +0530 Subject: [PATCH 0498/1834] ath10k: fix compile time sanity check for CE4 buffer size [ Upstream commit 62ca0690cd495bb7c1414cdf0cf790c2922a1d79 ] In 'ath10k_ce_alloc_pipe' the compile time sanity check to ensure that there is sufficient buffers in CE4 for HTT Tx MSDU descriptors, but this did not take into account of the case with 'peer flow control' enabled, fix this. Cc: Michal Kazior Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/ce.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index 0b4d79659884..041ef3be87b9 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -1059,7 +1059,7 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id, */ BUILD_BUG_ON(2 * TARGET_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); - BUILD_BUG_ON(2 * TARGET_10X_NUM_MSDU_DESC > + BUILD_BUG_ON(2 * TARGET_10_4_NUM_MSDU_DESC_PFC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); BUILD_BUG_ON(2 * TARGET_TLV_NUM_MSDU_DESC > (CE_HTT_H2T_MSG_SRC_NENTRIES - 1)); -- GitLab From c7fd50a893f31450bafba5ccd0adb09a2de1ab55 Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Wed, 5 Apr 2017 14:58:08 +0300 Subject: [PATCH 0499/1834] wil6210: fix protection against connections during reset [ Upstream commit b819447dfc4bd120c9d6cd8521252d544fce8fe7 ] Existing code that ignores connection events during reset flow will never take effect since it locks the same mutex taken by the reset flow. In addition, in case of unsolicited disconnect events ignore those as well since device is about to get reset. Signed-off-by: Hamad Kadmany Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/wil6210/wmi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index fae4f1285d08..94a356bbb6b9 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -501,16 +501,16 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) assoc_resp_ielen = 0; } - mutex_lock(&wil->mutex); if (test_bit(wil_status_resetting, wil->status) || !test_bit(wil_status_fwready, wil->status)) { wil_err(wil, "status_resetting, cancel connect event, CID %d\n", evt->cid); - mutex_unlock(&wil->mutex); /* no need for cleanup, wil_reset will do that */ return; } + mutex_lock(&wil->mutex); + if ((wdev->iftype == NL80211_IFTYPE_STATION) || (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { if (!test_bit(wil_status_fwconnecting, wil->status)) { @@ -608,6 +608,13 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, wil->sinfo_gen++; + if (test_bit(wil_status_resetting, wil->status) || + !test_bit(wil_status_fwready, wil->status)) { + wil_err(wil, "status_resetting, cancel disconnect event\n"); + /* no need for cleanup, wil_reset will do that */ + return; + } + mutex_lock(&wil->mutex); wil6210_disconnect(wil, evt->bssid, reason_code, true); mutex_unlock(&wil->mutex); -- GitLab From d546045ebfe80880e57be141d33a89176ec4713f Mon Sep 17 00:00:00 2001 From: Dedy Lansky Date: Wed, 5 Apr 2017 14:58:11 +0300 Subject: [PATCH 0500/1834] wil6210: fix memory access violation in wil_memcpy_from/toio_32 [ Upstream commit 0f6edfe2bbbb59d161580cb4870fcc46f5490f85 ] In case count is not multiple of 4, there is a read access in wil_memcpy_toio_32() from outside src buffer boundary. In wil_memcpy_fromio_32(), in case count is not multiple of 4, there is a write access to outside dst io memory boundary. Fix these issues with proper handling of the last 1 to 4 copied bytes. Signed-off-by: Dedy Lansky Signed-off-by: Maya Erez Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/wil6210/main.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 24b07a0ce6f7..f8bce58d48cc 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -129,9 +129,15 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, u32 *d = dst; const volatile u32 __iomem *s = src; - /* size_t is unsigned, if (count%4 != 0) it will wrap */ - for (count += 4; count > 4; count -= 4) + for (; count >= 4; count -= 4) *d++ = __raw_readl(s++); + + if (unlikely(count)) { + /* count can be 1..3 */ + u32 tmp = __raw_readl(s); + + memcpy(d, &tmp, count); + } } void wil_memcpy_fromio_halp_vote(struct wil6210_priv *wil, void *dst, @@ -148,8 +154,16 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, volatile u32 __iomem *d = dst; const u32 *s = src; - for (count += 4; count > 4; count -= 4) + for (; count >= 4; count -= 4) __raw_writel(*s++, d++); + + if (unlikely(count)) { + /* count can be 1..3 */ + u32 tmp = 0; + + memcpy(&tmp, s, count); + __raw_writel(tmp, d); + } } void wil_memcpy_toio_halp_vote(struct wil6210_priv *wil, -- GitLab From 46eae02ef6d9d9172d0cf4628f720b8673bdcc7d Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Wed, 12 Apr 2017 11:23:01 -0700 Subject: [PATCH 0501/1834] perf stat: Fix bug in handling events in error state [ Upstream commit db49a71798a38f3ddf3f3462703328dca39b1ac7 ] (This is a patch has been sitting in the Intel CQM/CMT driver series for a while, despite not depend on it. Sending it now independently since the series is being discarded.) When an event is in error state, read() returns 0 instead of sizeof() buffer. In certain modes, such as interval printing, ignoring the 0 return value may cause bogus count deltas to be computed and thus invalid results printed. This patch fixes this problem by modifying read_counters() to mark the event as not scaled (scaled = -1) to force the printout routine to show . Signed-off-by: Stephane Eranian Reviewed-by: David Carrillo-Cisneros Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Andi Kleen Cc: Mathieu Poirier Cc: Paul Turner Cc: Peter Zijlstra Cc: Wang Nan Link: http://lkml.kernel.org/r/20170412182301.44406-1-davidcc@google.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-stat.c | 12 +++++++++--- tools/perf/util/evsel.c | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index c241167c76c9..5b60ec669e73 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -311,8 +311,12 @@ static int read_counter(struct perf_evsel *counter) struct perf_counts_values *count; count = perf_counts(counter->counts, cpu, thread); - if (perf_evsel__read(counter, cpu, thread, count)) + if (perf_evsel__read(counter, cpu, thread, count)) { + counter->counts->scaled = -1; + perf_counts(counter->counts, cpu, thread)->ena = 0; + perf_counts(counter->counts, cpu, thread)->run = 0; return -1; + } if (STAT_RECORD) { if (perf_evsel__write_stat_event(counter, cpu, thread, count)) { @@ -337,12 +341,14 @@ static int read_counter(struct perf_evsel *counter) static void read_counters(void) { struct perf_evsel *counter; + int ret; evlist__for_each_entry(evsel_list, counter) { - if (read_counter(counter)) + ret = read_counter(counter); + if (ret) pr_debug("failed to read counter %s\n", counter->name); - if (perf_stat_process_counter(&stat_config, counter)) + if (ret == 0 && perf_stat_process_counter(&stat_config, counter)) pr_warning("failed to process counter %s\n", counter->name); } } diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 539724c7d30b..bce80f866dd0 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -1221,7 +1221,7 @@ int perf_evsel__read(struct perf_evsel *evsel, int cpu, int thread, if (FD(evsel, cpu, thread) < 0) return -EINVAL; - if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) < 0) + if (readn(FD(evsel, cpu, thread), count, sizeof(*count)) <= 0) return -errno; return 0; @@ -1239,7 +1239,7 @@ int __perf_evsel__read_on_cpu(struct perf_evsel *evsel, if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1, thread + 1) < 0) return -ENOMEM; - if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0) + if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) <= 0) return -errno; perf_evsel__compute_deltas(evsel, cpu, thread, &count); -- GitLab From ac09628e707f00a95effed606fa7f013cef77e52 Mon Sep 17 00:00:00 2001 From: Ganapathi Bhat Date: Tue, 4 Apr 2017 10:16:28 +0530 Subject: [PATCH 0502/1834] mwifiex: Fix invalid port issue [ Upstream commit ecd7eb7c2bcf99f6c23d68ad56ce15949da848a1 ] We have to use start port, for TX/RX of single packet, instead of current aggregating port. This will fix SDIO CMD53(TX/RX) returning -ETIMEDOUT and halting the data path. Fixes: 0cb52aac4d19 ("mwifiex: do not set multiport flag for tx/rx single packet") Signed-off-by: Ganapathi Bhat Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/sdio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index 8d601dcf2948..486b8c75cd1f 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -1458,7 +1458,7 @@ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, } if (card->mpa_rx.pkt_cnt == 1) - mport = adapter->ioport + port; + mport = adapter->ioport + card->mpa_rx.start_port; if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, mport, 1)) @@ -1891,7 +1891,7 @@ static int mwifiex_host_to_card_mp_aggr(struct mwifiex_adapter *adapter, } if (card->mpa_tx.pkt_cnt == 1) - mport = adapter->ioport + port; + mport = adapter->ioport + card->mpa_tx.start_port; ret = mwifiex_write_data_to_card(adapter, card->mpa_tx.buf, card->mpa_tx.buf_len, mport); -- GitLab From 9bf2ce49d3d4cea17e8597f7f9f0379280247113 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 1 Nov 2017 16:20:58 +0200 Subject: [PATCH 0503/1834] drm/edid: set ELD connector type in drm_edid_to_eld() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 1d1c36650752b7fb81cee515a9bba4131cac4b7c ] Since drm_edid_to_eld() knows the connector type, we can set the type in ELD while at it. Most connectors this gets called on are not DP encoders, and with the HDMI type being 0, this does not change behaviour for non-DP. For i915 having this in place earlier would have saved a considerable amount of debugging that lead to the fix 2d8f63297b9f ("drm/i915: always update ELD connector type after get modes"). I don't see other drivers, even the ones calling drm_edid_to_eld() on DP connectors, setting the connector type in ELD. Cc: Alex Deucher Cc: Christian König Cc: Archit Taneja Cc: Andrzej Hajda Cc: Russell King Cc: CK Hu Cc: Philipp Zabel Cc: Ben Skeggs Cc: Mark Yao Cc: Benjamin Gaignard Cc: Vincent Abriou Cc: Thierry Reding Cc: Eric Anholt Reviewed-by: Ville Syrjälä Reviewed-by: Alex Deucher Acked-by: Thierry Reding Signed-off-by: Jani Nikula Link: https://patchwork.freedesktop.org/patch/msgid/d527b31619528c477c2c136f25cdf118bc0cfc1d.1509545641.git.jani.nikula@intel.com Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/drm_edid.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index c6b281aa762f..6b31e0474271 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3347,8 +3347,7 @@ EXPORT_SYMBOL(drm_edid_get_monitor_name); * @edid: EDID to parse * * Fill the ELD (EDID-Like Data) buffer for passing to the audio driver. The - * Conn_Type, HDCP and Port_ID ELD fields are left for the graphics driver to - * fill in. + * HDCP and Port_ID ELD fields are left for the graphics driver to fill in. */ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) { @@ -3426,6 +3425,12 @@ void drm_edid_to_eld(struct drm_connector *connector, struct edid *edid) } eld[5] |= total_sad_count << 4; + if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort || + connector->connector_type == DRM_MODE_CONNECTOR_eDP) + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_DP; + else + eld[DRM_ELD_SAD_COUNT_CONN_TYPE] |= DRM_ELD_CONN_TYPE_HDMI; + eld[DRM_ELD_BASELINE_ELD_LEN] = DIV_ROUND_UP(drm_eld_calc_baseline_block_size(eld), 4); -- GitLab From 088d552d986e18f0a03a5367cf11b7841597c210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 13 Nov 2017 19:04:18 +0200 Subject: [PATCH 0504/1834] video/hdmi: Allow "empty" HDMI infoframes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 593f4b19a094c4426bd1e1e3cbab87a48bd13c71 ] HDMI 2.0 Appendix F suggest that we should keep sending the infoframe when switching from 3D to 2D mode, even if the infoframe isn't strictly necessary (ie. not needed to transmit the VIC or stereo information). This is a workaround against some sinks that fail to realize that they should switch from 3D to 2D mode when the source stop transmitting the infoframe. v2: Handle unpack() as well Pull the length calculation into a helper Cc: Shashank Sharma Cc: Andrzej Hajda Cc: Thierry Reding Cc: Hans Verkuil Cc: linux-media@vger.kernel.org Reviewed-by: Andrzej Hajda #v1 Signed-off-by: Ville Syrjälä Link: https://patchwork.freedesktop.org/patch/msgid/20171113170427.4150-2-ville.syrjala@linux.intel.com Reviewed-by: Shashank Sharma Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/hdmi.c | 51 +++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c index 162689227a23..b73520aaf697 100644 --- a/drivers/video/hdmi.c +++ b/drivers/video/hdmi.c @@ -321,6 +321,17 @@ int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame) } EXPORT_SYMBOL(hdmi_vendor_infoframe_init); +static int hdmi_vendor_infoframe_length(const struct hdmi_vendor_infoframe *frame) +{ + /* for side by side (half) we also need to provide 3D_Ext_Data */ + if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) + return 6; + else if (frame->vic != 0 || frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) + return 5; + else + return 4; +} + /** * hdmi_vendor_infoframe_pack() - write a HDMI vendor infoframe to binary buffer * @frame: HDMI infoframe @@ -341,19 +352,11 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, u8 *ptr = buffer; size_t length; - /* empty info frame */ - if (frame->vic == 0 && frame->s3d_struct == HDMI_3D_STRUCTURE_INVALID) - return -EINVAL; - /* only one of those can be supplied */ if (frame->vic != 0 && frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) return -EINVAL; - /* for side by side (half) we also need to provide 3D_Ext_Data */ - if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) - frame->length = 6; - else - frame->length = 5; + frame->length = hdmi_vendor_infoframe_length(frame); length = HDMI_INFOFRAME_HEADER_SIZE + frame->length; @@ -372,14 +375,16 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame, ptr[5] = 0x0c; ptr[6] = 0x00; - if (frame->vic) { - ptr[7] = 0x1 << 5; /* video format */ - ptr[8] = frame->vic; - } else { + if (frame->s3d_struct != HDMI_3D_STRUCTURE_INVALID) { ptr[7] = 0x2 << 5; /* video format */ ptr[8] = (frame->s3d_struct & 0xf) << 4; if (frame->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) ptr[9] = (frame->s3d_ext_data & 0xf) << 4; + } else if (frame->vic) { + ptr[7] = 0x1 << 5; /* video format */ + ptr[8] = frame->vic; + } else { + ptr[7] = 0x0 << 5; /* video format */ } hdmi_infoframe_set_checksum(buffer, length); @@ -1161,7 +1166,7 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR || ptr[1] != 1 || - (ptr[2] != 5 && ptr[2] != 6)) + (ptr[2] != 4 && ptr[2] != 5 && ptr[2] != 6)) return -EINVAL; length = ptr[2]; @@ -1189,16 +1194,22 @@ hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame, hvf->length = length; - if (hdmi_video_format == 0x1) { - hvf->vic = ptr[4]; - } else if (hdmi_video_format == 0x2) { + if (hdmi_video_format == 0x2) { + if (length != 5 && length != 6) + return -EINVAL; hvf->s3d_struct = ptr[4] >> 4; if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) { - if (length == 6) - hvf->s3d_ext_data = ptr[5] >> 4; - else + if (length != 6) return -EINVAL; + hvf->s3d_ext_data = ptr[5] >> 4; } + } else if (hdmi_video_format == 0x1) { + if (length != 5) + return -EINVAL; + hvf->vic = ptr[4]; + } else { + if (length != 4) + return -EINVAL; } return 0; -- GitLab From 8e93b348ca667484b40c0dffceb50ae405540851 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 22 Nov 2017 11:19:51 +0100 Subject: [PATCH 0505/1834] HID: elo: clear BTN_LEFT mapping [ Upstream commit 9abd04af951e5734c9d5cfee9b49790844b734cf ] ELO devices have one Button usage in GenDesk field, which makes hid-input map it to BTN_LEFT; that confuses userspace, which then considers the device to be a mouse/touchpad instead of touchscreen. Fix that by unmapping BTN_LEFT and keeping only BTN_TOUCH in place. Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-elo.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c index 0cd4f7216239..5eea6fe0d7bd 100644 --- a/drivers/hid/hid-elo.c +++ b/drivers/hid/hid-elo.c @@ -42,6 +42,12 @@ static int elo_input_configured(struct hid_device *hdev, { struct input_dev *input = hidinput->input; + /* + * ELO devices have one Button usage in GenDesk field, which makes + * hid-input map it to BTN_LEFT; that confuses userspace, which then + * considers the device to be a mouse/touchpad instead of touchscreen. + */ + clear_bit(BTN_LEFT, input->keybit); set_bit(BTN_TOUCH, input->keybit); set_bit(ABS_PRESSURE, input->absbit); input_set_abs_params(input, ABS_PRESSURE, 0, 256, 0, 0); -- GitLab From e95928a6407f32c716f11a4483e6438f88a0ed9f Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 19 Oct 2017 21:36:04 +0300 Subject: [PATCH 0506/1834] iwlwifi: mvm: rs: don't override the rate history in the search cycle [ Upstream commit 992172e3aec19e5b0ea5b757ba40a146b9282d1e ] When we are in a search cycle, we try different combinations of parameters. Those combinations are called 'columns'. When we switch to a new column, we first need to check if this column has a suitable rate, if not, we can't try it. This means we must not erase the statistics we gathered for the previous column until we are sure that we are indeed switching column. The code that tries to switch to a new column first sets a whole bunch of things for the new column, and only then checks that we can find suitable rates in that column. While doing that, the code mistakenly erased the rate statistics. This code was right until struct iwl_scale_tbl_info grew up for TPC. Fix this to make sure we don't erase the rate statistics until we are sure that we can indeed switch to the new column. Note that this bug is really harmless since it causes a change in the behavior only when we can't find any rate in the new column which should really not happen. In the case we do find a suitable we reset the rate statistics a few lines later anyway. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 227c5ed9cbe6..0aea476ebf50 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -1867,12 +1867,10 @@ static int rs_switch_to_column(struct iwl_mvm *mvm, struct rs_rate *rate = &search_tbl->rate; const struct rs_tx_column *column = &rs_tx_columns[col_id]; const struct rs_tx_column *curr_column = &rs_tx_columns[tbl->column]; - u32 sz = (sizeof(struct iwl_scale_tbl_info) - - (sizeof(struct iwl_rate_scale_data) * IWL_RATE_COUNT)); unsigned long rate_mask = 0; u32 rate_idx = 0; - memcpy(search_tbl, tbl, sz); + memcpy(search_tbl, tbl, offsetof(struct iwl_scale_tbl_info, win)); rate->sgi = column->sgi; rate->ant = column->ant; -- GitLab From 05fafb80ba2412da75ef8e23f37bec2285ac7f6f Mon Sep 17 00:00:00 2001 From: Yixun Lan Date: Tue, 7 Nov 2017 22:12:23 +0800 Subject: [PATCH 0507/1834] clk: meson: gxbb: fix wrong clock for SARADC/SANA [ Upstream commit 75eccf5ed83250c0aeaeeb76f7288254ac0a87b4 ] According to the datasheet, in Meson-GXBB/GXL series, The clock gate bit for SARADC is HHI_GCLK_MPEG2 bit[22], while clock gate bit for SANA is HHI_GCLK_MPEG0 bit[10]. Test passed at gxl-s905x-p212 board. The following published datasheets are wrong and should be updated [1] GXBB v1.1.4 [2] GXL v0.3_20170314 Fixes: 738f66d3211d ("clk: gxbb: add AmLogic GXBB clk controller driver") Tested-by: Xingyu Chen Signed-off-by: Yixun Lan Signed-off-by: Jerome Brunet Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/meson/gxbb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index 9d9af446bafc..37e05d6e010a 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -572,7 +572,7 @@ static MESON_GATE(gxbb_pl301, HHI_GCLK_MPEG0, 6); static MESON_GATE(gxbb_periphs, HHI_GCLK_MPEG0, 7); static MESON_GATE(gxbb_spicc, HHI_GCLK_MPEG0, 8); static MESON_GATE(gxbb_i2c, HHI_GCLK_MPEG0, 9); -static MESON_GATE(gxbb_sar_adc, HHI_GCLK_MPEG0, 10); +static MESON_GATE(gxbb_sana, HHI_GCLK_MPEG0, 10); static MESON_GATE(gxbb_smart_card, HHI_GCLK_MPEG0, 11); static MESON_GATE(gxbb_rng0, HHI_GCLK_MPEG0, 12); static MESON_GATE(gxbb_uart0, HHI_GCLK_MPEG0, 13); @@ -623,7 +623,7 @@ static MESON_GATE(gxbb_usb0_ddr_bridge, HHI_GCLK_MPEG2, 9); static MESON_GATE(gxbb_mmc_pclk, HHI_GCLK_MPEG2, 11); static MESON_GATE(gxbb_dvin, HHI_GCLK_MPEG2, 12); static MESON_GATE(gxbb_uart2, HHI_GCLK_MPEG2, 15); -static MESON_GATE(gxbb_sana, HHI_GCLK_MPEG2, 22); +static MESON_GATE(gxbb_sar_adc, HHI_GCLK_MPEG2, 22); static MESON_GATE(gxbb_vpu_intr, HHI_GCLK_MPEG2, 25); static MESON_GATE(gxbb_sec_ahb_ahb3_bridge, HHI_GCLK_MPEG2, 26); static MESON_GATE(gxbb_clk81_a53, HHI_GCLK_MPEG2, 29); -- GitLab From 7667c53f6f9adace76fd791039145de081e9f774 Mon Sep 17 00:00:00 2001 From: Simon Shields Date: Tue, 21 Nov 2017 22:24:24 +1100 Subject: [PATCH 0508/1834] ARM: dts: exynos: Correct Trats2 panel reset line [ Upstream commit 1b377924841df1e13ab5b225be3a83f807a92b52 ] Trats2 uses gpf2-1 as the panel reset GPIO. gpy4-5 was only used on early revisions of the board. Fixes: 420ae8451a22 ("ARM: dts: exynos4412-trats2: add panel node") Signed-off-by: Simon Shields Acked-by: Marek Szyprowski Tested-by: Marek Szyprowski Signed-off-by: Krzysztof Kozlowski Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/exynos4412-trats2.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 41ecd6d465a7..75a60633efff 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -408,7 +408,7 @@ reg = <0>; vdd3-supply = <&lcd_vdd3_reg>; vci-supply = <&ldo25_reg>; - reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpf2 1 GPIO_ACTIVE_HIGH>; power-on-delay= <50>; reset-delay = <100>; init-delay = <100>; -- GitLab From bac7bb1849a683ed64343ec86f24d5403363fe57 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 13 Oct 2017 17:00:18 -0700 Subject: [PATCH 0509/1834] sched: Stop switched_to_rt() from sending IPIs to offline CPUs [ Upstream commit 2fe2582649aa2355f79acddb86bd4d6c5363eb63 ] The rcutorture test suite occasionally provokes a splat due to invoking rt_mutex_lock() which needs to boost the priority of a task currently sitting on a runqueue that belongs to an offline CPU: WARNING: CPU: 0 PID: 12 at /home/paulmck/public_git/linux-rcu/arch/x86/kernel/smp.c:128 native_smp_send_reschedule+0x37/0x40 Modules linked in: CPU: 0 PID: 12 Comm: rcub/7 Not tainted 4.14.0-rc4+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 task: ffff9ed3de5f8cc0 task.stack: ffffbbf80012c000 RIP: 0010:native_smp_send_reschedule+0x37/0x40 RSP: 0018:ffffbbf80012fd10 EFLAGS: 00010082 RAX: 000000000000002f RBX: ffff9ed3dd9cb300 RCX: 0000000000000004 RDX: 0000000080000004 RSI: 0000000000000086 RDI: 00000000ffffffff RBP: ffffbbf80012fd10 R08: 000000000009da7a R09: 0000000000007b9d R10: 0000000000000001 R11: ffffffffbb57c2cd R12: 000000000000000d R13: ffff9ed3de5f8cc0 R14: 0000000000000061 R15: ffff9ed3ded59200 FS: 0000000000000000(0000) GS:ffff9ed3dea00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000080686f0 CR3: 000000001b9e0000 CR4: 00000000000006f0 Call Trace: resched_curr+0x61/0xd0 switched_to_rt+0x8f/0xa0 rt_mutex_setprio+0x25c/0x410 task_blocks_on_rt_mutex+0x1b3/0x1f0 rt_mutex_slowlock+0xa9/0x1e0 rt_mutex_lock+0x29/0x30 rcu_boost_kthread+0x127/0x3c0 kthread+0x104/0x140 ? rcu_report_unblock_qs_rnp+0x90/0x90 ? kthread_create_on_node+0x40/0x40 ret_from_fork+0x22/0x30 Code: f0 00 0f 92 c0 84 c0 74 14 48 8b 05 34 74 c5 00 be fd 00 00 00 ff 90 a0 00 00 00 5d c3 89 fe 48 c7 c7 a0 c6 fc b9 e8 d5 b5 06 00 <0f> ff 5d c3 0f 1f 44 00 00 8b 05 a2 d1 13 02 85 c0 75 38 55 48 But the target task's priority has already been adjusted, so the only purpose of switched_to_rt() invoking resched_curr() is to wake up the CPU running some task that needs to be preempted by the boosted task. But the CPU is offline, which presumably means that the task must be migrated to some other CPU, and that this other CPU will undertake any needed preemption at the time of migration. Because the runqueue lock is held when resched_curr() is invoked, we know that the boosted task cannot go anywhere, so it is not necessary to invoke resched_curr() in this particular case. This commit therefore makes switched_to_rt() refrain from invoking resched_curr() when the target CPU is offline. Signed-off-by: Paul E. McKenney Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/sched/rt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index f6d68ddfa2f3..c7b0d2e7a9aa 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -2206,7 +2206,7 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p) if (tsk_nr_cpus_allowed(p) > 1 && rq->rt.overloaded) queue_push_tasks(rq); #endif /* CONFIG_SMP */ - if (p->prio < rq->curr->prio) + if (p->prio < rq->curr->prio && cpu_online(cpu_of(rq))) resched_curr(rq); } } -- GitLab From cce2b93fd35194558e23582c858c4a9ce90c798c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 13 Oct 2017 16:24:28 -0700 Subject: [PATCH 0510/1834] sched: Stop resched_cpu() from sending IPIs to offline CPUs [ Upstream commit a0982dfa03efca6c239c52cabebcea4afb93ea6b ] The rcutorture test suite occasionally provokes a splat due to invoking resched_cpu() on an offline CPU: WARNING: CPU: 2 PID: 8 at /home/paulmck/public_git/linux-rcu/arch/x86/kernel/smp.c:128 native_smp_send_reschedule+0x37/0x40 Modules linked in: CPU: 2 PID: 8 Comm: rcu_preempt Not tainted 4.14.0-rc4+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 task: ffff902ede9daf00 task.stack: ffff96c50010c000 RIP: 0010:native_smp_send_reschedule+0x37/0x40 RSP: 0018:ffff96c50010fdb8 EFLAGS: 00010096 RAX: 000000000000002e RBX: ffff902edaab4680 RCX: 0000000000000003 RDX: 0000000080000003 RSI: 0000000000000000 RDI: 00000000ffffffff RBP: ffff96c50010fdb8 R08: 0000000000000000 R09: 0000000000000001 R10: 0000000000000000 R11: 00000000299f36ae R12: 0000000000000001 R13: ffffffff9de64240 R14: 0000000000000001 R15: ffffffff9de64240 FS: 0000000000000000(0000) GS:ffff902edfc80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00000000f7d4c642 CR3: 000000001e0e2000 CR4: 00000000000006e0 Call Trace: resched_curr+0x8f/0x1c0 resched_cpu+0x2c/0x40 rcu_implicit_dynticks_qs+0x152/0x220 force_qs_rnp+0x147/0x1d0 ? sync_rcu_exp_select_cpus+0x450/0x450 rcu_gp_kthread+0x5a9/0x950 kthread+0x142/0x180 ? force_qs_rnp+0x1d0/0x1d0 ? kthread_create_on_node+0x40/0x40 ret_from_fork+0x27/0x40 Code: 14 01 0f 92 c0 84 c0 74 14 48 8b 05 14 4f f4 00 be fd 00 00 00 ff 90 a0 00 00 00 5d c3 89 fe 48 c7 c7 38 89 ca 9d e8 e5 56 08 00 <0f> ff 5d c3 0f 1f 44 00 00 8b 05 52 9e 37 02 85 c0 75 38 55 48 ---[ end trace 26df9e5df4bba4ac ]--- This splat cannot be generated by expedited grace periods because they always invoke resched_cpu() on the current CPU, which is good because expedited grace periods require that resched_cpu() unconditionally succeed. However, other parts of RCU can tolerate resched_cpu() acting as a no-op, at least as long as it doesn't happen too often. This commit therefore makes resched_cpu() invoke resched_curr() only if the CPU is either online or is the current CPU. Signed-off-by: Paul E. McKenney Cc: Ingo Molnar Cc: Peter Zijlstra Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/sched/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index bce3a7ad4253..291ea6fa7ee6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -508,7 +508,8 @@ void resched_cpu(int cpu) unsigned long flags; raw_spin_lock_irqsave(&rq->lock, flags); - resched_curr(rq); + if (cpu_online(cpu) || cpu == smp_processor_id()) + resched_curr(rq); raw_spin_unlock_irqrestore(&rq->lock, flags); } -- GitLab From db699dcd8e7af2c497678bed4463f80f75addadc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Mon, 20 Nov 2017 09:45:35 -0800 Subject: [PATCH 0511/1834] test_firmware: fix setting old custom fw path back on exit [ Upstream commit 65c79230576873b312c3599479c1e42355c9f349 ] The file /sys/module/firmware_class/parameters/path can be used to set a custom firmware path. The fw_filesystem.sh script creates a temporary directory to add a test firmware file to be used during testing, in order for this to work it uses the custom path syfs file and it was supposed to reset back the file on execution exit. The script failed to do this due to a typo, it was using OLD_PATH instead of OLD_FWPATH, since its inception since v3.17. Its not as easy to just keep the old setting, it turns out that resetting an empty setting won't actually do what we want, we need to check if it was empty and set an empty space. Without this we end up having the temporary path always set after we run these tests. Fixes: 0a8adf58475 ("test: add firmware_class loader test") Signed-off-by: Luis R. Rodriguez Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/fw_filesystem.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index d8ac9ba67688..17e16fcaa0cc 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh @@ -28,7 +28,10 @@ test_finish() if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout fi - echo -n "$OLD_PATH" >/sys/module/firmware_class/parameters/path + if [ "$OLD_FWPATH" = "" ]; then + OLD_FWPATH=" " + fi + echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path rm -f "$FW" rmdir "$FWPATH" } -- GitLab From 6f8e8ec3d1bd6333f6af8ada6d092314bc9f73c6 Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Tue, 28 Nov 2017 13:53:12 +0100 Subject: [PATCH 0512/1834] net: ieee802154: adf7242: Fix bug if defined DEBUG [ Upstream commit 388b3b2b03701f3b3c10975c272892d7f78080df ] This fixes undefined reference to struct adf7242_local *lp in case DEBUG is defined. Signed-off-by: Michael Hennerich Signed-off-by: Stefan Schmidt Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ieee802154/adf7242.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ieee802154/adf7242.c b/drivers/net/ieee802154/adf7242.c index f355df7cf84a..1b980f12663a 100644 --- a/drivers/net/ieee802154/adf7242.c +++ b/drivers/net/ieee802154/adf7242.c @@ -888,7 +888,7 @@ static struct ieee802154_ops adf7242_ops = { .set_cca_ed_level = adf7242_set_cca_ed_level, }; -static void adf7242_debug(u8 irq1) +static void adf7242_debug(struct adf7242_local *lp, u8 irq1) { #ifdef DEBUG u8 stat; @@ -932,7 +932,7 @@ static irqreturn_t adf7242_isr(int irq, void *data) dev_err(&lp->spi->dev, "%s :ERROR IRQ1 = 0x%X\n", __func__, irq1); - adf7242_debug(irq1); + adf7242_debug(lp, irq1); xmit = test_bit(FLAG_XMIT, &lp->flags); -- GitLab From 5eef9b51114fcc65651d671add52f267f91b9451 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 20 Nov 2017 19:26:02 +0900 Subject: [PATCH 0513/1834] net: xfrm: allow clearing socket xfrm policies. [ Upstream commit be8f8284cd897af2482d4e54fbc2bdfc15557259 ] Currently it is possible to add or update socket policies, but not clear them. Therefore, once a socket policy has been applied, the socket cannot be used for unencrypted traffic. This patch allows (privileged) users to clear socket policies by passing in a NULL pointer and zero length argument to the {IP,IPV6}_{IPSEC,XFRM}_POLICY setsockopts. This results in both the incoming and outgoing policies being cleared. The simple approach taken in this patch cannot clear socket policies in only one direction. If desired this could be added in the future, for example by continuing to pass in a length of zero (which currently is guaranteed to return EMSGSIZE) and making the policy be a pointer to an integer that contains one of the XFRM_POLICY_{IN,OUT} enum values. An alternative would have been to interpret the length as a signed integer and use XFRM_POLICY_IN (i.e., 0) to clear the input policy and -XFRM_POLICY_OUT (i.e., -1) to clear the output policy. Tested: https://android-review.googlesource.com/539816 Signed-off-by: Lorenzo Colitti Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_policy.c | 2 +- net/xfrm/xfrm_state.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 5e89b7461f99..5b8fa6832687 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1346,7 +1346,7 @@ EXPORT_SYMBOL(xfrm_policy_delete); int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) { - struct net *net = xp_net(pol); + struct net *net = sock_net(sk); struct xfrm_policy *old_pol; #ifdef CONFIG_XFRM_SUB_POLICY diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 419bf5d463bd..13e0611a9085 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1883,6 +1883,13 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen struct xfrm_mgr *km; struct xfrm_policy *pol = NULL; + if (!optval && !optlen) { + xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); + xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); + __sk_dst_reset(sk); + return 0; + } + if (optlen <= 0 || optlen > PAGE_SIZE) return -EMSGSIZE; -- GitLab From da2ad1d8d47adb3fb0dbc86bdf27d0f84d5b0a59 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Wed, 8 Nov 2017 17:00:27 +0100 Subject: [PATCH 0514/1834] mtd: nand: fix interpretation of NAND_CMD_NONE in nand_command[_lp]() [ Upstream commit df467899da0b71465760b4e35127bce837244eee ] Some drivers (like nand_hynix.c) call ->cmdfunc() with NAND_CMD_NONE and a column address and expect the controller to only send address cycles. Right now, the default ->cmdfunc() implementations provided by the core do not filter out the command cycle in this case and forwards the request to the controller driver through the ->cmd_ctrl() method. The thing is, NAND controller drivers can get this wrong and send a command cycle with a NAND_CMD_NONE opcode and since NAND_CMD_NONE is -1, and the command field is usually casted to an u8, we end up sending the 0xFF command which is actually a RESET operation. Add conditions in nand_command[_lp]() functions to sending the initial command cycle when command == NAND_CMD_NONE. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nand_base.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 21c03086bb7f..a3e86e52640a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -715,7 +715,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, readcmd, ctrl); ctrl &= ~NAND_CTRL_CHANGE; } - chip->cmd_ctrl(mtd, command, ctrl); + if (command != NAND_CMD_NONE) + chip->cmd_ctrl(mtd, command, ctrl); /* Address cycle, when necessary */ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; @@ -744,6 +745,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, */ switch (command) { + case NAND_CMD_NONE: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: @@ -806,7 +808,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, } /* Command latch cycle */ - chip->cmd_ctrl(mtd, command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + if (command != NAND_CMD_NONE) + chip->cmd_ctrl(mtd, command, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); if (column != -1 || page_addr != -1) { int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; @@ -842,6 +846,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, */ switch (command) { + case NAND_CMD_NONE: case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: -- GitLab From 7c865a3d27274733a680bcd8be8cd50d3841d133 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Fri, 24 Nov 2017 15:04:03 +0300 Subject: [PATCH 0515/1834] net: thunderx: Set max queue count taking XDP_TX into account [ Upstream commit 87de083857aa269fb171ef0b39696b2888361c58 ] on T81 there are only 4 cores, hence setting max queue count to 4 would leave nothing for XDP_TX. This patch fixes this by doubling max queue count in above scenarios. Signed-off-by: Sunil Goutham Signed-off-by: cjacob Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/cavium/thunder/nicvf_main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 8a37012c9c89..c75d4ea9342b 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -1576,6 +1576,11 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) nic->pdev = pdev; nic->pnicvf = nic; nic->max_queues = qcount; + /* If no of CPUs are too low, there won't be any queues left + * for XDP_TX, hence double it. + */ + if (!nic->t88) + nic->max_queues *= 2; /* MAP VF's configuration registers */ nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); -- GitLab From 272b5eef085c23cd71eec30fe040fb1592682508 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 11:13:56 -0600 Subject: [PATCH 0516/1834] ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin [ Upstream commit e153db03c6b7a035c797bcdf35262586f003ee93 ] The correct DT property for specifying a GPIO used for reset is "reset-gpios", fix this here. Fixes: 4341881d0562 ("ARM: dts: Add devicetree for Gumstix Pepper board") Signed-off-by: Andrew F. Davis Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am335x-pepper.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts index 30e2f8770aaf..42b62f54e4b7 100644 --- a/arch/arm/boot/dts/am335x-pepper.dts +++ b/arch/arm/boot/dts/am335x-pepper.dts @@ -139,7 +139,7 @@ &audio_codec { status = "okay"; - gpio-reset = <&gpio1 16 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; AVDD-supply = <&ldo3_reg>; IOVDD-supply = <&ldo3_reg>; DRVDD-supply = <&ldo3_reg>; -- GitLab From e5ca83f556925b86133af12ef7f17c1a52c39d7e Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Wed, 29 Nov 2017 11:13:59 -0600 Subject: [PATCH 0517/1834] ARM: dts: omap3-n900: Fix the audio CODEC's reset pin [ Upstream commit 7be4b5dc7ffa9499ac6ef33a5ffa9ff43f9b7057 ] The correct DT property for specifying a GPIO used for reset is "reset-gpios", fix this here. Fixes: 14e3e295b2b9 ("ARM: dts: omap3-n900: Add TLV320AIC3X support") Signed-off-by: Andrew F. Davis Signed-off-by: Tony Lindgren Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/omap3-n900.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index 4d448f145ed1..6003b29c0fc0 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -510,7 +510,7 @@ tlv320aic3x: tlv320aic3x@18 { compatible = "ti,tlv320aic3x"; reg = <0x18>; - gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ + reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ ai3x-gpio-func = < 0 /* AIC3X_GPIO1_FUNC_DISABLED */ 5 /* AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT */ @@ -527,7 +527,7 @@ tlv320aic3x_aux: tlv320aic3x@19 { compatible = "ti,tlv320aic3x"; reg = <0x19>; - gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ + reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ AVDD-supply = <&vmmc2>; DRVDD-supply = <&vmmc2>; -- GitLab From 88347216d8e493d2a8bdcc3eb45beb55a8c0e4ef Mon Sep 17 00:00:00 2001 From: Jagdish Gediya Date: Thu, 23 Nov 2017 17:04:31 +0530 Subject: [PATCH 0518/1834] mtd: nand: ifc: update bufnum mask for ver >= 2.0.0 [ Upstream commit bccb06c353af3764ca86d9da47652458e6c2eb41 ] Bufnum mask is used to calculate page position in the internal SRAM. As IFC version 2.0.0 has 16KB of internal SRAM as compared to older versions which had 8KB. Hence bufnum mask needs to be updated. Signed-off-by: Jagdish Gediya Signed-off-by: Prabhakar Kushwaha Signed-off-by: Boris Brezillon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/fsl_ifc_nand.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index d1570f512f0b..f8f12ccc6471 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -907,6 +907,13 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) if (ctrl->version == FSL_IFC_VERSION_1_1_0) fsl_ifc_sram_init(priv); + /* + * As IFC version 2.0.0 has 16KB of internal SRAM as compared to older + * versions which had 8KB. Hence bufnum mask needs to be updated. + */ + if (ctrl->version >= FSL_IFC_VERSION_2_0_0) + priv->bufnum_mask = (priv->bufnum_mask * 2) + 1; + return 0; } -- GitLab From 708f90af5f2277ddd412583b873c7fc4ce7a20ce Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 29 Nov 2017 17:29:20 -0600 Subject: [PATCH 0519/1834] userns: Don't fail follow_automount based on s_user_ns [ Upstream commit bbc3e471011417598e598707486f5d8814ec9c01 ] When vfs_submount was added the test to limit automounts from filesystems that with s_user_ns != &init_user_ns accidentially left in follow_automount. The test was never about any security concerns and was always about how do we implement this for filesystems whose s_user_ns != &init_user_ns. At the moment this check makes no difference as there are no filesystems that both set FS_USERNS_MOUNT and implement d_automount. Remove this check now while I am thinking about it so there will not be odd booby traps for someone who does want to make this combination work. vfs_submount still needs improvements to allow this combination to work, and vfs_submount contains a check that presents a warning. The autofs4 filesystem could be modified to set FS_USERNS_MOUNT and it would need not work on this code path, as userspace performs the mounts. Fixes: 93faccbbfa95 ("fs: Better permission checking for submounts") Fixes: aeaa4a79ff6a ("fs: Call d_automount with the filesystems creds") Acked-by: Ian Kent Signed-off-by: "Eric W. Biederman" Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 6cfb45f262aa..917e7996b9c3 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1121,9 +1121,6 @@ static int follow_automount(struct path *path, struct nameidata *nd, path->dentry->d_inode) return -EISDIR; - if (path->dentry->d_sb->s_user_ns != &init_user_ns) - return -EACCES; - nd->total_link_count++; if (nd->total_link_count >= 40) return -ELOOP; -- GitLab From c21a7793a743dec2cdb7538168a6758b3bef165b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Thu, 30 Nov 2017 21:16:56 -0800 Subject: [PATCH 0520/1834] leds: pm8058: Silence pointer to integer size warning [ Upstream commit 8f52df50d9366f770a894d14ef724e5e04574e98 ] The pointer returned by of_device_get_match_data() doesn't have the same size as u32 on 64-bit architectures, causing a compile warning when compile-testing the driver on such platform. Cast the return value of of_device_get_match_data() to unsigned long and then to u32 to silence this warning. Fixes: 7f866986e705 ("leds: add PM8058 LEDs driver") Signed-off-by: Bjorn Andersson Reviewed-by: Linus Walleij Acked-by: Pavel Machek Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-pm8058.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-pm8058.c b/drivers/leds/leds-pm8058.c index a52674327857..8988ba3b2d65 100644 --- a/drivers/leds/leds-pm8058.c +++ b/drivers/leds/leds-pm8058.c @@ -106,7 +106,7 @@ static int pm8058_led_probe(struct platform_device *pdev) if (!led) return -ENOMEM; - led->ledtype = (u32)of_device_get_match_data(&pdev->dev); + led->ledtype = (u32)(unsigned long)of_device_get_match_data(&pdev->dev); map = dev_get_regmap(pdev->dev.parent, NULL); if (!map) { -- GitLab From 4aac8ff4c4d85603629ede10ca569e4e27a1e1ea Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 22 Nov 2017 21:27:31 +0100 Subject: [PATCH 0521/1834] power: supply: ab8500_charger: Fix an error handling path [ Upstream commit bf59fddde1c3eab89eb8dca8f3d3dc097887d2bb ] 'ret' is know to be 0 at this point, because it has not been updated by the the previous call to 'abx500_mask_and_set_register_interruptible()'. Fix it by updating 'ret' before checking if an error occurred. Fixes: 84edbeeab67c ("ab8500-charger: AB8500 charger driver") Signed-off-by: Christophe JAILLET Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/ab8500_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 5cee9aa87aa3..037e93224c38 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3218,7 +3218,7 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) } /* Enable backup battery charging */ - abx500_mask_and_set_register_interruptible(di->dev, + ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, RTC_BUP_CH_ENA); if (ret < 0) -- GitLab From 7c3632572ab2dbc399f61aca8156b3c18ecf4651 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Wed, 22 Nov 2017 21:31:20 +0100 Subject: [PATCH 0522/1834] power: supply: ab8500_charger: Bail out in case of error in 'ab8500_charger_init_hw_registers()' [ Upstream commit 09edcb647542487864e23aa8d2ef26be3e08978a ] If an error occurs when we enable the backup battery charging, we should go through the error handling path directly. Before commit db43e6c473b5 ("ab8500-bm: Add usb power path support") this was the case, but this commit has added some code between the last test and the 'out' label. So, in case of error, this added code is executed and the error may be silently ignored. Fix it by adding the missing 'goto out', as done in all other error handling paths. Fixes: db43e6c473b5 ("ab8500-bm: Add usb power path support") Signed-off-by: Christophe JAILLET Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/ab8500_charger.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index 037e93224c38..48a11fd86a7f 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -3221,8 +3221,10 @@ static int ab8500_charger_init_hw_registers(struct ab8500_charger *di) ret = abx500_mask_and_set_register_interruptible(di->dev, AB8500_RTC, AB8500_RTC_CTRL_REG, RTC_BUP_CH_ENA, RTC_BUP_CH_ENA); - if (ret < 0) + if (ret < 0) { dev_err(di->dev, "%s mask and set failed\n", __func__); + goto out; + } if (is_ab8540(di->parent)) { ret = abx500_mask_and_set_register_interruptible(di->dev, -- GitLab From 103188787d9c1ceb3a0aceeaa37a2f252c58111f Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Mon, 6 Nov 2017 13:39:31 +0530 Subject: [PATCH 0523/1834] ath10k: update tdls teardown state to target [ Upstream commit 424ea0d174e82365f85c6770225dba098b8f1d5f ] It is required to update the teardown state of the peer when a tdls link with that peer is terminated. This information is useful for the target to perform some cleanups wrt the tdls peer. Without proper cleanup, target assumes that the peer is connected and blocks future connection requests, updating the teardown state of the peer addresses the problem. Tested this change on QCA9888 with 10.4-3.5.1-00018 fw version. Signed-off-by: Manikanta Pubbisetty Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/mac.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 696b90270615..1e6e63dbd61c 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6054,6 +6054,16 @@ static int ath10k_sta_state(struct ieee80211_hw *hw, "mac vdev %d peer delete %pM sta %pK (sta gone)\n", arvif->vdev_id, sta->addr, sta); + if (sta->tdls) { + ret = ath10k_mac_tdls_peer_update(ar, arvif->vdev_id, + sta, + WMI_TDLS_PEER_STATE_TEARDOWN); + if (ret) + ath10k_warn(ar, "failed to update tdls peer state for %pM state %d: %i\n", + sta->addr, + WMI_TDLS_PEER_STATE_TEARDOWN, ret); + } + ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr); if (ret) ath10k_warn(ar, "failed to delete peer %pM for vdev %d: %i\n", -- GitLab From c6656ab87a0ea6185591d30ee965e5afa49e8c7f Mon Sep 17 00:00:00 2001 From: Li Dongyang Date: Tue, 14 Nov 2017 10:48:04 +1100 Subject: [PATCH 0524/1834] scsi: ses: don't ask for diagnostic pages repeatedly during probe [ Upstream commit 9c0a50022b8ac7e863e6ec8342fa476fe5d1d75c ] We are testing if there is a match with the ses device in a loop by calling ses_match_to_enclosure(), which will issue scsi receive diagnostics commands to the ses device for every device on the same host. On one of our boxes with 840 disks, it takes a long time to load the driver: [root@g1b-oss06 ~]# time modprobe ses real 40m48.247s user 0m0.001s sys 0m0.196s With the patch: [root@g1b-oss06 ~]# time modprobe ses real 0m17.915s user 0m0.008s sys 0m0.053s Note that we still need to refresh page 10 when we see a new disk to create the link. Signed-off-by: Li Dongyang Tested-by: Jason Ozolins Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/ses.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index f1cdf32d7514..69046d342bc5 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -578,13 +578,16 @@ static void ses_enclosure_data_process(struct enclosure_device *edev, } static void ses_match_to_enclosure(struct enclosure_device *edev, - struct scsi_device *sdev) + struct scsi_device *sdev, + int refresh) { + struct scsi_device *edev_sdev = to_scsi_device(edev->edev.parent); struct efd efd = { .addr = 0, }; - ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); + if (refresh) + ses_enclosure_data_process(edev, edev_sdev, 0); if (scsi_is_sas_rphy(sdev->sdev_target->dev.parent)) efd.addr = sas_get_address(sdev); @@ -615,7 +618,7 @@ static int ses_intf_add(struct device *cdev, struct enclosure_device *prev = NULL; while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { - ses_match_to_enclosure(edev, sdev); + ses_match_to_enclosure(edev, sdev, 1); prev = edev; } return -ENODEV; @@ -727,7 +730,7 @@ static int ses_intf_add(struct device *cdev, shost_for_each_device(tmp_sdev, sdev->host) { if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) continue; - ses_match_to_enclosure(edev, tmp_sdev); + ses_match_to_enclosure(edev, tmp_sdev, 0); } return 0; -- GitLab From 93f092f2c3c4d8f091f4b59b930283a8b4c5d6c0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Nov 2017 13:18:53 +0800 Subject: [PATCH 0525/1834] pwm: stmpe: Fix wrong register offset for hwpwm=2 case [ Upstream commit 8472b529e113e0863ea064fdee51bf73c3f86fd6 ] Fix trivial copy/paste bug. Signed-off-by: Axel Lin Reviewed-by: Linus Walleij Fixes: ef1f09eca74a ("pwm: Add a driver for the STMPE PWM") Signed-off-by: Thierry Reding Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pwm/pwm-stmpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pwm/pwm-stmpe.c b/drivers/pwm/pwm-stmpe.c index e464582a390a..3439f1e902cb 100644 --- a/drivers/pwm/pwm-stmpe.c +++ b/drivers/pwm/pwm-stmpe.c @@ -145,7 +145,7 @@ static int stmpe_24xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, break; case 2: - offset = STMPE24XX_PWMIC1; + offset = STMPE24XX_PWMIC2; break; default: -- GitLab From a40eb9e8aaf6799a632de003c7231b6307ed47fc Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Wed, 6 Dec 2017 12:11:38 +0000 Subject: [PATCH 0526/1834] clk: qcom: msm8916: fix mnd_width for codec_digcodec [ Upstream commit d8e488e8242ecf129eebc440c92d800a99ca109d ] This patch fixes missing mnd_width for codec_digital clk, this is now set to 8 inline with datasheet. Fixes: 3966fab8b6ab ("clk: qcom: Add MSM8916 Global Clock Controller support") Signed-off-by: Srinivas Kandagatla Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/qcom/gcc-msm8916.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/qcom/gcc-msm8916.c b/drivers/clk/qcom/gcc-msm8916.c index 5c4e193164d4..8dd71345b5d0 100644 --- a/drivers/clk/qcom/gcc-msm8916.c +++ b/drivers/clk/qcom/gcc-msm8916.c @@ -1437,6 +1437,7 @@ static const struct freq_tbl ftbl_codec_clk[] = { static struct clk_rcg2 codec_digcodec_clk_src = { .cmd_rcgr = 0x1c09c, + .mnd_width = 8, .hid_width = 5, .parent_map = gcc_xo_gpll1_emclk_sleep_map, .freq_tbl = ftbl_codec_clk, -- GitLab From 128e61839d68dee6bfccf9b64e80a041e85789fb Mon Sep 17 00:00:00 2001 From: Limin Zhu Date: Thu, 30 Nov 2017 14:22:34 +0800 Subject: [PATCH 0527/1834] mwifiex: cfg80211: do not change virtual interface during scan processing [ Upstream commit c61cfe49f0f0f0d1f8b56d0b045838d597e8c3a3 ] (1) Change virtual interface operation in cfg80211 process reset and reinitilize private data structure. (2) Scan result event processed in main process will dereference private data structure concurrently, ocassionly crash the kernel. The cornel case could be trigger by below steps: (1) wpa_cli mlan0 scan (2) ./hostapd mlan0.conf Cfg80211 asynchronous scan procedure is not all the time operated under rtnl lock, here we add the protect to serialize the cfg80211 scan and change_virtual interface operation. Signed-off-by: Limin Zhu Signed-off-by: Xinming Hu Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 8677a53ef725..48d51be11f9b 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -1109,6 +1109,12 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype; + if (priv->scan_request) { + mwifiex_dbg(priv->adapter, ERROR, + "change virtual interface: scan in process\n"); + return -EBUSY; + } + switch (curr_iftype) { case NL80211_IFTYPE_ADHOC: switch (type) { -- GitLab From 7f4d2f7547010aeded32f0269a206f8dac0cf88b Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Sat, 2 Dec 2017 16:50:49 +0200 Subject: [PATCH 0528/1834] ath10k: fix invalid STS_CAP_OFFSET_MASK [ Upstream commit 8cec57f5277ef0e354e37a0bf909dc71bc1f865b ] The 10.4 firmware defines this as a 3-bit field, as does the mac80211 stack. The 4th bit is defined as CONF_IMPLICIT_BF at least in the firmware header I have seen. This patch fixes the ath10k wmi header to match the firmware. Signed-off-by: Ben Greear Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/wmi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 1b243c899bef..9b8562ff6698 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5017,7 +5017,8 @@ enum wmi_10_4_vdev_param { #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) #define WMI_TXBF_STS_CAP_OFFSET_LSB 4 -#define WMI_TXBF_STS_CAP_OFFSET_MASK 0xf0 +#define WMI_TXBF_STS_CAP_OFFSET_MASK 0x70 +#define WMI_TXBF_CONF_IMPLICIT_BF BIT(7) #define WMI_BF_SOUND_DIM_OFFSET_LSB 8 #define WMI_BF_SOUND_DIM_OFFSET_MASK 0xf00 -- GitLab From c485b111e69c76a39d5535c0d53050635f0e3314 Mon Sep 17 00:00:00 2001 From: Julien BOIBESSOT Date: Tue, 5 Dec 2017 18:48:14 +0100 Subject: [PATCH 0529/1834] tools/usbip: fixes build with musl libc toolchain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 77be4c878c72e411ad22af96b6f81dd45c26450a ] Indeed musl doesn't define old SIGCLD signal name but only new one SIGCHLD. SIGCHLD is the new POSIX name for that signal so it doesn't change anything on other libcs. This fixes this kind of build error: usbipd.c: In function ‘set_signal’: usbipd.c:459:12: error: 'SIGCLD' undeclared (first use in this function) sigaction(SIGCLD, &act, NULL); ^~~~~~ usbipd.c:459:12: note: each undeclared identifier is reported only once for each function it appears in Makefile:407: recipe for target 'usbipd.o' failed make[3]: *** [usbipd.o] Error 1 Signed-off-by: Julien BOIBESSOT Acked-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/usb/usbip/src/usbipd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/usb/usbip/src/usbipd.c b/tools/usb/usbip/src/usbipd.c index a0972dea9e6c..193556507957 100644 --- a/tools/usb/usbip/src/usbipd.c +++ b/tools/usb/usbip/src/usbipd.c @@ -463,7 +463,7 @@ static void set_signal(void) sigaction(SIGTERM, &act, NULL); sigaction(SIGINT, &act, NULL); act.sa_handler = SIG_IGN; - sigaction(SIGCLD, &act, NULL); + sigaction(SIGCHLD, &act, NULL); } static const char *pid_file; -- GitLab From 26cae37274f3ea5dad4c4b7e8db08caaf502f14f Mon Sep 17 00:00:00 2001 From: Tobias Jordan Date: Thu, 7 Dec 2017 15:04:53 +0100 Subject: [PATCH 0530/1834] spi: sun6i: disable/unprepare clocks on remove [ Upstream commit 2d9bbd02c54094ceffa555143b0d68cd06504d63 ] sun6i_spi_probe() uses sun6i_spi_runtime_resume() to prepare/enable clocks, so sun6i_spi_remove() should use sun6i_spi_runtime_suspend() to disable/unprepare them if we're not suspended. Replacing pm_runtime_disable() by pm_runtime_force_suspend() will ensure that sun6i_spi_runtime_suspend() is called if needed. Found by Linux Driver Verification project (linuxtesting.org). Fixes: 3558fe900e8af (spi: sunxi: Add Allwinner A31 SPI controller driver) Signed-off-by: Tobias Jordan Acked-by: Maxime Ripard Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-sun6i.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 9918a57a6a6e..7e7da97982aa 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -464,7 +464,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) static int sun6i_spi_remove(struct platform_device *pdev) { - pm_runtime_disable(&pdev->dev); + pm_runtime_force_suspend(&pdev->dev); return 0; } -- GitLab From c3dec92f3d792d9180d29b29b2da88d8b861b03d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 6 Dec 2017 17:31:22 -0500 Subject: [PATCH 0531/1834] bnxt_en: Don't print "Link speed -1 no longer supported" messages. [ Upstream commit a8168b6cee6e9334dfebb4b9108e8d73794f6088 ] On some dual port NICs, the 2 ports have to be configured with compatible link speeds. Under some conditions, a port's configured speed may no longer be supported. The firmware will send a message to the driver when this happens. Improve this logic that prints out the warning by only printing it if we can determine the link speed that is no longer supported. If the speed is unknown or it is in autoneg mode, skip the warning message. Reported-by: Thomas Bogendoerfer Signed-off-by: Michael Chan Tested-by: Thomas Bogendoerfer Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index bbb3641eddcb..3aa993bbafd9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1498,12 +1498,16 @@ static int bnxt_async_event_process(struct bnxt *bp, if (BNXT_VF(bp)) goto async_event_process_exit; - if (data1 & 0x20000) { + + /* print unsupported speed warning in forced speed mode only */ + if (!(link_info->autoneg & BNXT_AUTONEG_SPEED) && + (data1 & 0x20000)) { u16 fw_speed = link_info->force_link_speed; u32 speed = bnxt_fw_to_ethtool_speed(fw_speed); - netdev_warn(bp->dev, "Link speed %d no longer supported\n", - speed); + if (speed != SPEED_UNKNOWN) + netdev_warn(bp->dev, "Link speed %d no longer supported\n", + speed); } set_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT, &bp->sp_event); /* fall thru */ -- GitLab From f2e152e2b04717f5d449256317afb9c0670f0fdd Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 4 Dec 2017 10:36:31 -0800 Subject: [PATCH 0532/1834] scsi: core: scsi_get_device_flags_keyed(): Always return device flags [ Upstream commit a44c9d36509c83cf64f33b93f6ab2e63822c01eb ] Since scsi_get_device_flags_keyed() callers do not check whether or not the returned value is an error code, change that function such that it returns a flags value even if the 'key' argument is invalid. Note: since commit 28a0bc4120d3 ("scsi: sd: Implement blacklist option for WRITE SAME w/ UNMAP") bit 31 is a valid device information flag so checking whether bit 31 is set in the return value is not sufficient to tell the difference between an error code and a flags value. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_devinfo.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 26e6b05d05fc..9545c40daa5e 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -596,17 +596,12 @@ int scsi_get_device_flags_keyed(struct scsi_device *sdev, int key) { struct scsi_dev_info_list *devinfo; - int err; devinfo = scsi_dev_info_list_find(vendor, model, key); if (!IS_ERR(devinfo)) return devinfo->flags; - err = PTR_ERR(devinfo); - if (err != -ENOENT) - return err; - - /* nothing found, return nothing */ + /* key or device not found: return nothing */ if (key != SCSI_DEVINFO_GLOBAL) return 0; -- GitLab From 5f3e85ab6ac55b37ddce0cbbecb222a12831b1e7 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Fri, 17 Nov 2017 21:31:36 +0100 Subject: [PATCH 0533/1834] scsi: devinfo: apply to HP XP the same flags as Hitachi VSP [ Upstream commit b369a0471503130cfc74f9f62071db97f48948c3 ] Commit 56f3d383f37b ("scsi: scsi_devinfo: Add TRY_VPD_PAGES to HITACHI OPEN-V blacklist entry") modified some Hitachi entries: HITACHI is always supporting VPD pages, even though it's claiming to support SCSI Revision 3 only. The same should have been done also for HP-rebranded. [mkp: checkpatch and tweaked commit message] Cc: Hannes Reinecke Cc: Takahiro Yasui Cc: Matthias Rudolph Cc: Martin K. Petersen Cc: James E.J. Bottomley Cc: SCSI ML Signed-off-by: Xose Vazquez Perez Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_devinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 9545c40daa5e..43d4b30cbf65 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -180,7 +180,7 @@ static struct { {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ - {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ + {"HP", "OPEN-", "*", BLIST_REPORTLUN2 | BLIST_TRY_VPD_PAGES}, /* HP XP Arrays */ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, -- GitLab From 1b2981c3cba7fdd0b3f48c7a52fcc69aa11bb5e9 Mon Sep 17 00:00:00 2001 From: Xose Vazquez Perez Date: Fri, 17 Nov 2017 22:05:13 +0100 Subject: [PATCH 0534/1834] scsi: dh: add new rdac devices [ Upstream commit 4b3aec2bbbce1c35f50e7475a9fd78d24b9ea4ea ] Add IBM 3542 and 3552, arrays: FAStT200 and FAStT500. Add full STK OPENstorage family, arrays: 9176, D173, D178, D210, D220, D240 and D280. Add STK BladeCtlr family, arrays: B210, B220, B240 and B280. These changes were done in multipath-tools time ago. Cc: NetApp RDAC team Cc: Hannes Reinecke Cc: Christophe Varoqui Cc: Martin K. Petersen Cc: James E.J. Bottomley Cc: SCSI ML Cc: device-mapper development Signed-off-by: Xose Vazquez Perez Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/scsi_dh.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 84addee05be6..a5e30e9449ef 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -56,10 +56,13 @@ static const struct scsi_dh_blist scsi_dh_blist[] = { {"IBM", "1815", "rdac", }, {"IBM", "1818", "rdac", }, {"IBM", "3526", "rdac", }, + {"IBM", "3542", "rdac", }, + {"IBM", "3552", "rdac", }, {"SGI", "TP9", "rdac", }, {"SGI", "IS", "rdac", }, - {"STK", "OPENstorage D280", "rdac", }, + {"STK", "OPENstorage", "rdac", }, {"STK", "FLEXLINE 380", "rdac", }, + {"STK", "BladeCtlr", "rdac", }, {"SUN", "CSM", "rdac", }, {"SUN", "LCSM100", "rdac", }, {"SUN", "STK6580_6780", "rdac", }, -- GitLab From 947e2e9bd754b68bb4379b67ef3cb44879ad2ee9 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Mon, 4 Dec 2017 06:01:11 -0500 Subject: [PATCH 0535/1834] media: vsp1: Prevent suspending and resuming DRM pipelines [ Upstream commit a17d2d6cd9985ca09a9e384f1bc71d710f7e5203 ] When used as part of a display pipeline, the VSP is stopped and restarted explicitly by the DU from its suspend and resume handlers. There is thus no need to stop or restart pipelines in the VSP suspend and resume handlers, and doing so would cause the hardware to be left in a misconfigured state. Ensure that the VSP suspend and resume handlers do not affect DRM-based pipelines. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/vsp1/vsp1_drv.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 57c713a4e1df..4ac1ff482a0b 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -509,7 +509,13 @@ static int __maybe_unused vsp1_pm_suspend(struct device *dev) { struct vsp1_device *vsp1 = dev_get_drvdata(dev); - vsp1_pipelines_suspend(vsp1); + /* + * When used as part of a display pipeline, the VSP is stopped and + * restarted explicitly by the DU. + */ + if (!vsp1->drm) + vsp1_pipelines_suspend(vsp1); + pm_runtime_force_suspend(vsp1->dev); return 0; @@ -520,7 +526,13 @@ static int __maybe_unused vsp1_pm_resume(struct device *dev) struct vsp1_device *vsp1 = dev_get_drvdata(dev); pm_runtime_force_resume(vsp1->dev); - vsp1_pipelines_resume(vsp1); + + /* + * When used as part of a display pipeline, the VSP is stopped and + * restarted explicitly by the DU. + */ + if (!vsp1->drm) + vsp1_pipelines_resume(vsp1); return 0; } -- GitLab From ff54d5e95ad2ba7067ddd4764136bbded8a8129c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Nov 2017 16:28:14 -0500 Subject: [PATCH 0536/1834] media: cpia2: Fix a couple off by one bugs [ Upstream commit d5ac225c7d64c9c3ef821239edc035634e594ec9 ] The cam->buffers[] array has cam->num_frames elements so the > needs to be changed to >= to avoid going beyond the end of the array. The ->buffers[] array is allocated in cpia2_allocate_buffers() if you want to confirm. Fixes: ab33d5071de7 ("V4L/DVB (3376): Add cpia2 camera support") Signed-off-by: Dan Carpenter Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/cpia2/cpia2_v4l.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 9caea8344547..d793c630f1dd 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -812,7 +812,7 @@ static int cpia2_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) struct camera_data *cam = video_drvdata(file); if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - buf->index > cam->num_frames) + buf->index >= cam->num_frames) return -EINVAL; buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; @@ -863,7 +863,7 @@ static int cpia2_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || buf->memory != V4L2_MEMORY_MMAP || - buf->index > cam->num_frames) + buf->index >= cam->num_frames) return -EINVAL; DBG("QBUF #%d\n", buf->index); -- GitLab From c3fd4d3c1966b34bad24ecd6629ebe55b865df10 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 7 Dec 2017 15:40:20 -0800 Subject: [PATCH 0537/1834] veth: set peer GSO values [ Upstream commit 72d24955b44a4039db54a1c252b5031969eeaac3 ] When new veth is created, and GSO values have been configured on one device, clone those values to the peer. For example: # ip link add dev vm1 gso_max_size 65530 type veth peer name vm2 This should create vm1 <--> vm2 with both having GSO maximum size set to 65530. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/veth.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index fbc853e64531..ee7460ee3d05 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -425,6 +425,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, if (ifmp && (dev->ifindex != 0)) peer->ifindex = ifmp->ifi_index; + peer->gso_max_size = dev->gso_max_size; + peer->gso_max_segs = dev->gso_max_segs; + err = register_netdevice(peer); put_net(net); net = NULL; -- GitLab From 049cff8555d41211c3dfbdcfc46cbb818d32eeae Mon Sep 17 00:00:00 2001 From: Yong Zhao Date: Fri, 8 Dec 2017 23:08:48 -0500 Subject: [PATCH 0538/1834] drm/amdkfd: Fix memory leaks in kfd topology [ Upstream commit 5108d768408abc80e4e8d99f5b406a73cb04056b ] Kobject created using kobject_create_and_add() can be freed using kobject_put() when there is no referenece any more. However, kobject memory allocated with kzalloc() has to set up a release callback in order to free it when the counter decreases to 0. Otherwise it causes memory leak. Signed-off-by: Yong Zhao Signed-off-by: Felix Kuehling Reviewed-by: Oded Gabbay Signed-off-by: Oded Gabbay Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index 1e5064749959..8c6e47c5507f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -519,11 +519,17 @@ static ssize_t sysprops_show(struct kobject *kobj, struct attribute *attr, return ret; } +static void kfd_topology_kobj_release(struct kobject *kobj) +{ + kfree(kobj); +} + static const struct sysfs_ops sysprops_ops = { .show = sysprops_show, }; static struct kobj_type sysprops_type = { + .release = kfd_topology_kobj_release, .sysfs_ops = &sysprops_ops, }; @@ -559,6 +565,7 @@ static const struct sysfs_ops iolink_ops = { }; static struct kobj_type iolink_type = { + .release = kfd_topology_kobj_release, .sysfs_ops = &iolink_ops, }; @@ -586,6 +593,7 @@ static const struct sysfs_ops mem_ops = { }; static struct kobj_type mem_type = { + .release = kfd_topology_kobj_release, .sysfs_ops = &mem_ops, }; @@ -625,6 +633,7 @@ static const struct sysfs_ops cache_ops = { }; static struct kobj_type cache_type = { + .release = kfd_topology_kobj_release, .sysfs_ops = &cache_ops, }; @@ -747,6 +756,7 @@ static const struct sysfs_ops node_ops = { }; static struct kobj_type node_type = { + .release = kfd_topology_kobj_release, .sysfs_ops = &node_ops, }; -- GitLab From f6edf95e54cb18ef12e82298e44eebad2fb9aa7d Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 16 Nov 2017 11:45:37 -0600 Subject: [PATCH 0539/1834] powerpc/modules: Don't try to restore r2 after a sibling call [ Upstream commit b9eab08d012fa093947b230f9a87257c27fb829b ] When attempting to load a livepatch module, I got the following error: module_64: patch_module: Expect noop after relocate, got 3c820000 The error was triggered by the following code in unregister_netdevice_queue(): 14c: 00 00 00 48 b 14c 14c: R_PPC64_REL24 net_set_todo 150: 00 00 82 3c addis r4,r2,0 GCC didn't insert a nop after the branch to net_set_todo() because it's a sibling call, so it never returns. The nop isn't needed after the branch in that case. Signed-off-by: Josh Poimboeuf Acked-by: Naveen N. Rao Reviewed-and-tested-by: Kamalesh Babulal Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/code-patching.h | 1 + arch/powerpc/kernel/module_64.c | 12 +++++++++++- arch/powerpc/lib/code-patching.c | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/code-patching.h b/arch/powerpc/include/asm/code-patching.h index 2015b072422c..b4ab1f497335 100644 --- a/arch/powerpc/include/asm/code-patching.h +++ b/arch/powerpc/include/asm/code-patching.h @@ -30,6 +30,7 @@ int patch_branch(unsigned int *addr, unsigned long target, int flags); int patch_instruction(unsigned int *addr, unsigned int instr); int instr_is_relative_branch(unsigned int instr); +int instr_is_relative_link_branch(unsigned int instr); int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr); unsigned long branch_target(const unsigned int *instr); unsigned int translate_branch(const unsigned int *dest, diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 183368e008cf..99407cf12ad5 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c @@ -494,7 +494,17 @@ static bool is_early_mcount_callsite(u32 *instruction) restore r2. */ static int restore_r2(u32 *instruction, struct module *me) { - if (is_early_mcount_callsite(instruction - 1)) + u32 *prev_insn = instruction - 1; + + if (is_early_mcount_callsite(prev_insn)) + return 1; + + /* + * Make sure the branch isn't a sibling call. Sibling calls aren't + * "link" branches and they don't return, so they don't need the r2 + * restore afterwards. + */ + if (!instr_is_relative_link_branch(*prev_insn)) return 1; if (*instruction != PPC_INST_NOP) { diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index d5edbeb8eb82..753d591f1b52 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -95,6 +95,11 @@ int instr_is_relative_branch(unsigned int instr) return instr_is_branch_iform(instr) || instr_is_branch_bform(instr); } +int instr_is_relative_link_branch(unsigned int instr) +{ + return instr_is_relative_branch(instr) && (instr & BRANCH_SET_LINK); +} + static unsigned long branch_iform_target(const unsigned int *instr) { signed long imm; -- GitLab From 678131a9cbeb64c50e347edcc9171b9feedb2c0d Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 8 Dec 2017 21:46:16 +0000 Subject: [PATCH 0540/1834] agp/intel: Flush all chipset writes after updating the GGTT [ Upstream commit 8516673a996870ea0ceb337ee4f83c33c5ec3111 ] Before accessing the GGTT we must flush the PTE writes and make them visible to the chipset, or else the indirect access may end up in the wrong page. In commit 3497971a71d8 ("agp/intel: Flush chipset writes after updating a single PTE"), we noticed corruption of the uploads for pwrite and for capturing GPU error states, but it was presumed that the explicit calls to intel_gtt_chipset_flush() were sufficient for the execbuffer path. However, we have not been flushing the chipset between the PTE writes and access via the GTT itself. For simplicity, do the flush after any PTE update rather than try and batch the flushes on a just-in-time basis. References: 3497971a71d8 ("agp/intel: Flush chipset writes after updating a single PTE") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Mika Kuoppala Cc: drm-intel-fixes@lists.freedesktop.org Reviewed-by: Joonas Lahtinen Link: https://patchwork.freedesktop.org/patch/msgid/20171208214616.30147-1-chris@chris-wilson.co.uk Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/char/agp/intel-gtt.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 0f7d28a98b9a..a7cc5b7be598 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -871,6 +871,8 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, } } wmb(); + if (intel_private.driver->chipset_flush) + intel_private.driver->chipset_flush(); } EXPORT_SYMBOL(intel_gtt_insert_sg_entries); -- GitLab From d8f060c2a8c0f81eede6a7775998e3afd91fea6f Mon Sep 17 00:00:00 2001 From: Adiel Aloni Date: Fri, 1 Dec 2017 13:50:53 +0200 Subject: [PATCH 0541/1834] mac80211_hwsim: enforce PS_MANUAL_POLL to be set after PS_ENABLED [ Upstream commit e16ea4bb516bc21ea2202f2107718b29218bea59 ] Enforce using PS_MANUAL_POLL in ps hwsim debugfs to trigger a poll, only if PS_ENABLED was set before. This is required due to commit c9491367b759 ("mac80211: always update the PM state of a peer on MGMT / DATA frames") that enforces the ap to check only mgmt/data frames ps bit, and then update station's power save accordingly. When sending only ps-poll (control frame) the ap will not be aware that the station entered power save. Setting ps enable before triggering ps_poll, will send NDP with PM bit enabled first. Signed-off-by: Adiel Aloni Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mac80211_hwsim.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 3757036af93e..4182c3775a72 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -728,16 +728,21 @@ static int hwsim_fops_ps_write(void *dat, u64 val) val != PS_MANUAL_POLL) return -EINVAL; - old_ps = data->ps; - data->ps = val; - - local_bh_disable(); if (val == PS_MANUAL_POLL) { + if (data->ps != PS_ENABLED) + return -EINVAL; + local_bh_disable(); ieee80211_iterate_active_interfaces_atomic( data->hw, IEEE80211_IFACE_ITER_NORMAL, hwsim_send_ps_poll, data); - data->ps_poll_pending = true; - } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { + local_bh_enable(); + return 0; + } + old_ps = data->ps; + data->ps = val; + + local_bh_disable(); + if (old_ps == PS_DISABLED && val != PS_DISABLED) { ieee80211_iterate_active_interfaces_atomic( data->hw, IEEE80211_IFACE_ITER_NORMAL, hwsim_send_nullfunc_ps, data); -- GitLab From c1ad3ae74614d08336cb15bce8e16bf0ed9ccc6b Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Sun, 29 Oct 2017 11:51:10 +0200 Subject: [PATCH 0542/1834] mac80211: remove BUG() when interface type is invalid [ Upstream commit c7976f5272486e4ff406014c4b43e2fa3b70b052 ] In the ieee80211_setup_sdata() we check if the interface type is valid and, if not, call BUG(). This should never happen, but if there is something wrong with the code, it will not be caught until the bug happens when an interface is being set up. Calling BUG() is too extreme for this and a WARN_ON() would be better used instead. Change that. Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/iface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index a7aa54f45e19..fa7d757fef95 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1520,7 +1520,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, break; case NL80211_IFTYPE_UNSPECIFIED: case NUM_NL80211_IFTYPES: - BUG(); + WARN_ON(1); break; } -- GitLab From 67f62d6ea4fc64a8f1460639233d240cedb711ff Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 9 Dec 2017 14:52:28 +0300 Subject: [PATCH 0543/1834] ASoC: nuc900: Fix a loop timeout test [ Upstream commit 65a12b3aafed5fc59f4ce41b22b752b1729e6701 ] We should be finishing the loop with timeout set to zero but because this is a post-op we finish with timeout == -1. Fixes: 1082e2703a2d ("ASoC: NUC900/audio: add nuc900 audio driver support") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/nuc900/nuc900-ac97.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index b6615affe571..fde974d52bb2 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c @@ -67,7 +67,7 @@ static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97, /* polling the AC_R_FINISH */ while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH) - && timeout--) + && --timeout) mdelay(1); if (!timeout) { @@ -121,7 +121,7 @@ static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg, /* polling the AC_W_FINISH */ while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH) - && timeout--) + && --timeout) mdelay(1); if (!timeout) -- GitLab From 283b46fcece41113f4b11cde33d86e336db4bde6 Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Thu, 7 Dec 2017 15:15:43 -0800 Subject: [PATCH 0544/1834] ipvlan: add L2 check for packets arriving via virtual devices [ Upstream commit 92ff42645028fa6f9b8aa767718457b9264316b4 ] Packets that don't have dest mac as the mac of the master device should not be entertained by the IPvlan rx-handler. This is mostly true as the packet path mostly takes care of that, except when the master device is a virtual device. As demonstrated in the following case - ip netns add ns1 ip link add ve1 type veth peer name ve2 ip link add link ve2 name iv1 type ipvlan mode l2 ip link set dev iv1 netns ns1 ip link set ve1 up ip link set ve2 up ip -n ns1 link set iv1 up ip addr add 192.168.10.1/24 dev ve1 ip -n ns1 addr 192.168.10.2/24 dev iv1 ping -c2 192.168.10.2 ip neigh show dev ve1 ip neigh show 192.168.10.2 lladdr dev ve1 ping -c2 192.168.10.2 This patch adds that missing check in the IPvlan rx-handler. Reported-by: Amit Sikka Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ipvlan/ipvlan_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 627eb825eb74..c747ab652665 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -299,6 +299,10 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb, if (dev_forward_skb(ipvlan->dev, skb) == NET_RX_SUCCESS) success = true; } else { + if (!ether_addr_equal_64bits(eth_hdr(skb)->h_dest, + ipvlan->phy_dev->dev_addr)) + skb->pkt_type = PACKET_OTHERHOST; + ret = RX_HANDLER_ANOTHER; success = true; } -- GitLab From 992cfe9506d42ed7deff2bd09fe522c97179240a Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Fri, 3 Nov 2017 19:17:20 +0900 Subject: [PATCH 0545/1834] rcutorture/configinit: Fix build directory error message [ Upstream commit 2adfa4210f8f35cdfb4e08318cc06b99752964c2 ] The 'configinit.sh' script checks the format of optional argument for the build directory, printing an error message if the format is not valid. However, the error message uses the wrong variable, indicating an empty string even though the user entered a non-empty (but erroneous) string. This commit fixes the script to use the correct variable. Fixes: c87b9c601ac8 ("rcutorture: Add KVM-based test framework") Signed-off-by: SeongJae Park Signed-off-by: Paul E. McKenney Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/rcutorture/bin/configinit.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/rcutorture/bin/configinit.sh b/tools/testing/selftests/rcutorture/bin/configinit.sh index 3f81a1095206..50a6371b2b2e 100755 --- a/tools/testing/selftests/rcutorture/bin/configinit.sh +++ b/tools/testing/selftests/rcutorture/bin/configinit.sh @@ -51,7 +51,7 @@ then mkdir $builddir fi else - echo Bad build directory: \"$builddir\" + echo Bad build directory: \"$buildloc\" exit 2 fi fi -- GitLab From ad11afd59d4c3308aeb61c7d61caa77875fa9bda Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Mon, 15 May 2017 02:07:23 -0700 Subject: [PATCH 0546/1834] locking/locktorture: Fix num reader/writer corner cases [ Upstream commit 2ce77d16db4240dd2e422fc0a5c26d3e2ec03446 ] Things can explode for locktorture if the user does combinations of nwriters_stress=0 nreaders_stress=0. Fix this by not assuming we always want to torture writer threads. Reported-by: Jeremy Linton Signed-off-by: Davidlohr Bueso Signed-off-by: Paul E. McKenney Reviewed-by: Jeremy Linton Tested-by: Jeremy Linton Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/locking/locktorture.c | 76 +++++++++++++++++++++--------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c index d3de04b12f8c..babc67cfed69 100644 --- a/kernel/locking/locktorture.c +++ b/kernel/locking/locktorture.c @@ -641,8 +641,7 @@ static void __torture_print_stats(char *page, { bool fail = 0; int i, n_stress; - long max = 0; - long min = statp[0].n_lock_acquired; + long max = 0, min = statp ? statp[0].n_lock_acquired : 0; long long sum = 0; n_stress = write ? cxt.nrealwriters_stress : cxt.nrealreaders_stress; @@ -749,7 +748,7 @@ static void lock_torture_cleanup(void) * such, only perform the underlying torture-specific cleanups, * and avoid anything related to locktorture. */ - if (!cxt.lwsa) + if (!cxt.lwsa && !cxt.lrsa) goto end; if (writer_tasks) { @@ -823,6 +822,13 @@ static int __init lock_torture_init(void) firsterr = -EINVAL; goto unwind; } + + if (nwriters_stress == 0 && nreaders_stress == 0) { + pr_alert("lock-torture: must run at least one locking thread\n"); + firsterr = -EINVAL; + goto unwind; + } + if (cxt.cur_ops->init) cxt.cur_ops->init(); @@ -846,17 +852,19 @@ static int __init lock_torture_init(void) #endif /* Initialize the statistics so that each run gets its own numbers. */ + if (nwriters_stress) { + lock_is_write_held = 0; + cxt.lwsa = kmalloc(sizeof(*cxt.lwsa) * cxt.nrealwriters_stress, GFP_KERNEL); + if (cxt.lwsa == NULL) { + VERBOSE_TOROUT_STRING("cxt.lwsa: Out of memory"); + firsterr = -ENOMEM; + goto unwind; + } - lock_is_write_held = 0; - cxt.lwsa = kmalloc(sizeof(*cxt.lwsa) * cxt.nrealwriters_stress, GFP_KERNEL); - if (cxt.lwsa == NULL) { - VERBOSE_TOROUT_STRING("cxt.lwsa: Out of memory"); - firsterr = -ENOMEM; - goto unwind; - } - for (i = 0; i < cxt.nrealwriters_stress; i++) { - cxt.lwsa[i].n_lock_fail = 0; - cxt.lwsa[i].n_lock_acquired = 0; + for (i = 0; i < cxt.nrealwriters_stress; i++) { + cxt.lwsa[i].n_lock_fail = 0; + cxt.lwsa[i].n_lock_acquired = 0; + } } if (cxt.cur_ops->readlock) { @@ -873,19 +881,21 @@ static int __init lock_torture_init(void) cxt.nrealreaders_stress = cxt.nrealwriters_stress; } - lock_is_read_held = 0; - cxt.lrsa = kmalloc(sizeof(*cxt.lrsa) * cxt.nrealreaders_stress, GFP_KERNEL); - if (cxt.lrsa == NULL) { - VERBOSE_TOROUT_STRING("cxt.lrsa: Out of memory"); - firsterr = -ENOMEM; - kfree(cxt.lwsa); - cxt.lwsa = NULL; - goto unwind; - } - - for (i = 0; i < cxt.nrealreaders_stress; i++) { - cxt.lrsa[i].n_lock_fail = 0; - cxt.lrsa[i].n_lock_acquired = 0; + if (nreaders_stress) { + lock_is_read_held = 0; + cxt.lrsa = kmalloc(sizeof(*cxt.lrsa) * cxt.nrealreaders_stress, GFP_KERNEL); + if (cxt.lrsa == NULL) { + VERBOSE_TOROUT_STRING("cxt.lrsa: Out of memory"); + firsterr = -ENOMEM; + kfree(cxt.lwsa); + cxt.lwsa = NULL; + goto unwind; + } + + for (i = 0; i < cxt.nrealreaders_stress; i++) { + cxt.lrsa[i].n_lock_fail = 0; + cxt.lrsa[i].n_lock_acquired = 0; + } } } @@ -915,12 +925,14 @@ static int __init lock_torture_init(void) goto unwind; } - writer_tasks = kzalloc(cxt.nrealwriters_stress * sizeof(writer_tasks[0]), - GFP_KERNEL); - if (writer_tasks == NULL) { - VERBOSE_TOROUT_ERRSTRING("writer_tasks: Out of memory"); - firsterr = -ENOMEM; - goto unwind; + if (nwriters_stress) { + writer_tasks = kzalloc(cxt.nrealwriters_stress * sizeof(writer_tasks[0]), + GFP_KERNEL); + if (writer_tasks == NULL) { + VERBOSE_TOROUT_ERRSTRING("writer_tasks: Out of memory"); + firsterr = -ENOMEM; + goto unwind; + } } if (cxt.cur_ops->readlock) { -- GitLab From 27a0856c212bd6a741bf058f3e5aed6964feba87 Mon Sep 17 00:00:00 2001 From: Mimi Zohar Date: Wed, 8 Nov 2017 07:38:28 -0500 Subject: [PATCH 0547/1834] ima: relax requiring a file signature for new files with zero length [ Upstream commit b7e27bc1d42e8e0cc58b602b529c25cd0071b336 ] Custom policies can require file signatures based on LSM labels. These files are normally created and only afterwards labeled, requiring them to be signed. Instead of requiring file signatures based on LSM labels, entire filesystems could require file signatures. In this case, we need the ability of writing new files without requiring file signatures. The definition of a "new" file was originally defined as any file with a length of zero. Subsequent patches redefined a "new" file to be based on the FILE_CREATE open flag. By combining the open flag with a file size of zero, this patch relaxes the file signature requirement. Fixes: 1ac202e978e1 ima: accept previously set IMA_NEW_FILE Signed-off-by: Mimi Zohar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- security/integrity/ima/ima_appraise.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 6830d2427e47..7bf8b005a178 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c @@ -207,7 +207,8 @@ int ima_appraise_measurement(enum ima_hooks func, if (opened & FILE_CREATED) iint->flags |= IMA_NEW_FILE; if ((iint->flags & IMA_NEW_FILE) && - !(iint->flags & IMA_DIGSIG_REQUIRED)) + (!(iint->flags & IMA_DIGSIG_REQUIRED) || + (inode->i_size == 0))) status = INTEGRITY_PASS; goto out; } -- GitLab From 691ac858a381049c3e49d4a84b4d0fa8a1cad201 Mon Sep 17 00:00:00 2001 From: Salil Date: Sat, 1 Apr 2017 12:03:48 +0100 Subject: [PATCH 0548/1834] net: hns: Some checkpatch.pl script & warning fixes commit b4957ab0826f6f7efdfdc648521e1c4c3fc6ceda upstream. This patch fixes some checkpatch.pl script caught errors and warnings during the compilation time. [ backported to 4.9.y to fix build warnings caused by the backporting of 64ec10dc2ab8 ("net: hns: Correct HNS RSS key set function") by Sasha - gregkh] Signed-off-by: Salil Mehta Signed-off-by: David S. Miller Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 11 +++++------ drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c | 1 - drivers/net/ethernet/hisilicon/hns/hns_enet.c | 5 +++-- drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 1 - 5 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index 1e1eb92998fb..02a03bccde7b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -86,12 +86,11 @@ static void hns_gmac_disable(void *mac_drv, enum mac_commom_mode mode) dsaf_set_dev_bit(drv, GMAC_PORT_EN_REG, GMAC_PORT_RX_EN_B, 0); } -/** -*hns_gmac_get_en - get port enable -*@mac_drv:mac device -*@rx:rx enable -*@tx:tx enable -*/ +/* hns_gmac_get_en - get port enable + * @mac_drv:mac device + * @rx:rx enable + * @tx:tx enable + */ static void hns_gmac_get_en(void *mac_drv, u32 *rx, u32 *tx) { struct mac_driver *drv = (struct mac_driver *)mac_drv; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h index c494fc52be74..62a12991ce9a 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.h @@ -70,7 +70,7 @@ enum dsaf_roce_qos_sl { }; #define DSAF_STATS_READ(p, offset) (*((u64 *)((u8 *)(p) + (offset)))) -#define HNS_DSAF_IS_DEBUG(dev) (dev->dsaf_mode == DSAF_MODE_DISABLE_SP) +#define HNS_DSAF_IS_DEBUG(dev) ((dev)->dsaf_mode == DSAF_MODE_DISABLE_SP) enum hal_dsaf_mode { HRD_DSAF_NO_DSAF_MODE = 0x0, diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index f0ed80d6ef9c..f3be9ac47bfb 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -430,7 +430,6 @@ static void hns_rcb_ring_pair_get_cfg(struct ring_pair_cb *ring_pair_cb) static int hns_rcb_get_port_in_comm( struct rcb_common_cb *rcb_common, int ring_idx) { - return ring_idx / (rcb_common->max_q_per_vf * rcb_common->max_vfn); } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index c06845b7b666..a79e0a1100aa 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -511,7 +511,8 @@ static void hns_nic_reuse_page(struct sk_buff *skb, int i, int last_offset; bool twobufs; - twobufs = ((PAGE_SIZE < 8192) && hnae_buf_size(ring) == HNS_BUFFER_SIZE_2048); + twobufs = ((PAGE_SIZE < 8192) && + hnae_buf_size(ring) == HNS_BUFFER_SIZE_2048); desc = &ring->desc[ring->next_to_clean]; size = le16_to_cpu(desc->rx.size); @@ -1700,7 +1701,7 @@ static void hns_nic_reset_subtask(struct hns_nic_priv *priv) static void hns_nic_service_event_complete(struct hns_nic_priv *priv) { WARN_ON(!test_bit(NIC_STATE_SERVICE_SCHED, &priv->state)); - + /* make sure to commit the things */ smp_mb__before_atomic(); clear_bit(NIC_STATE_SERVICE_SCHED, &priv->state); } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 8490cba230bd..86a496d71995 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -1243,7 +1243,6 @@ hns_set_rss(struct net_device *netdev, const u32 *indir, const u8 *key, { struct hns_nic_priv *priv = netdev_priv(netdev); struct hnae_ae_ops *ops; - int ret; if (AE_IS_VER1(priv->enet_ver)) { netdev_err(netdev, -- GitLab From 60845c87579a51a186868c7a42dd390a10840434 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Mon, 8 May 2017 17:09:10 -0700 Subject: [PATCH 0549/1834] x86/boot/32: Fix UP boot on Quark and possibly other platforms commit d2b6dc61a8dd3c429609b993778cb54e75a5c5f0 upstream. This partially reverts commit: 23b2a4ddebdd17f ("x86/boot/32: Defer resyncing initial_page_table until per-cpu is set up") That commit had one definite bug and one potential bug. The definite bug is that setup_per_cpu_areas() uses a differnet generic implementation on UP kernels, so initial_page_table never got resynced. This was fine for access to percpu data (it's in the identity map on UP), but it breaks other users of initial_page_table. The potential bug is that helpers like efi_init() would be called before the tables were synced. Avoid both problems by just syncing the page tables in setup_arch() *and* setup_per_cpu_areas(). Reported-by: Jan Kiszka Signed-off-by: Andy Lutomirski Cc: Andy Shevchenko Cc: Ard Biesheuvel Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: Josh Poimboeuf Cc: Juergen Gross Cc: Linus Torvalds Cc: Matt Fleming Cc: Peter Zijlstra Cc: Thomas Garnier Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/setup.c | 15 +++++++++++++++ arch/x86/kernel/setup_percpu.c | 10 +++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d1a214287fe3..6b55012d02a3 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1200,6 +1200,21 @@ void __init setup_arch(char **cmdline_p) kasan_init(); +#ifdef CONFIG_X86_32 + /* sync back kernel address range */ + clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + KERNEL_PGD_PTRS); + + /* + * sync back low identity map too. It is used for example + * in the 32-bit EFI stub. + */ + clone_pgd_range(initial_page_table, + swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); +#endif + tboot_probe(); map_vsyscall(); diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index bbba27269fdd..f9da471a7707 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -290,11 +290,11 @@ void __init setup_per_cpu_areas(void) #ifdef CONFIG_X86_32 /* - * Sync back kernel address range. We want to make sure that - * all kernel mappings, including percpu mappings, are available - * in the smpboot asm. We can't reliably pick up percpu - * mappings using vmalloc_fault(), because exception dispatch - * needs percpu data. + * Sync back kernel address range again. We already did this in + * setup_arch(), but percpu data also needs to be available in + * the smpboot asm. We can't reliably pick up percpu mappings + * using vmalloc_fault(), because exception dispatch needs + * percpu data. */ clone_pgd_range(initial_page_table + KERNEL_PGD_BOUNDARY, swapper_pg_dir + KERNEL_PGD_BOUNDARY, -- GitLab From aa9c22f8ea24c509c705ace6ab905d76d866528c Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Mon, 5 Mar 2018 19:25:51 +0300 Subject: [PATCH 0550/1834] x86/cpufeatures: Add Intel PCONFIG cpufeature commit 7958b2246fadf54b7ff820a2a5a2c5ca1554716f upstream. CPUID.0x7.0x0:EDX[18] indicates whether Intel CPU support PCONFIG instruction. Signed-off-by: Kirill A. Shutemov Cc: Dave Hansen Cc: Kai Huang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Tom Lendacky Cc: linux-mm@kvack.org Link: http://lkml.kernel.org/r/20180305162610.37510-4-kirill.shutemov@linux.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/cpufeatures.h | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h index ed7a1d2c4235..a2485311164b 100644 --- a/arch/x86/include/asm/cpufeatures.h +++ b/arch/x86/include/asm/cpufeatures.h @@ -302,6 +302,7 @@ /* Intel-defined CPU features, CPUID level 0x00000007:0 (EDX), word 18 */ #define X86_FEATURE_AVX512_4VNNIW (18*32+ 2) /* AVX-512 Neural Network Instructions */ #define X86_FEATURE_AVX512_4FMAPS (18*32+ 3) /* AVX-512 Multiply Accumulation Single precision */ +#define X86_FEATURE_PCONFIG (18*32+18) /* Intel PCONFIG */ #define X86_FEATURE_SPEC_CTRL (18*32+26) /* "" Speculation Control (IBRS + IBPB) */ #define X86_FEATURE_INTEL_STIBP (18*32+27) /* "" Single Thread Indirect Branch Predictors */ #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */ -- GitLab From 940bdec8b13bf018bd530292cf276c103c568fa7 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 13 Mar 2018 22:03:10 -0700 Subject: [PATCH 0551/1834] selftests/x86/entry_from_vm86: Exit with 1 if we fail commit 327d53d005ca47b10eae940616ed11c569f75a9b upstream. Fix a logic error that caused the test to exit with 0 even if test cases failed. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stas Sergeev Cc: Thomas Gleixner Cc: bartoldeman@gmail.com Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/b1cc37144038958a469c8f70a5f47a6a5638636a.1521003603.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/entry_from_vm86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index d075ea0e5ca1..1bf81c5a819e 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -231,7 +231,7 @@ int main(void) clearhandler(SIGSEGV); /* Make sure nothing explodes if we fork. */ - if (fork() > 0) + if (fork() == 0) return 0; return (nerrs == 0 ? 0 : 1); -- GitLab From 497f33ae317cc6f77e7cb69670e3ef433cf94bcf Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Sun, 5 Nov 2017 18:27:56 -0800 Subject: [PATCH 0552/1834] selftests/x86: Add tests for User-Mode Instruction Prevention commit 9390afebe1d3f5a0be18b1afdd0ce09d67cebf9e upstream. Certain user space programs that run on virtual-8086 mode may utilize instructions protected by the User-Mode Instruction Prevention (UMIP) security feature present in new Intel processors: SGDT, SIDT and SMSW. In such a case, a general protection fault is issued if UMIP is enabled. When such a fault happens, the kernel traps it and emulates the results of these instructions with dummy values. The purpose of this new test is to verify whether the impacted instructions can be executed without causing such #GP. If no #GP exceptions occur, we expect to exit virtual-8086 mode from INT3. The instructions protected by UMIP are executed in representative use cases: a) displacement-only memory addressing b) register-indirect memory addressing c) results stored directly in operands Unfortunately, it is not possible to check the results against a set of expected values because no emulation will occur in systems that do not have the UMIP feature. Instead, results are printed for verification. A simple verification is done to ensure that results of all tests are identical. Signed-off-by: Ricardo Neri Reviewed-by: Thomas Gleixner Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Chen Yucong Cc: Chris Metcalf Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Huang Rui Cc: Jiri Slaby Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Paul Gortmaker Cc: Peter Zijlstra Cc: Ravi V. Shankar Cc: Shuah Khan Cc: Tony Luck Cc: Vlastimil Babka Cc: ricardo.neri@intel.com Link: http://lkml.kernel.org/r/1509935277-22138-12-git-send-email-ricardo.neri-calderon@linux.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/entry_from_vm86.c | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 1bf81c5a819e..881be02f3fab 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -95,6 +95,22 @@ asm ( "int3\n\t" "vmcode_int80:\n\t" "int $0x80\n\t" + "vmcode_umip:\n\t" + /* addressing via displacements */ + "smsw (2052)\n\t" + "sidt (2054)\n\t" + "sgdt (2060)\n\t" + /* addressing via registers */ + "mov $2066, %bx\n\t" + "smsw (%bx)\n\t" + "mov $2068, %bx\n\t" + "sidt (%bx)\n\t" + "mov $2074, %bx\n\t" + "sgdt (%bx)\n\t" + /* register operands, only for smsw */ + "smsw %ax\n\t" + "mov %ax, (2080)\n\t" + "int3\n\t" ".size vmcode, . - vmcode\n\t" "end_vmcode:\n\t" ".code32\n\t" @@ -103,7 +119,7 @@ asm ( extern unsigned char vmcode[], end_vmcode[]; extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], - vmcode_sti[], vmcode_int3[], vmcode_int80[]; + vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[]; /* Returns false if the test was skipped. */ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, @@ -160,6 +176,58 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, return true; } +void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem) +{ + struct table_desc { + unsigned short limit; + unsigned long base; + } __attribute__((packed)); + + /* Initialize variables with arbitrary values */ + struct table_desc gdt1 = { .base = 0x3c3c3c3c, .limit = 0x9999 }; + struct table_desc gdt2 = { .base = 0x1a1a1a1a, .limit = 0xaeae }; + struct table_desc idt1 = { .base = 0x7b7b7b7b, .limit = 0xf1f1 }; + struct table_desc idt2 = { .base = 0x89898989, .limit = 0x1313 }; + unsigned short msw1 = 0x1414, msw2 = 0x2525, msw3 = 3737; + + /* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */ + do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests"); + + /* Results from displacement-only addressing */ + msw1 = *(unsigned short *)(test_mem + 2052); + memcpy(&idt1, test_mem + 2054, sizeof(idt1)); + memcpy(&gdt1, test_mem + 2060, sizeof(gdt1)); + + /* Results from register-indirect addressing */ + msw2 = *(unsigned short *)(test_mem + 2066); + memcpy(&idt2, test_mem + 2068, sizeof(idt2)); + memcpy(&gdt2, test_mem + 2074, sizeof(gdt2)); + + /* Results when using register operands */ + msw3 = *(unsigned short *)(test_mem + 2080); + + printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1); + printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n", + idt1.limit, idt1.base); + printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n", + gdt1.limit, gdt1.base); + + if (msw1 != msw2 || msw1 != msw3) + printf("[FAIL]\tAll the results of SMSW should be the same.\n"); + else + printf("[PASS]\tAll the results from SMSW are identical.\n"); + + if (memcmp(&gdt1, &gdt2, sizeof(gdt1))) + printf("[FAIL]\tAll the results of SGDT should be the same.\n"); + else + printf("[PASS]\tAll the results from SGDT are identical.\n"); + + if (memcmp(&idt1, &idt2, sizeof(idt1))) + printf("[FAIL]\tAll the results of SIDT should be the same.\n"); + else + printf("[PASS]\tAll the results from SIDT are identical.\n"); +} + int main(void) { struct vm86plus_struct v86; @@ -218,6 +286,9 @@ int main(void) v86.regs.eax = (unsigned int)-1; do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80"); + /* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */ + do_umip_tests(&v86, addr); + /* Execute a null pointer */ v86.regs.cs = 0; v86.regs.ss = 0; -- GitLab From 028c1fadf4a98e344d268c0d01a8fbecef4d01f8 Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Sun, 5 Nov 2017 18:27:57 -0800 Subject: [PATCH 0553/1834] selftests/x86: Add tests for the STR and SLDT instructions commit a9e017d5619eb371460c8e516f4684def62bef3a upstream. The STR and SLDT instructions are not valid when running on virtual-8086 mode and generate an invalid operand exception. These two instructions are protected by the Intel User-Mode Instruction Prevention (UMIP) security feature. In protected mode, if UMIP is enabled, these instructions generate a general protection fault if called from CPL > 0. Linux traps the general protection fault and emulates the instructions sgdt, sidt and smsw; but not str and sldt. These tests are added to verify that the emulation code does not emulate these two instructions but the expected invalid operand exception is seen. Tests fallback to exit with INT3 in case emulation does happen. Signed-off-by: Ricardo Neri Reviewed-by: Thomas Gleixner Cc: Andrew Morton Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Borislav Petkov Cc: Brian Gerst Cc: Chen Yucong Cc: Chris Metcalf Cc: Dave Hansen Cc: Denys Vlasenko Cc: Fenghua Yu Cc: H. Peter Anvin Cc: Huang Rui Cc: Jiri Slaby Cc: Jonathan Corbet Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Masami Hiramatsu Cc: Michael S. Tsirkin Cc: Paolo Bonzini Cc: Paul Gortmaker Cc: Peter Zijlstra Cc: Ravi V. Shankar Cc: Shuah Khan Cc: Tony Luck Cc: Vlastimil Babka Cc: ricardo.neri@intel.com Link: http://lkml.kernel.org/r/1509935277-22138-13-git-send-email-ricardo.neri-calderon@linux.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/entry_from_vm86.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 881be02f3fab..6e85f0d0498d 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -111,6 +111,11 @@ asm ( "smsw %ax\n\t" "mov %ax, (2080)\n\t" "int3\n\t" + "vmcode_umip_str:\n\t" + "str %eax\n\t" + "vmcode_umip_sldt:\n\t" + "sldt %eax\n\t" + "int3\n\t" ".size vmcode, . - vmcode\n\t" "end_vmcode:\n\t" ".code32\n\t" @@ -119,7 +124,8 @@ asm ( extern unsigned char vmcode[], end_vmcode[]; extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], - vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[]; + vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[], + vmcode_umip_str[], vmcode_umip_sldt[]; /* Returns false if the test was skipped. */ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, @@ -226,6 +232,16 @@ void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem) printf("[FAIL]\tAll the results of SIDT should be the same.\n"); else printf("[PASS]\tAll the results from SIDT are identical.\n"); + + sethandler(SIGILL, sighandler, 0); + do_test(vm86, vmcode_umip_str - vmcode, VM86_SIGNAL, 0, + "STR instruction"); + clearhandler(SIGILL); + + sethandler(SIGILL, sighandler, 0); + do_test(vm86, vmcode_umip_sldt - vmcode, VM86_SIGNAL, 0, + "SLDT instruction"); + clearhandler(SIGILL); } int main(void) -- GitLab From 403e064ebc48ce3a5fea28ab904d0780a18f168e Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 13 Mar 2018 22:03:11 -0700 Subject: [PATCH 0554/1834] selftests/x86/entry_from_vm86: Add test cases for POPF commit 78393fdde2a456cafa414b171c90f26a3df98b20 upstream. POPF is currently broken -- add tests to catch the error. This results in: [RUN] POPF with VIP set and IF clear from vm86 mode [INFO] Exited vm86 mode due to STI [FAIL] Incorrect return reason (started at eip = 0xd, ended at eip = 0xf) because POPF currently fails to check IF before reporting a pending interrupt. This patch also makes the FAIL message a bit more informative. Reported-by: Bart Oldeman Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stas Sergeev Cc: Thomas Gleixner Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/a16270b5cfe7832d6d00c479d0f871066cbdb52b.1521003603.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/entry_from_vm86.c | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 6e85f0d0498d..ade443a88421 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -95,6 +95,10 @@ asm ( "int3\n\t" "vmcode_int80:\n\t" "int $0x80\n\t" + "vmcode_popf_hlt:\n\t" + "push %ax\n\t" + "popf\n\t" + "hlt\n\t" "vmcode_umip:\n\t" /* addressing via displacements */ "smsw (2052)\n\t" @@ -124,8 +128,8 @@ asm ( extern unsigned char vmcode[], end_vmcode[]; extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], - vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[], - vmcode_umip_str[], vmcode_umip_sldt[]; + vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_popf_hlt[], + vmcode_umip[], vmcode_umip_str[], vmcode_umip_sldt[]; /* Returns false if the test was skipped. */ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, @@ -175,7 +179,7 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, (VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) { printf("[OK]\tReturned correctly\n"); } else { - printf("[FAIL]\tIncorrect return reason\n"); + printf("[FAIL]\tIncorrect return reason (started at eip = 0x%lx, ended at eip = 0x%lx)\n", eip, v86->regs.eip); nerrs++; } @@ -264,6 +268,9 @@ int main(void) v86.regs.ds = load_addr / 16; v86.regs.es = load_addr / 16; + /* Use the end of the page as our stack. */ + v86.regs.esp = 4096; + assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */ /* #BR -- should deliver SIG??? */ @@ -295,6 +302,23 @@ int main(void) v86.regs.eflags &= ~X86_EFLAGS_IF; do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set"); + /* POPF with VIP set but IF clear: should not trap */ + v86.regs.eflags = X86_EFLAGS_VIP; + v86.regs.eax = 0; + do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP set and IF clear"); + + /* POPF with VIP set and IF set: should trap */ + v86.regs.eflags = X86_EFLAGS_VIP; + v86.regs.eax = X86_EFLAGS_IF; + do_test(&v86, vmcode_popf_hlt - vmcode, VM86_STI, 0, "POPF with VIP and IF set"); + + /* POPF with VIP clear and IF set: should not trap */ + v86.regs.eflags = 0; + v86.regs.eax = X86_EFLAGS_IF; + do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP clear and IF set"); + + v86.regs.eflags = 0; + /* INT3 -- should cause #BP */ do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3"); -- GitLab From 990a63c518ff4d7b670a3ef276ec4029aabaca19 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 13 Mar 2018 22:03:12 -0700 Subject: [PATCH 0555/1834] x86/vm86/32: Fix POPF emulation commit b5069782453459f6ec1fdeb495d9901a4545fcb5 upstream. POPF would trap if VIP was set regardless of whether IF was set. Fix it. Suggested-by: Stas Sergeev Reported-by: Bart Oldeman Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org Fixes: 5ed92a8ab71f ("x86/vm86: Use the normal pt_regs area for vm86") Link: http://lkml.kernel.org/r/ce95f40556e7b2178b6bc06ee9557827ff94bd28.1521003603.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/vm86_32.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 8a1d63591399..961831bf74b1 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -719,7 +719,8 @@ void handle_vm86_fault(struct kernel_vm86_regs *regs, long error_code) return; check_vip: - if (VEFLAGS & X86_EFLAGS_VIP) { + if ((VEFLAGS & (X86_EFLAGS_VIP | X86_EFLAGS_VIF)) == + (X86_EFLAGS_VIP | X86_EFLAGS_VIF)) { save_v86_state(regs, VM86_STI); return; } -- GitLab From a999c6095e73377b2b513437707a7a2a53d101ff Mon Sep 17 00:00:00 2001 From: Andy Whitcroft Date: Wed, 14 Mar 2018 11:24:27 +0000 Subject: [PATCH 0556/1834] x86/speculation, objtool: Annotate indirect calls/jumps for objtool on 32-bit kernels commit a14bff131108faf50cc0cf864589fd71ee216c96 upstream. In the following commit: 9e0e3c5130e9 ("x86/speculation, objtool: Annotate indirect calls/jumps for objtool") ... we added annotations for CALL_NOSPEC/JMP_NOSPEC on 64-bit x86 kernels, but we did not annotate the 32-bit path. Annotate it similarly. Signed-off-by: Andy Whitcroft Acked-by: Peter Zijlstra (Intel) Cc: Andy Lutomirski Cc: Arjan van de Ven Cc: Borislav Petkov Cc: Dan Williams Cc: Dave Hansen Cc: David Woodhouse Cc: David Woodhouse Cc: Greg Kroah-Hartman Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20180314112427.22351-1-apw@canonical.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/nospec-branch.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index d0dabeae0505..f928ad9b143f 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -183,7 +183,10 @@ * otherwise we'll run out of registers. We don't care about CET * here, anyway. */ -# define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n", \ +# define CALL_NOSPEC \ + ALTERNATIVE( \ + ANNOTATE_RETPOLINE_SAFE \ + "call *%[thunk_target]\n", \ " jmp 904f;\n" \ " .align 16\n" \ "901: call 903f;\n" \ -- GitLab From ed82505913ccd47369fecb8fefb27abd32fb2e50 Mon Sep 17 00:00:00 2001 From: Alexander Sergeyev Date: Tue, 13 Mar 2018 22:38:56 +0300 Subject: [PATCH 0557/1834] x86/speculation: Remove Skylake C2 from Speculation Control microcode blacklist commit e3b3121fa8da94cb20f9e0c64ab7981ae47fd085 upstream. In accordance with Intel's microcode revision guidance from March 6 MCU rev 0xc2 is cleared on both Skylake H/S and Skylake Xeon E3 processors that share CPUID 506E3. Signed-off-by: Alexander Sergeyev Signed-off-by: Thomas Gleixner Cc: Jia Zhang Cc: Greg Kroah-Hartman Cc: Kyle Huey Cc: David Woodhouse Link: https://lkml.kernel.org/r/20180313193856.GA8580@localhost.localdomain Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/cpu/intel.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c index 768042530af2..8fb1d6522f8e 100644 --- a/arch/x86/kernel/cpu/intel.c +++ b/arch/x86/kernel/cpu/intel.c @@ -64,7 +64,7 @@ void check_mpx_erratum(struct cpuinfo_x86 *c) /* * Early microcode releases for the Spectre v2 mitigation were broken. * Information taken from; - * - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/01/microcode-update-guidance.pdf + * - https://newsroom.intel.com/wp-content/uploads/sites/11/2018/03/microcode-update-guidance.pdf * - https://kb.vmware.com/s/article/52345 * - Microcode revisions observed in the wild * - Release note from 20180108 microcode release @@ -82,7 +82,6 @@ static const struct sku_microcode spectre_bad_microcodes[] = { { INTEL_FAM6_KABYLAKE_MOBILE, 0x09, 0x80 }, { INTEL_FAM6_SKYLAKE_X, 0x03, 0x0100013e }, { INTEL_FAM6_SKYLAKE_X, 0x04, 0x0200003c }, - { INTEL_FAM6_SKYLAKE_DESKTOP, 0x03, 0xc2 }, { INTEL_FAM6_BROADWELL_CORE, 0x04, 0x28 }, { INTEL_FAM6_BROADWELL_GT3E, 0x01, 0x1b }, { INTEL_FAM6_BROADWELL_XEON_D, 0x02, 0x14 }, -- GitLab From d3b0e9891b1f85aa623f8b6f8205015fe394ac3a Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Tue, 13 Mar 2018 11:03:46 -0600 Subject: [PATCH 0558/1834] x86/mm: Fix vmalloc_fault to use pXd_large commit 18a955219bf7d9008ce480d4451b6b8bf4483a22 upstream. Gratian Crisan reported that vmalloc_fault() crashes when CONFIG_HUGETLBFS is not set since the function inadvertently uses pXn_huge(), which always return 0 in this case. ioremap() does not depend on CONFIG_HUGETLBFS. Fix vmalloc_fault() to call pXd_large() instead. Fixes: f4eafd8bcd52 ("x86/mm: Fix vmalloc_fault() to handle large pages properly") Reported-by: Gratian Crisan Signed-off-by: Toshi Kani Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Cc: linux-mm@kvack.org Cc: Borislav Petkov Cc: Andy Lutomirski Link: https://lkml.kernel.org/r/20180313170347.3829-2-toshi.kani@hpe.com Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/fault.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 74dea7f14c20..ae23c996e3a8 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -343,7 +343,7 @@ static noinline int vmalloc_fault(unsigned long address) if (!pmd_k) return -1; - if (pmd_huge(*pmd_k)) + if (pmd_large(*pmd_k)) return 0; pte_k = pte_offset_kernel(pmd_k, address); @@ -463,7 +463,7 @@ static noinline int vmalloc_fault(unsigned long address) if (pud_none(*pud) || pud_pfn(*pud) != pud_pfn(*pud_ref)) BUG(); - if (pud_huge(*pud)) + if (pud_large(*pud)) return 0; pmd = pmd_offset(pud, address); @@ -474,7 +474,7 @@ static noinline int vmalloc_fault(unsigned long address) if (pmd_none(*pmd) || pmd_pfn(*pmd) != pmd_pfn(*pmd_ref)) BUG(); - if (pmd_huge(*pmd)) + if (pmd_large(*pmd)) return 0; pte_ref = pte_offset_kernel(pmd_ref, address); -- GitLab From 8f6cfbea4e1621f078a08dfb2b444162ba2f7441 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Wed, 7 Mar 2018 08:18:05 -0500 Subject: [PATCH 0559/1834] parisc: Handle case where flush_cache_range is called with no context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 9ef0f88fe5466c2ca1d2975549ba6be502c464c1 upstream. Just when I had decided that flush_cache_range() was always called with a valid context, Helge reported two cases where the "BUG_ON(!vma->vm_mm->context);" was hit on the phantom buildd: kernel BUG at /mnt/sdb6/linux/linux-4.15.4/arch/parisc/kernel/cache.c:587! CPU: 1 PID: 3254 Comm: kworker/1:2 Tainted: G D 4.15.0-1-parisc64-smp #1 Debian 4.15.4-1+b1 Workqueue: events free_ioctx   IAOQ[0]: flush_cache_range+0x164/0x168   IAOQ[1]: flush_cache_page+0x0/0x1c8   RP(r2): unmap_page_range+0xae8/0xb88 Backtrace:   [<00000000404a6980>] unmap_page_range+0xae8/0xb88   [<00000000404a6ae0>] unmap_single_vma+0xc0/0x188   [<00000000404a6cdc>] zap_page_range_single+0x134/0x1f8   [<00000000404a702c>] unmap_mapping_range+0x1cc/0x208   [<0000000040461518>] truncate_pagecache+0x98/0x108   [<0000000040461624>] truncate_setsize+0x9c/0xb8   [<00000000405d7f30>] put_aio_ring_file+0x80/0x100   [<00000000405d803c>] aio_free_ring+0x8c/0x290   [<00000000405d82c0>] free_ioctx+0x80/0x180   [<0000000040284e6c>] process_one_work+0x21c/0x668   [<00000000402854c4>] worker_thread+0x20c/0x778   [<0000000040291d44>] kthread+0x2d4/0x2e0   [<0000000040204020>] end_fault_vector+0x20/0xc0 This indicates that we need to handle the no context case in flush_cache_range() as we do in flush_cache_mm(). In thinking about this, I realized that we don't need to flush the TLB when there is no context. So, I added context checks to the large flush cases in flush_cache_mm() and flush_cache_range(). The large flush case occurs frequently in flush_cache_mm() and the change should improve fork performance. The v2 version of this change removes the BUG_ON from flush_cache_page() by skipping the TLB flush when there is no context.  I also added code to flush the TLB in flush_cache_mm() and flush_cache_range() when we have a context that's not current.  Now all three routines handle TLB flushes in a similar manner. Signed-off-by: John David Anglin Cc: stable@vger.kernel.org # 4.9+ Signed-off-by: Helge Deller Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/cache.c | 41 +++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index 025afe5f17a7..8a0822125f8b 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -542,7 +542,8 @@ void flush_cache_mm(struct mm_struct *mm) rp3440, etc. So, avoid it if the mm isn't too big. */ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && mm_total_size(mm) >= parisc_cache_flush_threshold) { - flush_tlb_all(); + if (mm->context) + flush_tlb_all(); flush_cache_all(); return; } @@ -570,6 +571,8 @@ void flush_cache_mm(struct mm_struct *mm) pfn = pte_pfn(*ptep); if (!pfn_valid(pfn)) continue; + if (unlikely(mm->context)) + flush_tlb_page(vma, addr); __flush_cache_page(vma, addr, PFN_PHYS(pfn)); } } @@ -596,26 +599,46 @@ flush_user_icache_range(unsigned long start, unsigned long end) void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { + pgd_t *pgd; + unsigned long addr; + if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) && end - start >= parisc_cache_flush_threshold) { - flush_tlb_range(vma, start, end); + if (vma->vm_mm->context) + flush_tlb_range(vma, start, end); flush_cache_all(); return; } - flush_user_dcache_range_asm(start, end); - if (vma->vm_flags & VM_EXEC) - flush_user_icache_range_asm(start, end); - flush_tlb_range(vma, start, end); + if (vma->vm_mm->context == mfsp(3)) { + flush_user_dcache_range_asm(start, end); + if (vma->vm_flags & VM_EXEC) + flush_user_icache_range_asm(start, end); + flush_tlb_range(vma, start, end); + return; + } + + pgd = vma->vm_mm->pgd; + for (addr = vma->vm_start; addr < vma->vm_end; addr += PAGE_SIZE) { + unsigned long pfn; + pte_t *ptep = get_ptep(pgd, addr); + if (!ptep) + continue; + pfn = pte_pfn(*ptep); + if (pfn_valid(pfn)) { + if (unlikely(vma->vm_mm->context)) + flush_tlb_page(vma, addr); + __flush_cache_page(vma, addr, PFN_PHYS(pfn)); + } + } } void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn) { - BUG_ON(!vma->vm_mm->context); - if (pfn_valid(pfn)) { - flush_tlb_page(vma, vmaddr); + if (likely(vma->vm_mm->context)) + flush_tlb_page(vma, vmaddr); __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn)); } } -- GitLab From 238ba452eb4bbd6378f9d4857e0532a806b79013 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 10 Mar 2018 23:04:23 +0100 Subject: [PATCH 0560/1834] ALSA: pcm: Fix UAF in snd_pcm_oss_get_formats() commit 01c0b4265cc16bc1f43f475c5944c55c10d5768f upstream. snd_pcm_oss_get_formats() has an obvious use-after-free around snd_mask_test() calls, as spotted by syzbot. The passed format_mask argument is a pointer to the hw_params object that is freed before the loop. What a surprise that it has been present since the original code of decades ago... Reported-by: syzbot+4090700a4f13fccaf648@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 3321348fd86b..3e7c3573871d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1814,10 +1814,9 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) return -ENOMEM; _snd_pcm_hw_params_any(params); err = snd_pcm_hw_refine(substream, params); - format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - kfree(params); if (err < 0) - return err; + goto error; + format_mask = *hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); for (fmt = 0; fmt < 32; ++fmt) { if (snd_mask_test(&format_mask, fmt)) { int f = snd_pcm_oss_format_to(fmt); @@ -1825,7 +1824,10 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) formats |= f; } } - return formats; + + error: + kfree(params); + return err < 0 ? err : formats; } static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format) -- GitLab From 20cbd5198e28bf3ddb07f079b2ebe73cb68356bc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 12 Mar 2018 13:55:48 +0100 Subject: [PATCH 0561/1834] ALSA: hda - Revert power_save option default value commit 40088dc4e1ead7df31728c73f5b51d71da18831d upstream. With the commit 1ba8f9d30817 ("ALSA: hda: Add a power_save blacklist"), we changed the default value of power_save option to -1 for processing the power-save blacklist. Unfortunately, this seems breaking user-space applications that actually read the power_save parameter value via sysfs and judge / adjust the power-saving status. They see the value -1 as if the power-save is turned off, although the actual value is taken from CONFIG_SND_HDA_POWER_SAVE_DEFAULT and it can be a positive. So, overall, passing -1 there was no good idea. Let's partially revert it -- at least for power_save option default value is restored again to CONFIG_SND_HDA_POWER_SAVE_DEFAULT. Meanwhile, in this patch, we keep the blacklist behavior and make is adjustable via the new option, pm_blacklist. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199073 Fixes: 1ba8f9d30817 ("ALSA: hda: Add a power_save blacklist") Acked-by: Hans de Goede Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_intel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 688f3144d949..733b3423baa2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -180,11 +180,15 @@ static const struct kernel_param_ops param_ops_xint = { }; #define param_check_xint param_check_int -static int power_save = -1; +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; module_param(power_save, xint, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " "(in second, 0 = disable)."); +static bool pm_blacklist = true; +module_param(pm_blacklist, bool, 0644); +MODULE_PARM_DESC(pm_blacklist, "Enable power-management blacklist"); + /* reset the HD-audio controller in power save mode. * this may give more power-saving, but will take longer time to * wake up. @@ -2153,10 +2157,9 @@ static int azx_probe_continue(struct azx *chip) val = power_save; #ifdef CONFIG_PM - if (val == -1) { + if (pm_blacklist) { const struct snd_pci_quirk *q; - val = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; q = snd_pci_quirk_lookup(chip->pci, power_save_blacklist); if (q && val) { dev_info(chip->card->dev, "device %04x:%04x is on the power_save blacklist, forcing power_save to 0\n", -- GitLab From 1a3e9385ddf2e77d97b8bace4792a4b3a50797fd Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Mar 2018 21:58:28 +0100 Subject: [PATCH 0562/1834] ALSA: seq: Fix possible UAF in snd_seq_check_queue() commit d0f833065221cbfcbadf19fd4102bcfa9330006a upstream. Although we've covered the races between concurrent write() and ioctl() in the previous patch series, there is still a possible UAF in the following scenario: A: user client closed B: timer irq -> snd_seq_release() -> snd_seq_timer_interrupt() -> snd_seq_free_client() -> snd_seq_check_queue() -> cell = snd_seq_prioq_cell_peek() -> snd_seq_prioq_leave() .... removing all cells -> snd_seq_pool_done() .... vfree() -> snd_seq_compare_tick_time(cell) ... Oops So the problem is that a cell is peeked and accessed without any protection until it's retrieved from the queue again via snd_seq_prioq_cell_out(). This patch tries to address it, also cleans up the code by a slight refactoring. snd_seq_prioq_cell_out() now receives an extra pointer argument. When it's non-NULL, the function checks the event timestamp with the given pointer. The caller needs to pass the right reference either to snd_seq_tick or snd_seq_realtime depending on the event timestamp type. A good news is that the above change allows us to remove the snd_seq_prioq_cell_peek(), too, thus the patch actually reduces the code size. Reviewed-by: Nicolai Stange Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_prioq.c | 28 ++++++++++++++-------------- sound/core/seq/seq_prioq.h | 6 ++---- sound/core/seq/seq_queue.c | 28 +++++++++------------------- 3 files changed, 25 insertions(+), 37 deletions(-) diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index bc1c8488fc2a..2bc6759e4adc 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c @@ -87,7 +87,7 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo) if (f->cells > 0) { /* drain prioQ */ while (f->cells > 0) - snd_seq_cell_free(snd_seq_prioq_cell_out(f)); + snd_seq_cell_free(snd_seq_prioq_cell_out(f, NULL)); } kfree(f); @@ -214,8 +214,18 @@ int snd_seq_prioq_cell_in(struct snd_seq_prioq * f, return 0; } +/* return 1 if the current time >= event timestamp */ +static int event_is_ready(struct snd_seq_event *ev, void *current_time) +{ + if ((ev->flags & SNDRV_SEQ_TIME_STAMP_MASK) == SNDRV_SEQ_TIME_STAMP_TICK) + return snd_seq_compare_tick_time(current_time, &ev->time.tick); + else + return snd_seq_compare_real_time(current_time, &ev->time.time); +} + /* dequeue cell from prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f) +struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f, + void *current_time) { struct snd_seq_event_cell *cell; unsigned long flags; @@ -227,6 +237,8 @@ struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f) spin_lock_irqsave(&f->lock, flags); cell = f->head; + if (cell && current_time && !event_is_ready(&cell->event, current_time)) + cell = NULL; if (cell) { f->head = cell->next; @@ -252,18 +264,6 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f) return f->cells; } - -/* peek at cell at the head of the prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq * f) -{ - if (f == NULL) { - pr_debug("ALSA: seq: snd_seq_prioq_cell_in() called with NULL prioq\n"); - return NULL; - } - return f->head; -} - - static inline int prioq_match(struct snd_seq_event_cell *cell, int client, int timestamp) { diff --git a/sound/core/seq/seq_prioq.h b/sound/core/seq/seq_prioq.h index d38bb78d9345..2c315ca10fc4 100644 --- a/sound/core/seq/seq_prioq.h +++ b/sound/core/seq/seq_prioq.h @@ -44,14 +44,12 @@ void snd_seq_prioq_delete(struct snd_seq_prioq **fifo); int snd_seq_prioq_cell_in(struct snd_seq_prioq *f, struct snd_seq_event_cell *cell); /* dequeue cell from prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f); +struct snd_seq_event_cell *snd_seq_prioq_cell_out(struct snd_seq_prioq *f, + void *current_time); /* return number of events available in prioq */ int snd_seq_prioq_avail(struct snd_seq_prioq *f); -/* peek at cell at the head of the prioq */ -struct snd_seq_event_cell *snd_seq_prioq_cell_peek(struct snd_seq_prioq *f); - /* client left queue */ void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp); diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 79e0c5604ef8..1a6dc4ff44a6 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -277,30 +277,20 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop) __again: /* Process tick queue... */ - while ((cell = snd_seq_prioq_cell_peek(q->tickq)) != NULL) { - if (snd_seq_compare_tick_time(&q->timer->tick.cur_tick, - &cell->event.time.tick)) { - cell = snd_seq_prioq_cell_out(q->tickq); - if (cell) - snd_seq_dispatch_event(cell, atomic, hop); - } else { - /* event remains in the queue */ + for (;;) { + cell = snd_seq_prioq_cell_out(q->tickq, + &q->timer->tick.cur_tick); + if (!cell) break; - } + snd_seq_dispatch_event(cell, atomic, hop); } - /* Process time queue... */ - while ((cell = snd_seq_prioq_cell_peek(q->timeq)) != NULL) { - if (snd_seq_compare_real_time(&q->timer->cur_time, - &cell->event.time.time)) { - cell = snd_seq_prioq_cell_out(q->timeq); - if (cell) - snd_seq_dispatch_event(cell, atomic, hop); - } else { - /* event remains in the queue */ + for (;;) { + cell = snd_seq_prioq_cell_out(q->timeq, &q->timer->cur_time); + if (!cell) break; - } + snd_seq_dispatch_event(cell, atomic, hop); } /* free lock */ -- GitLab From c706deff725737d307a3ce149205ee9362d2e0c1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 9 Mar 2018 22:23:31 +0100 Subject: [PATCH 0563/1834] ALSA: seq: Clear client entry before deleting else at closing commit a2ff19f7b70118ced291a28d5313469914de451b upstream. When releasing a client, we need to clear the clienttab[] entry at first, then call snd_seq_queue_client_leave(). Otherwise, the in-flight cell in the queue might be picked up by the timer interrupt via snd_seq_check_queue() before calling snd_seq_queue_client_leave(), and it's delivered to another queue while the client is clearing queues. This may eventually result in an uncleared cell remaining in a queue, and the later snd_seq_pool_delete() may need to wait for a long time until the event gets really processed. By moving the clienttab[] clearance at the beginning of release, any event delivery of a cell belonging to this client will fail at a later point, since snd_seq_client_ptr() returns NULL. Thus the cell that was picked up by the timer interrupt will be returned immediately without further delivery, and the long stall of snd_seq_delete_pool() can be avoided, too. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/seq/seq_clientmgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 799ad3e1d24b..ecd1c5fc8db8 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -255,12 +255,12 @@ static int seq_free_client1(struct snd_seq_client *client) if (!client) return 0; - snd_seq_delete_all_ports(client); - snd_seq_queue_client_leave(client->number); spin_lock_irqsave(&clients_lock, flags); clienttablock[client->number] = 1; clienttab[client->number] = NULL; spin_unlock_irqrestore(&clients_lock, flags); + snd_seq_delete_all_ports(client); + snd_seq_queue_client_leave(client->number); snd_use_lock_sync(&client->use_lock); snd_seq_queue_client_termination(client->number); if (client->pool) -- GitLab From 0ca43b0aa033dc7240f8e94d01fa69cb16c89cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 9 Mar 2018 14:42:54 +0100 Subject: [PATCH 0564/1834] drm/amdgpu: fix prime teardown order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 342038d92403b3efa1138a8599666b9f026279d6 upstream. We unmapped imported DMA-bufs when the GEM handle was dropped, not when the hardware was done with the buffere. Signed-off-by: Christian König Reviewed-by: Michel Dänzer CC: stable@vger.kernel.org Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 2 -- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index a7ea9a3b454e..d5e4748e3300 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -36,8 +36,6 @@ void amdgpu_gem_object_free(struct drm_gem_object *gobj) struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj); if (robj) { - if (robj->gem_base.import_attach) - drm_prime_gem_destroy(&robj->gem_base, robj->tbo.sg); amdgpu_mn_unregister(robj); amdgpu_bo_unref(&robj); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index f3efb1c5dae9..5afe72778518 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -94,6 +94,8 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo) amdgpu_update_memory_usage(bo->adev, &bo->tbo.mem, NULL); + if (bo->gem_base.import_attach) + drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg); drm_gem_object_release(&bo->gem_base); amdgpu_bo_unref(&bo->parent); if (!list_empty(&bo->shadow_list)) { -- GitLab From 16c809b7daebfbd8a547d731df88a35a85c1fd12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Fri, 9 Mar 2018 18:26:18 +0100 Subject: [PATCH 0565/1834] drm/amdgpu/dce: Don't turn off DP sink when disconnected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7d617264eb22b18d979eac6e85877a141253034e upstream. Turning off the sink in this case causes various issues, because userspace expects it to stay on until it turns it off explicitly. Instead, turn the sink off and back on when a display is connected again. This dance seems necessary for link training to work correctly. Bugzilla: https://bugs.freedesktop.org/105308 Cc: stable@vger.kernel.org Reviewed-by: Alex Deucher Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- .../gpu/drm/amd/amdgpu/amdgpu_connectors.c | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c index c82b04b24bf9..e9311eb7b8d9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_connectors.c @@ -69,25 +69,18 @@ void amdgpu_connector_hotplug(struct drm_connector *connector) /* don't do anything if sink is not display port, i.e., * passive dp->(dvi|hdmi) adaptor */ - if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { - int saved_dpms = connector->dpms; - /* Only turn off the display if it's physically disconnected */ - if (!amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd)) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - } else if (amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) { - /* Don't try to start link training before we - * have the dpcd */ - if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) - return; - - /* set it to OFF so that drm_helper_connector_dpms() - * won't return immediately since the current state - * is ON at this point. - */ - connector->dpms = DRM_MODE_DPMS_OFF; - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - } - connector->dpms = saved_dpms; + if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT && + amdgpu_display_hpd_sense(adev, amdgpu_connector->hpd.hpd) && + amdgpu_atombios_dp_needs_link_train(amdgpu_connector)) { + /* Don't start link training before we have the DPCD */ + if (amdgpu_atombios_dp_get_dpcd(amdgpu_connector)) + return; + + /* Turn the connector off and back on immediately, which + * will trigger link training + */ + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } } } -- GitLab From eaa9592678a9553ba51493bbe0257f51e6638abd Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Wed, 14 Mar 2018 18:20:29 -0500 Subject: [PATCH 0566/1834] fs: Teach path_connected to handle nfs filesystems with multiple roots. commit 95dd77580ccd66a0da96e6d4696945b8cea39431 upstream. On nfsv2 and nfsv3 the nfs server can export subsets of the same filesystem and report the same filesystem identifier, so that the nfs client can know they are the same filesystem. The subsets can be from disjoint directory trees. The nfsv2 and nfsv3 filesystems provides no way to find the common root of all directory trees exported form the server with the same filesystem identifier. The practical result is that in struct super s_root for nfs s_root is not necessarily the root of the filesystem. The nfs mount code sets s_root to the root of the first subset of the nfs filesystem that the kernel mounts. This effects the dcache invalidation code in generic_shutdown_super currently called shrunk_dcache_for_umount and that code for years has gone through an additional list of dentries that might be dentry trees that need to be freed to accomodate nfs. When I wrote path_connected I did not realize nfs was so special, and it's hueristic for avoiding calling is_subdir can fail. The practical case where this fails is when there is a move of a directory from the subtree exposed by one nfs mount to the subtree exposed by another nfs mount. This move can happen either locally or remotely. With the remote case requiring that the move directory be cached before the move and that after the move someone walks the path to where the move directory now exists and in so doing causes the already cached directory to be moved in the dcache through the magic of d_splice_alias. If someone whose working directory is in the move directory or a subdirectory and now starts calling .. from the initial mount of nfs (where s_root == mnt_root), then path_connected as a heuristic will not bother with the is_subdir check. As s_root really is not the root of the nfs filesystem this heuristic is wrong, and the path may actually not be connected and path_connected can fail. The is_subdir function might be cheap enough that we can call it unconditionally. Verifying that will take some benchmarking and the result may not be the same on all kernels this fix needs to be backported to. So I am avoiding that for now. Filesystems with snapshots such as nilfs and btrfs do something similar. But as the directory tree of the snapshots are disjoint from one another and from the main directory tree rename won't move things between them and this problem will not occur. Cc: stable@vger.kernel.org Reported-by: Al Viro Fixes: 397d425dc26d ("vfs: Test for and handle paths that are unreachable from their mnt_root") Signed-off-by: "Eric W. Biederman" Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 5 +++-- fs/nfs/super.c | 2 ++ include/linux/fs.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 917e7996b9c3..891670e0956b 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -578,9 +578,10 @@ static int __nd_alloc_stack(struct nameidata *nd) static bool path_connected(const struct path *path) { struct vfsmount *mnt = path->mnt; + struct super_block *sb = mnt->mnt_sb; - /* Only bind mounts can have disconnected paths */ - if (mnt->mnt_root == mnt->mnt_sb->s_root) + /* Bind mounts and multi-root filesystems can have disconnected paths */ + if (!(sb->s_iflags & SB_I_MULTIROOT) && (mnt->mnt_root == sb->s_root)) return true; return is_subdir(path->dentry, mnt->mnt_root); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 51bf1f9ab287..2fdb8f5a7b69 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2613,6 +2613,8 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server, /* initial superblock/root creation */ mount_info->fill_super(s, mount_info); nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned); + if (!(server->flags & NFS_MOUNT_UNSHARED)) + s->s_iflags |= SB_I_MULTIROOT; } mntroot = nfs_get_root(s, mount_info->mntfh, dev_name); diff --git a/include/linux/fs.h b/include/linux/fs.h index 18552189560b..e9867aff53d8 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1319,6 +1319,7 @@ struct mm_struct; #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ #define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ #define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */ +#define SB_I_MULTIROOT 0x00000008 /* Multiple roots to the dentry tree */ /* sb->s_iflags to limit user namespace mounts */ #define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ -- GitLab From 05f16fe9ae8c18f461b25fd6f31c77333c739f58 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 23 Feb 2018 20:47:17 -0500 Subject: [PATCH 0567/1834] lock_parent() needs to recheck if dentry got __dentry_kill'ed under it commit 3b821409632ab778d46e807516b457dfa72736ed upstream. In case when dentry passed to lock_parent() is protected from freeing only by the fact that it's on a shrink list and trylock of parent fails, we could get hit by __dentry_kill() (and subsequent dentry_kill(parent)) between unlocking dentry and locking presumed parent. We need to recheck that dentry is alive once we lock both it and parent *and* postpone rcu_read_unlock() until after that point. Otherwise we could return a pointer to struct dentry that already is rcu-scheduled for freeing, with ->d_lock held on it; caller's subsequent attempt to unlock it can end up with memory corruption. Cc: stable@vger.kernel.org # 3.12+, counting backports Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index 67957f5b325c..c0c7fa8224ba 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -637,11 +637,16 @@ static inline struct dentry *lock_parent(struct dentry *dentry) spin_unlock(&parent->d_lock); goto again; } - rcu_read_unlock(); - if (parent != dentry) + if (parent != dentry) { spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - else + if (unlikely(dentry->d_lockref.count < 0)) { + spin_unlock(&parent->d_lock); + parent = NULL; + } + } else { parent = NULL; + } + rcu_read_unlock(); return parent; } -- GitLab From 48226104275c0d8ddf307e432de8f6e6c5316bff Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 14 Mar 2018 12:10:17 -0700 Subject: [PATCH 0568/1834] fs/aio: Add explicit RCU grace period when freeing kioctx commit a6d7cff472eea87d96899a20fa718d2bab7109f3 upstream. While fixing refcounting, e34ecee2ae79 ("aio: Fix a trinity splat") incorrectly removed explicit RCU grace period before freeing kioctx. The intention seems to be depending on the internal RCU grace periods of percpu_ref; however, percpu_ref uses a different flavor of RCU, sched-RCU. This can lead to kioctx being freed while RCU read protected dereferences are still in progress. Fix it by updating free_ioctx() to go through call_rcu() explicitly. v2: Comment added to explain double bouncing. Signed-off-by: Tejun Heo Reported-by: Jann Horn Fixes: e34ecee2ae79 ("aio: Fix a trinity splat") Cc: Kent Overstreet Cc: Linus Torvalds Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Greg Kroah-Hartman --- fs/aio.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 0fcb49ad67d4..c00eb7e9cd04 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -115,7 +115,8 @@ struct kioctx { struct page **ring_pages; long nr_pages; - struct work_struct free_work; + struct rcu_head free_rcu; + struct work_struct free_work; /* see free_ioctx() */ /* * signals when all in-flight requests are done @@ -581,6 +582,12 @@ static int kiocb_cancel(struct aio_kiocb *kiocb) return cancel(&kiocb->common); } +/* + * free_ioctx() should be RCU delayed to synchronize against the RCU + * protected lookup_ioctx() and also needs process context to call + * aio_free_ring(), so the double bouncing through kioctx->free_rcu and + * ->free_work. + */ static void free_ioctx(struct work_struct *work) { struct kioctx *ctx = container_of(work, struct kioctx, free_work); @@ -594,6 +601,14 @@ static void free_ioctx(struct work_struct *work) kmem_cache_free(kioctx_cachep, ctx); } +static void free_ioctx_rcufn(struct rcu_head *head) +{ + struct kioctx *ctx = container_of(head, struct kioctx, free_rcu); + + INIT_WORK(&ctx->free_work, free_ioctx); + schedule_work(&ctx->free_work); +} + static void free_ioctx_reqs(struct percpu_ref *ref) { struct kioctx *ctx = container_of(ref, struct kioctx, reqs); @@ -602,8 +617,8 @@ static void free_ioctx_reqs(struct percpu_ref *ref) if (ctx->rq_wait && atomic_dec_and_test(&ctx->rq_wait->count)) complete(&ctx->rq_wait->comp); - INIT_WORK(&ctx->free_work, free_ioctx); - schedule_work(&ctx->free_work); + /* Synchronize against RCU protected table->table[] dereferences */ + call_rcu(&ctx->free_rcu, free_ioctx_rcufn); } /* @@ -825,7 +840,7 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, table->table[ctx->id] = NULL; spin_unlock(&mm->ioctx_lock); - /* percpu_ref_kill() will do the necessary call_rcu() */ + /* free_ioctx_reqs() will do the necessary RCU synchronization */ wake_up_all(&ctx->wait); /* -- GitLab From aa14f4bd6c4f32b19cdbfe37d918d1cb3baaf260 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 14 Mar 2018 12:10:17 -0700 Subject: [PATCH 0569/1834] fs/aio: Use RCU accessors for kioctx_table->table[] commit d0264c01e7587001a8c4608a5d1818dba9a4c11a upstream. While converting ioctx index from a list to a table, db446a08c23d ("aio: convert the ioctx list to table lookup v3") missed tagging kioctx_table->table[] as an array of RCU pointers and using the appropriate RCU accessors. This introduces a small window in the lookup path where init and access may race. Mark kioctx_table->table[] with __rcu and use the approriate RCU accessors when using the field. Signed-off-by: Tejun Heo Reported-by: Jann Horn Fixes: db446a08c23d ("aio: convert the ioctx list to table lookup v3") Cc: Benjamin LaHaise Cc: Linus Torvalds Cc: stable@vger.kernel.org # v3.12+ Signed-off-by: Greg Kroah-Hartman --- fs/aio.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index c00eb7e9cd04..0606f033cd9b 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -68,9 +68,9 @@ struct aio_ring { #define AIO_RING_PAGES 8 struct kioctx_table { - struct rcu_head rcu; - unsigned nr; - struct kioctx *table[]; + struct rcu_head rcu; + unsigned nr; + struct kioctx __rcu *table[]; }; struct kioctx_cpu { @@ -330,7 +330,7 @@ static int aio_ring_mremap(struct vm_area_struct *vma) for (i = 0; i < table->nr; i++) { struct kioctx *ctx; - ctx = table->table[i]; + ctx = rcu_dereference(table->table[i]); if (ctx && ctx->aio_ring_file == file) { if (!atomic_read(&ctx->dead)) { ctx->user_id = ctx->mmap_base = vma->vm_start; @@ -659,9 +659,9 @@ static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm) while (1) { if (table) for (i = 0; i < table->nr; i++) - if (!table->table[i]) { + if (!rcu_access_pointer(table->table[i])) { ctx->id = i; - table->table[i] = ctx; + rcu_assign_pointer(table->table[i], ctx); spin_unlock(&mm->ioctx_lock); /* While kioctx setup is in progress, @@ -836,8 +836,8 @@ static int kill_ioctx(struct mm_struct *mm, struct kioctx *ctx, } table = rcu_dereference_raw(mm->ioctx_table); - WARN_ON(ctx != table->table[ctx->id]); - table->table[ctx->id] = NULL; + WARN_ON(ctx != rcu_access_pointer(table->table[ctx->id])); + RCU_INIT_POINTER(table->table[ctx->id], NULL); spin_unlock(&mm->ioctx_lock); /* free_ioctx_reqs() will do the necessary RCU synchronization */ @@ -882,7 +882,8 @@ void exit_aio(struct mm_struct *mm) skipped = 0; for (i = 0; i < table->nr; ++i) { - struct kioctx *ctx = table->table[i]; + struct kioctx *ctx = + rcu_dereference_protected(table->table[i], true); if (!ctx) { skipped++; @@ -1071,7 +1072,7 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) if (!table || id >= table->nr) goto out; - ctx = table->table[id]; + ctx = rcu_dereference(table->table[id]); if (ctx && ctx->user_id == ctx_id) { percpu_ref_get(&ctx->users); ret = ctx; -- GitLab From 43166185da4a7802dd011d629fcdb4e1df0d2bd3 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 6 Mar 2018 15:51:32 +0000 Subject: [PATCH 0570/1834] irqchip/gic-v3-its: Ensure nr_ites >= nr_lpis commit 4f2c7583e33eb08dc09dd2e25574b80175ba7d93 upstream. When struct its_device instances are created, the nr_ites member will be set to a power of 2 that equals or exceeds the requested number of MSIs passed to the msi_prepare() callback. At the same time, the LPI map is allocated to be some multiple of 32 in size, where the allocated size may be less than the requested size depending on whether a contiguous range of sufficient size is available in the global LPI bitmap. This may result in the situation where the nr_ites < nr_lpis, and since nr_ites is what we program into the hardware when we map the device, the additional LPIs will be non-functional. For bog standard hardware, this does not really matter. However, in cases where ITS device IDs are shared between different PCIe devices, we may end up allocating these additional LPIs without taking into account that they don't actually work. So let's make nr_ites at least 32. This ensures that all allocated LPIs are 'live', and that its_alloc_device_irq() will fail when attempts are made to allocate MSIs beyond what was allocated in the first place. Signed-off-by: Ard Biesheuvel [maz: updated comment] Signed-off-by: Marc Zyngier [ardb: trivial tweak of unrelated context] Signed-off-by: Ard Biesheuvel Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-v3-its.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index acb9d250a905..ac15e5d5d9b2 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -684,7 +684,7 @@ static struct irq_chip its_irq_chip = { * This gives us (((1UL << id_bits) - 8192) >> 5) possible allocations. */ #define IRQS_PER_CHUNK_SHIFT 5 -#define IRQS_PER_CHUNK (1 << IRQS_PER_CHUNK_SHIFT) +#define IRQS_PER_CHUNK (1UL << IRQS_PER_CHUNK_SHIFT) static unsigned long *lpi_bitmap; static u32 lpi_chunks; @@ -1320,11 +1320,10 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id, dev = kzalloc(sizeof(*dev), GFP_KERNEL); /* - * At least one bit of EventID is being used, hence a minimum - * of two entries. No, the architecture doesn't let you - * express an ITT with a single entry. + * We allocate at least one chunk worth of LPIs bet device, + * and thus that many ITEs. The device may require less though. */ - nr_ites = max(2UL, roundup_pow_of_two(nvecs)); + nr_ites = max(IRQS_PER_CHUNK, roundup_pow_of_two(nvecs)); sz = nr_ites * its->ite_size; sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1; itt = kzalloc(sz, GFP_KERNEL); -- GitLab From 691db1857ee784f026e4d2c267229db4885494ad Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Fri, 7 Jul 2017 10:56:38 +0200 Subject: [PATCH 0571/1834] scsi: sg: fix SG_DXFER_FROM_DEV transfers commit 68c59fcea1f2c6a54c62aa896cc623c1b5bc9b47 upstream. SG_DXFER_FROM_DEV transfers do not necessarily have a dxferp as we set it to NULL for the old sg_io read/write interface, but must have a length bigger than 0. This fixes a regression introduced by commit 28676d869bbb ("scsi: sg: check for valid direction before starting the request") Signed-off-by: Johannes Thumshirn Fixes: 28676d869bbb ("scsi: sg: check for valid direction before starting the request") Reported-by: Chris Clayton Tested-by: Chris Clayton Cc: Douglas Gilbert Reviewed-by: Hannes Reinecke Tested-by: Chris Clayton Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen Cc: Cristian Crinteanu Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index e6333cae8550..1536f143566d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -758,8 +758,11 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp) if (hp->dxferp || hp->dxfer_len > 0) return false; return true; - case SG_DXFER_TO_DEV: case SG_DXFER_FROM_DEV: + if (hp->dxfer_len < 0) + return false; + return true; + case SG_DXFER_TO_DEV: case SG_DXFER_TO_FROM_DEV: if (!hp->dxferp || hp->dxfer_len == 0) return false; -- GitLab From cbdcbd909efe41bbb10b7c15ff1ff15c1b4971a0 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 17 Jul 2017 15:11:42 +0200 Subject: [PATCH 0572/1834] scsi: sg: fix static checker warning in sg_is_valid_dxfer commit 14074aba4bcda3764c9a702b276308b89901d5b6 upstream. dxfer_len is an unsigned int and we always assign a value > 0 to it, so it doesn't make any sense to check if it is < 0. We can't really check dxferp as well as we have both NULL and not NULL cases in the possible call paths. So just return true for SG_DXFER_FROM_DEV transfer in sg_is_valid_dxfer(). Signed-off-by: Johannes Thumshirn Reported-by: Colin Ian King Reported-by: Dan Carpenter Cc: Douglas Gilbert Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 1536f143566d..638d11d9262f 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -759,8 +759,11 @@ static bool sg_is_valid_dxfer(sg_io_hdr_t *hp) return false; return true; case SG_DXFER_FROM_DEV: - if (hp->dxfer_len < 0) - return false; + /* + * for SG_DXFER_FROM_DEV we always set dxfer_len to > 0. dxferp + * can either be NULL or != NULL so there's no point in checking + * it either. So just return true. + */ return true; case SG_DXFER_TO_DEV: case SG_DXFER_TO_FROM_DEV: -- GitLab From 887cb857e5122a72caa02a3bea402b1c8bf4056b Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 27 Jul 2017 09:11:26 +0200 Subject: [PATCH 0573/1834] scsi: sg: only check for dxfer_len greater than 256M commit f930c7043663188429cd9b254e9d761edfc101ce upstream. Don't make any assumptions on the sg_io_hdr_t::dxfer_direction or the sg_io_hdr_t::dxferp in order to determine if it is a valid request. The only way we can check for bad requests is by checking if the length exceeds 256M. Signed-off-by: Johannes Thumshirn Fixes: 28676d869bbb (scsi: sg: check for valid direction before starting the request) Reported-by: Jason L Tibbitts III Tested-by: Jason L Tibbitts III Suggested-by: Doug Gilbert Cc: Doug Gilbert Cc: Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 31 +------------------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 638d11d9262f..7592ac8514d2 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -751,35 +751,6 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, return count; } -static bool sg_is_valid_dxfer(sg_io_hdr_t *hp) -{ - switch (hp->dxfer_direction) { - case SG_DXFER_NONE: - if (hp->dxferp || hp->dxfer_len > 0) - return false; - return true; - case SG_DXFER_FROM_DEV: - /* - * for SG_DXFER_FROM_DEV we always set dxfer_len to > 0. dxferp - * can either be NULL or != NULL so there's no point in checking - * it either. So just return true. - */ - return true; - case SG_DXFER_TO_DEV: - case SG_DXFER_TO_FROM_DEV: - if (!hp->dxferp || hp->dxfer_len == 0) - return false; - return true; - case SG_DXFER_UNKNOWN: - if ((!hp->dxferp && hp->dxfer_len) || - (hp->dxferp && hp->dxfer_len == 0)) - return false; - return true; - default: - return false; - } -} - static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char *cmnd, int timeout, int blocking) @@ -800,7 +771,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, "sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) cmnd[0], (int) hp->cmd_len)); - if (!sg_is_valid_dxfer(hp)) + if (hp->dxfer_len >= SZ_256M) return -EINVAL; k = sg_start_req(srp, cmnd); -- GitLab From 8890bae03f4dba1c2292e5445682b556af4e8f1b Mon Sep 17 00:00:00 2001 From: Hans van Kranenburg Date: Mon, 5 Feb 2018 17:45:11 +0100 Subject: [PATCH 0574/1834] btrfs: alloc_chunk: fix DUP stripe size handling commit 92e222df7b8f05c565009c7383321b593eca488b upstream. In case of using DUP, we search for enough unallocated disk space on a device to hold two stripes. The devices_info[ndevs-1].max_avail that holds the amount of unallocated space found is directly assigned to stripe_size, while it's actually twice the stripe size. Later on in the code, an unconditional division of stripe_size by dev_stripes corrects the value, but in the meantime there's a check to see if the stripe_size does not exceed max_chunk_size. Since during this check stripe_size is twice the amount as intended, the check will reduce the stripe_size to max_chunk_size if the actual correct to be used stripe_size is more than half the amount of max_chunk_size. The unconditional division later tries to correct stripe_size, but will actually make sure we can't allocate more than half the max_chunk_size. Fix this by moving the division by dev_stripes before the max chunk size check, so it always contains the right value, instead of putting a duct tape division in further on to get it fixed again. Since in all other cases than DUP, dev_stripes is 1, this change only affects DUP. Other attempts in the past were made to fix this: * 37db63a400 "Btrfs: fix max chunk size check in chunk allocator" tried to fix the same problem, but still resulted in part of the code acting on a wrongly doubled stripe_size value. * 86db25785a "Btrfs: fix max chunk size on raid5/6" unintentionally broke this fix again. The real problem was already introduced with the rest of the code in 73c5de0051. The user visible result however will be that the max chunk size for DUP will suddenly double, while it's actually acting according to the limits in the code again like it was 5 years ago. Reported-by: Naohiro Aota Link: https://www.spinics.net/lists/linux-btrfs/msg69752.html Fixes: 73c5de0051 ("btrfs: quasi-round-robin for chunk allocation") Fixes: 86db25785a ("Btrfs: fix max chunk size on raid5/6") Signed-off-by: Hans van Kranenburg Reviewed-by: David Sterba [ update comment ] Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/volumes.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 06a77e47957d..a73c29d2b315 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -4748,10 +4748,13 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, if (devs_max && ndevs > devs_max) ndevs = devs_max; /* - * the primary goal is to maximize the number of stripes, so use as many - * devices as possible, even if the stripes are not maximum sized. + * The primary goal is to maximize the number of stripes, so use as + * many devices as possible, even if the stripes are not maximum sized. + * + * The DUP profile stores more than one stripe per device, the + * max_avail is the total size so we have to adjust. */ - stripe_size = devices_info[ndevs-1].max_avail; + stripe_size = div_u64(devices_info[ndevs - 1].max_avail, dev_stripes); num_stripes = ndevs * dev_stripes; /* @@ -4791,8 +4794,6 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, stripe_size = devices_info[ndevs-1].max_avail; } - stripe_size = div_u64(stripe_size, dev_stripes); - /* align to BTRFS_STRIPE_LEN */ stripe_size = div_u64(stripe_size, raid_stripe_len); stripe_size *= raid_stripe_len; -- GitLab From 8ae7720cf90b952b9dba9b1d31062068d29137ff Mon Sep 17 00:00:00 2001 From: Nikolay Borisov Date: Tue, 30 Jan 2018 16:07:37 +0200 Subject: [PATCH 0575/1834] btrfs: Fix use-after-free when cleaning up fs_devs with a single stale device commit fd649f10c3d21ee9d7542c609f29978bdf73ab94 upstream. Commit 4fde46f0cc71 ("Btrfs: free the stale device") introduced btrfs_free_stale_device which iterates the device lists for all registered btrfs filesystems and deletes those devices which aren't mounted. In a btrfs_devices structure has only 1 device attached to it and it is unused then btrfs_free_stale_devices will proceed to also free the btrfs_fs_devices struct itself. Currently this leads to a use after free since list_for_each_entry will try to perform a check on the already freed memory to see if it has to terminate the loop. The fix is to use 'break' when we know we are freeing the current fs_devs. Fixes: 4fde46f0cc71 ("Btrfs: free the stale device") Signed-off-by: Nikolay Borisov Reviewed-by: Anand Jain Signed-off-by: David Sterba Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/volumes.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index a73c29d2b315..5900508ca6ed 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -583,6 +583,7 @@ void btrfs_free_stale_device(struct btrfs_device *cur_dev) btrfs_sysfs_remove_fsid(fs_devs); list_del(&fs_devs->list); free_fs_devices(fs_devs); + break; } else { fs_devs->num_devices--; list_del(&dev->dev_list); -- GitLab From 9f4a71db144905a41c795e5a67236e36cb20bb16 Mon Sep 17 00:00:00 2001 From: Bill Kuzeja Date: Thu, 25 May 2017 15:26:31 -0400 Subject: [PATCH 0576/1834] scsi: qla2xxx: Fix extraneous ref on sp's after adapter break commit 4cd3b6ebff8510b2139d64024411207090cfe0a9 upstream. Hung task timeouts can result if a qlogic board breaks unexpectedly while running I/O. These tasks become hung because command srb reference counts are not going to zero, hence the affected srbs and commands do not get freed. This fix accounts for this extra reference in the srbs in the case of a board failure. Fixes: a465537ad1a4 ("qla2xxx: Disable the adapter and skip error recovery in case of register disconnect") Signed-off-by: Bill Kuzeja Acked-by: Himanshu Madhani Signed-off-by: Martin K. Petersen Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/qla2xxx/qla_os.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 94630d4738e6..baccd116f864 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1443,7 +1443,7 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) void qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) { - int que, cnt; + int que, cnt, status; unsigned long flags; srb_t *sp; struct qla_hw_data *ha = vha->hw; @@ -1473,8 +1473,12 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) */ sp_get(sp); spin_unlock_irqrestore(&ha->hardware_lock, flags); - qla2xxx_eh_abort(GET_CMD_SP(sp)); + status = qla2xxx_eh_abort(GET_CMD_SP(sp)); spin_lock_irqsave(&ha->hardware_lock, flags); + /* Get rid of extra reference if immediate exit + * from ql2xxx_eh_abort */ + if (status == FAILED && (qla2x00_isp_reg_stat(ha))) + atomic_dec(&sp->ref_count); } req->outstanding_cmds[cnt] = NULL; sp->done(vha, sp, res); -- GitLab From 30fe81cca111c22bc6048ef8998691c8e51b0d7a Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 23 Jan 2018 09:35:14 +0000 Subject: [PATCH 0577/1834] USB: gadget: udc: Add missing platform_device_put() on error in bdc_pci_probe() commit 8874ae5f15f3feef3b4a415b9aed51edcf449aa1 upstream. Add the missing platform_device_put() before return from bdc_pci_probe() in the platform_device_add_resources() error handling case. Fixes: efed421a94e6 ("usb: gadget: Add UDC driver for Broadcom USB3.0 device controller IP BDC") Signed-off-by: Wei Yongjun Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/bdc/bdc_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/gadget/udc/bdc/bdc_pci.c b/drivers/usb/gadget/udc/bdc/bdc_pci.c index 02968842b359..708e36f530d8 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_pci.c +++ b/drivers/usb/gadget/udc/bdc/bdc_pci.c @@ -82,6 +82,7 @@ static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) if (ret) { dev_err(&pci->dev, "couldn't add resources to bdc device\n"); + platform_device_put(bdc); return ret; } -- GitLab From ecb1886f9b4fea6408f4d9c6defcc7ba3db88c29 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Fri, 2 Feb 2018 13:21:35 -0800 Subject: [PATCH 0578/1834] usb: dwc3: Fix GDBGFIFOSPACE_TYPE values commit b16ea8b9492e99e03b1269fe93ebdbf8e4eabf8a upstream. The FIFO/Queue type values are incorrect. Correct them according to DWC_usb3 programming guide section 1.2.27 (or DWC_usb31 section 1.2.25). Additionally, this patch includes ProtocolStatusQ and AuxEventQ types. Fixes: cf6d867d3b57 ("usb: dwc3: core: add fifo space helper") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/core.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index bc3678e9dcb1..94d6a3e2ad97 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -159,13 +159,15 @@ #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) #define DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(n) (((n) >> 16) & 0xffff) -#define DWC3_TXFIFOQ 1 -#define DWC3_RXFIFOQ 3 -#define DWC3_TXREQQ 5 -#define DWC3_RXREQQ 7 -#define DWC3_RXINFOQ 9 -#define DWC3_DESCFETCHQ 13 -#define DWC3_EVENTQ 15 +#define DWC3_TXFIFOQ 0 +#define DWC3_RXFIFOQ 1 +#define DWC3_TXREQQ 2 +#define DWC3_RXREQQ 3 +#define DWC3_RXINFOQ 4 +#define DWC3_PSTATQ 5 +#define DWC3_DESCFETCHQ 6 +#define DWC3_EVENTQ 7 +#define DWC3_AUXEVENTQ 8 /* Global RX Threshold Configuration Register */ #define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19) -- GitLab From 9fad15931cc5bc42a8cd4739d58ebab527ac1d42 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Thu, 15 Jun 2017 14:39:22 +0530 Subject: [PATCH 0579/1834] usb: gadget: bdc: 64-bit pointer capability check commit c8e4e5bdb62a5ac6f860ebcaaf7b467b62f453f1 upstream. Corrected the register to check the 64-bit pointer capability state. 64-bit pointer implementation capability was checking in wrong register, which causes the BDC enumeration failure in 64-bit memory address. Fixes: efed421a94e6 ("usb: gadget: Add UDC driver for Broadcom USB3.0 device controller IP BDC") Reviewed-by: Florian Fainelli Signed-off-by: Srinath Mannam Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/bdc/bdc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index ccb9c213cc9f..e9bd8d4abca0 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -475,7 +475,7 @@ static int bdc_probe(struct platform_device *pdev) bdc->dev = dev; dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); - temp = bdc_readl(bdc->regs, BDC_BDCSC); + temp = bdc_readl(bdc->regs, BDC_BDCCAP1); if ((temp & BDC_P64) && !dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { dev_dbg(bdc->dev, "Using 64-bit address\n"); -- GitLab From a779add58a837fbd5156e0fab0aca5e3b53754ef Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 22 Mar 2018 09:18:01 +0100 Subject: [PATCH 0580/1834] Linux 4.9.89 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1512ebceffda..16dca98900e7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 88 +SUBLEVEL = 89 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From f361eb39cdbfcb4372acb091d80c9c4bbf865262 Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Wed, 13 Dec 2017 14:20:17 +0800 Subject: [PATCH 0581/1834] PM / OPP: list_del_rcu should be used in function _remove_opp_dev list_del_rcu should be used to replace list_del in function _remove_opp_dev, since the opp is a rcu protected pointer. Test: for example, on an ARM big.Little platform, the opp_table of big cluster will be removed when big cluster is removed, which should be implemented in the cpufreq driver. Then a stress test that the big cluster is plugged in/out, can test the patch. Change-Id: I59c0ba16d372575ff1d80097575eeea826f6df52 Signed-off-by: Vincent Wang --- drivers/base/power/opp/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index a7c5b79371a7..94001aafc6d0 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -708,7 +708,7 @@ static void _remove_opp_dev(struct opp_device *opp_dev, struct opp_table *opp_table) { opp_debug_unregister(opp_dev, opp_table); - list_del(&opp_dev->node); + list_del_rcu(&opp_dev->node); call_srcu(&opp_table->srcu_head.srcu, &opp_dev->rcu_head, _kfree_opp_dev_rcu); } -- GitLab From 5f272a616a2a197a4b516a57b25de3db83ed0e80 Mon Sep 17 00:00:00 2001 From: Harsh Sahu Date: Thu, 22 Mar 2018 23:22:17 -0700 Subject: [PATCH 0582/1834] drm/msm : check buffer size before writing to user buffer Check the number of bytes to copy against the size of the user buffer before copy to user to avoid buffer overflow. Change-Id: Ida3f2470b8441010adc30312c12c6d75fdd6ccb8 Signed-off-by: Harsh Sahu --- drivers/gpu/drm/msm/sde_dbg.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde_dbg.c b/drivers/gpu/drm/msm/sde_dbg.c index 3a67a2288af2..582909580be9 100644 --- a/drivers/gpu/drm/msm/sde_dbg.c +++ b/drivers/gpu/drm/msm/sde_dbg.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2785,6 +2785,11 @@ static ssize_t sde_evtlog_dump_read(struct file *file, char __user *buff, len = sde_evtlog_dump_to_buffer(sde_dbg_base.evtlog, evtlog_buf, SDE_EVTLOG_BUF_MAX, true); + if (len < 0 || len > count) { + pr_err("len is more than user buffer size"); + return 0; + } + if (copy_to_user(buff, evtlog_buf, len)) return -EFAULT; *ppos += len; -- GitLab From ebc27895e954ef84e33dbc7f72183d02c2c5f496 Mon Sep 17 00:00:00 2001 From: Joel Fernandes Date: Fri, 23 Mar 2018 09:32:41 -0700 Subject: [PATCH 0583/1834] ANDROID: debugobjects: Make stack check warning more informative Currently there is a difficult to debug bug where an object on the stack appears to not be on it. Discussing with tglx, he suggests printing the pointers and the location of the stack for the currently running task. Lets do the same, so that the error message is more informative and can help in debugging. After debugging, we can upstream this patch if its useful. Bug: 72009635 Change-Id: Id50518e70a500b850580684e82b999afbf88ee75 Signed-off-by: Joel Fernandes --- lib/debugobjects.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/debugobjects.c b/lib/debugobjects.c index 056052dc8e91..19572a4bbdca 100644 --- a/lib/debugobjects.c +++ b/lib/debugobjects.c @@ -293,10 +293,13 @@ static void debug_object_is_on_stack(void *addr, int onstack) return; limit++; - if (is_on_stack) - pr_warn("object is on stack, but not annotated\n"); - else - pr_warn("object is not on stack, but annotated\n"); + if (is_on_stack) { + pr_warn("object %p is on stack %p, but NOT annotated\n", addr, + task_stack_page(current)); + } else { + pr_warn("object %p is NOT on stack %p, but annotated\n", addr, + task_stack_page(current)); + } WARN_ON(1); } -- GitLab From f152ce1be2ab0d243e69c8b779181a5925623c2d Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 5 Mar 2018 11:17:07 -0800 Subject: [PATCH 0584/1834] BACKPORT, FROMLIST: crypto: arm64/speck - add NEON-accelerated implementation of Speck-XTS Add a NEON-accelerated implementation of Speck128-XTS and Speck64-XTS for ARM64. This is ported from the 32-bit version. It may be useful on devices with 64-bit ARM CPUs that don't have the Cryptography Extensions, so cannot do AES efficiently -- e.g. the Cortex-A53 processor on the Raspberry Pi 3. It generally works the same way as the 32-bit version, but there are some slight differences due to the different instructions, registers, and syntax available in ARM64 vs. in ARM32. For example, in the 64-bit version there are enough registers to hold the XTS tweaks for each 128-byte chunk, so they don't need to be saved on the stack. Benchmarks on a Raspberry Pi 3 running a 64-bit kernel: Algorithm Encryption Decryption --------- ---------- ---------- Speck64/128-XTS (NEON) 92.2 MB/s 92.2 MB/s Speck128/256-XTS (NEON) 75.0 MB/s 75.0 MB/s Speck128/256-XTS (generic) 47.4 MB/s 35.6 MB/s AES-128-XTS (NEON bit-sliced) 33.4 MB/s 29.6 MB/s AES-256-XTS (NEON bit-sliced) 24.6 MB/s 21.7 MB/s The code performs well on higher-end ARM64 processors as well, though such processors tend to have the Crypto Extensions which make AES preferred. For example, here are the same benchmarks run on a HiKey960 (with CPU affinity set for the A73 cores), with the Crypto Extensions implementation of AES-256-XTS added: Algorithm Encryption Decryption --------- ----------- ----------- AES-256-XTS (Crypto Extensions) 1273.3 MB/s 1274.7 MB/s Speck64/128-XTS (NEON) 359.8 MB/s 348.0 MB/s Speck128/256-XTS (NEON) 292.5 MB/s 286.1 MB/s Speck128/256-XTS (generic) 186.3 MB/s 181.8 MB/s AES-128-XTS (NEON bit-sliced) 142.0 MB/s 124.3 MB/s AES-256-XTS (NEON bit-sliced) 104.7 MB/s 91.1 MB/s Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu (cherry picked from commit 91a2abb78f940ac821345cb7cc376dca94336c2f git://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master) (changed speck-neon-glue.c to use blkcipher API instead of skcipher API) (resolved merge conflicts in arch/arm64/crypto/Makefile and arch/arm64/crypto/Kconfig) (made CONFIG_CRYPTO_SPECK_NEON select CONFIG_CRYPTO_GF128MUL, since gf128mul_x_ble() is non-inline in older kernels) Change-Id: Iaed7a14c84b32b09ec299060a5d27060693043d5 Signed-off-by: Eric Biggers --- arch/arm64/crypto/Kconfig | 7 + arch/arm64/crypto/Makefile | 3 + arch/arm64/crypto/speck-neon-core.S | 352 ++++++++++++++++++++++++++++ arch/arm64/crypto/speck-neon-glue.c | 308 ++++++++++++++++++++++++ 4 files changed, 670 insertions(+) create mode 100644 arch/arm64/crypto/speck-neon-core.S create mode 100644 arch/arm64/crypto/speck-neon-glue.c diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig index 2cf32e9887e1..2b10984ee58c 100644 --- a/arch/arm64/crypto/Kconfig +++ b/arch/arm64/crypto/Kconfig @@ -53,4 +53,11 @@ config CRYPTO_CRC32_ARM64 tristate "CRC32 and CRC32C using optional ARMv8 instructions" depends on ARM64 select CRYPTO_HASH + +config CRYPTO_SPECK_NEON + tristate "NEON accelerated Speck cipher algorithms" + depends on KERNEL_MODE_NEON + select CRYPTO_BLKCIPHER + select CRYPTO_GF128MUL + select CRYPTO_SPECK endif diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile index 550e02a5aa32..9908765a2f45 100644 --- a/arch/arm64/crypto/Makefile +++ b/arch/arm64/crypto/Makefile @@ -30,6 +30,9 @@ aes-ce-blk-y := aes-glue-ce.o aes-ce.o obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o aes-neon-blk-y := aes-glue-neon.o aes-neon.o +obj-$(CONFIG_CRYPTO_SPECK_NEON) += speck-neon.o +speck-neon-y := speck-neon-core.o speck-neon-glue.o + AFLAGS_aes-ce.o := -DINTERLEAVE=4 AFLAGS_aes-neon.o := -DINTERLEAVE=4 diff --git a/arch/arm64/crypto/speck-neon-core.S b/arch/arm64/crypto/speck-neon-core.S new file mode 100644 index 000000000000..b14463438b09 --- /dev/null +++ b/arch/arm64/crypto/speck-neon-core.S @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ARM64 NEON-accelerated implementation of Speck128-XTS and Speck64-XTS + * + * Copyright (c) 2018 Google, Inc + * + * Author: Eric Biggers + */ + +#include + + .text + + // arguments + ROUND_KEYS .req x0 // const {u64,u32} *round_keys + NROUNDS .req w1 // int nrounds + NROUNDS_X .req x1 + DST .req x2 // void *dst + SRC .req x3 // const void *src + NBYTES .req w4 // unsigned int nbytes + TWEAK .req x5 // void *tweak + + // registers which hold the data being encrypted/decrypted + // (underscores avoid a naming collision with ARM64 registers x0-x3) + X_0 .req v0 + Y_0 .req v1 + X_1 .req v2 + Y_1 .req v3 + X_2 .req v4 + Y_2 .req v5 + X_3 .req v6 + Y_3 .req v7 + + // the round key, duplicated in all lanes + ROUND_KEY .req v8 + + // index vector for tbl-based 8-bit rotates + ROTATE_TABLE .req v9 + ROTATE_TABLE_Q .req q9 + + // temporary registers + TMP0 .req v10 + TMP1 .req v11 + TMP2 .req v12 + TMP3 .req v13 + + // multiplication table for updating XTS tweaks + GFMUL_TABLE .req v14 + GFMUL_TABLE_Q .req q14 + + // next XTS tweak value(s) + TWEAKV_NEXT .req v15 + + // XTS tweaks for the blocks currently being encrypted/decrypted + TWEAKV0 .req v16 + TWEAKV1 .req v17 + TWEAKV2 .req v18 + TWEAKV3 .req v19 + TWEAKV4 .req v20 + TWEAKV5 .req v21 + TWEAKV6 .req v22 + TWEAKV7 .req v23 + + .align 4 +.Lror64_8_table: + .octa 0x080f0e0d0c0b0a090007060504030201 +.Lror32_8_table: + .octa 0x0c0f0e0d080b0a090407060500030201 +.Lrol64_8_table: + .octa 0x0e0d0c0b0a09080f0605040302010007 +.Lrol32_8_table: + .octa 0x0e0d0c0f0a09080b0605040702010003 +.Lgf128mul_table: + .octa 0x00000000000000870000000000000001 +.Lgf64mul_table: + .octa 0x0000000000000000000000002d361b00 + +/* + * _speck_round_128bytes() - Speck encryption round on 128 bytes at a time + * + * Do one Speck encryption round on the 128 bytes (8 blocks for Speck128, 16 for + * Speck64) stored in X0-X3 and Y0-Y3, using the round key stored in all lanes + * of ROUND_KEY. 'n' is the lane size: 64 for Speck128, or 32 for Speck64. + * 'lanes' is the lane specifier: "2d" for Speck128 or "4s" for Speck64. + */ +.macro _speck_round_128bytes n, lanes + + // x = ror(x, 8) + tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b + tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b + tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b + tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b + + // x += y + add X_0.\lanes, X_0.\lanes, Y_0.\lanes + add X_1.\lanes, X_1.\lanes, Y_1.\lanes + add X_2.\lanes, X_2.\lanes, Y_2.\lanes + add X_3.\lanes, X_3.\lanes, Y_3.\lanes + + // x ^= k + eor X_0.16b, X_0.16b, ROUND_KEY.16b + eor X_1.16b, X_1.16b, ROUND_KEY.16b + eor X_2.16b, X_2.16b, ROUND_KEY.16b + eor X_3.16b, X_3.16b, ROUND_KEY.16b + + // y = rol(y, 3) + shl TMP0.\lanes, Y_0.\lanes, #3 + shl TMP1.\lanes, Y_1.\lanes, #3 + shl TMP2.\lanes, Y_2.\lanes, #3 + shl TMP3.\lanes, Y_3.\lanes, #3 + sri TMP0.\lanes, Y_0.\lanes, #(\n - 3) + sri TMP1.\lanes, Y_1.\lanes, #(\n - 3) + sri TMP2.\lanes, Y_2.\lanes, #(\n - 3) + sri TMP3.\lanes, Y_3.\lanes, #(\n - 3) + + // y ^= x + eor Y_0.16b, TMP0.16b, X_0.16b + eor Y_1.16b, TMP1.16b, X_1.16b + eor Y_2.16b, TMP2.16b, X_2.16b + eor Y_3.16b, TMP3.16b, X_3.16b +.endm + +/* + * _speck_unround_128bytes() - Speck decryption round on 128 bytes at a time + * + * This is the inverse of _speck_round_128bytes(). + */ +.macro _speck_unround_128bytes n, lanes + + // y ^= x + eor TMP0.16b, Y_0.16b, X_0.16b + eor TMP1.16b, Y_1.16b, X_1.16b + eor TMP2.16b, Y_2.16b, X_2.16b + eor TMP3.16b, Y_3.16b, X_3.16b + + // y = ror(y, 3) + ushr Y_0.\lanes, TMP0.\lanes, #3 + ushr Y_1.\lanes, TMP1.\lanes, #3 + ushr Y_2.\lanes, TMP2.\lanes, #3 + ushr Y_3.\lanes, TMP3.\lanes, #3 + sli Y_0.\lanes, TMP0.\lanes, #(\n - 3) + sli Y_1.\lanes, TMP1.\lanes, #(\n - 3) + sli Y_2.\lanes, TMP2.\lanes, #(\n - 3) + sli Y_3.\lanes, TMP3.\lanes, #(\n - 3) + + // x ^= k + eor X_0.16b, X_0.16b, ROUND_KEY.16b + eor X_1.16b, X_1.16b, ROUND_KEY.16b + eor X_2.16b, X_2.16b, ROUND_KEY.16b + eor X_3.16b, X_3.16b, ROUND_KEY.16b + + // x -= y + sub X_0.\lanes, X_0.\lanes, Y_0.\lanes + sub X_1.\lanes, X_1.\lanes, Y_1.\lanes + sub X_2.\lanes, X_2.\lanes, Y_2.\lanes + sub X_3.\lanes, X_3.\lanes, Y_3.\lanes + + // x = rol(x, 8) + tbl X_0.16b, {X_0.16b}, ROTATE_TABLE.16b + tbl X_1.16b, {X_1.16b}, ROTATE_TABLE.16b + tbl X_2.16b, {X_2.16b}, ROTATE_TABLE.16b + tbl X_3.16b, {X_3.16b}, ROTATE_TABLE.16b +.endm + +.macro _next_xts_tweak next, cur, tmp, n +.if \n == 64 + /* + * Calculate the next tweak by multiplying the current one by x, + * modulo p(x) = x^128 + x^7 + x^2 + x + 1. + */ + sshr \tmp\().2d, \cur\().2d, #63 + and \tmp\().16b, \tmp\().16b, GFMUL_TABLE.16b + shl \next\().2d, \cur\().2d, #1 + ext \tmp\().16b, \tmp\().16b, \tmp\().16b, #8 + eor \next\().16b, \next\().16b, \tmp\().16b +.else + /* + * Calculate the next two tweaks by multiplying the current ones by x^2, + * modulo p(x) = x^64 + x^4 + x^3 + x + 1. + */ + ushr \tmp\().2d, \cur\().2d, #62 + shl \next\().2d, \cur\().2d, #2 + tbl \tmp\().16b, {GFMUL_TABLE.16b}, \tmp\().16b + eor \next\().16b, \next\().16b, \tmp\().16b +.endif +.endm + +/* + * _speck_xts_crypt() - Speck-XTS encryption/decryption + * + * Encrypt or decrypt NBYTES bytes of data from the SRC buffer to the DST buffer + * using Speck-XTS, specifically the variant with a block size of '2n' and round + * count given by NROUNDS. The expanded round keys are given in ROUND_KEYS, and + * the current XTS tweak value is given in TWEAK. It's assumed that NBYTES is a + * nonzero multiple of 128. + */ +.macro _speck_xts_crypt n, lanes, decrypting + + /* + * If decrypting, modify the ROUND_KEYS parameter to point to the last + * round key rather than the first, since for decryption the round keys + * are used in reverse order. + */ +.if \decrypting + mov NROUNDS, NROUNDS /* zero the high 32 bits */ +.if \n == 64 + add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #3 + sub ROUND_KEYS, ROUND_KEYS, #8 +.else + add ROUND_KEYS, ROUND_KEYS, NROUNDS_X, lsl #2 + sub ROUND_KEYS, ROUND_KEYS, #4 +.endif +.endif + + // Load the index vector for tbl-based 8-bit rotates +.if \decrypting + ldr ROTATE_TABLE_Q, .Lrol\n\()_8_table +.else + ldr ROTATE_TABLE_Q, .Lror\n\()_8_table +.endif + + // One-time XTS preparation +.if \n == 64 + // Load first tweak + ld1 {TWEAKV0.16b}, [TWEAK] + + // Load GF(2^128) multiplication table + ldr GFMUL_TABLE_Q, .Lgf128mul_table +.else + // Load first tweak + ld1 {TWEAKV0.8b}, [TWEAK] + + // Load GF(2^64) multiplication table + ldr GFMUL_TABLE_Q, .Lgf64mul_table + + // Calculate second tweak, packing it together with the first + ushr TMP0.2d, TWEAKV0.2d, #63 + shl TMP1.2d, TWEAKV0.2d, #1 + tbl TMP0.8b, {GFMUL_TABLE.16b}, TMP0.8b + eor TMP0.8b, TMP0.8b, TMP1.8b + mov TWEAKV0.d[1], TMP0.d[0] +.endif + +.Lnext_128bytes_\@: + + // Calculate XTS tweaks for next 128 bytes + _next_xts_tweak TWEAKV1, TWEAKV0, TMP0, \n + _next_xts_tweak TWEAKV2, TWEAKV1, TMP0, \n + _next_xts_tweak TWEAKV3, TWEAKV2, TMP0, \n + _next_xts_tweak TWEAKV4, TWEAKV3, TMP0, \n + _next_xts_tweak TWEAKV5, TWEAKV4, TMP0, \n + _next_xts_tweak TWEAKV6, TWEAKV5, TMP0, \n + _next_xts_tweak TWEAKV7, TWEAKV6, TMP0, \n + _next_xts_tweak TWEAKV_NEXT, TWEAKV7, TMP0, \n + + // Load the next source blocks into {X,Y}[0-3] + ld1 {X_0.16b-Y_1.16b}, [SRC], #64 + ld1 {X_2.16b-Y_3.16b}, [SRC], #64 + + // XOR the source blocks with their XTS tweaks + eor TMP0.16b, X_0.16b, TWEAKV0.16b + eor Y_0.16b, Y_0.16b, TWEAKV1.16b + eor TMP1.16b, X_1.16b, TWEAKV2.16b + eor Y_1.16b, Y_1.16b, TWEAKV3.16b + eor TMP2.16b, X_2.16b, TWEAKV4.16b + eor Y_2.16b, Y_2.16b, TWEAKV5.16b + eor TMP3.16b, X_3.16b, TWEAKV6.16b + eor Y_3.16b, Y_3.16b, TWEAKV7.16b + + /* + * De-interleave the 'x' and 'y' elements of each block, i.e. make it so + * that the X[0-3] registers contain only the second halves of blocks, + * and the Y[0-3] registers contain only the first halves of blocks. + * (Speck uses the order (y, x) rather than the more intuitive (x, y).) + */ + uzp2 X_0.\lanes, TMP0.\lanes, Y_0.\lanes + uzp1 Y_0.\lanes, TMP0.\lanes, Y_0.\lanes + uzp2 X_1.\lanes, TMP1.\lanes, Y_1.\lanes + uzp1 Y_1.\lanes, TMP1.\lanes, Y_1.\lanes + uzp2 X_2.\lanes, TMP2.\lanes, Y_2.\lanes + uzp1 Y_2.\lanes, TMP2.\lanes, Y_2.\lanes + uzp2 X_3.\lanes, TMP3.\lanes, Y_3.\lanes + uzp1 Y_3.\lanes, TMP3.\lanes, Y_3.\lanes + + // Do the cipher rounds + mov x6, ROUND_KEYS + mov w7, NROUNDS +.Lnext_round_\@: +.if \decrypting + ld1r {ROUND_KEY.\lanes}, [x6] + sub x6, x6, #( \n / 8 ) + _speck_unround_128bytes \n, \lanes +.else + ld1r {ROUND_KEY.\lanes}, [x6], #( \n / 8 ) + _speck_round_128bytes \n, \lanes +.endif + subs w7, w7, #1 + bne .Lnext_round_\@ + + // Re-interleave the 'x' and 'y' elements of each block + zip1 TMP0.\lanes, Y_0.\lanes, X_0.\lanes + zip2 Y_0.\lanes, Y_0.\lanes, X_0.\lanes + zip1 TMP1.\lanes, Y_1.\lanes, X_1.\lanes + zip2 Y_1.\lanes, Y_1.\lanes, X_1.\lanes + zip1 TMP2.\lanes, Y_2.\lanes, X_2.\lanes + zip2 Y_2.\lanes, Y_2.\lanes, X_2.\lanes + zip1 TMP3.\lanes, Y_3.\lanes, X_3.\lanes + zip2 Y_3.\lanes, Y_3.\lanes, X_3.\lanes + + // XOR the encrypted/decrypted blocks with the tweaks calculated earlier + eor X_0.16b, TMP0.16b, TWEAKV0.16b + eor Y_0.16b, Y_0.16b, TWEAKV1.16b + eor X_1.16b, TMP1.16b, TWEAKV2.16b + eor Y_1.16b, Y_1.16b, TWEAKV3.16b + eor X_2.16b, TMP2.16b, TWEAKV4.16b + eor Y_2.16b, Y_2.16b, TWEAKV5.16b + eor X_3.16b, TMP3.16b, TWEAKV6.16b + eor Y_3.16b, Y_3.16b, TWEAKV7.16b + mov TWEAKV0.16b, TWEAKV_NEXT.16b + + // Store the ciphertext in the destination buffer + st1 {X_0.16b-Y_1.16b}, [DST], #64 + st1 {X_2.16b-Y_3.16b}, [DST], #64 + + // Continue if there are more 128-byte chunks remaining + subs NBYTES, NBYTES, #128 + bne .Lnext_128bytes_\@ + + // Store the next tweak and return +.if \n == 64 + st1 {TWEAKV_NEXT.16b}, [TWEAK] +.else + st1 {TWEAKV_NEXT.8b}, [TWEAK] +.endif + ret +.endm + +ENTRY(speck128_xts_encrypt_neon) + _speck_xts_crypt n=64, lanes=2d, decrypting=0 +ENDPROC(speck128_xts_encrypt_neon) + +ENTRY(speck128_xts_decrypt_neon) + _speck_xts_crypt n=64, lanes=2d, decrypting=1 +ENDPROC(speck128_xts_decrypt_neon) + +ENTRY(speck64_xts_encrypt_neon) + _speck_xts_crypt n=32, lanes=4s, decrypting=0 +ENDPROC(speck64_xts_encrypt_neon) + +ENTRY(speck64_xts_decrypt_neon) + _speck_xts_crypt n=32, lanes=4s, decrypting=1 +ENDPROC(speck64_xts_decrypt_neon) diff --git a/arch/arm64/crypto/speck-neon-glue.c b/arch/arm64/crypto/speck-neon-glue.c new file mode 100644 index 000000000000..c7d18569d408 --- /dev/null +++ b/arch/arm64/crypto/speck-neon-glue.c @@ -0,0 +1,308 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS + * (64-bit version; based on the 32-bit version) + * + * Copyright (c) 2018 Google, Inc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* The assembly functions only handle multiples of 128 bytes */ +#define SPECK_NEON_CHUNK_SIZE 128 + +/* Speck128 */ + +struct speck128_xts_tfm_ctx { + struct speck128_tfm_ctx main_key; + struct speck128_tfm_ctx tweak_key; +}; + +asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *, + u8 *, const u8 *); +typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *, + const void *, unsigned int, void *); + +static __always_inline int +__speck128_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, + speck128_crypt_one_t crypt_one, + speck128_xts_crypt_many_t crypt_many) +{ + struct crypto_blkcipher *tfm = desc->tfm; + const struct speck128_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct blkcipher_walk walk; + le128 tweak; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE); + + crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; + u8 *dst = walk.dst.virt.addr; + const u8 *src = walk.src.virt.addr; + + if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { + unsigned int count; + + count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); + kernel_neon_begin(); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); + kernel_neon_end(); + dst += count; + src += count; + nbytes -= count; + } + + /* Handle any remainder with generic code */ + while (nbytes >= sizeof(tweak)) { + le128_xor((le128 *)dst, (const le128 *)src, &tweak); + (*crypt_one)(&ctx->main_key, dst, dst); + le128_xor((le128 *)dst, (const le128 *)dst, &tweak); + gf128mul_x_ble((be128 *)&tweak, (const be128 *)&tweak); + + dst += sizeof(tweak); + src += sizeof(tweak); + nbytes -= sizeof(tweak); + } + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int speck128_xts_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return __speck128_xts_crypt(desc, dst, src, nbytes, + crypto_speck128_encrypt, + speck128_xts_encrypt_neon); +} + +static int speck128_xts_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int nbytes) +{ + return __speck128_xts_crypt(desc, dst, src, nbytes, + crypto_speck128_decrypt, + speck128_xts_decrypt_neon); +} + +static int speck128_xts_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct speck128_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + if (keylen % 2) + return -EINVAL; + + keylen /= 2; + + err = crypto_speck128_setkey(&ctx->main_key, key, keylen); + if (err) + return err; + + return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen); +} + +/* Speck64 */ + +struct speck64_xts_tfm_ctx { + struct speck64_tfm_ctx main_key; + struct speck64_tfm_ctx tweak_key; +}; + +asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds, + void *dst, const void *src, + unsigned int nbytes, void *tweak); + +typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *, + u8 *, const u8 *); +typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *, + const void *, unsigned int, void *); + +static __always_inline int +__speck64_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, + struct scatterlist *src, unsigned int nbytes, + speck64_crypt_one_t crypt_one, + speck64_xts_crypt_many_t crypt_many) +{ + struct crypto_blkcipher *tfm = desc->tfm; + const struct speck64_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm); + struct blkcipher_walk walk; + __le64 tweak; + int err; + + blkcipher_walk_init(&walk, dst, src, nbytes); + err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE); + + crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv); + + while (walk.nbytes > 0) { + unsigned int nbytes = walk.nbytes; + u8 *dst = walk.dst.virt.addr; + const u8 *src = walk.src.virt.addr; + + if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) { + unsigned int count; + + count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE); + kernel_neon_begin(); + (*crypt_many)(ctx->main_key.round_keys, + ctx->main_key.nrounds, + dst, src, count, &tweak); + kernel_neon_end(); + dst += count; + src += count; + nbytes -= count; + } + + /* Handle any remainder with generic code */ + while (nbytes >= sizeof(tweak)) { + *(__le64 *)dst = *(__le64 *)src ^ tweak; + (*crypt_one)(&ctx->main_key, dst, dst); + *(__le64 *)dst ^= tweak; + tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^ + ((tweak & cpu_to_le64(1ULL << 63)) ? + 0x1B : 0)); + dst += sizeof(tweak); + src += sizeof(tweak); + nbytes -= sizeof(tweak); + } + err = blkcipher_walk_done(desc, &walk, nbytes); + } + + return err; +} + +static int speck64_xts_encrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return __speck64_xts_crypt(desc, dst, src, nbytes, + crypto_speck64_encrypt, + speck64_xts_encrypt_neon); +} + +static int speck64_xts_decrypt(struct blkcipher_desc *desc, + struct scatterlist *dst, struct scatterlist *src, + unsigned int nbytes) +{ + return __speck64_xts_crypt(desc, dst, src, nbytes, + crypto_speck64_decrypt, + speck64_xts_decrypt_neon); +} + +static int speck64_xts_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keylen) +{ + struct speck64_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm); + int err; + + if (keylen % 2) + return -EINVAL; + + keylen /= 2; + + err = crypto_speck64_setkey(&ctx->main_key, key, keylen); + if (err) + return err; + + return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen); +} + +static struct crypto_alg speck_algs[] = { + { + .cra_name = "xts(speck128)", + .cra_driver_name = "xts-speck128-neon", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SPECK128_BLOCK_SIZE, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx), + .cra_alignmask = 7, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * SPECK128_128_KEY_SIZE, + .max_keysize = 2 * SPECK128_256_KEY_SIZE, + .ivsize = SPECK128_BLOCK_SIZE, + .setkey = speck128_xts_setkey, + .encrypt = speck128_xts_encrypt, + .decrypt = speck128_xts_decrypt, + } + } + }, { + .cra_name = "xts(speck64)", + .cra_driver_name = "xts-speck64-neon", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SPECK64_BLOCK_SIZE, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx), + .cra_alignmask = 7, + .cra_module = THIS_MODULE, + .cra_u = { + .blkcipher = { + .min_keysize = 2 * SPECK64_96_KEY_SIZE, + .max_keysize = 2 * SPECK64_128_KEY_SIZE, + .ivsize = SPECK64_BLOCK_SIZE, + .setkey = speck64_xts_setkey, + .encrypt = speck64_xts_encrypt, + .decrypt = speck64_xts_decrypt, + } + } + } +}; + +static int __init speck_neon_module_init(void) +{ + if (!(elf_hwcap & HWCAP_ASIMD)) + return -ENODEV; + return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +static void __exit speck_neon_module_exit(void) +{ + crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs)); +} + +module_init(speck_neon_module_init); +module_exit(speck_neon_module_exit); + +MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biggers "); +MODULE_ALIAS_CRYPTO("xts(speck128)"); +MODULE_ALIAS_CRYPTO("xts-speck128-neon"); +MODULE_ALIAS_CRYPTO("xts(speck64)"); +MODULE_ALIAS_CRYPTO("xts-speck64-neon"); -- GitLab From 890962b83636836b044022773995d5ae558499ea Mon Sep 17 00:00:00 2001 From: Jeremy Boone Date: Thu, 8 Feb 2018 12:28:08 -0800 Subject: [PATCH 0585/1834] tpm: fix potential buffer overruns caused by bit glitches on the bus commit 3be23274755ee85771270a23af7691dc9b3a95db upstream. Discrete TPMs are often connected over slow serial buses which, on some platforms, can have glitches causing bit flips. If a bit does flip it could cause an overrun if it's in one of the size parameters, so sanity check that we're not overrunning the provided buffer when doing a memcpy(). Signed-off-by: Jeremy Boone Cc: stable@vger.kernel.org Signed-off-by: James Bottomley Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen Signed-off-by: James Morris Signed-off-by: Greg Kroah-Hartman --- drivers/char/tpm/tpm-interface.c | 5 +++++ drivers/char/tpm/tpm2-cmd.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index d0ac2d56520f..830d7e30e508 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1078,6 +1078,11 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) break; recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); + if (recd > num_bytes) { + total = -EFAULT; + break; + } + memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); dest += recd; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 17896d654033..a5780ebe15ef 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -668,6 +668,11 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, if (!rc) { data_len = be16_to_cpup( (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); + if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE + 1) { + rc = -EFAULT; + goto out; + } + data = &buf.data[TPM_HEADER_SIZE + 6]; memcpy(payload->key, data, data_len - 1); @@ -675,6 +680,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, payload->migratable = data[data_len - 1]; } +out: tpm_buf_destroy(&buf); return rc; } -- GitLab From 548af581f939bbad7fa21fa8dace32e5eef075e5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 17 May 2017 06:50:32 +0000 Subject: [PATCH 0586/1834] ASoC: rsnd: check src mod pointer for rsnd_mod_id() commit 374503c6109e60f48fa9b11341b14466f07bd3f4 upstream. Without this patch, gcc 4.9.x says sound/soc/sh/rcar/cmd.c: In function 'rsnd_cmd_init': sound/soc/sh/rcar/cmd.c:85:14: warning: array subscript is below array\ bounds [-Warray-bounds] data = path[rsnd_mod_id(src)] | Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- sound/soc/sh/rcar/cmd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c index 7d92a24b7cfa..98835e9d1d7d 100644 --- a/sound/soc/sh/rcar/cmd.c +++ b/sound/soc/sh/rcar/cmd.c @@ -82,6 +82,9 @@ static int rsnd_cmd_init(struct rsnd_mod *mod, [9] = 0x2, }; + if (unlikely(!src)) + return -EIO; + data = path[rsnd_mod_id(src)] | cmd_case[rsnd_mod_id(src)] << 16; } -- GitLab From fca16f9a02d9c44d8231ee52f84de3d57422bc3d Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 25 Oct 2017 15:58:31 -0500 Subject: [PATCH 0587/1834] SMB3: Validate negotiate request must always be signed commit 4587eee04e2ac7ac3ac9fa2bc164fb6e548f99cd upstream. According to MS-SMB2 3.2.55 validate_negotiate request must always be signed. Some Windows can fail the request if you send it unsigned See kernel bugzilla bug 197311 CC: Stable Acked-by: Ronnie Sahlberg Signed-off-by: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 94c4c1901222..4c2eaf05a6a4 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1712,6 +1712,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, } else iov[0].iov_len = get_rfc1002_length(req) + 4; + /* validate negotiate request must be signed - see MS-SMB2 3.2.5.5 */ + if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) + req->hdr.Flags |= SMB2_FLAGS_SIGNED; rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buftype, 0); rsp = (struct smb2_ioctl_rsp *)iov[0].iov_base; -- GitLab From df09b6f7b54adba78693997096d0bcb1bd80537c Mon Sep 17 00:00:00 2001 From: Pavel Shilovsky Date: Mon, 7 Nov 2016 18:20:50 -0800 Subject: [PATCH 0588/1834] CIFS: Enable encryption during session setup phase commit cabfb3680f78981d26c078a26e5c748531257ebb upstream. In order to allow encryption on SMB connection we need to exchange a session key and generate encryption and decryption keys. Signed-off-by: Pavel Shilovsky Cc: Steve French Signed-off-by: Greg Kroah-Hartman --- fs/cifs/sess.c | 22 ++++++++++------------ fs/cifs/smb2pdu.c | 12 ++---------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 538d9b55699a..c3db2a882aee 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -344,13 +344,12 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer, /* BB is NTLMV2 session security format easier to use here? */ flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; - if (ses->server->sign) { + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC | + NTLMSSP_NEGOTIATE_SEAL; + if (ses->server->sign) flags |= NTLMSSP_NEGOTIATE_SIGN; - if (!ses->server->session_estab || - ses->ntlmssp->sesskey_per_smbsess) - flags |= NTLMSSP_NEGOTIATE_KEY_XCH; - } + if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) + flags |= NTLMSSP_NEGOTIATE_KEY_XCH; sec_blob->NegotiateFlags = cpu_to_le32(flags); @@ -407,13 +406,12 @@ int build_ntlmssp_auth_blob(unsigned char **pbuffer, flags = NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC; - if (ses->server->sign) { + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC | + NTLMSSP_NEGOTIATE_SEAL; + if (ses->server->sign) flags |= NTLMSSP_NEGOTIATE_SIGN; - if (!ses->server->session_estab || - ses->ntlmssp->sesskey_per_smbsess) - flags |= NTLMSSP_NEGOTIATE_KEY_XCH; - } + if (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) + flags |= NTLMSSP_NEGOTIATE_KEY_XCH; tmp = *pbuffer + sizeof(AUTHENTICATE_MESSAGE); sec_blob->NegotiateFlags = cpu_to_le32(flags); diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 4c2eaf05a6a4..7c26286a525d 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -707,15 +707,13 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data) struct cifs_ses *ses = sess_data->ses; mutex_lock(&ses->server->srv_mutex); - if (ses->server->sign && ses->server->ops->generate_signingkey) { + if (ses->server->ops->generate_signingkey) { rc = ses->server->ops->generate_signingkey(ses); - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; if (rc) { cifs_dbg(FYI, "SMB3 session key generation failed\n"); mutex_unlock(&ses->server->srv_mutex); - goto keygen_exit; + return rc; } } if (!ses->server->session_estab) { @@ -729,12 +727,6 @@ SMB2_sess_establish_session(struct SMB2_sess_data *sess_data) ses->status = CifsGood; ses->need_reconnect = false; spin_unlock(&GlobalMid_Lock); - -keygen_exit: - if (!ses->server->sign) { - kfree(ses->auth_key.response); - ses->auth_key.response = NULL; - } return rc; } -- GitLab From d3c79a38843b7d44734dacc17694a72a0b269b74 Mon Sep 17 00:00:00 2001 From: Yisheng Xie Date: Wed, 28 Feb 2018 14:59:22 +0800 Subject: [PATCH 0589/1834] staging: android: ashmem: Fix possible deadlock in ashmem_ioctl commit 740a5759bf222332fbb5eda42f89aa25ba38f9b2 upstream. ashmem_mutex may create a chain of dependencies like: CPU0 CPU1 mmap syscall ioctl syscall -> mmap_sem (acquired) -> ashmem_ioctl -> ashmem_mmap -> ashmem_mutex (acquired) -> ashmem_mutex (try to acquire) -> copy_from_user -> mmap_sem (try to acquire) There is a lock odering problem between mmap_sem and ashmem_mutex causing a lockdep splat[1] during a syzcaller test. This patch fixes the problem by move copy_from_user out of ashmem_mutex. [1] https://www.spinics.net/lists/kernel/msg2733200.html Fixes: ce8a3a9e76d0 (staging: android: ashmem: Fix a race condition in pin ioctls) Reported-by: syzbot+d7a918a7a8e1c952bc36@syzkaller.appspotmail.com Signed-off-by: Yisheng Xie Cc: "Joel Fernandes (Google)" Signed-off-by: Greg Kroah-Hartman --- drivers/staging/android/ashmem.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index db100154f85c..6d690e5fa9bb 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -718,16 +718,14 @@ static int ashmem_pin_unpin(struct ashmem_area *asma, unsigned long cmd, size_t pgstart, pgend; int ret = -EINVAL; + if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) + return -EFAULT; + mutex_lock(&ashmem_mutex); if (unlikely(!asma->file)) goto out_unlock; - if (unlikely(copy_from_user(&pin, p, sizeof(pin)))) { - ret = -EFAULT; - goto out_unlock; - } - /* per custom, you can pass zero for len to mean "everything onward" */ if (!pin.len) pin.len = PAGE_ALIGN(asma->size) - pin.offset; -- GitLab From 2d07d7d7032c340564d84cedfba60a4d53355e95 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Mon, 19 Mar 2018 20:23:18 +0100 Subject: [PATCH 0590/1834] Revert "led: core: Fix brightness setting when setting delay_off=0" This reverts commit 86b9fa2190907f4f550d9d6bf490c5f89ca33836 which was commit 2b83ff96f51d0b039c4561b9f95c824d7bddb85c upstream. The commit being reverted has two flaws: - it introduces a regression, fixed in the upstream commit 7b6af2c53192f1766892ef40c8f48a413509ed72. - it has truncated commit message Reported-by: Sasha Levin Reported-by: Matthias Schiffer Signed-off-by: Jacek Anaszewski Signed-off-by: Greg Kroah-Hartman --- drivers/leds/led-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index d70d4a5273b8..3bce44893021 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -186,7 +186,7 @@ void led_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { - led_stop_software_blink(led_cdev); + del_timer_sync(&led_cdev->blink_timer); led_cdev->flags &= ~LED_BLINK_ONESHOT; led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; -- GitLab From d1ef7ed6e586ef69b366719bc37f1009e1d7d5d4 Mon Sep 17 00:00:00 2001 From: Jacek Anaszewski Date: Mon, 19 Mar 2018 20:23:19 +0100 Subject: [PATCH 0591/1834] led: core: Clear LED_BLINK_SW flag in led_blink_set() [Only needed in 4.9.y due to other fixes in mainline - gregkh] With the current code, the following sequence won't work : echo timer > trigger echo 0 > delay_off * at this point we call ** led_delay_off_store ** led_blink_set --- drivers/leds/led-core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c index 3bce44893021..454ed4dc6ec1 100644 --- a/drivers/leds/led-core.c +++ b/drivers/leds/led-core.c @@ -188,6 +188,7 @@ void led_blink_set(struct led_classdev *led_cdev, { del_timer_sync(&led_cdev->blink_timer); + led_cdev->flags &= ~LED_BLINK_SW; led_cdev->flags &= ~LED_BLINK_ONESHOT; led_cdev->flags &= ~LED_BLINK_ONESHOT_STOP; -- GitLab From 09604c91cb04979eff200d05e44df845cd0fb7cf Mon Sep 17 00:00:00 2001 From: Santeri Toivonen Date: Tue, 4 Apr 2017 21:09:00 +0300 Subject: [PATCH 0592/1834] platform/x86: asus-nb-wmi: Add wapf4 quirk for the X302UA [ Upstream commit f35823619db8bbaa2afea8705f239c3cecb9d22f ] Asus laptop X302UA starts up with Wi-Fi disabled, without a way to enable it. Set wapf=4 to fix the problem. Signed-off-by: Santeri Toivonen Signed-off-by: Darren Hart (VMware) Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 6eb2837f6b89..ab44326ea3e7 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -150,6 +150,15 @@ static const struct dmi_system_id asus_quirks[] = { */ .driver_data = &quirk_asus_wapf4, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X302UA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X302UA"), + }, + .driver_data = &quirk_asus_wapf4, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. X401U", -- GitLab From 86138a4972c4c347413f8461cd06f6a947947dfc Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Tue, 11 Apr 2017 22:36:00 -0700 Subject: [PATCH 0593/1834] bonding: handle link transition from FAIL to UP correctly [ Upstream commit fb9eb899a6dc663e4a2deed9af2ac28f507d0ffb ] When link transitions from LINK_FAIL to LINK_UP, the commit phase is not called. This leads to an erroneous state causing slave-link state to get stuck in "going down" state while its speed and duplex are perfectly fine. This issue is a side-effect of splitting link-set into propose and commit phases introduced by de77ecd4ef02 ("bonding: improve link-status update in mii-monitoring") This patch fixes these issues by calling commit phase whenever link state change is proposed. Fixes: de77ecd4ef02 ("bonding: improve link-status update in mii-monitoring") Signed-off-by: Mahesh Bandewar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index c3f3096b24ae..4907c9b57565 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2067,6 +2067,7 @@ static int bond_miimon_inspect(struct bonding *bond) (bond->params.downdelay - slave->delay) * bond->params.miimon, slave->dev->name); + commit++; continue; } @@ -2104,7 +2105,7 @@ static int bond_miimon_inspect(struct bonding *bond) (bond->params.updelay - slave->delay) * bond->params.miimon, slave->dev->name); - + commit++; continue; } -- GitLab From 8623759933ff15a3864d33225ad26ae87566655d Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Wed, 12 Apr 2017 09:58:47 +0800 Subject: [PATCH 0594/1834] regulator: anatop: set default voltage selector for pcie [ Upstream commit 9bf944548169f6153c3d3778cf983cb5db251a0e ] Set the initial voltage selector for vddpcie in case it's disabled by default. This fixes the below warning: 20c8000.anatop:regulator-vddpcie: Failed to read a valid default voltage selector. anatop_regulator: probe of 20c8000.anatop:regulator-vddpcie failed with error -22 Cc: Liam Girdwood Cc: Mark Brown Cc: Shawn Guo Cc: Sascha Hauer Cc: Robin Gong Cc: Richard Zhu Signed-off-by: Richard Zhu Signed-off-by: Dong Aisheng Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/regulator/anatop-regulator.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 3a6d0290c54c..c5e272ea4372 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -296,6 +296,11 @@ static int anatop_regulator_probe(struct platform_device *pdev) if (!sreg->sel && !strcmp(sreg->name, "vddpu")) sreg->sel = 22; + /* set the default voltage of the pcie phy to be 1.100v */ + if (!sreg->sel && rdesc->name && + !strcmp(rdesc->name, "vddpcie")) + sreg->sel = 0x10; + if (!sreg->bypass && !sreg->sel) { dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n"); return -EINVAL; -- GitLab From f15ea8e12821a5709b2eec406cbefa1dba27ff5b Mon Sep 17 00:00:00 2001 From: Liam Breck Date: Tue, 11 Apr 2017 04:59:54 -0700 Subject: [PATCH 0595/1834] power: supply: bq24190_charger: Limit over/under voltage fault logging [ Upstream commit d63d07c6fc25182af6d3ab5b3b8737b0c1025ebd ] If the charger is unplugged before the battery is full we may see an over/under voltage fault. Ignore this rather then emitting a message or uevent. This fixes messages like these getting logged on charger unplug + replug: bq24190-charger 15-006b: Fault: boost 0, charge 1, battery 0, ntc 0 bq24190-charger 15-006b: Fault: boost 0, charge 0, battery 0, ntc 0 Cc: Tony Lindgren Cc: Hans de Goede Signed-off-by: Liam Breck Acked-by: Tony Lindgren Reviewed-by: Hans de Goede Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/bq24190_charger.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index 50171fd3cc6d..cdd71ecd72ed 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1184,8 +1184,13 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data) } } while (f_reg && ++i < 2); + /* ignore over/under voltage fault after disconnect */ + if (f_reg == (1 << BQ24190_REG_F_CHRG_FAULT_SHIFT) && + !(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) + f_reg = 0; + if (f_reg != bdi->f_reg) { - dev_info(bdi->dev, + dev_warn(bdi->dev, "Fault: boost %d, charge %d, battery %d, ntc %d\n", !!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK), !!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK), -- GitLab From cd1ff13ae462558879061456667ca105e3c2f051 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 8 Apr 2017 19:54:20 +0200 Subject: [PATCH 0596/1834] x86: i8259: export legacy_pic symbol [ Upstream commit 7ee06cb2f840a96be46233181ed4557901a74385 ] The classic PC rtc-coms driver has a workaround for broken ACPI device nodes for it which lack an irq resource. This workaround used to unconditionally hardcode the irq to 8 in these cases. This was causing irq conflict problems on systems without a legacy-pic so a recent patch added an if (nr_legacy_irqs()) guard to the workaround to avoid this irq conflict. nr_legacy_irqs() uses the legacy_pic symbol under the hood causing an undefined symbol error if the rtc-cmos code is build as a module. This commit exports the legacy_pic symbol to fix this. Cc: rtc-linux@googlegroups.com Cc: alexandre.belloni@free-electrons.com Signed-off-by: Hans de Goede Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/i8259.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c index be22f5a2192e..4e3b8a587c88 100644 --- a/arch/x86/kernel/i8259.c +++ b/arch/x86/kernel/i8259.c @@ -418,6 +418,7 @@ struct legacy_pic default_legacy_pic = { }; struct legacy_pic *legacy_pic = &default_legacy_pic; +EXPORT_SYMBOL(legacy_pic); static int __init i8259A_init_ops(void) { -- GitLab From f114850808ea4aadc9d033f895ff024b7faf8dee Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 18 Mar 2017 14:45:49 +0100 Subject: [PATCH 0597/1834] rtc: cmos: Do not assume irq 8 for rtc when there are no legacy irqs [ Upstream commit a1e23a42f1bdc00e32fc4869caef12e4e6272f26 ] On some systems (e.g. Intel Bay Trail systems) the legacy PIC is not used, in this case virq 8 will be a random irq, rather then hw_irq 8 from the PIC. Requesting virq 8 in this case will not help us to get alarm irqs and may cause problems for other drivers which actually do need virq 8, for example on an Asus Transformer T100TA this leads to: [ 28.745155] genirq: Flags mismatch irq 8. 00000088 (mmc0) vs. 00000080 (rtc0) [ 28.753700] mmc0: Failed to request IRQ 8: -16 [ 28.975934] sdhci-acpi: probe of 80860F14:01 failed with error -16 This commit fixes this by making the rtc-cmos driver continue without using an irq rather then claiming irq 8 when no irq is specified in the pnp-info and there are no legacy-irqs. Signed-off-by: Hans de Goede Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-cmos.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 7030d7cd3861..c554e529fc4e 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -41,6 +41,9 @@ #include #include #include +#ifdef CONFIG_X86 +#include +#endif /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include @@ -1117,17 +1120,23 @@ static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) { cmos_wake_setup(&pnp->dev); - if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) + if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) { + unsigned int irq = 0; +#ifdef CONFIG_X86 /* Some machines contain a PNP entry for the RTC, but * don't define the IRQ. It should always be safe to - * hardcode it in these cases + * hardcode it on systems with a legacy PIC. */ + if (nr_legacy_irqs()) + irq = 8; +#endif return cmos_do_probe(&pnp->dev, - pnp_get_resource(pnp, IORESOURCE_IO, 0), 8); - else + pnp_get_resource(pnp, IORESOURCE_IO, 0), irq); + } else { return cmos_do_probe(&pnp->dev, pnp_get_resource(pnp, IORESOURCE_IO, 0), pnp_irq(pnp, 0)); + } } static void cmos_pnp_remove(struct pnp_dev *pnp) -- GitLab From 4dbe5cc3885b98f3a8e45065e42d90901c1f33c2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 12 Dec 2016 15:32:57 -0800 Subject: [PATCH 0598/1834] Input: ar1021_i2c - fix too long name in driver's device table [ Upstream commit 95123fc43560d6f4a60e74f72836e63cd8848f76 ] The name field in structure i2c_device_id is 20 characters, and we expect it to be NULL-terminated, however we are trying to stuff it with 21 bytes and thus NULL-terminator is lost. This causes issues when one creates device with name "MICROCHIP_AR1021_I2C" as i2c core cuts off the last "C", and automatic module loading by alias does not work as result. The -I2C suffix in the device name is superfluous, we know what bus we are dealing with, so let's drop it. Also, no other driver uses capitals, and the manufacturer name is normally not included, except in very rare cases of incompatible name collisions. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=116211 Fixes: dd4cae8bf166 ("Input: Add Microchip AR1021 i2c touchscreen") Reviewed-By: Christian Gmeiner Tested-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/ar1021_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 71b5a634cf6d..e7bb155911d0 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -152,7 +152,7 @@ static int __maybe_unused ar1021_i2c_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ar1021_i2c_pm, ar1021_i2c_suspend, ar1021_i2c_resume); static const struct i2c_device_id ar1021_i2c_id[] = { - { "MICROCHIP_AR1021_I2C", 0 }, + { "ar1021", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id); -- GitLab From 58e7fd9cae5f0b8deabfae1f1f87526b5a874e08 Mon Sep 17 00:00:00 2001 From: Deepa Dinamani Date: Sun, 26 Mar 2017 12:04:13 -0700 Subject: [PATCH 0599/1834] time: Change posix clocks ops interfaces to use timespec64 [ Upstream commit d340266e19ddb70dbd608f9deedcfb35fdb9d419 ] struct timespec is not y2038 safe on 32 bit machines. The posix clocks apis use struct timespec directly and through struct itimerspec. Replace the posix clock interfaces to use struct timespec64 and struct itimerspec64 instead. Also fix up their implementations accordingly. Note that the clock_getres() interface has also been changed to use timespec64 even though this particular interface is not affected by the y2038 problem. This helps verification for internal kernel code for y2038 readiness by getting rid of time_t/ timeval/ timespec. Signed-off-by: Deepa Dinamani Cc: arnd@arndb.de Cc: y2038@lists.linaro.org Cc: netdev@vger.kernel.org Cc: Richard Cochran Cc: john.stultz@linaro.org Link: http://lkml.kernel.org/r/1490555058-4603-3-git-send-email-deepa.kernel@gmail.com Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/ptp/ptp_clock.c | 18 +++++++----------- include/linux/posix-clock.h | 10 +++++----- kernel/time/posix-clock.c | 34 ++++++++++++++++++++++++---------- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index 86280b7e41f3..2aa5b37cc6d2 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -97,30 +97,26 @@ static s32 scaled_ppm_to_ppb(long ppm) /* posix clock implementation */ -static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp) +static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp) { tp->tv_sec = 0; tp->tv_nsec = 1; return 0; } -static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp) +static int ptp_clock_settime(struct posix_clock *pc, const struct timespec64 *tp) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); - struct timespec64 ts = timespec_to_timespec64(*tp); - return ptp->info->settime64(ptp->info, &ts); + return ptp->info->settime64(ptp->info, tp); } -static int ptp_clock_gettime(struct posix_clock *pc, struct timespec *tp) +static int ptp_clock_gettime(struct posix_clock *pc, struct timespec64 *tp) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); - struct timespec64 ts; int err; - err = ptp->info->gettime64(ptp->info, &ts); - if (!err) - *tp = timespec64_to_timespec(ts); + err = ptp->info->gettime64(ptp->info, tp); return err; } @@ -133,7 +129,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx) ops = ptp->info; if (tx->modes & ADJ_SETOFFSET) { - struct timespec ts; + struct timespec64 ts; ktime_t kt; s64 delta; @@ -146,7 +142,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx) if ((unsigned long) ts.tv_nsec >= NSEC_PER_SEC) return -EINVAL; - kt = timespec_to_ktime(ts); + kt = timespec64_to_ktime(ts); delta = ktime_to_ns(kt); err = ops->adjtime(ops, delta); } else if (tx->modes & ADJ_FREQUENCY) { diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h index 34c4498b800f..83b22ae9ae12 100644 --- a/include/linux/posix-clock.h +++ b/include/linux/posix-clock.h @@ -59,23 +59,23 @@ struct posix_clock_operations { int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx); - int (*clock_gettime)(struct posix_clock *pc, struct timespec *ts); + int (*clock_gettime)(struct posix_clock *pc, struct timespec64 *ts); - int (*clock_getres) (struct posix_clock *pc, struct timespec *ts); + int (*clock_getres) (struct posix_clock *pc, struct timespec64 *ts); int (*clock_settime)(struct posix_clock *pc, - const struct timespec *ts); + const struct timespec64 *ts); int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit); int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit); void (*timer_gettime)(struct posix_clock *pc, - struct k_itimer *kit, struct itimerspec *tsp); + struct k_itimer *kit, struct itimerspec64 *tsp); int (*timer_settime)(struct posix_clock *pc, struct k_itimer *kit, int flags, - struct itimerspec *tsp, struct itimerspec *old); + struct itimerspec64 *tsp, struct itimerspec64 *old); /* * Optional character device methods: */ diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c index 9cff0ab82b63..e24008c098c6 100644 --- a/kernel/time/posix-clock.c +++ b/kernel/time/posix-clock.c @@ -300,14 +300,17 @@ static int pc_clock_adjtime(clockid_t id, struct timex *tx) static int pc_clock_gettime(clockid_t id, struct timespec *ts) { struct posix_clock_desc cd; + struct timespec64 ts64; int err; err = get_clock_desc(id, &cd); if (err) return err; - if (cd.clk->ops.clock_gettime) - err = cd.clk->ops.clock_gettime(cd.clk, ts); + if (cd.clk->ops.clock_gettime) { + err = cd.clk->ops.clock_gettime(cd.clk, &ts64); + *ts = timespec64_to_timespec(ts64); + } else err = -EOPNOTSUPP; @@ -319,14 +322,17 @@ static int pc_clock_gettime(clockid_t id, struct timespec *ts) static int pc_clock_getres(clockid_t id, struct timespec *ts) { struct posix_clock_desc cd; + struct timespec64 ts64; int err; err = get_clock_desc(id, &cd); if (err) return err; - if (cd.clk->ops.clock_getres) - err = cd.clk->ops.clock_getres(cd.clk, ts); + if (cd.clk->ops.clock_getres) { + err = cd.clk->ops.clock_getres(cd.clk, &ts64); + *ts = timespec64_to_timespec(ts64); + } else err = -EOPNOTSUPP; @@ -337,6 +343,7 @@ static int pc_clock_getres(clockid_t id, struct timespec *ts) static int pc_clock_settime(clockid_t id, const struct timespec *ts) { + struct timespec64 ts64 = timespec_to_timespec64(*ts); struct posix_clock_desc cd; int err; @@ -350,7 +357,7 @@ static int pc_clock_settime(clockid_t id, const struct timespec *ts) } if (cd.clk->ops.clock_settime) - err = cd.clk->ops.clock_settime(cd.clk, ts); + err = cd.clk->ops.clock_settime(cd.clk, &ts64); else err = -EOPNOTSUPP; out: @@ -403,29 +410,36 @@ static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) { clockid_t id = kit->it_clock; struct posix_clock_desc cd; + struct itimerspec64 ts64; if (get_clock_desc(id, &cd)) return; - if (cd.clk->ops.timer_gettime) - cd.clk->ops.timer_gettime(cd.clk, kit, ts); - + if (cd.clk->ops.timer_gettime) { + cd.clk->ops.timer_gettime(cd.clk, kit, &ts64); + *ts = itimerspec64_to_itimerspec(&ts64); + } put_clock_desc(&cd); } static int pc_timer_settime(struct k_itimer *kit, int flags, struct itimerspec *ts, struct itimerspec *old) { + struct itimerspec64 ts64 = itimerspec_to_itimerspec64(ts); clockid_t id = kit->it_clock; struct posix_clock_desc cd; + struct itimerspec64 old64; int err; err = get_clock_desc(id, &cd); if (err) return err; - if (cd.clk->ops.timer_settime) - err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old); + if (cd.clk->ops.timer_settime) { + err = cd.clk->ops.timer_settime(cd.clk, kit, flags, &ts64, &old64); + if (old) + *old = itimerspec64_to_itimerspec(&old64); + } else err = -EOPNOTSUPP; -- GitLab From 723dde3922983e1eb5bbc336d826fe6eac57fc9a Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 12 Apr 2017 22:07:33 +0200 Subject: [PATCH 0600/1834] ACPI/processor: Fix error handling in __acpi_processor_start() [ Upstream commit a5cbdf693a60d5b86d4d21dfedd90f17754eb273 ] When acpi_install_notify_handler() fails the cooling device stays registered and the sysfs files created via acpi_pss_perf_init() are leaked and the function returns success. Undo acpi_pss_perf_init() and return a proper error code. Signed-off-by: Thomas Gleixner Cc: Fenghua Yu Cc: Tony Luck Cc: Herbert Xu Cc: "Rafael J. Wysocki" Cc: Peter Zijlstra Cc: Benjamin Herrenschmidt Cc: Sebastian Siewior Cc: Lai Jiangshan Cc: linux-acpi@vger.kernel.org Cc: Viresh Kumar Cc: Michael Ellerman Cc: Tejun Heo Cc: "David S. Miller" Cc: Len Brown Link: http://lkml.kernel.org/r/20170412201042.695499645@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_driver.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 9d5f0c7ed3f7..eab8cdad7dc3 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -251,6 +251,9 @@ static int __acpi_processor_start(struct acpi_device *device) if (ACPI_SUCCESS(status)) return 0; + result = -ENODEV; + acpi_pss_perf_exit(pr, device); + err_power_exit: acpi_processor_power_exit(pr); return result; -- GitLab From b7e5f1a204e1209c6abeda71956b58f0f6ee21fe Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 12 Apr 2017 22:07:34 +0200 Subject: [PATCH 0601/1834] ACPI/processor: Replace racy task affinity logic [ Upstream commit 8153f9ac43897f9f4786b30badc134fcc1a4fb11 ] acpi_processor_get_throttling() requires to invoke the getter function on the target CPU. This is achieved by temporarily setting the affinity of the calling user space thread to the requested CPU and reset it to the original affinity afterwards. That's racy vs. CPU hotplug and concurrent affinity settings for that thread resulting in code executing on the wrong CPU and overwriting the new affinity setting. acpi_processor_get_throttling() is invoked in two ways: 1) The CPU online callback, which is already running on the target CPU and obviously protected against hotplug and not affected by affinity settings. 2) The ACPI driver probe function, which is not protected against hotplug during modprobe. Switch it over to work_on_cpu() and protect the probe function against CPU hotplug. Signed-off-by: Thomas Gleixner Cc: Fenghua Yu Cc: Tony Luck Cc: Herbert Xu Cc: "Rafael J. Wysocki" Cc: Peter Zijlstra Cc: Benjamin Herrenschmidt Cc: Sebastian Siewior Cc: Lai Jiangshan Cc: linux-acpi@vger.kernel.org Cc: Viresh Kumar Cc: Michael Ellerman Cc: Tejun Heo Cc: "David S. Miller" Cc: Len Brown Link: http://lkml.kernel.org/r/20170412201042.785920903@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/processor_driver.c | 7 +++- drivers/acpi/processor_throttling.c | 62 +++++++++++++++++------------ 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index eab8cdad7dc3..8697a82bd465 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -262,11 +262,16 @@ static int __acpi_processor_start(struct acpi_device *device) static int acpi_processor_start(struct device *dev) { struct acpi_device *device = ACPI_COMPANION(dev); + int ret; if (!device) return -ENODEV; - return __acpi_processor_start(device); + /* Protect against concurrent CPU hotplug operations */ + get_online_cpus(); + ret = __acpi_processor_start(device); + put_online_cpus(); + return ret; } static int acpi_processor_stop(struct device *dev) diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index d51ca1c05619..207e9bbb9490 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -62,8 +62,8 @@ struct acpi_processor_throttling_arg { #define THROTTLING_POSTCHANGE (2) static int acpi_processor_get_throttling(struct acpi_processor *pr); -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force); +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct); static int acpi_processor_update_tsd_coord(void) { @@ -891,7 +891,8 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid throttling state, reset\n")); state = 0; - ret = acpi_processor_set_throttling(pr, state, true); + ret = __acpi_processor_set_throttling(pr, state, true, + true); if (ret) return ret; } @@ -901,36 +902,31 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr) return 0; } -static int acpi_processor_get_throttling(struct acpi_processor *pr) +static long __acpi_processor_get_throttling(void *data) { - cpumask_var_t saved_mask; - int ret; + struct acpi_processor *pr = data; + + return pr->throttling.acpi_processor_get_throttling(pr); +} +static int acpi_processor_get_throttling(struct acpi_processor *pr) +{ if (!pr) return -EINVAL; if (!pr->flags.throttling) return -ENODEV; - if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) - return -ENOMEM; - /* - * Migrate task to the cpu pointed by pr. + * This is either called from the CPU hotplug callback of + * processor_driver or via the ACPI probe function. In the latter + * case the CPU is not guaranteed to be online. Both call sites are + * protected against CPU hotplug. */ - cpumask_copy(saved_mask, ¤t->cpus_allowed); - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { - /* Can't migrate to the target pr->id CPU. Exit */ - free_cpumask_var(saved_mask); + if (!cpu_online(pr->id)) return -ENODEV; - } - ret = pr->throttling.acpi_processor_get_throttling(pr); - /* restore the previous state */ - set_cpus_allowed_ptr(current, saved_mask); - free_cpumask_var(saved_mask); - return ret; + return work_on_cpu(pr->id, __acpi_processor_get_throttling, pr); } static int acpi_processor_get_fadt_info(struct acpi_processor *pr) @@ -1080,8 +1076,15 @@ static long acpi_processor_throttling_fn(void *data) arg->target_state, arg->force); } -int acpi_processor_set_throttling(struct acpi_processor *pr, - int state, bool force) +static int call_on_cpu(int cpu, long (*fn)(void *), void *arg, bool direct) +{ + if (direct) + return fn(arg); + return work_on_cpu(cpu, fn, arg); +} + +static int __acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force, bool direct) { int ret = 0; unsigned int i; @@ -1130,7 +1133,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, arg.pr = pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, &arg, + direct); } else { /* * When the T-state coordination is SW_ALL or HW_ALL, @@ -1163,8 +1167,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, arg.pr = match_pr; arg.target_state = state; arg.force = force; - ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, - &arg); + ret = call_on_cpu(pr->id, acpi_processor_throttling_fn, + &arg, direct); } } /* @@ -1182,6 +1186,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, return ret; } +int acpi_processor_set_throttling(struct acpi_processor *pr, int state, + bool force) +{ + return __acpi_processor_set_throttling(pr, state, force, false); +} + int acpi_processor_get_throttling_info(struct acpi_processor *pr) { int result = 0; -- GitLab From ade9f4ba0d7af1ee2a310f1dda96c9174e35202b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 12 Apr 2017 22:07:36 +0200 Subject: [PATCH 0602/1834] cpufreq/sh: Replace racy task affinity logic [ Upstream commit 205dcc1ecbc566cbc20acf246e68de3b080b3ecf ] The target() callback must run on the affected cpu. This is achieved by temporarily setting the affinity of the calling thread to the requested CPU and reset it to the original affinity afterwards. That's racy vs. concurrent affinity settings for that thread resulting in code executing on the wrong CPU. Replace it by work_on_cpu(). All call pathes which invoke the callbacks are already protected against CPU hotplug. Signed-off-by: Thomas Gleixner Acked-by: Viresh Kumar Cc: Fenghua Yu Cc: Tony Luck Cc: Herbert Xu Cc: "Rafael J. Wysocki" Cc: Peter Zijlstra Cc: Benjamin Herrenschmidt Cc: Sebastian Siewior Cc: linux-pm@vger.kernel.org Cc: Lai Jiangshan Cc: Michael Ellerman Cc: Tejun Heo Cc: "David S. Miller" Cc: Len Brown Link: http://lkml.kernel.org/r/20170412201042.958216363@linutronix.de Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/cpufreq/sh-cpufreq.c | 45 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/drivers/cpufreq/sh-cpufreq.c b/drivers/cpufreq/sh-cpufreq.c index 86628e22b2a3..719c3d9f07fb 100644 --- a/drivers/cpufreq/sh-cpufreq.c +++ b/drivers/cpufreq/sh-cpufreq.c @@ -30,54 +30,63 @@ static DEFINE_PER_CPU(struct clk, sh_cpuclk); +struct cpufreq_target { + struct cpufreq_policy *policy; + unsigned int freq; +}; + static unsigned int sh_cpufreq_get(unsigned int cpu) { return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000; } -/* - * Here we notify other drivers of the proposed change and the final change. - */ -static int sh_cpufreq_target(struct cpufreq_policy *policy, - unsigned int target_freq, - unsigned int relation) +static long __sh_cpufreq_target(void *arg) { - unsigned int cpu = policy->cpu; + struct cpufreq_target *target = arg; + struct cpufreq_policy *policy = target->policy; + int cpu = policy->cpu; struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); - cpumask_t cpus_allowed; struct cpufreq_freqs freqs; struct device *dev; long freq; - cpus_allowed = current->cpus_allowed; - set_cpus_allowed_ptr(current, cpumask_of(cpu)); - - BUG_ON(smp_processor_id() != cpu); + if (smp_processor_id() != cpu) + return -ENODEV; dev = get_cpu_device(cpu); /* Convert target_freq from kHz to Hz */ - freq = clk_round_rate(cpuclk, target_freq * 1000); + freq = clk_round_rate(cpuclk, target->freq * 1000); if (freq < (policy->min * 1000) || freq > (policy->max * 1000)) return -EINVAL; - dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000); + dev_dbg(dev, "requested frequency %u Hz\n", target->freq * 1000); freqs.old = sh_cpufreq_get(cpu); freqs.new = (freq + 500) / 1000; freqs.flags = 0; - cpufreq_freq_transition_begin(policy, &freqs); - set_cpus_allowed_ptr(current, &cpus_allowed); + cpufreq_freq_transition_begin(target->policy, &freqs); clk_set_rate(cpuclk, freq); - cpufreq_freq_transition_end(policy, &freqs, 0); + cpufreq_freq_transition_end(target->policy, &freqs, 0); dev_dbg(dev, "set frequency %lu Hz\n", freq); - return 0; } +/* + * Here we notify other drivers of the proposed change and the final change. + */ +static int sh_cpufreq_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_target data = { .policy = policy, .freq = target_freq }; + + return work_on_cpu(policy->cpu, __sh_cpufreq_target, &data); +} + static int sh_cpufreq_verify(struct cpufreq_policy *policy) { struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu); -- GitLab From f2596a9808acfd02ce1ee389f0e1c37e64aec5f6 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 15 Apr 2017 12:08:31 +0200 Subject: [PATCH 0603/1834] genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs [ Upstream commit 382bd4de61827dbaaf5fb4fb7b1f4be4a86505e7 ] When requesting a shared irq with IRQF_TRIGGER_NONE then the irqaction flags get filled with the trigger type from the irq_data: if (!(new->flags & IRQF_TRIGGER_MASK)) new->flags |= irqd_get_trigger_type(&desc->irq_data); On the first setup_irq() the trigger type in irq_data is NONE when the above code executes, then the irq is started up for the first time and then the actual trigger type gets established, but that's too late to fix up new->flags. When then a second user of the irq requests the irq with IRQF_TRIGGER_NONE its irqaction's triggertype gets set to the actual trigger type and the following check fails: if (!((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) Resulting in the request_irq failing with -EBUSY even though both users requested the irq with IRQF_SHARED | IRQF_TRIGGER_NONE Fix this by comparing the new irqaction's trigger type to the trigger type stored in the irq_data which correctly reflects the actual trigger type being used for the irq. Suggested-by: Thomas Gleixner Signed-off-by: Hans de Goede Acked-by: Marc Zyngier Link: http://lkml.kernel.org/r/20170415100831.17073-1-hdegoede@redhat.com Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ea41820ab12e..ed18aa4dceab 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1210,8 +1210,10 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) * set the trigger type must match. Also all must * agree on ONESHOT. */ + unsigned int oldtype = irqd_get_trigger_type(&desc->irq_data); + if (!((old->flags & new->flags) & IRQF_SHARED) || - ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || + (oldtype != (new->flags & IRQF_TRIGGER_MASK)) || ((old->flags ^ new->flags) & IRQF_ONESHOT)) goto mismatch; -- GitLab From 8cda29d440c39e267ab67217171ed708ac27a0b4 Mon Sep 17 00:00:00 2001 From: Edgar Cherkasov Date: Tue, 4 Apr 2017 19:18:27 +0300 Subject: [PATCH 0604/1834] i2c: i2c-scmi: add a MS HID [ Upstream commit e058e7a4bc89104540a8a303682248614b5df6f1 ] Description of the problem: - i2c-scmi driver contains only two identifiers "SMBUS01" and "SMBUSIBM"; - the fist HID (SMBUS01) is clearly defined in "SMBus Control Method Interface Specification, version 1.0": "Each device must specify 'SMBUS01' as its _HID and use a unique _UID value"; - unfortunately, BIOS vendors (like AMI) seem to ignore this requirement and implement "SMB0001" HID instead of "SMBUS01"; - I speculate that they do this because only "SMB0001" is hard coded in Windows SMBus driver produced by Microsoft. This leads to following situation: - SMBus works out of box in Windows but not in Linux; - board vendors are forced to add correct "SMBUS01" HID to BIOS to make SMBus work in Linux. Moreover the same board vendors complain that tools (3-rd party ASL compiler) do not like the "SMBUS01" identifier and produce errors. So they need to constantly patch the compiler for each new version of BIOS. As it is very unlikely that BIOS vendors implement a correct HID in future, I would propose to consider whether it is possible to work around the problem by adding MS HID to the Linux i2c-scmi driver. v2: move the definition of the new HID to the driver itself. Signed-off-by: Edgar Cherkasov Signed-off-by: Michael Brunner Acked-by: Viktor Krasnov Reviewed-by: Jean Delvare Reviewed-by: Mika Westerberg Signed-off-by: Wolfram Sang Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/busses/i2c-scmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index dfc98df7b1b6..7aa7b9cb6203 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -18,6 +18,9 @@ #define ACPI_SMBUS_HC_CLASS "smbus" #define ACPI_SMBUS_HC_DEVICE_NAME "cmi" +/* SMBUS HID definition as supported by Microsoft Windows */ +#define ACPI_SMBUS_MS_HID "SMB0001" + ACPI_MODULE_NAME("smbus_cmi"); struct smbus_methods_t { @@ -51,6 +54,7 @@ static const struct smbus_methods_t ibm_smbus_methods = { static const struct acpi_device_id acpi_smbus_cmi_ids[] = { {"SMBUS01", (kernel_ulong_t)&smbus_methods}, {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, + {ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods}, {"", 0} }; MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); -- GitLab From 2bea4875294f1715e2b52dd66d8b666d733f1308 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 12 Apr 2017 11:49:04 -0700 Subject: [PATCH 0605/1834] net: ipv6: send unsolicited NA on admin up [ Upstream commit 4a6e3c5def13c91adf2acc613837001f09af3baa ] ndisc_notify is the ipv6 equivalent to arp_notify. When arp_notify is set to 1, gratuitous arp requests are sent when the device is brought up. The same is expected when ndisc_notify is set to 1 (per ndisc_notify in Documentation/networking/ip-sysctl.txt). The NA is not sent on NETDEV_UP event; add it. Fixes: 5cb04436eef6 ("ipv6: add knob to send unsolicited ND on link-layer address change") Signed-off-by: David Ahern Acked-by: Hannes Frederic Sowa Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ndisc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d8e671457d10..41c22cb33424 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1723,6 +1723,8 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); fib6_run_gc(0, net, false); + /* fallthrough */ + case NETDEV_UP: idev = in6_dev_get(dev); if (!idev) break; -- GitLab From 355edc25c3f9b5171abaea2a160c569a1e52f4d2 Mon Sep 17 00:00:00 2001 From: Jasmin J Date: Fri, 17 Mar 2017 23:04:20 -0300 Subject: [PATCH 0606/1834] media/dvb-core: Race condition when writing to CAM [ Upstream commit e7080d4471d805d921a9ea21b32f911a91e248cb ] It started with a sporadic message in syslog: "CAM tried to send a buffer larger than the ecount size" This message is not the fault itself, but a consecutive fault, after a read error from the CAM. This happens only on several CAMs, several hardware, and of course sporadic. It is a consecutive fault, if the last read from the CAM did fail. I guess this will not happen on all CAMs, but at least it did on mine. There was a write error to the CAM and during the re-initialization procedure, the CAM finished the last read, although it got a RS. The write error to the CAM happened because a race condition between HC write, checking DA and FR. This patch added an additional check for DA(RE), just after checking FR. It is important to read the CAMs status register again, to give the CAM the necessary time for a proper reaction to HC. Please note the description within the source code (patch below). [mchehab@s-opensource.com: make checkpatch happy] Signed-off-by: Jasmin jessich Tested-by: Ralph Metzler Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb-core/dvb_ca_en50221.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index b5b5b195ea7f..42ce88ceac66 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -779,6 +779,29 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * b goto exit; } + /* + * It may need some time for the CAM to settle down, or there might + * be a race condition between the CAM, writing HC and our last + * check for DA. This happens, if the CAM asserts DA, just after + * checking DA before we are setting HC. In this case it might be + * a bug in the CAM to keep the FR bit, the lower layer/HW + * communication requires a longer timeout or the CAM needs more + * time internally. But this happens in reality! + * We need to read the status from the HW again and do the same + * we did for the previous check for DA + */ + status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); + if (status < 0) + goto exit; + + if (status & (STATUSREG_DA | STATUSREG_RE)) { + if (status & STATUSREG_DA) + dvb_ca_en50221_thread_wakeup(ca); + + status = -EAGAIN; + goto exit; + } + /* send the amount of data */ if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) goto exit; -- GitLab From 4bd1761b69f3e627dfb5fc6c2ac38e451e9e67c8 Mon Sep 17 00:00:00 2001 From: Adam Borowski Date: Tue, 7 Mar 2017 23:34:44 +0100 Subject: [PATCH 0607/1834] btrfs: fix a bogus warning when converting only data or metadata [ Upstream commit 14506127979a5a3d0c5d9b4cc76ce9d4ec23b717 ] If your filesystem has, eg, data:raid0 metadata:raid1, and you run "btrfs balance -dconvert=raid1", the meta.target field will be uninitialized. That's otherwise ok, as it's unused except for this warning. Thus, let's use the existing set of raid levels for the comparison. As a side effect, non-convert balances will now nag about data>metadata. Signed-off-by: Adam Borowski Reviewed-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/volumes.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 5900508ca6ed..4730ba2cc049 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3765,6 +3765,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl, struct btrfs_ioctl_balance_args *bargs) { struct btrfs_fs_info *fs_info = bctl->fs_info; + u64 meta_target, data_target; u64 allowed; int mixed = 0; int ret; @@ -3861,11 +3862,16 @@ int btrfs_balance(struct btrfs_balance_control *bctl, } } while (read_seqretry(&fs_info->profiles_lock, seq)); - if (btrfs_get_num_tolerated_disk_barrier_failures(bctl->meta.target) < - btrfs_get_num_tolerated_disk_barrier_failures(bctl->data.target)) { + /* if we're not converting, the target field is uninitialized */ + meta_target = (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) ? + bctl->meta.target : fs_info->avail_metadata_alloc_bits; + data_target = (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) ? + bctl->data.target : fs_info->avail_data_alloc_bits; + if (btrfs_get_num_tolerated_disk_barrier_failures(meta_target) < + btrfs_get_num_tolerated_disk_barrier_failures(data_target)) { btrfs_warn(fs_info, "metadata profile 0x%llx has lower redundancy than data profile 0x%llx", - bctl->meta.target, bctl->data.target); + meta_target, data_target); } if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { -- GitLab From 92bfedfa933ef9aa5fded7de9415d09c1dcd3200 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 17 Apr 2017 10:04:07 -0500 Subject: [PATCH 0608/1834] ASoC: Intel: Atom: update Thinkpad 10 quirk [ Upstream commit beb5989a8c6c6867b4e873cca2a66d31f977368f ] There are multiple skews of the same Lenovo audio hardware based on the Realtek RT5670 codec. Manufacturer: LENOVO Product Name: 20C1CTO1WW Version: ThinkPad 10 Manufacturer: LENOVO Product Name: 20C3001VHH Version: ThinkPad 10 Manufacturer: LENOVO Product Name: 20C10024GE Version: ThinkPad Tablet B Manufacturer: LENOVO Product Name: 20359 Version: Lenovo Miix 2 10 For all these devices, the same quirk is used to force the machine driver to be based on RT5670 instead of RT5640 as indicated by the BIOS. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96691 Tested-by: Nicole Faerber Tested-by: Viacheslav Ostroukh Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/atom/sst/sst_acpi.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 0bfa68862460..cd16b431d1bd 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -420,7 +420,21 @@ static const struct dmi_system_id byt_table[] = { .callback = byt_thinkpad10_quirk_cb, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_NAME, "20C3001VHH"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad 10"), + }, + }, + { + .callback = byt_thinkpad10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad Tablet B"), + }, + }, + { + .callback = byt_thinkpad10_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Miix 2 10"), }, }, { } -- GitLab From 61ea482ba847c373e2dd7c5de9132d9ca47cf90a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 13 Apr 2017 23:14:34 -0700 Subject: [PATCH 0609/1834] tools/testing/nvdimm: fix nfit_test shutdown crash [ Upstream commit 8b06b884cd98f7ec8b5028680b99fabfb7b3e192 ] Keep the nfit_test instances alive until after nfit_test_teardown(), as we may be doing resource lookups until the final un-registrations have completed. This fixes crashes of the form. BUG: unable to handle kernel NULL pointer dereference at 0000000000000038 IP: __release_resource+0x12/0x90 Call Trace: remove_resource+0x23/0x40 __wrap_remove_resource+0x29/0x30 [nfit_test_iomap] acpi_nfit_remove_resource+0xe/0x10 [nfit] devm_action_release+0xf/0x20 release_nodes+0x16d/0x2b0 devres_release_all+0x3c/0x60 device_release+0x21/0x90 kobject_release+0x6a/0x170 kobject_put+0x2f/0x60 put_device+0x17/0x20 platform_device_unregister+0x20/0x30 nfit_test_exit+0x36/0x960 [nfit_test] Reported-by: Linda Knippers Signed-off-by: Dan Williams Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/nvdimm/test/nfit.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 71620fa95953..d025eafc09c2 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -1908,6 +1908,7 @@ static __init int nfit_test_init(void) put_device(&pdev->dev); goto err_register; } + get_device(&pdev->dev); rc = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rc) @@ -1926,6 +1927,10 @@ static __init int nfit_test_init(void) if (instances[i]) platform_device_unregister(&instances[i]->pdev); nfit_test_teardown(); + for (i = 0; i < NUM_NFITS; i++) + if (instances[i]) + put_device(&instances[i]->pdev.dev); + return rc; } @@ -1933,10 +1938,13 @@ static __exit void nfit_test_exit(void) { int i; - platform_driver_unregister(&nfit_test_driver); for (i = 0; i < NUM_NFITS; i++) platform_device_unregister(&instances[i]->pdev); + platform_driver_unregister(&nfit_test_driver); nfit_test_teardown(); + + for (i = 0; i < NUM_NFITS; i++) + put_device(&instances[i]->pdev.dev); class_destroy(nfit_test_dimm); } -- GitLab From f5df9a59c68ea8272960cb88d31434ccb69b3510 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Tue, 18 Apr 2017 20:09:06 +0200 Subject: [PATCH 0610/1834] spi: dw: Disable clock after unregistering the host [ Upstream commit 400c18e3dc86e04ef5afec9b86a8586ca629b9e9 ] The dw_mmio driver disables the block clock before unregistering the host. The code unregistering the host may access the SPI block registers. If register access happens with block clock disabled, this may lead to a bus hang. Disable the clock after unregistering the host to prevent such situation. This bug was observed on Altera Cyclone V SoC. Signed-off-by: Marek Vasut Cc: Andy Shevchenko Cc: Mark Brown Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-dw-mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 447497e9124c..d25cc4037e23 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -115,8 +115,8 @@ static int dw_spi_mmio_remove(struct platform_device *pdev) { struct dw_spi_mmio *dwsmmio = platform_get_drvdata(pdev); - clk_disable_unprepare(dwsmmio->clk); dw_spi_remove_host(&dwsmmio->dws); + clk_disable_unprepare(dwsmmio->clk); return 0; } -- GitLab From 3095a0dc94b82910627ec18ddae50a8b0fc718b6 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 19 Apr 2017 12:27:38 +1000 Subject: [PATCH 0611/1834] powerpc/64s: Remove SAO feature from Power9 DD1 [ Upstream commit ca80d5d0a8175c9be04cfbce24180b8f5e0a744b ] Power9 DD1 does not implement SAO. Although it's not widely used, its presence or absence is visible to user space via arch_validate_prot() so it's moderately important that we get the value right. Fixes: 7dccfbc325bb ("powerpc/book3s: Add a cpu table entry for different POWER9 revs") Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/cputable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index ab68d0ee7725..4e54282c29b4 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -474,7 +474,8 @@ enum { CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \ CPU_FTR_DBELL | CPU_FTR_HAS_PPR | CPU_FTR_DAWR | \ CPU_FTR_ARCH_207S | CPU_FTR_TM_COMP | CPU_FTR_ARCH_300) -#define CPU_FTRS_POWER9_DD1 (CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) +#define CPU_FTRS_POWER9_DD1 ((CPU_FTRS_POWER9 | CPU_FTR_POWER9_DD1) & \ + (~CPU_FTR_SAO)) #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \ -- GitLab From 723052b2540bf8bea0df3b73547c75c50bdd86ae Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Wed, 12 Apr 2017 23:19:37 +0530 Subject: [PATCH 0612/1834] ath: Fix updating radar flags for coutry code India [ Upstream commit c0c345d4cacc6a1f39d4856f37dcf6e34f51a5e4 ] As per latest regulatory update for India, channel 52, 56, 60, 64 is no longer restricted to DFS. Enabling DFS/no infra flags in driver results in applying all DFS related restrictions (like doing CAC etc before this channel moves to 'available state') for these channels even though the country code is programmed as 'India' in he hardware, fix this by relaxing the frequency range while applying RADAR flags only if the country code is programmed to India. If the frequency range needs to modified based on different country code, ath_is_radar_freq can be extended/modified dynamically. Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/regd.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index f8506037736f..404fc306cb2a 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -254,8 +254,12 @@ bool ath_is_49ghz_allowed(u16 regdomain) EXPORT_SYMBOL(ath_is_49ghz_allowed); /* Frequency is one where radar detection is required */ -static bool ath_is_radar_freq(u16 center_freq) +static bool ath_is_radar_freq(u16 center_freq, + struct ath_regulatory *reg) + { + if (reg->country_code == CTRY_INDIA) + return (center_freq >= 5500 && center_freq <= 5700); return (center_freq >= 5260 && center_freq <= 5700); } @@ -306,7 +310,7 @@ __ath_reg_apply_beaconing_flags(struct wiphy *wiphy, enum nl80211_reg_initiator initiator, struct ieee80211_channel *ch) { - if (ath_is_radar_freq(ch->center_freq) || + if (ath_is_radar_freq(ch->center_freq, reg) || (ch->flags & IEEE80211_CHAN_RADAR)) return; @@ -395,8 +399,9 @@ ath_reg_apply_ir_flags(struct wiphy *wiphy, } } -/* Always apply Radar/DFS rules on freq range 5260 MHz - 5700 MHz */ -static void ath_reg_apply_radar_flags(struct wiphy *wiphy) +/* Always apply Radar/DFS rules on freq range 5500 MHz - 5700 MHz */ +static void ath_reg_apply_radar_flags(struct wiphy *wiphy, + struct ath_regulatory *reg) { struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; @@ -409,7 +414,7 @@ static void ath_reg_apply_radar_flags(struct wiphy *wiphy) for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; - if (!ath_is_radar_freq(ch->center_freq)) + if (!ath_is_radar_freq(ch->center_freq, reg)) continue; /* We always enable radar detection/DFS on this * frequency range. Additionally we also apply on @@ -505,7 +510,7 @@ void ath_reg_notifier_apply(struct wiphy *wiphy, struct ath_common *common = container_of(reg, struct ath_common, regulatory); /* We always apply this */ - ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_radar_flags(wiphy, reg); /* * This would happen when we have sent a custom regulatory request @@ -653,7 +658,7 @@ ath_regd_init_wiphy(struct ath_regulatory *reg, } wiphy_apply_custom_regulatory(wiphy, regd); - ath_reg_apply_radar_flags(wiphy); + ath_reg_apply_radar_flags(wiphy, reg); ath_reg_apply_world_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER, reg); return 0; } -- GitLab From cfa8803d3876f8842152df5034b4434930efd1f5 Mon Sep 17 00:00:00 2001 From: Bharat Kumar Reddy Gooty Date: Mon, 20 Mar 2017 18:12:14 -0400 Subject: [PATCH 0613/1834] clk: ns2: Correct SDIO bits [ Upstream commit 8973aa4aecac223548366ca81818309a0f0efa6d ] Corrected the bits for power and iso. Signed-off-by: Bharat Kumar Reddy Gooty Signed-off-by: Jon Mason Fixes: f7225a83 ("clk: ns2: add clock support for Broadcom Northstar 2 SoC") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/bcm/clk-ns2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-ns2.c b/drivers/clk/bcm/clk-ns2.c index a564e9248814..adc14145861a 100644 --- a/drivers/clk/bcm/clk-ns2.c +++ b/drivers/clk/bcm/clk-ns2.c @@ -103,7 +103,7 @@ CLK_OF_DECLARE(ns2_genpll_src_clk, "brcm,ns2-genpll-scr", static const struct iproc_pll_ctrl genpll_sw = { .flags = IPROC_CLK_AON | IPROC_CLK_PLL_SPLIT_STAT_CTRL, - .aon = AON_VAL(0x0, 2, 9, 8), + .aon = AON_VAL(0x0, 1, 11, 10), .reset = RESET_VAL(0x4, 2, 1), .dig_filter = DF_VAL(0x0, 9, 3, 5, 4, 2, 3), .ndiv_int = REG_VAL(0x8, 4, 10), -- GitLab From e2b737ef004896714a3f73c9bab0444da8dfc7b7 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 13 Feb 2017 11:29:16 +0200 Subject: [PATCH 0614/1834] iwlwifi: split the handler and the wake parts of the notification infra [ Upstream commit 2220fb2960b72915e7fd9da640a4695dceff238c ] The notification infrastructure (iwl_notification_wait_* functions) allows to wait until a list of notifications will come up from the firmware and to run a special handler (notif_wait handler) when those are received. The operation mode notifies the notification infrastructure about any Rx being received by the mean of iwl_notification_wait_notify() which will do two things: 1) call the notif_wait handler 2) wakeup the thread that was waiting for the notification Typically, only after those two steps happened, the operation mode will run its own handler for the notification that was received from the firmware. This means that the thread that was waiting for that notification can be running before the operation mode's handler was called. When the operation mode's handler is ASYNC, things get even worse since the thread that was waiting for the notification isn't even guaranteed that the ASYNC callback was added to async_handlers_list before it starts to run. This means that even calling iwl_mvm_wait_for_async_handlers() can't guarantee that absolutely everything related to that notification has run. The following can happen: Thread sending the command Operation mode's Rx path -------------------------- ------------------------ iwl_init_notification_wait() iwl_mvm_send_cmd() iwl_mvm_rx_common() iwl_notification_wait_notify() iwl_mvm_wait_for_async_handlers() // Possibly free some data // structure list_add_tail(async_handlers_list); schedule_work(async_handlers_wk); // Access the freed structure Split the 'run notif_wait's handler' and the 'wake up the thread' parts to fix this. This allows the operation mode to do the following: Thread sending the command Operation mode's Rx path -------------------------- ------------------------ iwl_init_notification_wait() iwl_mvm_send_cmd() iwl_mvm_rx_common() iwl_notification_wait() // Will run the notif_wait's handler list_add_tail(async_handlers_list); schedule_work(async_handlers_wk); iwl_notification_notify() iwl_mvm_wait_for_async_handlers() This way, the waiter is guaranteed that all the handlers have been run (if SYNC), or at least enqueued (if ASYNC) by the time it wakes up. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../wireless/intel/iwlwifi/iwl-notif-wait.c | 10 +++----- .../wireless/intel/iwlwifi/iwl-notif-wait.h | 25 +++++++++++++++---- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c index 88f260db3744..68412ff2112e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.c @@ -76,8 +76,8 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait) } IWL_EXPORT_SYMBOL(iwl_notification_wait_init); -void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, - struct iwl_rx_packet *pkt) +bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait, + struct iwl_rx_packet *pkt) { bool triggered = false; @@ -118,13 +118,11 @@ void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, } } spin_unlock(¬if_wait->notif_wait_lock); - } - if (triggered) - wake_up_all(¬if_wait->notif_waitq); + return triggered; } -IWL_EXPORT_SYMBOL(iwl_notification_wait_notify); +IWL_EXPORT_SYMBOL(iwl_notification_wait); void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait) { diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h index 0f9995ed71cd..368884be4e7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-notif-wait.h @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright(c) 2015 Intel Deutschland GmbH + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -32,6 +32,7 @@ * BSD LICENSE * * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 - 2017 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -89,10 +90,10 @@ struct iwl_notif_wait_data { * * This structure is not used directly, to wait for a * notification declare it on the stack, and call - * iwlagn_init_notification_wait() with appropriate + * iwl_init_notification_wait() with appropriate * parameters. Then do whatever will cause the ucode * to notify the driver, and to wait for that then - * call iwlagn_wait_notification(). + * call iwl_wait_notification(). * * Each notification is one-shot. If at some point we * need to support multi-shot notifications (which @@ -114,10 +115,24 @@ struct iwl_notification_wait { /* caller functions */ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_data); -void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data, - struct iwl_rx_packet *pkt); +bool iwl_notification_wait(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt); void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data); +static inline void +iwl_notification_notify(struct iwl_notif_wait_data *notif_data) +{ + wake_up_all(¬if_data->notif_waitq); +} + +static inline void +iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data, + struct iwl_rx_packet *pkt) +{ + if (iwl_notification_wait(notif_data, pkt)) + iwl_notification_notify(notif_data); +} + /* user functions */ void __acquires(wait_entry) iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data, -- GitLab From 0bb43a3a7542c907d2c32e811d75faed6d55eda1 Mon Sep 17 00:00:00 2001 From: Liad Kaufman Date: Sun, 19 Feb 2017 10:42:40 +0200 Subject: [PATCH 0615/1834] iwlwifi: a000: fix memory offsets and lengths [ Upstream commit f4d1047914ea05e0f8393944da18f6ee5dad24c4 ] Memory offsets and lengths for A000 HW is different than currently specified. Fixes: e34d975e40ff ("iwlwifi: Add a000 HW family support") Signed-off-by: Liad Kaufman Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/iwl-a000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c index ea1618525878..e267377edbe7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-a000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-a000.c @@ -65,12 +65,12 @@ #define IWL_A000_TX_POWER_VERSION 0xffff /* meaningless */ /* Memory offsets and lengths */ -#define IWL_A000_DCCM_OFFSET 0x800000 -#define IWL_A000_DCCM_LEN 0x18000 +#define IWL_A000_DCCM_OFFSET 0x800000 /* LMAC1 */ +#define IWL_A000_DCCM_LEN 0x10000 /* LMAC1 */ #define IWL_A000_DCCM2_OFFSET 0x880000 #define IWL_A000_DCCM2_LEN 0x8000 #define IWL_A000_SMEM_OFFSET 0x400000 -#define IWL_A000_SMEM_LEN 0x68000 +#define IWL_A000_SMEM_LEN 0xD0000 #define IWL_A000_FW_PRE "iwlwifi-Qu-a0-jf-b0-" #define IWL_A000_MODULE_FIRMWARE(api) \ -- GitLab From 489e563cd3e1086ef30ac0b3a4a76ef25b8e3ff2 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Thu, 13 Apr 2017 12:13:00 +1000 Subject: [PATCH 0616/1834] scsi: virtio_scsi: Always try to read VPD pages [ Upstream commit 25d1d50e23275e141e3a3fe06c25a99f4c4bf4e0 ] Passed through SCSI targets may have transfer limits which come from the host SCSI controller or something on the host side other than the target itself. To make this work properly, the hypervisor can adjust the target's VPD information to advertise these limits. But for that to work, the guest has to look at the VPD pages, which we won't do by default if it is an SPC-2 device, even if it does actually support it. This adds a workaround to address this, forcing devices attached to a virtio-scsi controller to always check the VPD pages. This is modelled on a similar workaround for the storvsc (Hyper-V) SCSI controller, although that exists for slightly different reasons. A specific case which causes this is a volume from IBM's IPR RAID controller (which presents as an SPC-2 device, although it does support VPD) passed through with qemu's 'scsi-block' device. [mkp: fixed typo] Signed-off-by: David Gibson Acked-by: Paolo Bonzini Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/virtio_scsi.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index c680d7641311..8f4adc1d9588 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #define VIRTIO_SCSI_MEMPOOL_SZ 64 @@ -705,6 +706,28 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc) return virtscsi_tmf(vscsi, cmd); } +static int virtscsi_device_alloc(struct scsi_device *sdevice) +{ + /* + * Passed through SCSI targets (e.g. with qemu's 'scsi-block') + * may have transfer limits which come from the host SCSI + * controller or something on the host side other than the + * target itself. + * + * To make this work properly, the hypervisor can adjust the + * target's VPD information to advertise these limits. But + * for that to work, the guest has to look at the VPD pages, + * which we won't do by default if it is an SPC-2 device, even + * if it does actually support it. + * + * So, set the blist to always try to read the VPD pages. + */ + sdevice->sdev_bflags = BLIST_TRY_VPD_PAGES; + + return 0; +} + + /** * virtscsi_change_queue_depth() - Change a virtscsi target's queue depth * @sdev: Virtscsi target whose queue depth to change @@ -776,6 +799,7 @@ static struct scsi_host_template virtscsi_host_template_single = { .change_queue_depth = virtscsi_change_queue_depth, .eh_abort_handler = virtscsi_abort, .eh_device_reset_handler = virtscsi_device_reset, + .slave_alloc = virtscsi_device_alloc, .can_queue = 1024, .dma_boundary = UINT_MAX, -- GitLab From 90089934fce3a476d508c08bfb271f5ba19d6204 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Fri, 24 Mar 2017 17:48:10 +1100 Subject: [PATCH 0617/1834] KVM: PPC: Book3S PR: Exit KVM on failed mapping [ Upstream commit bd9166ffe624000140fc6b606b256df01fc0d060 ] At the moment kvmppc_mmu_map_page() returns -1 if mmu_hash_ops.hpte_insert() fails for any reason so the page fault handler resumes the guest and it faults on the same address again. This adds distinction to kvmppc_mmu_map_page() to return -EIO if mmu_hash_ops.hpte_insert() failed for a reason other than full pteg. At the moment only pSeries_lpar_hpte_insert() returns -2 if plpar_pte_enter() failed with a code other than H_PTEG_FULL. Other mmu_hash_ops.hpte_insert() instances can only fail with -1 "full pteg". With this change, if PR KVM fails to update HPT, it can signal the userspace about this instead of returning to guest and having the very same page fault over and over again. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Signed-off-by: Paul Mackerras Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kvm/book3s_64_mmu_host.c | 5 ++++- arch/powerpc/kvm/book3s_pr.c | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c index a587e8f4fd26..4b4e927c4822 100644 --- a/arch/powerpc/kvm/book3s_64_mmu_host.c +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c @@ -177,12 +177,15 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte, ret = mmu_hash_ops.hpte_insert(hpteg, vpn, hpaddr, rflags, vflags, hpsize, hpsize, MMU_SEGSIZE_256M); - if (ret < 0) { + if (ret == -1) { /* If we couldn't map a primary PTE, try a secondary */ hash = ~hash; vflags ^= HPTE_V_SECONDARY; attempt++; goto map_again; + } else if (ret < 0) { + r = -EIO; + goto out_unlock; } else { trace_kvm_book3s_64_mmu_map(rflags, hpteg, vpn, hpaddr, orig_pte); diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 826c541a12af..e0d88d0890aa 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -627,7 +627,11 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, kvmppc_mmu_unmap_page(vcpu, &pte); } /* The guest's PTE is not mapped yet. Map on the host */ - kvmppc_mmu_map_page(vcpu, &pte, iswrite); + if (kvmppc_mmu_map_page(vcpu, &pte, iswrite) == -EIO) { + /* Exit KVM if mapping failed */ + run->exit_reason = KVM_EXIT_INTERNAL_ERROR; + return RESUME_HOST; + } if (data) vcpu->stat.sp_storage++; else if (vcpu->arch.mmu.is_dcbz32(vcpu) && -- GitLab From c1c0f99f4fab4ccc194a846693288b820404e833 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 14 Apr 2017 14:51:20 -0700 Subject: [PATCH 0618/1834] mwifiex: don't leak 'chan_stats' on reset [ Upstream commit fb9e67bee3ab7111513130c516ffe378d885c0d0 ] 'chan_stats' is (re)allocated in _mwifiex_fw_dpc() -> mwifiex_init_channel_scan_gap(), which is called whenever the device is initialized -- at probe or at reset. But we only free it in we completely unregister the adapter, meaning we leak a copy of it during every reset. Let's free it in the shutdown / removal paths instead (and in the error-handling path), to avoid the leak. Ideally, we can eventually unify much of mwifiex_shutdown_sw() and mwifiex_remove_card() (way too much copy-and-paste) to reduce the burden on bugfixes like this. But that's work for tomorrow. Signed-off-by: Brian Norris Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/mwifiex/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/marvell/mwifiex/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 2478ccd6f2d9..1e36f11831a9 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -146,7 +146,6 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter) kfree(adapter->regd); - vfree(adapter->chan_stats); kfree(adapter); return 0; } @@ -636,6 +635,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); err_init_fw: @@ -1429,6 +1429,7 @@ mwifiex_shutdown_sw(struct mwifiex_adapter *adapter, struct semaphore *sem) mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); up(sem); exit_sem_err: @@ -1729,6 +1730,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev); rtnl_unlock(); } + vfree(adapter->chan_stats); wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); -- GitLab From b7de32ed33d8ce036f7b33d902318523b73d1b74 Mon Sep 17 00:00:00 2001 From: Tiantian Feng Date: Wed, 19 Apr 2017 18:18:39 +0200 Subject: [PATCH 0619/1834] x86/reboot: Turn off KVM when halting a CPU [ Upstream commit fba4f472b33aa81ca1836f57d005455261e9126f ] A CPU in VMX root mode will ignore INIT signals and will fail to bring up the APs after reboot. Therefore, on a panic we disable VMX on all CPUs before rebooting or triggering kdump. Do this when halting the machine as well, in case a firmware-level reboot does not perform a cold reset for all processors. Without doing this, rebooting the host may hang. Signed-off-by: Tiantian Feng Signed-off-by: Xishi Qiu [ Rewritten commit message. ] Signed-off-by: Paolo Bonzini Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: kvm@vger.kernel.org Link: http://lkml.kernel.org/r/20170419161839.30550-1-pbonzini@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/smp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index ca699677e288..ea217caa731c 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -33,6 +33,7 @@ #include #include #include +#include /* * Some notes on x86 processor bugs affecting SMP operation: @@ -162,6 +163,7 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) if (raw_smp_processor_id() == atomic_read(&stopping_cpu)) return NMI_HANDLED; + cpu_emergency_vmxoff(); stop_this_cpu(NULL); return NMI_HANDLED; @@ -174,6 +176,7 @@ static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) asmlinkage __visible void smp_reboot_interrupt(void) { ipi_entering_ack_irq(); + cpu_emergency_vmxoff(); stop_this_cpu(NULL); irq_exit(); } -- GitLab From 84c9248a240ec9c5cd98ecbe6f241d7b2cb7eeca Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Mon, 3 Apr 2017 23:58:54 +0100 Subject: [PATCH 0620/1834] ARM: 8668/1: ftrace: Fix dynamic ftrace with DEBUG_RODATA and !FRAME_POINTER [ Upstream commit 6f05d0761af612e04572ba4d65b4c0274a88444f ] The support for dynamic ftrace with CONFIG_DEBUG_RODATA involves overriding the weak arch_ftrace_update_code() with a variant which makes the kernel text writable around the patching. This override was however added under the CONFIG_OLD_MCOUNT ifdef, and CONFIG_OLD_MCOUNT is only enabled if frame pointers are enabled. This leads to non-functional dynamic ftrace (ftrace triggers a WARN_ON()) when CONFIG_DEBUG_RODATA is enabled and CONFIG_FRAME_POINTER is not. Move the override out of that ifdef and into the CONFIG_DYNAMIC_FTRACE ifdef where it belongs. Fixes: 80d6b0c2eed2a ("ARM: mm: allow text and rodata sections to be read-only") Suggested-by: Nicolai Stange Suggested-by: Rabin Vincent Signed-off-by: Abel Vesa Acked-by: Rabin Vincent Signed-off-by: Russell King Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/kernel/ftrace.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 3f1759411d51..414e60ed0257 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -29,11 +29,6 @@ #endif #ifdef CONFIG_DYNAMIC_FTRACE -#ifdef CONFIG_OLD_MCOUNT -#define OLD_MCOUNT_ADDR ((unsigned long) mcount) -#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old) - -#define OLD_NOP 0xe1a00000 /* mov r0, r0 */ static int __ftrace_modify_code(void *data) { @@ -51,6 +46,12 @@ void arch_ftrace_update_code(int command) stop_machine(__ftrace_modify_code, &command, NULL); } +#ifdef CONFIG_OLD_MCOUNT +#define OLD_MCOUNT_ADDR ((unsigned long) mcount) +#define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old) + +#define OLD_NOP 0xe1a00000 /* mov r0, r0 */ + static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) { return rec->arch.old_mcount ? OLD_NOP : NOP; -- GitLab From 994f316d50e2a3ee7ec83745824398a169a030e2 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 20 Apr 2017 10:07:34 +0100 Subject: [PATCH 0621/1834] irqchip/mips-gic: Separate IPI reservation & usage tracking [ Upstream commit f8dcd9e81797ae24acc44c84f0eb3b9e6cee9791 ] Since commit 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") introduced the GIC IPI IRQ domain we have tracked both reservation of interrupts & their use with a single bitmap - ipi_resrv. If an interrupt is reserved for use as an IPI but not actually in use then the appropriate bit is set in ipi_resrv. If an interrupt is either not reserved for use as an IPI or has been allocated as one then the appropriate bit is clear in ipi_resrv. Unfortunately this means that checking whether a bit is set in ipi_resrv to prevent IPI interrupts being allocated for use with a device is broken, because if the interrupt has been allocated as an IPI first then its bit will be clear. Fix this by separating the tracking of IPI reservation & usage, introducing a separate ipi_available bitmap for the latter. This means that ipi_resrv will now always have bits set corresponding to all interrupts reserved for use as IPIs, whether or not they have been allocated yet, and therefore that checking it when allocating device interrupts works as expected. Fixes: 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain") Signed-off-by: Paul Burton Signed-off-by: Matt Redfearn Cc: linux-mips@linux-mips.org Cc: Jason Cooper Cc: Marc Zyngier Cc: Ralf Baechle Link: http://lkml.kernel.org/r/1492679256-14513-2-git-send-email-matt.redfearn@imgtec.com Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-mips-gic.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index d74374f25392..abf696b49dd7 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -55,6 +55,7 @@ static unsigned int gic_cpu_pin; static unsigned int timer_cpu_pin; static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS); +DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS); static void __gic_irq_dispatch(void); @@ -746,17 +747,17 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return gic_setup_dev_chip(d, virq, spec->hwirq); } else { - base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs); + base_hwirq = find_first_bit(ipi_available, gic_shared_intrs); if (base_hwirq == gic_shared_intrs) { return -ENOMEM; } /* check that we have enough space */ for (i = base_hwirq; i < nr_irqs; i++) { - if (!test_bit(i, ipi_resrv)) + if (!test_bit(i, ipi_available)) return -EBUSY; } - bitmap_clear(ipi_resrv, base_hwirq, nr_irqs); + bitmap_clear(ipi_available, base_hwirq, nr_irqs); /* map the hwirq for each cpu consecutively */ i = 0; @@ -787,7 +788,7 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq, return 0; error: - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); return ret; } @@ -802,7 +803,7 @@ void gic_irq_domain_free(struct irq_domain *d, unsigned int virq, return; base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data)); - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); + bitmap_set(ipi_available, base_hwirq, nr_irqs); } int gic_irq_domain_match(struct irq_domain *d, struct device_node *node, @@ -1066,6 +1067,7 @@ static void __init __gic_init(unsigned long gic_base_addr, 2 * gic_vpes); } + bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); gic_basic_init(); } -- GitLab From a3a9a972e230b6198aea87c66fec0104c2b55ad1 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Wed, 12 Apr 2017 00:21:26 -0500 Subject: [PATCH 0622/1834] iommu/omap: Register driver before setting IOMMU ops [ Upstream commit abaa7e5b054aae567861628b74dbc7fbf8ed79e8 ] Move the registration of the OMAP IOMMU platform driver before setting the IOMMU callbacks on the platform bus. This causes the IOMMU devices to be probed first before the .add_device() callback is invoked for all registered devices, and allows the iommu_group support to be added to the OMAP IOMMU driver. While at this, also check for the return status from bus_set_iommu. Signed-off-by: Suman Anna Signed-off-by: Joerg Roedel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/omap-iommu.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index e2583cce2cc1..54556713c8d1 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -1299,6 +1299,7 @@ static int __init omap_iommu_init(void) const unsigned long flags = SLAB_HWCACHE_ALIGN; size_t align = 1 << 10; /* L2 pagetable alignement */ struct device_node *np; + int ret; np = of_find_matching_node(NULL, omap_iommu_of_match); if (!np) @@ -1312,11 +1313,25 @@ static int __init omap_iommu_init(void) return -ENOMEM; iopte_cachep = p; - bus_set_iommu(&platform_bus_type, &omap_iommu_ops); - omap_iommu_debugfs_init(); - return platform_driver_register(&omap_iommu_driver); + ret = platform_driver_register(&omap_iommu_driver); + if (ret) { + pr_err("%s: failed to register driver\n", __func__); + goto fail_driver; + } + + ret = bus_set_iommu(&platform_bus_type, &omap_iommu_ops); + if (ret) + goto fail_bus; + + return 0; + +fail_bus: + platform_driver_unregister(&omap_iommu_driver); +fail_driver: + kmem_cache_destroy(iopte_cachep); + return ret; } subsys_initcall(omap_iommu_init); /* must be ready before omap3isp is probed */ -- GitLab From 8a09ef5ba1592302c2f2d6ee7f3301191b2a5296 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Mon, 17 Apr 2017 17:11:05 +0800 Subject: [PATCH 0623/1834] md/raid10: wait up frozen array in handle_write_completed [ Upstream commit cf25ae78fc50010f66b9be945017796da34c434d ] Since nr_queued is changed, we need to call wake_up here if the array is already frozen and waiting for condition "nr_pending == nr_queued + extra" to be true. And commit 824e47daddbf ("RAID1: avoid unnecessary spin locks in I/O barrier code") which has already added the wake_up for raid1. Signed-off-by: Guoqing Jiang Reviewed-by: NeilBrown Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index b19b551bb34b..b1daff78f7b2 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2704,6 +2704,11 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) list_add(&r10_bio->retry_list, &conf->bio_end_io_list); conf->nr_queued++; spin_unlock_irq(&conf->device_lock); + /* + * In case freeze_array() is waiting for condition + * nr_pending == nr_queued + extra to be true. + */ + wake_up(&conf->wait_barrier); md_wakeup_thread(conf->mddev->thread); } else { if (test_bit(R10BIO_WriteError, -- GitLab From 76441e151c0a4950cdbf014c2377895f48fba2c6 Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Fri, 14 Apr 2017 12:29:54 -0400 Subject: [PATCH 0624/1834] NFS: Fix missing pg_cleanup after nfs_pageio_cond_complete() [ Upstream commit 43b7d964ed30dbca5c83c90cb010985b429ec4f9 ] Commit a7d42ddb3099727f58366fa006f850a219cce6c8 ("nfs: add mirroring support to pgio layer") moved pg_cleanup out of the path when there was non-sequental I/O that needed to be flushed. The result is that for layouts that have more than one layout segment per file, the pg_lseg is not cleared, so we can end up hitting the WARN_ON_ONCE(req_start >= seg_end) in pnfs_generic_pg_test since the pg_lseg will be pointing to that previously-flushed layout segment. Signed-off-by: Benjamin Coddington Fixes: a7d42ddb3099 ("nfs: add mirroring support to pgio layer") Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/pagelist.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 3d17fc82b9fe..892c88542ebd 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -1262,8 +1262,10 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) mirror = &desc->pg_mirrors[midx]; if (!list_empty(&mirror->pg_list)) { prev = nfs_list_entry(mirror->pg_list.prev); - if (index != prev->wb_index + 1) - nfs_pageio_complete_mirror(desc, midx); + if (index != prev->wb_index + 1) { + nfs_pageio_complete(desc); + break; + } } } } -- GitLab From 5f63431093a2be7ac048f6ce072e3606eb70c87c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 18 Apr 2017 09:45:52 -0700 Subject: [PATCH 0625/1834] tcp: remove poll() flakes with FastOpen [ Upstream commit 0f9fa831aecfc297b7b45d4f046759bcefcf87f0 ] When using TCP FastOpen for an active session, we send one wakeup event from tcp_finish_connect(), right before the data eventually contained in the received SYNACK is queued to sk->sk_receive_queue. This means that depending on machine load or luck, poll() users might receive POLLOUT events instead of POLLIN|POLLOUT To fix this, we need to move the call to sk->sk_state_change() after the (optional) call to tcp_rcv_fastopen_synack() Signed-off-by: Eric Dumazet Acked-by: Yuchung Cheng Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 2f107e46355c..b5f264ae3bff 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5606,10 +5606,6 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) else tp->pred_flags = 0; - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); - } } static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, @@ -5678,6 +5674,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, struct tcp_sock *tp = tcp_sk(sk); struct tcp_fastopen_cookie foc = { .len = -1 }; int saved_clamp = tp->rx_opt.mss_clamp; + bool fastopen_fail; tcp_parse_options(skb, &tp->rx_opt, 0, &foc); if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) @@ -5781,10 +5778,15 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, tcp_finish_connect(sk, skb); - if ((tp->syn_fastopen || tp->syn_data) && - tcp_rcv_fastopen_synack(sk, skb, &foc)) - return -1; + fastopen_fail = (tp->syn_fastopen || tp->syn_data) && + tcp_rcv_fastopen_synack(sk, skb, &foc); + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); + } + if (fastopen_fail) + return -1; if (sk->sk_write_pending || icsk->icsk_accept_queue.rskq_defer_accept || icsk->icsk_ack.pingpong) { -- GitLab From 91dbad3979787d6b4e6f7194191698b0f35040b9 Mon Sep 17 00:00:00 2001 From: Bernd Faust Date: Thu, 16 Feb 2017 19:42:07 +0100 Subject: [PATCH 0626/1834] e1000e: fix timing for 82579 Gigabit Ethernet controller [ Upstream commit 5313eeccd2d7f486be4e5c7560e3e2be239ec8f7 ] After an upgrade to Linux kernel v4.x the hardware timestamps of the 82579 Gigabit Ethernet Controller are different than expected. The values that are being read are almost four times as big as before the kernel upgrade. The difference is that after the upgrade the driver sets the clock frequency to 25MHz, where before the upgrade it was set to 96MHz. Intel confirmed that the correct frequency for this network adapter is 96MHz. Signed-off-by: Bernd Faust Acked-by: Sasha Neftin Acked-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/netdev.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 0feddf3393f9..528a926dd979 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -3528,6 +3528,12 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca) switch (hw->mac.type) { case e1000_pch2lan: + /* Stable 96MHz frequency */ + incperiod = INCPERIOD_96MHz; + incvalue = INCVALUE_96MHz; + shift = INCVALUE_SHIFT_96MHz; + adapter->cc.shift = shift + INCPERIOD_SHIFT_96MHz; + break; case e1000_pch_lpt: if (er32(TSYNCRXCTL) & E1000_TSYNCRXCTL_SYSCFI) { /* Stable 96MHz frequency */ -- GitLab From 67dc18ea69f42802f0087870f886aed397dcf21d Mon Sep 17 00:00:00 2001 From: Mikhail Paulyshka Date: Fri, 21 Apr 2017 08:52:42 +0200 Subject: [PATCH 0627/1834] ALSA: hda - Fix headset microphone detection for ASUS N551 and N751 [ Upstream commit fc7438b1eb12b6c93d7b7a62423779eb5dfc673c ] Headset microphone does not work out of the box on ASUS Nx51 laptops. This patch fixes it. Patch tested on Asus N551 laptop. Asus N751 part is not tested, but according to [1] this laptop uses the same audiosystem. 1. https://bugzilla.kernel.org/show_bug.cgi?id=117781 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195437 Signed-off-by: Mikhail Paulyshka Signed-off-by: Takashi Iwai Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cd427ea8861d..dae0021f39c3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6780,6 +6780,7 @@ enum { ALC668_FIXUP_DELL_DISABLE_AAMIX, ALC668_FIXUP_DELL_XPS13, ALC662_FIXUP_ASUS_Nx50, + ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, ALC668_FIXUP_ASUS_Nx51, ALC891_FIXUP_HEADSET_MODE, ALC891_FIXUP_DELL_MIC_NO_PRESENCE, @@ -7031,14 +7032,21 @@ static const struct hda_fixup alc662_fixups[] = { .chained = true, .chain_id = ALC662_FIXUP_BASS_1A }, + [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_alc668, + .chain_id = ALC662_FIXUP_BASS_CHMAP + }, [ALC668_FIXUP_ASUS_Nx51] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { - {0x1a, 0x90170151}, /* bass speaker */ + { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1a, 0x90170151 }, /* bass speaker */ + { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ {} }, .chained = true, - .chain_id = ALC662_FIXUP_BASS_CHMAP, + .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE, }, [ALC891_FIXUP_HEADSET_MODE] = { .type = HDA_FIXUP_FUNC, -- GitLab From 7bd191b0a0946f877f4d355e44aa944e6849fd63 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Sun, 19 Mar 2017 11:18:55 +0200 Subject: [PATCH 0628/1834] IB/ipoib: Fix deadlock between ipoib_stop and mcast join flow [ Upstream commit 3e31a490e01a6e67cbe9f6e1df2f3ff0fbf48972 ] Before calling ipoib_stop, rtnl_lock should be taken, then the flow clears the IPOIB_FLAG_ADMIN_UP and IPOIB_FLAG_OPER_UP flags, and waits for mcast completion if IPOIB_MCAST_FLAG_BUSY is set. On the other hand, the flow of multicast join task initializes a mcast completion, sets the IPOIB_MCAST_FLAG_BUSY and calls ipoib_mcast_join. If IPOIB_FLAG_OPER_UP flag is not set, this call returns EINVAL without setting the mcast completion and leads to a deadlock. ipoib_stop | | | clear_bit(IPOIB_FLAG_ADMIN_UP) | | | Context Switch | | ipoib_mcast_join_task | | | spin_lock_irq(lock) | | | init_completion(mcast) | | | set_bit(IPOIB_MCAST_FLAG_BUSY) | | | Context Switch | | clear_bit(IPOIB_FLAG_OPER_UP) | | | spin_lock_irqsave(lock) | | | Context Switch | | ipoib_mcast_join | return (-EINVAL) | | | spin_unlock_irq(lock) | | | Context Switch | | ipoib_mcast_dev_flush | wait_for_completion(mcast) | ipoib_stop will wait for mcast completion for ever, and will not release the rtnl_lock. As a result panic occurs with the following trace: [13441.639268] Call Trace: [13441.640150] [] schedule+0x29/0x70 [13441.641038] [] schedule_timeout+0x239/0x2d0 [13441.641914] [] ? complete+0x47/0x50 [13441.642765] [] ? flush_workqueue_prep_pwqs+0x16d/0x200 [13441.643580] [] wait_for_completion+0x116/0x170 [13441.644434] [] ? wake_up_state+0x20/0x20 [13441.645293] [] ipoib_mcast_dev_flush+0x150/0x190 [ib_ipoib] [13441.646159] [] ipoib_ib_dev_down+0x37/0x60 [ib_ipoib] [13441.647013] [] ipoib_stop+0x75/0x150 [ib_ipoib] Fixes: 08bc327629cb ("IB/ipoib: fix for rare multicast join race condition") Signed-off-by: Feras Daoud Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 6b6826f3e446..8f79caedf905 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -487,6 +487,9 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) return -EINVAL; + init_completion(&mcast->done); + set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw); rec.mgid = mcast->mcmember.mgid; @@ -645,8 +648,6 @@ void ipoib_mcast_join_task(struct work_struct *work) if (mcast->backoff == 1 || time_after_eq(jiffies, mcast->delay_until)) { /* Found the next unjoined group */ - init_completion(&mcast->done); - set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); if (ipoib_mcast_join(dev, mcast)) { spin_unlock_irq(&priv->lock); return; @@ -666,11 +667,9 @@ void ipoib_mcast_join_task(struct work_struct *work) queue_delayed_work(priv->wq, &priv->mcast_task, delay_until - jiffies); } - if (mcast) { - init_completion(&mcast->done); - set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); + if (mcast) ipoib_mcast_join(dev, mcast); - } + spin_unlock_irq(&priv->lock); } -- GitLab From 089f13786bdc483d0ff54367d9dbe0dd19746481 Mon Sep 17 00:00:00 2001 From: Feras Daoud Date: Sun, 19 Mar 2017 11:18:54 +0200 Subject: [PATCH 0629/1834] IB/ipoib: Update broadcast object if PKey value was changed in index 0 [ Upstream commit 9a9b8112699d78e7f317019b37f377e90023f3ed ] Update the broadcast address in the priv->broadcast object when the Pkey value changes in index 0, otherwise the multicast GID value will keep the previous value of the PKey, and will not be updated. This leads to interface state down because the interface will keep the old PKey value. For example, in SR-IOV environment, if the PF changes the value of PKey index 0 for one of the VFs, then the VF receives PKey change event that triggers heavy flush. This flush calls update_parent_pkey that update the broadcast object and its relevant members. If in this case the multicast GID will not be updated, the interface state will be down. Fixes: c2904141696e ("IPoIB: Fix pkey change flow for virtualization environments") Signed-off-by: Feras Daoud Signed-off-by: Erez Shitrit Reviewed-by: Alex Vesker Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 335bd2c9e16e..34122c96522b 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -974,6 +974,19 @@ static inline int update_parent_pkey(struct ipoib_dev_priv *priv) */ priv->dev->broadcast[8] = priv->pkey >> 8; priv->dev->broadcast[9] = priv->pkey & 0xff; + + /* + * Update the broadcast address in the priv->broadcast object, + * in case it already exists, otherwise no one will do that. + */ + if (priv->broadcast) { + spin_lock_irq(&priv->lock); + memcpy(priv->broadcast->mcmember.mgid.raw, + priv->dev->broadcast + 4, + sizeof(union ib_gid)); + spin_unlock_irq(&priv->lock); + } + return 0; } -- GitLab From 2b09da0e7718bc7bd203b9ea62c21d7a088dbe98 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Apr 2017 13:39:09 +0300 Subject: [PATCH 0630/1834] HSI: ssi_protocol: double free in ssip_pn_xmit() [ Upstream commit 3026050179a3a9a6f5c892c414b5e36ecf092081 ] If skb_pad() fails then it frees skb and we don't need to free it again at the end of the function. Fixes: dc7bf5d7 ("HSI: Introduce driver for SSI Protocol") Signed-off-by: Dan Carpenter Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hsi/clients/ssi_protocol.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hsi/clients/ssi_protocol.c b/drivers/hsi/clients/ssi_protocol.c index 6031cd146556..802afc98e8bd 100644 --- a/drivers/hsi/clients/ssi_protocol.c +++ b/drivers/hsi/clients/ssi_protocol.c @@ -989,7 +989,7 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; /* Pad to 32-bits - FIXME: Revisit*/ if ((skb->len & 3) && skb_pad(skb, 4 - (skb->len & 3))) - goto drop; + goto inc_dropped; /* * Modem sends Phonet messages over SSI with its own endianess... @@ -1041,8 +1041,9 @@ static int ssip_pn_xmit(struct sk_buff *skb, struct net_device *dev) drop2: hsi_free_msg(msg); drop: - dev->stats.tx_dropped++; dev_kfree_skb(skb); +inc_dropped: + dev->stats.tx_dropped++; return 0; } -- GitLab From 0021b4613a8acf33937c7492817fe484e19e4381 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Wed, 29 Mar 2017 06:03:00 +0300 Subject: [PATCH 0631/1834] IB/mlx4: Take write semaphore when changing the vma struct [ Upstream commit 22c3653d04bd0c67b75e99d85e0c0bdf83947df5 ] When the driver disassociate user context, it changes the vma to anonymous by setting the vm_ops to null and zap the vma ptes. In order to avoid race in the kernel, we need to take write lock before we change the vma entries. Fixes: ae184ddeca5db ('IB/mlx4_ib: Disassociate support') Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx4/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index c41c8d0a4ac0..129dbd790dba 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1168,7 +1168,7 @@ static void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) /* need to protect from a race on closing the vma as part of * mlx4_ib_vma_close(). */ - down_read(&owning_mm->mmap_sem); + down_write(&owning_mm->mmap_sem); for (i = 0; i < HW_BAR_COUNT; i++) { vma = context->hw_bar_info[i].vma; if (!vma) @@ -1186,7 +1186,7 @@ static void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) context->hw_bar_info[i].vma->vm_ops = NULL; } - up_read(&owning_mm->mmap_sem); + up_write(&owning_mm->mmap_sem); mmput(owning_mm); put_task_struct(owning_process); } -- GitLab From df7aedb171e262c4f2c692f323bc9b1c8c13ef59 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Wed, 29 Mar 2017 06:03:01 +0300 Subject: [PATCH 0632/1834] IB/mlx4: Change vma from shared to private [ Upstream commit ca37a664a8e4e9988b220988ceb4d79e3316f195 ] Anonymous VMA (->vm_ops == NULL) cannot be shared, otherwise it would lead to SIGBUS. Remove the shared flags from the vma after we change it to be anonymous. This is easily reproduced by doing modprobe -r while running a user-space application such as raw_ethernet_bw. Fixes: ae184ddeca5db ('IB/mlx4_ib: Disassociate support') Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx4/main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 129dbd790dba..19bc1c2186ff 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1182,6 +1182,8 @@ static void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) BUG_ON(1); } + context->hw_bar_info[i].vma->vm_flags &= + ~(VM_SHARED | VM_MAYSHARE); /* context going to be destroyed, should not access ops any more */ context->hw_bar_info[i].vma->vm_ops = NULL; } -- GitLab From 9238066e2838e2981c908e66bfc599442fd6917b Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Wed, 29 Mar 2017 06:03:02 +0300 Subject: [PATCH 0633/1834] IB/mlx5: Take write semaphore when changing the vma struct [ Upstream commit ecc7d83be3243835c9396a1a2fb8ce95f205207b ] When the driver disassociate user context, it changes the vma to anonymous by setting the vm_ops to null and zap the vma ptes. In order to avoid race in the kernel, we need to take write lock before we change the vma entries. Fixes: 7c2344c3bbf97 ('IB/mlx5: Implements disassociate_ucontext API') Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 5e29fbd3a5a0..150227786969 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1313,7 +1313,7 @@ static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) /* need to protect from a race on closing the vma as part of * mlx5_ib_vma_close. */ - down_read(&owning_mm->mmap_sem); + down_write(&owning_mm->mmap_sem); list_for_each_entry_safe(vma_private, n, &context->vma_private_list, list) { vma = vma_private->vma; @@ -1327,7 +1327,7 @@ static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) list_del(&vma_private->list); kfree(vma_private); } - up_read(&owning_mm->mmap_sem); + up_write(&owning_mm->mmap_sem); mmput(owning_mm); put_task_struct(owning_process); } -- GitLab From c404dff4874d44e89783d2a4534d3b29ca7b68f0 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Wed, 29 Mar 2017 06:03:03 +0300 Subject: [PATCH 0634/1834] IB/mlx5: Change vma from shared to private [ Upstream commit 1377661298d2820d675553d186c31b6f46c140d0 ] Anonymous VMA (->vm_ops == NULL) cannot be shared, otherwise it would lead to SIGBUS. Remove the shared flags from the vma after we change it to be anonymous. This is easily reproduced by doing modprobe -r while running a user-space application such as raw_ethernet_bw. Fixes: 7c2344c3bbf97 ('IB/mlx5: Implements disassociate_ucontext API') Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 150227786969..d7da1dca765f 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1323,6 +1323,7 @@ static void mlx5_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) /* context going to be destroyed, should * not access ops any more. */ + vma->vm_flags &= ~(VM_SHARED | VM_MAYSHARE); vma->vm_ops = NULL; list_del(&vma_private->list); kfree(vma_private); -- GitLab From 4b829c03c902b4b79f3078402b130a61e5cce286 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Thu, 20 Apr 2017 13:26:54 +0300 Subject: [PATCH 0635/1834] IB/mlx5: Set correct SL in completion for RoCE [ Upstream commit 12f8fedef2ec94c783f929126b20440a01512c14 ] There is a difference when parsing a completion entry between Ethernet and IB ports. When link layer is Ethernet the bits describe the type of L3 header in the packet. In the case when link layer is Ethernet and VLAN header is present the value of SL is equal to the 3 UP bits in the VLAN header. If VLAN header is not present then the SL is undefined and consumer of the completion should check if IB_WC_WITH_VLAN is set. While that, this patch also fills the vlan_id field in the completion if present. Signed-off-by: Moni Shoua Reviewed-by: Majd Dibbiny Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/cq.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 9cdcff77b9a8..fc62a7ded734 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -172,6 +172,8 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, struct mlx5_ib_srq *srq; struct mlx5_ib_wq *wq; u16 wqe_ctr; + u8 roce_packet_type; + bool vlan_present; u8 g; if (qp->ibqp.srq || qp->ibqp.xrcd) { @@ -223,7 +225,6 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, break; } wc->slid = be16_to_cpu(cqe->slid); - wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; wc->src_qp = be32_to_cpu(cqe->flags_rqpn) & 0xffffff; wc->dlid_path_bits = cqe->ml_path; g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; @@ -237,10 +238,22 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, wc->pkey_index = 0; } - if (ll != IB_LINK_LAYER_ETHERNET) + if (ll != IB_LINK_LAYER_ETHERNET) { + wc->sl = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0xf; return; + } + + vlan_present = cqe->l4_l3_hdr_type & 0x1; + roce_packet_type = (be32_to_cpu(cqe->flags_rqpn) >> 24) & 0x3; + if (vlan_present) { + wc->vlan_id = (be16_to_cpu(cqe->vlan_info)) & 0xfff; + wc->sl = (be16_to_cpu(cqe->vlan_info) >> 13) & 0x7; + wc->wc_flags |= IB_WC_WITH_VLAN; + } else { + wc->sl = 0; + } - switch (wc->sl & 0x3) { + switch (roce_packet_type) { case MLX5_CQE_ROCE_L3_HEADER_TYPE_GRH: wc->network_hdr_type = RDMA_NETWORK_IB; break; -- GitLab From b281844747fbbfbab6a0427f8a58bd4af580de38 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 20 Apr 2017 13:17:02 +0300 Subject: [PATCH 0636/1834] ASoC: Intel: Skylake: Uninitialized variable in probe_codec() [ Upstream commit e6a33532affd14c12688c0e9b2e773e8b2550f3b ] My static checker complains that if snd_hdac_bus_get_response() returns -EIO then "res" is uninitialized. Fix this by initializing it to -1 so that the error is handled correctly. Fixes: d8c2dab8381d ("ASoC: Intel: Add Skylake HDA audio driver") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/skylake/skl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 06fa5e85dd0e..3e526fbd267e 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -457,7 +457,7 @@ static int probe_codec(struct hdac_ext_bus *ebus, int addr) struct hdac_bus *bus = ebus_to_hbus(ebus); unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res; + unsigned int res = -1; mutex_lock(&bus->cmd_mutex); snd_hdac_bus_send_cmd(bus, cmd); -- GitLab From 5a049986d6a6759ae23685cb2fd93ce56163bb34 Mon Sep 17 00:00:00 2001 From: Brian King Date: Wed, 19 Apr 2017 13:45:10 -0400 Subject: [PATCH 0637/1834] ibmvnic: Disable irq prior to close [ Upstream commit dd9c20fa07ba5cfb5a0ab3181d68530506610605 ] Add some code to call disable_irq on all the vnic interface's irqs. This fixes a crash observed when closing an active interface, as seen in the oops below when we try to access a buffer in the interrupt handler which we've already freed. Unable to handle kernel paging request for data at address 0x00000001 Faulting instruction address: 0xd000000003886824 Oops: Kernel access of bad area, sig: 11 [#1] SMP NR_CPUS=2048 NUMA pSeries Modules linked in: ibmvnic(OEN) rpadlpar_io(X) rpaphp(X) tcp_diag udp_diag inet_diag unix_diag af_packet_diag netlink_diag rpcsec_ Supported: No, Unsupported modules are loaded CPU: 8 PID: 0 Comm: swapper/8 Tainted: G OE NX 4.4.49-92.11-default #1 task: c00000007f990110 ti: c0000000fffa0000 task.ti: c00000007f9b8000 NIP: d000000003886824 LR: d000000003886824 CTR: c0000000007eff60 REGS: c0000000fffa3a70 TRAP: 0300 Tainted: G OE NX (4.4.49-92.11-default) MSR: 8000000000009033 CR: 22008042 XER: 20000008 CFAR: c000000000008468 DAR: 0000000000000001 DSISR: 40000000 SOFTE: 0 GPR00: d000000003886824 c0000000fffa3cf0 d000000003894118 0000000000000000 GPR04: 0000000000000000 0000000000000000 c000000001249da0 0000000000000000 GPR08: 000000000000000e 0000000000000000 c0000000ccb00000 d000000003889180 GPR12: c0000000007eff60 c000000007af4c00 0000000000000001 c0000000010def30 GPR16: c00000007f9b8000 c000000000b98c30 c00000007f9b8080 c000000000bab858 GPR20: 0000000000000005 0000000000000000 c0000000ff5d7e80 c0000000f809f648 GPR24: c0000000ff5d7ec8 0000000000000000 0000000000000000 c0000000ccb001a0 GPR28: 000000000000000a c0000000f809f600 c0000000fd4cd900 c0000000f9cd5b00 NIP [d000000003886824] ibmvnic_interrupt_tx+0x114/0x380 [ibmvnic] LR [d000000003886824] ibmvnic_interrupt_tx+0x114/0x380 [ibmvnic] Call Trace: [c0000000fffa3cf0] [d000000003886824] ibmvnic_interrupt_tx+0x114/0x380 [ibmvnic] (unreliable) [c0000000fffa3dd0] [c000000000132940] __handle_irq_event_percpu+0x90/0x2e0 [c0000000fffa3e90] [c000000000132bcc] handle_irq_event_percpu+0x3c/0x90 [c0000000fffa3ed0] [c000000000132c88] handle_irq_event+0x68/0xc0 [c0000000fffa3f00] [c000000000137edc] handle_fasteoi_irq+0xec/0x250 [c0000000fffa3f30] [c000000000131b04] generic_handle_irq+0x54/0x80 [c0000000fffa3f60] [c000000000011190] __do_irq+0x80/0x1d0 [c0000000fffa3f90] [c0000000000248d8] call_do_irq+0x14/0x24 [c00000007f9bb9e0] [c000000000011380] do_IRQ+0xa0/0x120 [c00000007f9bba40] [c000000000002594] hardware_interrupt_common+0x114/0x180 Signed-off-by: Brian King Signed-off-by: Nathan Fontenot Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ibm/ibmvnic.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 7c6c1468628b..49094c965697 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -511,6 +511,23 @@ static int ibmvnic_open(struct net_device *netdev) return -ENOMEM; } +static void disable_sub_crqs(struct ibmvnic_adapter *adapter) +{ + int i; + + if (adapter->tx_scrq) { + for (i = 0; i < adapter->req_tx_queues; i++) + if (adapter->tx_scrq[i]) + disable_irq(adapter->tx_scrq[i]->irq); + } + + if (adapter->rx_scrq) { + for (i = 0; i < adapter->req_rx_queues; i++) + if (adapter->rx_scrq[i]) + disable_irq(adapter->rx_scrq[i]->irq); + } +} + static int ibmvnic_close(struct net_device *netdev) { struct ibmvnic_adapter *adapter = netdev_priv(netdev); @@ -519,6 +536,7 @@ static int ibmvnic_close(struct net_device *netdev) int i; adapter->closing = true; + disable_sub_crqs(adapter); for (i = 0; i < adapter->req_rx_queues; i++) napi_disable(&adapter->napi[i]); -- GitLab From 72bded3b6c5201d15050ec639e9ec8d9aeceda10 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Wed, 19 Apr 2017 13:53:49 -0700 Subject: [PATCH 0638/1834] netvsc: Deal with rescinded channels correctly [ Upstream commit 73e64fa4f417b22d8d5521999a631ced8e2d442e ] We will not be able to send packets over a channel that has been rescinded. Make necessary adjustments so we can properly cleanup even when the channel is rescinded. This issue can be trigerred in the NIC hot-remove path. Signed-off-by: K. Y. Srinivasan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/hyperv/netvsc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index c2ac39a940f7..14f58b60d1b5 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -151,6 +151,13 @@ static void netvsc_destroy_buf(struct hv_device *device) sizeof(struct nvsp_message), (unsigned long)revoke_packet, VM_PKT_DATA_INBAND, 0); + /* If the failure is because the channel is rescinded; + * ignore the failure since we cannot send on a rescinded + * channel. This would allow us to properly cleanup + * even when the channel is rescinded. + */ + if (device->channel->rescind) + ret = 0; /* * If we failed here, we might as well return and * have a leak rather than continue and a bugchk @@ -211,6 +218,15 @@ static void netvsc_destroy_buf(struct hv_device *device) sizeof(struct nvsp_message), (unsigned long)revoke_packet, VM_PKT_DATA_INBAND, 0); + + /* If the failure is because the channel is rescinded; + * ignore the failure since we cannot send on a rescinded + * channel. This would allow us to properly cleanup + * even when the channel is rescinded. + */ + if (device->channel->rescind) + ret = 0; + /* If we failed here, we might as well return and * have a leak rather than continue and a bugchk */ -- GitLab From 730ff617b9ed6f35a98b6a8d7a5f8d5baa042556 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 21 Apr 2017 16:04:56 -0700 Subject: [PATCH 0639/1834] Fix driver usage of 128B WQEs when WQ_CREATE is V1. [ Upstream commit 3f247de750b8dd8f50a2c1390e2a1238790a9dff ] There are two versions of a structure for queue creation and setup that the driver shares with FW. The driver was only treating as version 0. Verify WQ_CREATE with 128B WQEs in V0 and V1. Code review of another bug showed the driver passing 128B WQEs and 8 pages in WQ CREATE and V0. Code inspection/instrumentation showed that the driver uses V0 in WQ_CREATE and if the caller passes queue->entry_size 128B, the driver sets the hdr_version to V1 so all is good. When I tested the V1 WQ_CREATE, the mailbox failed causing the driver to unload. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Johannes Thumshirn Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_sli.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 8f1df76a77b6..0902ed204ba8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -13696,6 +13696,9 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, case LPFC_Q_CREATE_VERSION_1: bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, wq->entry_count); + bf_set(lpfc_mbox_hdr_version, &shdr->request, + LPFC_Q_CREATE_VERSION_1); + switch (wq->entry_size) { default: case 64: -- GitLab From c5406a7557444708a5742a08acb83c6d339d0bb9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 21 Apr 2017 16:05:05 -0700 Subject: [PATCH 0640/1834] Fix Express lane queue creation. [ Upstream commit 7e04e21afa82ef024416f5413b5bdb66e0505bcd ] The older sli4 adapters only supported the 64 byte WQE entry size. The new adapter (fw) support both 64 and 128 byte WQE entry sizies. The Express lane WQ was not being created with the 128 byte WQE sizes when it was supported. Not having the right WQE size created for the express lane work queue caused the the firmware to overwrite the lun indentifier in the FCP header. This patch correctly creates the express lane work queue with the supported size. Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Johannes Thumshirn Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/lpfc/lpfc_init.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index f7e3f27bb5c5..e9ea8f4ea2c9 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11312,6 +11312,7 @@ int lpfc_fof_queue_create(struct lpfc_hba *phba) { struct lpfc_queue *qdesc; + uint32_t wqesize; /* Create FOF EQ */ qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, @@ -11332,8 +11333,11 @@ lpfc_fof_queue_create(struct lpfc_hba *phba) phba->sli4_hba.oas_cq = qdesc; /* Create OAS WQ */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, + wqesize = (phba->fcp_embed_io) ? + LPFC_WQE128_SIZE : phba->sli4_hba.wq_esize; + qdesc = lpfc_sli4_queue_alloc(phba, wqesize, phba->sli4_hba.wq_ecount); + if (!qdesc) goto out_error; -- GitLab From 9907f1f6d86d10aecdc14427f7224cf95d32dd73 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Fri, 14 Apr 2017 10:29:25 -0700 Subject: [PATCH 0641/1834] gpio: gpio-wcove: fix irq pending status bit width [ Upstream commit 7c2d176fe3f8dce632b948f79c7e89916ffe2c70 ] Whiskey cove PMIC has three GPIO banks with total number of 13 GPIO pins. But when checking for the pending status, for_each_set_bit() uses bit width of 7 and hence it only checks the status for first 7 GPIO pins missing to check/clear the status of rest of the GPIO pins. This patch fixes this issue. Signed-off-by: Kuppuswamy Sathyanarayanan Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-wcove.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index d0ddba7a9d08..1012c86925ad 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -318,7 +318,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) while (pending) { /* One iteration is for all pending bits */ for_each_set_bit(gpio, (const unsigned long *)&pending, - GROUP0_NR_IRQS) { + WCOVE_GPIO_NUM) { offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0; mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) : BIT(gpio); -- GitLab From 87cfd7f65fc22368291d54221510af3dd31b4a3b Mon Sep 17 00:00:00 2001 From: Gao Feng Date: Fri, 14 Apr 2017 10:00:08 +0800 Subject: [PATCH 0642/1834] netfilter: xt_CT: fix refcnt leak on error path [ Upstream commit 470acf55a021713869b9bcc967268ac90c8a0fac ] There are two cases which causes refcnt leak. 1. When nf_ct_timeout_ext_add failed in xt_ct_set_timeout, it should free the timeout refcnt. Now goto the err_put_timeout error handler instead of going ahead. 2. When the time policy is not found, we should call module_put. Otherwise, the related cthelper module cannot be removed anymore. It is easy to reproduce by typing the following command: # iptables -t raw -A OUTPUT -p tcp -j CT --helper ftp --timeout xxx Signed-off-by: Gao Feng Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/xt_CT.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 6669e68d589e..00ef8243d48d 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -168,8 +168,10 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par, goto err_put_timeout; } timeout_ext = nf_ct_timeout_ext_add(ct, timeout, GFP_ATOMIC); - if (timeout_ext == NULL) + if (!timeout_ext) { ret = -ENOMEM; + goto err_put_timeout; + } rcu_read_unlock(); return ret; @@ -201,6 +203,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par, struct xt_ct_target_info_v1 *info) { struct nf_conntrack_zone zone; + struct nf_conn_help *help; struct nf_conn *ct; int ret = -EOPNOTSUPP; @@ -249,7 +252,7 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par, if (info->timeout[0]) { ret = xt_ct_set_timeout(ct, par, info->timeout); if (ret < 0) - goto err3; + goto err4; } __set_bit(IPS_CONFIRMED_BIT, &ct->status); nf_conntrack_get(&ct->ct_general); @@ -257,6 +260,10 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par, info->ct = ct; return 0; +err4: + help = nfct_help(ct); + if (help) + module_put(help->helper->me); err3: nf_ct_tmpl_free(ct); err2: -- GitLab From d2e269c09fc74a5da3701d58954422612dae4a47 Mon Sep 17 00:00:00 2001 From: Jarno Rajahalme Date: Fri, 14 Apr 2017 14:26:38 -0700 Subject: [PATCH 0643/1834] openvswitch: Delete conntrack entry clashing with an expectation. [ Upstream commit cf5d70918877c6a6655dc1e92e2ebb661ce904fd ] Conntrack helpers do not check for a potentially clashing conntrack entry when creating a new expectation. Also, nf_conntrack_in() will check expectations (via init_conntrack()) only if a conntrack entry can not be found. The expectation for a packet which also matches an existing conntrack entry will not be removed by conntrack, and is currently handled inconsistently by OVS, as OVS expects the expectation to be removed when the connection tracking entry matching that expectation is confirmed. It should be noted that normally an IP stack would not allow reuse of a 5-tuple of an old (possibly lingering) connection for a new data connection, so this is somewhat unlikely corner case. However, it is possible that a misbehaving source could cause conntrack entries be created that could then interfere with new related connections. Fix this in the OVS module by deleting the clashing conntrack entry after an expectation has been matched. This causes the following nf_conntrack_in() call also find the expectation and remove it when creating the new conntrack entry, as well as the forthcoming reply direction packets to match the new related connection instead of the old clashing conntrack entry. Fixes: 7f8a436eaa2c ("openvswitch: Add conntrack action") Reported-by: Yang Song Signed-off-by: Jarno Rajahalme Acked-by: Joe Stringer Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/openvswitch/conntrack.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index b28e45b691de..466393936db9 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -396,10 +396,38 @@ ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone, u16 proto, const struct sk_buff *skb) { struct nf_conntrack_tuple tuple; + struct nf_conntrack_expect *exp; if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, net, &tuple)) return NULL; - return __nf_ct_expect_find(net, zone, &tuple); + + exp = __nf_ct_expect_find(net, zone, &tuple); + if (exp) { + struct nf_conntrack_tuple_hash *h; + + /* Delete existing conntrack entry, if it clashes with the + * expectation. This can happen since conntrack ALGs do not + * check for clashes between (new) expectations and existing + * conntrack entries. nf_conntrack_in() will check the + * expectations only if a conntrack entry can not be found, + * which can lead to OVS finding the expectation (here) in the + * init direction, but which will not be removed by the + * nf_conntrack_in() call, if a matching conntrack entry is + * found instead. In this case all init direction packets + * would be reported as new related packets, while reply + * direction packets would be reported as un-related + * established packets. + */ + h = nf_conntrack_find_get(net, zone, &tuple); + if (h) { + struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); + + nf_ct_delete(ct, 0, 0); + nf_conntrack_put(&ct->ct_general); + } + } + + return exp; } /* This replicates logic from nf_conntrack_core.c that is not exported. */ -- GitLab From 3a0427103f90ced70dc77fd3f098ac30697303dc Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Sat, 15 Apr 2017 19:27:42 +0800 Subject: [PATCH 0644/1834] netfilter: nf_ct_helper: permit cthelpers with different names via nfnetlink [ Upstream commit 66e5a6b18bd09d0431e97cd3c162e76c5c2aebba ] cthelpers added via nfnetlink may have the same tuple, i.e. except for the l3proto and l4proto, other fields are all zero. So even with the different names, we will also fail to add them: # nfct helper add ssdp inet udp # nfct helper add tftp inet udp nfct v1.4.3: netlink error: File exists So in order to avoid unpredictable behaviour, we should: 1. cthelpers can be selected by nft ct helper obj or xt_CT target, so report error if duplicated { name, l3proto, l4proto } tuple exist. 2. cthelpers can be selected by nf_ct_tuple_src_mask_cmp when nf_ct_auto_assign_helper is enabled, so also report error if duplicated { l3proto, l4proto, src-port } tuple exist. Also note, if the cthelper is added from userspace, then the src-port will always be zero, it's invalid for nf_ct_auto_assign_helper, so there's no need to check the second point listed above. Fixes: 893e093c786c ("netfilter: nf_ct_helper: bail out on duplicated helpers") Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_helper.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index 6dc44d9b4190..92e69af41656 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -379,17 +379,33 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) struct nf_conntrack_tuple_mask mask = { .src.u.all = htons(0xFFFF) }; unsigned int h = helper_hash(&me->tuple); struct nf_conntrack_helper *cur; - int ret = 0; + int ret = 0, i; BUG_ON(me->expect_policy == NULL); BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); BUG_ON(strlen(me->name) > NF_CT_HELPER_NAME_LEN - 1); mutex_lock(&nf_ct_helper_mutex); - hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) { - if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple, &mask)) { - ret = -EEXIST; - goto out; + for (i = 0; i < nf_ct_helper_hsize; i++) { + hlist_for_each_entry(cur, &nf_ct_helper_hash[i], hnode) { + if (!strcmp(cur->name, me->name) && + (cur->tuple.src.l3num == NFPROTO_UNSPEC || + cur->tuple.src.l3num == me->tuple.src.l3num) && + cur->tuple.dst.protonum == me->tuple.dst.protonum) { + ret = -EEXIST; + goto out; + } + } + } + + /* avoid unpredictable behaviour for auto_assign_helper */ + if (!(me->flags & NF_CT_HELPER_F_USERSPACE)) { + hlist_for_each_entry(cur, &nf_ct_helper_hash[h], hnode) { + if (nf_ct_tuple_src_mask_cmp(&cur->tuple, &me->tuple, + &mask)) { + ret = -EEXIST; + goto out; + } } } hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); -- GitLab From abff7f51914942f1d1a80d674cb21aa48a534ba0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 10 Apr 2017 16:54:17 +0300 Subject: [PATCH 0645/1834] mmc: host: omap_hsmmc: checking for NULL instead of IS_ERR() [ Upstream commit ec5ab8933772c87f24ad62a4a602fe8949f423c2 ] devm_pinctrl_get() returns error pointers, it never returns NULL. Fixes: 455e5cd6f736 ("mmc: omap_hsmmc: Pin remux workaround to support SDIO interrupt on AM335x") Signed-off-by: Dan Carpenter Reviewed-by: Kishon Vijay Abraham I Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/omap_hsmmc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 5f2f24a7360d..a082aa330f47 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1762,8 +1762,8 @@ static int omap_hsmmc_configure_wake_irq(struct omap_hsmmc_host *host) */ if (host->pdata->controller_flags & OMAP_HSMMC_SWAKEUP_MISSING) { struct pinctrl *p = devm_pinctrl_get(host->dev); - if (!p) { - ret = -ENODEV; + if (IS_ERR(p)) { + ret = PTR_ERR(p); goto err_free_irq; } if (IS_ERR(pinctrl_lookup_state(p, PINCTRL_STATE_DEFAULT))) { -- GitLab From 185c88b1ef47f9b0a35b92e7a66d51b4acce2136 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 15:09:19 +0800 Subject: [PATCH 0646/1834] tipc: check return value of nlmsg_new [ Upstream commit 78302fd405769c9a9379e9adda119d533dce2eed ] Function nlmsg_new() will return a NULL pointer if there is no enough memory, and its return value should be checked before it is used. However, in function tipc_nl_node_get_monitor(), the validation of the return value of function nlmsg_new() is missed. This patch fixes the bug. Signed-off-by: Pan Bian Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/tipc/node.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/tipc/node.c b/net/tipc/node.c index 5b3e1ea37b6d..db8fbc076e1a 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -2094,6 +2094,8 @@ int tipc_nl_node_get_monitor(struct sk_buff *skb, struct genl_info *info) int err; msg.skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg.skb) + return -ENOMEM; msg.portid = info->snd_portid; msg.seq = info->snd_seq; -- GitLab From eff9431cafa95b343fc6035833a0ed342e6120d0 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 17:38:35 +0800 Subject: [PATCH 0647/1834] wan: pc300too: abort path on failure [ Upstream commit 2a39e7aa8a98f777f0732ca7125b6c9668791760 ] In function pc300_pci_init_one(), on the ioremap error path, function pc300_pci_remove_one() is called to free the allocated memory. However, the path is not terminated, and the freed memory will be used later, resulting in use-after-free bugs. This path fixes the bug. Signed-off-by: Pan Bian Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/pc300too.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index db363856e0b5..2b064998915f 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -347,6 +347,7 @@ static int pc300_pci_init_one(struct pci_dev *pdev, card->rambase == NULL) { pr_err("ioremap() failed\n"); pc300_pci_remove_one(pdev); + return -ENOMEM; } /* PLX PCI 9050 workaround for local configuration register read bug */ -- GitLab From bf4b579b67141d6d62ea3a243ce8397fb693d52c Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 20:04:04 +0800 Subject: [PATCH 0648/1834] qlcnic: fix unchecked return value [ Upstream commit 91ec701a553cb3de470fd471c6fefe3ad1125455 ] Function pci_find_ext_capability() may return 0, which is an invalid address. In function qlcnic_sriov_virtid_fn(), its return value is used without validation. This may result in invalid memory access bugs. This patch fixes the bug. Signed-off-by: Pan Bian Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index d7107055ec60..2f656f395f39 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -128,6 +128,8 @@ static int qlcnic_sriov_virtid_fn(struct qlcnic_adapter *adapter, int vf_id) return 0; pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_SRIOV); + if (!pos) + return 0; pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); -- GitLab From 7ad1c43e6dc47c5ab1843180a3764a3dd982205a Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Sun, 23 Apr 2017 18:29:30 +0800 Subject: [PATCH 0649/1834] netfilter: nft_dynset: continue to next expr if _OP_ADD succeeded [ Upstream commit 277a292835c196894ef895d5e1fd6170bb916f55 ] Currently, after adding the following nft rules: # nft add set x target1 { type ipv4_addr \; flags timeout \;} # nft add rule x y set add ip daddr timeout 1d @target1 counter the counters will always be zero despite of the elements are added to the dynamic set "target1" or not, as we will break the nft expr traversal unconditionally: # nft list ruleset ... set target1 { ... elements = { 8.8.8.8 expires 23h59m53s} } chain output { ... set add ip daddr timeout 1d @target1 counter packets 0 bytes 0 ^ ^ ... } Since we add the elements to the set successfully, we should continue to the next expression. Additionally, if elements are added to "flow table" successfully, we will _always_ continue to the next expr, even if the operation is _OP_ADD. So it's better to keep them to be consistent. Fixes: 22fe54d5fefc ("netfilter: nf_tables: add support for dynamic set updates") Reported-by: Robert White Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nft_dynset.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c index 31ca94793aa9..b9dd4e960426 100644 --- a/net/netfilter/nft_dynset.c +++ b/net/netfilter/nft_dynset.c @@ -82,8 +82,7 @@ static void nft_dynset_eval(const struct nft_expr *expr, nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { timeout = priv->timeout ? : set->timeout; *nft_set_ext_expiration(ext) = jiffies + timeout; - } else if (sexpr == NULL) - goto out; + } if (sexpr != NULL) sexpr->ops->eval(sexpr, regs, pkt); @@ -92,7 +91,7 @@ static void nft_dynset_eval(const struct nft_expr *expr, regs->verdict.code = NFT_BREAK; return; } -out: + if (!priv->invert) regs->verdict.code = NFT_BREAK; } -- GitLab From 9338ee7eea66913d821e1db1ae7b308c1f99adbb Mon Sep 17 00:00:00 2001 From: Maarten Maathuis Date: Mon, 24 Apr 2017 23:35:21 +0200 Subject: [PATCH 0650/1834] platform/x86: intel-vbtn: add volume up and down [ Upstream commit 8d9e29972836b75eb74f533594999500a4c7cc19 ] Tested on HP Elite X2 1012 G1. Matches event report of Lenovo Helix 2 (https://www.spinics.net/lists/ibm-acpi-devel/msg03982.html). Signed-off-by: Maarten Maathuis [andy: fixed indentation of comments and massaged title of the change] Signed-off-by: Andy Shevchenko Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/intel-vbtn.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 78080763df51..a74340dff530 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -37,6 +37,10 @@ static const struct acpi_device_id intel_vbtn_ids[] = { static const struct key_entry intel_vbtn_keymap[] = { { KE_IGNORE, 0xC0, { KEY_POWER } }, /* power key press */ { KE_KEY, 0xC1, { KEY_POWER } }, /* power key release */ + { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* volume-up key press */ + { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* volume-up key release */ + { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* volume-down key press */ + { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ { KE_END }, }; -- GitLab From 8a15303518c005ae63ce1e22053822ea43db6dd1 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sun, 2 Apr 2017 17:08:05 +1000 Subject: [PATCH 0651/1834] scsi: mac_esp: Replace bogus memory barrier with spinlock [ Upstream commit 4da2b1eb230ba4ad19b58984dc52e05b1073df5f ] Commit da244654c66e ("[SCSI] mac_esp: fix for quadras with two esp chips") added mac_scsi_esp_intr() to handle the IRQ lines from a pair of on-board ESP chips (a normal shared IRQ did not work). Proper mutual exclusion was missing from that patch. This patch fixes race conditions between comparison and assignment of esp_chips[] pointers. Signed-off-by: Finn Thain Reviewed-by: Michael Schmitz Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mac_esp.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 14c0334f41e4..26c67c42985c 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -55,6 +55,7 @@ struct mac_esp_priv { int error; }; static struct esp *esp_chips[2]; +static DEFINE_SPINLOCK(esp_chips_lock); #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ platform_get_drvdata((struct platform_device *) \ @@ -562,15 +563,18 @@ static int esp_mac_probe(struct platform_device *dev) } host->irq = IRQ_MAC_SCSI; - esp_chips[dev->id] = esp; - mb(); - if (esp_chips[!dev->id] == NULL) { - err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); - if (err < 0) { - esp_chips[dev->id] = NULL; - goto fail_free_priv; - } + + /* The request_irq() call is intended to succeed for the first device + * and fail for the second device. + */ + err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); + spin_lock(&esp_chips_lock); + if (err < 0 && esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); + goto fail_free_priv; } + esp_chips[dev->id] = esp; + spin_unlock(&esp_chips_lock); err = scsi_esp_register(esp, &dev->dev); if (err) @@ -579,8 +583,13 @@ static int esp_mac_probe(struct platform_device *dev) return 0; fail_free_irq: - if (esp_chips[!dev->id] == NULL) + spin_lock(&esp_chips_lock); + esp_chips[dev->id] = NULL; + if (esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); free_irq(host->irq, esp); + } else + spin_unlock(&esp_chips_lock); fail_free_priv: kfree(mep); fail_free_command_block: @@ -599,9 +608,13 @@ static int esp_mac_remove(struct platform_device *dev) scsi_esp_unregister(esp); + spin_lock(&esp_chips_lock); esp_chips[dev->id] = NULL; - if (!(esp_chips[0] || esp_chips[1])) + if (esp_chips[!dev->id] == NULL) { + spin_unlock(&esp_chips_lock); free_irq(irq, NULL); + } else + spin_unlock(&esp_chips_lock); kfree(mep); -- GitLab From 81fa3239900f7fb378764318d200b5bb9c477cd6 Mon Sep 17 00:00:00 2001 From: Vlad Tsyrklevich Date: Fri, 24 Mar 2017 15:55:17 -0400 Subject: [PATCH 0652/1834] infiniband/uverbs: Fix integer overflows [ Upstream commit 4f7f4dcfff2c19debbcdbcc861c325610a15e0c5 ] The 'num_sge' variable is verfied to be smaller than the 'sge_count' variable; however, since both are user-controlled it's possible to cause an integer overflow for the kmalloc multiply on 32-bit platforms (num_sge and sge_count are both defined u32). By crafting an input that causes a smaller-than-expected allocation it's possible to write controlled data out-of-bounds. Signed-off-by: Vlad Tsyrklevich Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/uverbs_cmd.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index d118ffe0bfb6..4b717cf50d27 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2491,9 +2491,13 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, static void *alloc_wr(size_t wr_size, __u32 num_sge) { + if (num_sge >= (U32_MAX - ALIGN(wr_size, sizeof (struct ib_sge))) / + sizeof (struct ib_sge)) + return NULL; + return kmalloc(ALIGN(wr_size, sizeof (struct ib_sge)) + num_sge * sizeof (struct ib_sge), GFP_KERNEL); -}; +} ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, struct ib_device *ib_dev, @@ -2720,6 +2724,13 @@ static struct ib_recv_wr *ib_uverbs_unmarshall_recv(const char __user *buf, goto err; } + if (user_wr->num_sge >= + (U32_MAX - ALIGN(sizeof *next, sizeof (struct ib_sge))) / + sizeof (struct ib_sge)) { + ret = -EINVAL; + goto err; + } + next = kmalloc(ALIGN(sizeof *next, sizeof (struct ib_sge)) + user_wr->num_sge * sizeof (struct ib_sge), GFP_KERNEL); -- GitLab From b5e7b5ce7fa21d02b12d4383b003da22e79f91e1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 25 Apr 2017 11:26:53 -0400 Subject: [PATCH 0653/1834] pNFS: Fix use after free issues in pnfs_do_read() [ Upstream commit 6aeafd05eca9bc8ab6b03d7e56d09ffd18190f44 ] The assumption should be that if the caller returns PNFS_ATTEMPTED, then hdr has been consumed, and so we should not be testing hdr->task.tk_status. If the caller returns PNFS_TRY_AGAIN, then we need to recoalesce and free hdr. Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/pnfs.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index b8e44746f761..e9a697e9d292 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -2308,10 +2308,20 @@ pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr) enum pnfs_try_status trypnfs; trypnfs = pnfs_try_to_read_data(hdr, call_ops, lseg); - if (trypnfs == PNFS_TRY_AGAIN) - pnfs_read_resend_pnfs(hdr); - if (trypnfs == PNFS_NOT_ATTEMPTED || hdr->task.tk_status) + switch (trypnfs) { + case PNFS_NOT_ATTEMPTED: pnfs_read_through_mds(desc, hdr); + case PNFS_ATTEMPTED: + break; + case PNFS_TRY_AGAIN: + /* cleanup hdr and prepare to redo pnfs */ + if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { + struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc); + list_splice_init(&hdr->pages, &mirror->pg_list); + mirror->pg_recoalesce = 1; + } + hdr->mds_ops->rpc_release(hdr); + } } static void pnfs_readhdr_free(struct nfs_pgio_header *hdr) -- GitLab From abdb88128d3642ae378cf9239da4cb8228049476 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Tue, 11 Apr 2017 13:22:29 -0400 Subject: [PATCH 0654/1834] xprtrdma: Cancel refresh worker during buffer shutdown [ Upstream commit 9378b274e1eb6925db315e345f48850d2d5d9789 ] Trying to create MRs while the transport is being torn down can cause a crash. Fixes: e2ac236c0b65 ("xprtrdma: Allocate MRs on demand") Signed-off-by: Chuck Lever Signed-off-by: Anna Schumaker Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtrdma/verbs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 69502fa68a3c..1a2b1f61ed26 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -1054,6 +1054,7 @@ void rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) { cancel_delayed_work_sync(&buf->rb_recovery_worker); + cancel_delayed_work_sync(&buf->rb_refresh_worker); while (!list_empty(&buf->rb_recv_bufs)) { struct rpcrdma_rep *rep; -- GitLab From b5684e7a731d04dee1a2e9b76e5aba228647d5f9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 15 Mar 2017 12:40:44 +1100 Subject: [PATCH 0655/1834] NFS: don't try to cross a mountpount when there isn't one there. [ Upstream commit 99bbf6ecc694dfe0b026e15359c5aa2a60b97a93 ] consider the sequence of commands: mkdir -p /import/nfs /import/bind /import/etc mount --bind / /import/bind mount --make-private /import/bind mount --bind /import/etc /import/bind/etc exportfs -o rw,no_root_squash,crossmnt,async,no_subtree_check localhost:/ mount -o vers=4 localhost:/ /import/nfs ls -l /import/nfs/etc You would not expect this to report a stale file handle. Yet it does. The manipulations under /import/bind cause the dentry for /etc to get the DCACHE_MOUNTED flag set, even though nothing is mounted on /etc. This causes nfsd to call nfsd_cross_mnt() even though there is no mountpoint. So an upcall to mountd for "/etc" is performed. The 'crossmnt' flag on the export of / causes mountd to report that /etc is exported as it is a descendant of /. It assumes the kernel wouldn't ask about something that wasn't a mountpoint. The filehandle returned identifies the filesystem and the inode number of /etc. When this filehandle is presented to rpc.mountd, via "nfsd.fh", the inode cannot be found associated with any name in /etc/exports, or with any mountpoint listed by getmntent(). So rpc.mountd says the filehandle doesn't exist. Hence ESTALE. This is fixed by teaching nfsd not to trust DCACHE_MOUNTED too much. It is just a hint, not a guarantee. Change nfsd_mountpoint() to return '1' for a certain mountpoint, '2' for a possible mountpoint, and 0 otherwise. Then change nfsd_crossmnt() to check if follow_down() actually found a mountpount and, if not, to avoid performing a lookup if the location is not known to certainly require an export-point. Signed-off-by: NeilBrown Signed-off-by: J. Bruce Fields Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/vfs.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index b829cc9a9b39..8f0b19a3ca81 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -94,6 +94,12 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, err = follow_down(&path); if (err < 0) goto out; + if (path.mnt == exp->ex_path.mnt && path.dentry == dentry && + nfsd_mountpoint(dentry, exp) == 2) { + /* This is only a mountpoint in some other namespace */ + path_put(&path); + goto out; + } exp2 = rqst_exp_get_by_name(rqstp, &path); if (IS_ERR(exp2)) { @@ -167,16 +173,26 @@ static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, st /* * For nfsd purposes, we treat V4ROOT exports as though there was an * export at *every* directory. + * We return: + * '1' if this dentry *must* be an export point, + * '2' if it might be, if there is really a mount here, and + * '0' if there is no chance of an export point here. */ int nfsd_mountpoint(struct dentry *dentry, struct svc_export *exp) { - if (d_mountpoint(dentry)) + if (!d_inode(dentry)) + return 0; + if (exp->ex_flags & NFSEXP_V4ROOT) return 1; if (nfsd4_is_junction(dentry)) return 1; - if (!(exp->ex_flags & NFSEXP_V4ROOT)) - return 0; - return d_inode(dentry) != NULL; + if (d_mountpoint(dentry)) + /* + * Might only be a mountpoint in a different namespace, + * but we need to check. + */ + return 2; + return 0; } __be32 -- GitLab From 19b0f2fad8ceb65480e8faf5cb8f7de015b94655 Mon Sep 17 00:00:00 2001 From: Shrirang Bagul Date: Wed, 19 Apr 2017 22:05:00 +0800 Subject: [PATCH 0656/1834] iio: st_pressure: st_accel: Initialise sensor platform data properly [ Upstream commit 7383d44b84c94aaca4bf695a6bd8a69f2295ef1a ] This patch fixes the sensor platform data initialisation for st_pressure and st_accel device drivers. Without this patch, the driver fails to register the sensors when the user removes and re-loads the driver. 1. Unload the kernel modules for st_pressure $ sudo rmmod st_pressure_i2c $ sudo rmmod st_pressure 2. Re-load the driver $ sudo insmod st_pressure $ sudo insmod st_pressure_i2c Signed-off-by: Jonathan Cameron Acked-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iio/accel/st_accel_core.c | 7 ++++--- drivers/iio/pressure/st_pressure_core.c | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 3a557e3181ea..fe94415a0bc7 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -827,6 +827,8 @@ static const struct iio_trigger_ops st_accel_trigger_ops = { int st_accel_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); + struct st_sensors_platform_data *pdata = + (struct st_sensors_platform_data *)adata->dev->platform_data; int irq = adata->get_irq_data_ready(indio_dev); int err; @@ -853,9 +855,8 @@ int st_accel_common_probe(struct iio_dev *indio_dev) &adata->sensor_settings->fs.fs_avl[0]; adata->odr = adata->sensor_settings->odr.odr_avl[0].hz; - if (!adata->dev->platform_data) - adata->dev->platform_data = - (struct st_sensors_platform_data *)&default_accel_pdata; + if (!pdata) + pdata = (struct st_sensors_platform_data *)&default_accel_pdata; err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data); if (err < 0) diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 44e46c159a7e..bec60299b6ec 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -638,6 +638,8 @@ static const struct iio_trigger_ops st_press_trigger_ops = { int st_press_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *press_data = iio_priv(indio_dev); + struct st_sensors_platform_data *pdata = + (struct st_sensors_platform_data *)press_data->dev->platform_data; int irq = press_data->get_irq_data_ready(indio_dev); int err; @@ -673,10 +675,8 @@ int st_press_common_probe(struct iio_dev *indio_dev) press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz; /* Some devices don't support a data ready pin. */ - if (!press_data->dev->platform_data && - press_data->sensor_settings->drdy_irq.addr) - press_data->dev->platform_data = - (struct st_sensors_platform_data *)&default_press_pdata; + if (!pdata && press_data->sensor_settings->drdy_irq.addr) + pdata = (struct st_sensors_platform_data *)&default_press_pdata; err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data); if (err < 0) -- GitLab From 9d79cd54ba0e3b712d734eb24210432680900154 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 15:00:23 +0800 Subject: [PATCH 0657/1834] mt7601u: check return value of alloc_skb [ Upstream commit 5fb01e91daf84ad1e50edfcf63116ecbe31e7ba7 ] Function alloc_skb() will return a NULL pointer if there is no enough memory. However, in function mt7601u_mcu_msg_alloc(), its return value is not validated before it is used. This patch fixes it. Signed-off-by: Pan Bian Acked-by: Jakub Kicinski Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/mediatek/mt7601u/mcu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index dbdfb3f5c507..a9f5f398b2f8 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -66,8 +66,10 @@ mt7601u_mcu_msg_alloc(struct mt7601u_dev *dev, const void *data, int len) WARN_ON(len % 4); /* if length is not divisible by 4 we need to pad */ skb = alloc_skb(len + MT_DMA_HDR_LEN + 4, GFP_KERNEL); - skb_reserve(skb, MT_DMA_HDR_LEN); - memcpy(skb_put(skb, len), data, len); + if (skb) { + skb_reserve(skb, MT_DMA_HDR_LEN); + memcpy(skb_put(skb, len), data, len); + } return skb; } @@ -170,6 +172,8 @@ static int mt7601u_mcu_function_select(struct mt7601u_dev *dev, }; skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); + if (!skb) + return -ENOMEM; return mt7601u_mcu_msg_send(dev, skb, CMD_FUN_SET_OP, func == 5); } @@ -205,6 +209,8 @@ mt7601u_mcu_calibrate(struct mt7601u_dev *dev, enum mcu_calibrate cal, u32 val) }; skb = mt7601u_mcu_msg_alloc(dev, &msg, sizeof(msg)); + if (!skb) + return -ENOMEM; return mt7601u_mcu_msg_send(dev, skb, CMD_CALIBRATION_OP, true); } -- GitLab From 0397b294e87940c35af30e0a5bd6cfc110d132cb Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 21:19:38 +0800 Subject: [PATCH 0658/1834] libertas: check return value of alloc_workqueue [ Upstream commit dc3f89c38a8406554ffeffa370aad086a9c5e9de ] Function alloc_workqueue() will return a NULL pointer if there is no enough memory, and its return value should be validated before using. However, in function if_spi_probe(), its return value is not checked. This may result in a NULL dereference bug. This patch fixes the bug. Signed-off-by: Pan Bian Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/marvell/libertas/if_spi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index c3a53cd6988e..7b4955cc38db 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1181,6 +1181,10 @@ static int if_spi_probe(struct spi_device *spi) /* Initialize interrupt handling stuff. */ card->workqueue = alloc_workqueue("libertas_spi", WQ_MEM_RECLAIM, 0); + if (!card->workqueue) { + err = -ENOMEM; + goto remove_card; + } INIT_WORK(&card->packet_work, if_spi_host_to_card_worker); INIT_WORK(&card->resume_work, if_spi_resume_worker); @@ -1209,6 +1213,7 @@ static int if_spi_probe(struct spi_device *spi) free_irq(spi->irq, card); terminate_workqueue: destroy_workqueue(card->workqueue); +remove_card: lbs_remove_card(priv); /* will call free_netdev */ free_card: free_if_spi_card(card); -- GitLab From c3161cdbccf1ea0d516ad029ef6f1b3be0b65708 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Mon, 24 Apr 2017 08:40:28 +0800 Subject: [PATCH 0659/1834] rndis_wlan: add return value validation [ Upstream commit 9dc7efd3978aa67ae598129d2a3f240b390ce508 ] Function create_singlethread_workqueue() will return a NULL pointer if there is no enough memory, and its return value should be validated before using. However, in function rndis_wlan_bind(), its return value is not checked. This may cause NULL dereference bugs. This patch fixes it. Signed-off-by: Pan Bian Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/rndis_wlan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 603c90470225..15b2350d9f45 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -3427,6 +3427,10 @@ static int rndis_wlan_bind(struct usbnet *usbdev, struct usb_interface *intf) /* because rndis_command() sleeps we need to use workqueue */ priv->workqueue = create_singlethread_workqueue("rndis_wlan"); + if (!priv->workqueue) { + wiphy_free(wiphy); + return -ENOMEM; + } INIT_WORK(&priv->work, rndis_wlan_worker); INIT_DELAYED_WORK(&priv->dev_poller_work, rndis_device_poller); INIT_DELAYED_WORK(&priv->scan_work, rndis_get_scan_results); -- GitLab From fd35ded5b59bf4d0c7e154b3bd5b72c5c06591e9 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Wed, 8 Mar 2017 16:43:49 +0000 Subject: [PATCH 0660/1834] Btrfs: fix incorrect space accounting after failure to insert inline extent [ Upstream commit 1c81ba237bcecad9bc885a1ddcf02d725ea38482 ] When using compression, if we fail to insert an inline extent we incorrectly end up attempting to free the reserved data space twice, once through extent_clear_unlock_delalloc(), because we pass it the flag EXTENT_DO_ACCOUNTING, and once through a direct call to btrfs_free_reserved_data_space_noquota(). This results in a trace like the following: [ 834.576240] ------------[ cut here ]------------ [ 834.576825] WARNING: CPU: 2 PID: 486 at fs/btrfs/extent-tree.c:4316 btrfs_free_reserved_data_space_noquota+0x60/0x9f [btrfs] [ 834.579501] Modules linked in: btrfs crc32c_generic xor raid6_pq ppdev i2c_piix4 acpi_cpufreq psmouse tpm_tis parport_pc pcspkr serio_raw tpm_tis_core sg parport evdev i2c_core tpm button loop autofs4 ext4 crc16 jbd2 mbcache sr_mod cdrom sd_mod ata_generic virtio_scsi ata_piix virtio_pci libata virtio_ring virtio scsi_mod e1000 floppy [last unloaded: btrfs] [ 834.592116] CPU: 2 PID: 486 Comm: kworker/u32:4 Not tainted 4.10.0-rc8-btrfs-next-37+ #2 [ 834.593316] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.9.1-0-gb3ef39f-prebuilt.qemu-project.org 04/01/2014 [ 834.595273] Workqueue: btrfs-delalloc btrfs_delalloc_helper [btrfs] [ 834.596103] Call Trace: [ 834.596103] dump_stack+0x67/0x90 [ 834.596103] __warn+0xc2/0xdd [ 834.596103] warn_slowpath_null+0x1d/0x1f [ 834.596103] btrfs_free_reserved_data_space_noquota+0x60/0x9f [btrfs] [ 834.596103] compress_file_range.constprop.42+0x2fa/0x3fc [btrfs] [ 834.596103] ? submit_compressed_extents+0x3a7/0x3a7 [btrfs] [ 834.596103] async_cow_start+0x32/0x4d [btrfs] [ 834.596103] btrfs_scrubparity_helper+0x187/0x3e7 [btrfs] [ 834.596103] btrfs_delalloc_helper+0xe/0x10 [btrfs] [ 834.596103] process_one_work+0x273/0x4e4 [ 834.596103] worker_thread+0x1eb/0x2ca [ 834.596103] ? rescuer_thread+0x2b6/0x2b6 [ 834.596103] kthread+0x100/0x108 [ 834.596103] ? __list_del_entry+0x22/0x22 [ 834.596103] ret_from_fork+0x2e/0x40 [ 834.611656] ---[ end trace 719902fe6bdef08f ]--- So fix this by not calling directly btrfs_free_reserved_data_space_noquota() if an error happened. Signed-off-by: Filipe Manana Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/inode.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d196ce4be31c..ffd5831ca15c 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -567,8 +567,10 @@ static noinline void compress_file_range(struct inode *inode, PAGE_SET_WRITEBACK | page_error_op | PAGE_END_WRITEBACK); - btrfs_free_reserved_data_space_noquota(inode, start, - end - start + 1); + if (ret == 0) + btrfs_free_reserved_data_space_noquota(inode, + start, + end - start + 1); goto free_pages_out; } } -- GitLab From 7016b20cab9b6e7e6d898355ea43eb07ecae14ad Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Tue, 4 Apr 2017 20:31:00 +0100 Subject: [PATCH 0661/1834] Btrfs: send, fix file hole not being preserved due to inline extent [ Upstream commit e1cbfd7bf6dabdac561c75d08357571f44040a45 ] Normally we don't have inline extents followed by regular extents, but there's currently at least one harmless case where this happens. For example, when the page size is 4Kb and compression is enabled: $ mkfs.btrfs -f /dev/sdb $ mount -o compress /dev/sdb /mnt $ xfs_io -f -c "pwrite -S 0xaa 0 4K" -c "fsync" /mnt/foobar $ xfs_io -c "pwrite -S 0xbb 8K 4K" -c "fsync" /mnt/foobar In this case we get a compressed inline extent, representing 4Kb of data, followed by a hole extent and then a regular data extent. The inline extent was not expanded/converted to a regular extent exactly because it represents 4Kb of data. This does not cause any apparent problem (such as the issue solved by commit e1699d2d7bf6 ("btrfs: add missing memset while reading compressed inline extents")) except trigger an unexpected case in the incremental send code path that makes us issue an operation to write a hole when it's not needed, resulting in more writes at the receiver and wasting space at the receiver. So teach the incremental send code to deal with this particular case. The issue can be currently triggered by running fstests btrfs/137 with compression enabled (MOUNT_OPTIONS="-o compress" ./check btrfs/137). Signed-off-by: Filipe Manana Reviewed-by: Liu Bo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/send.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c index 9a47b5598df7..d040afc966fe 100644 --- a/fs/btrfs/send.c +++ b/fs/btrfs/send.c @@ -5156,13 +5156,19 @@ static int is_extent_unchanged(struct send_ctx *sctx, while (key.offset < ekey->offset + left_len) { ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); right_type = btrfs_file_extent_type(eb, ei); - if (right_type != BTRFS_FILE_EXTENT_REG) { + if (right_type != BTRFS_FILE_EXTENT_REG && + right_type != BTRFS_FILE_EXTENT_INLINE) { ret = 0; goto out; } right_disknr = btrfs_file_extent_disk_bytenr(eb, ei); - right_len = btrfs_file_extent_num_bytes(eb, ei); + if (right_type == BTRFS_FILE_EXTENT_INLINE) { + right_len = btrfs_file_extent_inline_len(eb, slot, ei); + right_len = PAGE_ALIGN(right_len); + } else { + right_len = btrfs_file_extent_num_bytes(eb, ei); + } right_offset = btrfs_file_extent_offset(eb, ei); right_gen = btrfs_file_extent_generation(eb, ei); @@ -5176,6 +5182,19 @@ static int is_extent_unchanged(struct send_ctx *sctx, goto out; } + /* + * We just wanted to see if when we have an inline extent, what + * follows it is a regular extent (wanted to check the above + * condition for inline extents too). This should normally not + * happen but it's possible for example when we have an inline + * compressed extent representing data with a size matching + * the page size (currently the same as sector size). + */ + if (right_type == BTRFS_FILE_EXTENT_INLINE) { + ret = 0; + goto out; + } + left_offset_fixed = left_offset; if (key.offset < ekey->offset) { /* Fix the right offset for 2a and 7. */ -- GitLab From dfe9db1d7d40d277e79746bbcfc3046f64d57ba0 Mon Sep 17 00:00:00 2001 From: Filipe Manana Date: Mon, 3 Apr 2017 15:57:17 +0100 Subject: [PATCH 0662/1834] Btrfs: fix extent map leak during fallocate error path [ Upstream commit be2d253cc98244765323a7c94cc1ac5cd5a17072 ] If the call to btrfs_qgroup_reserve_data() failed, we were leaking an extent map structure. The failure can happen either due to an -ENOMEM condition or, when quotas are enabled, due to -EDQUOT for example. Signed-off-by: Filipe Manana Reviewed-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/file.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 3286a6e47ff0..c95ff096cd24 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c @@ -2817,8 +2817,10 @@ static long btrfs_fallocate(struct file *file, int mode, } ret = btrfs_qgroup_reserve_data(inode, cur_offset, last_byte - cur_offset); - if (ret < 0) + if (ret < 0) { + free_extent_map(em); break; + } } else { /* * Do not need to reserve unwritten extent for this -- GitLab From 688b8451ee72f1ce5cc2e70297960597cfcf19ae Mon Sep 17 00:00:00 2001 From: Martin Brandenburg Date: Tue, 25 Apr 2017 15:38:07 -0400 Subject: [PATCH 0663/1834] orangefs: do not wait for timeout if umounting [ Upstream commit b5a9d61eebdd0016ccb383b25a5c3d04977a6549 ] When the computer is turned off, all the processes are killed and then all the filesystems are umounted. OrangeFS should not wait for the userspace daemon to come back in that case. This only works for plain umount(2). To actually take advantage of this interactively, `umount -f' is needed; otherwise umount will issue a statfs first, which will wait for the userspace daemon to come back. Signed-off-by: Martin Brandenburg Signed-off-by: Mike Marshall Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/orangefs/waitqueue.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/orangefs/waitqueue.c b/fs/orangefs/waitqueue.c index f61b00887481..cbca58ba008a 100644 --- a/fs/orangefs/waitqueue.c +++ b/fs/orangefs/waitqueue.c @@ -124,7 +124,14 @@ int service_operation(struct orangefs_kernel_op_s *op, gossip_debug(GOSSIP_WAIT_DEBUG, "%s:client core is NOT in service.\n", __func__); - timeout = op_timeout_secs * HZ; + /* + * Don't wait for the userspace component to return if + * the filesystem is being umounted anyway. + */ + if (op->upcall.type == ORANGEFS_VFS_OP_FS_UMOUNT) + timeout = 0; + else + timeout = op_timeout_secs * HZ; } spin_unlock(&orangefs_request_list_lock); -- GitLab From e864196707d102f13a3ab6152c7f647628ffaefa Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 26 Apr 2017 10:58:51 +0300 Subject: [PATCH 0664/1834] mac80211: don't parse encrypted management frames in ieee80211_frame_acked [ Upstream commit cf147085fdda044622973a12e4e06f1c753ab677 ] ieee80211_frame_acked is called when a frame is acked by the peer. In case this is a management frame, we check if this an SMPS frame, in which case we can update our antenna configuration. When we parse the management frame we look at the category in case it is an action frame. That byte sits after the IV in case the frame was encrypted. This means that if the frame was encrypted, we basically look at the IV instead of looking at the category. It is then theorically possible that we think that an SMPS action frame was acked where really we had another frame that was encrypted. Since the only management frame whose ack needs to be tracked is the SMPS action frame, and that frame is not a robust management frame, it will never be encrypted. The easiest way to fix this problem is then to not look at frames that were encrypted. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/status.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/status.c b/net/mac80211/status.c index ad37b4e58c2f..72fe9bc7a1f9 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -200,6 +200,7 @@ static void ieee80211_frame_acked(struct sta_info *sta, struct sk_buff *skb) } if (ieee80211_is_action(mgmt->frame_control) && + !ieee80211_has_protected(mgmt->frame_control) && mgmt->u.action.category == WLAN_CATEGORY_HT && mgmt->u.action.u.ht_smps.action == WLAN_HT_ACTION_SMPS && ieee80211_sdata_running(sdata)) { -- GitLab From 0fff422f157f4e0b64591d4802d0ebe5b0b1579b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 26 Apr 2017 16:18:49 +0800 Subject: [PATCH 0665/1834] ACPICA: iasl: Fix IORT SMMU GSI disassembling [ Upstream commit bb1e23e66e6237ff7a1824b37366540a89149c33 ] ACPICA commit 637b88de24a78c20478728d9d66632b06fcaa5bf If the IORT template is compiled and then iort.aml binary disassembled to iort.dsl, SMMUv1 node lists incorrect offset for SMMU_Nsg_cfg_irpt Interrupt: [0ECh 0236 8] SMMU_Nsg_irpt Interrupt : 0000000000000000 [0ECh 0236 8] SMMU_Nsg_cfg_irpt Interrupt : 0000000000000000 This is because iasl hasn't implemented SMMU GSI decoding yet. This patch fixes this issue by preparing structures for decoding IORT SMMU GSI. ACPICA BZ 1340, reported by Alexei Fedorov, fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/637b88de Link: https://bugs.acpica.org/show_bug.cgi?id=1340 Reported-by: Alexei Fedorov Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/acpi/actbl2.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index c93dbadfc71d..db7d15b6a580 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -783,6 +783,15 @@ struct acpi_iort_smmu { #define ACPI_IORT_SMMU_DVM_SUPPORTED (1) #define ACPI_IORT_SMMU_COHERENT_WALK (1<<1) +/* Global interrupt format */ + +struct acpi_iort_smmu_gsi { + u32 nsg_irpt; + u32 nsg_irpt_flags; + u32 nsg_cfg_irpt; + u32 nsg_cfg_irpt_flags; +}; + struct acpi_iort_smmu_v3 { u64 base_address; /* SMMUv3 base address */ u32 flags; -- GitLab From 3a0c4d9778df57772d07ea241a2cc1f734dee986 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 19 Apr 2017 15:35:48 +0100 Subject: [PATCH 0666/1834] iio: hid-sensor: fix return of -EINVAL on invalid values in ret or value [ Upstream commit c894acc7bf400d039bf740420b22f0b71b7fb504 ] Ensure that when an invalid value in ret or value is found -EINVAL is returned. A previous commit broke the way the return error is being returned and instead caused the return code in ret to be re-assigned rather than be returned. Fixes: 5d9854eaea776 ("iio: hid-sensor: Store restore poll and hysteresis on S3") Signed-off-by: Colin Ian King Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iio/common/hid-sensors/hid-sensor-attributes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index ab646a90e3da..af85db50412e 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -215,7 +215,7 @@ int hid_sensor_write_samp_freq_value(struct hid_sensor_common *st, ret = sensor_hub_set_feature(st->hsdev, st->poll.report_id, st->poll.index, sizeof(value), &value); if (ret < 0 || value < 0) - ret = -EINVAL; + return -EINVAL; ret = sensor_hub_get_feature(st->hsdev, st->poll.report_id, @@ -265,7 +265,7 @@ int hid_sensor_write_raw_hyst_value(struct hid_sensor_common *st, st->sensitivity.index, sizeof(value), &value); if (ret < 0 || value < 0) - ret = -EINVAL; + return -EINVAL; ret = sensor_hub_get_feature(st->hsdev, st->sensitivity.report_id, -- GitLab From 3ba6aff7f6539d6923646eed031fcd032dc624f9 Mon Sep 17 00:00:00 2001 From: Rask Ingemann Lambertsen Date: Wed, 22 Feb 2017 20:41:02 +0100 Subject: [PATCH 0667/1834] dt-bindings: mfd: axp20x: Add "xpowers,master-mode" property for AXP806 PMICs [ Upstream commit 8461cf20d17e0090e9236b73d25b31be4f7fadc5 ] commit b101829a029a ("mfd: axp20x: Fix AXP806 access errors on cold boot") was intended to fix the case where a board uses an AXP806 in slave mode, but the boot loader leaves it in master mode for lack of AXP806 support. But now the driver breaks on boards where the PMIC is operating in master mode. To let the device tree describe which mode of operation is needed, this patch introduces a new property "xpowers,master-mode". Fixes: 204ae2963e10 ("mfd: axp20x: Add bindings for AXP806 PMIC") Signed-off-by: Rask Ingemann Lambertsen Acked-by: Chen-Yu Tsai Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/mfd/axp20x.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/axp20x.txt b/Documentation/devicetree/bindings/mfd/axp20x.txt index 8f3ad9ab4637..b41d2601c6ba 100644 --- a/Documentation/devicetree/bindings/mfd/axp20x.txt +++ b/Documentation/devicetree/bindings/mfd/axp20x.txt @@ -28,6 +28,9 @@ Optional properties: regulator to drive the OTG VBus, rather then as an input pin which signals whether the board is driving OTG VBus or not. +- x-powers,master-mode: Boolean (axp806 only). Set this when the PMIC is + wired for master mode. The default is slave mode. + - -supply: a phandle to the regulator supply node. May be omitted if inputs are unregulated, such as using the IPSOUT output from the PMIC. -- GitLab From 6ed083b35d291e06b1792fd4ff3fb45b5ab6e5c5 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Thu, 10 Nov 2016 10:39:18 +0530 Subject: [PATCH 0668/1834] mfd: palmas: Reset the POWERHOLD mux during power off [ Upstream commit 85fdaf8eb9bbec1f0f8a52fd5d85659d60738816 ] POWERHOLD signal has higher priority over the DEV_ON bit. So power off will not happen if the POWERHOLD is held high. Hence reset the MUX to GPIO_7 mode to release the POWERHOLD and the DEV_ON bit to take effect to power off the PMIC. PMIC Power off happens in dire situations like thermal shutdown so irrespective of the POWERHOLD setting go ahead and turn off the powerhold. Currently poweroff is broken on boards that have powerhold enabled. This fixes poweroff on those boards. Signed-off-by: Keerthy Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/palmas.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 8f8bacb67a15..a6b5259ffbdd 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -430,6 +430,20 @@ static void palmas_power_off(void) { unsigned int addr; int ret, slave; + struct device_node *np = palmas_dev->dev->of_node; + + if (of_property_read_bool(np, "ti,palmas-override-powerhold")) { + addr = PALMAS_BASE_TO_REG(PALMAS_PU_PD_OD_BASE, + PALMAS_PRIMARY_SECONDARY_PAD2); + slave = PALMAS_BASE_TO_SLAVE(PALMAS_PU_PD_OD_BASE); + + ret = regmap_update_bits(palmas_dev->regmap[slave], addr, + PALMAS_PRIMARY_SECONDARY_PAD2_GPIO_7_MASK, 0); + if (ret) + dev_err(palmas_dev->dev, + "Unable to write PRIMARY_SECONDARY_PAD2 %d\n", + ret); + } if (!palmas_dev) return; -- GitLab From db54facd56a40e7766bf7f7cda1ae138e72a691c Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 27 Apr 2017 07:45:18 -0600 Subject: [PATCH 0669/1834] mtip32xx: use runtime tag to initialize command header [ Upstream commit a4e84aae8139aca9fbfbced1f45c51ca81b57488 ] mtip32xx supposes that 'request_idx' passed to .init_request() is tag of the request, and use that as request's tag to initialize command header. After MQ IO scheduler is in, request tag assigned isn't same with the request index anymore, so cause strange hardware failure on mtip32xx, even whole system panic is triggered. This patch fixes the issue by initializing command header via request's real tag. Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/block/mtip32xx/mtip32xx.c | 36 ++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 3cfd879267b2..b86273fdf48e 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -169,6 +169,25 @@ static bool mtip_check_surprise_removal(struct pci_dev *pdev) return false; /* device present */ } +/* we have to use runtime tag to setup command header */ +static void mtip_init_cmd_header(struct request *rq) +{ + struct driver_data *dd = rq->q->queuedata; + struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); + u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64; + + /* Point the command headers at the command tables. */ + cmd->command_header = dd->port->command_list + + (sizeof(struct mtip_cmd_hdr) * rq->tag); + cmd->command_header_dma = dd->port->command_list_dma + + (sizeof(struct mtip_cmd_hdr) * rq->tag); + + if (host_cap_64) + cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16); + + cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF); +} + static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd) { struct request *rq; @@ -180,6 +199,9 @@ static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd) if (IS_ERR(rq)) return NULL; + /* Internal cmd isn't submitted via .queue_rq */ + mtip_init_cmd_header(rq); + return blk_mq_rq_to_pdu(rq); } @@ -3811,6 +3833,8 @@ static int mtip_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq = bd->rq; int ret; + mtip_init_cmd_header(rq); + if (unlikely(mtip_check_unal_depth(hctx, rq))) return BLK_MQ_RQ_QUEUE_BUSY; @@ -3842,7 +3866,6 @@ static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx, { struct driver_data *dd = data; struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); - u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64; /* * For flush requests, request_idx starts at the end of the @@ -3859,17 +3882,6 @@ static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx, memset(cmd->command, 0, CMD_DMA_ALLOC_SZ); - /* Point the command headers at the command tables. */ - cmd->command_header = dd->port->command_list + - (sizeof(struct mtip_cmd_hdr) * request_idx); - cmd->command_header_dma = dd->port->command_list_dma + - (sizeof(struct mtip_cmd_hdr) * request_idx); - - if (host_cap_64) - cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16); - - cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF); - sg_init_table(cmd->sg, MTIP_MAX_SG); return 0; } -- GitLab From 5b0425c6b654028da99bab00b7c9a6eba87cd01b Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Thu, 27 Apr 2017 15:42:20 +0800 Subject: [PATCH 0670/1834] x86/KASLR: Fix kexec kernel boot crash when KASLR randomization fails [ Upstream commit da63b6b20077469bd6bd96e07991ce145fc4fbc4 ] Dave found that a kdump kernel with KASLR enabled will reset to the BIOS immediately if physical randomization failed to find a new position for the kernel. A kernel with the 'nokaslr' option works in this case. The reason is that KASLR will install a new page table for the identity mapping, while it missed building it for the original kernel location if KASLR physical randomization fails. This only happens in the kexec/kdump kernel, because the identity mapping has been built for kexec/kdump in the 1st kernel for the whole memory by calling init_pgtable(). Here if physical randomizaiton fails, it won't build the identity mapping for the original area of the kernel but change to a new page table '_pgtable'. Then the kernel will triple fault immediately caused by no identity mappings. The normal kernel won't see this bug, because it comes here via startup_32() and CR3 will be set to _pgtable already. In startup_32() the identity mapping is built for the 0~4G area. In KASLR we just append to the existing area instead of entirely overwriting it for on-demand identity mapping building. So the identity mapping for the original area of kernel is still there. To fix it we just switch to the new identity mapping page table when physical KASLR succeeds. Otherwise we keep the old page table unchanged just like "nokaslr" does. Signed-off-by: Baoquan He Signed-off-by: Dave Young Acked-by: Kees Cook Cc: Borislav Petkov Cc: Dave Jiang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Garnier Cc: Thomas Gleixner Cc: Yinghai Lu Link: http://lkml.kernel.org/r/1493278940-5885-1-git-send-email-bhe@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/boot/compressed/kaslr.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86/boot/compressed/kaslr.c b/arch/x86/boot/compressed/kaslr.c index 6de58f1bd7ec..eb5ff66b4d7a 100644 --- a/arch/x86/boot/compressed/kaslr.c +++ b/arch/x86/boot/compressed/kaslr.c @@ -460,10 +460,17 @@ void choose_random_location(unsigned long input, add_identity_map(random_addr, output_size); *output = random_addr; } + + /* + * This loads the identity mapping page table. + * This should only be done if a new physical address + * is found for the kernel, otherwise we should keep + * the old page table to make it be like the "nokaslr" + * case. + */ + finalize_identity_maps(); } - /* This actually loads the identity pagetable on x86_64. */ - finalize_identity_maps(); /* Pick random virtual address starting from LOAD_PHYSICAL_ADDR. */ if (IS_ENABLED(CONFIG_X86_64)) -- GitLab From ccda7d225dc55e8518a8aad974885ea3f0456a65 Mon Sep 17 00:00:00 2001 From: Kuppuswamy Sathyanarayanan Date: Mon, 24 Apr 2017 12:15:04 -0700 Subject: [PATCH 0671/1834] gpio: gpio-wcove: fix GPIO IRQ status mask [ Upstream commit 881ebd229f4a5ea88f269c1225245e50db9ba303 ] According to Whiskey Cove PMIC spec, bit 7 of GPIOIRQ0_REG belongs to battery IO. So we should skip this bit when checking for GPIO IRQ pending status. Otherwise, wcove_gpio_irq_handler() might go into the infinite loop until IRQ "pending" status becomes 0. This patch fixes this issue. Signed-off-by: Kuppuswamy Sathyanarayanan Acked-by: Mika Westerberg Acked-by: Andy Shevchenko Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-wcove.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c index 1012c86925ad..5ef4980f3f14 100644 --- a/drivers/gpio/gpio-wcove.c +++ b/drivers/gpio/gpio-wcove.c @@ -51,6 +51,8 @@ #define GROUP1_NR_IRQS 6 #define IRQ_MASK_BASE 0x4e19 #define IRQ_STATUS_BASE 0x4e0b +#define GPIO_IRQ0_MASK GENMASK(6, 0) +#define GPIO_IRQ1_MASK GENMASK(5, 0) #define UPDATE_IRQ_TYPE BIT(0) #define UPDATE_IRQ_MASK BIT(1) @@ -310,7 +312,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) return IRQ_NONE; } - pending = p[0] | (p[1] << 8); + pending = (p[0] & GPIO_IRQ0_MASK) | ((p[1] & GPIO_IRQ1_MASK) << 7); if (!pending) return IRQ_NONE; @@ -334,7 +336,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data) break; } - pending = p[0] | (p[1] << 8); + pending = (p[0] & GPIO_IRQ0_MASK) | ((p[1] & GPIO_IRQ1_MASK) << 7); } return IRQ_HANDLED; -- GitLab From 6806bc0a63ef0797f429b0284f85f1c277d709be Mon Sep 17 00:00:00 2001 From: Sameer Wadgaonkar Date: Tue, 18 Apr 2017 16:55:25 -0400 Subject: [PATCH 0672/1834] staging: unisys: visorhba: fix s-Par to boot with option CONFIG_VMAP_STACK set to y [ Upstream commit 3c2bf0bd08123f3497bd3e84bd9088c937b0cb40 ] The root issue is that we are not allowed to have items on the stack being passed to "DMA" like operations. In this case we have a vmcall and an inline completion of scsi command. This patch fixes the issue by moving the variables on stack in do_scsi_nolinuxstat() to heap memory. Signed-off-by: Sameer Wadgaonkar Signed-off-by: David Kershner Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorhba/visorhba_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 5a7a87efed27..28b5392153a8 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -842,7 +842,7 @@ static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) { struct scsi_device *scsidev; - unsigned char buf[36]; + unsigned char *buf; struct scatterlist *sg; unsigned int i; char *this_page; @@ -857,6 +857,10 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) if (cmdrsp->scsi.no_disk_result == 0) return; + buf = kzalloc(sizeof(char) * 36, GFP_KERNEL); + if (!buf) + return; + /* Linux scsi code wants a device at Lun 0 * to issue report luns, but we don't want * a disk there so we'll present a processor @@ -868,6 +872,7 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) if (scsi_sg_count(scsicmd) == 0) { memcpy(scsi_sglist(scsicmd), buf, cmdrsp->scsi.bufflen); + kfree(buf); return; } @@ -879,6 +884,7 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) memcpy(this_page, buf + bufind, sg[i].length); kunmap_atomic(this_page_orig); } + kfree(buf); } else { devdata = (struct visorhba_devdata *)scsidev->host->hostdata; for_each_vdisk_match(vdisk, devdata, scsidev) { -- GitLab From 419707a9fbe14ec1877159707ecf4111197c38e8 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 19:53:58 +0800 Subject: [PATCH 0673/1834] staging: wilc1000: fix unchecked return value [ Upstream commit 9e96652756ad647b7bcc03cb99ffc9756d7b5f93 ] Function dev_alloc_skb() will return a NULL pointer if there is no enough memory. However, in function WILC_WFI_mon_xmit(), its return value is used without validation. This may result in a bad memory access bug. This patch fixes the bug. Signed-off-by: Pan Bian Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wilc1000/linux_mon.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/wilc1000/linux_mon.c b/drivers/staging/wilc1000/linux_mon.c index 242f82f4d24f..d8ab4cb11289 100644 --- a/drivers/staging/wilc1000/linux_mon.c +++ b/drivers/staging/wilc1000/linux_mon.c @@ -197,6 +197,8 @@ static netdev_tx_t WILC_WFI_mon_xmit(struct sk_buff *skb, if (skb->data[0] == 0xc0 && (!(memcmp(broadcast, &skb->data[4], 6)))) { skb2 = dev_alloc_skb(skb->len + sizeof(struct wilc_wfi_radiotap_cb_hdr)); + if (!skb2) + return -ENOMEM; memcpy(skb_put(skb2, skb->len), skb->data, skb->len); -- GitLab From dfe9c1de141667e360bb28e1e23904316a285607 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Thu, 20 Apr 2017 11:44:16 +0200 Subject: [PATCH 0674/1834] ipvs: explicitly forbid ipv6 service/dest creation if ipv6 mod is disabled [ Upstream commit 1442f6f7c1b77de1c508318164a527e240c24a4d ] When creating a new ipvs service, ipv6 addresses are always accepted if CONFIG_IP_VS_IPV6 is enabled. On dest creation the address family is not explicitly checked. This allows the user-space to configure ipvs services even if the system is booted with ipv6.disable=1. On specific configuration, ipvs can try to call ipv6 routing code at setup time, causing the kernel to oops due to fib6_rules_ops being NULL. This change addresses the issue adding a check for the ipv6 module being enabled while validating ipv6 service operations and adding the same validation for dest operations. According to git history, this issue is apparently present since the introduction of ipv6 support, and the oops can be triggered since commit 09571c7ae30865ad ("IPVS: Add function to determine if IPv6 address is local") Fixes: 09571c7ae30865ad ("IPVS: Add function to determine if IPv6 address is local") Signed-off-by: Paolo Abeni Acked-by: Julian Anastasov Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/ipvs/ip_vs_ctl.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 2155c2498aed..74d119512d96 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3092,6 +3092,17 @@ static int ip_vs_genl_dump_services(struct sk_buff *skb, return skb->len; } +static bool ip_vs_is_af_valid(int af) +{ + if (af == AF_INET) + return true; +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6 && ipv6_mod_enabled()) + return true; +#endif + return false; +} + static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs, struct ip_vs_service_user_kern *usvc, struct nlattr *nla, int full_entry, @@ -3118,11 +3129,7 @@ static int ip_vs_genl_parse_service(struct netns_ipvs *ipvs, memset(usvc, 0, sizeof(*usvc)); usvc->af = nla_get_u16(nla_af); -#ifdef CONFIG_IP_VS_IPV6 - if (usvc->af != AF_INET && usvc->af != AF_INET6) -#else - if (usvc->af != AF_INET) -#endif + if (!ip_vs_is_af_valid(usvc->af)) return -EAFNOSUPPORT; if (nla_fwmark) { @@ -3624,6 +3631,11 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) if (udest.af == 0) udest.af = svc->af; + if (!ip_vs_is_af_valid(udest.af)) { + ret = -EAFNOSUPPORT; + goto out; + } + if (udest.af != svc->af && cmd != IPVS_CMD_DEL_DEST) { /* The synchronization protocol is incompatible * with mixed family services -- GitLab From 92db807f6c2e2a05f00689ca7f23351400abf541 Mon Sep 17 00:00:00 2001 From: Mohammed Shafi Shajakhan Date: Thu, 27 Apr 2017 12:45:38 +0530 Subject: [PATCH 0675/1834] mac80211: Fix possible sband related NULL pointer de-reference [ Upstream commit 21a8e9dd52b64f0170bad208293ef8c30c3c1403 ] Existing API 'ieee80211_get_sdata_band' returns default 2 GHz band even if the channel context configuration is NULL. This crashes for chipsets which support 5 Ghz alone when it tries to access members of 'sband'. Channel context configuration can be NULL in multivif case and when channel switch is in progress (or) when it fails. Fix this by replacing the API 'ieee80211_get_sdata_band' with 'ieee80211_get_sband' which returns a NULL pointer for sband when the channel configuration is NULL. An example scenario is as below: In multivif mode (AP + STA) with drivers like ath10k, when we do a channel switch in the AP vif (which has a number of clients connected) and a STA vif which is connected to some other AP, when the channel switch in AP vif fails, while the STA vifs tries to connect to the other AP, there is a window where the channel context is NULL/invalid and this results in a crash while the clients connected to the AP vif tries to reconnect and this race is very similar to the one investigated by Michal in https://patchwork.kernel.org/patch/3788161/ and this does happens with hardware that supports 5Ghz alone after long hours of testing with continuous channel switch on the AP vif ieee80211 phy0: channel context reservation cannot be finalized because some interfaces aren't switching wlan0: failed to finalize CSA, disconnecting wlan0-1: deauthenticating from 8c:fd:f0:01:54:9c by local choice (Reason: 3=DEAUTH_LEAVING) WARNING: CPU: 1 PID: 19032 at net/mac80211/ieee80211_i.h:1013 sta_info_alloc+0x374/0x3fc [mac80211] [] (sta_info_alloc [mac80211]) [] (ieee80211_add_station [mac80211])) [] (nl80211_new_station [cfg80211]) Unable to handle kernel NULL pointer dereference at virtual address 00000014 pgd = d5f4c000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM PC is at sta_info_alloc+0x380/0x3fc [mac80211] LR is at sta_info_alloc+0x37c/0x3fc [mac80211] [] (sta_info_alloc [mac80211]) [] (ieee80211_add_station [mac80211]) [] (nl80211_new_station [cfg80211])) Cc: Michal Kazior Signed-off-by: Mohammed Shafi Shajakhan Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 30 +++++++++++++++++------------- net/mac80211/ibss.c | 6 +++++- net/mac80211/ieee80211_i.h | 36 +++++++++++++++++++++--------------- net/mac80211/mesh.c | 29 ++++++++++++++++++++--------- net/mac80211/mesh_plink.c | 37 ++++++++++++++++++++++++++----------- net/mac80211/mlme.c | 14 ++++++++++++-- net/mac80211/rate.c | 4 +++- net/mac80211/sta_info.c | 13 +++++++++---- net/mac80211/tdls.c | 29 +++++++++++++++++++---------- net/mac80211/tx.c | 5 ++++- net/mac80211/util.c | 6 +++--- 11 files changed, 139 insertions(+), 70 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index dee60428c78c..efa2a2fcae72 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -620,10 +620,11 @@ void sta_set_rate_info_tx(struct sta_info *sta, int shift = ieee80211_vif_get_shift(&sta->sdata->vif); u16 brate; - sband = sta->local->hw.wiphy->bands[ - ieee80211_get_sdata_band(sta->sdata)]; - brate = sband->bitrates[rate->idx].bitrate; - rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); + sband = ieee80211_get_sband(sta->sdata); + if (sband) { + brate = sband->bitrates[rate->idx].bitrate; + rinfo->legacy = DIV_ROUND_UP(brate, 1 << shift); + } } if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) rinfo->bw = RATE_INFO_BW_40; @@ -1218,10 +1219,11 @@ static int sta_apply_parameters(struct ieee80211_local *local, int ret = 0; struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); u32 mask, set; - sband = local->hw.wiphy->bands[band]; + sband = ieee80211_get_sband(sdata); + if (!sband) + return -EINVAL; mask = params->sta_flags_mask; set = params->sta_flags_set; @@ -1354,7 +1356,7 @@ static int sta_apply_parameters(struct ieee80211_local *local, ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef, sband, params->supported_rates, params->supported_rates_len, - &sta->sta.supp_rates[band]); + &sta->sta.supp_rates[sband->band]); } if (params->ht_capa) @@ -1370,8 +1372,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, /* returned value is only needed for rc update, but the * rc isn't initialized here yet, so ignore it */ - __ieee80211_vht_handle_opmode(sdata, sta, - params->opmode_notif, band); + __ieee80211_vht_handle_opmode(sdata, sta, params->opmode_notif, + sband->band); } if (params->support_p2p_ps >= 0) @@ -2017,13 +2019,15 @@ static int ieee80211_change_bss(struct wiphy *wiphy, struct bss_parameters *params) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - enum nl80211_band band; + struct ieee80211_supported_band *sband; u32 changed = 0; if (!sdata_dereference(sdata->u.ap.beacon, sdata)) return -ENOENT; - band = ieee80211_get_sdata_band(sdata); + sband = ieee80211_get_sband(sdata); + if (!sband) + return -EINVAL; if (params->use_cts_prot >= 0) { sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; @@ -2036,7 +2040,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, } if (!sdata->vif.bss_conf.use_short_slot && - band == NL80211_BAND_5GHZ) { + sband->band == NL80211_BAND_5GHZ) { sdata->vif.bss_conf.use_short_slot = true; changed |= BSS_CHANGED_ERP_SLOT; } @@ -2049,7 +2053,7 @@ static int ieee80211_change_bss(struct wiphy *wiphy, if (params->basic_rates) { ieee80211_parse_bitrates(&sdata->vif.bss_conf.chandef, - wiphy->bands[band], + wiphy->bands[sband->band], params->basic_rates, params->basic_rates_len, &sdata->vif.bss_conf.basic_rates); diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 62d13eabe17f..d31818e7d10c 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -994,7 +994,7 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, enum nl80211_band band = rx_status->band; enum nl80211_bss_scan_width scan_width; struct ieee80211_local *local = sdata->local; - struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; + struct ieee80211_supported_band *sband; bool rates_updated = false; u32 supp_rates = 0; @@ -1004,6 +1004,10 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata, if (!ether_addr_equal(mgmt->bssid, sdata->u.ibss.bssid)) return; + sband = local->hw.wiphy->bands[band]; + if (WARN_ON(!sband)) + return; + rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 03dbc6bd8598..7fd544d970d9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -991,21 +991,6 @@ sdata_assert_lock(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&sdata->wdev.mtx); } -static inline enum nl80211_band -ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata) -{ - enum nl80211_band band = NL80211_BAND_2GHZ; - struct ieee80211_chanctx_conf *chanctx_conf; - - rcu_read_lock(); - chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); - if (!WARN_ON(!chanctx_conf)) - band = chanctx_conf->def.chan->band; - rcu_read_unlock(); - - return band; -} - static inline int ieee80211_chandef_get_shift(struct cfg80211_chan_def *chandef) { @@ -1410,6 +1395,27 @@ IEEE80211_WDEV_TO_SUB_IF(struct wireless_dev *wdev) return container_of(wdev, struct ieee80211_sub_if_data, wdev); } +static inline struct ieee80211_supported_band * +ieee80211_get_sband(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *chanctx_conf; + enum nl80211_band band; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); + + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return NULL; + } + + band = chanctx_conf->def.chan->band; + rcu_read_unlock(); + + return local->hw.wiphy->bands[band]; +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b4b3fe078868..b2a27263d6ff 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -63,6 +63,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u32 basic_rates = 0; struct cfg80211_chan_def sta_chan_def; + struct ieee80211_supported_band *sband; /* * As support for each feature is added, check for matching @@ -83,7 +84,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) return false; - ieee80211_sta_get_rates(sdata, ie, ieee80211_get_sdata_band(sdata), + sband = ieee80211_get_sband(sdata); + if (!sband) + return false; + + ieee80211_sta_get_rates(sdata, ie, sband->band, &basic_rates); if (sdata->vif.bss_conf.basic_rates != basic_rates) @@ -399,12 +404,13 @@ static int mesh_add_ds_params_ie(struct ieee80211_sub_if_data *sdata, int mesh_add_ht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { - struct ieee80211_local *local = sdata->local; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_supported_band *sband; u8 *pos; - sband = local->hw.wiphy->bands[band]; + sband = ieee80211_get_sband(sdata); + if (!sband) + return -EINVAL; + if (!sband->ht_cap.ht_supported || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || @@ -462,12 +468,13 @@ int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { - struct ieee80211_local *local = sdata->local; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_supported_band *sband; u8 *pos; - sband = local->hw.wiphy->bands[band]; + sband = ieee80211_get_sband(sdata); + if (!sband) + return -EINVAL; + if (!sband->vht_cap.vht_supported || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || @@ -916,12 +923,16 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, struct cfg80211_csa_settings params; struct ieee80211_csa_ie csa_ie; struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); + struct ieee80211_supported_band *sband; int err; u32 sta_flags; sdata_assert_lock(sdata); + sband = ieee80211_get_sband(sdata); + if (!sband) + return false; + sta_flags = IEEE80211_STA_DISABLE_VHT; switch (sdata->vif.bss_conf.chandef.width) { case NL80211_CHAN_WIDTH_20_NOHT: @@ -935,7 +946,7 @@ ieee80211_mesh_process_chnswitch(struct ieee80211_sub_if_data *sdata, memset(¶ms, 0, sizeof(params)); memset(&csa_ie, 0, sizeof(csa_ie)); - err = ieee80211_parse_ch_switch_ie(sdata, elems, band, + err = ieee80211_parse_ch_switch_ie(sdata, elems, sband->band, sta_flags, sdata->vif.addr, &csa_ie); if (err < 0) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index fcba70e57073..2d3c4695e75b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -93,19 +93,23 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); - struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; + struct ieee80211_supported_band *sband; struct sta_info *sta; u32 erp_rates = 0, changed = 0; int i; bool short_slot = false; - if (band == NL80211_BAND_5GHZ) { + sband = ieee80211_get_sband(sdata); + if (!sband) + return changed; + + if (sband->band == NL80211_BAND_5GHZ) { /* (IEEE 802.11-2012 19.4.5) */ short_slot = true; goto out; - } else if (band != NL80211_BAND_2GHZ) + } else if (sband->band != NL80211_BAND_2GHZ) { goto out; + } for (i = 0; i < sband->n_bitrates; i++) if (sband->bitrates[i].flags & IEEE80211_RATE_ERP_G) @@ -121,7 +125,7 @@ static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata) continue; short_slot = false; - if (erp_rates & sta->sta.supp_rates[band]) + if (erp_rates & sta->sta.supp_rates[sband->band]) short_slot = true; else break; @@ -247,7 +251,15 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, mgmt->u.action.u.self_prot.action_code = action; if (action != WLAN_SP_MESH_PEERING_CLOSE) { - enum nl80211_band band = ieee80211_get_sdata_band(sdata); + struct ieee80211_supported_band *sband; + enum nl80211_band band; + + sband = ieee80211_get_sband(sdata); + if (!sband) { + err = -EINVAL; + goto free; + } + band = sband->band; /* capability info */ pos = skb_put(skb, 2); @@ -393,13 +405,16 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, struct ieee802_11_elems *elems, bool insert) { struct ieee80211_local *local = sdata->local; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); struct ieee80211_supported_band *sband; u32 rates, basic_rates = 0, changed = 0; enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth; - sband = local->hw.wiphy->bands[band]; - rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates); + sband = ieee80211_get_sband(sdata); + if (!sband) + return; + + rates = ieee80211_sta_get_rates(sdata, elems, sband->band, + &basic_rates); spin_lock_bh(&sta->mesh->plink_lock); sta->rx_stats.last_rx = jiffies; @@ -410,9 +425,9 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, goto out; sta->mesh->processed_beacon = true; - if (sta->sta.supp_rates[band] != rates) + if (sta->sta.supp_rates[sband->band] != rates) changed |= IEEE80211_RC_SUPP_RATES_CHANGED; - sta->sta.supp_rates[band] = rates; + sta->sta.supp_rates[sband->band] = rates; if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, elems->ht_cap_elem, sta)) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1118c61f835d..fdab4f1390d2 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1851,11 +1851,16 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, u16 capab, bool erp_valid, u8 erp) { struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; + struct ieee80211_supported_band *sband; u32 changed = 0; bool use_protection; bool use_short_preamble; bool use_short_slot; + sband = ieee80211_get_sband(sdata); + if (!sband) + return changed; + if (erp_valid) { use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0; use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0; @@ -1865,7 +1870,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, } use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); - if (ieee80211_get_sdata_band(sdata) == NL80211_BAND_5GHZ) + if (sband->band == NL80211_BAND_5GHZ) use_short_slot = true; if (use_protection != bss_conf->use_cts_prot) { @@ -2994,7 +2999,12 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, goto out; } - sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)]; + sband = ieee80211_get_sband(sdata); + if (!sband) { + mutex_unlock(&sdata->local->sta_mtx); + ret = false; + goto out; + } /* Set up internal HT/VHT capabilities */ if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 206698bc93f4..dbceb42c2a8e 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -875,7 +875,9 @@ int rate_control_set_rates(struct ieee80211_hw *hw, struct ieee80211_sta_rates *old; struct ieee80211_supported_band *sband; - sband = hw->wiphy->bands[ieee80211_get_sdata_band(sta->sdata)]; + sband = ieee80211_get_sband(sta->sdata); + if (!sband) + return -EINVAL; rate_control_apply_mask_ratetbl(sta, sband, rates); /* * mac80211 guarantees that this function will not be called diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 348700b424ea..1ecf3d07d1f5 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -395,10 +395,15 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->sta.smps_mode = IEEE80211_SMPS_OFF; if (sdata->vif.type == NL80211_IFTYPE_AP || sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { - struct ieee80211_supported_band *sband = - hw->wiphy->bands[ieee80211_get_sdata_band(sdata)]; - u8 smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> - IEEE80211_HT_CAP_SM_PS_SHIFT; + struct ieee80211_supported_band *sband; + u8 smps; + + sband = ieee80211_get_sband(sdata); + if (!sband) + goto free_txq; + + smps = (sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> + IEEE80211_HT_CAP_SM_PS_SHIFT; /* * Assume that hostapd advertises our caps in the beacon and * this is the known_smps_mode for a station that just assciated diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index afca7d103684..f20dcf1b1830 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -47,8 +47,7 @@ static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata, NL80211_FEATURE_TDLS_CHANNEL_SWITCH; bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) && !ifmgd->tdls_wider_bw_prohibited; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); - struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; + struct ieee80211_supported_band *sband = ieee80211_get_sband(sdata); bool vht = sband && sband->vht_cap.vht_supported; u8 *pos = (void *)skb_put(skb, 10); @@ -180,11 +179,14 @@ static void ieee80211_tdls_add_bss_coex_ie(struct sk_buff *skb) static u16 ieee80211_get_tdls_sta_capab(struct ieee80211_sub_if_data *sdata, u16 status_code) { + struct ieee80211_supported_band *sband; + /* The capability will be 0 when sending a failure code */ if (status_code != 0) return 0; - if (ieee80211_get_sdata_band(sdata) == NL80211_BAND_2GHZ) { + sband = ieee80211_get_sband(sdata); + if (sband && sband->band == NL80211_BAND_2GHZ) { return WLAN_CAPABILITY_SHORT_SLOT_TIME | WLAN_CAPABILITY_SHORT_PREAMBLE; } @@ -358,17 +360,20 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, u8 action_code, bool initiator, const u8 *extra_ies, size_t extra_ies_len) { - enum nl80211_band band = ieee80211_get_sdata_band(sdata); - struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; + struct ieee80211_local *local = sdata->local; struct ieee80211_sta_ht_cap ht_cap; struct ieee80211_sta_vht_cap vht_cap; struct sta_info *sta = NULL; size_t offset = 0, noffset; u8 *pos; - ieee80211_add_srates_ie(sdata, skb, false, band); - ieee80211_add_ext_srates_ie(sdata, skb, false, band); + sband = ieee80211_get_sband(sdata); + if (!sband) + return; + + ieee80211_add_srates_ie(sdata, skb, false, sband->band); + ieee80211_add_ext_srates_ie(sdata, skb, false, sband->band); ieee80211_tdls_add_supp_channels(sdata, skb); /* add any custom IEs that go before Extended Capabilities */ @@ -439,7 +444,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, * the same on all bands. The specification limits the setup to a * single HT-cap, so use the current band for now. */ - sband = local->hw.wiphy->bands[band]; memcpy(&ht_cap, &sband->ht_cap, sizeof(ht_cap)); if ((action_code == WLAN_TDLS_SETUP_REQUEST || @@ -545,9 +549,13 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; size_t offset = 0, noffset; struct sta_info *sta, *ap_sta; - enum nl80211_band band = ieee80211_get_sdata_band(sdata); + struct ieee80211_supported_band *sband; u8 *pos; + sband = ieee80211_get_sband(sdata); + if (!sband) + return; + mutex_lock(&local->sta_mtx); sta = sta_info_get(sdata, peer); @@ -612,7 +620,8 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, ieee80211_tdls_add_link_ie(sdata, skb, peer, initiator); /* only include VHT-operation if not on the 2.4GHz band */ - if (band != NL80211_BAND_2GHZ && sta->sta.vht_cap.vht_supported) { + if (sband->band != NL80211_BAND_2GHZ && + sta->sta.vht_cap.vht_supported) { /* * if both peers support WIDER_BW, we can expand the chandef to * a wider compatible one, up to 80MHz diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1ffd1e145c13..84582998f65f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -4182,7 +4182,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, return bcn; shift = ieee80211_vif_get_shift(vif); - sband = hw->wiphy->bands[ieee80211_get_sdata_band(vif_to_sdata(vif))]; + sband = ieee80211_get_sband(vif_to_sdata(vif)); + if (!sband) + return bcn; + ieee80211_tx_monitor(hw_to_local(hw), copy, sband, 1, shift, false); return bcn; diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 545c79a42a77..a2756096b94a 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1590,14 +1590,14 @@ u32 ieee80211_sta_get_rates(struct ieee80211_sub_if_data *sdata, size_t num_rates; u32 supp_rates, rate_flags; int i, j, shift; + sband = sdata->local->hw.wiphy->bands[band]; + if (WARN_ON(!sband)) + return 1; rate_flags = ieee80211_chandef_rate_flags(&sdata->vif.bss_conf.chandef); shift = ieee80211_vif_get_shift(&sdata->vif); - if (WARN_ON(!sband)) - return 1; - num_rates = sband->n_bitrates; supp_rates = 0; for (i = 0; i < elems->supp_rates_len + -- GitLab From ff3d5600e2e6240869dd73e4c205108d672db7d7 Mon Sep 17 00:00:00 2001 From: yangbo lu Date: Thu, 20 Apr 2017 14:58:29 +0800 Subject: [PATCH 0676/1834] mmc: sdhci-of-esdhc: limit SD clock for ls1012a/ls1046a [ Upstream commit a627f025eb0534052ff451427c16750b3530634c ] The ls1046a datasheet specified that the max SD clock frequency for eSDHC SDR104/HS200 was 167MHz, and the ls1012a datasheet specified it's 125MHz for ls1012a. So this patch is to add the limitation. Signed-off-by: Yangbo Lu Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-of-esdhc.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 3c27401cf7fe..a51d636c2312 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -432,6 +432,20 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) if (esdhc->vendor_ver < VENDOR_V_23) pre_div = 2; + /* + * Limit SD clock to 167MHz for ls1046a according to its datasheet + */ + if (clock > 167000000 && + of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc")) + clock = 167000000; + + /* + * Limit SD clock to 125MHz for ls1012a according to its datasheet + */ + if (clock > 125000000 && + of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc")) + clock = 125000000; + /* Workaround to reduce the clock frequency for p1010 esdhc */ if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { if (clock > 20000000) -- GitLab From c70c7be280448ad7dce9d74fb66c858de534383a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 28 Apr 2017 15:57:56 +0300 Subject: [PATCH 0677/1834] netfilter: x_tables: unlock on error in xt_find_table_lock() [ Upstream commit 7dde07e9c53617549d67dd3e1d791496d0d3868e ] According to my static checker we should unlock here before the return. That seems reasonable to me as well. Fixes" b9e69e127397 ("netfilter: xtables: don't hook tables by default") Signed-off-by: Dan Carpenter Acked-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/x_tables.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index ac26b71d900e..7ad1a863587a 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -1006,8 +1006,10 @@ struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, list_for_each_entry(t, &init_net.xt.tables[af], list) { if (strcmp(t->name, name)) continue; - if (!try_module_get(t->me)) + if (!try_module_get(t->me)) { + mutex_unlock(&xt[af].mutex); return NULL; + } mutex_unlock(&xt[af].mutex); if (t->table_init(net) != 0) { -- GitLab From b642685751f3b998721ea318792004d474fca5b0 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Mon, 27 Mar 2017 15:15:20 +0530 Subject: [PATCH 0678/1834] ARM: DRA7: clockdomain: Change the CLKTRCTRL of CM_PCIE_CLKSTCTRL to SW_WKUP [ Upstream commit 2c949ce38f4e81d7487f165fa3b8f77d74a2a6c4 ] The PCIe programming sequence in TRM suggests CLKSTCTRL of PCIe should be set to SW_WKUP. There are no issues when CLKSTCTRL is set to HW_AUTO in RC mode. However in EP mode, the host system is not able to access the MEMSPACE and setting the CLKSTCTRL to SW_WKUP fixes it. Acked-by: Tony Lindgren Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-omap2/clockdomains7xx_data.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/clockdomains7xx_data.c b/arch/arm/mach-omap2/clockdomains7xx_data.c index ef9ed36e8a61..e3416b40e82b 100644 --- a/arch/arm/mach-omap2/clockdomains7xx_data.c +++ b/arch/arm/mach-omap2/clockdomains7xx_data.c @@ -524,7 +524,7 @@ static struct clockdomain pcie_7xx_clkdm = { .dep_bit = DRA7XX_PCIE_STATDEP_SHIFT, .wkdep_srcs = pcie_wkup_sleep_deps, .sleepdep_srcs = pcie_wkup_sleep_deps, - .flags = CLKDM_CAN_HWSUP_SWSUP, + .flags = CLKDM_CAN_SWSUP, }; static struct clockdomain atl_7xx_clkdm = { -- GitLab From 566edbdefb71f4b4852aa3d8c55b79ebf3fc1f09 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 27 Apr 2017 12:14:20 +0300 Subject: [PATCH 0679/1834] IB/rdmavt: restore IRQs on error path in rvt_create_ah() [ Upstream commit f0bb2d44ca26b7090dc7bade8877b77005f07dfc ] We need to call spin_unlock_irqrestore() instead of vanilla spin_unlock() on this error path. Fixes: 119a8e708d16 ("IB/rdmavt: Add AH to rdmavt") Signed-off-by: Dan Carpenter Reviewed-by: Leon Romanovsky Acked-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/sw/rdmavt/ah.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/sw/rdmavt/ah.c b/drivers/infiniband/sw/rdmavt/ah.c index 16c446142c2a..b0f09fb45c72 100644 --- a/drivers/infiniband/sw/rdmavt/ah.c +++ b/drivers/infiniband/sw/rdmavt/ah.c @@ -119,7 +119,7 @@ struct ib_ah *rvt_create_ah(struct ib_pd *pd, spin_lock_irqsave(&dev->n_ahs_lock, flags); if (dev->n_ahs_allocated == dev->dparms.props.max_ah) { - spin_unlock(&dev->n_ahs_lock); + spin_unlock_irqrestore(&dev->n_ahs_lock, flags); kfree(ah); return ERR_PTR(-ENOMEM); } -- GitLab From b38508b8e016e5017c3920000bd9233e0c4d3666 Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Fri, 28 Apr 2017 10:40:02 -0700 Subject: [PATCH 0680/1834] IB/hfi1: Fix softlockup issue [ Upstream commit 22546b741af8355cd2e16739b6af4a8f17081839 ] Soft lockups can occur because the mad processing on different CPUs acquire the spin lock dc8051_lock: [534552.835870] [] ? read_dev_port_cntr.isra.37+0x23/0x160 [hfi1] [534552.835880] [] read_dev_cntr+0x4f/0x60 [hfi1] [534552.835893] [] pma_get_opa_portstatus+0x64d/0x8c0 [hfi1] [534552.835904] [] hfi1_process_mad+0x48d/0x18c0 [hfi1] [534552.835908] [] ? __slab_free+0x81/0x2f0 [534552.835936] [] ? ib_mad_recv_done+0x21e/0xa30 [ib_core] [534552.835939] [] ? __kmalloc+0x1f3/0x240 [534552.835947] [] ib_mad_recv_done+0x2cb/0xa30 [ib_core] [534552.835955] [] __ib_process_cq+0x55/0xd0 [ib_core] [534552.835962] [] ib_cq_poll_work+0x20/0x60 [ib_core] [534552.835964] [] process_one_work+0x17b/0x470 [534552.835966] [] worker_thread+0x126/0x410 [534552.835969] [] ? rescuer_thread+0x460/0x460 [534552.835971] [] kthread+0xcf/0xe0 [534552.835974] [] ? kthread_create_on_node+0x140/0x140 [534552.835977] [] ret_from_fork+0x58/0x90 [534552.835980] [] ? kthread_create_on_node+0x140/0x140 This issue is made worse when the 8051 is busy and the reads take longer. Fix by using a non-spinning lock procure. Reviewed-by: Michael J. Ruhl Reviewed-by: Mike Marciszyn Signed-off-by: Tadeusz Struk Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/chip.c | 86 +++++++++++++++++++------------ drivers/infiniband/hw/hfi1/hfi.h | 7 +-- drivers/infiniband/hw/hfi1/init.c | 2 +- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 3be62ef154d1..7853b0caad32 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -6379,18 +6379,17 @@ static void lcb_shutdown(struct hfi1_devdata *dd, int abort) * * The expectation is that the caller of this routine would have taken * care of properly transitioning the link into the correct state. + * NOTE: the caller needs to acquire the dd->dc8051_lock lock + * before calling this function. */ -static void dc_shutdown(struct hfi1_devdata *dd) +static void _dc_shutdown(struct hfi1_devdata *dd) { - unsigned long flags; + lockdep_assert_held(&dd->dc8051_lock); - spin_lock_irqsave(&dd->dc8051_lock, flags); - if (dd->dc_shutdown) { - spin_unlock_irqrestore(&dd->dc8051_lock, flags); + if (dd->dc_shutdown) return; - } + dd->dc_shutdown = 1; - spin_unlock_irqrestore(&dd->dc8051_lock, flags); /* Shutdown the LCB */ lcb_shutdown(dd, 1); /* @@ -6401,35 +6400,45 @@ static void dc_shutdown(struct hfi1_devdata *dd) write_csr(dd, DC_DC8051_CFG_RST, 0x1); } +static void dc_shutdown(struct hfi1_devdata *dd) +{ + mutex_lock(&dd->dc8051_lock); + _dc_shutdown(dd); + mutex_unlock(&dd->dc8051_lock); +} + /* * Calling this after the DC has been brought out of reset should not * do any damage. + * NOTE: the caller needs to acquire the dd->dc8051_lock lock + * before calling this function. */ -static void dc_start(struct hfi1_devdata *dd) +static void _dc_start(struct hfi1_devdata *dd) { - unsigned long flags; - int ret; + lockdep_assert_held(&dd->dc8051_lock); - spin_lock_irqsave(&dd->dc8051_lock, flags); if (!dd->dc_shutdown) - goto done; - spin_unlock_irqrestore(&dd->dc8051_lock, flags); + return; + /* Take the 8051 out of reset */ write_csr(dd, DC_DC8051_CFG_RST, 0ull); /* Wait until 8051 is ready */ - ret = wait_fm_ready(dd, TIMEOUT_8051_START); - if (ret) { + if (wait_fm_ready(dd, TIMEOUT_8051_START)) dd_dev_err(dd, "%s: timeout starting 8051 firmware\n", __func__); - } + /* Take away reset for LCB and RX FPE (set in lcb_shutdown). */ write_csr(dd, DCC_CFG_RESET, 0x10); /* lcb_shutdown() with abort=1 does not restore these */ write_csr(dd, DC_LCB_ERR_EN, dd->lcb_err_en); - spin_lock_irqsave(&dd->dc8051_lock, flags); dd->dc_shutdown = 0; -done: - spin_unlock_irqrestore(&dd->dc8051_lock, flags); +} + +static void dc_start(struct hfi1_devdata *dd) +{ + mutex_lock(&dd->dc8051_lock); + _dc_start(dd); + mutex_unlock(&dd->dc8051_lock); } /* @@ -8418,16 +8427,11 @@ static int do_8051_command( { u64 reg, completed; int return_code; - unsigned long flags; unsigned long timeout; hfi1_cdbg(DC8051, "type %d, data 0x%012llx", type, in_data); - /* - * Alternative to holding the lock for a long time: - * - keep busy wait - have other users bounce off - */ - spin_lock_irqsave(&dd->dc8051_lock, flags); + mutex_lock(&dd->dc8051_lock); /* We can't send any commands to the 8051 if it's in reset */ if (dd->dc_shutdown) { @@ -8453,10 +8457,8 @@ static int do_8051_command( return_code = -ENXIO; goto fail; } - spin_unlock_irqrestore(&dd->dc8051_lock, flags); - dc_shutdown(dd); - dc_start(dd); - spin_lock_irqsave(&dd->dc8051_lock, flags); + _dc_shutdown(dd); + _dc_start(dd); } /* @@ -8534,8 +8536,7 @@ static int do_8051_command( write_csr(dd, DC_DC8051_CFG_HOST_CMD_0, 0); fail: - spin_unlock_irqrestore(&dd->dc8051_lock, flags); - + mutex_unlock(&dd->dc8051_lock); return return_code; } @@ -11849,6 +11850,10 @@ static void free_cntrs(struct hfi1_devdata *dd) dd->scntrs = NULL; kfree(dd->cntrnames); dd->cntrnames = NULL; + if (dd->update_cntr_wq) { + destroy_workqueue(dd->update_cntr_wq); + dd->update_cntr_wq = NULL; + } } static u64 read_dev_port_cntr(struct hfi1_devdata *dd, struct cntr_entry *entry, @@ -12004,7 +12009,7 @@ u64 write_port_cntr(struct hfi1_pportdata *ppd, int index, int vl, u64 data) return write_dev_port_cntr(ppd->dd, entry, sval, ppd, vl, data); } -static void update_synth_timer(unsigned long opaque) +static void do_update_synth_timer(struct work_struct *work) { u64 cur_tx; u64 cur_rx; @@ -12013,8 +12018,8 @@ static void update_synth_timer(unsigned long opaque) int i, j, vl; struct hfi1_pportdata *ppd; struct cntr_entry *entry; - - struct hfi1_devdata *dd = (struct hfi1_devdata *)opaque; + struct hfi1_devdata *dd = container_of(work, struct hfi1_devdata, + update_cntr_work); /* * Rather than keep beating on the CSRs pick a minimal set that we can @@ -12097,7 +12102,13 @@ static void update_synth_timer(unsigned long opaque) } else { hfi1_cdbg(CNTR, "[%d] No update necessary", dd->unit); } +} + +static void update_synth_timer(unsigned long opaque) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)opaque; + queue_work(dd->update_cntr_wq, &dd->update_cntr_work); mod_timer(&dd->synth_stats_timer, jiffies + HZ * SYNTH_CNT_TIME); } @@ -12333,6 +12344,13 @@ static int init_cntrs(struct hfi1_devdata *dd) if (init_cpu_counters(dd)) goto bail; + dd->update_cntr_wq = alloc_ordered_workqueue("hfi1_update_cntr_%d", + WQ_MEM_RECLAIM, dd->unit); + if (!dd->update_cntr_wq) + goto bail; + + INIT_WORK(&dd->update_cntr_work, do_update_synth_timer); + mod_timer(&dd->synth_stats_timer, jiffies + HZ * SYNTH_CNT_TIME); return 0; bail: diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index cc87fd4e534b..a3279f3d2578 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -475,7 +475,7 @@ struct rvt_sge_state; #define HFI1_PART_ENFORCE_OUT 0x2 /* how often we check for synthetic counter wrap around */ -#define SYNTH_CNT_TIME 2 +#define SYNTH_CNT_TIME 3 /* Counter flags */ #define CNTR_NORMAL 0x0 /* Normal counters, just read register */ @@ -929,8 +929,9 @@ struct hfi1_devdata { spinlock_t rcvctrl_lock; /* protect changes to RcvCtrl */ /* around rcd and (user ctxts) ctxt_cnt use (intr vs free) */ spinlock_t uctxt_lock; /* rcd and user context changes */ - /* exclusive access to 8051 */ - spinlock_t dc8051_lock; + struct mutex dc8051_lock; /* exclusive access to 8051 */ + struct workqueue_struct *update_cntr_wq; + struct work_struct update_cntr_work; /* exclusive access to 8051 memory */ spinlock_t dc8051_memlock; int dc8051_timed_out; /* remember if the 8051 timed out */ diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index a3dd27b1305d..84a97f3f9299 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -1078,11 +1078,11 @@ struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra) spin_lock_init(&dd->uctxt_lock); spin_lock_init(&dd->hfi1_diag_trans_lock); spin_lock_init(&dd->sc_init_lock); - spin_lock_init(&dd->dc8051_lock); spin_lock_init(&dd->dc8051_memlock); seqlock_init(&dd->sc2vl_lock); spin_lock_init(&dd->sde_map_lock); spin_lock_init(&dd->pio_map_lock); + mutex_init(&dd->dc8051_lock); init_waitqueue_head(&dd->event_queue); dd->int_counter = alloc_percpu(u64); -- GitLab From 7c1c184bb571e696ffcd57ed43c65f8c91a6d03e Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 28 Apr 2017 16:19:49 +0200 Subject: [PATCH 0681/1834] platform/x86: asus-wmi: try to set als by default [ Upstream commit e9b615186805e2c18a0ac76aca62c1543ecfdbb8 ] some laptops, for example ASUS UX330UAK, have brocken als_get function but working als_set funktion. In this case, ALS will stay turned off. Method (WMNB, 3, Serialized) { ... If (Local0 == 0x53545344) { ... If (IIA0 == 0x00050001) { If (!ALSP) { Return (0x02) } Local0 = (GALS & 0x10) <<<---- bug, should be: (GALS () & 0x10) If (Local0) { Return (0x00050001) } Else { Return (0x00050000) } } ..... If (Local0 == 0x53564544) { ... If (IIA0 == 0x00050001) { Return (ALSC (IIA1)) } ...... Method (GALS, 0, NotSerialized) { Local0 = Zero Local0 |= 0x20 If (ALAE) { Local0 |= 0x10 } Local1 = 0x0A Local1 <<= 0x08 Local0 |= Local1 Return (Local0) } Since it works without problems on Windows I assume ASUS WMI driver for Win never trying to get ALS state, and instead it is setting it by default to ON. This patch will do the same. Turn ALS on by default. Signed-off-by: Oleksij Rempel Signed-off-by: Andy Shevchenko Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++++ drivers/platform/x86/asus-wmi.c | 12 ++++++++++++ drivers/platform/x86/asus-wmi.h | 1 + 3 files changed, 26 insertions(+) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index ab44326ea3e7..687cc5b922ee 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -120,6 +120,10 @@ static struct quirk_entry quirk_asus_x550lb = { .xusb2pr = 0x01D9, }; +static struct quirk_entry quirk_asus_ux330uak = { + .wmi_force_als_set = true, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { quirks = dmi->driver_data; @@ -420,6 +424,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_ux303ub, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. UX330UAK", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "UX330UAK"), + }, + .driver_data = &quirk_asus_ux330uak, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. X550LB", diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 8499d3ae4257..8a1bfd489c26 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -1108,6 +1108,15 @@ static void asus_wmi_set_xusb2pr(struct asus_wmi *asus) orig_ports_available, ports_available); } +/* + * Some devices dont support or have borcken get_als method + * but still support set method. + */ +static void asus_wmi_set_als(void) +{ + asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL); +} + /* * Hwmon device */ @@ -2120,6 +2129,9 @@ static int asus_wmi_add(struct platform_device *pdev) goto fail_rfkill; } + if (asus->driver->quirks->wmi_force_als_set) + asus_wmi_set_als(); + /* Some Asus desktop boards export an acpi-video backlight interface, stop this from showing up */ chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE); diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index fdff626c3b51..5db052d1de1e 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -45,6 +45,7 @@ struct quirk_entry { bool store_backlight_power; bool wmi_backlight_power; bool wmi_backlight_native; + bool wmi_force_als_set; int wapf; /* * For machines with AMD graphic chips, it will send out WMI event -- GitLab From e9e5ad6b0ef2f00ba23f550c1347bbfb44b66e20 Mon Sep 17 00:00:00 2001 From: Robert Lippert Date: Thu, 20 Apr 2017 16:49:47 -0700 Subject: [PATCH 0682/1834] ipmi/watchdog: fix wdog hang on panic waiting for ipmi response [ Upstream commit 2c1175c2e8e5487233cabde358a19577562ac83e ] Commit c49c097610fe ("ipmi: Don't call receive handler in the panic context") means that the panic_recv_free is not called during a panic and the atomic count does not drop to 0. Fix this by only expecting one decrement of the atomic variable which comes from panic_smi_free. Signed-off-by: Robert Lippert Signed-off-by: Corey Minyard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/char/ipmi/ipmi_watchdog.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 909311016108..055d2ce378a7 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -515,7 +515,7 @@ static void panic_halt_ipmi_heartbeat(void) msg.cmd = IPMI_WDOG_RESET_TIMER; msg.data = NULL; msg.data_len = 0; - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = ipmi_request_supply_msgs(watchdog_user, (struct ipmi_addr *) &addr, 0, @@ -525,7 +525,7 @@ static void panic_halt_ipmi_heartbeat(void) &panic_halt_heartbeat_recv_msg, 1); if (rv) - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); } static struct ipmi_smi_msg panic_halt_smi_msg = { @@ -549,12 +549,12 @@ static void panic_halt_ipmi_set_timeout(void) /* Wait for the messages to be free. */ while (atomic_read(&panic_done_count) != 0) ipmi_poll_interface(watchdog_user); - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = i_ipmi_set_timeout(&panic_halt_smi_msg, &panic_halt_recv_msg, &send_heartbeat_now); if (rv) { - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); printk(KERN_WARNING PFX "Unable to extend the watchdog timeout."); } else { -- GitLab From ec4b63f5c0a47d01b92af90cd645f47e03f36a98 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 21 Apr 2017 13:48:08 +0200 Subject: [PATCH 0683/1834] ACPI / PMIC: xpower: Fix power_table addresses [ Upstream commit 2bde7c32b1db162692f05c6be066b5bcd3d9fdbe ] The power table addresses should be contiguous, but there was a hole where 0x34 was missing. On most devices this is not a problem as addresses above 0x34 are used for the BUC# convertors which are not used in the DSDTs I've access to but after the BUC# convertors there is a field named GPI1 in the DSTDs, which does get used in some cases and ended up turning BUC6 on and off due to the wrong addresses, resulting in turning the entire device off (or causing it to reboot). Removing the hole in the addresses fixes this, fixing one of my Bay Trail tablets turning off while booting the mainline kernel. While at it add comments with the field names used in the DSDTs to make it easier to compare the register and bits used at each address with the datasheet. Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/pmic/intel_pmic_xpower.c | 50 +++++++++++++-------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c index e6e991ac20f3..0c6874e6a9b6 100644 --- a/drivers/acpi/pmic/intel_pmic_xpower.c +++ b/drivers/acpi/pmic/intel_pmic_xpower.c @@ -28,97 +28,97 @@ static struct pmic_table power_table[] = { .address = 0x00, .reg = 0x13, .bit = 0x05, - }, + }, /* ALD1 */ { .address = 0x04, .reg = 0x13, .bit = 0x06, - }, + }, /* ALD2 */ { .address = 0x08, .reg = 0x13, .bit = 0x07, - }, + }, /* ALD3 */ { .address = 0x0c, .reg = 0x12, .bit = 0x03, - }, + }, /* DLD1 */ { .address = 0x10, .reg = 0x12, .bit = 0x04, - }, + }, /* DLD2 */ { .address = 0x14, .reg = 0x12, .bit = 0x05, - }, + }, /* DLD3 */ { .address = 0x18, .reg = 0x12, .bit = 0x06, - }, + }, /* DLD4 */ { .address = 0x1c, .reg = 0x12, .bit = 0x00, - }, + }, /* ELD1 */ { .address = 0x20, .reg = 0x12, .bit = 0x01, - }, + }, /* ELD2 */ { .address = 0x24, .reg = 0x12, .bit = 0x02, - }, + }, /* ELD3 */ { .address = 0x28, .reg = 0x13, .bit = 0x02, - }, + }, /* FLD1 */ { .address = 0x2c, .reg = 0x13, .bit = 0x03, - }, + }, /* FLD2 */ { .address = 0x30, .reg = 0x13, .bit = 0x04, - }, + }, /* FLD3 */ { - .address = 0x38, + .address = 0x34, .reg = 0x10, .bit = 0x03, - }, + }, /* BUC1 */ { - .address = 0x3c, + .address = 0x38, .reg = 0x10, .bit = 0x06, - }, + }, /* BUC2 */ { - .address = 0x40, + .address = 0x3c, .reg = 0x10, .bit = 0x05, - }, + }, /* BUC3 */ { - .address = 0x44, + .address = 0x40, .reg = 0x10, .bit = 0x04, - }, + }, /* BUC4 */ { - .address = 0x48, + .address = 0x44, .reg = 0x10, .bit = 0x01, - }, + }, /* BUC5 */ { - .address = 0x4c, + .address = 0x48, .reg = 0x10, .bit = 0x00 - }, + }, /* BUC6 */ }; /* TMP0 - TMP5 are the same, all from GPADC */ -- GitLab From 8112fa3c00c68f4407c970aeaa73a8e64c1e717b Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 24 Apr 2017 17:09:15 +0800 Subject: [PATCH 0684/1834] drm/amdgpu: fix gpu reset crash MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 51687759be93fbc553f2727e86be25c38126ba93 ] [ 413.687439] BUG: unable to handle kernel NULL pointer dereference at 0000000000000548 [ 413.687479] IP: [] to_live_kthread+0x5/0x60 [ 413.687507] PGD 1efd12067 [ 413.687519] PUD 1efd11067 [ 413.687531] PMD 0 [ 413.687543] Oops: 0000 [#1] SMP [ 413.687557] Modules linked in: amdgpu(OE) ttm(OE) drm_kms_helper(E) drm(E) i2c_algo_bit(E) fb_sys_fops(E) syscopyarea(E) sysfillrect(E) sysimgblt(E) rpcsec_gss_krb5(E) nfsv4(E) nfs(E) fscache(E) snd_hda_codec_realtek(E) snd_hda_codec_generic(E) snd_hda_codec_hdmi(E) snd_hda_intel(E) eeepc_wmi(E) snd_hda_codec(E) asus_wmi(E) snd_hda_core(E) sparse_keymap(E) snd_hwdep(E) video(E) snd_pcm(E) snd_seq_midi(E) joydev(E) snd_seq_midi_event(E) snd_rawmidi(E) snd_seq(E) snd_seq_device(E) snd_timer(E) kvm(E) irqbypass(E) crct10dif_pclmul(E) snd(E) crc32_pclmul(E) ghash_clmulni_intel(E) soundcore(E) aesni_intel(E) aes_x86_64(E) lrw(E) gf128mul(E) glue_helper(E) ablk_helper(E) cryptd(E) shpchp(E) serio_raw(E) i2c_piix4(E) 8250_dw(E) i2c_designware_platform(E) i2c_designware_core(E) mac_hid(E) binfmt_misc(E) [ 413.687894] parport_pc(E) ppdev(E) lp(E) parport(E) nfsd(E) auth_rpcgss(E) nfs_acl(E) lockd(E) grace(E) sunrpc(E) autofs4(E) hid_generic(E) usbhid(E) hid(E) psmouse(E) ahci(E) r8169(E) mii(E) libahci(E) wmi(E) [ 413.687989] CPU: 13 PID: 1134 Comm: kworker/13:2 Tainted: G OE 4.9.0-custom #4 [ 413.688019] Hardware name: System manufacturer System Product Name/PRIME B350-PLUS, BIOS 0606 04/06/2017 [ 413.688089] Workqueue: events amd_sched_job_timedout [amdgpu] [ 413.688116] task: ffff88020f9657c0 task.stack: ffffc90001a88000 [ 413.688139] RIP: 0010:[] [] to_live_kthread+0x5/0x60 [ 413.688171] RSP: 0018:ffffc90001a8bd60 EFLAGS: 00010282 [ 413.688191] RAX: ffff88020f0073f8 RBX: ffff88020f000000 RCX: 0000000000000000 [ 413.688217] RDX: 0000000000000001 RSI: ffff88020f9670c0 RDI: 0000000000000000 [ 413.688243] RBP: ffffc90001a8bd78 R08: 0000000000000000 R09: 0000000000001000 [ 413.688269] R10: 0000006051b11a82 R11: 0000000000000001 R12: 0000000000000000 [ 413.688295] R13: ffff88020f002770 R14: ffff88020f004838 R15: ffff8801b23c2c60 [ 413.688321] FS: 0000000000000000(0000) GS:ffff88021ef40000(0000) knlGS:0000000000000000 [ 413.688352] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 413.688373] CR2: 0000000000000548 CR3: 00000001efd0f000 CR4: 00000000003406e0 [ 413.688399] Stack: [ 413.688407] ffffffff8109b304 ffff88020f000000 0000000000000070 ffffc90001a8bdf0 [ 413.688439] ffffffffa05ce29d ffffffffa052feb7 ffffffffa07b5820 ffffc90001a8bda0 [ 413.688470] ffffffff00000018 ffff8801bb88f060 0000000001a8bdb8 ffff88021ef59280 [ 413.688502] Call Trace: [ 413.688514] [] ? kthread_park+0x14/0x60 [ 413.688555] [] amdgpu_gpu_reset+0x7d/0x670 [amdgpu] [ 413.688589] [] ? drm_printk+0x97/0xa0 [drm] [ 413.688643] [] amdgpu_job_timedout+0x46/0x50 [amdgpu] [ 413.688700] [] amd_sched_job_timedout+0x17/0x20 [amdgpu] [ 413.688727] [] process_one_work+0x153/0x3f0 [ 413.688751] [] worker_thread+0x12b/0x4b0 [ 413.688773] [] ? do_syscall_64+0x6e/0x180 [ 413.688795] [] ? rescuer_thread+0x350/0x350 [ 413.688818] [] ? do_syscall_64+0x6e/0x180 [ 413.688839] [] kthread+0xd3/0xf0 [ 413.688858] [] ? kthread_park+0x60/0x60 [ 413.688881] [] ret_from_fork+0x25/0x30 [ 413.688901] Code: 25 40 d3 00 00 48 8b 80 48 05 00 00 48 89 e5 5d 48 8b 40 c8 48 c1 e8 02 83 e0 01 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 <48> 8b b7 48 05 00 00 55 48 89 e5 48 85 f6 74 31 8b 97 f8 18 00 [ 413.689045] RIP [] to_live_kthread+0x5/0x60 [ 413.689064] RSP [ 413.689076] CR2: 0000000000000548 [ 413.697985] ---[ end trace 0a314a64821f84e9 ]--- The root cause is some ring doesn't have scheduler, like KIQ ring Reviewed-by: Christian König Signed-off-by: Chunming Zhou Signed-off-by: Alex Deucher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 50f18f666d67..d0c3e56ece74 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2237,7 +2237,7 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring) + if (!ring || !ring->sched.thread) continue; kthread_park(ring->sched.thread); amd_sched_hw_job_reset(&ring->sched); @@ -2326,7 +2326,8 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev) } for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { struct amdgpu_ring *ring = adev->rings[i]; - if (!ring) + + if (!ring || !ring->sched.thread) continue; amd_sched_job_recovery(&ring->sched); @@ -2335,7 +2336,7 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev) } else { dev_err(adev->dev, "asic resume failed (%d).\n", r); for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { - if (adev->rings[i]) { + if (adev->rings[i] && adev->rings[i]->sched.thread) { kthread_unpark(adev->rings[i]->sched.thread); } } -- GitLab From 7be76fbbd25c4cd838125f8ea843d1fb1c657db0 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Mon, 24 Apr 2017 01:59:34 +0200 Subject: [PATCH 0685/1834] drm/nouveau/kms: Increase max retries in scanout position queries. [ Upstream commit 60b95d709525e3ce1c51e1fc93175dcd1755d345 ] So far we only allowed for 1 retry and just failed the query - and thereby high precision vblank timestamping - if we did not get a reasonable result, as such a failure wasn't considered all too horrible. There are a few NVidia gpu models out there which may need a bit more than 1 retry to get a successful query result under some conditions. Since Linux 4.4 the update code for vblank counter and timestamp in drm_update_vblank_count() changed so that the implementation assumes that high precision vblank timestamping of a kms driver either consistently succeeds or consistently fails for a given video mode and encoder/connector combo. Iow. switching from success to fail or vice versa on a modeset or connector change is ok, but spurious temporary failure for a given setup can confuse the core code and potentially cause bad miscounting of vblanks and confusion or hangs in userspace clients which rely on vblank stuff, e.g., desktop compositors. Therefore change the max retry count to a larger number - more than any gpu so far is known to need to succeed, but still low enough so that these queries which do also happen in vblank interrupt are still fast enough to be not disastrously long if something would go badly wrong with them. As such sporadic retries only happen seldom even on affected gpu's, this could mean a vblank irq could take a few dozen microseconds longer every few hours of uptime -- better than a desktop compositor randomly hanging every couple of hours or days of uptime in a hard to reproduce manner. Signed-off-by: Mario Kleiner Signed-off-by: Ben Skeggs Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/nouveau/nouveau_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 2c2b86d68129..6526a3366087 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -106,7 +106,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, }; struct nouveau_display *disp = nouveau_display(crtc->dev); struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)]; - int ret, retry = 1; + int ret, retry = 20; do { ret = nvif_mthd(&disp->disp, 0, &args, sizeof(args)); -- GitLab From 81ca30d9654a6035f0bef174bd7df541b3e94217 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Sat, 29 Apr 2017 20:12:16 -0400 Subject: [PATCH 0686/1834] jbd2: Fix lockdep splat with generic/270 test [ Upstream commit c52c47e4b4fbe4284602fc2ccbfc4a4d8dc05b49 ] I've hit a lockdep splat with generic/270 test complaining that: 3216.fsstress.b/3533 is trying to acquire lock: (jbd2_handle){++++..}, at: [] jbd2_log_wait_commit+0x0/0x150 but task is already holding lock: (jbd2_handle){++++..}, at: [] start_this_handle+0x35b/0x850 The underlying problem is that jbd2_journal_force_commit_nested() (called from ext4_should_retry_alloc()) may get called while a transaction handle is started. In such case it takes care to not wait for commit of the running transaction (which would deadlock) but only for a commit of a transaction that is already committing (which is safe as that doesn't wait for any filesystem locks). In fact there are also other callers of jbd2_log_wait_commit() that take care to pass tid of a transaction that is already committing and for those cases, the lockdep instrumentation is too restrictive and leading to false positive reports. Fix the problem by calling jbd2_might_wait_for_commit() from jbd2_log_wait_commit() only if the transaction isn't already committing. Fixes: 1eaa566d368b214d99cbb973647c1b0b8102a9ae Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/journal.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 7d4b557f1962..047c8ef620fe 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -691,8 +691,21 @@ int jbd2_log_wait_commit(journal_t *journal, tid_t tid) { int err = 0; - jbd2_might_wait_for_commit(journal); read_lock(&journal->j_state_lock); +#ifdef CONFIG_PROVE_LOCKING + /* + * Some callers make sure transaction is already committing and in that + * case we cannot block on open handles anymore. So don't warn in that + * case. + */ + if (tid_gt(tid, journal->j_commit_sequence) && + (!journal->j_committing_transaction || + journal->j_committing_transaction->t_tid != tid)) { + read_unlock(&journal->j_state_lock); + jbd2_might_wait_for_commit(journal); + read_lock(&journal->j_state_lock); + } +#endif #ifdef CONFIG_JBD2_DEBUG if (!tid_geq(journal->j_commit_request, tid)) { printk(KERN_ERR -- GitLab From b1b6f948b41cb69fe4ac81f49eb218df9399507c Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 30 Mar 2017 20:49:02 -0700 Subject: [PATCH 0687/1834] ixgbevf: fix size of queue stats length [ Upstream commit f87fc44770f54ff1b54d44ae9cec11f10efeca02 ] IXGBEVF_QUEUE_STATS_LEN is based on ixgebvf_stats, not ixgbe_stats. This change fixes a bug where ethtool -S displayed some empty fields. Signed-off-by: Emil Tantilov Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/ixgbevf/ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index 508e72c5f1c2..d665de8849a2 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -80,7 +80,7 @@ static struct ixgbe_stats ixgbevf_gstrings_stats[] = { #define IXGBEVF_QUEUE_STATS_LEN ( \ (((struct ixgbevf_adapter *)netdev_priv(netdev))->num_tx_queues + \ ((struct ixgbevf_adapter *)netdev_priv(netdev))->num_rx_queues) * \ - (sizeof(struct ixgbe_stats) / sizeof(u64))) + (sizeof(struct ixgbevf_stats) / sizeof(u64))) #define IXGBEVF_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbevf_gstrings_stats) #define IXGBEVF_STATS_LEN (IXGBEVF_GLOBAL_STATS_LEN + IXGBEVF_QUEUE_STATS_LEN) -- GitLab From b0d0441f2a6ae3dc20ee4a6871d48178c17911a7 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Tue, 7 Feb 2017 10:05:09 +0100 Subject: [PATCH 0688/1834] net: ethernet: ucc_geth: fix MEM_PART_MURAM mode [ Upstream commit 8b8642af15ed14b9a7a34d3401afbcc274533e13 ] Since commit 5093bb965a163 ("powerpc/QE: switch to the cpm_muram implementation"), muram area is not part of immrbar mapping anymore so immrbar_virt_to_phys() is not usable anymore. Fixes: 5093bb965a163 ("powerpc/QE: switch to the cpm_muram implementation") Signed-off-by: Christophe Leroy Acked-by: David S. Miller Acked-by: Li Yang Signed-off-by: Scott Wood Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/ucc_geth.c | 8 +++----- include/soc/fsl/qe/qe.h | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index f76d33279454..ef9bc26ebc1a 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -2594,11 +2594,10 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) } else if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_MURAM) { out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base, - (u32) immrbar_virt_to_phys(ugeth-> - p_tx_bd_ring[i])); + (u32)qe_muram_dma(ugeth->p_tx_bd_ring[i])); out_be32(&ugeth->p_send_q_mem_reg->sqqd[i]. last_bd_completed_address, - (u32) immrbar_virt_to_phys(endOfRing)); + (u32)qe_muram_dma(endOfRing)); } } @@ -2844,8 +2843,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) } else if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_MURAM) { out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr, - (u32) immrbar_virt_to_phys(ugeth-> - p_rx_bd_ring[i])); + (u32)qe_muram_dma(ugeth->p_rx_bd_ring[i])); } /* rest of fields handled by QE */ } diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h index 70339d7958c0..0cd4c11479b1 100644 --- a/include/soc/fsl/qe/qe.h +++ b/include/soc/fsl/qe/qe.h @@ -243,6 +243,7 @@ static inline int qe_alive_during_sleep(void) #define qe_muram_free cpm_muram_free #define qe_muram_addr cpm_muram_addr #define qe_muram_offset cpm_muram_offset +#define qe_muram_dma cpm_muram_dma #define qe_setbits32(_addr, _v) iowrite32be(ioread32be(_addr) | (_v), (_addr)) #define qe_clrbits32(_addr, _v) iowrite32be(ioread32be(_addr) & ~(_v), (_addr)) -- GitLab From 949b9dc1818a100941ed63c5147059a5f64c7987 Mon Sep 17 00:00:00 2001 From: Valentin Longchamp Date: Fri, 17 Feb 2017 11:29:45 +0100 Subject: [PATCH 0689/1834] soc/fsl/qe: round brg_freq to 1kHz granularity [ Upstream commit 2ccf80b7566cc035d903dd0ac5d7ebd25c2c1060 ] Because of integer computation rounding in u-boot (that sets the QE brg-frequency DTS prop), the clk value is 99999999 Hz even though it is 100 MHz. When setting brg clks that are exact divisors of 100 MHz, this small differnce plays a role and can result in lower clks to be output (for instance 20 MHz - divide by 5 - results in 16.666 MHz - divide by 6). This patch fixes that by "forcing" the brg_clk to the nearest kHz when the difference is below 2 integer rounding errors (i.e. 4). Signed-off-by: Valentin Longchamp Signed-off-by: Scott Wood Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/soc/fsl/qe/qe.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c index 2707a827261b..5482302d3d9e 100644 --- a/drivers/soc/fsl/qe/qe.c +++ b/drivers/soc/fsl/qe/qe.c @@ -163,11 +163,15 @@ EXPORT_SYMBOL(qe_issue_cmd); */ static unsigned int brg_clk = 0; +#define CLK_GRAN (1000) +#define CLK_GRAN_LIMIT (5) + unsigned int qe_get_brg_clk(void) { struct device_node *qe; int size; const u32 *prop; + unsigned int mod; if (brg_clk) return brg_clk; @@ -185,6 +189,15 @@ unsigned int qe_get_brg_clk(void) of_node_put(qe); + /* round this if near to a multiple of CLK_GRAN */ + mod = brg_clk % CLK_GRAN; + if (mod) { + if (mod < CLK_GRAN_LIMIT) + brg_clk -= mod; + else if (mod > (CLK_GRAN - CLK_GRAN_LIMIT)) + brg_clk += CLK_GRAN - mod; + } + return brg_clk; } EXPORT_SYMBOL(qe_get_brg_clk); -- GitLab From bbb952d00c8b254890e1cef7f7b7d23874c3aaa9 Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Fri, 28 Apr 2017 13:57:25 +0100 Subject: [PATCH 0690/1834] Bluetooth: hci_ldisc: Add protocol check to hci_uart_dequeue() [ Upstream commit 048e1bd3a27fbeb84ccdff52e165370c1339a193 ] Before attempting to dequeue a Data Link protocol encapsulated message, check that the Data Link protocol is still bound to the HCI UART driver. This makes the code consistent with the usage of the other proto function pointers. Therefore, add a check for HCI_UART_PROTO_READY into hci_uart_dequeue() and return NULL if the Data Link protocol is not bound. This is needed for robustness as there is a scheduling race condition. hci_uart_write_work() is scheduled to run via work queue hu->write_work from hci_uart_tx_wakeup(). Therefore, there is a delay between scheduling hci_uart_write_work() to run and hci_uart_dequeue() running whereby the Data Link protocol layer could become unbound during the scheduling delay. In this case, without the check, the call to the unbound Data Link protocol layer dequeue function can crash. It is noted that hci_uart_tty_close() has a "cancel_work_sync(&hu->write_work)" statement but this only reduces the window of the race condition because it is possible for a new work-item to be added to work queue hu->write_work after the call to cancel_work_sync(). For example, Data Link layer retransmissions can be added to the work queue after the cancel_work_sync() has finished. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_ldisc.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 9497c469efd2..7ec73945351c 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -113,10 +113,12 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) { struct sk_buff *skb = hu->tx_skb; - if (!skb) - skb = hu->proto->dequeue(hu); - else + if (!skb) { + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) + skb = hu->proto->dequeue(hu); + } else { hu->tx_skb = NULL; + } return skb; } -- GitLab From b5d95e85b20634f58c2d57f4041222a9adefd282 Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Fri, 28 Apr 2017 13:57:26 +0100 Subject: [PATCH 0691/1834] Bluetooth: hci_ldisc: Add protocol check to hci_uart_tx_wakeup() [ Upstream commit 2d6f1da168e1d62c47f7d50135ac4cbd8411dcb1 ] Before attempting to schedule a work-item onto hu->write_work in hci_uart_tx_wakeup(), check that the Data Link protocol layer is still bound to the HCI UART driver. Failure to perform this protocol check causes a race condition between the work queue hu->write_work running hci_uart_write_work() and the Data Link protocol layer being unbound (closed) in hci_uart_tty_close(). Note hci_uart_tty_close() does have a "cancel_work_sync(&hu->write_work)" but it is ineffective because it cannot prevent work-items being added to hu->write_work after cancel_work_sync() has run. Therefore, add a check for HCI_UART_PROTO_READY into hci_uart_tx_wakeup() which prevents scheduling of the work queue when HCI_UART_PROTO_READY is in the clear state. However, note a small race condition remains because the hci_uart_tx_wakeup() thread can run in parallel with the hci_uart_tty_close() thread so it is possible that a schedule of hu->write_work can occur when HCI_UART_PROTO_READY is cleared. A complete solution needs locking of the threads which is implemented in a future commit. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_ldisc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 7ec73945351c..2230f9368c21 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -125,6 +125,9 @@ static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) int hci_uart_tx_wakeup(struct hci_uart *hu) { + if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) + return 0; + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); return 0; -- GitLab From 9c8cd2a87247a9561536345715ef63143551f0c9 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 27 Apr 2017 21:24:35 +0200 Subject: [PATCH 0692/1834] vxlan: correctly handle ipv6.disable module parameter [ Upstream commit d074bf9600443403aa24fbc12c1f18eadc90f5aa ] When IPv6 is compiled but disabled at runtime, __vxlan_sock_add returns -EAFNOSUPPORT. For metadata based tunnels, this causes failure of the whole operation of bringing up the tunnel. Ignore failure of IPv6 socket creation for metadata based tunnels caused by IPv6 not being available. Fixes: b1be00a6c39f ("vxlan: support both IPv4 and IPv6 sockets in a single vxlan device") Signed-off-by: Jiri Benc Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/vxlan.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 50570d779b01..0f5dfb8a545d 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2816,17 +2816,21 @@ static int __vxlan_sock_add(struct vxlan_dev *vxlan, bool ipv6) static int vxlan_sock_add(struct vxlan_dev *vxlan) { - bool ipv6 = vxlan->flags & VXLAN_F_IPV6; bool metadata = vxlan->flags & VXLAN_F_COLLECT_METADATA; + bool ipv6 = vxlan->flags & VXLAN_F_IPV6 || metadata; + bool ipv4 = !ipv6 || metadata; int ret = 0; RCU_INIT_POINTER(vxlan->vn4_sock, NULL); #if IS_ENABLED(CONFIG_IPV6) RCU_INIT_POINTER(vxlan->vn6_sock, NULL); - if (ipv6 || metadata) + if (ipv6) { ret = __vxlan_sock_add(vxlan, true); + if (ret < 0 && ret != -EAFNOSUPPORT) + ipv4 = false; + } #endif - if (!ret && (!ipv6 || metadata)) + if (ipv4) ret = __vxlan_sock_add(vxlan, false); if (ret < 0) vxlan_sock_release(vxlan); -- GitLab From 498d02453e734133baff5ae24d54bf2b72abb179 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 28 Apr 2017 15:56:09 +0300 Subject: [PATCH 0693/1834] qed: Unlock on error in qed_vf_pf_acquire() [ Upstream commit 66117a9d9a8ca948680d6554769ef9e88f936954 ] My static checker complains that we're holding a mutex on this error path. Let's goto exit instead of returning directly. Fixes: b0bccb69eba3 ("qed: Change locking scheme for VF channel") Signed-off-by: Dan Carpenter Acked-by: Yuval Mintz Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_vf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_vf.c b/drivers/net/ethernet/qlogic/qed/qed_vf.c index abf5bf11f865..0645124a887b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_vf.c +++ b/drivers/net/ethernet/qlogic/qed/qed_vf.c @@ -204,7 +204,7 @@ static int qed_vf_pf_acquire(struct qed_hwfn *p_hwfn) /* send acquire request */ rc = qed_send_msg2pf(p_hwfn, &resp->hdr.status, sizeof(*resp)); if (rc) - return rc; + goto exit; /* copy acquire response from buffer to p_hwfn */ memcpy(&p_iov->acquire_resp, resp, sizeof(p_iov->acquire_resp)); -- GitLab From 909dbba2106f370d93bb4b6dc7520a8ef7791f08 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Fri, 28 Apr 2017 19:17:41 -0500 Subject: [PATCH 0694/1834] bnx2x: Align RX buffers [ Upstream commit 9b70de6d0266888b3743f03802502e43131043c8 ] The bnx2x driver is not providing proper alignment on the receive buffers it passes to build_skb(), causing skb_shared_info to be misaligned. skb_shared_info contains an atomic, and while PPC normally supports unaligned accesses, it does not support unaligned atomics. Aligning the size of rx buffers will ensure that page_frag_alloc() returns aligned addresses. This can be reproduced on PPC by setting the network MTU to 1450 (or other non-multiple-of-4) and then generating sufficient inbound network traffic (one or two large "wget"s usually does it), producing the following oops: Unable to handle kernel paging request for unaligned access at address 0xc00000ffc43af656 Faulting instruction address: 0xc00000000080ef8c Oops: Kernel access of bad area, sig: 7 [#1] SMP NR_CPUS=2048 NUMA PowerNV Modules linked in: vmx_crypto powernv_rng rng_core powernv_op_panel leds_powernv led_class nfsd ip_tables x_tables autofs4 xfs lpfc bnx2x mdio libcrc32c crc_t10dif crct10dif_generic crct10dif_common CPU: 104 PID: 0 Comm: swapper/104 Not tainted 4.11.0-rc8-00088-g4c761da #2 task: c00000ffd4892400 task.stack: c00000ffd4920000 NIP: c00000000080ef8c LR: c00000000080eee8 CTR: c0000000001f8320 REGS: c00000ffffc33710 TRAP: 0600 Not tainted (4.11.0-rc8-00088-g4c761da) MSR: 9000000000009033 CR: 24082042 XER: 00000000 CFAR: c00000000080eea0 DAR: c00000ffc43af656 DSISR: 00000000 SOFTE: 1 GPR00: c000000000907f64 c00000ffffc33990 c000000000dd3b00 c00000ffcaf22100 GPR04: c00000ffcaf22e00 0000000000000000 0000000000000000 0000000000000000 GPR08: 0000000000b80008 c00000ffc43af636 c00000ffc43af656 0000000000000000 GPR12: c0000000001f6f00 c00000000fe1a000 000000000000049f 000000000000c51f GPR16: 00000000ffffef33 0000000000000000 0000000000008a43 0000000000000001 GPR20: c00000ffc58a90c0 0000000000000000 000000000000dd86 0000000000000000 GPR24: c000007fd0ed10c0 00000000ffffffff 0000000000000158 000000000000014a GPR28: c00000ffc43af010 c00000ffc9144000 c00000ffcaf22e00 c00000ffcaf22100 NIP [c00000000080ef8c] __skb_clone+0xdc/0x140 LR [c00000000080eee8] __skb_clone+0x38/0x140 Call Trace: [c00000ffffc33990] [c00000000080fb74] skb_clone+0x74/0x110 (unreliable) [c00000ffffc339c0] [c000000000907f64] packet_rcv+0x144/0x510 [c00000ffffc33a40] [c000000000827b64] __netif_receive_skb_core+0x5b4/0xd80 [c00000ffffc33b00] [c00000000082b2bc] netif_receive_skb_internal+0x2c/0xc0 [c00000ffffc33b40] [c00000000082c49c] napi_gro_receive+0x11c/0x260 [c00000ffffc33b80] [d000000066483d68] bnx2x_poll+0xcf8/0x17b0 [bnx2x] [c00000ffffc33d00] [c00000000082babc] net_rx_action+0x31c/0x480 [c00000ffffc33e10] [c0000000000d5a44] __do_softirq+0x164/0x3d0 [c00000ffffc33f00] [c0000000000d60a8] irq_exit+0x108/0x120 [c00000ffffc33f20] [c000000000015b98] __do_irq+0x98/0x200 [c00000ffffc33f90] [c000000000027f14] call_do_irq+0x14/0x24 [c00000ffd4923a90] [c000000000015d94] do_IRQ+0x94/0x110 [c00000ffd4923ae0] [c000000000008d90] hardware_interrupt_common+0x150/0x160 Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 596f88b693ef..ca6c4718000f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2026,6 +2026,7 @@ static void bnx2x_set_rx_buf_size(struct bnx2x *bp) ETH_OVREHEAD + mtu + BNX2X_FW_RX_ALIGN_END; + fp->rx_buf_size = SKB_DATA_ALIGN(fp->rx_buf_size); /* Note : rx_buf_size doesn't take into account NET_SKB_PAD */ if (fp->rx_buf_size + NET_SKB_PAD <= PAGE_SIZE) fp->rx_frag_size = fp->rx_buf_size + NET_SKB_PAD; -- GitLab From 5ac685af62fb165a8bec3ca26c0c180e4de04929 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 14 Apr 2017 18:52:33 +0200 Subject: [PATCH 0695/1834] power: supply: bq24190_charger: Add disable-reset device-property [ Upstream commit 6cf62a3b97e78ba41d31390e59a1ddc98a9e3622 ] Allow platform-code to disable the reset on probe and suspend/resume by setting a "disable-reset" boolean device property on the device. There are several reasons why the platform-code may want to disable the reset on probe and suspend/resume: 1) Resetting the charger should never be necessary it should always have sane values programmed. If it is running with invalid values while we are not running (system turned off or suspended) there is a big problem as that may lead to overcharging the battery. 2) The reset in suspend() is meant to put the charger back into default mode, but this is not necessary and not a good idea. If the charger has been programmed with a higher max charge_current / charge_voltage then putting it back in default-mode will reset those to the safe power-on defaults, leading to slower charging, or charging to a lower voltage (and thus not using the full capacity) while suspended which is undesirable. Reprogramming the max charge_current / charge_voltage after the reset will not help here as that will put the charger back in host mode and start the i2c watchdog if the host then does not do anything for 40s (iow if we're suspended for more then 40s) the watchdog expires resetting the device to default-mode, including resetting all the registers to there safe power-on defaults. So the only way to keep using custom charge settings while suspending is to keep the charger in its normal running state with the i2c watchdog disabled. This is fine as the charger will still automatically switch from constant current to constant voltage and stop charging when the battery is full. 3) Besides never being necessary resetting the charger also causes problems on systems where the charge voltage limit is set higher then the reset value, if this is the case and the charger is reset while charging and the battery voltage is between the 2 voltages, then about half the time the charger gets confused and claims to be charging (REG08 contains 0x64) but in reality the charger has decoupled itself from VBUS (Q1 off) and is drawing 0A from VBUS, leaving the system running from the battery. This last problem is happening on a GPD-win mini PC with a bq24292i charger chip combined with a max17047 fuel-gauge and a LiHV battery. I've checked and TI does not list any errata for the bq24292i which could explain this (there are no errata at all). Cc: Liam Breck Cc: Tony Lindgren Signed-off-by: Hans de Goede Acked-by: Liam Breck Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/bq24190_charger.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index cdd71ecd72ed..8ed2782d1bb1 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -506,6 +506,9 @@ static int bq24190_register_reset(struct bq24190_dev_info *bdi) int ret, limit = 100; u8 v; + if (device_property_read_bool(bdi->dev, "disable-reset")) + return 0; + /* Reset the registers */ ret = bq24190_write_mask(bdi, BQ24190_REG_POC, BQ24190_REG_POC_RESET_MASK, -- GitLab From 9822cb80738a31f4e4821e385920547ddb95828e Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Mon, 24 Apr 2017 16:22:08 +0800 Subject: [PATCH 0696/1834] power: supply: isp1704: Fix unchecked return value of devm_kzalloc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 8b20839988f1ed5e534b270f3776709b640dc7e0 ] Function devm_kzalloc() will return a NULL pointer. However, in function isp1704_charger_probe(), the return value of devm_kzalloc() is directly used without validation. This may result in a bad memory access bug. Fixes: 34a109610e2a ("isp1704_charger: Add DT support") Signed-off-by: Pan Bian Reviewed-by: Pali Rohár Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/isp1704_charger.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/power/supply/isp1704_charger.c b/drivers/power/supply/isp1704_charger.c index 4cd6899b961e..95af5f305838 100644 --- a/drivers/power/supply/isp1704_charger.c +++ b/drivers/power/supply/isp1704_charger.c @@ -418,6 +418,10 @@ static int isp1704_charger_probe(struct platform_device *pdev) pdata = devm_kzalloc(&pdev->dev, sizeof(struct isp1704_charger_data), GFP_KERNEL); + if (!pdata) { + ret = -ENOMEM; + goto fail0; + } pdata->enable_gpio = gpio; dev_info(&pdev->dev, "init gpio %d\n", pdata->enable_gpio); -- GitLab From 5b65f7d823f3ce0e6e46eb08b2d35972e6092699 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Tue, 25 Apr 2017 15:18:05 +0200 Subject: [PATCH 0697/1834] power: supply: pda_power: move from timer to delayed_work [ Upstream commit 633e8799ddc09431be2744c4a1efdbda13af2b0b ] This changed is needed to avoid locking problem during boot as shown: <5>[ 8.824096] Registering SWP/SWPB emulation handler <6>[ 8.977294] clock: disabling unused clocks to save power <3>[ 9.108154] BUG: sleeping function called from invalid context at kernel_albert/kernel/mutex.c:269 <3>[ 9.122894] in_atomic(): 1, irqs_disabled(): 0, pid: 1, name: swapper/0 <4>[ 9.130249] 3 locks held by swapper/0/1: <4>[ 9.134613] #0: (&__lockdep_no_validate__){......}, at: [] __driver_attach+0x58/0xa8 <4>[ 9.144500] #1: (&__lockdep_no_validate__){......}, at: [] __driver_attach+0x68/0xa8 <4>[ 9.154357] #2: (&polling_timer){......}, at: [] run_timer_softirq+0x108/0x3ec <4>[ 9.163726] Backtrace: <4>[ 9.166473] [] (dump_backtrace+0x0/0x114) from [] (dump_stack+0x20/0x24) <4>[ 9.175811] r6:00203230 r5:0000010d r4:d782e000 r3:60000113 <4>[ 9.182250] [] (dump_stack+0x0/0x24) from [] (__might_sleep+0x10c/0x128) <4>[ 9.191650] [] (__might_sleep+0x0/0x128) from [] (mutex_lock_nested+0x34/0x36c) <4>[ 9.201660] r5:c02d5350 r4:d79a0c64 <4>[ 9.205688] [] (mutex_lock_nested+0x0/0x36c) from [] (regulator_set_current_limit+0x30/0x118) <4>[ 9.217071] [] (regulator_set_current_limit+0x0/0x118) from [] (update_charger+0x84/0xc4) <4>[ 9.228027] r7:d782fb20 r6:00000101 r5:c1767e94 r4:00000000 <4>[ 9.234436] [] (update_charger+0x0/0xc4) from [] (psy_changed+0x20/0x48) <4>[ 9.243804] r5:d782e000 r4:c1767e94 <4>[ 9.247802] [] (psy_changed+0x0/0x48) from [] (polling_timer_func+0x84/0xb8) <4>[ 9.257537] r4:c1767e94 r3:00000002 <4>[ 9.261566] [] (polling_timer_func+0x0/0xb8) from [] (run_timer_softirq+0x17c/0x3ec) <4>[ 9.272033] r4:c1767eb0 r3:00000000 <4>[ 9.276062] [] (run_timer_softirq+0x0/0x3ec) from [] (__do_softirq+0xf0/0x298) <4>[ 9.286010] [] (__do_softirq+0x0/0x298) from [] (irq_exit+0x98/0xa0) <4>[ 9.295013] [] (irq_exit+0x0/0xa0) from [] (handle_IRQ+0x60/0xc0) <4>[ 9.303680] r4:c1194e98 r3:c00bc778 <4>[ 9.307708] [] (handle_IRQ+0x0/0xc0) from [] (gic_handle_irq+0x34/0x68) <4>[ 9.316955] r8:000ac383 r7:d782fc3c r6:d782fc08 r5:c11936c4 r4:e0802100 <4>[ 9.324310] r3:c026ba48 <4>[ 9.327301] [] (gic_handle_irq+0x0/0x68) from [] (__irq_svc+0x40/0x74) <4>[ 9.336456] Exception stack(0xd782fc08 to 0xd782fc50) <4>[ 9.342041] fc00: d6e30e6c ac383627 00000000 ac383417 ea19c000 ea200000 <4>[ 9.351104] fc20: beffffff 00000667 000ac383 d6e30670 d6e3066c d782fc94 d782fbe8 d782fc50 <4>[ 9.360168] fc40: c026ba48 c001d1f0 00000113 ffffffff Fixes: b2998049cfae ("[BATTERY] pda_power platform driver") Signed-off-by: Michael Trimarchi Signed-off-by: Anthony Brandon Signed-off-by: Sebastian Reichel Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/power/supply/pda_power.c | 49 ++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/drivers/power/supply/pda_power.c b/drivers/power/supply/pda_power.c index dfe1ee89f7c7..922a86787c5c 100644 --- a/drivers/power/supply/pda_power.c +++ b/drivers/power/supply/pda_power.c @@ -30,9 +30,9 @@ static inline unsigned int get_irq_flags(struct resource *res) static struct device *dev; static struct pda_power_pdata *pdata; static struct resource *ac_irq, *usb_irq; -static struct timer_list charger_timer; -static struct timer_list supply_timer; -static struct timer_list polling_timer; +static struct delayed_work charger_work; +static struct delayed_work polling_work; +static struct delayed_work supply_work; static int polling; static struct power_supply *pda_psy_ac, *pda_psy_usb; @@ -140,7 +140,7 @@ static void update_charger(void) } } -static void supply_timer_func(unsigned long unused) +static void supply_work_func(struct work_struct *work) { if (ac_status == PDA_PSY_TO_CHANGE) { ac_status = new_ac_status; @@ -161,11 +161,12 @@ static void psy_changed(void) * Okay, charger set. Now wait a bit before notifying supplicants, * charge power should stabilize. */ - mod_timer(&supply_timer, - jiffies + msecs_to_jiffies(pdata->wait_for_charger)); + cancel_delayed_work(&supply_work); + schedule_delayed_work(&supply_work, + msecs_to_jiffies(pdata->wait_for_charger)); } -static void charger_timer_func(unsigned long unused) +static void charger_work_func(struct work_struct *work) { update_status(); psy_changed(); @@ -184,13 +185,14 @@ static irqreturn_t power_changed_isr(int irq, void *power_supply) * Wait a bit before reading ac/usb line status and setting charger, * because ac/usb status readings may lag from irq. */ - mod_timer(&charger_timer, - jiffies + msecs_to_jiffies(pdata->wait_for_status)); + cancel_delayed_work(&charger_work); + schedule_delayed_work(&charger_work, + msecs_to_jiffies(pdata->wait_for_status)); return IRQ_HANDLED; } -static void polling_timer_func(unsigned long unused) +static void polling_work_func(struct work_struct *work) { int changed = 0; @@ -211,8 +213,9 @@ static void polling_timer_func(unsigned long unused) if (changed) psy_changed(); - mod_timer(&polling_timer, - jiffies + msecs_to_jiffies(pdata->polling_interval)); + cancel_delayed_work(&polling_work); + schedule_delayed_work(&polling_work, + msecs_to_jiffies(pdata->polling_interval)); } #if IS_ENABLED(CONFIG_USB_PHY) @@ -250,8 +253,9 @@ static int otg_handle_notification(struct notifier_block *nb, * Wait a bit before reading ac/usb line status and setting charger, * because ac/usb status readings may lag from irq. */ - mod_timer(&charger_timer, - jiffies + msecs_to_jiffies(pdata->wait_for_status)); + cancel_delayed_work(&charger_work); + schedule_delayed_work(&charger_work, + msecs_to_jiffies(pdata->wait_for_status)); return NOTIFY_OK; } @@ -300,8 +304,8 @@ static int pda_power_probe(struct platform_device *pdev) if (!pdata->ac_max_uA) pdata->ac_max_uA = 500000; - setup_timer(&charger_timer, charger_timer_func, 0); - setup_timer(&supply_timer, supply_timer_func, 0); + INIT_DELAYED_WORK(&charger_work, charger_work_func); + INIT_DELAYED_WORK(&supply_work, supply_work_func); ac_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ac"); usb_irq = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "usb"); @@ -385,9 +389,10 @@ static int pda_power_probe(struct platform_device *pdev) if (polling) { dev_dbg(dev, "will poll for status\n"); - setup_timer(&polling_timer, polling_timer_func, 0); - mod_timer(&polling_timer, - jiffies + msecs_to_jiffies(pdata->polling_interval)); + INIT_DELAYED_WORK(&polling_work, polling_work_func); + cancel_delayed_work(&polling_work); + schedule_delayed_work(&polling_work, + msecs_to_jiffies(pdata->polling_interval)); } if (ac_irq || usb_irq) @@ -433,9 +438,9 @@ static int pda_power_remove(struct platform_device *pdev) free_irq(ac_irq->start, pda_psy_ac); if (polling) - del_timer_sync(&polling_timer); - del_timer_sync(&charger_timer); - del_timer_sync(&supply_timer); + cancel_delayed_work_sync(&polling_work); + cancel_delayed_work_sync(&charger_work); + cancel_delayed_work_sync(&supply_work); if (pdata->is_usb_online) power_supply_unregister(pda_psy_usb); -- GitLab From edc0bfd6e2276e3d53dc3ebb7f454d1b940e4967 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Fri, 28 Apr 2017 10:25:51 -0700 Subject: [PATCH 0698/1834] Input: twl4030-pwrbutton - use correct device for irq request [ Upstream commit 3071e9dd6cd3f2290d770117330f2c8b2e9a97e4 ] The interrupt should be requested for the platform device and not for the input device. Fixes: 7f9ce649d267 ("Input: twl4030-pwrbutton - simplify driver using devm_*") Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/misc/twl4030-pwrbutton.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c index 603fc2fadf05..12b20840fb74 100644 --- a/drivers/input/misc/twl4030-pwrbutton.c +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -70,7 +70,7 @@ static int twl4030_pwrbutton_probe(struct platform_device *pdev) pwr->phys = "twl4030_pwrbutton/input0"; pwr->dev.parent = &pdev->dev; - err = devm_request_threaded_irq(&pwr->dev, irq, NULL, powerbutton_irq, + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, powerbutton_irq, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_pwrbutton", pwr); -- GitLab From 9002e49554da9e3a4d70b2c18e7603d6fcefdbfe Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 6 Apr 2017 14:49:44 +0200 Subject: [PATCH 0699/1834] IB/rxe: Don't clamp residual length to mtu [ Upstream commit d52418502e288b5c7e9e2e6cf1de5f1d3d79d2e1 ] When reading a RDMA WRITE FIRST packet we copy the DMA length from the RDMA header into the qp->resp.resid variable for later use. Later in check_rkey() we clamp it to the MTU if the packet is an RDMA WRITE packet and has a residual length bigger than the MTU. Later in write_data_in() we subtract the payload of the packet from the residual length. If the packet happens to have a payload of exactly the MTU size we end up with a residual length of 0 despite the packet not being the last in the conversation. When the next packet in the conversation arrives, we don't have any residual length left and thus set the QP into an error state. This broke NVMe over Fabrics functionality over rdma_rxe.ko The patch was verified using the following test. # echo eth0 > /sys/module/rdma_rxe/parameters/add # nvme connect -t rdma -a 192.168.155.101 -s 1023 -n nvmf-test # mkfs.xfs -fK /dev/nvme0n1 meta-data=/dev/nvme0n1 isize=256 agcount=4, agsize=65536 blks = sectsz=4096 attr=2, projid32bit=1 = crc=0 finobt=0, sparse=0 data = bsize=4096 blocks=262144, imaxpct=25 = sunit=0 swidth=0 blks naming =version 2 bsize=4096 ascii-ci=0 ftype=1 log =internal log bsize=4096 blocks=2560, version=2 = sectsz=4096 sunit=1 blks, lazy-count=1 realtime =none extsz=4096 blocks=0, rtextents=0 # mount /dev/nvme0n1 /tmp/ [ 148.923263] XFS (nvme0n1): Mounting V4 Filesystem [ 148.961196] XFS (nvme0n1): Ending clean mount # dd if=/dev/urandom of=test.bin bs=1M count=128 128+0 records in 128+0 records out 134217728 bytes (134 MB, 128 MiB) copied, 0.437991 s, 306 MB/s # sha256sum test.bin cde42941f045efa8c4f0f157ab6f29741753cdd8d1cff93a6b03649d83c4129a test.bin # cp test.bin /tmp/ sha256sum /tmp/test.bin cde42941f045efa8c4f0f157ab6f29741753cdd8d1cff93a6b03649d83c4129a /tmp/test.bin Signed-off-by: Johannes Thumshirn Cc: Hannes Reinecke Cc: Sagi Grimberg Cc: Max Gurtovoy Acked-by: Moni Shoua Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/sw/rxe/rxe_resp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 8c0ddd7165ae..0d25dc84d294 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -471,8 +471,6 @@ static enum resp_states check_rkey(struct rxe_qp *qp, state = RESPST_ERR_LENGTH; goto err; } - - qp->resp.resid = mtu; } else { if (pktlen != resid) { state = RESPST_ERR_LENGTH; -- GitLab From 2710fb8f0c828656a147870dccc5164c0f0c48ea Mon Sep 17 00:00:00 2001 From: Shaohua Li Date: Mon, 1 May 2017 12:15:07 -0700 Subject: [PATCH 0700/1834] md/raid10: skip spare disk as 'first' disk [ Upstream commit b506335e5d2b4ec687dde392a3bdbf7601778f1d ] Commit 6f287ca(md/raid10: reset the 'first' at the end of loop) ignores a case in reshape, the first rdev could be a spare disk, which shouldn't be accounted as the first disk since it doesn't include the offset info. Fix: 6f287ca(md/raid10: reset the 'first' at the end of loop) Cc: Guoqing Jiang Cc: NeilBrown Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index b1daff78f7b2..18a4271bf569 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -4089,6 +4089,7 @@ static int raid10_start_reshape(struct mddev *mddev) diff = 0; if (first || diff < min_offset_diff) min_offset_diff = diff; + first = 0; } } -- GitLab From a9b90d80db0e53ce4fe06a1ffe12ac683f7b06c9 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 30 Apr 2017 22:54:16 +0200 Subject: [PATCH 0701/1834] ACPI / power: Delay turning off unused power resources after suspend [ Upstream commit 8ece1d83346bcc431090d59a2184276192189cdd ] Commit 660b1113e0f3 (ACPI / PM: Fix consistency check for power resources during resume) introduced a check for ACPI power resources which have been turned on by the BIOS during suspend and turns these back off again. This is causing problems on a Dell Venue Pro 11 7130 (i5-4300Y) it causes the following messages to show up in dmesg: [ 131.014605] ACPI: Waking up from system sleep state S3 [ 131.150271] acpi LNXPOWER:07: Turning OFF [ 131.150323] acpi LNXPOWER:06: Turning OFF [ 131.150911] acpi LNXPOWER:00: Turning OFF [ 131.169014] ACPI : EC: interrupt unblocked [ 131.181811] xhci_hcd 0000:00:14.0: System wakeup disabled by ACPI [ 133.535728] pci_raw_set_power_state: 76 callbacks suppressed [ 133.535735] iwlwifi 0000:01:00.0: Refused to change power state, currently in D3 [ 133.597672] PM: noirq resume of devices complete after 2428.891 msecs Followed by a bunch of iwlwifi errors later on and the pcie device dropping from the bus (acpiphp thinks it has been unplugged). Disabling the turning off of unused power resources fixes this. Instead of adding a quirk for this system, this commit fixes this by moving the disabling of unused power resources to later in the resume sequence when the iwlwifi card has been moved out of D3 so the ref_count for its power resource no longer is 0. This new behavior seems to match the intend of the original commit which commit-msg says: "(... which means that no devices are going to need them any time soon) and we should turn them off". This also avoids power resources which we need when bringing devices out of D3 from getting bounced off and then back on again. Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/power.c | 10 ++++++++++ drivers/acpi/sleep.c | 1 + drivers/acpi/sleep.h | 1 + 3 files changed, 12 insertions(+) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 1c2b846c5776..3a6c9b741b23 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -864,6 +864,16 @@ void acpi_resume_power_resources(void) mutex_unlock(&resource->resource_lock); } + + mutex_unlock(&power_resource_list_lock); +} + +void acpi_turn_off_unused_power_resources(void) +{ + struct acpi_power_resource *resource; + + mutex_lock(&power_resource_list_lock); + list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) { int result, state; diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index a4327af676fe..097d630ab886 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -474,6 +474,7 @@ static void acpi_pm_start(u32 acpi_state) */ static void acpi_pm_end(void) { + acpi_turn_off_unused_power_resources(); acpi_scan_lock_release(); /* * This is necessary in case acpi_pm_finish() is not called during a diff --git a/drivers/acpi/sleep.h b/drivers/acpi/sleep.h index a9cc34e663f9..a82ff74faf7a 100644 --- a/drivers/acpi/sleep.h +++ b/drivers/acpi/sleep.h @@ -6,6 +6,7 @@ extern struct list_head acpi_wakeup_device_list; extern struct mutex acpi_device_lock; extern void acpi_resume_power_resources(void); +extern void acpi_turn_off_unused_power_resources(void); static inline acpi_status acpi_set_waking_vector(u32 wakeup_address) { -- GitLab From 9935f862199bf7ddc2d26fad089b756fab0ad816 Mon Sep 17 00:00:00 2001 From: Sergei Trofimovich Date: Mon, 1 May 2017 11:51:55 -0700 Subject: [PATCH 0702/1834] ia64: fix module loading for gcc-5.4 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit a25fb8508c1b80dce742dbeaa4d75a1e9f2c5617 ] Starting from gcc-5.4+ gcc generates MLX instructions in more cases to refer local symbols: https://gcc.gnu.org/PR60465 That caused ia64 module loader to choke on such instructions: fuse: invalid slot number 1 for IMM64 The Linux kernel used to handle only case where relocation pointed to slot=2 instruction in the bundle. That limitation was fixed in linux by commit 9c184a073bfd ("[IA64] Fix 2.6 kernel for the new ia64 assembler") See http://sources.redhat.com/bugzilla/show_bug.cgi?id=1433 This change lifts the slot=2 restriction from the kernel module loader. Tested on 'fuse' and 'btrfs' kernel modules. Cc: Markus Elfring Cc: H J Lu Cc: Fenghua Yu Cc: Andrew Morton Bug: https://bugs.gentoo.org/601014 Tested-by: Émeric MASCHINO Signed-off-by: Sergei Trofimovich Signed-off-by: Tony Luck Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/ia64/kernel/module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c index 6ab0ae7d6535..d1d945c6bd05 100644 --- a/arch/ia64/kernel/module.c +++ b/arch/ia64/kernel/module.c @@ -153,7 +153,7 @@ slot (const struct insn *insn) static int apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) { - if (slot(insn) != 2) { + if (slot(insn) != 1 && slot(insn) != 2) { printk(KERN_ERR "%s: invalid slot number %d for IMM64\n", mod->name, slot(insn)); return 0; @@ -165,7 +165,7 @@ apply_imm64 (struct module *mod, struct insn *insn, uint64_t val) static int apply_imm60 (struct module *mod, struct insn *insn, uint64_t val) { - if (slot(insn) != 2) { + if (slot(insn) != 1 && slot(insn) != 2) { printk(KERN_ERR "%s: invalid slot number %d for IMM60\n", mod->name, slot(insn)); return 0; -- GitLab From f29bc9dc0bef0cb6f3ca069d96fbd535439d1680 Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Fri, 31 Mar 2017 19:53:35 +0400 Subject: [PATCH 0703/1834] tcm_fileio: Prevent information leak for short reads [ Upstream commit f11b55d13563e9428c88c873f4f03a6bef11ec0a ] If we failed to read data from backing file (probably because some one truncate file under us), we must zerofill cmd's data, otherwise it will be returned as is. Most likely cmd's data are unitialized pages from page cache. This result in information leak. (Change BUG_ON into -EINVAL se_cmd failure - nab) testcase: https://github.com/dmonakhov/xfstests/commit/e11a1b7b907ca67b1be51a1594025600767366d5 Signed-off-by: Dmitry Monakhov Signed-off-by: Nicholas Bellinger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/target/target_core_file.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 97928b42ad62..57a3d3936364 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -276,12 +276,11 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd, else ret = vfs_iter_read(fd, &iter, &pos); - kfree(bvec); - if (is_write) { if (ret < 0 || ret != data_length) { pr_err("%s() write returned %d\n", __func__, ret); - return (ret < 0 ? ret : -EINVAL); + if (ret >= 0) + ret = -EINVAL; } } else { /* @@ -294,17 +293,29 @@ static int fd_do_rw(struct se_cmd *cmd, struct file *fd, pr_err("%s() returned %d, expecting %u for " "S_ISBLK\n", __func__, ret, data_length); - return (ret < 0 ? ret : -EINVAL); + if (ret >= 0) + ret = -EINVAL; } } else { if (ret < 0) { pr_err("%s() returned %d for non S_ISBLK\n", __func__, ret); - return ret; + } else if (ret != data_length) { + /* + * Short read case: + * Probably some one truncate file under us. + * We must explicitly zero sg-pages to prevent + * expose uninizialized pages to userspace. + */ + if (ret < data_length) + ret += iov_iter_zero(data_length - ret, &iter); + else + ret = -EINVAL; } } } - return 1; + kfree(bvec); + return ret; } static sense_reason_t -- GitLab From 51174d2553d33d574c159098c94a10050762ee4c Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 14 Mar 2017 18:35:43 +0100 Subject: [PATCH 0704/1834] x86/xen: split xen_smp_prepare_boot_cpu() [ Upstream commit a2d1078a35f9a38ae888aa6147e4ca32666154a1 ] Split xen_smp_prepare_boot_cpu() into xen_pv_smp_prepare_boot_cpu() and xen_hvm_smp_prepare_boot_cpu() to support further splitting of smp.c. Signed-off-by: Vitaly Kuznetsov Reviewed-by: Juergen Gross Signed-off-by: Juergen Gross Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/xen/smp.c | 49 ++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 137afbbd0590..a11540e51f62 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -299,35 +299,46 @@ static void __init xen_filter_cpu_maps(void) } -static void __init xen_smp_prepare_boot_cpu(void) +static void __init xen_pv_smp_prepare_boot_cpu(void) { BUG_ON(smp_processor_id() != 0); native_smp_prepare_boot_cpu(); - if (xen_pv_domain()) { - if (!xen_feature(XENFEAT_writable_page_tables)) - /* We've switched to the "real" per-cpu gdt, so make - * sure the old memory can be recycled. */ - make_lowmem_page_readwrite(xen_initial_gdt); + if (!xen_feature(XENFEAT_writable_page_tables)) + /* We've switched to the "real" per-cpu gdt, so make + * sure the old memory can be recycled. */ + make_lowmem_page_readwrite(xen_initial_gdt); #ifdef CONFIG_X86_32 - /* - * Xen starts us with XEN_FLAT_RING1_DS, but linux code - * expects __USER_DS - */ - loadsegment(ds, __USER_DS); - loadsegment(es, __USER_DS); + /* + * Xen starts us with XEN_FLAT_RING1_DS, but linux code + * expects __USER_DS + */ + loadsegment(ds, __USER_DS); + loadsegment(es, __USER_DS); #endif - xen_filter_cpu_maps(); - xen_setup_vcpu_info_placement(); - } + xen_filter_cpu_maps(); + xen_setup_vcpu_info_placement(); + + /* + * The alternative logic (which patches the unlock/lock) runs before + * the smp bootup up code is activated. Hence we need to set this up + * the core kernel is being patched. Otherwise we will have only + * modules patched but not core code. + */ + xen_init_spinlocks(); +} + +static void __init xen_hvm_smp_prepare_boot_cpu(void) +{ + BUG_ON(smp_processor_id() != 0); + native_smp_prepare_boot_cpu(); /* * Setup vcpu_info for boot CPU. */ - if (xen_hvm_domain()) - xen_vcpu_setup(0); + xen_vcpu_setup(0); /* * The alternative logic (which patches the unlock/lock) runs before @@ -733,7 +744,7 @@ static irqreturn_t xen_irq_work_interrupt(int irq, void *dev_id) } static const struct smp_ops xen_smp_ops __initconst = { - .smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu, + .smp_prepare_boot_cpu = xen_pv_smp_prepare_boot_cpu, .smp_prepare_cpus = xen_smp_prepare_cpus, .smp_cpus_done = xen_smp_cpus_done, @@ -772,5 +783,5 @@ void __init xen_hvm_smp_init(void) smp_ops.cpu_die = xen_cpu_die; smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi; smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi; - smp_ops.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu; + smp_ops.smp_prepare_boot_cpu = xen_hvm_smp_prepare_boot_cpu; } -- GitLab From e5ea3b04080c790a1d8a1ec2e8526bebb66f497b Mon Sep 17 00:00:00 2001 From: Maksim Salau Date: Tue, 2 May 2017 13:47:53 +0200 Subject: [PATCH 0705/1834] video: fbdev: udlfb: Fix buffer on stack [ Upstream commit 45f580c42e5c125d55dbd8099750a1998de3d917 ] Allocate buffers on HEAP instead of STACK for local array that is to be sent using usb_control_msg(). Signed-off-by: Maksim Salau Cc: Bernie Thompson Cc: Geert Uytterhoeven Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/udlfb.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index 53326badfb61..2add8def83be 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -1487,15 +1487,25 @@ static struct device_attribute fb_device_attrs[] = { static int dlfb_select_std_channel(struct dlfb_data *dev) { int ret; - u8 set_def_chn[] = { 0x57, 0xCD, 0xDC, 0xA7, + void *buf; + static const u8 set_def_chn[] = { + 0x57, 0xCD, 0xDC, 0xA7, 0x1C, 0x88, 0x5E, 0x15, 0x60, 0xFE, 0xC6, 0x97, 0x16, 0x3D, 0x47, 0xF2 }; + buf = kmemdup(set_def_chn, sizeof(set_def_chn), GFP_KERNEL); + + if (!buf) + return -ENOMEM; + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), NR_USB_REQUEST_CHANNEL, (USB_DIR_OUT | USB_TYPE_VENDOR), 0, 0, - set_def_chn, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT); + buf, sizeof(set_def_chn), USB_CTRL_SET_TIMEOUT); + + kfree(buf); + return ret; } -- GitLab From e22a6754abda4ab563fce3f3241e71a8c917c979 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Tue, 2 May 2017 13:47:53 +0200 Subject: [PATCH 0706/1834] sm501fb: don't return zero on failure path in sm501fb_start() [ Upstream commit dc85e9a87420613b3129d5cc5ecd79c58351c546 ] If fbmem iomemory mapping failed, sm501fb_start() breaks off initialization, deallocates resources, but returns zero. As a result, double deallocation can happen in sm501fb_stop(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Cc: Tomi Valkeinen Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/sm501fb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c index d0a4e2f79a57..d215faacce04 100644 --- a/drivers/video/fbdev/sm501fb.c +++ b/drivers/video/fbdev/sm501fb.c @@ -1600,6 +1600,7 @@ static int sm501fb_start(struct sm501fb_info *info, info->fbmem = ioremap(res->start, resource_size(res)); if (info->fbmem == NULL) { dev_err(dev, "cannot remap framebuffer\n"); + ret = -ENXIO; goto err_mem_res; } -- GitLab From 1b9c9549b2c9814d35b22fa817466226d9fbb8e5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 1 May 2017 17:06:56 -0400 Subject: [PATCH 0707/1834] pNFS: Fix a deadlock when coalescing writes and returning the layout [ Upstream commit 61f454e30c18a28924e96be12592c0d5e24bcc81 ] Consider the following deadlock: Process P1 Process P2 Process P3 ========== ========== ========== lock_page(page) lseg = pnfs_update_layout(inode) lo = NFS_I(inode)->layout pnfs_error_mark_layout_for_return(lo) lock_page(page) lseg = pnfs_update_layout(inode) In this scenario, - P1 has declared the layout to be in error, but P2 holds a reference to a layout segment on that inode, so the layoutreturn is deferred. - P2 is waiting for a page lock held by P3. - P3 is asking for a new layout segment, but is blocked waiting for the layoutreturn. The fix is to ensure that pnfs_error_mark_layout_for_return() does not set the NFS_LAYOUT_RETURN flag, which blocks P3. Instead, we allow the latter to call LAYOUTGET so that it can make progress and unblock P2. Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/pnfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index e9a697e9d292..0e008db16b16 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1953,8 +1953,6 @@ void pnfs_error_mark_layout_for_return(struct inode *inode, spin_lock(&inode->i_lock); pnfs_set_plh_return_info(lo, range.iomode, 0); - /* Block LAYOUTGET */ - set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags); /* * mark all matching lsegs so that we are sure to have no live * segments at hand when sending layoutreturn. See pnfs_put_lseg() -- GitLab From b2a863dba3defce5f37af95007999ce9f48f8af6 Mon Sep 17 00:00:00 2001 From: Timmy Li Date: Tue, 2 May 2017 10:46:52 +0800 Subject: [PATCH 0708/1834] net: hns: fix ethtool_get_strings overflow in hns driver [ Upstream commit 412b65d15a7f8a93794653968308fc100f2aa87c ] hns_get_sset_count() returns HNS_NET_STATS_CNT and the data space allocated is not enough for ethtool_get_strings(), which will cause random memory corruption. When SLAB and DEBUG_SLAB are both enabled, memory corruptions like the the following can be observed without this patch: [ 43.115200] Slab corruption (Not tainted): Acpi-ParseExt start=ffff801fb0b69030, len=80 [ 43.115206] Redzone: 0x9f911029d006462/0x5f78745f31657070. [ 43.115208] Last user: [<5f7272655f746b70>](0x5f7272655f746b70) [ 43.115214] 010: 70 70 65 31 5f 74 78 5f 70 6b 74 00 6b 6b 6b 6b ppe1_tx_pkt.kkkk [ 43.115217] 030: 70 70 65 31 5f 74 78 5f 70 6b 74 5f 6f 6b 00 6b ppe1_tx_pkt_ok.k [ 43.115218] Next obj: start=ffff801fb0b69098, len=80 [ 43.115220] Redzone: 0x706d655f6f666966/0x9f911029d74e35b. [ 43.115229] Last user: [](acpi_os_release_object+0x28/0x38) [ 43.115231] 000: 74 79 00 6b 6b 6b 6b 6b 70 70 65 31 5f 74 78 5f ty.kkkkkppe1_tx_ [ 43.115232] 010: 70 6b 74 5f 65 72 72 5f 63 73 75 6d 5f 66 61 69 pkt_err_csum_fai Signed-off-by: Timmy Li Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index 02a03bccde7b..34b5e699a1d5 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -671,7 +671,7 @@ static void hns_gmac_get_strings(u32 stringset, u8 *data) static int hns_gmac_get_sset_count(int stringset) { - if (stringset == ETH_SS_STATS) + if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) return ARRAY_SIZE(g_gmac_stats_string); return 0; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c index 6ea872287307..4ecb809785f9 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c @@ -422,7 +422,7 @@ void hns_ppe_update_stats(struct hns_ppe_cb *ppe_cb) int hns_ppe_get_sset_count(int stringset) { - if (stringset == ETH_SS_STATS) + if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) return ETH_PPE_STATIC_NUM; return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index f3be9ac47bfb..fbbbbffd58dc 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -798,7 +798,7 @@ void hns_rcb_get_stats(struct hnae_queue *queue, u64 *data) */ int hns_rcb_get_ring_sset_count(int stringset) { - if (stringset == ETH_SS_STATS) + if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) return HNS_RING_STATIC_REG_NUM; return 0; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c index 8f4f0e8da984..d1c868c800f9 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_xgmac.c @@ -776,7 +776,7 @@ static void hns_xgmac_get_strings(u32 stringset, u8 *data) */ static int hns_xgmac_get_sset_count(int stringset) { - if (stringset == ETH_SS_STATS) + if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) return ARRAY_SIZE(g_xgmac_stats_string); return 0; -- GitLab From 31da33dd8ed44ec5c5d72630644c06905c2be7c5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 1 May 2017 21:43:43 +0300 Subject: [PATCH 0709/1834] cifs: small underflow in cnvrtDosUnixTm() [ Upstream commit 564277eceeca01e02b1ef3e141cfb939184601b4 ] January is month 1. There is no zero-th month. If someone passes a zero month then it means we read from one space before the start of the total_days_of_prev_months[] array. We may as well also be strict about days as well. Fixes: 1bd5bbcb6531 ("[CIFS] Legacy time handling for Win9x and OS/2 part 1") Signed-off-by: Dan Carpenter Signed-off-by: Steve French Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/cifs/netmisc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index abae6dd2c6b9..cc88f4f0325e 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -980,10 +980,10 @@ struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time, int offset) cifs_dbg(VFS, "illegal hours %d\n", st->Hours); days = sd->Day; month = sd->Month; - if ((days > 31) || (month > 12)) { + if (days < 1 || days > 31 || month < 1 || month > 12) { cifs_dbg(VFS, "illegal date, month %d day: %d\n", month, days); - if (month > 12) - month = 12; + days = clamp(days, 1, 31); + month = clamp(month, 1, 12); } month -= 1; days += total_days_of_prev_months[month]; -- GitLab From 7eb0b7339722ec570a47503f0d7b14d9c14b8d86 Mon Sep 17 00:00:00 2001 From: Johannes Weiner Date: Wed, 3 May 2017 14:51:54 -0700 Subject: [PATCH 0710/1834] mm: fix check for reclaimable pages in PF_MEMALLOC reclaim throttling [ Upstream commit d450abd81b081d45adb12f303a07dd44b15eb1bc ] PF_MEMALLOC direct reclaimers get throttled on a node when the sum of all free pages in each zone fall below half the min watermark. During the summation, we want to exclude zones that don't have reclaimables. Checking the same pgdat over and over again doesn't make sense. Fixes: 599d0c954f91 ("mm, vmscan: move LRU lists to node") Link: http://lkml.kernel.org/r/20170228214007.5621-3-hannes@cmpxchg.org Signed-off-by: Johannes Weiner Acked-by: Hillf Danton Acked-by: Michal Hocko Cc: Jia He Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 4365de74bdb0..cdd5c3b5c357 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2841,8 +2841,10 @@ static bool allow_direct_reclaim(pg_data_t *pgdat) for (i = 0; i <= ZONE_NORMAL; i++) { zone = &pgdat->node_zones[i]; - if (!managed_zone(zone) || - pgdat_reclaimable_pages(pgdat) == 0) + if (!managed_zone(zone)) + continue; + + if (!zone_reclaimable_pages(zone)) continue; pfmemalloc_reserve += min_wmark_pages(zone); -- GitLab From 82d938a9ed8e8d880dfd7e4def4adc1578e2710e Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Wed, 3 May 2017 14:53:02 -0700 Subject: [PATCH 0711/1834] mm, vmstat: suppress pcp stats for unpopulated zones in zoneinfo [ Upstream commit 7dfb8bf3b9caef4049bee51d2c22e1c3a311d483 ] After "mm, vmstat: print non-populated zones in zoneinfo", /proc/zoneinfo will show unpopulated zones. The per-cpu pageset statistics are not relevant for unpopulated zones and can be potentially lengthy, so supress them when they are not interesting. Also moves lowmem reserve protection information above pcp stats since it is relevant for all zones per vm.lowmem_reserve_ratio. Link: http://lkml.kernel.org/r/alpine.DEB.2.10.1703061400500.46428@chino.kir.corp.google.com Signed-off-by: David Rientjes Cc: Anshuman Khandual Cc: Vlastimil Babka Cc: Mel Gorman Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/vmstat.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/mm/vmstat.c b/mm/vmstat.c index 3863b5d6d598..68b3193e4493 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1387,18 +1387,24 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, zone->present_pages, zone->managed_pages); - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) - seq_printf(m, "\n %-12s %lu", vmstat_text[i], - zone_page_state(zone, i)); - seq_printf(m, "\n protection: (%ld", zone->lowmem_reserve[0]); for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) seq_printf(m, ", %ld", zone->lowmem_reserve[i]); - seq_printf(m, - ")" - "\n pagesets"); + seq_putc(m, ')'); + + /* If unpopulated, no other information is useful */ + if (!populated_zone(zone)) { + seq_putc(m, '\n'); + return; + } + + for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) + seq_printf(m, "\n %-12s %lu", vmstat_text[i], + zone_page_state(zone, i)); + + seq_printf(m, "\n pagesets"); for_each_online_cpu(i) { struct per_cpu_pageset *pageset; -- GitLab From 0b42ce075d8ed11259b36cdbed99bbab8f1f69f1 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Wed, 3 May 2017 14:56:22 -0700 Subject: [PATCH 0712/1834] mm: hwpoison: call shake_page() after try_to_unmap() for mlocked page [ Upstream commit 286c469a988fbaf68e3a97ddf1e6c245c1446968 ] Memory error handler calls try_to_unmap() for error pages in various states. If the error page is a mlocked page, error handling could fail with "still referenced by 1 users" message. This is because the page is linked to and stays in lru cache after the following call chain. try_to_unmap_one page_remove_rmap clear_page_mlock putback_lru_page lru_cache_add memory_failure() calls shake_page() to hanlde the similar issue, but current code doesn't cover because shake_page() is called only before try_to_unmap(). So this patches adds shake_page(). Fixes: 23a003bfd23ea9ea0b7756b920e51f64b284b468 ("mm/madvise: pass return code of memory_failure() to userspace") Link: http://lkml.kernel.org/r/20170417055948.GM31394@yexl-desktop Link: http://lkml.kernel.org/r/1493197841-23986-3-git-send-email-n-horiguchi@ah.jp.nec.com Signed-off-by: Naoya Horiguchi Reported-by: kernel test robot Cc: Xiaolong Ye Cc: Chen Gong Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/memory-failure.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 5aa71a82ca73..851efb004857 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -921,6 +921,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, int ret; int kill = 1, forcekill; struct page *hpage = *hpagep; + bool mlocked = PageMlocked(hpage); /* * Here we are interested only in user-mapped pages, so skip any @@ -984,6 +985,13 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn, pr_err("Memory failure: %#lx: failed to unmap page (mapcount=%d)\n", pfn, page_mapcount(hpage)); + /* + * try_to_unmap() might put mlocked page in lru cache, so call + * shake_page() again to ensure that it's flushed. + */ + if (mlocked) + shake_page(hpage, 0); + /* * Now that the dirty bit has been propagated to the * struct page and all unmaps done we can decide if -- GitLab From a06dfdb14333c5b7e8069339fb5561debe5068e4 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Mon, 24 Apr 2017 15:05:11 -0700 Subject: [PATCH 0713/1834] rtc: ds1374: wdt: Fix issue with timeout scaling from secs to wdt ticks [ Upstream commit 453d0744f6c6ca3f9749b8c57c2e85b5b9f52514 ] The issue is that the internal counter that triggers the watchdog reset is actually running at 4096 Hz instead of 1Hz, therefore the value given by userland (in sec) needs to be multiplied by 4096 to get the correct behavior. Fixes: 920f91e50c5b ("drivers/rtc/rtc-ds1374.c: add watchdog support") Signed-off-by: Moritz Fischer Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-ds1374.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 3b3049c8c9e0..5b5bc7dc3a1c 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -527,6 +527,10 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, if (get_user(new_margin, (int __user *)arg)) return -EFAULT; + /* the hardware's tick rate is 4096 Hz, so + * the counter value needs to be scaled accordingly + */ + new_margin <<= 12; if (new_margin < 1 || new_margin > 16777216) return -EINVAL; @@ -535,7 +539,8 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, ds1374_wdt_ping(); /* fallthrough */ case WDIOC_GETTIMEOUT: - return put_user(wdt_margin, (int __user *)arg); + /* when returning ... inverse is true */ + return put_user((wdt_margin >> 12), (int __user *)arg); case WDIOC_SETOPTIONS: if (copy_from_user(&options, (int __user *)arg, sizeof(int))) return -EFAULT; -- GitLab From 0e37c9f8d3f5a77cfebca019a25478ce7e2f7874 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Mon, 24 Apr 2017 15:05:12 -0700 Subject: [PATCH 0714/1834] rtc: ds1374: wdt: Fix stop/start ioctl always returning -EINVAL [ Upstream commit 538c08f4c89580fc644e2bc64e0a4b86c925da4e ] The WDIOC_SETOPTIONS case in the watchdog ioctl would alwayss falls through to the -EINVAL case. This is wrong since thew watchdog does actually get stopped or started correctly. Fixes: 920f91e50c5b ("drivers/rtc/rtc-ds1374.c: add watchdog support") Signed-off-by: Moritz Fischer Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-ds1374.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 5b5bc7dc3a1c..c0eb113588ff 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -548,14 +548,15 @@ static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, if (options & WDIOS_DISABLECARD) { pr_info("disable watchdog\n"); ds1374_wdt_disable(); + return 0; } if (options & WDIOS_ENABLECARD) { pr_info("enable watchdog\n"); ds1374_wdt_settimeout(wdt_margin); ds1374_wdt_ping(); + return 0; } - return -EINVAL; } return -ENOTTY; -- GitLab From 975760baa6e74d57502909b5dd0f01507187c6ff Mon Sep 17 00:00:00 2001 From: Michael Mera Date: Mon, 24 Apr 2017 16:11:57 +0900 Subject: [PATCH 0715/1834] ath10k: fix out of bounds access to local buffer [ Upstream commit a16703aaeaedec7a8bee5be5522c7c3e75478951 ] During write to debugfs file simulate_fw_crash, fixed-size local buffer 'buf' is accessed and modified at index 'count-1', where 'count' is the size of the write (so potentially out of bounds). This patch fixes this problem. Signed-off-by: Michael Mera Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/debug.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 6aa2b93497dd..0dadc6044dba 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -624,17 +624,21 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - char buf[32]; + char buf[32] = {0}; + ssize_t rc; int ret; - simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + /* filter partial writes and invalid commands */ + if (*ppos != 0 || count >= sizeof(buf) || count == 0) + return -EINVAL; - /* make sure that buf is null terminated */ - buf[sizeof(buf) - 1] = 0; + rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); + if (rc < 0) + return rc; /* drop the possible '\n' from the end */ - if (buf[count - 1] == '\n') - buf[count - 1] = 0; + if (buf[*ppos - 1] == '\n') + buf[*ppos - 1] = '\0'; mutex_lock(&ar->conf_mutex); -- GitLab From 85e598bc1514ba0d161cc0960017ca3b7b1c1640 Mon Sep 17 00:00:00 2001 From: Kim Phillips Date: Wed, 3 May 2017 13:14:02 +0100 Subject: [PATCH 0716/1834] perf tests kmod-path: Don't fail if compressed modules aren't supported [ Upstream commit 805b151a1afd24414706a7f6ae275fbb9649be74 ] __kmod_path__parse() uses is_supported_compression() to determine and parse out compressed module file extensions. On systems without zlib, this test fails and __kmod_path__parse() continues to strcmp "ko" with "gz". Don't do this on those systems. Signed-off-by: Kim Phillips Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Peter Zijlstra Fixes: 3c8a67f50a1e ("perf tools: Add kmod_path__parse function") Link: http://lkml.kernel.org/r/20170503131402.c66e314460026c80cd787b34@arm.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/tests/kmod-path.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c index 76f41f249944..6cd9e5107f77 100644 --- a/tools/perf/tests/kmod-path.c +++ b/tools/perf/tests/kmod-path.c @@ -61,6 +61,7 @@ int test__kmod_path__parse(int subtest __maybe_unused) M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_KERNEL, true); M("/xxxx/xxxx/x-x.ko", PERF_RECORD_MISC_USER, false); +#ifdef HAVE_ZLIB_SUPPORT /* path alloc_name alloc_ext kmod comp name ext */ T("/xxxx/xxxx/x.ko.gz", true , true , true, true, "[x]", "gz"); T("/xxxx/xxxx/x.ko.gz", false , true , true, true, NULL , "gz"); @@ -96,6 +97,7 @@ int test__kmod_path__parse(int subtest __maybe_unused) M("x.ko.gz", PERF_RECORD_MISC_CPUMODE_UNKNOWN, true); M("x.ko.gz", PERF_RECORD_MISC_KERNEL, true); M("x.ko.gz", PERF_RECORD_MISC_USER, false); +#endif /* path alloc_name alloc_ext kmod comp name ext */ T("[test_module]", true , true , true, false, "[test_module]", NULL); -- GitLab From 18dd7b964c01ac44497471f4ea3f4c0c663eab55 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 4 May 2017 15:05:26 +0200 Subject: [PATCH 0717/1834] block/mq: Cure cpu hotplug lock inversion [ Upstream commit eabe06595d62cfa9278e2cd012df614bc68a7042 ] By poking at /debug/sched_features I triggered the following splat: [] ====================================================== [] WARNING: possible circular locking dependency detected [] 4.11.0-00873-g964c8b7-dirty #694 Not tainted [] ------------------------------------------------------ [] bash/2109 is trying to acquire lock: [] (cpu_hotplug_lock.rw_sem){++++++}, at: [] static_key_slow_dec+0x1b/0x50 [] [] but task is already holding lock: [] (&sb->s_type->i_mutex_key#4){+++++.}, at: [] sched_feat_write+0x86/0x170 [] [] which lock already depends on the new lock. [] [] [] the existing dependency chain (in reverse order) is: [] [] -> #2 (&sb->s_type->i_mutex_key#4){+++++.}: [] lock_acquire+0x100/0x210 [] down_write+0x28/0x60 [] start_creating+0x5e/0xf0 [] debugfs_create_dir+0x13/0x110 [] blk_mq_debugfs_register+0x21/0x70 [] blk_mq_register_dev+0x64/0xd0 [] blk_register_queue+0x6a/0x170 [] device_add_disk+0x22d/0x440 [] loop_add+0x1f3/0x280 [] loop_init+0x104/0x142 [] do_one_initcall+0x43/0x180 [] kernel_init_freeable+0x1de/0x266 [] kernel_init+0xe/0x100 [] ret_from_fork+0x31/0x40 [] [] -> #1 (all_q_mutex){+.+.+.}: [] lock_acquire+0x100/0x210 [] __mutex_lock+0x6c/0x960 [] mutex_lock_nested+0x1b/0x20 [] blk_mq_init_allocated_queue+0x37c/0x4e0 [] blk_mq_init_queue+0x3a/0x60 [] loop_add+0xe5/0x280 [] loop_init+0x104/0x142 [] do_one_initcall+0x43/0x180 [] kernel_init_freeable+0x1de/0x266 [] kernel_init+0xe/0x100 [] ret_from_fork+0x31/0x40 [] *** DEADLOCK *** [] [] 3 locks held by bash/2109: [] #0: (sb_writers#11){.+.+.+}, at: [] vfs_write+0x17d/0x1a0 [] #1: (debugfs_srcu){......}, at: [] full_proxy_write+0x5d/0xd0 [] #2: (&sb->s_type->i_mutex_key#4){+++++.}, at: [] sched_feat_write+0x86/0x170 [] [] stack backtrace: [] CPU: 9 PID: 2109 Comm: bash Not tainted 4.11.0-00873-g964c8b7-dirty #694 [] Hardware name: Intel Corporation S2600GZ/S2600GZ, BIOS SE5C600.86B.02.02.0002.122320131210 12/23/2013 [] Call Trace: [] lock_acquire+0x100/0x210 [] get_online_cpus+0x2a/0x90 [] static_key_slow_dec+0x1b/0x50 [] static_key_disable+0x20/0x30 [] sched_feat_write+0x131/0x170 [] full_proxy_write+0x97/0xd0 [] __vfs_write+0x28/0x120 [] vfs_write+0xb5/0x1a0 [] SyS_write+0x49/0xa0 [] entry_SYSCALL_64_fastpath+0x23/0xc2 This is because of the cpu hotplug lock rework. Break the chain at #1 by reversing the lock acquisition order. This way i_mutex_key#4 no longer depends on cpu_hotplug_lock and things are good. Cc: Jens Axboe Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 10f8f94b7f20..c6572ffc1e87 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2014,15 +2014,15 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, blk_mq_init_cpu_queues(q, set->nr_hw_queues); - get_online_cpus(); mutex_lock(&all_q_mutex); + get_online_cpus(); list_add_tail(&q->all_q_node, &all_q_list); blk_mq_add_queue_tag_set(set, q); blk_mq_map_swqueue(q, cpu_online_mask); - mutex_unlock(&all_q_mutex); put_online_cpus(); + mutex_unlock(&all_q_mutex); return q; -- GitLab From f37dc00bace9e9deb2c3db35fc7bf815dbf0c913 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 6 Nov 2017 12:16:56 +0100 Subject: [PATCH 0718/1834] Bluetooth: hci_qca: Avoid setup failure on missing rampatch [ Upstream commit ba8f3597900291a93604643017fff66a14546015 ] Assuming that the original code idea was to enable in-band sleeping only if the setup_rome method returns succes and run in 'standard' mode otherwise, we should not return setup_rome return value which makes qca_setup fail if no rampatch/nvm file found. This fixes BT issue on the dragonboard-820C p4 which includes the following QCA controller: hci0: Product:0x00000008 hci0: Patch :0x00000111 hci0: ROM :0x00000302 hci0: SOC :0x00000044 Since there is no rampatch for this controller revision, just make it work as is. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_qca.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 6c867fbc56a7..74b2f4a14643 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -936,6 +936,9 @@ static int qca_setup(struct hci_uart *hu) if (!ret) { set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); qca_debugfs_init(hdev); + } else if (ret == -ENOENT) { + /* No patch/nvm-config found, run with original fw/config */ + ret = 0; } /* Setup bdaddr */ -- GitLab From dadb6c1a8d889b5cab5ff6ed44db9cdb445467e7 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 22 Nov 2017 15:03:17 +0100 Subject: [PATCH 0719/1834] Bluetooth: btqcomsmd: Fix skb double free corruption [ Upstream commit 67b8fbead4685b36d290a0ef91c6ddffc4920ec9 ] In case of hci send frame failure, skb is still owned by the caller (hci_core) and then should not be freed. This fixes crash on dragonboard-410c when sending SCO packet. skb is freed by both btqcomsmd and hci_core. Fixes: 1511cc750c3d ("Bluetooth: Introduce Qualcomm WCNSS SMD based HCI driver") Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btqcomsmd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/btqcomsmd.c b/drivers/bluetooth/btqcomsmd.c index 08c2c93887c1..3aac78a5091b 100644 --- a/drivers/bluetooth/btqcomsmd.c +++ b/drivers/bluetooth/btqcomsmd.c @@ -85,7 +85,8 @@ static int btqcomsmd_send(struct hci_dev *hdev, struct sk_buff *skb) break; } - kfree_skb(skb); + if (!ret) + kfree_skb(skb); return ret; } -- GitLab From bac8b847be924575031d0486b2c53ccad7c910b8 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Mon, 20 Nov 2017 09:00:55 -0500 Subject: [PATCH 0720/1834] media: c8sectpfe: fix potential NULL pointer dereference in c8sectpfe_timer_interrupt [ Upstream commit baed3c4bc4c13de93e0dba0a26d601411ebcb389 ] _channel_ is being dereferenced before it is null checked, hence there is a potential null pointer dereference. Fix this by moving the pointer dereference after _channel_ has been null checked. This issue was detected with the help of Coccinelle. Fixes: c5f5d0f99794 ("[media] c8sectpfe: STiH407/10 Linux DVB demux support") Signed-off-by: Gustavo A. R. Silva Acked-by: Patrice Chotard Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 30c148b9d65e..06e2cfd09855 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -83,7 +83,7 @@ static void c8sectpfe_timer_interrupt(unsigned long ac8sectpfei) static void channel_swdemux_tsklet(unsigned long data) { struct channel_info *channel = (struct channel_info *)data; - struct c8sectpfei *fei = channel->fei; + struct c8sectpfei *fei; unsigned long wp, rp; int pos, num_packets, n, size; u8 *buf; @@ -91,6 +91,8 @@ static void channel_swdemux_tsklet(unsigned long data) if (unlikely(!channel || !channel->irec)) return; + fei = channel->fei; + wp = readl(channel->irec + DMA_PRDS_BUSWP_TP(0)); rp = readl(channel->irec + DMA_PRDS_BUSRP_TP(0)); -- GitLab From af302f2d047a4dccb501bfd7c74b7537e35ea4bf Mon Sep 17 00:00:00 2001 From: Prakash Kamliya Date: Mon, 4 Dec 2017 19:10:15 +0530 Subject: [PATCH 0721/1834] drm/msm: fix leak in failed get_pages [ Upstream commit 62e3a3e342af3c313ab38603811ecdb1fcc79edb ] get_pages doesn't keep a reference of the pages allocated when it fails later in the code path. This can lead to a memory leak. Keep reference of the allocated pages so that it can be freed when msm_gem_free_object gets called later during cleanup. Signed-off-by: Prakash Kamliya Signed-off-by: Sharat Masetty Signed-off-by: Rob Clark Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/msm/msm_gem.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index b6ac27e31929..797d1f8340b9 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -91,14 +91,17 @@ static struct page **get_pages(struct drm_gem_object *obj) return p; } + msm_obj->pages = p; + msm_obj->sgt = drm_prime_pages_to_sg(p, npages); if (IS_ERR(msm_obj->sgt)) { + void *ptr = ERR_CAST(msm_obj->sgt); + dev_err(dev->dev, "failed to allocate sgt\n"); - return ERR_CAST(msm_obj->sgt); + msm_obj->sgt = NULL; + return ptr; } - msm_obj->pages = p; - /* For non-cached buffers, ensure the new pages are clean * because display controller, GPU, etc. are not coherent: */ @@ -121,7 +124,10 @@ static void put_pages(struct drm_gem_object *obj) if (msm_obj->flags & (MSM_BO_WC|MSM_BO_UNCACHED)) dma_unmap_sg(obj->dev->dev, msm_obj->sgt->sgl, msm_obj->sgt->nents, DMA_BIDIRECTIONAL); - sg_free_table(msm_obj->sgt); + + if (msm_obj->sgt) + sg_free_table(msm_obj->sgt); + kfree(msm_obj->sgt); if (use_pages(obj)) -- GitLab From 7c06c3dd3af35953963cb54b4cbecc327fc81b2e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 29 Nov 2017 09:47:33 +0100 Subject: [PATCH 0722/1834] RDMA/iwpm: Fix uninitialized error code in iwpm_send_mapinfo() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 302d6424e4a293a5761997e6c9fc3dfb1e4c355f ] With gcc-4.1.2: drivers/infiniband/core/iwpm_util.c: In function ‘iwpm_send_mapinfo’: drivers/infiniband/core/iwpm_util.c:647: warning: ‘ret’ may be used uninitialized in this function Indeed, if nl_client is not found in any of the scanned has buckets, ret will be used uninitialized. Preinitialize ret to -EINVAL to fix this. Fixes: 30dc5e63d6a5ad24 ("RDMA/core: Add support for iWARP Port Mapper user space service") Signed-off-by: Geert Uytterhoeven Reviewed-by: Tatyana Nikolova Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/iwpm_util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index ade71e7f0131..2fe4c2c921de 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -664,6 +664,7 @@ int iwpm_send_mapinfo(u8 nl_client, int iwpm_pid) } skb_num++; spin_lock_irqsave(&iwpm_mapinfo_lock, flags); + ret = -EINVAL; for (i = 0; i < IWPM_MAPINFO_HASH_SIZE; i++) { hlist_for_each_entry(map_info, &iwpm_hash_bucket[i], hlist_node) { -- GitLab From 1f13ef920ad0ceccf22ba1d309f84d55608ef4eb Mon Sep 17 00:00:00 2001 From: Tsang-Shian Lin Date: Sat, 9 Dec 2017 11:37:10 -0600 Subject: [PATCH 0723/1834] rtlwifi: rtl_pci: Fix the bug when inactiveps is enabled. [ Upstream commit b7573a0a27bfa8270dea9b145448f6884b7cacc1 ] Reset the driver current tx read/write index to zero when inactiveps nic out of sync with HW state. Wrong driver tx read/write index will cause Tx fail. Signed-off-by: Tsang-Shian Lin Signed-off-by: Ping-Ke Shih Signed-off-by: Larry Finger Cc: Yan-Hsuan Chuang Cc: Birming Chiu Cc: Shaofu Cc: Steven Ting Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtlwifi/pci.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 75ffeaa54ed8..e15b462d096b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -1572,7 +1572,14 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) dev_kfree_skb_irq(skb); ring->idx = (ring->idx + 1) % ring->entries; } + + if (rtlpriv->use_new_trx_flow) { + rtlpci->tx_ring[i].cur_tx_rp = 0; + rtlpci->tx_ring[i].cur_tx_wp = 0; + } + ring->idx = 0; + ring->entries = rtlpci->txringcount[i]; } } spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); -- GitLab From a20f36c59b459881d6ecf30eb6b34c461e81d5b5 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Thu, 21 Sep 2017 19:23:56 -0400 Subject: [PATCH 0724/1834] media: bt8xx: Fix err 'bt878_probe()' [ Upstream commit 45392ff6881dbe56d41ef0b17c2e576065f8ffa1 ] This is odd to call 'pci_disable_device()' in an error path before a coresponding successful 'pci_enable_device()'. Return directly instead. Fixes: 77e0be12100a ("V4L/DVB (4176): Bug-fix: Fix memory overflow") Signed-off-by: Christophe JAILLET Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/pci/bt8xx/bt878.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c index 8aa726651630..90fcccc05b56 100644 --- a/drivers/media/pci/bt8xx/bt878.c +++ b/drivers/media/pci/bt8xx/bt878.c @@ -422,8 +422,7 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) bt878_num); if (bt878_num >= BT878_MAX) { printk(KERN_ERR "bt878: Too many devices inserted\n"); - result = -ENOMEM; - goto fail0; + return -ENOMEM; } if (pci_enable_device(dev)) return -EIO; -- GitLab From bb32772bc409f3cb0a40c318a5dda37f177107c3 Mon Sep 17 00:00:00 2001 From: Balaji Pothunoori Date: Thu, 7 Dec 2017 16:58:04 +0200 Subject: [PATCH 0725/1834] ath10k: handling qos at STA side based on AP WMM enable/disable [ Upstream commit 07ffb4497360ae8789f05555fec8171ee952304d ] Data packets are not sent by STA in case of STA joined to non QOS AP (WMM disabled AP). This is happening because of STA is sending data packets to firmware from host with qos enabled along with non qos queue value(TID = 16). Due to qos enabled, firmware is discarding the packet. This patch fixes this issue by updating the qos based on station WME capability field if WMM is disabled in AP. This patch is required by 10.4 family chipsets like QCA4019/QCA9888/QCA9884/QCA99X0. Firmware Versoin : 10.4-3.5.1-00018. For 10.2.4 family chipsets QCA988X/QCA9887 and QCA6174 this patch has no effect. Signed-off-by: Balaji Pothunoori Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1e6e63dbd61c..a497bf31953d 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2505,7 +2505,7 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar, } break; case WMI_VDEV_TYPE_STA: - if (vif->bss_conf.qos) + if (sta->wme) arg->peer_flags |= arvif->ar->wmi.peer_flags->qos; break; case WMI_VDEV_TYPE_IBSS: -- GitLab From 034371788a56304c2836eb58706b9e2f04387359 Mon Sep 17 00:00:00 2001 From: Ron Economos Date: Mon, 11 Dec 2017 19:51:53 -0500 Subject: [PATCH 0726/1834] media: [RESEND] media: dvb-frontends: Add delay to Si2168 restart [ Upstream commit 380a6c86457573aa42d27ae11e025eb25941a0b7 ] On faster CPUs a delay is required after the resume command and the restart command. Without the delay, the restart command often returns -EREMOTEIO and the Si2168 does not restart. Note that this patch fixes the same issue as https://patchwork.linuxtv.org/patch/44304/, but I believe my udelay() fix addresses the actual problem. Signed-off-by: Ron Economos Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/dvb-frontends/si2168.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 20b4a659e2e4..0fe69f79a24d 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -14,6 +14,8 @@ * GNU General Public License for more details. */ +#include + #include "si2168_priv.h" static const struct dvb_frontend_ops si2168_ops; @@ -378,6 +380,7 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; + udelay(100); memcpy(cmd.args, "\x85", 1); cmd.wlen = 1; cmd.rlen = 1; -- GitLab From 8ee96dfd01bcab79e50a596c9d5142e0bf05c787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rn=20Mork?= Date: Thu, 14 Dec 2017 19:55:50 +0100 Subject: [PATCH 0727/1834] qmi_wwan: set FLAG_SEND_ZLP to avoid network initiated disconnect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 245d21190aec547c0de64f70c0e6de871c185a24 ] It has been reported that the dummy byte we add to avoid ZLPs can be forwarded by the modem to the PGW/GGSN, and that some operators will drop the connection if this happens. In theory, QMI devices are based on CDC ECM and should as such both support ZLPs and silently ignore the dummy byte. The latter assumption failed. Let's test out the first. Signed-off-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/qmi_wwan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index a30d6a6dbd95..973e90fb4a24 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -531,7 +531,7 @@ static int qmi_wwan_resume(struct usb_interface *intf) static const struct driver_info qmi_wwan_info = { .description = "WWAN/QMI device", - .flags = FLAG_WWAN, + .flags = FLAG_WWAN | FLAG_SEND_ZLP, .bind = qmi_wwan_bind, .unbind = qmi_wwan_unbind, .manage_power = qmi_wwan_manage_power, @@ -540,7 +540,7 @@ static const struct driver_info qmi_wwan_info = { static const struct driver_info qmi_wwan_info_quirk_dtr = { .description = "WWAN/QMI device", - .flags = FLAG_WWAN, + .flags = FLAG_WWAN | FLAG_SEND_ZLP, .bind = qmi_wwan_bind, .unbind = qmi_wwan_unbind, .manage_power = qmi_wwan_manage_power, -- GitLab From a50521b04da98f22d1223b8396144d48427ff2fb Mon Sep 17 00:00:00 2001 From: Stefan Potyra Date: Wed, 6 Dec 2017 16:46:12 +0100 Subject: [PATCH 0728/1834] serial: 8250_dw: Disable clock on error [ Upstream commit 8af016aa5a27c6a2505460eb4d83f1e70c38dc43 ] If there is no clock rate for uartclk defined, disable the previously enabled clock again. Found by Linux Driver Verification project (linuxtesting.org). Fixes: 23f5b3fdd04e serial: 8250_dw: only get the clock rate in one place Signed-off-by: Stefan Potyra Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 459d726f9d59..3eb01a719d22 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -464,7 +464,8 @@ static int dw8250_probe(struct platform_device *pdev) /* If no clock rate is defined, fail. */ if (!p->uartclk) { dev_err(dev, "clock rate not defined\n"); - return -EINVAL; + err = -EINVAL; + goto err_clk; } data->pclk = devm_clk_get(dev, "apb_pclk"); -- GitLab From 32dc29cf72e866fafca3a12ea821954632a0edca Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 4 Dec 2017 15:49:48 +0100 Subject: [PATCH 0729/1834] cros_ec: fix nul-termination for firmware build info [ Upstream commit 50a0d71a5d20e1d3eff1d974fdc8559ad6d74892 ] As gcc-8 reports, we zero out the wrong byte: drivers/platform/chrome/cros_ec_sysfs.c: In function 'show_ec_version': drivers/platform/chrome/cros_ec_sysfs.c:190:12: error: array subscript 4294967295 is above array bounds of 'uint8_t[]' [-Werror=array-bounds] This changes the code back to what it did before changing to a zero-length array structure. Fixes: a841178445bb ("mfd: cros_ec: Use a zero-length array for command data") Signed-off-by: Arnd Bergmann Signed-off-by: Benson Leung Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index f3baf9973989..24f1630a8b3f 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c @@ -187,7 +187,7 @@ static ssize_t show_ec_version(struct device *dev, count += scnprintf(buf + count, PAGE_SIZE - count, "Build info: EC error %d\n", msg->result); else { - msg->data[sizeof(msg->data) - 1] = '\0'; + msg->data[EC_HOST_PARAM_SIZE - 1] = '\0'; count += scnprintf(buf + count, PAGE_SIZE - count, "Build info: %s\n", msg->data); } -- GitLab From 6ad31f858328e0c4257c3b0367271d7e99d16af2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 25 Sep 2017 09:17:01 -0700 Subject: [PATCH 0730/1834] watchdog: Fix potential kref imbalance when opening watchdog [ Upstream commit 4bcd615fad6adddc68b058d498b30a9e0e0db77a ] If a watchdog driver's open function sets WDOG_HW_RUNNING with the expectation that the watchdog can not be stopped, but then stops the watchdog anyway in its stop function, kref_get() wil not be called in watchdog_open(). If the watchdog then stops on close, WDOG_HW_RUNNING will be cleared and kref_put() will be called, causing a kref imbalance. As result the character device data structure will be released, which in turn will cause the system to crash on the next call to watchdog_open(). Fixes: ee142889e32f5 ("watchdog: Introduce WDOG_HW_RUNNING flag") Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/watchdog_dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 32930a073a12..977fe74e5abe 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -760,6 +760,7 @@ static int watchdog_open(struct inode *inode, struct file *file) { struct watchdog_core_data *wd_data; struct watchdog_device *wdd; + bool hw_running; int err; /* Get the corresponding watchdog device */ @@ -779,7 +780,8 @@ static int watchdog_open(struct inode *inode, struct file *file) * If the /dev/watchdog device is open, we don't want the module * to be unloaded. */ - if (!watchdog_hw_running(wdd) && !try_module_get(wdd->ops->owner)) { + hw_running = watchdog_hw_running(wdd); + if (!hw_running && !try_module_get(wdd->ops->owner)) { err = -EBUSY; goto out_clear; } @@ -790,7 +792,7 @@ static int watchdog_open(struct inode *inode, struct file *file) file->private_data = wd_data; - if (!watchdog_hw_running(wdd)) + if (!hw_running) kref_get(&wd_data->kref); /* dev/watchdog is a virtual (and thus non-seekable) filesystem */ -- GitLab From 236738a6df2c87a8e3d5553ba93b7465cd9a0f4c Mon Sep 17 00:00:00 2001 From: Shawn Nematbakhsh Date: Fri, 8 Sep 2017 13:50:11 -0700 Subject: [PATCH 0731/1834] platform/chrome: Use proper protocol transfer function [ Upstream commit d48b8c58c57f6edbe2965f0a5f62c5cf9593ca96 ] pkt_xfer should be used for protocol v3, and cmd_xfer otherwise. We had one instance of these functions correct, but not the second, fall-back case. We use the fall-back only when the first command returns an IN_PROGRESS status, which is only used on some EC firmwares where we don't want to constantly poll the bus, but instead back off and sleep/retry for a little while. Fixes: 2c7589af3c4d ("mfd: cros_ec: add proto v3 skeleton") Signed-off-by: Shawn Nematbakhsh Signed-off-by: Brian Norris Reviewed-by: Javier Martinez Canillas Signed-off-by: Benson Leung Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/platform/chrome/cros_ec_proto.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/platform/chrome/cros_ec_proto.c b/drivers/platform/chrome/cros_ec_proto.c index 04053fe1e980..cfa3e850c49f 100644 --- a/drivers/platform/chrome/cros_ec_proto.c +++ b/drivers/platform/chrome/cros_ec_proto.c @@ -60,12 +60,14 @@ static int send_command(struct cros_ec_device *ec_dev, struct cros_ec_command *msg) { int ret; + int (*xfer_fxn)(struct cros_ec_device *ec, struct cros_ec_command *msg); if (ec_dev->proto_version > 2) - ret = ec_dev->pkt_xfer(ec_dev, msg); + xfer_fxn = ec_dev->pkt_xfer; else - ret = ec_dev->cmd_xfer(ec_dev, msg); + xfer_fxn = ec_dev->cmd_xfer; + ret = (*xfer_fxn)(ec_dev, msg); if (msg->result == EC_RES_IN_PROGRESS) { int i; struct cros_ec_command *status_msg; @@ -88,7 +90,7 @@ static int send_command(struct cros_ec_device *ec_dev, for (i = 0; i < EC_COMMAND_RETRIES; i++) { usleep_range(10000, 11000); - ret = ec_dev->cmd_xfer(ec_dev, status_msg); + ret = (*xfer_fxn)(ec_dev, status_msg); if (ret < 0) break; -- GitLab From 2d443c9ee9f71fb37f5dac530b868b1ea27d202e Mon Sep 17 00:00:00 2001 From: Kedareswara rao Appana Date: Thu, 7 Dec 2017 10:54:28 +0530 Subject: [PATCH 0732/1834] dmaengine: zynqmp_dma: Fix race condition in the probe [ Upstream commit 5ba080aada5e739165e0f38d5cc3b04c82b323c8 ] Incase of interrupt property is not present, Driver is trying to free an invalid irq, This patch fixes it by adding a check before freeing the irq. Signed-off-by: Kedareswara rao Appana Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/dma/xilinx/zynqmp_dma.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/dma/xilinx/zynqmp_dma.c b/drivers/dma/xilinx/zynqmp_dma.c index 6d221e5c72ee..22658057fe27 100644 --- a/drivers/dma/xilinx/zynqmp_dma.c +++ b/drivers/dma/xilinx/zynqmp_dma.c @@ -933,7 +933,8 @@ static void zynqmp_dma_chan_remove(struct zynqmp_dma_chan *chan) if (!chan) return; - devm_free_irq(chan->zdev->dev, chan->irq, chan); + if (chan->irq) + devm_free_irq(chan->zdev->dev, chan->irq, chan); tasklet_kill(&chan->tasklet); list_del(&chan->common.device_node); clk_disable_unprepare(chan->clk_apb); -- GitLab From e7425b35a374cc25c18654c76ff7a88835e11380 Mon Sep 17 00:00:00 2001 From: Logan Gunthorpe Date: Tue, 5 Dec 2017 16:30:51 -0700 Subject: [PATCH 0733/1834] drm/tilcdc: ensure nonatomic iowrite64 is not used [ Upstream commit 4e5ca2d930aa8714400aedf4bf1dc959cb04280f ] Add a check to ensure iowrite64 is only used if it is atomic. It was decided in [1] that the tilcdc driver should not be using an atomic operation (so it was left out of this patchset). However, it turns out that through the drm code, a nonatomic header is actually included: include/linux/io-64-nonatomic-lo-hi.h is included from include/drm/drm_os_linux.h:9:0, from include/drm/drmP.h:74, from include/drm/drm_modeset_helper.h:26, from include/drm/drm_atomic_helper.h:33, from drivers/gpu/drm/tilcdc/tilcdc_crtc.c:19: And thus, without this change, this patchset would inadvertantly change the behaviour of the tilcdc driver. [1] lkml.kernel.org/r/CAK8P3a2HhO_zCnsTzq7hmWSz5La5Thu19FWZpun16iMnyyNreQ@mail.gmail.com Signed-off-by: Logan Gunthorpe Reviewed-by: Andy Shevchenko Cc: Jyri Sarha Cc: Arnd Bergmann Cc: Tomi Valkeinen Cc: David Airlie Signed-off-by: Jyri Sarha Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/tilcdc/tilcdc_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_regs.h b/drivers/gpu/drm/tilcdc/tilcdc_regs.h index f57c0d62c76a..19d8dc3cdd40 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_regs.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_regs.h @@ -124,7 +124,7 @@ static inline void tilcdc_write64(struct drm_device *dev, u32 reg, u64 data) struct tilcdc_drm_private *priv = dev->dev_private; volatile void __iomem *addr = priv->mmio + reg; -#ifdef iowrite64 +#if defined(iowrite64) && !defined(iowrite64_is_nonatomic) iowrite64(data, addr); #else __iowmb(); -- GitLab From 963f3129a189213876200d46e5698638d44c5e11 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 12 Dec 2017 10:49:02 +0000 Subject: [PATCH 0734/1834] mmc: avoid removing non-removable hosts during suspend [ Upstream commit de8dcc3d2c0e08e5068ee1e26fc46415c15e3637 ] The Weibu F3C MiniPC has an onboard AP6255 module, presenting two SDIO functions on a single MMC host (Bluetooth/btsdio and WiFi/brcmfmac), and the mmc layer correctly detects this as non-removable. After suspend/resume, the wifi and bluetooth interfaces disappear and do not get probed again. The conditions here are: 1. During suspend, we reach mmc_pm_notify() 2. mmc_pm_notify() calls mmc_sdio_pre_suspend() to see if we can suspend the SDIO host. However, mmc_sdio_pre_suspend() returns -ENOSYS because btsdio_driver does not have a suspend method. 3. mmc_pm_notify() proceeds to remove the card 4. Upon resume, mmc_rescan() does nothing with this host, because of the rescan_entered check which aims to only scan a non-removable device a single time (i.e. during boot). Fix the loss of functionality by detecting that we are unable to suspend a non-removable host, so avoid the forced removal in that case. The comment above this function already indicates that this code was only intended for removable devices. Signed-off-by: Daniel Drake Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/core/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 2553d903a82b..cff5829790c9 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2974,6 +2974,14 @@ static int mmc_pm_notify(struct notifier_block *notify_block, if (!err) break; + if (!mmc_card_is_removable(host)) { + dev_warn(mmc_dev(host), + "pre_suspend failed for non-removable host: " + "%d\n", err); + /* Avoid removing non-removable hosts */ + break; + } + /* Calling bus_ops->remove() with a claimed host can deadlock */ host->bus_ops->remove(host); mmc_claim_host(host); -- GitLab From 15e113da626f0c91cb003c597c1be57eac5fd576 Mon Sep 17 00:00:00 2001 From: Erez Shitrit Date: Tue, 14 Nov 2017 14:51:53 +0200 Subject: [PATCH 0735/1834] IB/ipoib: Avoid memory leak if the SA returns a different DGID [ Upstream commit 439000892ee17a9c92f1e4297818790ef8bb4ced ] The ipoib path database is organized around DGIDs from the LLADDR, but the SA is free to return a different GID when asked for path. This causes a bug because the SA's modified DGID is copied into the database key, even though it is no longer the correct lookup key, causing a memory leak and other malfunctions. Ensure the database key does not change after the SA query completes. Demonstration of the bug is as follows ipoib wants to send to GID fe80:0000:0000:0000:0002:c903:00ef:5ee2, it creates new record in the DB with that gid as a key, and issues a new request to the SM. Now, the SM from some reason returns path-record with other SGID (for example, 2001:0000:0000:0000:0002:c903:00ef:5ee2 that contains the local subnet prefix) now ipoib will overwrite the current entry with the new one, and if new request to the original GID arrives ipoib will not find it in the DB (was overwritten) and will create new record that in its turn will also be overwritten by the response from the SM, and so on till the driver eats all the device memory. Signed-off-by: Erez Shitrit Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e37e918cb935..0df7d4504c06 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -799,6 +799,22 @@ static void path_rec_completion(int status, spin_lock_irqsave(&priv->lock, flags); if (!IS_ERR_OR_NULL(ah)) { + /* + * pathrec.dgid is used as the database key from the LLADDR, + * it must remain unchanged even if the SA returns a different + * GID to use in the AH. + */ + if (memcmp(pathrec->dgid.raw, path->pathrec.dgid.raw, + sizeof(union ib_gid))) { + ipoib_dbg( + priv, + "%s got PathRec for gid %pI6 while asked for %pI6\n", + dev->name, pathrec->dgid.raw, + path->pathrec.dgid.raw); + memcpy(pathrec->dgid.raw, path->pathrec.dgid.raw, + sizeof(union ib_gid)); + } + path->pathrec = *pathrec; old_ah = path->ah; -- GitLab From 211a1e9f5efc7eafbe24ddb5601c71e5325db435 Mon Sep 17 00:00:00 2001 From: Parav Pandit Date: Tue, 14 Nov 2017 14:51:55 +0200 Subject: [PATCH 0736/1834] RDMA/cma: Use correct size when writing netlink stats [ Upstream commit 7baaa49af3716fb31877c61f59b74d029ce15b75 ] The code was using the src size when formatting the dst. They are almost certainly the same value but it reads wrong. Fixes: ce117ffac2e9 ("RDMA/cma: Export AF_IB statistics") Signed-off-by: Parav Pandit Reviewed-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 30f01613b518..de3d08c24715 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -4336,7 +4336,7 @@ static int cma_get_id_stats(struct sk_buff *skb, struct netlink_callback *cb) RDMA_NL_RDMA_CM_ATTR_SRC_ADDR)) goto out; if (ibnl_put_attr(skb, nlh, - rdma_addr_size(cma_src_addr(id_priv)), + rdma_addr_size(cma_dst_addr(id_priv)), cma_dst_addr(id_priv), RDMA_NL_RDMA_CM_ATTR_DST_ADDR)) goto out; -- GitLab From 37c704e0ec7f33599866d41921379ffa8d8a7a9e Mon Sep 17 00:00:00 2001 From: Artemy Kovalyov Date: Tue, 14 Nov 2017 14:51:59 +0200 Subject: [PATCH 0737/1834] IB/umem: Fix use of npages/nmap fields [ Upstream commit edf1a84fe37c51290e2c88154ecaf48dadff3d27 ] In ib_umem structure npages holds original number of sg entries, while nmap is number of DMA blocks returned by dma_map_sg. Fixes: c5d76f130b28 ('IB/core: Add umem function to read data from user-space') Signed-off-by: Artemy Kovalyov Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/umem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 8e973a2993a6..e74aa1d60fdb 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -357,7 +357,7 @@ int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offset, return -EINVAL; } - ret = sg_pcopy_to_buffer(umem->sg_head.sgl, umem->nmap, dst, length, + ret = sg_pcopy_to_buffer(umem->sg_head.sgl, umem->npages, dst, length, offset + ib_umem_offset(umem)); if (ret < 0) -- GitLab From eba1940e654b8218c08ac575edb24865c1dc32c0 Mon Sep 17 00:00:00 2001 From: Bharat Potnuri Date: Tue, 28 Nov 2017 23:58:07 +0530 Subject: [PATCH 0738/1834] iser-target: avoid reinitializing rdma contexts for isert commands [ Upstream commit 66f53e6f5400578bae58db0c06d85a8820831f40 ] isert commands that failed during isert_rdma_rw_ctx_post() are queued to Queue-Full(QF) queue and are scheduled to be reposted during queue-full queue processing. During this reposting, the rdma contexts are initialised again in isert_rdma_rw_ctx_post(), which is leaking significant memory. unreferenced object 0xffff8830201d9640 (size 64): comm "kworker/0:2", pid 195, jiffies 4295374851 (age 4528.436s) hex dump (first 32 bytes): 00 60 8b cb 2e 00 00 00 00 10 00 00 00 00 00 00 .`.............. 00 90 e3 cb 2e 00 00 00 00 10 00 00 00 00 00 00 ................ backtrace: [] kmemleak_alloc+0x4e/0xb0 [] __kmalloc+0x125/0x2b0 [] rdma_rw_ctx_init+0x15f/0x6f0 [ib_core] [] isert_rdma_rw_ctx_post+0xc4/0x3c0 [ib_isert] [] isert_put_datain+0x112/0x1c0 [ib_isert] [] lio_queue_data_in+0x2e/0x30 [iscsi_target_mod] [] target_qf_do_work+0x2b2/0x4b0 [target_core_mod] [] process_one_work+0x1db/0x5d0 [] worker_thread+0x4d/0x3e0 [] kthread+0x117/0x150 [] ret_from_fork+0x27/0x40 [] 0xffffffffffffffff Here is patch to use the older rdma contexts while reposting the isert commands intead of reinitialising them. Signed-off-by: Potnuri Bharat Teja Reviewed-by: Sagi Grimberg Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/isert/ib_isert.c | 7 +++++++ drivers/infiniband/ulp/isert/ib_isert.h | 1 + 2 files changed, 8 insertions(+) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 0983470929bd..b879d21b7548 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -2098,6 +2098,9 @@ isert_rdma_rw_ctx_post(struct isert_cmd *cmd, struct isert_conn *conn, u32 rkey, offset; int ret; + if (cmd->ctx_init_done) + goto rdma_ctx_post; + if (dir == DMA_FROM_DEVICE) { addr = cmd->write_va; rkey = cmd->write_stag; @@ -2125,11 +2128,15 @@ isert_rdma_rw_ctx_post(struct isert_cmd *cmd, struct isert_conn *conn, se_cmd->t_data_sg, se_cmd->t_data_nents, offset, addr, rkey, dir); } + if (ret < 0) { isert_err("Cmd: %p failed to prepare RDMA res\n", cmd); return ret; } + cmd->ctx_init_done = true; + +rdma_ctx_post: ret = rdma_rw_ctx_post(&cmd->rw, conn->qp, port_num, cqe, chain_wr); if (ret < 0) isert_err("Cmd: %p failed to post RDMA res\n", cmd); diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index c02ada57d7f5..85bd19753d55 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h @@ -124,6 +124,7 @@ struct isert_cmd { struct rdma_rw_ctx rw; struct work_struct comp_work; struct scatterlist sg; + bool ctx_init_done; }; static inline struct isert_cmd *tx_desc_to_cmd(struct iser_tx_desc *desc) -- GitLab From 87408eb1eae7c59e81e6e3efeadde168d3b3f130 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 1 Dec 2017 11:06:39 -0600 Subject: [PATCH 0739/1834] vgacon: Set VGA struct resource types [ Upstream commit c82084117f79bcae085e40da526253736a247120 ] Set the resource type when we reserve VGA-related I/O port resources. The resource code doesn't actually look at the type, so it inserts resources without a type in the tree correctly even without this change. But if we ever print a resource without a type, it looks like this: vga+ [??? 0x000003c0-0x000003df flags 0x0] Setting the type means it will be printed correctly as: vga+ [io 0x000003c0-0x000003df] Signed-off-by: Bjorn Helgaas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/alpha/kernel/console.c | 1 + drivers/video/console/vgacon.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/arch/alpha/kernel/console.c b/arch/alpha/kernel/console.c index 6a61deed4a85..ab228ed45945 100644 --- a/arch/alpha/kernel/console.c +++ b/arch/alpha/kernel/console.c @@ -20,6 +20,7 @@ struct pci_controller *pci_vga_hose; static struct resource alpha_vga = { .name = "alpha-vga+", + .flags = IORESOURCE_IO, .start = 0x3C0, .end = 0x3DF }; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 11576611a974..dda1c4b3a229 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -405,7 +405,10 @@ static const char *vgacon_startup(void) vga_video_port_val = VGA_CRT_DM; if ((screen_info.orig_video_ega_bx & 0xff) != 0x10) { static struct resource ega_console_resource = - { .name = "ega", .start = 0x3B0, .end = 0x3BF }; + { .name = "ega", + .flags = IORESOURCE_IO, + .start = 0x3B0, + .end = 0x3BF }; vga_video_type = VIDEO_TYPE_EGAM; vga_vram_size = 0x8000; display_desc = "EGA+"; @@ -413,9 +416,15 @@ static const char *vgacon_startup(void) &ega_console_resource); } else { static struct resource mda1_console_resource = - { .name = "mda", .start = 0x3B0, .end = 0x3BB }; + { .name = "mda", + .flags = IORESOURCE_IO, + .start = 0x3B0, + .end = 0x3BB }; static struct resource mda2_console_resource = - { .name = "mda", .start = 0x3BF, .end = 0x3BF }; + { .name = "mda", + .flags = IORESOURCE_IO, + .start = 0x3BF, + .end = 0x3BF }; vga_video_type = VIDEO_TYPE_MDA; vga_vram_size = 0x2000; display_desc = "*MDA"; @@ -437,15 +446,21 @@ static const char *vgacon_startup(void) vga_vram_size = 0x8000; if (!screen_info.orig_video_isVGA) { - static struct resource ega_console_resource - = { .name = "ega", .start = 0x3C0, .end = 0x3DF }; + static struct resource ega_console_resource = + { .name = "ega", + .flags = IORESOURCE_IO, + .start = 0x3C0, + .end = 0x3DF }; vga_video_type = VIDEO_TYPE_EGAC; display_desc = "EGA"; request_resource(&ioport_resource, &ega_console_resource); } else { - static struct resource vga_console_resource - = { .name = "vga+", .start = 0x3C0, .end = 0x3DF }; + static struct resource vga_console_resource = + { .name = "vga+", + .flags = IORESOURCE_IO, + .start = 0x3C0, + .end = 0x3DF }; vga_video_type = VIDEO_TYPE_VGAC; display_desc = "VGA+"; request_resource(&ioport_resource, @@ -489,7 +504,10 @@ static const char *vgacon_startup(void) } } else { static struct resource cga_console_resource = - { .name = "cga", .start = 0x3D4, .end = 0x3D5 }; + { .name = "cga", + .flags = IORESOURCE_IO, + .start = 0x3D4, + .end = 0x3D5 }; vga_video_type = VIDEO_TYPE_CGA; vga_vram_size = 0x2000; display_desc = "*CGA"; -- GitLab From 4ae338d139874259807f686738b02cb25a863535 Mon Sep 17 00:00:00 2001 From: "H. Nikolaus Schaller" Date: Tue, 28 Nov 2017 16:48:54 +0100 Subject: [PATCH 0740/1834] omapdrm: panel: fix compatible vendor string for td028ttec1 [ Upstream commit c1b9d4c75cd549e08bd0596d7f9dcc20f7f6e8fa ] The vendor name was "toppoly" but other panels and the vendor list have defined it as "tpo". So let's fix it in driver and bindings. We keep the old definition in parallel to stay compatible with potential older DTB setup. Signed-off-by: H. Nikolaus Schaller Signed-off-by: Tomi Valkeinen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../panel/{toppoly,td028ttec1.txt => tpo,td028ttec1.txt} | 4 ++-- drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c | 3 +++ .../video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) rename Documentation/devicetree/bindings/display/panel/{toppoly,td028ttec1.txt => tpo,td028ttec1.txt} (84%) diff --git a/Documentation/devicetree/bindings/display/panel/toppoly,td028ttec1.txt b/Documentation/devicetree/bindings/display/panel/tpo,td028ttec1.txt similarity index 84% rename from Documentation/devicetree/bindings/display/panel/toppoly,td028ttec1.txt rename to Documentation/devicetree/bindings/display/panel/tpo,td028ttec1.txt index 7175dc3740ac..ed34253d9fb1 100644 --- a/Documentation/devicetree/bindings/display/panel/toppoly,td028ttec1.txt +++ b/Documentation/devicetree/bindings/display/panel/tpo,td028ttec1.txt @@ -2,7 +2,7 @@ Toppoly TD028TTEC1 Panel ======================== Required properties: -- compatible: "toppoly,td028ttec1" +- compatible: "tpo,td028ttec1" Optional properties: - label: a symbolic name for the panel @@ -14,7 +14,7 @@ Example ------- lcd-panel: td028ttec1@0 { - compatible = "toppoly,td028ttec1"; + compatible = "tpo,td028ttec1"; reg = <0>; spi-max-frequency = <100000>; spi-cpol; diff --git a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c index e859b3f893f7..6112c32b994f 100644 --- a/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c +++ b/drivers/gpu/drm/omapdrm/displays/panel-tpo-td028ttec1.c @@ -456,6 +456,8 @@ static int td028ttec1_panel_remove(struct spi_device *spi) } static const struct of_device_id td028ttec1_of_match[] = { + { .compatible = "omapdss,tpo,td028ttec1", }, + /* keep to not break older DTB */ { .compatible = "omapdss,toppoly,td028ttec1", }, {}, }; @@ -475,6 +477,7 @@ static struct spi_driver td028ttec1_spi_driver = { module_spi_driver(td028ttec1_spi_driver); +MODULE_ALIAS("spi:tpo,td028ttec1"); MODULE_ALIAS("spi:toppoly,td028ttec1"); MODULE_AUTHOR("H. Nikolaus Schaller "); MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver"); diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c index b529a8c2b652..3984716096aa 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-tpo-td028ttec1.c @@ -455,6 +455,8 @@ static int td028ttec1_panel_remove(struct spi_device *spi) } static const struct of_device_id td028ttec1_of_match[] = { + { .compatible = "omapdss,tpo,td028ttec1", }, + /* keep to not break older DTB */ { .compatible = "omapdss,toppoly,td028ttec1", }, {}, }; @@ -474,6 +476,7 @@ static struct spi_driver td028ttec1_spi_driver = { module_spi_driver(td028ttec1_spi_driver); +MODULE_ALIAS("spi:tpo,td028ttec1"); MODULE_ALIAS("spi:toppoly,td028ttec1"); MODULE_AUTHOR("H. Nikolaus Schaller "); MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver"); -- GitLab From abb3ee3ac5926b271af968737026674f24a90743 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 29 Sep 2017 14:49:49 +0300 Subject: [PATCH 0741/1834] drm/omap: DMM: Check for DMM readiness after successful transaction commit [ Upstream commit b7ea6b286c4051e043f691781785e3c4672f014a ] Check the status of the DMM engine after it is reported that the transaction was completed as in rare cases the engine might not reached a working state. The wait_status() will print information in case the DMM is not reached the expected state and the dmm_txn_commit() will return with an error code to make sure that we are not continuing with a broken setup. Signed-off-by: Peter Ujfalusi Signed-off-by: Tomi Valkeinen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index 4b83e9eeab06..7def04049498 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -298,7 +298,12 @@ static int dmm_txn_commit(struct dmm_txn *txn, bool wait) msecs_to_jiffies(100))) { dev_err(dmm->dev, "timed out waiting for done\n"); ret = -ETIMEDOUT; + goto cleanup; } + + /* Check the engine status before continue */ + ret = wait_status(engine, DMM_PATSTATUS_READY | + DMM_PATSTATUS_VALID | DMM_PATSTATUS_DONE); } cleanup: -- GitLab From d69cf8561fb995be0e72da6c92e206f342707d67 Mon Sep 17 00:00:00 2001 From: Sahara Date: Wed, 13 Dec 2017 09:10:48 +0400 Subject: [PATCH 0742/1834] pty: cancel pty slave port buf's work in tty_release [ Upstream commit 2b022ab7542df60021ab57854b3faaaf42552eaf ] In case that CONFIG_SLUB_DEBUG is on and pty is used, races between release_one_tty and flush_to_ldisc work threads may happen and lead to use-after-free condition on tty->link->port. Because SLUB_DEBUG is turned on, freed tty->link->port is filled with POISON_FREE value. So far without SLUB_DEBUG, port was filled with zero and flush_to_ldisc could return without a problem by checking if tty is NULL. CPU 0 CPU 1 ----- ----- release_tty pty_write cancel_work_sync(tty) to = tty->link tty_kref_put(tty->link) tty_schedule_flip(to->port) << workqueue >> ... release_one_tty ... pty_cleanup ... kfree(tty->link->port) << workqueue >> flush_to_ldisc tty = READ_ONCE(port->itty) tty is 0x6b6b6b6b6b6b6b6b !!PANIC!! access tty->ldisc Unable to handle kernel paging request at virtual address 6b6b6b6b6b6b6b93 pgd = ffffffc0eb1c3000 [6b6b6b6b6b6b6b93] *pgd=0000000000000000, *pud=0000000000000000 ------------[ cut here ]------------ Kernel BUG at ffffff800851154c [verbose debug info unavailable] Internal error: Oops - BUG: 96000004 [#1] PREEMPT SMP CPU: 3 PID: 265 Comm: kworker/u8:9 Tainted: G W 3.18.31-g0a58eeb #1 Hardware name: Qualcomm Technologies, Inc. MSM 8996pro v1.1 + PMI8996 Carbide (DT) Workqueue: events_unbound flush_to_ldisc task: ffffffc0ed610ec0 ti: ffffffc0ed624000 task.ti: ffffffc0ed624000 PC is at ldsem_down_read_trylock+0x0/0x4c LR is at tty_ldisc_ref+0x24/0x4c pc : [] lr : [] pstate: 80400145 sp : ffffffc0ed627cd0 x29: ffffffc0ed627cd0 x28: 0000000000000000 x27: ffffff8009e05000 x26: ffffffc0d382cfa0 x25: 0000000000000000 x24: ffffff800a012f08 x23: 0000000000000000 x22: ffffffc0703fbc88 x21: 6b6b6b6b6b6b6b6b x20: 6b6b6b6b6b6b6b93 x19: 0000000000000000 x18: 0000000000000001 x17: 00e80000f80d6f53 x16: 0000000000000001 x15: 0000007f7d826fff x14: 00000000000000a0 x13: 0000000000000000 x12: 0000000000000109 x11: 0000000000000000 x10: 0000000000000000 x9 : ffffffc0ed624000 x8 : ffffffc0ed611580 x7 : 0000000000000000 x6 : ffffff800a42e000 x5 : 00000000000003fc x4 : 0000000003bd1201 x3 : 0000000000000001 x2 : 0000000000000001 x1 : ffffff800851004c x0 : 6b6b6b6b6b6b6b93 Signed-off-by: Sahara Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 8d9f9a803b42..fb9bada5f1d5 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1702,6 +1702,8 @@ static void release_tty(struct tty_struct *tty, int idx) if (tty->link) tty->link->port->itty = NULL; tty_buffer_cancel_work(tty->port); + if (tty->link) + tty_buffer_cancel_work(tty->link->port); tty_kref_put(tty->link); tty_kref_put(tty); -- GitLab From ba936f25f95378142e854cc70e35375a452815a9 Mon Sep 17 00:00:00 2001 From: Robert Walker Date: Mon, 18 Dec 2017 11:05:44 -0700 Subject: [PATCH 0743/1834] coresight: Fix disabling of CoreSight TPIU [ Upstream commit 11595db8e17faaa05fadc25746c870e31276962f ] The CoreSight TPIU should be disabled when tracing to other sinks to allow them to operate at full bandwidth. This patch fixes tpiu_disable_hw() to correctly disable the TPIU by configuring the TPIU to stop on flush, initiating a manual flush, waiting for the flush to complete and then waits for the TPIU to indicate it has stopped. Signed-off-by: Robert Walker Tested-by: Mike Leach Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-tpiu.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-tpiu.c b/drivers/hwtracing/coresight/coresight-tpiu.c index 0673baf0f2f5..ff579a7c6d00 100644 --- a/drivers/hwtracing/coresight/coresight-tpiu.c +++ b/drivers/hwtracing/coresight/coresight-tpiu.c @@ -46,8 +46,11 @@ #define TPIU_ITATBCTR0 0xef8 /** register definition **/ +/* FFSR - 0x300 */ +#define FFSR_FT_STOPPED BIT(1) /* FFCR - 0x304 */ #define FFCR_FON_MAN BIT(6) +#define FFCR_STOP_FI BIT(12) /** * @base: memory mapped base address for this component. @@ -85,10 +88,14 @@ static void tpiu_disable_hw(struct tpiu_drvdata *drvdata) { CS_UNLOCK(drvdata->base); - /* Clear formatter controle reg. */ - writel_relaxed(0x0, drvdata->base + TPIU_FFCR); + /* Clear formatter and stop on flush */ + writel_relaxed(FFCR_STOP_FI, drvdata->base + TPIU_FFCR); /* Generate manual flush */ - writel_relaxed(FFCR_FON_MAN, drvdata->base + TPIU_FFCR); + writel_relaxed(FFCR_STOP_FI | FFCR_FON_MAN, drvdata->base + TPIU_FFCR); + /* Wait for flush to complete */ + coresight_timeout(drvdata->base, TPIU_FFCR, FFCR_FON_MAN, 0); + /* Wait for formatter to stop */ + coresight_timeout(drvdata->base, TPIU_FFSR, FFSR_FT_STOPPED, 1); CS_LOCK(drvdata->base); } -- GitLab From bd6552cfc5f7fce149a9bda2a5438a486db14831 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 1 Mar 2017 10:32:57 -0800 Subject: [PATCH 0744/1834] pinctrl: Really force states during suspend/resume [ Upstream commit 981ed1bfbc6c4660b2ddaa8392893e20a6255048 ] In case a platform only defaults a "default" set of pins, but not a "sleep" set of pins, and this particular platform suspends and resumes in a way that the pin states are not preserved by the hardware, when we resume, we would call pinctrl_single_resume() -> pinctrl_force_default() -> pinctrl_select_state() and the first thing we do is check that the pins state is the same as before, and do nothing. In order to fix this, decouple the actual state change from pinctrl_select_state() and move it pinctrl_commit_state(), while keeping the p->state == state check in pinctrl_select_state() not to change the caller assumptions. pinctrl_force_sleep() and pinctrl_force_default() are updated to bypass the state check by calling pinctrl_commit_state(). [Linus Walleij] The forced pin control states are currently only used in some pin controller drivers that grab their own reference to their own pins. This is equal to the pin control hogs: pins taken by pin control devices since there are no corresponding device in the Linux device hierarchy, such as memory controller lines or unused GPIO lines, or GPIO lines that are used orthogonally from the GPIO subsystem but pincontrol-wise managed as hogs (non-strict mode, allowing simultaneous use by GPIO and pin control). For this case forcing the state from the drivers' suspend()/resume() callbacks makes sense and should semantically match the name of the function. Fixes: 6e5e959dde0d ("pinctrl: API changes to support multiple states per device") Signed-off-by: Florian Fainelli Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/core.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index fb38e208f32d..735d8f7f9d71 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -992,19 +992,16 @@ struct pinctrl_state *pinctrl_lookup_state(struct pinctrl *p, EXPORT_SYMBOL_GPL(pinctrl_lookup_state); /** - * pinctrl_select_state() - select/activate/program a pinctrl state to HW + * pinctrl_commit_state() - select/activate/program a pinctrl state to HW * @p: the pinctrl handle for the device that requests configuration * @state: the state handle to select/activate/program */ -int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) +static int pinctrl_commit_state(struct pinctrl *p, struct pinctrl_state *state) { struct pinctrl_setting *setting, *setting2; struct pinctrl_state *old_state = p->state; int ret; - if (p->state == state) - return 0; - if (p->state) { /* * For each pinmux setting in the old state, forget SW's record @@ -1068,6 +1065,19 @@ int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) return ret; } + +/** + * pinctrl_select_state() - select/activate/program a pinctrl state to HW + * @p: the pinctrl handle for the device that requests configuration + * @state: the state handle to select/activate/program + */ +int pinctrl_select_state(struct pinctrl *p, struct pinctrl_state *state) +{ + if (p->state == state) + return 0; + + return pinctrl_commit_state(p, state); +} EXPORT_SYMBOL_GPL(pinctrl_select_state); static void devm_pinctrl_release(struct device *dev, void *res) @@ -1236,7 +1246,7 @@ void pinctrl_unregister_map(struct pinctrl_map const *map) int pinctrl_force_sleep(struct pinctrl_dev *pctldev) { if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_sleep)) - return pinctrl_select_state(pctldev->p, pctldev->hog_sleep); + return pinctrl_commit_state(pctldev->p, pctldev->hog_sleep); return 0; } EXPORT_SYMBOL_GPL(pinctrl_force_sleep); @@ -1248,7 +1258,7 @@ EXPORT_SYMBOL_GPL(pinctrl_force_sleep); int pinctrl_force_default(struct pinctrl_dev *pctldev) { if (!IS_ERR(pctldev->p) && !IS_ERR(pctldev->hog_default)) - return pinctrl_select_state(pctldev->p, pctldev->hog_default); + return pinctrl_commit_state(pctldev->p, pctldev->hog_default); return 0; } EXPORT_SYMBOL_GPL(pinctrl_force_default); -- GitLab From f03b94ef0e8792e06a0212912b1117f26cdc6dda Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 12 Dec 2017 09:43:43 -0800 Subject: [PATCH 0745/1834] pinctrl: rockchip: enable clock when reading pin direction register [ Upstream commit 5c9d8c4f6b8168738a26bcf288516cc3a0886810 ] We generally leave the GPIO clock disabled, unless an interrupt is requested or we're accessing IO registers. We forgot to do this for the ->get_direction() callback, which means we can sometimes [1] get incorrect results [2] from, e.g., /sys/kernel/debug/gpio. Enable the clock, so we get the right results! [1] Sometimes, because many systems have 1 or mor interrupt requested on each GPIO bank, so they always leave their clock on. [2] Incorrect, meaning the register returns 0, and so we interpret that as "input". Signed-off-by: Brian Norris Reviewed-by: Heiko Stuebner Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/pinctrl-rockchip.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 49bf7dcb7ed8..f826793e972c 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1278,8 +1278,16 @@ static int rockchip_gpio_get_direction(struct gpio_chip *chip, unsigned offset) { struct rockchip_pin_bank *bank = gpiochip_get_data(chip); u32 data; + int ret; + ret = clk_enable(bank->clk); + if (ret < 0) { + dev_err(bank->drvdata->dev, + "failed to enable clock for bank %s\n", bank->name); + return ret; + } data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); + clk_disable(bank->clk); return !(data & BIT(offset)); } -- GitLab From 62088f53b14ff275c32e5c9efb95dbab9e8423c8 Mon Sep 17 00:00:00 2001 From: Jerry Snitselaar Date: Wed, 20 Dec 2017 09:48:56 -0700 Subject: [PATCH 0746/1834] iommu/vt-d: clean up pr_irq if request_threaded_irq fails [ Upstream commit 72d548113881dd32bf7f0b221d031e6586468437 ] It is unlikely request_threaded_irq will fail, but if it does for some reason we should clear iommu->pr_irq in the error path. Also intel_svm_finish_prq shouldn't try to clean up the page request interrupt if pr_irq is 0. Without these, if request_threaded_irq were to fail the following occurs: fail with no fixes: [ 0.683147] ------------[ cut here ]------------ [ 0.683148] NULL pointer, cannot free irq [ 0.683158] WARNING: CPU: 1 PID: 1 at kernel/irq/irqdomain.c:1632 irq_domain_free_irqs+0x126/0x140 [ 0.683160] Modules linked in: [ 0.683163] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc2 #3 [ 0.683165] Hardware name: /NUC7i3BNB, BIOS BNKBL357.86A.0036.2017.0105.1112 01/05/2017 [ 0.683168] RIP: 0010:irq_domain_free_irqs+0x126/0x140 [ 0.683169] RSP: 0000:ffffc90000037ce8 EFLAGS: 00010292 [ 0.683171] RAX: 000000000000001d RBX: ffff880276283c00 RCX: ffffffff81c5e5e8 [ 0.683172] RDX: 0000000000000001 RSI: 0000000000000096 RDI: 0000000000000246 [ 0.683174] RBP: ffff880276283c00 R08: 0000000000000000 R09: 000000000000023c [ 0.683175] R10: 0000000000000007 R11: 0000000000000000 R12: 000000000000007a [ 0.683176] R13: 0000000000000001 R14: 0000000000000000 R15: 0000010010000000 [ 0.683178] FS: 0000000000000000(0000) GS:ffff88027ec80000(0000) knlGS:0000000000000000 [ 0.683180] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.683181] CR2: 0000000000000000 CR3: 0000000001c09001 CR4: 00000000003606e0 [ 0.683182] Call Trace: [ 0.683189] intel_svm_finish_prq+0x3c/0x60 [ 0.683191] free_dmar_iommu+0x1ac/0x1b0 [ 0.683195] init_dmars+0xaaa/0xaea [ 0.683200] ? klist_next+0x19/0xc0 [ 0.683203] ? pci_do_find_bus+0x50/0x50 [ 0.683205] ? pci_get_dev_by_id+0x52/0x70 [ 0.683208] intel_iommu_init+0x498/0x5c7 [ 0.683211] pci_iommu_init+0x13/0x3c [ 0.683214] ? e820__memblock_setup+0x61/0x61 [ 0.683217] do_one_initcall+0x4d/0x1a0 [ 0.683220] kernel_init_freeable+0x186/0x20e [ 0.683222] ? set_debug_rodata+0x11/0x11 [ 0.683225] ? rest_init+0xb0/0xb0 [ 0.683226] kernel_init+0xa/0xff [ 0.683229] ret_from_fork+0x1f/0x30 [ 0.683259] Code: 89 ee 44 89 e7 e8 3b e8 ff ff 5b 5d 44 89 e7 44 89 ee 41 5c 41 5d 41 5e e9 a8 84 ff ff 48 c7 c7 a8 71 a7 81 31 c0 e8 6a d3 f9 ff <0f> ff 5b 5d 41 5c 41 5d 41 5 e c3 0f 1f 44 00 00 66 2e 0f 1f 84 [ 0.683285] ---[ end trace f7650e42792627ca ]--- with iommu->pr_irq = 0, but no check in intel_svm_finish_prq: [ 0.669561] ------------[ cut here ]------------ [ 0.669563] Trying to free already-free IRQ 0 [ 0.669573] WARNING: CPU: 3 PID: 1 at kernel/irq/manage.c:1546 __free_irq+0xa4/0x2c0 [ 0.669574] Modules linked in: [ 0.669577] CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc2 #4 [ 0.669579] Hardware name: /NUC7i3BNB, BIOS BNKBL357.86A.0036.2017.0105.1112 01/05/2017 [ 0.669581] RIP: 0010:__free_irq+0xa4/0x2c0 [ 0.669582] RSP: 0000:ffffc90000037cc0 EFLAGS: 00010082 [ 0.669584] RAX: 0000000000000021 RBX: 0000000000000000 RCX: ffffffff81c5e5e8 [ 0.669585] RDX: 0000000000000001 RSI: 0000000000000086 RDI: 0000000000000046 [ 0.669587] RBP: 0000000000000000 R08: 0000000000000000 R09: 000000000000023c [ 0.669588] R10: 0000000000000007 R11: 0000000000000000 R12: ffff880276253960 [ 0.669589] R13: ffff8802762538a4 R14: ffff880276253800 R15: ffff880276283600 [ 0.669593] FS: 0000000000000000(0000) GS:ffff88027ed80000(0000) knlGS:0000000000000000 [ 0.669594] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 0.669596] CR2: 0000000000000000 CR3: 0000000001c09001 CR4: 00000000003606e0 [ 0.669602] Call Trace: [ 0.669616] free_irq+0x30/0x60 [ 0.669620] intel_svm_finish_prq+0x34/0x60 [ 0.669623] free_dmar_iommu+0x1ac/0x1b0 [ 0.669627] init_dmars+0xaaa/0xaea [ 0.669631] ? klist_next+0x19/0xc0 [ 0.669634] ? pci_do_find_bus+0x50/0x50 [ 0.669637] ? pci_get_dev_by_id+0x52/0x70 [ 0.669639] intel_iommu_init+0x498/0x5c7 [ 0.669642] pci_iommu_init+0x13/0x3c [ 0.669645] ? e820__memblock_setup+0x61/0x61 [ 0.669648] do_one_initcall+0x4d/0x1a0 [ 0.669651] kernel_init_freeable+0x186/0x20e [ 0.669653] ? set_debug_rodata+0x11/0x11 [ 0.669656] ? rest_init+0xb0/0xb0 [ 0.669658] kernel_init+0xa/0xff [ 0.669661] ret_from_fork+0x1f/0x30 [ 0.669662] Code: 7a 08 75 0e e9 c3 01 00 00 4c 39 7b 08 74 57 48 89 da 48 8b 5a 18 48 85 db 75 ee 89 ee 48 c7 c7 78 67 a7 81 31 c0 e8 4c 37 fa ff <0f> ff 48 8b 34 24 4c 89 ef e 8 0e 4c 68 00 49 8b 46 40 48 8b 80 [ 0.669688] ---[ end trace 58a470248700f2fc ]--- Cc: Alex Williamson Cc: Joerg Roedel Cc: Ashok Raj Signed-off-by: Jerry Snitselaar Reviewed-by: Ashok Raj Signed-off-by: Alex Williamson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-svm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index cb72e0011310..3a1c40684213 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -127,6 +127,7 @@ int intel_svm_enable_prq(struct intel_iommu *iommu) pr_err("IOMMU: %s: Failed to request IRQ for page request queue\n", iommu->name); dmar_free_hwirq(irq); + iommu->pr_irq = 0; goto err; } dmar_writeq(iommu->reg + DMAR_PQH_REG, 0ULL); @@ -142,9 +143,11 @@ int intel_svm_finish_prq(struct intel_iommu *iommu) dmar_writeq(iommu->reg + DMAR_PQT_REG, 0ULL); dmar_writeq(iommu->reg + DMAR_PQA_REG, 0ULL); - free_irq(iommu->pr_irq, iommu); - dmar_free_hwirq(iommu->pr_irq); - iommu->pr_irq = 0; + if (iommu->pr_irq) { + free_irq(iommu->pr_irq, iommu); + dmar_free_hwirq(iommu->pr_irq); + iommu->pr_irq = 0; + } free_pages((unsigned long)iommu->prq, PRQ_ORDER); iommu->prq = NULL; -- GitLab From 1139d77d8a7f9aa6b6ae0a1c902f94775dad2f52 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Tue, 19 Dec 2017 16:59:21 +0300 Subject: [PATCH 0747/1834] ip6_vti: adjust vti mtu according to mtu of lower device [ Upstream commit 53c81e95df1793933f87748d36070a721f6cb287 ] LTP/udp6_ipsec_vti tests fail when sending large UDP datagrams over ip6_vti that require fragmentation and the underlying device has an MTU smaller than 1500 plus some extra space for headers. This happens because ip6_vti, by default, sets MTU to ETH_DATA_LEN and not updating it depending on a destination address or link parameter. Further attempts to send UDP packets may succeed because pmtu gets updated on ICMPV6_PKT_TOOBIG in vti6_err(). In case the lower device has larger MTU size, e.g. 9000, ip6_vti works but not using the possible maximum size, output packets have 1500 limit. The above cases require manual MTU setup after ip6_vti creation. However ip_vti already updates MTU based on lower device with ip_tunnel_bind_dev(). Here is the example when the lower device MTU is set to 9000: # ip a sh ltp_ns_veth2 ltp_ns_veth2@if7: mtu 9000 ... inet 10.0.0.2/24 scope global ltp_ns_veth2 inet6 fd00::2/64 scope global # ip li add vti6 type vti6 local fd00::2 remote fd00::1 # ip li show vti6 vti6@NONE: mtu 1500 ... link/tunnel6 fd00::2 peer fd00::1 After the patch: # ip li add vti6 type vti6 local fd00::2 remote fd00::1 # ip li show vti6 vti6@NONE: mtu 8832 ... link/tunnel6 fd00::2 peer fd00::1 Reported-by: Petr Vorel Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_vti.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 912333586de6..345efeb887ef 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -625,6 +625,7 @@ static void vti6_link_config(struct ip6_tnl *t) { struct net_device *dev = t->dev; struct __ip6_tnl_parm *p = &t->parms; + struct net_device *tdev = NULL; memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); @@ -637,6 +638,25 @@ static void vti6_link_config(struct ip6_tnl *t) dev->flags |= IFF_POINTOPOINT; else dev->flags &= ~IFF_POINTOPOINT; + + if (p->flags & IP6_TNL_F_CAP_XMIT) { + int strict = (ipv6_addr_type(&p->raddr) & + (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); + struct rt6_info *rt = rt6_lookup(t->net, + &p->raddr, &p->laddr, + p->link, strict); + + if (rt) + tdev = rt->dst.dev; + ip6_rt_put(rt); + } + + if (!tdev && p->link) + tdev = __dev_get_by_index(t->net, p->link); + + if (tdev) + dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len, + IPV6_MIN_MTU); } /** -- GitLab From dc445b384679db0c811d789958963962f963767f Mon Sep 17 00:00:00 2001 From: Anton Vasilyev Date: Tue, 8 Aug 2017 18:56:37 +0300 Subject: [PATCH 0748/1834] RDMA/ocrdma: Fix permissions for OCRDMA_RESET_STATS [ Upstream commit 744820869166c8c78be891240cf5f66e8a333694 ] Debugfs file reset_stats is created with S_IRUSR permissions, but ocrdma_dbgfs_ops_read() doesn't support OCRDMA_RESET_STATS, whereas ocrdma_dbgfs_ops_write() supports only OCRDMA_RESET_STATS. The patch fixes misstype with permissions. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Anton Vasilyev Acked-by: Selvin Xavier Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/ocrdma/ocrdma_stats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c index 8bef09a8c49f..265943069b35 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c @@ -836,7 +836,7 @@ void ocrdma_add_port_stats(struct ocrdma_dev *dev) dev->reset_stats.type = OCRDMA_RESET_STATS; dev->reset_stats.dev = dev; - if (!debugfs_create_file("reset_stats", S_IRUSR, dev->dir, + if (!debugfs_create_file("reset_stats", 0200, dev->dir, &dev->reset_stats, &ocrdma_dbg_ops)) goto err; -- GitLab From 64d5c600648eab27c8b76189e0eb263f346448b3 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Mon, 18 Dec 2017 23:27:03 +1030 Subject: [PATCH 0749/1834] ARM: dts: aspeed-evb: Add unit name to memory node [ Upstream commit e40ed274489a5f516da120186578eb379b452ac6 ] Fixes a warning when building with W=1. All of the ASPEED device trees build without warnings now. Signed-off-by: Joel Stanley Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/aspeed-ast2500-evb.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/aspeed-ast2500-evb.dts b/arch/arm/boot/dts/aspeed-ast2500-evb.dts index 1b7a5ff0e533..d7774d35e466 100644 --- a/arch/arm/boot/dts/aspeed-ast2500-evb.dts +++ b/arch/arm/boot/dts/aspeed-ast2500-evb.dts @@ -15,7 +15,7 @@ bootargs = "console=ttyS4,115200 earlyprintk"; }; - memory { + memory@80000000 { reg = <0x80000000 0x20000000>; }; }; -- GitLab From eeed4cf828189504c053c584ae70333c426a5bc2 Mon Sep 17 00:00:00 2001 From: Benjamin Coddington Date: Tue, 19 Dec 2017 09:35:25 -0500 Subject: [PATCH 0750/1834] nfsd4: permit layoutget of executable-only files [ Upstream commit 66282ec1cf004c09083c29cb5e49019037937bbd ] Clients must be able to read a file in order to execute it, and for pNFS that means the client needs to be able to perform a LAYOUTGET on the file. This behavior for executable-only files was added for OPEN in commit a043226bc140 "nfsd4: permit read opens of executable-only files". This fixes up xfstests generic/126 on block/scsi layouts. Signed-off-by: Benjamin Coddington Signed-off-by: J. Bruce Fields Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4proc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 022d95886d66..eef0caf6e67d 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1338,14 +1338,14 @@ nfsd4_layoutget(struct svc_rqst *rqstp, const struct nfsd4_layout_ops *ops; struct nfs4_layout_stateid *ls; __be32 nfserr; - int accmode; + int accmode = NFSD_MAY_READ_IF_EXEC; switch (lgp->lg_seg.iomode) { case IOMODE_READ: - accmode = NFSD_MAY_READ; + accmode |= NFSD_MAY_READ; break; case IOMODE_RW: - accmode = NFSD_MAY_READ | NFSD_MAY_WRITE; + accmode |= NFSD_MAY_READ | NFSD_MAY_WRITE; break; default: dprintk("%s: invalid iomode %d\n", -- GitLab From 9fd65f85db4565a3c8ad5728dad3e894cf4ffd11 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 2 Nov 2017 00:36:09 -0700 Subject: [PATCH 0751/1834] clk: Don't touch hardware when reparenting during registration [ Upstream commit f8f8f1d04494d3a6546bee3f0618c4dba31d7b72 ] The orphan clocks reparent operation shouldn't touch the hardware if clocks are enabled, otherwise it may get a chance to disable a newly registered critical clock which triggers the warning below. Assuming we have two clocks: A and B, B is the parent of A. Clock A has flag: CLK_OPS_PARENT_ENABLE Clock B has flag: CLK_IS_CRITICAL Step 1: Clock A is registered, then it becomes orphan. Step 2: Clock B is registered. Before clock B reach the critical clock enable operation, orphan A will find the newly registered parent B and do reparent operation, then parent B will be finally disabled in __clk_set_parent_after() due to CLK_OPS_PARENT_ENABLE flag as there's still no users of B which will then trigger the following warning. WARNING: CPU: 0 PID: 0 at drivers/clk/clk.c:597 clk_core_disable+0xb4/0xe0 Modules linked in: CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.11.0-rc1-00056-gdff1f66-dirty #1373 Hardware name: Generic DT based system Backtrace: [] (dump_backtrace) from [] (show_stack+0x18/0x1c) r6:600000d3 r5:00000000 r4:c0e26358 r3:00000000 [] (show_stack) from [] (dump_stack+0xb4/0xe8) [] (dump_stack) from [] (__warn+0xd8/0x104) r10:c0c21cd0 r9:c048aa78 r8:00000255 r7:00000009 r6:c0c1cd90 r5:00000000 r4:00000000 r3:c0e01d34 [] (__warn) from [] (warn_slowpath_null+0x28/0x30) r9:00000000 r8:ef00bf80 r7:c165ac4c r6:ef00bf80 r5:ef00bf80 r4:ef00bf80 [] (warn_slowpath_null) from [] (clk_core_disable+0xb4/0xe0) [] (clk_core_disable) from [] (clk_core_disable_lock+0x20/0x2c) r4:000000d3 r3:c0e0af00 [] (clk_core_disable_lock) from [] (clk_core_disable_unprepare+0x14/0x28) r5:00000000 r4:ef00bf80 [] (clk_core_disable_unprepare) from [] (__clk_set_parent_after+0x38/0x54) r4:ef00bd80 r3:000010a0 [] (__clk_set_parent_after) from [] (clk_register+0x4d0/0x648) r6:ef00d500 r5:ef00bf80 r4:ef00bd80 r3:ef00bfd4 [] (clk_register) from [] (clk_hw_register+0x10/0x1c) r9:00000000 r8:00000003 r7:00000000 r6:00000824 r5:00000001 r4:ef00d500 [] (clk_hw_register) from [] (_register_divider+0xcc/0x120) [] (_register_divider) from [] (clk_register_divider+0x44/0x54) r10:00000004 r9:00000003 r8:00000001 r7:00000000 r6:00000003 r5:00000001 r4:f0810030 [] (clk_register_divider) from [] (imx7ulp_clocks_init+0x558/0xe98) r7:c0e296f8 r6:c165c808 r5:00000000 r4:c165c808 [] (imx7ulp_clocks_init) from [] (of_clk_init+0x118/0x1e0) r10:00000001 r9:c0e01f68 r8:00000000 r7:c0e01f60 r6:ef7f8974 r5:ef0035c0 r4:00000006 [] (of_clk_init) from [] (time_init+0x2c/0x38) r10:efffed40 r9:c0d61a48 r8:c0e78000 r7:c0e07900 r6:ffffffff r5:c0e78000 r4:00000000 [] (time_init) from [] (start_kernel+0x218/0x394) [] (start_kernel) from [<6000807c>] (0x6000807c) r10:00000000 r9:410fc075 r8:6000406a r7:c0e0c930 r6:c0d61a44 r5:c0e07918 r4:c0e78294 We know that the clk isn't enabled with any sort of prepare_count here so we don't need to enable anything to prevent a race. And we're holding the prepare mutex so set_rate/set_parent can't race here either. Based on an earlier patch by Dong Aisheng. Fixes: fc8726a2c021 ("clk: core: support clocks which requires parents enable (part 2)") Cc: Michael Turquette Cc: Shawn Guo Reported-by: Dong Aisheng Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 0fb39fe217d1..097b0db43cbd 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2443,14 +2443,17 @@ static int __clk_core_init(struct clk_core *core) */ hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { struct clk_core *parent = __clk_init_parent(orphan); + unsigned long flags; /* * we could call __clk_set_parent, but that would result in a * redundant call to the .set_rate op, if it exists */ if (parent) { - __clk_set_parent_before(orphan, parent); - __clk_set_parent_after(orphan, parent, NULL); + /* update the clk tree topology */ + flags = clk_enable_lock(); + clk_reparent(orphan, parent); + clk_enable_unlock(flags); __clk_recalc_accuracies(orphan); __clk_recalc_rates(orphan, 0); } -- GitLab From c53ae7d94e9a79eb6e589d02d4b1fc40fbfa5b45 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 5 Sep 2017 11:32:40 +0200 Subject: [PATCH 0752/1834] clk: axi-clkgen: Correctly handle nocount bit in recalc_rate() [ Upstream commit 063578dc5f407f67d149133818efabe457daafda ] If the nocount bit is set the divider is bypassed and the settings for the divider count should be ignored and a divider value of 1 should be assumed. Handle this correctly in the driver recalc_rate() callback. While the driver sets up the part so that the read back dividers values yield the correct result the power-on reset settings of the part might not reflect this and hence calling e.g. clk_get_rate() without prior calls to clk_set_rate() will yield the wrong result. Signed-off-by: Lars-Peter Clausen Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk-axi-clkgen.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-axi-clkgen.c b/drivers/clk/clk-axi-clkgen.c index 5e918e7afaba..95a6e9834392 100644 --- a/drivers/clk/clk-axi-clkgen.c +++ b/drivers/clk/clk-axi-clkgen.c @@ -40,6 +40,10 @@ #define MMCM_REG_FILTER1 0x4e #define MMCM_REG_FILTER2 0x4f +#define MMCM_CLKOUT_NOCOUNT BIT(6) + +#define MMCM_CLK_DIV_NOCOUNT BIT(12) + struct axi_clkgen { void __iomem *base; struct clk_hw clk_hw; @@ -315,12 +319,27 @@ static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw, unsigned int reg; unsigned long long tmp; - axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®); - dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_2, ®); + if (reg & MMCM_CLKOUT_NOCOUNT) { + dout = 1; + } else { + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLKOUT0_1, ®); + dout = (reg & 0x3f) + ((reg >> 6) & 0x3f); + } + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_DIV, ®); - d = (reg & 0x3f) + ((reg >> 6) & 0x3f); - axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®); - m = (reg & 0x3f) + ((reg >> 6) & 0x3f); + if (reg & MMCM_CLK_DIV_NOCOUNT) + d = 1; + else + d = (reg & 0x3f) + ((reg >> 6) & 0x3f); + + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB2, ®); + if (reg & MMCM_CLKOUT_NOCOUNT) { + m = 1; + } else { + axi_clkgen_mmcm_read(axi_clkgen, MMCM_REG_CLK_FB1, ®); + m = (reg & 0x3f) + ((reg >> 6) & 0x3f); + } if (d == 0 || dout == 0) return 0; -- GitLab From bc0e7313d869e2f67b83e099d540c295a4493281 Mon Sep 17 00:00:00 2001 From: Sergej Sawazki Date: Tue, 25 Jul 2017 23:21:02 +0200 Subject: [PATCH 0753/1834] clk: si5351: Rename internal plls to avoid name collisions [ Upstream commit cdba9a4fb0b53703959ac861e415816cb61aded4 ] This drivers probe fails due to a clock name collision if a clock named 'plla' or 'pllb' is already registered when registering this drivers internal plls. Fix it by renaming internal plls to avoid name collisions. Cc: Sebastian Hesselbarth Cc: Rabeeh Khoury Signed-off-by: Sergej Sawazki Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk-si5351.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c index b051db43fae1..136a86094c53 100644 --- a/drivers/clk/clk-si5351.c +++ b/drivers/clk/clk-si5351.c @@ -72,7 +72,7 @@ static const char * const si5351_input_names[] = { "xtal", "clkin" }; static const char * const si5351_pll_names[] = { - "plla", "pllb", "vxco" + "si5351_plla", "si5351_pllb", "si5351_vxco" }; static const char * const si5351_msynth_names[] = { "ms0", "ms1", "ms2", "ms3", "ms4", "ms5", "ms6", "ms7" -- GitLab From 559205f2899596550b0ea19f733b59b557cc6c1e Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Tue, 19 Dec 2017 12:51:16 +0200 Subject: [PATCH 0754/1834] dmaengine: ti-dma-crossbar: Fix event mapping for TPCC_EVT_MUX_60_63 [ Upstream commit d087f15786021a9605b20f4c678312510be4cac1 ] Register layout of a typical TPCC_EVT_MUX_M_N register is such that the lowest numbered event is at the lowest byte address and highest numbered event at highest byte address. But TPCC_EVT_MUX_60_63 register layout is different, in that the lowest numbered event is at the highest address and highest numbered event is at the lowest address. Therefore, modify ti_am335x_xbar_write() to handle TPCC_EVT_MUX_60_63 register accordingly. Signed-off-by: Vignesh R Signed-off-by: Peter Ujfalusi Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/dma/ti-dma-crossbar.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 43e88d85129e..8c3c588834d2 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -54,7 +54,15 @@ struct ti_am335x_xbar_map { static inline void ti_am335x_xbar_write(void __iomem *iomem, int event, u8 val) { - writeb_relaxed(val, iomem + event); + /* + * TPCC_EVT_MUX_60_63 register layout is different than the + * rest, in the sense, that event 63 is mapped to lowest byte + * and event 60 is mapped to highest, handle it separately. + */ + if (event >= 60 && event <= 63) + writeb_relaxed(val, iomem + (63 - event % 4)); + else + writeb_relaxed(val, iomem + event); } static void ti_am335x_xbar_free(struct device *dev, void *route_data) -- GitLab From e2ee1a1843e5cf0e4040d006d6895262e47332d4 Mon Sep 17 00:00:00 2001 From: Boris Pismenny Date: Thu, 8 Mar 2018 15:51:41 +0200 Subject: [PATCH 0755/1834] IB/mlx5: Fix integer overflows in mlx5_ib_create_srq commit c2b37f76485f073f020e60b5954b6dc4e55f693c upstream. This patch validates user provided input to prevent integer overflow due to integer manipulation in the mlx5_ib_create_srq function. Cc: syzkaller Fixes: e126ba97dba9 ("mlx5: Add driver for Mellanox Connect-IB adapters") Signed-off-by: Boris Pismenny Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/srq.c | 15 +++++++++------ include/linux/mlx5/driver.h | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index d61fd2c727c0..5c1dbe2f8757 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -243,8 +243,8 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, { struct mlx5_ib_dev *dev = to_mdev(pd->device); struct mlx5_ib_srq *srq; - int desc_size; - int buf_size; + size_t desc_size; + size_t buf_size; int err; struct mlx5_srq_attr in = {0}; __u32 max_srq_wqes = 1 << MLX5_CAP_GEN(dev->mdev, log_max_srq_sz); @@ -268,15 +268,18 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, desc_size = sizeof(struct mlx5_wqe_srq_next_seg) + srq->msrq.max_gs * sizeof(struct mlx5_wqe_data_seg); + if (desc_size == 0 || srq->msrq.max_gs > desc_size) + return ERR_PTR(-EINVAL); desc_size = roundup_pow_of_two(desc_size); - desc_size = max_t(int, 32, desc_size); + desc_size = max_t(size_t, 32, desc_size); + if (desc_size < sizeof(struct mlx5_wqe_srq_next_seg)) + return ERR_PTR(-EINVAL); srq->msrq.max_avail_gather = (desc_size - sizeof(struct mlx5_wqe_srq_next_seg)) / sizeof(struct mlx5_wqe_data_seg); srq->msrq.wqe_shift = ilog2(desc_size); buf_size = srq->msrq.max * desc_size; - mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n", - desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs, - srq->msrq.max_avail_gather); + if (buf_size < desc_size) + return ERR_PTR(-EINVAL); in.type = init_attr->srq_type; if (pd->uobject) diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 6a620e01b040..7751d72a6a40 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -380,8 +380,8 @@ struct mlx5_core_srq { struct mlx5_core_rsc_common common; /* must be first */ u32 srqn; int max; - int max_gs; - int max_avail_gather; + size_t max_gs; + size_t max_avail_gather; int wqe_shift; void (*event) (struct mlx5_core_srq *, enum mlx5_event); -- GitLab From 971e09c7be1c051272663cd552c4a815d6f7a151 Mon Sep 17 00:00:00 2001 From: Boris Pismenny Date: Thu, 8 Mar 2018 15:51:40 +0200 Subject: [PATCH 0756/1834] IB/mlx5: Fix out-of-bounds read in create_raw_packet_qp_rq commit 2c292dbb398ee46fc1343daf6c3cf9715a75688e upstream. Add a check for the length of the qpin structure to prevent out-of-bounds reads BUG: KASAN: slab-out-of-bounds in create_raw_packet_qp+0x114c/0x15e2 Read of size 8192 at addr ffff880066b99290 by task syz-executor3/549 CPU: 3 PID: 549 Comm: syz-executor3 Not tainted 4.15.0-rc2+ #27 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014 Call Trace: dump_stack+0x8d/0xd4 print_address_description+0x73/0x290 kasan_report+0x25c/0x370 ? create_raw_packet_qp+0x114c/0x15e2 memcpy+0x1f/0x50 create_raw_packet_qp+0x114c/0x15e2 ? create_raw_packet_qp_tis.isra.28+0x13d/0x13d ? lock_acquire+0x370/0x370 create_qp_common+0x2245/0x3b50 ? destroy_qp_user.isra.47+0x100/0x100 ? kasan_kmalloc+0x13d/0x170 ? sched_clock_cpu+0x18/0x180 ? fs_reclaim_acquire.part.15+0x5/0x30 ? __lock_acquire+0xa11/0x1da0 ? sched_clock_cpu+0x18/0x180 ? kmem_cache_alloc_trace+0x17e/0x310 ? mlx5_ib_create_qp+0x30e/0x17b0 mlx5_ib_create_qp+0x33d/0x17b0 ? sched_clock_cpu+0x18/0x180 ? create_qp_common+0x3b50/0x3b50 ? lock_acquire+0x370/0x370 ? __radix_tree_lookup+0x180/0x220 ? uverbs_try_lock_object+0x68/0xc0 ? rdma_lookup_get_uobject+0x114/0x240 create_qp.isra.5+0xce4/0x1e20 ? ib_uverbs_ex_create_cq_cb+0xa0/0xa0 ? copy_ah_attr_from_uverbs.isra.2+0xa00/0xa00 ? ib_uverbs_cq_event_handler+0x160/0x160 ? __might_fault+0x17c/0x1c0 ib_uverbs_create_qp+0x21b/0x2a0 ? ib_uverbs_destroy_cq+0x2e0/0x2e0 ib_uverbs_write+0x55a/0xad0 ? ib_uverbs_destroy_cq+0x2e0/0x2e0 ? ib_uverbs_destroy_cq+0x2e0/0x2e0 ? ib_uverbs_open+0x760/0x760 ? futex_wake+0x147/0x410 ? check_prev_add+0x1680/0x1680 ? do_futex+0x3d3/0xa60 ? sched_clock_cpu+0x18/0x180 __vfs_write+0xf7/0x5c0 ? ib_uverbs_open+0x760/0x760 ? kernel_read+0x110/0x110 ? lock_acquire+0x370/0x370 ? __fget+0x264/0x3b0 vfs_write+0x18a/0x460 SyS_write+0xc7/0x1a0 ? SyS_read+0x1a0/0x1a0 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL_64_fastpath+0x18/0x85 RIP: 0033:0x4477b9 RSP: 002b:00007f1822cadc18 EFLAGS: 00000292 ORIG_RAX: 0000000000000001 RAX: ffffffffffffffda RBX: 0000000000000005 RCX: 00000000004477b9 RDX: 0000000000000070 RSI: 000000002000a000 RDI: 0000000000000005 RBP: 0000000000708000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000292 R12: 00000000ffffffff R13: 0000000000005d70 R14: 00000000006e6e30 R15: 0000000020010ff0 Allocated by task 549: __kmalloc+0x15e/0x340 kvmalloc_node+0xa1/0xd0 create_user_qp.isra.46+0xd42/0x1610 create_qp_common+0x2e63/0x3b50 mlx5_ib_create_qp+0x33d/0x17b0 create_qp.isra.5+0xce4/0x1e20 ib_uverbs_create_qp+0x21b/0x2a0 ib_uverbs_write+0x55a/0xad0 __vfs_write+0xf7/0x5c0 vfs_write+0x18a/0x460 SyS_write+0xc7/0x1a0 entry_SYSCALL_64_fastpath+0x18/0x85 Freed by task 368: kfree+0xeb/0x2f0 kernfs_fop_release+0x140/0x180 __fput+0x266/0x700 task_work_run+0x104/0x180 exit_to_usermode_loop+0xf7/0x110 syscall_return_slowpath+0x298/0x370 entry_SYSCALL_64_fastpath+0x83/0x85 The buggy address belongs to the object at ffff880066b99180 which belongs to the cache kmalloc-512 of size 512 The buggy address is located 272 bytes inside of 512-byte region [ffff880066b99180, ffff880066b99380) The buggy address belongs to the page: page:000000006040eedd count:1 mapcount:0 mapping: (null) index:0x0 compound_mapcount: 0 flags: 0x4000000000008100(slab|head) raw: 4000000000008100 0000000000000000 0000000000000000 0000000180190019 raw: ffffea00019a7500 0000000b0000000b ffff88006c403080 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff880066b99180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff880066b99200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 >ffff880066b99280: 00 00 fc fc fc fc fc fc fc fc fc fc fc fc fc fc ^ ffff880066b99300: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff880066b99380: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc Cc: syzkaller Fixes: 0fb2ed66a14c ("IB/mlx5: Add create and destroy functionality for Raw Packet QP") Signed-off-by: Boris Pismenny Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/mlx5/qp.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index fdd156101a72..403df3591d29 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -1130,7 +1130,7 @@ static void destroy_raw_packet_qp_sq(struct mlx5_ib_dev *dev, ib_umem_release(sq->ubuffer.umem); } -static int get_rq_pas_size(void *qpc) +static size_t get_rq_pas_size(void *qpc) { u32 log_page_size = MLX5_GET(qpc, qpc, log_page_size) + 12; u32 log_rq_stride = MLX5_GET(qpc, qpc, log_rq_stride); @@ -1146,7 +1146,8 @@ static int get_rq_pas_size(void *qpc) } static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev, - struct mlx5_ib_rq *rq, void *qpin) + struct mlx5_ib_rq *rq, void *qpin, + size_t qpinlen) { struct mlx5_ib_qp *mqp = rq->base.container_mibqp; __be64 *pas; @@ -1155,9 +1156,12 @@ static int create_raw_packet_qp_rq(struct mlx5_ib_dev *dev, void *rqc; void *wq; void *qpc = MLX5_ADDR_OF(create_qp_in, qpin, qpc); - int inlen; + size_t rq_pas_size = get_rq_pas_size(qpc); + size_t inlen; int err; - u32 rq_pas_size = get_rq_pas_size(qpc); + + if (qpinlen < rq_pas_size + MLX5_BYTE_OFF(create_qp_in, pas)) + return -EINVAL; inlen = MLX5_ST_SZ_BYTES(create_rq_in) + rq_pas_size; in = mlx5_vzalloc(inlen); @@ -1235,7 +1239,7 @@ static void destroy_raw_packet_qp_tir(struct mlx5_ib_dev *dev, } static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, - u32 *in, + u32 *in, size_t inlen, struct ib_pd *pd) { struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; @@ -1262,7 +1266,7 @@ static int create_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, if (qp->rq.wqe_cnt) { rq->base.container_mibqp = qp; - err = create_raw_packet_qp_rq(dev, rq, in); + err = create_raw_packet_qp_rq(dev, rq, in, inlen); if (err) goto err_destroy_sq; @@ -1753,10 +1757,15 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, qp->flags |= MLX5_IB_QP_LSO; } + if (inlen < 0) { + err = -EINVAL; + goto err; + } + if (init_attr->qp_type == IB_QPT_RAW_PACKET) { qp->raw_packet_qp.sq.ubuffer.buf_addr = ucmd.sq_buf_addr; raw_packet_qp_copy_info(qp, &qp->raw_packet_qp); - err = create_raw_packet_qp(dev, qp, in, pd); + err = create_raw_packet_qp(dev, qp, in, inlen, pd); } else { err = mlx5_core_create_qp(dev->mdev, &base->mqp, in, inlen); } @@ -1796,6 +1805,7 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, else if (qp->create_type == MLX5_QP_KERNEL) destroy_qp_kernel(dev, qp); +err: kvfree(in); return err; } -- GitLab From bbdfb44745abd2daa8af06e553d7628570daf250 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Wed, 14 Feb 2018 14:43:36 +0100 Subject: [PATCH 0757/1834] clk: migrate the count of orphaned clocks at init commit 99652a469df19086d594e8e89757d4081a812789 upstream. The orphan clocks reparents should migrate any existing count from the orphan clock to its new acestor clocks, otherwise we may have inconsistent counts in the tree and end-up with gated critical clocks Assuming we have two clocks, A and B. * Clock A has CLK_IS_CRITICAL flag set. * Clock B is an ancestor of A which can gate. Clock B gate is left enabled by the bootloader. Step 1: Clock A is registered. Since it is a critical clock, it is enabled. The clock being still an orphan, no parent are enabled. Step 2: Clock B is registered and reparented to clock A (potentially through several other clocks). We are now in situation where the enable count of clock A is 1 while the enable count of its ancestors is 0, which is not good. Step 3: in lateinit, clk_disable_unused() is called, the enable_count of clock B being 0, clock B is gated and and critical clock A actually gets disabled. This situation was found while adding fdiv_clk gates to the meson8b platform. These clocks parent clk81 critical clock, which is the mother of all peripheral clocks in this system. Because of the issue described here, the system is crashing when clk_disable_unused() is called. The situation is solved by reverting commit f8f8f1d04494 ("clk: Don't touch hardware when reparenting during registration"). To avoid breaking again the situation described in this commit description, enabling critical clock should be done before walking the orphan list. This way, a parent critical clock may not be accidentally disabled due to the CLK_OPS_PARENT_ENABLE mechanism. Fixes: f8f8f1d04494 ("clk: Don't touch hardware when reparenting during registration") Cc: Stephen Boyd Cc: Shawn Guo Cc: Dong Aisheng Signed-off-by: Jerome Brunet Tested-by: Marek Szyprowski Tested-by: Heiko Stuebner Signed-off-by: Michael Turquette Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk.c | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 097b0db43cbd..0cdb8550729d 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2437,23 +2437,38 @@ static int __clk_core_init(struct clk_core *core) rate = 0; core->rate = core->req_rate = rate; + /* + * Enable CLK_IS_CRITICAL clocks so newly added critical clocks + * don't get accidentally disabled when walking the orphan tree and + * reparenting clocks + */ + if (core->flags & CLK_IS_CRITICAL) { + unsigned long flags; + + clk_core_prepare(core); + + flags = clk_enable_lock(); + clk_core_enable(core); + clk_enable_unlock(flags); + } + /* * walk the list of orphan clocks and reparent any that newly finds a * parent. */ hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) { struct clk_core *parent = __clk_init_parent(orphan); - unsigned long flags; /* - * we could call __clk_set_parent, but that would result in a - * redundant call to the .set_rate op, if it exists + * We need to use __clk_set_parent_before() and _after() to + * to properly migrate any prepare/enable count of the orphan + * clock. This is important for CLK_IS_CRITICAL clocks, which + * are enabled during init but might not have a parent yet. */ if (parent) { /* update the clk tree topology */ - flags = clk_enable_lock(); - clk_reparent(orphan, parent); - clk_enable_unlock(flags); + __clk_set_parent_before(orphan, parent); + __clk_set_parent_after(orphan, parent, NULL); __clk_recalc_accuracies(orphan); __clk_recalc_rates(orphan, 0); } @@ -2470,16 +2485,6 @@ static int __clk_core_init(struct clk_core *core) if (core->ops->init) core->ops->init(core->hw); - if (core->flags & CLK_IS_CRITICAL) { - unsigned long flags; - - clk_core_prepare(core); - - flags = clk_enable_lock(); - clk_core_enable(core); - clk_enable_unlock(flags); - } - kref_init(&core->ref); out: clk_prepare_unlock(); -- GitLab From e3fb6525c99c2ac9940953f421e4e7d1e354b0e6 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 13 Mar 2018 11:43:23 +0200 Subject: [PATCH 0758/1834] RDMA/ucma: Fix access to non-initialized CM_ID object commit 7688f2c3bbf55e52388e37ac5d63ca471a7712e1 upstream. The attempt to join multicast group without ensuring that CMA device exists will lead to the following crash reported by syzkaller. [ 64.076794] BUG: KASAN: null-ptr-deref in rdma_join_multicast+0x26e/0x12c0 [ 64.076797] Read of size 8 at addr 00000000000000b0 by task join/691 [ 64.076797] [ 64.076800] CPU: 1 PID: 691 Comm: join Not tainted 4.16.0-rc1-00219-gb97853b65b93 #23 [ 64.076802] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-proj4 [ 64.076803] Call Trace: [ 64.076809] dump_stack+0x5c/0x77 [ 64.076817] kasan_report+0x163/0x380 [ 64.085859] ? rdma_join_multicast+0x26e/0x12c0 [ 64.086634] rdma_join_multicast+0x26e/0x12c0 [ 64.087370] ? rdma_disconnect+0xf0/0xf0 [ 64.088579] ? __radix_tree_replace+0xc3/0x110 [ 64.089132] ? node_tag_clear+0x81/0xb0 [ 64.089606] ? idr_alloc_u32+0x12e/0x1a0 [ 64.090517] ? __fprop_inc_percpu_max+0x150/0x150 [ 64.091768] ? tracing_record_taskinfo+0x10/0xc0 [ 64.092340] ? idr_alloc+0x76/0xc0 [ 64.092951] ? idr_alloc_u32+0x1a0/0x1a0 [ 64.093632] ? ucma_process_join+0x23d/0x460 [ 64.094510] ucma_process_join+0x23d/0x460 [ 64.095199] ? ucma_migrate_id+0x440/0x440 [ 64.095696] ? futex_wake+0x10b/0x2a0 [ 64.096159] ucma_join_multicast+0x88/0xe0 [ 64.096660] ? ucma_process_join+0x460/0x460 [ 64.097540] ? _copy_from_user+0x5e/0x90 [ 64.098017] ucma_write+0x174/0x1f0 [ 64.098640] ? ucma_resolve_route+0xf0/0xf0 [ 64.099343] ? rb_erase_cached+0x6c7/0x7f0 [ 64.099839] __vfs_write+0xc4/0x350 [ 64.100622] ? perf_syscall_enter+0xe4/0x5f0 [ 64.101335] ? kernel_read+0xa0/0xa0 [ 64.103525] ? perf_sched_cb_inc+0xc0/0xc0 [ 64.105510] ? syscall_exit_register+0x2a0/0x2a0 [ 64.107359] ? __switch_to+0x351/0x640 [ 64.109285] ? fsnotify+0x899/0x8f0 [ 64.111610] ? fsnotify_unmount_inodes+0x170/0x170 [ 64.113876] ? __fsnotify_update_child_dentry_flags+0x30/0x30 [ 64.115813] ? ring_buffer_record_is_on+0xd/0x20 [ 64.117824] ? __fget+0xa8/0xf0 [ 64.119869] vfs_write+0xf7/0x280 [ 64.122001] SyS_write+0xa1/0x120 [ 64.124213] ? SyS_read+0x120/0x120 [ 64.126644] ? SyS_read+0x120/0x120 [ 64.128563] do_syscall_64+0xeb/0x250 [ 64.130732] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 64.132984] RIP: 0033:0x7f5c994ade99 [ 64.135699] RSP: 002b:00007f5c99b97d98 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 [ 64.138740] RAX: ffffffffffffffda RBX: 00000000200001e4 RCX: 00007f5c994ade99 [ 64.141056] RDX: 00000000000000a0 RSI: 00000000200001c0 RDI: 0000000000000015 [ 64.143536] RBP: 00007f5c99b97ec0 R08: 0000000000000000 R09: 0000000000000000 [ 64.146017] R10: 0000000000000000 R11: 0000000000000246 R12: 00007f5c99b97fc0 [ 64.148608] R13: 0000000000000000 R14: 00007fff660e1c40 R15: 00007f5c99b989c0 [ 64.151060] [ 64.153703] Disabling lock debugging due to kernel taint [ 64.156032] BUG: unable to handle kernel NULL pointer dereference at 00000000000000b0 [ 64.159066] IP: rdma_join_multicast+0x26e/0x12c0 [ 64.161451] PGD 80000001d0298067 P4D 80000001d0298067 PUD 1dea39067 PMD 0 [ 64.164442] Oops: 0000 [#1] SMP KASAN PTI [ 64.166817] CPU: 1 PID: 691 Comm: join Tainted: G B 4.16.0-rc1-00219-gb97853b65b93 #23 [ 64.170004] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-proj4 [ 64.174985] RIP: 0010:rdma_join_multicast+0x26e/0x12c0 [ 64.177246] RSP: 0018:ffff8801c8207860 EFLAGS: 00010282 [ 64.179901] RAX: 0000000000000000 RBX: 0000000000000000 RCX: ffffffff94789522 [ 64.183344] RDX: 1ffffffff2d50fa5 RSI: 0000000000000297 RDI: 0000000000000297 [ 64.186237] RBP: ffff8801c8207a50 R08: 0000000000000000 R09: ffffed0039040ea7 [ 64.189328] R10: 0000000000000001 R11: ffffed0039040ea6 R12: 0000000000000000 [ 64.192634] R13: 0000000000000000 R14: ffff8801e2022800 R15: ffff8801d4ac2400 [ 64.196105] FS: 00007f5c99b98700(0000) GS:ffff8801e5d00000(0000) knlGS:0000000000000000 [ 64.199211] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 64.202046] CR2: 00000000000000b0 CR3: 00000001d1c48004 CR4: 00000000003606a0 [ 64.205032] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 64.208221] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 64.211554] Call Trace: [ 64.213464] ? rdma_disconnect+0xf0/0xf0 [ 64.216124] ? __radix_tree_replace+0xc3/0x110 [ 64.219337] ? node_tag_clear+0x81/0xb0 [ 64.222140] ? idr_alloc_u32+0x12e/0x1a0 [ 64.224422] ? __fprop_inc_percpu_max+0x150/0x150 [ 64.226588] ? tracing_record_taskinfo+0x10/0xc0 [ 64.229763] ? idr_alloc+0x76/0xc0 [ 64.232186] ? idr_alloc_u32+0x1a0/0x1a0 [ 64.234505] ? ucma_process_join+0x23d/0x460 [ 64.237024] ucma_process_join+0x23d/0x460 [ 64.240076] ? ucma_migrate_id+0x440/0x440 [ 64.243284] ? futex_wake+0x10b/0x2a0 [ 64.245302] ucma_join_multicast+0x88/0xe0 [ 64.247783] ? ucma_process_join+0x460/0x460 [ 64.250841] ? _copy_from_user+0x5e/0x90 [ 64.253878] ucma_write+0x174/0x1f0 [ 64.257008] ? ucma_resolve_route+0xf0/0xf0 [ 64.259877] ? rb_erase_cached+0x6c7/0x7f0 [ 64.262746] __vfs_write+0xc4/0x350 [ 64.265537] ? perf_syscall_enter+0xe4/0x5f0 [ 64.267792] ? kernel_read+0xa0/0xa0 [ 64.270358] ? perf_sched_cb_inc+0xc0/0xc0 [ 64.272575] ? syscall_exit_register+0x2a0/0x2a0 [ 64.275367] ? __switch_to+0x351/0x640 [ 64.277700] ? fsnotify+0x899/0x8f0 [ 64.280530] ? fsnotify_unmount_inodes+0x170/0x170 [ 64.283156] ? __fsnotify_update_child_dentry_flags+0x30/0x30 [ 64.286182] ? ring_buffer_record_is_on+0xd/0x20 [ 64.288749] ? __fget+0xa8/0xf0 [ 64.291136] vfs_write+0xf7/0x280 [ 64.292972] SyS_write+0xa1/0x120 [ 64.294965] ? SyS_read+0x120/0x120 [ 64.297474] ? SyS_read+0x120/0x120 [ 64.299751] do_syscall_64+0xeb/0x250 [ 64.301826] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 64.304352] RIP: 0033:0x7f5c994ade99 [ 64.306711] RSP: 002b:00007f5c99b97d98 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 [ 64.309577] RAX: ffffffffffffffda RBX: 00000000200001e4 RCX: 00007f5c994ade99 [ 64.312334] RDX: 00000000000000a0 RSI: 00000000200001c0 RDI: 0000000000000015 [ 64.315783] RBP: 00007f5c99b97ec0 R08: 0000000000000000 R09: 0000000000000000 [ 64.318365] R10: 0000000000000000 R11: 0000000000000246 R12: 00007f5c99b97fc0 [ 64.320980] R13: 0000000000000000 R14: 00007fff660e1c40 R15: 00007f5c99b989c0 [ 64.323515] Code: e8 e8 79 08 ff 4c 89 ff 45 0f b6 a7 b8 01 00 00 e8 68 7c 08 ff 49 8b 1f 4d 89 e5 49 c1 e4 04 48 8 [ 64.330753] RIP: rdma_join_multicast+0x26e/0x12c0 RSP: ffff8801c8207860 [ 64.332979] CR2: 00000000000000b0 [ 64.335550] ---[ end trace 0c00c17a408849c1 ]--- Reported-by: Fixes: c8f6a362bf3e ("RDMA/cma: Add multicast communication support") Signed-off-by: Leon Romanovsky Reviewed-by: Sean Hefty Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/cma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index de3d08c24715..cbe5324c4331 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -4039,6 +4039,9 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, struct cma_multicast *mc; int ret; + if (!id->device) + return -EINVAL; + id_priv = container_of(id, struct rdma_id_private, id); if (!cma_comp(id_priv, RDMA_CM_ADDR_BOUND) && !cma_comp(id_priv, RDMA_CM_ADDR_RESOLVED)) -- GitLab From 805cbd500ee258f8c8e5c0c709389fffd70994eb Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 13 Mar 2018 18:37:27 +0200 Subject: [PATCH 0759/1834] RDMA/ucma: Don't allow join attempts for unsupported AF family commit 0c81ffc60d5280991773d17e84bda605387148b1 upstream. Users can provide garbage while calling to ucma_join_ip_multicast(), it will indirectly cause to rdma_addr_size() return 0, making the call to ucma_process_join(), which had the right checks, but it is better to check the input as early as possible. The following crash from syzkaller revealed it. kernel BUG at lib/string.c:1052! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 0 PID: 4113 Comm: syz-executor0 Not tainted 4.16.0-rc5+ #261 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:fortify_panic+0x13/0x20 lib/string.c:1051 RSP: 0018:ffff8801ca81f8f0 EFLAGS: 00010286 RAX: 0000000000000022 RBX: 1ffff10039503f23 RCX: 0000000000000000 RDX: 0000000000000022 RSI: 1ffff10039503ed3 RDI: ffffed0039503f12 RBP: ffff8801ca81f8f0 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000006 R11: 0000000000000000 R12: ffff8801ca81f998 R13: ffff8801ca81f938 R14: ffff8801ca81fa58 R15: 000000000000fa00 FS: 0000000000000000(0000) GS:ffff8801db200000(0063) knlGS:000000000a12a900 CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 CR2: 0000000008138024 CR3: 00000001cbb58004 CR4: 00000000001606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: memcpy include/linux/string.h:344 [inline] ucma_join_ip_multicast+0x36b/0x3b0 drivers/infiniband/core/ucma.c:1421 ucma_write+0x2d6/0x3d0 drivers/infiniband/core/ucma.c:1633 __vfs_write+0xef/0x970 fs/read_write.c:480 vfs_write+0x189/0x510 fs/read_write.c:544 SYSC_write fs/read_write.c:589 [inline] SyS_write+0xef/0x220 fs/read_write.c:581 do_syscall_32_irqs_on arch/x86/entry/common.c:330 [inline] do_fast_syscall_32+0x3ec/0xf9f arch/x86/entry/common.c:392 entry_SYSENTER_compat+0x70/0x7f arch/x86/entry/entry_64_compat.S:139 RIP: 0023:0xf7f9ec99 RSP: 002b:00000000ff8172cc EFLAGS: 00000282 ORIG_RAX: 0000000000000004 RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000020000100 RDX: 0000000000000063 RSI: 0000000000000000 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 Code: 08 5b 41 5c 41 5d 41 5e 41 5f 5d c3 0f 0b 48 89 df e8 42 2c e3 fb eb de 55 48 89 fe 48 c7 c7 80 75 98 86 48 89 e5 e8 85 95 94 fb <0f> 0b 90 90 90 90 90 90 90 90 90 90 90 55 48 89 e5 41 57 41 56 RIP: fortify_panic+0x13/0x20 lib/string.c:1051 RSP: ffff8801ca81f8f0 Fixes: 5bc2b7b397b0 ("RDMA/ucma: Allow user space to specify AF_IB when joining multicast") Reported-by: Signed-off-by: Leon Romanovsky Reviewed-by: Sean Hefty Signed-off-by: Doug Ledford Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 6840d3c5cd64..017a09ceba3f 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1330,7 +1330,7 @@ static ssize_t ucma_process_join(struct ucma_file *file, return -ENOSPC; addr = (struct sockaddr *) &cmd->addr; - if (!cmd->addr_size || (cmd->addr_size != rdma_addr_size(addr))) + if (cmd->addr_size != rdma_addr_size(addr)) return -EINVAL; if (cmd->join_flags == RDMA_MC_JOIN_FLAG_FULLMEMBER) @@ -1398,6 +1398,9 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file, join_cmd.uid = cmd.uid; join_cmd.id = cmd.id; join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr); + if (!join_cmd.addr_size) + return -EINVAL; + join_cmd.join_flags = RDMA_MC_JOIN_FLAG_FULLMEMBER; memcpy(&join_cmd.addr, &cmd.addr, join_cmd.addr_size); @@ -1413,6 +1416,9 @@ static ssize_t ucma_join_multicast(struct ucma_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; + if (!rdma_addr_size((struct sockaddr *)&cmd.addr)) + return -EINVAL; + return ucma_process_join(file, &cmd, out_len); } -- GitLab From 8dd5c0c47332c67a04830e3842d4d6282f1824fd Mon Sep 17 00:00:00 2001 From: Krzysztof Opasiak Date: Tue, 24 Jan 2017 03:27:24 +0100 Subject: [PATCH 0760/1834] usb: gadget: f_hid: fix: Move IN request allocation to set_alt() commit 749494b6bdbbaf0899aa1c62a1ad74cd747bce47 upstream. Since commit: ba1582f22231 ("usb: gadget: f_hid: use alloc_ep_req()") we cannot allocate any requests in bind() as we check if we should align request buffer based on endpoint descriptor which is assigned in set_alt(). Allocating request in bind() function causes a NULL pointer dereference. This commit moves allocation of IN request from bind() to set_alt() to prevent this issue. Fixes: ba1582f22231 ("usb: gadget: f_hid: use alloc_ep_req()") Cc: stable@vger.kernel.org Tested-by: David Lechner Signed-off-by: Krzysztof Opasiak Signed-off-by: Felipe Balbi Cc: Bin Liu Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_hid.c | 89 ++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 22 deletions(-) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index b6d4b484c51a..5815120c0402 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -284,6 +284,7 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, size_t count, loff_t *offp) { struct f_hidg *hidg = file->private_data; + struct usb_request *req; unsigned long flags; ssize_t status = -ENOMEM; @@ -293,7 +294,7 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, spin_lock_irqsave(&hidg->write_spinlock, flags); #define WRITE_COND (!hidg->write_pending) - +try_again: /* write queue */ while (!WRITE_COND) { spin_unlock_irqrestore(&hidg->write_spinlock, flags); @@ -308,6 +309,7 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, } hidg->write_pending = 1; + req = hidg->req; count = min_t(unsigned, count, hidg->report_length); spin_unlock_irqrestore(&hidg->write_spinlock, flags); @@ -320,24 +322,38 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, goto release_write_pending; } - hidg->req->status = 0; - hidg->req->zero = 0; - hidg->req->length = count; - hidg->req->complete = f_hidg_req_complete; - hidg->req->context = hidg; + spin_lock_irqsave(&hidg->write_spinlock, flags); + + /* we our function has been disabled by host */ + if (!hidg->req) { + free_ep_req(hidg->in_ep, hidg->req); + /* + * TODO + * Should we fail with error here? + */ + goto try_again; + } + + req->status = 0; + req->zero = 0; + req->length = count; + req->complete = f_hidg_req_complete; + req->context = hidg; status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC); if (status < 0) { ERROR(hidg->func.config->cdev, "usb_ep_queue error on int endpoint %zd\n", status); - goto release_write_pending; + goto release_write_pending_unlocked; } else { status = count; } + spin_unlock_irqrestore(&hidg->write_spinlock, flags); return status; release_write_pending: spin_lock_irqsave(&hidg->write_spinlock, flags); +release_write_pending_unlocked: hidg->write_pending = 0; spin_unlock_irqrestore(&hidg->write_spinlock, flags); @@ -541,12 +557,23 @@ static void hidg_disable(struct usb_function *f) kfree(list); } spin_unlock_irqrestore(&hidg->read_spinlock, flags); + + spin_lock_irqsave(&hidg->write_spinlock, flags); + if (!hidg->write_pending) { + free_ep_req(hidg->in_ep, hidg->req); + hidg->write_pending = 1; + } + + hidg->req = NULL; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); } static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct usb_composite_dev *cdev = f->config->cdev; struct f_hidg *hidg = func_to_hidg(f); + struct usb_request *req_in = NULL; + unsigned long flags; int i, status = 0; VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt); @@ -567,6 +594,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) goto fail; } hidg->in_ep->driver_data = hidg; + + req_in = hidg_alloc_ep_req(hidg->in_ep, hidg->report_length); + if (!req_in) { + status = -ENOMEM; + goto disable_ep_in; + } } @@ -578,12 +611,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) hidg->out_ep); if (status) { ERROR(cdev, "config_ep_by_speed FAILED!\n"); - goto fail; + goto free_req_in; } status = usb_ep_enable(hidg->out_ep); if (status < 0) { ERROR(cdev, "Enable OUT endpoint FAILED!\n"); - goto fail; + goto free_req_in; } hidg->out_ep->driver_data = hidg; @@ -599,17 +632,37 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) req->context = hidg; status = usb_ep_queue(hidg->out_ep, req, GFP_ATOMIC); - if (status) + if (status) { ERROR(cdev, "%s queue req --> %d\n", hidg->out_ep->name, status); + free_ep_req(hidg->out_ep, req); + } } else { - usb_ep_disable(hidg->out_ep); status = -ENOMEM; - goto fail; + goto disable_out_ep; } } } + if (hidg->in_ep != NULL) { + spin_lock_irqsave(&hidg->write_spinlock, flags); + hidg->req = req_in; + hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); + + wake_up(&hidg->write_queue); + } + return 0; +disable_out_ep: + usb_ep_disable(hidg->out_ep); +free_req_in: + if (req_in) + free_ep_req(hidg->in_ep, req_in); + +disable_ep_in: + if (hidg->in_ep) + usb_ep_disable(hidg->in_ep); + fail: return status; } @@ -658,12 +711,6 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; hidg->out_ep = ep; - /* preallocate request and buffer */ - status = -ENOMEM; - hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length); - if (!hidg->req) - goto fail; - /* set descriptor dynamic values */ hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; @@ -690,6 +737,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; spin_lock_init(&hidg->write_spinlock); + hidg->write_pending = 1; + hidg->req = NULL; spin_lock_init(&hidg->read_spinlock); init_waitqueue_head(&hidg->write_queue); init_waitqueue_head(&hidg->read_queue); @@ -954,10 +1003,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) device_destroy(hidg_class, MKDEV(major, hidg->minor)); cdev_del(&hidg->cdev); - /* disable/free request and end point */ - usb_ep_disable(hidg->in_ep); - free_ep_req(hidg->in_ep, hidg->req); - usb_free_all_descriptors(f); } -- GitLab From 24f70aa804cd7f8fee4353cf4990997d1c8375ae Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 24 Mar 2018 11:00:27 +0100 Subject: [PATCH 0761/1834] Linux 4.9.90 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 16dca98900e7..df3b20af0fdb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 89 +SUBLEVEL = 90 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 6106fc7bfd202e5f7efa56f46aa1e603a7377770 Mon Sep 17 00:00:00 2001 From: Ramkumar Radhakrishnan Date: Fri, 6 May 2016 15:19:03 -0700 Subject: [PATCH 0762/1834] msm: mdss: align yuv bitstream plane size and stride appropriately. Add align function to align the values to non power of 2 and align yuv bitstream plane size and stride appropriately. Change-Id: I40695e9e7a99fe7c814d26fa7b5205370b7f9f64 CRs-Fixed: 997601 Signed-off-by: Ramkumar Radhakrishnan --- drivers/video/fbdev/msm/mdss_mdp_util.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index 29f6c1ad80d1..c0301097517f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -31,6 +31,7 @@ #include "mdss_panel.h" #define PHY_ADDR_4G (1ULL<<32) +#define ALIGN_UP(x, align) ((DIV_ROUND_UP((x), (align))) * (align)) void mdss_mdp_format_flag_removal(u32 *table, u32 num, u32 remove_bits) { @@ -451,13 +452,13 @@ static int mdss_mdp_get_ubwc_plane_size(struct mdss_mdp_format_params *fmt, } /* Y bitstream stride and plane size */ - ps->ystride[0] = ALIGN(width, y_stride_alignment); + ps->ystride[0] = ALIGN_UP(width, y_stride_alignment); ps->ystride[0] = (ps->ystride[0] * y_bpp_numer) / y_bpp_denom; ps->plane_size[0] = ALIGN(ps->ystride[0] * ALIGN(height, y_height_alignment), 4096); /* CbCr bitstream stride and plane size */ - ps->ystride[1] = ALIGN(width / 2, uv_stride_alignment); + ps->ystride[1] = ALIGN_UP(width / 2, uv_stride_alignment); ps->ystride[1] = (ps->ystride[1] * uv_bpp_numer) / uv_bpp_denom; ps->plane_size[1] = ALIGN(ps->ystride[1] * ALIGN(height / 2, uv_height_alignment), 4096); -- GitLab From 6d68a7b4898b22756af7ea5b45e9c65bc32461ae Mon Sep 17 00:00:00 2001 From: Abhijit Kulkarni Date: Tue, 12 Apr 2016 15:48:52 -0700 Subject: [PATCH 0763/1834] msm: mdss: enable additonal clocks Need to enable clk_mmss_mnoc_ahb_clk before turning on the ahb_clk, as there is a core fsm dependency between these clocks. CRs-Fixed: 1008505 Change-Id: I9c87fee27c6a6ef875100c9fc1b9d0cb7c14a2b5 Signed-off-by: Abhijit Kulkarni --- drivers/video/fbdev/msm/mdss.h | 1 + drivers/video/fbdev/msm/mdss_mdp.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 12a317149aae..e6d55b5ec7a0 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -42,6 +42,7 @@ enum mdss_mdp_clk_type { MDSS_CLK_MDP_CORE, MDSS_CLK_MDP_LUT, MDSS_CLK_MDP_VSYNC, + MDSS_CLK_MNOC_AHB, MDSS_MAX_CLK }; diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 13a4bb63bbe1..a3725534cf55 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1270,6 +1270,7 @@ static inline void __mdss_mdp_reg_access_clk_enable( mdss_update_reg_bus_vote(mdata->reg_bus_clt, VOTE_INDEX_LOW); mdss_bus_rt_bw_vote(true); + mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, 1); mdss_mdp_clk_update(MDSS_CLK_AHB, 1); mdss_mdp_clk_update(MDSS_CLK_AXI, 1); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, 1); @@ -1278,6 +1279,7 @@ static inline void __mdss_mdp_reg_access_clk_enable( mdss_mdp_clk_update(MDSS_CLK_AXI, 0); mdss_mdp_clk_update(MDSS_CLK_AHB, 0); mdss_bus_rt_bw_vote(false); + mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, 0); mdss_update_reg_bus_vote(mdata->reg_bus_clt, VOTE_INDEX_DISABLE); } @@ -1558,6 +1560,7 @@ void mdss_mdp_clk_ctrl(int enable) mdata->clk_ena = enable; spin_unlock_irqrestore(&mdp_lock, flags); + mdss_mdp_clk_update(MDSS_CLK_MNOC_AHB, enable); mdss_mdp_clk_update(MDSS_CLK_AHB, enable); mdss_mdp_clk_update(MDSS_CLK_AXI, enable); mdss_mdp_clk_update(MDSS_CLK_MDP_CORE, enable); @@ -1721,6 +1724,9 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata) /* vsync_clk is optional for non-smart panels */ mdss_mdp_irq_clk_register(mdata, "vsync_clk", MDSS_CLK_MDP_VSYNC); + /* this clk is not present on all MDSS revisions */ + mdss_mdp_irq_clk_register(mdata, "mnoc_clk", MDSS_CLK_MNOC_AHB); + /* Setting the default clock rate to the max supported.*/ mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate); pr_debug("mdp clk rate=%ld\n", -- GitLab From e523334f782a4a702e897b0d208d42d1238a9933 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Tue, 13 Feb 2018 20:42:16 -0800 Subject: [PATCH 0764/1834] msm: camera: req_mgr: Populate dev_hdl to notify events to RT devices When sending a specific request to a particular connected device fails, we need to notify other devices for which the same request was already sent. While doing this notification dev_hdl needs to be populated correctly. Change-Id: Ib04e600ee96689fa70e471864b6ea14244768007 Signed-off-by: Karthik Anantha Ram --- drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index aaba48112821..c544320651ef 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -460,6 +460,7 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, for (; i >= 0; i--) { dev = &link->l_dev[i]; evt_data.evt_type = CAM_REQ_MGR_LINK_EVT_ERR; + evt_data.dev_hdl = dev->dev_hdl; evt_data.link_hdl = link->link_hdl; evt_data.req_id = apply_req.request_id; evt_data.u.error = CRM_KMD_ERR_BUBBLE; -- GitLab From 79376ba755a5ad908d32df15063c0ad3cc4d8850 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Tue, 13 Mar 2018 15:17:51 +0530 Subject: [PATCH 0765/1834] usb: dwc3: Enable evicting endpoint cache after flow control MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In 3.00a and 3.20a synopsys release a performance enhancemnet was done to keep the Non Stream capable bulk IN endpoint in cache after flow control. This enhancement causes host mode concurrency issue in which xhci command timeout is happening when mutliple mass storage devices is connected to the device using HUB and simultaneous file transfers are happening to mass storage devices. This failure is caused because if one endpoint flow controlled, other endpoints will not be serviced right. This change sets EnableEpCacheEvict bit which will disable the enhancement. Change-Id: Iafb72f75b81b1bcbe8c5e38ebd6fe40905670e7a Signed-off-by: Pratham Pratap --- drivers/usb/dwc3/core.c | 11 +++++++++++ drivers/usb/dwc3/core.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index edf855c137ae..221b6fff47c9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -913,6 +913,17 @@ int dwc3_core_init(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } + /* + * Enable evicting endpoint cache after flow control for bulk + * endpoints for dwc3 core version 3.00a and 3.20a + */ + if (dwc->revision == DWC3_REVISION_300A || + dwc->revision == DWC3_REVISION_320A) { + reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); + reg |= DWC3_GUCTL2_ENABLE_EP_CACHE_EVICT; + dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); + } + return 0; err2: diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 69d3fa897778..7cf549dbff79 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -220,6 +220,9 @@ /* Global User Control 1 Register */ #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW (1 << 24) +/* Global User Control 2 Register */ +#define DWC3_GUCTL2_ENABLE_EP_CACHE_EVICT (1 << 12) + /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) #define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8) -- GitLab From 3eaa5de1101627899c0cfb986588a969969fdabc Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Tue, 20 Mar 2018 19:29:51 +1100 Subject: [PATCH 0766/1834] MIPS: ralink: Remove ralink_halt() commit 891731f6a5dbe508d12443175a7e166a2fba616a upstream. ralink_halt() does nothing that machine_halt() doesn't already do, so it adds no value. It actually causes incorrect behaviour due to the "unreachable()" at the end. This tells the compiler that the end of the function will never be reached, which isn't true. The compiler responds by not adding a 'return' instruction, so control simply moves on to whatever bytes come afterwards in memory. In my tested, that was the ralink_restart() function. This means that an attempt to 'halt' the machine would actually cause a reboot. So remove ralink_halt() so that a 'halt' really does halt. Fixes: c06e836ada59 ("MIPS: ralink: adds reset code") Signed-off-by: NeilBrown Cc: John Crispin Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: # 3.9+ Patchwork: https://patchwork.linux-mips.org/patch/18851/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/ralink/reset.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c index 64543d66e76b..e9531fea23a2 100644 --- a/arch/mips/ralink/reset.c +++ b/arch/mips/ralink/reset.c @@ -96,16 +96,9 @@ static void ralink_restart(char *command) unreachable(); } -static void ralink_halt(void) -{ - local_irq_disable(); - unreachable(); -} - static int __init mips_reboot_setup(void) { _machine_restart = ralink_restart; - _machine_halt = ralink_halt; return 0; } -- GitLab From 055c49dcf10fe7db6087037abb87728e7dc84192 Mon Sep 17 00:00:00 2001 From: Michael Nosthoff Date: Fri, 9 Mar 2018 10:02:45 +0100 Subject: [PATCH 0767/1834] iio: st_pressure: st_accel: pass correct platform data to init commit 8b438686a001db64c21782d04ef68111e53c45d9 upstream. Commit 7383d44b added a pointer pdata which get set to the default platform_data when non was defined in the device. But it did not pass this pointer to the st_sensors_init_sensor call but still used the maybe uninitialized platform_data from dev. This breaks initialization when no platform_data is given and the optional st,drdy-int-pin devicetree option is not set. This commit fixes this. Cc: stable@vger.kernel.org Fixes: 7383d44b ("iio: st_pressure: st_accel: Initialise sensor platform data properly") Signed-off-by: Michael Nosthoff Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- drivers/iio/accel/st_accel_core.c | 2 +- drivers/iio/pressure/st_pressure_core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index fe94415a0bc7..32cd64c2ee06 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -858,7 +858,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) if (!pdata) pdata = (struct st_sensors_platform_data *)&default_accel_pdata; - err = st_sensors_init_sensor(indio_dev, adata->dev->platform_data); + err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) goto st_accel_power_off; diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index bec60299b6ec..3458418d88bc 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -678,7 +678,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) if (!pdata && press_data->sensor_settings->drdy_irq.addr) pdata = (struct st_sensors_platform_data *)&default_press_pdata; - err = st_sensors_init_sensor(indio_dev, press_data->dev->platform_data); + err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) goto st_press_power_off; -- GitLab From b1d25da581e5f36c5a6cea0fca7db3bb2b6573ad Mon Sep 17 00:00:00 2001 From: Kirill Marinushkin Date: Mon, 19 Mar 2018 07:11:08 +0100 Subject: [PATCH 0768/1834] ALSA: usb-audio: Fix parsing descriptor of UAC2 processing unit commit a6618f4aedb2b60932d766bd82ae7ce866e842aa upstream. Currently, the offsets in the UAC2 processing unit descriptor are calculated incorrectly. It causes an issue when connecting the device which provides such a feature: ~~~~ [84126.724420] usb 1-1.3.1: invalid Processing Unit descriptor (id 18) ~~~~ After this patch is applied, the UAC2 processing unit inits w/o this error. Fixes: 23caaf19b11e ("ALSA: usb-mixer: Add support for Audio Class v2.0") Signed-off-by: Kirill Marinushkin Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/usb/audio.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h index d2314be4f0c0..19f9dc2c06f6 100644 --- a/include/uapi/linux/usb/audio.h +++ b/include/uapi/linux/usb/audio.h @@ -369,7 +369,7 @@ static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_d { return (protocol == UAC_VERSION_1) ? desc->baSourceID[desc->bNrInPins + 4] : - desc->baSourceID[desc->bNrInPins + 6]; + 2; /* in UAC2, this value is constant */ } static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc, @@ -377,7 +377,7 @@ static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_de { return (protocol == UAC_VERSION_1) ? &desc->baSourceID[desc->bNrInPins + 5] : - &desc->baSourceID[desc->bNrInPins + 7]; + &desc->baSourceID[desc->bNrInPins + 6]; } static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc, -- GitLab From d44f3ad7b06b84cff1c9f74efa3e4305c7b3e177 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Mar 2018 08:56:06 +0100 Subject: [PATCH 0769/1834] ALSA: aloop: Sync stale timer before release commit 67a01afaf3d34893cf7d2ea19b34555d6abb7cb0 upstream. The aloop driver tries to stop the pending timer via timer_del() in the trigger callback and in the close callback. The former is correct, as it's an atomic operation, while the latter expects that the timer gets really removed and proceeds the resource releases after that. But timer_del() doesn't synchronize, hence the running timer may still access the released resources. A similar situation can be also seen in the prepare callback after trigger(STOP) where the prepare tries to re-initialize the things while a timer is still running. The problems like the above are seen indirectly in some syzkaller reports (although it's not 100% clear whether this is the only cause, as the race condition is quite narrow and not always easy to trigger). For addressing these issues, this patch adds the explicit alls of timer_del_sync() in some places, so that the pending timer is properly killed / synced. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/aloop.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index cbd20cb8ca11..610d36bce2c2 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -192,6 +192,11 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm) dpcm->timer.expires = 0; } +static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm) +{ + del_timer_sync(&dpcm->timer); +} + #define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) #define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) #define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) @@ -326,6 +331,8 @@ static int loopback_prepare(struct snd_pcm_substream *substream) struct loopback_cable *cable = dpcm->cable; int bps, salign; + loopback_timer_stop_sync(dpcm); + salign = (snd_pcm_format_width(runtime->format) * runtime->channels) / 8; bps = salign * runtime->rate; @@ -745,7 +752,7 @@ static int loopback_close(struct snd_pcm_substream *substream) struct loopback *loopback = substream->private_data; struct loopback_pcm *dpcm = substream->runtime->private_data; - loopback_timer_stop(dpcm); + loopback_timer_stop_sync(dpcm); mutex_lock(&loopback->cable_lock); free_cable(substream); mutex_unlock(&loopback->cable_lock); -- GitLab From 789697007799297173bfb388cc7a71417b31273a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Mar 2018 10:40:27 +0100 Subject: [PATCH 0770/1834] ALSA: aloop: Fix access to not-yet-ready substream via cable commit 8e6b1a72a75bb5067ccb6b56d8ca4aa3a300a64e upstream. In loopback_open() and loopback_close(), we assign and release the substream object to the corresponding cable in a racy way. It's neither locked nor done in the right position. The open callback assigns the substream before its preparation finishes, hence the other side of the cable may pick it up, which may lead to the invalid memory access. This patch addresses these: move the assignment to the end of the open callback, and wrap with cable->lock for avoiding concurrent accesses. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/aloop.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 610d36bce2c2..dc91002d1e0d 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -666,7 +666,9 @@ static void free_cable(struct snd_pcm_substream *substream) return; if (cable->streams[!substream->stream]) { /* other stream is still alive */ + spin_lock_irq(&cable->lock); cable->streams[substream->stream] = NULL; + spin_unlock_irq(&cable->lock); } else { /* free the cable */ loopback->cables[substream->number][dev] = NULL; @@ -706,7 +708,6 @@ static int loopback_open(struct snd_pcm_substream *substream) loopback->cables[substream->number][dev] = cable; } dpcm->cable = cable; - cable->streams[substream->stream] = dpcm; snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); @@ -738,6 +739,11 @@ static int loopback_open(struct snd_pcm_substream *substream) runtime->hw = loopback_pcm_hardware; else runtime->hw = cable->hw; + + spin_lock_irq(&cable->lock); + cable->streams[substream->stream] = dpcm; + spin_unlock_irq(&cable->lock); + unlock: if (err < 0) { free_cable(substream); -- GitLab From ff0b03a460b12bcafa0cccd6c2dd8ce89340d986 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 17 Mar 2018 22:40:18 +0100 Subject: [PATCH 0771/1834] ALSA: hda/realtek - Always immediately update mute LED with pin VREF commit e40bdb03d3cd7da66bd0bc1e40cbcfb49351265c upstream. Some HP laptops have a mute mute LED controlled by a pin VREF. The Realtek codec driver updates the VREF via vmaster hook by calling snd_hda_set_pin_ctl_cache(). This works fine as long as the driver is running in a normal mode. However, when the VREF change happens during the codec being in runtime PM suspend, the regmap access will skip and postpone the actual register change. This ends up with the unchanged LED status until the next runtime PM resume even if you change the Master mute switch. (Interestingly, the machine keeps the LED status even after the codec goes into D3 -- but it's another story.) For improving this usability, let the driver temporarily powering up / down only during the pin VREF change. This can be achieved easily by wrapping the call with snd_hda_power_up_pm() / *_down_pm(). Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=199073 Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/patch_realtek.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index dae0021f39c3..e2230bed7409 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -3261,8 +3261,12 @@ static void alc269_fixup_mic_mute_hook(void *private_data, int enabled) pinval = snd_hda_codec_get_pin_target(codec, spec->mute_led_nid); pinval &= ~AC_PINCTL_VREFEN; pinval |= enabled ? AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80; - if (spec->mute_led_nid) + if (spec->mute_led_nid) { + /* temporarily power up/down for setting VREF */ + snd_hda_power_up_pm(codec); snd_hda_set_pin_ctl_cache(codec, spec->mute_led_nid, pinval); + snd_hda_power_down_pm(codec); + } } /* Make sure the led works even in runtime suspend */ -- GitLab From d8963938399a4b066448dd2a8dd100fb4e91fef8 Mon Sep 17 00:00:00 2001 From: Evgeniy Didin Date: Wed, 14 Mar 2018 22:30:51 +0300 Subject: [PATCH 0772/1834] mmc: dw_mmc: fix falling from idmac to PIO mode when dw_mci_reset occurs commit 47b7de2f6c18f75d1f2716efe752cba43f32a626 upstream. It was found that in IDMAC mode after soft-reset driver switches to PIO mode. That's what happens in case of DTO timeout overflow calculation failure: 1. soft-reset is called 2. driver restarts dma 3. descriptors states are checked, one of descriptor is owned by the IDMAC. 4. driver can't use DMA and then switches to PIO mode. Failure was already fixed in: https://www.spinics.net/lists/linux-mmc/msg48125.html. Behaviour while soft-reset is not something we except or even want to happen. So we switch from dw_mci_idmac_reset to dw_mci_idmac_init, so descriptors are cleaned before starting dma. And while at it explicitly zero des0 which otherwise might contain garbage as being allocated by dmam_alloc_coherent(). Signed-off-by: Evgeniy Didin Cc: Jaehoon Chung Cc: Ulf Hansson Cc: Andy Shevchenko Cc: Jisheng Zhang Cc: Shawn Lin Cc: Alexey Brodkin Cc: Eugeniy Paltsev Cc: linux-snps-arc@lists.infradead.org Cc: # 4.4+ Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/dw_mmc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index f81f4175f49a..d382dbd44635 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -490,6 +490,7 @@ static int dw_mci_idmac_init(struct dw_mci *host) (sizeof(struct idmac_desc_64addr) * (i + 1))) >> 32; /* Initialize reserved and buffer size fields to "0" */ + p->des0 = 0; p->des1 = 0; p->des2 = 0; p->des3 = 0; @@ -512,6 +513,7 @@ static int dw_mci_idmac_init(struct dw_mci *host) i++, p++) { p->des3 = cpu_to_le32(host->sg_dma + (sizeof(struct idmac_desc) * (i + 1))); + p->des0 = 0; p->des1 = 0; } @@ -2878,8 +2880,8 @@ static bool dw_mci_reset(struct dw_mci *host) } if (host->use_dma == TRANS_MODE_IDMAC) - /* It is also recommended that we reset and reprogram idmac */ - dw_mci_idmac_reset(host); + /* It is also required that we reinit idmac */ + dw_mci_idmac_init(host); ret = true; -- GitLab From d2327a25e43a7843d65f5bab3daeb833c5caf63f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Mar 2018 11:36:33 +0100 Subject: [PATCH 0773/1834] PCI: Add function 1 DMA alias quirk for Highpoint RocketRAID 644L commit 1903be8222b7c278ca897c129ce477c1dd6403a8 upstream. The Highpoint RocketRAID 644L uses a Marvel 88SE9235 controller, as with other Marvel controllers this needs a function 1 DMA alias quirk. Note the RocketRAID 642L uses the same Marvel 88SE9235 controller and already is listed with a function 1 DMA alias quirk. Cc: stable@vger.kernel.org BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1534106 Signed-off-by: Hans de Goede Acked-by: Bjorn Helgaas Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/pci/quirks.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4c9fb8b323e8..fb177dc576d6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3877,6 +3877,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL_EXT, 0x9230, quirk_dma_func1_alias); DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0642, quirk_dma_func1_alias); +DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TTI, 0x0645, + quirk_dma_func1_alias); /* https://bugs.gentoo.org/show_bug.cgi?id=497630 */ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB388_ESD, -- GitLab From 3ba5143bbbed8bd0ab2ee85a46f1165ff3039232 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Mar 2018 11:36:32 +0100 Subject: [PATCH 0774/1834] ahci: Add PCI-id for the Highpoint Rocketraid 644L card commit 28b2182dad43f6f8fcbd167539a26714fd12bd64 upstream. Like the Highpoint Rocketraid 642L and cards using a Marvel 88SE9235 controller in general, this RAID card also supports AHCI mode and short of a custom driver, this is the only way to make it work under Linux. Note that even though the card is called to 644L, it has a product-id of 0x0645. Cc: stable@vger.kernel.org BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1534106 Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Acked-by: Bjorn Helgaas Signed-off-by: Greg Kroah-Hartman --- drivers/ata/ahci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 9b46ef4c851e..4d4b5f607b81 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -539,7 +539,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9230), .driver_data = board_ahci_yes_fbs }, - { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), + { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0642), /* highpoint rocketraid 642L */ + .driver_data = board_ahci_yes_fbs }, + { PCI_DEVICE(PCI_VENDOR_ID_TTI, 0x0645), /* highpoint rocketraid 644L */ .driver_data = board_ahci_yes_fbs }, /* Promise */ -- GitLab From beb9ece1db9cabbe01b297e7df2e4d6769dad8bc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 8 Feb 2018 14:43:35 +0100 Subject: [PATCH 0775/1834] clk: bcm2835: Fix ana->maskX definitions commit 49012d1bf5f78782d398adb984a080a88ba42965 upstream. ana->maskX values are already '~'-ed in bcm2835_pll_set_rate(). Remove the '~' in the definition to fix ANA setup. Note that this commit fixes a long standing bug preventing one from using an HDMI display if it's plugged after the FW has booted Linux. This is because PLLH is used by the HDMI encoder to generate the pixel clock. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Cc: Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/bcm/clk-bcm2835.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 2acaa77ad482..48e7040adb63 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -401,17 +401,17 @@ struct bcm2835_pll_ana_bits { static const struct bcm2835_pll_ana_bits bcm2835_ana_default = { .mask0 = 0, .set0 = 0, - .mask1 = (u32)~(A2W_PLL_KI_MASK | A2W_PLL_KP_MASK), + .mask1 = A2W_PLL_KI_MASK | A2W_PLL_KP_MASK, .set1 = (2 << A2W_PLL_KI_SHIFT) | (8 << A2W_PLL_KP_SHIFT), - .mask3 = (u32)~A2W_PLL_KA_MASK, + .mask3 = A2W_PLL_KA_MASK, .set3 = (2 << A2W_PLL_KA_SHIFT), .fb_prediv_mask = BIT(14), }; static const struct bcm2835_pll_ana_bits bcm2835_ana_pllh = { - .mask0 = (u32)~(A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK), + .mask0 = A2W_PLLH_KA_MASK | A2W_PLLH_KI_LOW_MASK, .set0 = (2 << A2W_PLLH_KA_SHIFT) | (2 << A2W_PLLH_KI_LOW_SHIFT), - .mask1 = (u32)~(A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK), + .mask1 = A2W_PLLH_KI_HIGH_MASK | A2W_PLLH_KP_MASK, .set1 = (6 << A2W_PLLH_KP_SHIFT), .mask3 = 0, .set3 = 0, -- GitLab From 8f0dd27b3db01e7785038ea9a711f210067ee6ae Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 8 Feb 2018 14:43:36 +0100 Subject: [PATCH 0776/1834] clk: bcm2835: Protect sections updating shared registers commit 7997f3b2df751aab0b8e60149b226a32966c41ac upstream. CM_PLLx and A2W_XOSC_CTRL registers are accessed by different clock handlers and must be accessed with ->regs_lock held. Update the sections where this protection is missing. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Cc: Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/bcm/clk-bcm2835.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 48e7040adb63..abdc149941e2 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -566,8 +566,10 @@ static int bcm2835_pll_on(struct clk_hw *hw) ~A2W_PLL_CTRL_PWRDN); /* Take the PLL out of reset. */ + spin_lock(&cprman->regs_lock); cprman_write(cprman, data->cm_ctrl_reg, cprman_read(cprman, data->cm_ctrl_reg) & ~CM_PLL_ANARST); + spin_unlock(&cprman->regs_lock); /* Wait for the PLL to lock. */ timeout = ktime_add_ns(ktime_get(), LOCK_TIMEOUT_NS); @@ -644,9 +646,11 @@ static int bcm2835_pll_set_rate(struct clk_hw *hw, } /* Unmask the reference clock from the oscillator. */ + spin_lock(&cprman->regs_lock); cprman_write(cprman, A2W_XOSC_CTRL, cprman_read(cprman, A2W_XOSC_CTRL) | data->reference_enable_mask); + spin_unlock(&cprman->regs_lock); if (do_ana_setup_first) bcm2835_pll_write_ana(cprman, data->ana_reg_base, ana); -- GitLab From bdbd9153899061cc9aacfc376b26a2224850c61a Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 17 Feb 2018 21:05:04 +0800 Subject: [PATCH 0777/1834] clk: sunxi-ng: a31: Fix CLK_OUT_* clock ops commit 5682e268350f9eccdbb04006605c1b7068a7b323 upstream. When support for the A31/A31s CCU was first added, the clock ops for the CLK_OUT_* clocks was set to the wrong type. The clocks are MP-type, but the ops was set for div (M) clocks. This went unnoticed until now. This was because while they are different clocks, their data structures aligned in a way that ccu_div_ops would access the second ccu_div_internal and ccu_mux_internal structures, which were valid, if not incorrect. Furthermore, the use of these CLK_OUT_* was for feeding a precise 32.768 kHz clock signal to the WiFi chip. This was achievable by using the parent with the same clock rate and no divider. So the incorrect divider setting did not affect this usage. Commit 946797aa3f08 ("clk: sunxi-ng: Support fixed post-dividers on MP style clocks") added a new field to the ccu_mp structure, which broke the aforementioned alignment. Now the system crashes as div_ops tries to look up a nonexistent table. Reported-by: Philipp Rossak Tested-by: Philipp Rossak Fixes: c6e6c96d8fa6 ("clk: sunxi-ng: Add A31/A31s clocks") Cc: Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Signed-off-by: Greg Kroah-Hartman --- drivers/clk/sunxi-ng/ccu-sun6i-a31.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 9fe0939c1273..6ea5401e6881 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -750,7 +750,7 @@ static struct ccu_mp out_a_clk = { .features = CCU_FEATURE_FIXED_PREDIV, .hw.init = CLK_HW_INIT_PARENTS("out-a", clk_out_parents, - &ccu_div_ops, + &ccu_mp_ops, 0), }, }; @@ -771,7 +771,7 @@ static struct ccu_mp out_b_clk = { .features = CCU_FEATURE_FIXED_PREDIV, .hw.init = CLK_HW_INIT_PARENTS("out-b", clk_out_parents, - &ccu_div_ops, + &ccu_mp_ops, 0), }, }; @@ -792,7 +792,7 @@ static struct ccu_mp out_c_clk = { .features = CCU_FEATURE_FIXED_PREDIV, .hw.init = CLK_HW_INIT_PARENTS("out-c", clk_out_parents, - &ccu_div_ops, + &ccu_mp_ops, 0), }, }; -- GitLab From dd62bc3058313ef183aeb22d9de2297cb486dd8d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Mar 2018 17:02:34 +0100 Subject: [PATCH 0778/1834] Bluetooth: btusb: Fix quirk for Atheros 1525/QCA6174 commit f44cb4b19ed40b655c2d422c9021ab2c2625adb6 upstream. The Atheros 1525/QCA6174 BT doesn't seem working properly on the recent kernels, as it tries to load a wrong firmware ar3k/AthrBT_0x00000200.dfu and it fails. This seems to have been a problem for some time, and the known workaround is to apply BTUSB_QCA_ROM quirk instead of BTUSB_ATH3012. The device in question is: T: Bus=01 Lev=01 Prnt=01 Port=09 Cnt=03 Dev#= 4 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0cf3 ProdID=3004 Rev= 0.01 C:* #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=1082504 Reported-by: Ivan Levshin Tested-by: Ivan Levshin Cc: Signed-off-by: Takashi Iwai Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/btusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 3257647d4f74..f8ba5c714df5 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -217,7 +217,6 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0930, 0x0227), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0b05, 0x17d0), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x0036), .driver_info = BTUSB_ATH3012 }, - { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x3008), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311d), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0x311e), .driver_info = BTUSB_ATH3012 }, @@ -250,6 +249,7 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, /* QCA ROME chipset */ + { USB_DEVICE(0x0cf3, 0x3004), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe007), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe009), .driver_info = BTUSB_QCA_ROME }, { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME }, -- GitLab From 85f0fec12c58509b0e3717ad07427aa508a2d869 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 3 Feb 2018 20:30:56 -0800 Subject: [PATCH 0779/1834] libata: fix length validation of ATAPI-relayed SCSI commands commit 058f58e235cbe03e923b30ea7c49995a46a8725f upstream. syzkaller reported a crash in ata_bmdma_fill_sg() when writing to /dev/sg1. The immediate cause was that the ATA command's scatterlist was not DMA-mapped, which causes 'pi - 1' to underflow, resulting in a write to 'qc->ap->bmdma_prd[0xffffffff]'. Strangely though, the flag ATA_QCFLAG_DMAMAP was set in qc->flags. The root cause is that when __ata_scsi_queuecmd() is preparing to relay a SCSI command to an ATAPI device, it doesn't correctly validate the CDB length before copying it into the 16-byte buffer 'cdb' in 'struct ata_queued_cmd'. Namely, it validates the fixed CDB length expected based on the SCSI opcode but not the actual CDB length, which can be larger due to the use of the SG_NEXT_CMD_LEN ioctl. Since 'flags' is the next member in ata_queued_cmd, a buffer overflow corrupts it. Fix it by requiring that the actual CDB length be <= 16 (ATAPI_CDB_LEN). [Really it seems the length should be required to be <= dev->cdb_len, but the current behavior seems to have been intentionally introduced by commit 607126c2a21c ("libata-scsi: be tolerant of 12-byte ATAPI commands in 16-byte CDBs") to work around a userspace bug in mplayer. Probably the workaround is no longer needed (mplayer was fixed in 2007), but continuing to allow lengths to up 16 appears harmless for now.] Here's a reproducer that works in QEMU when /dev/sg1 refers to the CD-ROM drive that qemu-system-x86_64 creates by default: #include #include #include #define SG_NEXT_CMD_LEN 0x2283 int main() { char buf[53] = { [36] = 0x7e, [52] = 0x02 }; int fd = open("/dev/sg1", O_RDWR); ioctl(fd, SG_NEXT_CMD_LEN, &(int){ 17 }); write(fd, buf, sizeof(buf)); } The crash was: BUG: unable to handle kernel paging request at ffff8cb97db37ffc IP: ata_bmdma_fill_sg drivers/ata/libata-sff.c:2623 [inline] IP: ata_bmdma_qc_prep+0xa4/0xc0 drivers/ata/libata-sff.c:2727 PGD fb6c067 P4D fb6c067 PUD 0 Oops: 0002 [#1] SMP CPU: 1 PID: 150 Comm: syz_ata_bmdma_q Not tainted 4.15.0-next-20180202 #99 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014 [...] Call Trace: ata_qc_issue+0x100/0x1d0 drivers/ata/libata-core.c:5421 ata_scsi_translate+0xc9/0x1a0 drivers/ata/libata-scsi.c:2024 __ata_scsi_queuecmd drivers/ata/libata-scsi.c:4326 [inline] ata_scsi_queuecmd+0x8c/0x210 drivers/ata/libata-scsi.c:4375 scsi_dispatch_cmd+0xa2/0xe0 drivers/scsi/scsi_lib.c:1727 scsi_request_fn+0x24c/0x530 drivers/scsi/scsi_lib.c:1865 __blk_run_queue_uncond block/blk-core.c:412 [inline] __blk_run_queue+0x3a/0x60 block/blk-core.c:432 blk_execute_rq_nowait+0x93/0xc0 block/blk-exec.c:78 sg_common_write.isra.7+0x272/0x5a0 drivers/scsi/sg.c:806 sg_write+0x1ef/0x340 drivers/scsi/sg.c:677 __vfs_write+0x31/0x160 fs/read_write.c:480 vfs_write+0xa7/0x160 fs/read_write.c:544 SYSC_write fs/read_write.c:589 [inline] SyS_write+0x4d/0xc0 fs/read_write.c:581 do_syscall_64+0x5e/0x110 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x21/0x86 Fixes: 607126c2a21c ("libata-scsi: be tolerant of 12-byte ATAPI commands in 16-byte CDBs") Reported-by: syzbot+1ff6f9fcc3c35f1c72a95e26528c8e7e3276e4da@syzkaller.appspotmail.com Cc: # v2.6.24+ Signed-off-by: Eric Biggers Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-scsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index e3e10e8f6f6a..64c8f9f46ddb 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -4177,7 +4177,9 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *scmd, if (likely((scsi_op != ATA_16) || !atapi_passthru16)) { /* relay SCSI command to ATAPI device */ int len = COMMAND_SIZE(scsi_op); - if (unlikely(len > scmd->cmd_len || len > dev->cdb_len)) + if (unlikely(len > scmd->cmd_len || + len > dev->cdb_len || + scmd->cmd_len > ATAPI_CDB_LEN)) goto bad_cdb_len; xlat_func = atapi_xlat; -- GitLab From 195c71dc031bed7890e39d9571d8f9e2acdb6a5b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 3 Feb 2018 20:33:27 -0800 Subject: [PATCH 0780/1834] libata: remove WARN() for DMA or PIO command without data commit 9173e5e80729c8434b8d27531527c5245f4a5594 upstream. syzkaller hit a WARN() in ata_qc_issue() when writing to /dev/sg0. This happened because it issued a READ_6 command with no data buffer. Just remove the WARN(), as it doesn't appear indicate a kernel bug. The expected behavior is to fail the command, which the code does. Here's a reproducer that works in QEMU when /dev/sg0 refers to a disk of the default type ("82371SB PIIX3 IDE"): #include #include int main() { char buf[42] = { [36] = 0x8 /* READ_6 */ }; write(open("/dev/sg0", O_RDWR), buf, sizeof(buf)); } Fixes: f92a26365a72 ("libata: change ATA_QCFLAG_DMAMAP semantics") Reported-by: syzbot+f7b556d1766502a69d85071d2ff08bd87be53d0f@syzkaller.appspotmail.com Cc: # v2.6.25+ Signed-off-by: Eric Biggers Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index aee39524375c..233040a3f1ad 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5265,8 +5265,7 @@ void ata_qc_issue(struct ata_queued_cmd *qc) * We guarantee to LLDs that they will have at least one * non-zero sg if the command is a data command. */ - if (WARN_ON_ONCE(ata_is_data(prot) && - (!qc->sg || !qc->n_elem || !qc->nbytes))) + if (ata_is_data(prot) && (!qc->sg || !qc->n_elem || !qc->nbytes)) goto sys_err; if (ata_is_dma(prot) || (ata_is_pio(prot) && -- GitLab From 8b8524d75697da34116c3fd42103b67f69f3dcc8 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 3 Feb 2018 20:33:51 -0800 Subject: [PATCH 0781/1834] libata: don't try to pass through NCQ commands to non-NCQ devices commit 2c1ec6fda2d07044cda922ee25337cf5d4b429b3 upstream. syzkaller hit a WARN() in ata_bmdma_qc_issue() when writing to /dev/sg0. This happened because it issued an ATA pass-through command (ATA_16) where the protocol field indicated that NCQ should be used -- but the device did not support NCQ. We could just remove the WARN() from libata-sff.c, but the real problem seems to be that the SCSI -> ATA translation code passes through NCQ commands without verifying that the device actually supports NCQ. Fix this by adding the appropriate check to ata_scsi_pass_thru(). Here's reproducer that works in QEMU when /dev/sg0 refers to a disk of the default type ("82371SB PIIX3 IDE"): #include #include int main() { char buf[53] = { 0 }; buf[36] = 0x85; /* ATA_16 */ buf[37] = (12 << 1); /* FPDMA */ buf[38] = 0x1; /* Has data */ buf[51] = 0xC8; /* ATA_CMD_READ */ write(open("/dev/sg0", O_RDWR), buf, sizeof(buf)); } Fixes: ee7fb331c3ac ("libata: add support for NCQ commands for SG interface") Reported-by: syzbot+2f69ca28df61bdfc77cd36af2e789850355a221e@syzkaller.appspotmail.com Cc: # v4.4+ Signed-off-by: Eric Biggers Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-scsi.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 64c8f9f46ddb..9babbc845750 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -3226,6 +3226,12 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc) goto invalid_fld; } + /* We may not issue NCQ commands to devices not supporting NCQ */ + if (ata_is_ncq(tf->protocol) && !ata_ncq_enabled(dev)) { + fp = 1; + goto invalid_fld; + } + /* sanity check for pio multi commands */ if ((cdb[1] & 0xe0) && !is_multi_taskfile(tf)) { fp = 1; -- GitLab From a9f062b850db21be39afb2cf22b8eca42ec1e314 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 16 Feb 2018 10:48:20 +0100 Subject: [PATCH 0782/1834] libata: Apply NOLPM quirk to Crucial MX100 512GB SSDs commit 9c7be59fc519af9081c46c48f06f2b8fadf55ad8 upstream. Various people have reported the Crucial MX100 512GB model not working with LPM set to min_power. I've now received a report that it also does not work with the new med_power_with_dipm level. It does work with medium_power, but that has no measurable power-savings and given the amount of people being bitten by the other levels not working, this commit just disables LPM altogether. Note all reporters of this have either the 512GB model (max capacity), or are not specifying their SSD's size. So for now this quirk assumes this is a problem with the 512GB model only. Buglink: https://bugzilla.kernel.org/show_bug.cgi?id=89261 Buglink: https://github.com/linrunner/TLP/issues/84 Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 233040a3f1ad..6b90bf756c7d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4403,6 +4403,11 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, + /* The 512GB version of the MX100 has both queued TRIM and LPM issues */ + { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + /* devices that don't properly handle queued TRIM commands */ { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, -- GitLab From 2bcfcae486246875cfb9835cee24955fbfc0c17a Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sun, 18 Feb 2018 22:17:09 +0800 Subject: [PATCH 0783/1834] libata: disable LPM for Crucial BX100 SSD 500GB drive commit b17e5729a630d8326a48ec34ef02e6b4464a6aef upstream. After Laptop Mode Tools starts to use min_power for LPM, a user found out Crucial BX100 SSD can't get mounted. Crucial BX100 SSD 500GB drive don't work well with min_power. This also happens to med_power_with_dipm. So let's disable LPM for Crucial BX100 SSD 500GB drive. BugLink: https://bugs.launchpad.net/bugs/1726930 Signed-off-by: Kai-Heng Feng Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 6b90bf756c7d..ac35d5738ba9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4403,6 +4403,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-212D", NULL, ATA_HORKAGE_NOSETXFER }, { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, + /* Crucial BX100 SSD 500GB has broken LPM support */ + { "CT500BX100SSD1", "MU02", ATA_HORKAGE_NOLPM }, + /* The 512GB version of the MX100 has both queued TRIM and LPM issues */ { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM | -- GitLab From db4a121a8939ec1d24efe38e3405dc9776c6b925 Mon Sep 17 00:00:00 2001 From: Ju Hyung Park Date: Sun, 11 Mar 2018 02:28:35 +0900 Subject: [PATCH 0784/1834] libata: Enable queued TRIM for Samsung SSD 860 commit ca6bfcb2f6d9deab3924bf901e73622a94900473 upstream. Samsung explicitly states that queued TRIM is supported for Linux with 860 PRO and 860 EVO. Make the previous blacklist to cover only 840 and 850 series. Signed-off-by: Park Ju Hyung Reviewed-by: Martin K. Petersen Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ac35d5738ba9..1f4810ea33c5 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4422,7 +4422,9 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, - { "Samsung SSD 8*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + { "Samsung SSD 840*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM, }, + { "Samsung SSD 850*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, { "FCCT*M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, -- GitLab From a7262d24ab62e92728b7c3fbbd85b718a81ce865 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Mar 2018 16:33:58 +0100 Subject: [PATCH 0785/1834] libata: Apply NOLPM quirk to Crucial M500 480 and 960GB SSDs commit 62ac3f7305470e3f52f159de448bc1a771717e88 upstream. There have been reports of the Crucial M500 480GB model not working with LPM set to min_power / med_power_with_dipm level. It has not been tested with medium_power, but that typically has no measurable power-savings. Note the reporters Crucial_CT480M500SSD3 has a firmware version of MU03 and there is a MU05 update available, but that update does not mention any LPM fixes in its changelog, so the quirk matches all firmware versions. In my experience the LPM problems with (older) Crucial SSDs seem to be limited to higher capacity versions of the SSDs (different firmware?), so this commit adds a NOLPM quirk for the 480 and 960GB versions of the M500, to avoid LPM causing issues with these SSDs. Cc: stable@vger.kernel.org Reported-and-tested-by: Martin Steigerwald Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 1f4810ea33c5..cf84a52ed20e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4411,6 +4411,14 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NOLPM, }, + /* 480GB+ M500 SSDs have both queued TRIM and LPM issues */ + { "Crucial_CT480M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + { "Crucial_CT960M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, + /* devices that don't properly handle queued TRIM commands */ { "Micron_M500_*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM, }, -- GitLab From ed57941c84c4d8c5d30998c3832e0d20deaf0cfe Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Mar 2018 16:33:59 +0100 Subject: [PATCH 0786/1834] libata: Make Crucial BX100 500GB LPM quirk apply to all firmware versions commit 3bf7b5d6d017c27e0d3b160aafb35a8e7cfeda1f upstream. Commit b17e5729a630 ("libata: disable LPM for Crucial BX100 SSD 500GB drive"), introduced a ATA_HORKAGE_NOLPM quirk for Crucial BX100 500GB SSDs but limited this to the MU02 firmware version, according to: http://www.crucial.com/usa/en/support-ssd-firmware MU02 is the last version, so there are no newer possibly fixed versions and if the MU02 version has broken LPM then the MU01 almost certainly also has broken LPM, so this commit changes the quirk to apply to all firmware versions. Fixes: b17e5729a630 ("libata: disable LPM for Crucial BX100 SSD 500GB...") Cc: stable@vger.kernel.org Cc: Kai-Heng Feng Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index cf84a52ed20e..b41d1a7b7c9d 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4404,7 +4404,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, /* Crucial BX100 SSD 500GB has broken LPM support */ - { "CT500BX100SSD1", "MU02", ATA_HORKAGE_NOLPM }, + { "CT500BX100SSD1", NULL, ATA_HORKAGE_NOLPM }, /* The 512GB version of the MX100 has both queued TRIM and LPM issues */ { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | -- GitLab From 8d7a2a6d455cea5b80b584a6df147191ba0043ad Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Mar 2018 16:34:00 +0100 Subject: [PATCH 0787/1834] libata: Modify quirks for MX100 to limit NCQ_TRIM quirk to MU01 version commit d418ff56b8f2d2b296daafa8da151fe27689b757 upstream. When commit 9c7be59fc519af ("libata: Apply NOLPM quirk to Crucial MX100 512GB SSDs") was added it inherited the ATA_HORKAGE_NO_NCQ_TRIM quirk from the existing "Crucial_CT*MX100*" entry, but that entry sets model_rev to "MU01", where as the entry adding the NOLPM quirk sets it to NULL. This means that after this commit we no apply the NO_NCQ_TRIM quirk to all "Crucial_CT512MX100*" SSDs even if they have the fixed "MU02" firmware. This commit splits the "Crucial_CT512MX100*" quirk into 2 quirks, one for the "MU01" firmware and one for all other firmware versions, so that we once again only apply the NO_NCQ_TRIM quirk to the "MU01" firmware version. Fixes: 9c7be59fc519af ("libata: Apply NOLPM quirk to ... MX100 512GB SSDs") Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libata-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b41d1a7b7c9d..e08c09fa5da0 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4406,10 +4406,13 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Crucial BX100 SSD 500GB has broken LPM support */ { "CT500BX100SSD1", NULL, ATA_HORKAGE_NOLPM }, - /* The 512GB version of the MX100 has both queued TRIM and LPM issues */ - { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | + /* 512GB MX100 with MU01 firmware has both queued TRIM and LPM issues */ + { "Crucial_CT512MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | ATA_HORKAGE_ZERO_AFTER_TRIM | ATA_HORKAGE_NOLPM, }, + /* 512GB MX100 with newer firmware has only LPM issues */ + { "Crucial_CT512MX100*", NULL, ATA_HORKAGE_ZERO_AFTER_TRIM | + ATA_HORKAGE_NOLPM, }, /* 480GB+ M500 SSDs have both queued TRIM and LPM issues */ { "Crucial_CT480M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | -- GitLab From e294c4c2d33b7307a89cdf31bec08a112d6a9297 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 16 Mar 2018 11:32:02 -0400 Subject: [PATCH 0788/1834] nfsd: remove blocked locks on client teardown commit 68ef3bc3166468678d5e1fdd216628c35bd1186f upstream. We had some reports of panics in nfsd4_lm_notify, and that showed a nfs4_lockowner that had outlived its so_client. Ensure that we walk any leftover lockowners after tearing down all of the stateids, and remove any blocked locks that they hold. With this change, we also don't need to walk the nbl_lru on nfsd_net shutdown, as that will happen naturally when we tear down the clients. Fixes: 76d348fadff5 (nfsd: have nfsd4_lock use blocking locks for v4.1+ locks) Reported-by: Frank Sorenson Signed-off-by: Jeff Layton Cc: stable@vger.kernel.org # 4.9 Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- fs/nfsd/nfs4state.c | 62 +++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f463c4e0b2ea..12d780718b48 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -263,6 +263,35 @@ free_blocked_lock(struct nfsd4_blocked_lock *nbl) kfree(nbl); } +static void +remove_blocked_locks(struct nfs4_lockowner *lo) +{ + struct nfs4_client *clp = lo->lo_owner.so_client; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + struct nfsd4_blocked_lock *nbl; + LIST_HEAD(reaplist); + + /* Dequeue all blocked locks */ + spin_lock(&nn->blocked_locks_lock); + while (!list_empty(&lo->lo_blocked)) { + nbl = list_first_entry(&lo->lo_blocked, + struct nfsd4_blocked_lock, + nbl_list); + list_del_init(&nbl->nbl_list); + list_move(&nbl->nbl_lru, &reaplist); + } + spin_unlock(&nn->blocked_locks_lock); + + /* Now free them */ + while (!list_empty(&reaplist)) { + nbl = list_first_entry(&reaplist, struct nfsd4_blocked_lock, + nbl_lru); + list_del_init(&nbl->nbl_lru); + posix_unblock_lock(&nbl->nbl_lock); + free_blocked_lock(nbl); + } +} + static int nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) { @@ -1854,6 +1883,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp) static void __destroy_client(struct nfs4_client *clp) { + int i; struct nfs4_openowner *oo; struct nfs4_delegation *dp; struct list_head reaplist; @@ -1883,6 +1913,16 @@ __destroy_client(struct nfs4_client *clp) nfs4_get_stateowner(&oo->oo_owner); release_openowner(oo); } + for (i = 0; i < OWNER_HASH_SIZE; i++) { + struct nfs4_stateowner *so, *tmp; + + list_for_each_entry_safe(so, tmp, &clp->cl_ownerstr_hashtbl[i], + so_strhash) { + /* Should be no openowners at this point */ + WARN_ON_ONCE(so->so_is_open_owner); + remove_blocked_locks(lockowner(so)); + } + } nfsd4_return_all_client_layouts(clp); nfsd4_shutdown_callback(clp); if (clp->cl_cb_conn.cb_xprt) @@ -6266,6 +6306,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, } spin_unlock(&clp->cl_lock); free_ol_stateid_reaplist(&reaplist); + remove_blocked_locks(lo); nfs4_put_stateowner(&lo->lo_owner); return status; @@ -7051,6 +7092,8 @@ nfs4_state_destroy_net(struct net *net) } } + WARN_ON(!list_empty(&nn->blocked_locks_lru)); + for (i = 0; i < CLIENT_HASH_SIZE; i++) { while (!list_empty(&nn->unconf_id_hashtbl[i])) { clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); @@ -7117,7 +7160,6 @@ nfs4_state_shutdown_net(struct net *net) struct nfs4_delegation *dp = NULL; struct list_head *pos, *next, reaplist; struct nfsd_net *nn = net_generic(net, nfsd_net_id); - struct nfsd4_blocked_lock *nbl; cancel_delayed_work_sync(&nn->laundromat_work); locks_end_grace(&nn->nfsd4_manager); @@ -7138,24 +7180,6 @@ nfs4_state_shutdown_net(struct net *net) nfs4_put_stid(&dp->dl_stid); } - BUG_ON(!list_empty(&reaplist)); - spin_lock(&nn->blocked_locks_lock); - while (!list_empty(&nn->blocked_locks_lru)) { - nbl = list_first_entry(&nn->blocked_locks_lru, - struct nfsd4_blocked_lock, nbl_lru); - list_move(&nbl->nbl_lru, &reaplist); - list_del_init(&nbl->nbl_list); - } - spin_unlock(&nn->blocked_locks_lock); - - while (!list_empty(&reaplist)) { - nbl = list_first_entry(&reaplist, - struct nfsd4_blocked_lock, nbl_lru); - list_del_init(&nbl->nbl_lru); - posix_unblock_lock(&nbl->nbl_lock); - free_blocked_lock(nbl); - } - nfsd4_client_tracking_exit(net); nfs4_state_destroy_net(net); } -- GitLab From 9c7f7bdb1932f8c1e5f80d32c717184701afe701 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Thu, 22 Mar 2018 16:17:20 -0700 Subject: [PATCH 0789/1834] mm/vmalloc: add interfaces to free unmapped page table commit b6bdb7517c3d3f41f20e5c2948d6bc3f8897394e upstream. On architectures with CONFIG_HAVE_ARCH_HUGE_VMAP set, ioremap() may create pud/pmd mappings. A kernel panic was observed on arm64 systems with Cortex-A75 in the following steps as described by Hanjun Guo. 1. ioremap a 4K size, valid page table will build, 2. iounmap it, pte0 will set to 0; 3. ioremap the same address with 2M size, pgd/pmd is unchanged, then set the a new value for pmd; 4. pte0 is leaked; 5. CPU may meet exception because the old pmd is still in TLB, which will lead to kernel panic. This panic is not reproducible on x86. INVLPG, called from iounmap, purges all levels of entries associated with purged address on x86. x86 still has memory leak. The patch changes the ioremap path to free unmapped page table(s) since doing so in the unmap path has the following issues: - The iounmap() path is shared with vunmap(). Since vmap() only supports pte mappings, making vunmap() to free a pte page is an overhead for regular vmap users as they do not need a pte page freed up. - Checking if all entries in a pte page are cleared in the unmap path is racy, and serializing this check is expensive. - The unmap path calls free_vmap_area_noflush() to do lazy TLB purges. Clearing a pud/pmd entry before the lazy TLB purges needs extra TLB purge. Add two interfaces, pud_free_pmd_page() and pmd_free_pte_page(), which clear a given pud/pmd entry and free up a page for the lower level entries. This patch implements their stub functions on x86 and arm64, which work as workaround. [akpm@linux-foundation.org: fix typo in pmd_free_pte_page() stub] Link: http://lkml.kernel.org/r/20180314180155.19492-2-toshi.kani@hpe.com Fixes: e61ce6ade404e ("mm: change ioremap to set up huge I/O mappings") Reported-by: Lei Li Signed-off-by: Toshi Kani Cc: Catalin Marinas Cc: Wang Xuefeng Cc: Will Deacon Cc: Hanjun Guo Cc: Michal Hocko Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Borislav Petkov Cc: Matthew Wilcox Cc: Chintan Pandya Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/mmu.c | 10 ++++++++++ arch/x86/mm/pgtable.c | 24 ++++++++++++++++++++++++ include/asm-generic/pgtable.h | 10 ++++++++++ lib/ioremap.c | 6 ++++-- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index d5cc6d73c2c4..638f7f2bd79c 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -772,3 +772,13 @@ int pmd_clear_huge(pmd_t *pmd) pmd_clear(pmd); return 1; } + +int pud_free_pmd_page(pud_t *pud) +{ + return pud_none(*pud); +} + +int pmd_free_pte_page(pmd_t *pmd) +{ + return pmd_none(*pmd); +} diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index 209b9465e97a..e478b105a103 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -643,4 +643,28 @@ int pmd_clear_huge(pmd_t *pmd) return 0; } + +/** + * pud_free_pmd_page - Clear pud entry and free pmd page. + * @pud: Pointer to a PUD. + * + * Context: The pud range has been unmaped and TLB purged. + * Return: 1 if clearing the entry succeeded. 0 otherwise. + */ +int pud_free_pmd_page(pud_t *pud) +{ + return pud_none(*pud); +} + +/** + * pmd_free_pte_page - Clear pmd entry and free pte page. + * @pmd: Pointer to a PMD. + * + * Context: The pmd range has been unmaped and TLB purged. + * Return: 1 if clearing the entry succeeded. 0 otherwise. + */ +int pmd_free_pte_page(pmd_t *pmd) +{ + return pmd_none(*pmd); +} #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index c4f8fd2fd384..f6ea0f3c03f8 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -764,6 +764,8 @@ int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot); int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot); int pud_clear_huge(pud_t *pud); int pmd_clear_huge(pmd_t *pmd); +int pud_free_pmd_page(pud_t *pud); +int pmd_free_pte_page(pmd_t *pmd); #else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */ static inline int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot) { @@ -781,6 +783,14 @@ static inline int pmd_clear_huge(pmd_t *pmd) { return 0; } +static inline int pud_free_pmd_page(pud_t *pud) +{ + return 0; +} +static inline int pmd_free_pte_page(pmd_t *pmd) +{ + return 0; +} #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ #ifndef __HAVE_ARCH_FLUSH_PMD_TLB_RANGE diff --git a/lib/ioremap.c b/lib/ioremap.c index 86c8911b0e3a..5323b59ca393 100644 --- a/lib/ioremap.c +++ b/lib/ioremap.c @@ -83,7 +83,8 @@ static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr, if (ioremap_pmd_enabled() && ((next - addr) == PMD_SIZE) && - IS_ALIGNED(phys_addr + addr, PMD_SIZE)) { + IS_ALIGNED(phys_addr + addr, PMD_SIZE) && + pmd_free_pte_page(pmd)) { if (pmd_set_huge(pmd, phys_addr + addr, prot)) continue; } @@ -109,7 +110,8 @@ static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr, if (ioremap_pud_enabled() && ((next - addr) == PUD_SIZE) && - IS_ALIGNED(phys_addr + addr, PUD_SIZE)) { + IS_ALIGNED(phys_addr + addr, PUD_SIZE) && + pud_free_pmd_page(pud)) { if (pud_set_huge(pud, phys_addr + addr, prot)) continue; } -- GitLab From f4fe4f987ad9df650495102965ff86a950eff4e2 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Thu, 22 Mar 2018 16:17:24 -0700 Subject: [PATCH 0790/1834] x86/mm: implement free pmd/pte page interfaces commit 28ee90fe6048fa7b7ceaeb8831c0e4e454a4cf89 upstream. Implement pud_free_pmd_page() and pmd_free_pte_page() on x86, which clear a given pud/pmd entry and free up lower level page table(s). The address range associated with the pud/pmd entry must have been purged by INVLPG. Link: http://lkml.kernel.org/r/20180314180155.19492-3-toshi.kani@hpe.com Fixes: e61ce6ade404e ("mm: change ioremap to set up huge I/O mappings") Signed-off-by: Toshi Kani Reported-by: Lei Li Cc: Michal Hocko Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Borislav Petkov Cc: Matthew Wilcox Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/mm/pgtable.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c index e478b105a103..b97ef29c940f 100644 --- a/arch/x86/mm/pgtable.c +++ b/arch/x86/mm/pgtable.c @@ -653,7 +653,22 @@ int pmd_clear_huge(pmd_t *pmd) */ int pud_free_pmd_page(pud_t *pud) { - return pud_none(*pud); + pmd_t *pmd; + int i; + + if (pud_none(*pud)) + return 1; + + pmd = (pmd_t *)pud_page_vaddr(*pud); + + for (i = 0; i < PTRS_PER_PMD; i++) + if (!pmd_free_pte_page(&pmd[i])) + return 0; + + pud_clear(pud); + free_page((unsigned long)pmd); + + return 1; } /** @@ -665,6 +680,15 @@ int pud_free_pmd_page(pud_t *pud) */ int pmd_free_pte_page(pmd_t *pmd) { - return pmd_none(*pmd); + pte_t *pte; + + if (pmd_none(*pmd)) + return 1; + + pte = (pte_t *)pmd_page_vaddr(*pmd); + pmd_clear(pmd); + free_page((unsigned long)pte); + + return 1; } #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ -- GitLab From 24284d5f53d0d8d4bc9321cfbd23f7bd63480059 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 22 Mar 2018 16:17:28 -0700 Subject: [PATCH 0791/1834] mm/khugepaged.c: convert VM_BUG_ON() to collapse fail commit fece2029a9e65b9a990831afe2a2b83290cbbe26 upstream. khugepaged is not yet able to convert PTE-mapped huge pages back to PMD mapped. We do not collapse such pages. See check khugepaged_scan_pmd(). But if between khugepaged_scan_pmd() and __collapse_huge_page_isolate() somebody managed to instantiate THP in the range and then split the PMD back to PTEs we would have a problem -- VM_BUG_ON_PAGE(PageCompound(page)) will get triggered. It's possible since we drop mmap_sem during collapse to re-take for write. Replace the VM_BUG_ON() with graceful collapse fail. Link: http://lkml.kernel.org/r/20180315152353.27989-1-kirill.shutemov@linux.intel.com Fixes: b1caa957ae6d ("khugepaged: ignore pmd tables with THP mapped with ptes") Signed-off-by: Kirill A. Shutemov Cc: Laura Abbott Cc: Jerome Marchand Cc: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/khugepaged.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 5d7c006373d3..898eb26f5dc8 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -528,7 +528,12 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma, goto out; } - VM_BUG_ON_PAGE(PageCompound(page), page); + /* TODO: teach khugepaged to collapse THP mapped with pte */ + if (PageCompound(page)) { + result = SCAN_PAGE_COMPOUND; + goto out; + } + VM_BUG_ON_PAGE(!PageAnon(page), page); VM_BUG_ON_PAGE(!PageSwapBacked(page), page); -- GitLab From 142d9dda9e3b55c2b4604bd3d90f3db1c3219e55 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 22 Mar 2018 16:17:31 -0700 Subject: [PATCH 0792/1834] mm/thp: do not wait for lock_page() in deferred_split_scan() commit fa41b900c30b45fab03783724932dc30cd46a6be upstream. deferred_split_scan() gets called from reclaim path. Waiting for page lock may lead to deadlock there. Replace lock_page() with trylock_page() and skip the page if we failed to lock it. We will get to the page on the next scan. Link: http://lkml.kernel.org/r/20180315150747.31945-1-kirill.shutemov@linux.intel.com Fixes: 9a982250f773 ("thp: introduce deferred_split_huge_page()") Signed-off-by: Kirill A. Shutemov Acked-by: Michal Hocko Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/huge_memory.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index c234c078693c..e2982ea26090 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2279,11 +2279,13 @@ static unsigned long deferred_split_scan(struct shrinker *shrink, list_for_each_safe(pos, next, &list) { page = list_entry((void *)pos, struct page, mapping); - lock_page(page); + if (!trylock_page(page)) + goto next; /* split_huge_page() removes page from list on success */ if (!split_huge_page(page)) split++; unlock_page(page); +next: put_page(page); } -- GitLab From 8ab899550b9a7ab2eebf84c1a694aafbd1e2121f Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Thu, 22 Mar 2018 16:17:35 -0700 Subject: [PATCH 0793/1834] mm/shmem: do not wait for lock_page() in shmem_unused_huge_shrink() commit b3cd54b257ad95d344d121dc563d943ca39b0921 upstream. shmem_unused_huge_shrink() gets called from reclaim path. Waiting for page lock may lead to deadlock there. There was a bug report that may be attributed to this: http://lkml.kernel.org/r/alpine.LRH.2.11.1801242349220.30642@mail.ewheeler.net Replace lock_page() with trylock_page() and skip the page if we failed to lock it. We will get to the page on the next scan. We can test for the PageTransHuge() outside the page lock as we only need protection against splitting the page under us. Holding pin oni the page is enough for this. Link: http://lkml.kernel.org/r/20180316210830.43738-1-kirill.shutemov@linux.intel.com Fixes: 779750d20b93 ("shmem: split huge pages beyond i_size under memory pressure") Signed-off-by: Kirill A. Shutemov Reported-by: Eric Wheeler Acked-by: Michal Hocko Reviewed-by: Andrew Morton Cc: Tetsuo Handa Cc: Hugh Dickins Cc: [4.8+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/shmem.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/mm/shmem.c b/mm/shmem.c index 2123bfc39ef2..42ca5df2c0e3 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -466,36 +466,45 @@ static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo, info = list_entry(pos, struct shmem_inode_info, shrinklist); inode = &info->vfs_inode; - if (nr_to_split && split >= nr_to_split) { - iput(inode); - continue; - } + if (nr_to_split && split >= nr_to_split) + goto leave; - page = find_lock_page(inode->i_mapping, + page = find_get_page(inode->i_mapping, (inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT); if (!page) goto drop; + /* No huge page at the end of the file: nothing to split */ if (!PageTransHuge(page)) { - unlock_page(page); put_page(page); goto drop; } + /* + * Leave the inode on the list if we failed to lock + * the page at this time. + * + * Waiting for the lock may lead to deadlock in the + * reclaim path. + */ + if (!trylock_page(page)) { + put_page(page); + goto leave; + } + ret = split_huge_page(page); unlock_page(page); put_page(page); - if (ret) { - /* split failed: leave it on the list */ - iput(inode); - continue; - } + /* If split failed leave the inode on the list */ + if (ret) + goto leave; split++; drop: list_del_init(&info->shrinklist); removed++; +leave: iput(inode); } -- GitLab From f0c88241d3526f9de39970e006a49d9c66650ab3 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Wed, 21 Mar 2018 10:18:38 +0100 Subject: [PATCH 0794/1834] drm/vmwgfx: Fix a destoy-while-held mutex problem. commit 73a88250b70954a8f27c2444e1c2411bba3c29d9 upstream. When validating legacy surfaces, the backup bo might be destroyed at surface validate time. However, the kms resource validation code may have the bo reserved, so we will destroy a locked mutex. While there shouldn't be any other users of that mutex when it is destroyed, it causes a lock leak and thus throws a lockdep error. Fix this by having the kms resource validation code hold a reference to the bo while we have it reserved. We do this by introducing a validation context which might come in handy when the kms code is extended to validate multiple resources or buffers. Cc: Signed-off-by: Thomas Hellstrom Reviewed-by: Brian Paul Reviewed-by: Sinclair Yeh Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 28 +++++++++++++++++++--------- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 12 +++++++++--- drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c | 5 +++-- drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c | 5 +++-- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index bf28ccc150df..87086af42114 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -27,7 +27,6 @@ #include "vmwgfx_kms.h" - /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) @@ -1933,9 +1932,12 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, * Helper to be used if an error forces the caller to undo the actions of * vmw_kms_helper_resource_prepare. */ -void vmw_kms_helper_resource_revert(struct vmw_resource *res) +void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx) { - vmw_kms_helper_buffer_revert(res->backup); + struct vmw_resource *res = ctx->res; + + vmw_kms_helper_buffer_revert(ctx->buf); + vmw_dmabuf_unreference(&ctx->buf); vmw_resource_unreserve(res, false, NULL, 0); mutex_unlock(&res->dev_priv->cmdbuf_mutex); } @@ -1952,10 +1954,14 @@ void vmw_kms_helper_resource_revert(struct vmw_resource *res) * interrupted by a signal. */ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, - bool interruptible) + bool interruptible, + struct vmw_validation_ctx *ctx) { int ret = 0; + ctx->buf = NULL; + ctx->res = res; + if (interruptible) ret = mutex_lock_interruptible(&res->dev_priv->cmdbuf_mutex); else @@ -1974,6 +1980,8 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, res->dev_priv->has_mob); if (ret) goto out_unreserve; + + ctx->buf = vmw_dmabuf_reference(res->backup); } ret = vmw_resource_validate(res); if (ret) @@ -1981,7 +1989,7 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, return 0; out_revert: - vmw_kms_helper_buffer_revert(res->backup); + vmw_kms_helper_buffer_revert(ctx->buf); out_unreserve: vmw_resource_unreserve(res, false, NULL, 0); out_unlock: @@ -1997,11 +2005,13 @@ int vmw_kms_helper_resource_prepare(struct vmw_resource *res, * @out_fence: Optional pointer to a fence pointer. If non-NULL, a * ref-counted fence pointer is returned here. */ -void vmw_kms_helper_resource_finish(struct vmw_resource *res, - struct vmw_fence_obj **out_fence) +void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, + struct vmw_fence_obj **out_fence) { - if (res->backup || out_fence) - vmw_kms_helper_buffer_finish(res->dev_priv, NULL, res->backup, + struct vmw_resource *res = ctx->res; + + if (ctx->buf || out_fence) + vmw_kms_helper_buffer_finish(res->dev_priv, NULL, ctx->buf, out_fence, NULL); vmw_resource_unreserve(res, false, NULL, 0); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index ff4803c107bc..2dd05395e98b 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -183,6 +183,11 @@ struct vmw_display_unit { int set_gui_y; }; +struct vmw_validation_ctx { + struct vmw_resource *res; + struct vmw_dma_buffer *buf; +}; + #define vmw_crtc_to_du(x) \ container_of(x, struct vmw_display_unit, crtc) #define vmw_connector_to_du(x) \ @@ -233,9 +238,10 @@ void vmw_kms_helper_buffer_finish(struct vmw_private *dev_priv, struct drm_vmw_fence_rep __user * user_fence_rep); int vmw_kms_helper_resource_prepare(struct vmw_resource *res, - bool interruptible); -void vmw_kms_helper_resource_revert(struct vmw_resource *res); -void vmw_kms_helper_resource_finish(struct vmw_resource *res, + bool interruptible, + struct vmw_validation_ctx *ctx); +void vmw_kms_helper_resource_revert(struct vmw_validation_ctx *ctx); +void vmw_kms_helper_resource_finish(struct vmw_validation_ctx *ctx, struct vmw_fence_obj **out_fence); int vmw_kms_readback(struct vmw_private *dev_priv, struct drm_file *file_priv, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index f42359084adc..a6ca2185f5b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -753,12 +753,13 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer_surface *vfbs = container_of(framebuffer, typeof(*vfbs), base); struct vmw_kms_sou_surface_dirty sdirty; + struct vmw_validation_ctx ctx; int ret; if (!srf) srf = &vfbs->surface->res; - ret = vmw_kms_helper_resource_prepare(srf, true); + ret = vmw_kms_helper_resource_prepare(srf, true, &ctx); if (ret) return ret; @@ -777,7 +778,7 @@ int vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, dest_x, dest_y, num_clips, inc, &sdirty.base); - vmw_kms_helper_resource_finish(srf, out_fence); + vmw_kms_helper_resource_finish(&ctx, out_fence); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c index 94ad8d2acf9a..8b914504b857 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c @@ -977,12 +977,13 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, struct vmw_framebuffer_surface *vfbs = container_of(framebuffer, typeof(*vfbs), base); struct vmw_stdu_dirty sdirty; + struct vmw_validation_ctx ctx; int ret; if (!srf) srf = &vfbs->surface->res; - ret = vmw_kms_helper_resource_prepare(srf, true); + ret = vmw_kms_helper_resource_prepare(srf, true, &ctx); if (ret) return ret; @@ -1005,7 +1006,7 @@ int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, dest_x, dest_y, num_clips, inc, &sdirty.base); out_finish: - vmw_kms_helper_resource_finish(srf, out_fence); + vmw_kms_helper_resource_finish(&ctx, out_fence); return ret; } -- GitLab From e664e6d66380d53e5e468d0f1318df4516a3be25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michel=20D=C3=A4nzer?= Date: Wed, 14 Mar 2018 18:14:04 +0100 Subject: [PATCH 0795/1834] drm/radeon: Don't turn off DP sink when disconnected MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 2681bc79eeb640562c932007bfebbbdc55bf6a7d upstream. Turning off the sink in this case causes various issues, because userspace expects it to stay on until it turns it off explicitly. Instead, turn the sink off and back on when a display is connected again. This dance seems necessary for link training to work correctly. Bugzilla: https://bugs.freedesktop.org/105308 Cc: stable@vger.kernel.org Reviewed-by: Alex Deucher Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_connectors.c | 31 +++++++++------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index af0d7fd5706b..f416f5c2e8e9 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -90,25 +90,18 @@ void radeon_connector_hotplug(struct drm_connector *connector) /* don't do anything if sink is not display port, i.e., * passive dp->(dvi|hdmi) adaptor */ - if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) { - int saved_dpms = connector->dpms; - /* Only turn off the display if it's physically disconnected */ - if (!radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); - } else if (radeon_dp_needs_link_train(radeon_connector)) { - /* Don't try to start link training before we - * have the dpcd */ - if (!radeon_dp_getdpcd(radeon_connector)) - return; - - /* set it to OFF so that drm_helper_connector_dpms() - * won't return immediately since the current state - * is ON at this point. - */ - connector->dpms = DRM_MODE_DPMS_OFF; - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); - } - connector->dpms = saved_dpms; + if (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT && + radeon_hpd_sense(rdev, radeon_connector->hpd.hpd) && + radeon_dp_needs_link_train(radeon_connector)) { + /* Don't start link training before we have the DPCD */ + if (!radeon_dp_getdpcd(radeon_connector)) + return; + + /* Turn the connector off and back on immediately, which + * will trigger link training + */ + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF); + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); } } } -- GitLab From 4ac9ab4f5f45d1ad0585c7bfa9ccff43b9984045 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 21 Mar 2018 16:45:53 +0100 Subject: [PATCH 0796/1834] drm: udl: Properly check framebuffer mmap offsets commit 3b82a4db8eaccce735dffd50b4d4e1578099b8e8 upstream. The memmap options sent to the udl framebuffer driver were not being checked for all sets of possible crazy values. Fix this up by properly bounding the allowed values. Reported-by: Eyal Itkin Cc: stable Signed-off-by: Greg Kroah-Hartman Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20180321154553.GA18454@kroah.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/udl/udl_fb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 611b6b9bb3cb..67ea2ce03a23 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -158,10 +158,15 @@ static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long offset; unsigned long page, pos; - if (offset + size > info->fix.smem_len) + if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) + return -EINVAL; + + offset = vma->vm_pgoff << PAGE_SHIFT; + + if (offset > info->fix.smem_len || size > info->fix.smem_len - offset) return -EINVAL; pos = (unsigned long)info->fix.smem_start + offset; -- GitLab From f33db316d0f531f18659a240ffeda9d910446370 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Mar 2018 19:49:14 -0700 Subject: [PATCH 0797/1834] acpi, numa: fix pxm to online numa node associations commit dc9e0a9347e932e3fd3cd03e7ff241022ed6ea8a upstream. Commit 99759869faf1 "acpi: Add acpi_map_pxm_to_online_node()" added support for mapping a given proximity to its nearest, by SLIT distance, online node. However, it sometimes returns unexpected results due to the fact that it switches from comparing the PXM node to the last node that was closer than the current max. for_each_online_node(n) { dist = node_distance(node, n); if (dist < min_dist) { min_dist = dist; node = n; <---- from this point we're using the wrong node for node_distance() Fixes: 99759869faf1 ("acpi: Add acpi_map_pxm_to_online_node()") Cc: Reviewed-by: Toshi Kani Acked-by: Rafael J. Wysocki > Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/numa.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index ce3a7a16f03f..17b518cb787c 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -103,25 +103,27 @@ int acpi_map_pxm_to_node(int pxm) */ int acpi_map_pxm_to_online_node(int pxm) { - int node, n, dist, min_dist; + int node, min_node; node = acpi_map_pxm_to_node(pxm); if (node == NUMA_NO_NODE) node = 0; + min_node = node; if (!node_online(node)) { - min_dist = INT_MAX; + int min_dist = INT_MAX, dist, n; + for_each_online_node(n) { dist = node_distance(node, n); if (dist < min_dist) { min_dist = dist; - node = n; + min_node = n; } } } - return node; + return min_node; } EXPORT_SYMBOL(acpi_map_pxm_to_online_node); -- GitLab From d0826ba87dedab9abd3f2628cc9fbee3f413bd4f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 19 Mar 2018 14:51:49 +0100 Subject: [PATCH 0798/1834] ACPI / watchdog: Fix off-by-one error at resource assignment commit b1abf6fc49829d89660c961fafe3f90f3d843c55 upstream. The resource allocation in WDAT watchdog has off-one-by error, it sets one byte more than the actual end address. This may eventually lead to unexpected resource conflicts. Fixes: 058dfc767008 (ACPI / watchdog: Add support for WDAT hardware watchdog) Cc: 4.9+ # 4.9+ Signed-off-by: Takashi Iwai Acked-by: Mika Westerberg Acked-by: Guenter Roeck Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_watchdog.c | 4 ++-- drivers/watchdog/wdat_wdt.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index 13caebd679f5..ce8fc680785b 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -74,10 +74,10 @@ void __init acpi_watchdog_init(void) res.start = gas->address; if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { res.flags = IORESOURCE_MEM; - res.end = res.start + ALIGN(gas->access_width, 4); + res.end = res.start + ALIGN(gas->access_width, 4) - 1; } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { res.flags = IORESOURCE_IO; - res.end = res.start + gas->access_width; + res.end = res.start + gas->access_width - 1; } else { pr_warn("Unsupported address space: %u\n", gas->space_id); diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index 6d1fbda0f461..0da9943d405f 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -392,7 +392,7 @@ static int wdat_wdt_probe(struct platform_device *pdev) memset(&r, 0, sizeof(r)); r.start = gas->address; - r.end = r.start + gas->access_width; + r.end = r.start + gas->access_width - 1; if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { r.flags = IORESOURCE_MEM; } else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { -- GitLab From 6fa877d2aca8da2f597c3a97355f7b4d8690dc1e Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Mon, 5 Mar 2018 16:56:13 -0700 Subject: [PATCH 0799/1834] libnvdimm, {btt, blk}: do integrity setup before add_disk() commit 3ffb0ba9b567a8efb9a04ed3d1ec15ff333ada22 upstream. Prior to 25520d55cdb6 ("block: Inline blk_integrity in struct gendisk") we needed to temporarily add a zero-capacity disk before registering for blk-integrity. But adding a zero-capacity disk caused the partition table scanning to bail early, and this resulted in partitions not coming up after a probe of the BTT or blk namespaces. We can now register for integrity before the disk has been added, and this fixes the rescan problems. Fixes: 25520d55cdb6 ("block: Inline blk_integrity in struct gendisk") Reported-by: Dariusz Dokupil Cc: Signed-off-by: Vishal Verma Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/nvdimm/blk.c | 3 +-- drivers/nvdimm/btt.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c index 9faaa9694d87..77db9795510f 100644 --- a/drivers/nvdimm/blk.c +++ b/drivers/nvdimm/blk.c @@ -286,8 +286,6 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk) disk->queue = q; disk->flags = GENHD_FL_EXT_DEVT; nvdimm_namespace_disk_name(&nsblk->common, disk->disk_name); - set_capacity(disk, 0); - device_add_disk(dev, disk); if (devm_add_action_or_reset(dev, nd_blk_release_disk, disk)) return -ENOMEM; @@ -300,6 +298,7 @@ static int nsblk_attach_disk(struct nd_namespace_blk *nsblk) } set_capacity(disk, available_disk_size >> SECTOR_SHIFT); + device_add_disk(dev, disk); revalidate_disk(disk); return 0; } diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 7121453ec047..0c46ada027cf 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -1392,8 +1392,6 @@ static int btt_blk_init(struct btt *btt) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, btt->btt_queue); btt->btt_queue->queuedata = btt; - set_capacity(btt->btt_disk, 0); - device_add_disk(&btt->nd_btt->dev, btt->btt_disk); if (btt_meta_size(btt)) { int rc = nd_integrity_init(btt->btt_disk, btt_meta_size(btt)); @@ -1405,6 +1403,7 @@ static int btt_blk_init(struct btt *btt) } } set_capacity(btt->btt_disk, btt->nlba * btt->sector_size >> 9); + device_add_disk(&btt->nd_btt->dev, btt->btt_disk); btt->nd_btt->size = btt->nlba * (u64)btt->sector_size; revalidate_disk(btt->btt_disk); -- GitLab From 0a9be1b13232aa76c5561513415029da4e513f75 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Wed, 28 Feb 2018 21:15:20 +0100 Subject: [PATCH 0800/1834] brcmfmac: fix P2P_DEVICE ethernet address generation commit 455f3e76cfc0d893585a5f358b9ddbe9c1e1e53b upstream. The firmware has a requirement that the P2P_DEVICE address should be different from the address of the primary interface. When not specified by user-space, the driver generates the MAC address for the P2P_DEVICE interface using the MAC address of the primary interface and setting the locally administered bit. However, the MAC address of the primary interface may already have that bit set causing the creation of the P2P_DEVICE interface to fail with -EBUSY. Fix this by using a random address instead to determine the P2P_DEVICE address. Cc: stable@vger.kernel.org # 3.10.y Reported-by: Hans de Goede Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- .../broadcom/brcm80211/brcmfmac/p2p.c | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 85d949e03f79..f78d91b69287 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -462,25 +462,23 @@ static int brcmf_p2p_set_firmware(struct brcmf_if *ifp, u8 *p2p_mac) * @dev_addr: optional device address. * * P2P needs mac addresses for P2P device and interface. If no device - * address it specified, these are derived from the primary net device, ie. - * the permanent ethernet address of the device. + * address it specified, these are derived from a random ethernet + * address. */ static void brcmf_p2p_generate_bss_mac(struct brcmf_p2p_info *p2p, u8 *dev_addr) { - struct brcmf_if *pri_ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp; - bool local_admin = false; + bool random_addr = false; - if (!dev_addr || is_zero_ether_addr(dev_addr)) { - dev_addr = pri_ifp->mac_addr; - local_admin = true; - } + if (!dev_addr || is_zero_ether_addr(dev_addr)) + random_addr = true; - /* Generate the P2P Device Address. This consists of the device's - * primary MAC address with the locally administered bit set. + /* Generate the P2P Device Address obtaining a random ethernet + * address with the locally administered bit set. */ - memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); - if (local_admin) - p2p->dev_addr[0] |= 0x02; + if (random_addr) + eth_random_addr(p2p->dev_addr); + else + memcpy(p2p->dev_addr, dev_addr, ETH_ALEN); /* Generate the P2P Interface Address. If the discovery and connection * BSSCFGs need to simultaneously co-exist, then this address must be -- GitLab From 0e17fddb648afe74a4fc94789b7b70cf854e8903 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Thu, 22 Feb 2018 14:28:59 -0600 Subject: [PATCH 0801/1834] rtlwifi: rtl8723be: Fix loss of signal commit 78dc897b7ee67205423dbbc6b56be49fb18d15b5 upstream. In commit c713fb071edc ("rtlwifi: rtl8821ae: Fix connection lost problem correctly") a problem in rtl8821ae that caused loss of signal was fixed. That same problem has now been reported for rtl8723be. Accordingly, the ASPM L1 latency has been increased from 0 to 7 to fix the instability. Signed-off-by: Larry Finger Cc: Stable Tested-by: James Cameron Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index aba60c3145c5..618e509e75d6 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -1125,7 +1125,8 @@ static void _rtl8723be_enable_aspm_back_door(struct ieee80211_hw *hw) /* Configuration Space offset 0x70f BIT7 is used to control L0S */ tmp8 = _rtl8723be_dbi_read(rtlpriv, 0x70f); - _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7)); + _rtl8723be_dbi_write(rtlpriv, 0x70f, tmp8 | BIT(7) | + ASPM_L1_LATENCY << 3); /* Configuration Space offset 0x719 Bit3 is for L1 * BIT4 is for clock request -- GitLab From d434dae76129e2466dd1dab294ed0acc8e49939e Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 17 Mar 2018 21:38:10 +0900 Subject: [PATCH 0802/1834] tracing: probeevent: Fix to support minus offset from symbol commit c5d343b6b7badd1f5fe0873eff2e8d63a193e732 upstream. In Documentation/trace/kprobetrace.txt, it says @SYM[+|-offs] : Fetch memory at SYM +|- offs (SYM should be a data symbol) However, the parser doesn't parse minus offset correctly, since commit 2fba0c8867af ("tracing/kprobes: Fix probe offset to be unsigned") drops minus ("-") offset support for kprobe probe address usage. This fixes the traceprobe_split_symbol_offset() to parse minus offset again with checking the offset range, and add a minus offset check in kprobe probe address usage. Link: http://lkml.kernel.org/r/152129028983.31874.13419301530285775521.stgit@devbox Cc: Ingo Molnar Cc: Tom Zanussi Cc: Arnaldo Carvalho de Melo Cc: Ravi Bangoria Cc: stable@vger.kernel.org Fixes: 2fba0c8867af ("tracing/kprobes: Fix probe offset to be unsigned") Acked-by: Namhyung Kim Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) Signed-off-by: Greg Kroah-Hartman --- kernel/trace/trace_kprobe.c | 4 ++-- kernel/trace/trace_probe.c | 8 +++----- kernel/trace/trace_probe.h | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 5ff45cae4ac4..ea3ed03fed7e 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -607,7 +607,7 @@ static int create_trace_kprobe(int argc, char **argv) bool is_return = false, is_delete = false; char *symbol = NULL, *event = NULL, *group = NULL; char *arg; - unsigned long offset = 0; + long offset = 0; void *addr = NULL; char buf[MAX_EVENT_NAME_LEN]; @@ -675,7 +675,7 @@ static int create_trace_kprobe(int argc, char **argv) symbol = argv[1]; /* TODO: support .init module functions */ ret = traceprobe_split_symbol_offset(symbol, &offset); - if (ret) { + if (ret || offset < 0 || offset > UINT_MAX) { pr_info("Failed to parse either an address or a symbol.\n"); return ret; } diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 8c0553d9afd3..5ea191b917e9 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c @@ -319,7 +319,7 @@ static fetch_func_t get_fetch_size_function(const struct fetch_type *type, } /* Split symbol and offset. */ -int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset) +int traceprobe_split_symbol_offset(char *symbol, long *offset) { char *tmp; int ret; @@ -327,13 +327,11 @@ int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset) if (!offset) return -EINVAL; - tmp = strchr(symbol, '+'); + tmp = strpbrk(symbol, "+-"); if (tmp) { - /* skip sign because kstrtoul doesn't accept '+' */ - ret = kstrtoul(tmp + 1, 0, offset); + ret = kstrtol(tmp, 0, offset); if (ret) return ret; - *tmp = '\0'; } else *offset = 0; diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h index 0c0ae54d44c6..2b84c0de92c7 100644 --- a/kernel/trace/trace_probe.h +++ b/kernel/trace/trace_probe.h @@ -354,7 +354,7 @@ extern int traceprobe_conflict_field_name(const char *name, extern void traceprobe_update_arg(struct probe_arg *arg); extern void traceprobe_free_probe_arg(struct probe_arg *arg); -extern int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset); +extern int traceprobe_split_symbol_offset(char *symbol, long *offset); extern ssize_t traceprobe_probes_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos, -- GitLab From 9eab80eded7bb767f2f0770b3380e6affd3dc2c5 Mon Sep 17 00:00:00 2001 From: OuYang ZhiZhong Date: Sun, 11 Mar 2018 15:59:07 +0800 Subject: [PATCH 0803/1834] mtdchar: fix usage of mtd_ooblayout_ecc() commit 6de564939e14327148e31ddcf769e34105176447 upstream. Section was not properly computed. The value of OOB region definition is always ECC section 0 information in the OOB area, but we want to get all the ECC bytes information, so we should call mtd_ooblayout_ecc(mtd, section++, &oobregion) until it returns -ERANGE. Fixes: c2b78452a9db ("mtd: use mtd_ooblayout_xxx() helpers where appropriate") Cc: Signed-off-by: OuYang ZhiZhong Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/mtdchar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 2a47a3f0e730..b4092eab53ac 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -487,7 +487,7 @@ static int shrink_ecclayout(struct mtd_info *mtd, for (i = 0; i < MTD_MAX_ECCPOS_ENTRIES;) { u32 eccpos; - ret = mtd_ooblayout_ecc(mtd, section, &oobregion); + ret = mtd_ooblayout_ecc(mtd, section++, &oobregion); if (ret < 0) { if (ret != -ERANGE) return ret; @@ -534,7 +534,7 @@ static int get_oobinfo(struct mtd_info *mtd, struct nand_oobinfo *to) for (i = 0; i < ARRAY_SIZE(to->eccpos);) { u32 eccpos; - ret = mtd_ooblayout_ecc(mtd, section, &oobregion); + ret = mtd_ooblayout_ecc(mtd, section++, &oobregion); if (ret < 0) { if (ret != -ERANGE) return ret; -- GitLab From 9b5dd849509b3df53d0b98eac79d86cdeb54ef2c Mon Sep 17 00:00:00 2001 From: Jagdish Gediya Date: Wed, 21 Mar 2018 04:31:36 +0530 Subject: [PATCH 0804/1834] mtd: nand: fsl_ifc: Fix nand waitfunc return value commit fa8e6d58c5bc260f4369c6699683d69695daed0a upstream. As per the IFC hardware manual, Most significant 2 bytes in nand_fsr register are the outcome of NAND READ STATUS command. So status value need to be shifted and aligned as per the nand framework requirement. Fixes: 82771882d960 ("NAND Machine support for Integrated Flash Controller") Cc: stable@vger.kernel.org # v3.18+ Signed-off-by: Jagdish Gediya Reviewed-by: Prabhakar Kushwaha Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/fsl_ifc_nand.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index f8f12ccc6471..a4d78c57b1e1 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -656,6 +656,7 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs; u32 nand_fsr; + int status; /* Use READ_STATUS command, but wait for the device to be ready */ ifc_out32((IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | @@ -670,12 +671,12 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) fsl_ifc_run_command(mtd); nand_fsr = ifc_in32(&ifc->ifc_nand.nand_fsr); - + status = nand_fsr >> 24; /* * The chip always seems to report that it is * write-protected, even when it is not. */ - return nand_fsr | NAND_STATUS_WP; + return status | NAND_STATUS_WP; } static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, -- GitLab From eca95cb6b47a4190d3cf110d51ba186eb40e3a44 Mon Sep 17 00:00:00 2001 From: Jagdish Gediya Date: Wed, 21 Mar 2018 05:51:46 +0530 Subject: [PATCH 0805/1834] mtd: nand: fsl_ifc: Fix eccstat array overflow for IFC ver >= 2.0.0 commit 843c3a59997f18060848b8632607dd04781b52d1 upstream. Number of ECC status registers i.e. (ECCSTATx) has been increased in IFC version 2.0.0 due to increase in SRAM size. This is causing eccstat array to over flow. So, replace eccstat array with u32 variable to make it fail-safe and independent of number of ECC status registers or SRAM size. Fixes: bccb06c353af ("mtd: nand: ifc: update bufnum mask for ver >= 2.0.0") Cc: stable@vger.kernel.org # 3.18+ Signed-off-by: Prabhakar Kushwaha Signed-off-by: Jagdish Gediya Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/fsl_ifc_nand.c | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index a4d78c57b1e1..97e6f37a742e 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -201,14 +201,9 @@ static int is_blank(struct mtd_info *mtd, unsigned int bufnum) /* returns nonzero if entire page is blank */ static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, - u32 *eccstat, unsigned int bufnum) + u32 eccstat, unsigned int bufnum) { - u32 reg = eccstat[bufnum / 4]; - int errors; - - errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; - - return errors; + return (eccstat >> ((3 - bufnum % 4) * 8)) & 15; } /* @@ -221,7 +216,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) struct fsl_ifc_ctrl *ctrl = priv->ctrl; struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; struct fsl_ifc_runtime __iomem *ifc = ctrl->rregs; - u32 eccstat[4]; + u32 eccstat; int i; /* set the chip select for NAND Transaction */ @@ -256,8 +251,8 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) if (nctrl->eccread) { int errors; int bufnum = nctrl->page & priv->bufnum_mask; - int sector = bufnum * chip->ecc.steps; - int sector_end = sector + chip->ecc.steps - 1; + int sector_start = bufnum * chip->ecc.steps; + int sector_end = sector_start + chip->ecc.steps - 1; __be32 *eccstat_regs; if (ctrl->version >= FSL_IFC_VERSION_2_0_0) @@ -265,10 +260,12 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) else eccstat_regs = ifc->ifc_nand.v1_nand_eccstat; - for (i = sector / 4; i <= sector_end / 4; i++) - eccstat[i] = ifc_in32(&eccstat_regs[i]); + eccstat = ifc_in32(&eccstat_regs[sector_start / 4]); + + for (i = sector_start; i <= sector_end; i++) { + if (i != sector_start && !(i % 4)) + eccstat = ifc_in32(&eccstat_regs[i / 4]); - for (i = sector; i <= sector_end; i++) { errors = check_read_ecc(mtd, ctrl, eccstat, i); if (errors == 15) { -- GitLab From 4d9ed68855f0844af153d70424e9e6160fe6f61c Mon Sep 17 00:00:00 2001 From: Jagdish Gediya Date: Thu, 22 Mar 2018 01:08:10 +0530 Subject: [PATCH 0806/1834] mtd: nand: fsl_ifc: Read ECCSTAT0 and ECCSTAT1 registers for IFC 2.0 commit 6b00c35138b404be98b85f4a703be594cbed501c upstream. Due to missing information in Hardware manual, current implementation doesn't read ECCSTAT0 and ECCSTAT1 registers for IFC 2.0. Add support to read ECCSTAT0 and ECCSTAT1 registers during ecccheck for IFC 2.0. Fixes: 656441478ed5 ("mtd: nand: ifc: Fix location of eccstat registers for IFC V1.0") Cc: stable@vger.kernel.org # v3.18+ Signed-off-by: Jagdish Gediya Reviewed-by: Prabhakar Kushwaha Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/fsl_ifc_nand.c | 6 +----- include/linux/fsl_ifc.h | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 97e6f37a742e..2f6b55229d5b 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -255,11 +255,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) int sector_end = sector_start + chip->ecc.steps - 1; __be32 *eccstat_regs; - if (ctrl->version >= FSL_IFC_VERSION_2_0_0) - eccstat_regs = ifc->ifc_nand.v2_nand_eccstat; - else - eccstat_regs = ifc->ifc_nand.v1_nand_eccstat; - + eccstat_regs = ifc->ifc_nand.nand_eccstat; eccstat = ifc_in32(&eccstat_regs[sector_start / 4]); for (i = sector_start; i <= sector_end; i++) { diff --git a/include/linux/fsl_ifc.h b/include/linux/fsl_ifc.h index c332f0a45607..3fdfede2f0f3 100644 --- a/include/linux/fsl_ifc.h +++ b/include/linux/fsl_ifc.h @@ -734,11 +734,7 @@ struct fsl_ifc_nand { u32 res19[0x10]; __be32 nand_fsr; u32 res20; - /* The V1 nand_eccstat is actually 4 words that overlaps the - * V2 nand_eccstat. - */ - __be32 v1_nand_eccstat[2]; - __be32 v2_nand_eccstat[6]; + __be32 nand_eccstat[8]; u32 res21[0x1c]; __be32 nanndcr; u32 res22[0x2]; -- GitLab From 5e7124c4d6786488198b192f90491e5a5ba51230 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 19 Mar 2018 14:07:45 +0300 Subject: [PATCH 0807/1834] staging: ncpfs: memory corruption in ncp_read_kernel() commit 4c41aa24baa4ed338241d05494f2c595c885af8f upstream. If the server is malicious then *bytes_read could be larger than the size of the "target" buffer. It would lead to memory corruption when we do the memcpy(). Reported-by: Dr Silvio Cesare of InfoSect Signed-off-by: Dan Carpenter Cc: stable Signed-off-by: Greg Kroah-Hartman --- fs/ncpfs/ncplib_kernel.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index 88dbbc9fcf4d..f571570a2e72 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -980,6 +980,10 @@ ncp_read_kernel(struct ncp_server *server, const char *file_id, goto out; } *bytes_read = ncp_reply_be16(server, 0); + if (*bytes_read > to_read) { + result = -EINVAL; + goto out; + } source = ncp_reply_data(server, 2 + (offset & 1)); memcpy(target, source, *bytes_read); -- GitLab From a452b356c58cdec58ff3a628be725755b0715540 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 1 Mar 2018 19:34:00 +0100 Subject: [PATCH 0808/1834] can: ifi: Repair the error handling commit 880dd464b4304583c557c4e5f5ecebfd55d232b1 upstream. The new version of the IFI CANFD core has significantly less complex error state indication logic. In particular, the warning/error state bits are no longer all over the place, but are all present in the STATUS register. Moreover, there is a new IRQ register bit indicating transition between error states (active/warning/passive/busoff). This patch makes use of this bit to weed out the obscure selective INTERRUPT register clearing, which was used to carry over the error state indication into the poll function. While at it, this patch fixes the handling of the ACTIVE state, since the hardware provides indication of the core being in ACTIVE state and that in turn fixes the state transition indication toward userspace. Finally, register reads in the poll function are moved to the matching subfunctions since those are also no longer needed in the poll function. Signed-off-by: Marek Vasut Cc: Heiko Schocher Cc: Markus Marb Cc: Marc Kleine-Budde Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/ifi_canfd/ifi_canfd.c | 64 ++++++++++++++++----------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index c06ef438f23f..acfa7bfb98af 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -30,6 +30,7 @@ #define IFI_CANFD_STCMD_ERROR_ACTIVE BIT(2) #define IFI_CANFD_STCMD_ERROR_PASSIVE BIT(3) #define IFI_CANFD_STCMD_BUSOFF BIT(4) +#define IFI_CANFD_STCMD_ERROR_WARNING BIT(5) #define IFI_CANFD_STCMD_BUSMONITOR BIT(16) #define IFI_CANFD_STCMD_LOOPBACK BIT(18) #define IFI_CANFD_STCMD_DISABLE_CANFD BIT(24) @@ -52,7 +53,10 @@ #define IFI_CANFD_TXSTCMD_OVERFLOW BIT(13) #define IFI_CANFD_INTERRUPT 0xc +#define IFI_CANFD_INTERRUPT_ERROR_BUSOFF BIT(0) #define IFI_CANFD_INTERRUPT_ERROR_WARNING BIT(1) +#define IFI_CANFD_INTERRUPT_ERROR_STATE_CHG BIT(2) +#define IFI_CANFD_INTERRUPT_ERROR_REC_TEC_INC BIT(3) #define IFI_CANFD_INTERRUPT_ERROR_COUNTER BIT(10) #define IFI_CANFD_INTERRUPT_TXFIFO_EMPTY BIT(16) #define IFI_CANFD_INTERRUPT_TXFIFO_REMOVE BIT(22) @@ -61,6 +65,10 @@ #define IFI_CANFD_INTERRUPT_SET_IRQ ((u32)BIT(31)) #define IFI_CANFD_IRQMASK 0x10 +#define IFI_CANFD_IRQMASK_ERROR_BUSOFF BIT(0) +#define IFI_CANFD_IRQMASK_ERROR_WARNING BIT(1) +#define IFI_CANFD_IRQMASK_ERROR_STATE_CHG BIT(2) +#define IFI_CANFD_IRQMASK_ERROR_REC_TEC_INC BIT(3) #define IFI_CANFD_IRQMASK_SET_ERR BIT(7) #define IFI_CANFD_IRQMASK_SET_TS BIT(15) #define IFI_CANFD_IRQMASK_TXFIFO_EMPTY BIT(16) @@ -220,7 +228,10 @@ static void ifi_canfd_irq_enable(struct net_device *ndev, bool enable) if (enable) { enirq = IFI_CANFD_IRQMASK_TXFIFO_EMPTY | - IFI_CANFD_IRQMASK_RXFIFO_NEMPTY; + IFI_CANFD_IRQMASK_RXFIFO_NEMPTY | + IFI_CANFD_IRQMASK_ERROR_STATE_CHG | + IFI_CANFD_IRQMASK_ERROR_WARNING | + IFI_CANFD_IRQMASK_ERROR_BUSOFF; if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) enirq |= IFI_CANFD_INTERRUPT_ERROR_COUNTER; } @@ -361,12 +372,13 @@ static int ifi_canfd_handle_lost_msg(struct net_device *ndev) return 1; } -static int ifi_canfd_handle_lec_err(struct net_device *ndev, const u32 errctr) +static int ifi_canfd_handle_lec_err(struct net_device *ndev) { struct ifi_canfd_priv *priv = netdev_priv(ndev); struct net_device_stats *stats = &ndev->stats; struct can_frame *cf; struct sk_buff *skb; + u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR); const u32 errmask = IFI_CANFD_ERROR_CTR_OVERLOAD_FIRST | IFI_CANFD_ERROR_CTR_ACK_ERROR_FIRST | IFI_CANFD_ERROR_CTR_BIT0_ERROR_FIRST | @@ -449,6 +461,11 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev, switch (new_state) { case CAN_STATE_ERROR_ACTIVE: + /* error active state */ + priv->can.can_stats.error_warning++; + priv->can.state = CAN_STATE_ERROR_ACTIVE; + break; + case CAN_STATE_ERROR_WARNING: /* error warning state */ priv->can.can_stats.error_warning++; priv->can.state = CAN_STATE_ERROR_WARNING; @@ -477,7 +494,7 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev, ifi_canfd_get_berr_counter(ndev, &bec); switch (new_state) { - case CAN_STATE_ERROR_ACTIVE: + case CAN_STATE_ERROR_WARNING: /* error warning state */ cf->can_id |= CAN_ERR_CRTL; cf->data[1] = (bec.txerr > bec.rxerr) ? @@ -510,22 +527,21 @@ static int ifi_canfd_handle_state_change(struct net_device *ndev, return 1; } -static int ifi_canfd_handle_state_errors(struct net_device *ndev, u32 stcmd) +static int ifi_canfd_handle_state_errors(struct net_device *ndev) { struct ifi_canfd_priv *priv = netdev_priv(ndev); + u32 stcmd = readl(priv->base + IFI_CANFD_STCMD); int work_done = 0; - u32 isr; - /* - * The ErrWarn condition is a little special, since the bit is - * located in the INTERRUPT register instead of STCMD register. - */ - isr = readl(priv->base + IFI_CANFD_INTERRUPT); - if ((isr & IFI_CANFD_INTERRUPT_ERROR_WARNING) && + if ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) && + (priv->can.state != CAN_STATE_ERROR_ACTIVE)) { + netdev_dbg(ndev, "Error, entered active state\n"); + work_done += ifi_canfd_handle_state_change(ndev, + CAN_STATE_ERROR_ACTIVE); + } + + if ((stcmd & IFI_CANFD_STCMD_ERROR_WARNING) && (priv->can.state != CAN_STATE_ERROR_WARNING)) { - /* Clear the interrupt */ - writel(IFI_CANFD_INTERRUPT_ERROR_WARNING, - priv->base + IFI_CANFD_INTERRUPT); netdev_dbg(ndev, "Error, entered warning state\n"); work_done += ifi_canfd_handle_state_change(ndev, CAN_STATE_ERROR_WARNING); @@ -552,18 +568,11 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota) { struct net_device *ndev = napi->dev; struct ifi_canfd_priv *priv = netdev_priv(ndev); - const u32 stcmd_state_mask = IFI_CANFD_STCMD_ERROR_PASSIVE | - IFI_CANFD_STCMD_BUSOFF; - int work_done = 0; - - u32 stcmd = readl(priv->base + IFI_CANFD_STCMD); u32 rxstcmd = readl(priv->base + IFI_CANFD_RXSTCMD); - u32 errctr = readl(priv->base + IFI_CANFD_ERROR_CTR); + int work_done = 0; /* Handle bus state changes */ - if ((stcmd & stcmd_state_mask) || - ((stcmd & IFI_CANFD_STCMD_ERROR_ACTIVE) == 0)) - work_done += ifi_canfd_handle_state_errors(ndev, stcmd); + work_done += ifi_canfd_handle_state_errors(ndev); /* Handle lost messages on RX */ if (rxstcmd & IFI_CANFD_RXSTCMD_OVERFLOW) @@ -571,7 +580,7 @@ static int ifi_canfd_poll(struct napi_struct *napi, int quota) /* Handle lec errors on the bus */ if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) - work_done += ifi_canfd_handle_lec_err(ndev, errctr); + work_done += ifi_canfd_handle_lec_err(ndev); /* Handle normal messages on RX */ if (!(rxstcmd & IFI_CANFD_RXSTCMD_EMPTY)) @@ -592,12 +601,13 @@ static irqreturn_t ifi_canfd_isr(int irq, void *dev_id) struct net_device_stats *stats = &ndev->stats; const u32 rx_irq_mask = IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY | IFI_CANFD_INTERRUPT_RXFIFO_NEMPTY_PER | + IFI_CANFD_INTERRUPT_ERROR_COUNTER | + IFI_CANFD_INTERRUPT_ERROR_STATE_CHG | IFI_CANFD_INTERRUPT_ERROR_WARNING | - IFI_CANFD_INTERRUPT_ERROR_COUNTER; + IFI_CANFD_INTERRUPT_ERROR_BUSOFF; const u32 tx_irq_mask = IFI_CANFD_INTERRUPT_TXFIFO_EMPTY | IFI_CANFD_INTERRUPT_TXFIFO_REMOVE; - const u32 clr_irq_mask = ~((u32)(IFI_CANFD_INTERRUPT_SET_IRQ | - IFI_CANFD_INTERRUPT_ERROR_WARNING)); + const u32 clr_irq_mask = ~((u32)IFI_CANFD_INTERRUPT_SET_IRQ); u32 isr; isr = readl(priv->base + IFI_CANFD_INTERRUPT); -- GitLab From 6e400b460a92fd662548edd23d819fd5cc11b208 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 5 Mar 2018 21:29:52 +0100 Subject: [PATCH 0809/1834] can: ifi: Check core revision upon probe commit 591d65d5b15496af8d05e252bc1da611c66c0b79 upstream. Older versions of the core are not compatible with the driver due to various intrusive fixes of the core. Read out the VER register, check the core revision bitfield and verify if the core in use is new enough (rev 2.1 or newer) to work correctly with this driver. Signed-off-by: Marek Vasut Cc: Heiko Schocher Cc: Markus Marb Cc: Marc Kleine-Budde Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/ifi_canfd/ifi_canfd.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/can/ifi_canfd/ifi_canfd.c b/drivers/net/can/ifi_canfd/ifi_canfd.c index acfa7bfb98af..6c676403f823 100644 --- a/drivers/net/can/ifi_canfd/ifi_canfd.c +++ b/drivers/net/can/ifi_canfd/ifi_canfd.c @@ -144,6 +144,8 @@ #define IFI_CANFD_SYSCLOCK 0x50 #define IFI_CANFD_VER 0x54 +#define IFI_CANFD_VER_REV_MASK 0xff +#define IFI_CANFD_VER_REV_MIN_SUPPORTED 0x15 #define IFI_CANFD_IP_ID 0x58 #define IFI_CANFD_IP_ID_VALUE 0xD073CAFD @@ -943,7 +945,7 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) struct resource *res; void __iomem *addr; int irq, ret; - u32 id; + u32 id, rev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); addr = devm_ioremap_resource(dev, res); @@ -957,6 +959,13 @@ static int ifi_canfd_plat_probe(struct platform_device *pdev) return -EINVAL; } + rev = readl(addr + IFI_CANFD_VER) & IFI_CANFD_VER_REV_MASK; + if (rev < IFI_CANFD_VER_REV_MIN_SUPPORTED) { + dev_err(dev, "This block is too old (rev %i), minimum supported is rev %i\n", + rev, IFI_CANFD_VER_REV_MIN_SUPPORTED); + return -EINVAL; + } + ndev = alloc_candev(sizeof(*priv), 1); if (!ndev) return -ENOMEM; -- GitLab From 01a303d27a9c5fc80d7bdf2f2961e9ad14b608dc Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Wed, 14 Mar 2018 11:52:56 +0000 Subject: [PATCH 0810/1834] can: cc770: Fix stalls on rt-linux, remove redundant IRQ ack commit f4353daf4905c0099fd25fa742e2ffd4a4bab26a upstream. This has been reported to cause stalls on rt-linux. Suggested-by: Richard Weinberger Tested-by: Richard Weinberger Signed-off-by: Andri Yngvason Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/cc770/cc770.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 1e37313054f3..9fed163262e0 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -447,15 +447,6 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) stats->tx_bytes += dlc; - - /* - * HM: We had some cases of repeated IRQs so make sure the - * INT is acknowledged I know it's already further up, but - * doing again fixed the issue - */ - cc770_write_reg(priv, msgobj[mo].ctrl0, - MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); - return NETDEV_TX_OK; } @@ -684,12 +675,6 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) /* Nothing more to send, switch off interrupts */ cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); - /* - * We had some cases of repeated IRQ so make sure the - * INT is acknowledged - */ - cc770_write_reg(priv, msgobj[mo].ctrl0, - MSGVAL_UNC | TXIE_UNC | RXIE_UNC | INTPND_RES); stats->tx_packets++; can_get_echo_skb(dev, 0); -- GitLab From 5fdbcc3d6db6f17ec43ef200353208a3a9cf7234 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Wed, 14 Mar 2018 11:52:57 +0000 Subject: [PATCH 0811/1834] can: cc770: Fix queue stall & dropped RTR reply commit 746201235b3f876792099079f4c6fea941d76183 upstream. While waiting for the TX object to send an RTR, an external message with a matching id can overwrite the TX data. In this case we must call the rx routine and then try transmitting the message that was overwritten again. The queue was being stalled because the RX event did not generate an interrupt to wake up the queue again and the TX event did not happen because the TXRQST flag is reset by the chip when new data is received. According to the CC770 datasheet the id of a message object should not be changed while the MSGVAL bit is set. This has been fixed by resetting the MSGVAL bit before modifying the object in the transmit function and setting it after. It is not enough to set & reset CPUUPD. It is important to keep the MSGVAL bit reset while the message object is being modified. Otherwise, during RTR transmission, a frame with matching id could trigger an rx-interrupt, which would cause a race condition between the interrupt routine and the transmit function. Signed-off-by: Andri Yngvason Tested-by: Richard Weinberger Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/cc770/cc770.c | 94 ++++++++++++++++++++++++----------- drivers/net/can/cc770/cc770.h | 2 + 2 files changed, 68 insertions(+), 28 deletions(-) diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 9fed163262e0..2743d82d4424 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -390,37 +390,23 @@ static int cc770_get_berr_counter(const struct net_device *dev, return 0; } -static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void cc770_tx(struct net_device *dev, int mo) { struct cc770_priv *priv = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; - struct can_frame *cf = (struct can_frame *)skb->data; - unsigned int mo = obj2msgobj(CC770_OBJ_TX); + struct can_frame *cf = (struct can_frame *)priv->tx_skb->data; u8 dlc, rtr; u32 id; int i; - if (can_dropped_invalid_skb(dev, skb)) - return NETDEV_TX_OK; - - if ((cc770_read_reg(priv, - msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { - netdev_err(dev, "TX register is still occupied!\n"); - return NETDEV_TX_BUSY; - } - - netif_stop_queue(dev); - dlc = cf->can_dlc; id = cf->can_id; - if (cf->can_id & CAN_RTR_FLAG) - rtr = 0; - else - rtr = MSGCFG_DIR; + rtr = cf->can_id & CAN_RTR_FLAG ? 0 : MSGCFG_DIR; + + cc770_write_reg(priv, msgobj[mo].ctrl0, + MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); cc770_write_reg(priv, msgobj[mo].ctrl1, RMTPND_RES | TXRQST_RES | CPUUPD_SET | NEWDAT_RES); - cc770_write_reg(priv, msgobj[mo].ctrl0, - MSGVAL_SET | TXIE_SET | RXIE_RES | INTPND_RES); + if (id & CAN_EFF_FLAG) { id &= CAN_EFF_MASK; cc770_write_reg(priv, msgobj[mo].config, @@ -439,13 +425,30 @@ static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) for (i = 0; i < dlc; i++) cc770_write_reg(priv, msgobj[mo].data[i], cf->data[i]); - /* Store echo skb before starting the transfer */ - can_put_echo_skb(skb, dev, 0); - cc770_write_reg(priv, msgobj[mo].ctrl1, - RMTPND_RES | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC); + RMTPND_UNC | TXRQST_SET | CPUUPD_RES | NEWDAT_UNC); + cc770_write_reg(priv, msgobj[mo].ctrl0, + MSGVAL_SET | TXIE_SET | RXIE_SET | INTPND_UNC); +} + +static netdev_tx_t cc770_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct cc770_priv *priv = netdev_priv(dev); + unsigned int mo = obj2msgobj(CC770_OBJ_TX); + + if (can_dropped_invalid_skb(dev, skb)) + return NETDEV_TX_OK; - stats->tx_bytes += dlc; + netif_stop_queue(dev); + + if ((cc770_read_reg(priv, + msgobj[mo].ctrl1) & TXRQST_UNC) == TXRQST_SET) { + netdev_err(dev, "TX register is still occupied!\n"); + return NETDEV_TX_BUSY; + } + + priv->tx_skb = skb; + cc770_tx(dev, mo); return NETDEV_TX_OK; } @@ -671,13 +674,47 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) struct cc770_priv *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; unsigned int mo = obj2msgobj(o); + struct can_frame *cf; + u8 ctrl1; + + ctrl1 = cc770_read_reg(priv, msgobj[mo].ctrl1); - /* Nothing more to send, switch off interrupts */ cc770_write_reg(priv, msgobj[mo].ctrl0, MSGVAL_RES | TXIE_RES | RXIE_RES | INTPND_RES); + cc770_write_reg(priv, msgobj[mo].ctrl1, + RMTPND_RES | TXRQST_RES | MSGLST_RES | NEWDAT_RES); - stats->tx_packets++; + if (unlikely(!priv->tx_skb)) { + netdev_err(dev, "missing tx skb in tx interrupt\n"); + return; + } + + if (unlikely(ctrl1 & MSGLST_SET)) { + stats->rx_over_errors++; + stats->rx_errors++; + } + + /* When the CC770 is sending an RTR message and it receives a regular + * message that matches the id of the RTR message, it will overwrite the + * outgoing message in the TX register. When this happens we must + * process the received message and try to transmit the outgoing skb + * again. + */ + if (unlikely(ctrl1 & NEWDAT_SET)) { + cc770_rx(dev, mo, ctrl1); + cc770_tx(dev, mo); + return; + } + + can_put_echo_skb(priv->tx_skb, dev, 0); can_get_echo_skb(dev, 0); + + cf = (struct can_frame *)priv->tx_skb->data; + stats->tx_bytes += cf->can_dlc; + stats->tx_packets++; + + priv->tx_skb = NULL; + netif_wake_queue(dev); } @@ -789,6 +826,7 @@ struct net_device *alloc_cc770dev(int sizeof_priv) priv->can.do_set_bittiming = cc770_set_bittiming; priv->can.do_set_mode = cc770_set_mode; priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; + priv->tx_skb = NULL; memcpy(priv->obj_flags, cc770_obj_flags, sizeof(cc770_obj_flags)); diff --git a/drivers/net/can/cc770/cc770.h b/drivers/net/can/cc770/cc770.h index a1739db98d91..95752e1d1283 100644 --- a/drivers/net/can/cc770/cc770.h +++ b/drivers/net/can/cc770/cc770.h @@ -193,6 +193,8 @@ struct cc770_priv { u8 cpu_interface; /* CPU interface register */ u8 clkout; /* Clock out register */ u8 bus_config; /* Bus conffiguration register */ + + struct sk_buff *tx_skb; }; struct net_device *alloc_cc770dev(int sizeof_priv); -- GitLab From 101a72edd98d2f87d112f21f81f796f584f1bd58 Mon Sep 17 00:00:00 2001 From: Andri Yngvason Date: Thu, 15 Mar 2018 18:23:17 +0000 Subject: [PATCH 0812/1834] can: cc770: Fix use after free in cc770_tx_interrupt() commit 9ffd7503944ec7c0ef41c3245d1306c221aef2be upstream. This fixes use after free introduced by the last cc770 patch. Signed-off-by: Andri Yngvason Fixes: 746201235b3f ("can: cc770: Fix queue stall & dropped RTR reply") Cc: linux-stable Signed-off-by: Marc Kleine-Budde Signed-off-by: Greg Kroah-Hartman --- drivers/net/can/cc770/cc770.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c index 2743d82d4424..6da69af103e6 100644 --- a/drivers/net/can/cc770/cc770.c +++ b/drivers/net/can/cc770/cc770.c @@ -706,13 +706,12 @@ static void cc770_tx_interrupt(struct net_device *dev, unsigned int o) return; } - can_put_echo_skb(priv->tx_skb, dev, 0); - can_get_echo_skb(dev, 0); - cf = (struct can_frame *)priv->tx_skb->data; stats->tx_bytes += cf->can_dlc; stats->tx_packets++; + can_put_echo_skb(priv->tx_skb, dev, 0); + can_get_echo_skb(dev, 0); priv->tx_skb = NULL; netif_wake_queue(dev); -- GitLab From 7c28067736a24a19e0d646fea510357228e95910 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 24 Mar 2018 10:43:26 +0100 Subject: [PATCH 0813/1834] tty: vt: fix up tabstops properly commit f1869a890cdedb92a3fab969db5d0fd982850273 upstream. Tabs on a console with long lines do not wrap properly, so correctly account for the line length when computing the tab placement location. Reported-by: James Holderness Signed-off-by: Greg Kroah-Hartman Cc: stable Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ce2c3c6349d4..68c7bb0b7991 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1727,7 +1727,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear) default_attr(vc); update_attr(vc); - vc->vc_tab_stop[0] = 0x01010100; + vc->vc_tab_stop[0] = vc->vc_tab_stop[1] = vc->vc_tab_stop[2] = vc->vc_tab_stop[3] = @@ -1771,7 +1771,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_pos -= (vc->vc_x << 1); while (vc->vc_x < vc->vc_cols - 1) { vc->vc_x++; - if (vc->vc_tab_stop[vc->vc_x >> 5] & (1 << (vc->vc_x & 31))) + if (vc->vc_tab_stop[7 & (vc->vc_x >> 5)] & (1 << (vc->vc_x & 31))) break; } vc->vc_pos += (vc->vc_x << 1); @@ -1831,7 +1831,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) lf(vc); return; case 'H': - vc->vc_tab_stop[vc->vc_x >> 5] |= (1 << (vc->vc_x & 31)); + vc->vc_tab_stop[7 & (vc->vc_x >> 5)] |= (1 << (vc->vc_x & 31)); return; case 'Z': respond_ID(tty); @@ -2024,7 +2024,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) return; case 'g': if (!vc->vc_par[0]) - vc->vc_tab_stop[vc->vc_x >> 5] &= ~(1 << (vc->vc_x & 31)); + vc->vc_tab_stop[7 & (vc->vc_x >> 5)] &= ~(1 << (vc->vc_x & 31)); else if (vc->vc_par[0] == 3) { vc->vc_tab_stop[0] = vc->vc_tab_stop[1] = -- GitLab From c68a7a87e1e6553b7f65ad35acdaf31c84fc5b16 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 17 Mar 2018 08:25:07 -0700 Subject: [PATCH 0814/1834] selftests/x86/ptrace_syscall: Fix for yet more glibc interference commit 4b0b37d4cc54b21a6ecad7271cbc850555869c62 upstream. glibc keeps getting cleverer, and my version now turns raise() into more than one syscall. Since the test relies on ptrace seeing an exact set of syscalls, this breaks the test. Replace raise(SIGSTOP) with syscall(SYS_tgkill, ...) to force glibc to get out of our way. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kselftest@vger.kernel.org Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/bc80338b453afa187bc5f895bd8e2c8d6e264da2.1521300271.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/ptrace_syscall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/x86/ptrace_syscall.c b/tools/testing/selftests/x86/ptrace_syscall.c index eaea92439708..1e3da137a8bb 100644 --- a/tools/testing/selftests/x86/ptrace_syscall.c +++ b/tools/testing/selftests/x86/ptrace_syscall.c @@ -182,8 +182,10 @@ static void test_ptrace_syscall_restart(void) if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) err(1, "PTRACE_TRACEME"); + pid_t pid = getpid(), tid = syscall(SYS_gettid); + printf("\tChild will make one syscall\n"); - raise(SIGSTOP); + syscall(SYS_tgkill, pid, tid, SIGSTOP); syscall(SYS_gettid, 10, 11, 12, 13, 14, 15); _exit(0); @@ -300,9 +302,11 @@ static void test_restart_under_ptrace(void) if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) err(1, "PTRACE_TRACEME"); + pid_t pid = getpid(), tid = syscall(SYS_gettid); + printf("\tChild will take a nap until signaled\n"); setsigign(SIGUSR1, SA_RESTART); - raise(SIGSTOP); + syscall(SYS_tgkill, pid, tid, SIGSTOP); syscall(SYS_pause, 0, 0, 0, 0, 0, 0); _exit(0); -- GitLab From 587da2b6282302325bd4bcc28a7615e822184ff1 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 20 Mar 2018 12:16:59 -0700 Subject: [PATCH 0815/1834] kvm/x86: fix icebp instruction handling commit 32d43cd391bacb5f0814c2624399a5dad3501d09 upstream. The undocumented 'icebp' instruction (aka 'int1') works pretty much like 'int3' in the absense of in-circuit probing equipment (except, obviously, that it raises #DB instead of raising #BP), and is used by some validation test-suites as such. But Andy Lutomirski noticed that his test suite acted differently in kvm than on bare hardware. The reason is that kvm used an inexact test for the icebp instruction: it just assumed that an all-zero VM exit qualification value meant that the VM exit was due to icebp. That is not unlike the guess that do_debug() does for the actual exception handling case, but it's purely a heuristic, not an absolute rule. do_debug() does it because it wants to ascribe _some_ reasons to the #DB that happened, and an empty %dr6 value means that 'icebp' is the most likely casue and we have no better information. But kvm can just do it right, because unlike the do_debug() case, kvm actually sees the real reason for the #DB in the VM-exit interruption information field. So instead of relying on an inexact heuristic, just use the actual VM exit information that says "it was 'icebp'". Right now the 'icebp' instruction isn't technically documented by Intel, but that will hopefully change. The special "privileged software exception" information _is_ actually mentioned in the Intel SDM, even though the cause of it isn't enumerated. Reported-by: Andy Lutomirski Tested-by: Paolo Bonzini Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/vmx.h | 1 + arch/x86/kvm/vmx.c | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h index 6899cf187ba2..9cbfbef6a115 100644 --- a/arch/x86/include/asm/vmx.h +++ b/arch/x86/include/asm/vmx.h @@ -309,6 +309,7 @@ enum vmcs_field { #define INTR_TYPE_NMI_INTR (2 << 8) /* NMI */ #define INTR_TYPE_HARD_EXCEPTION (3 << 8) /* processor exception */ #define INTR_TYPE_SOFT_INTR (4 << 8) /* software interrupt */ +#define INTR_TYPE_PRIV_SW_EXCEPTION (5 << 8) /* ICE breakpoint - undocumented */ #define INTR_TYPE_SOFT_EXCEPTION (6 << 8) /* software exception */ /* GUEST_INTERRUPTIBILITY_INFO flags. */ diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 0f3bb4632310..7ed422e2641b 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1053,6 +1053,13 @@ static inline bool is_machine_check(u32 intr_info) (INTR_TYPE_HARD_EXCEPTION | MC_VECTOR | INTR_INFO_VALID_MASK); } +/* Undocumented: icebp/int1 */ +static inline bool is_icebp(u32 intr_info) +{ + return (intr_info & (INTR_INFO_INTR_TYPE_MASK | INTR_INFO_VALID_MASK)) + == (INTR_TYPE_PRIV_SW_EXCEPTION | INTR_INFO_VALID_MASK); +} + static inline bool cpu_has_vmx_msr_bitmap(void) { return vmcs_config.cpu_based_exec_ctrl & CPU_BASED_USE_MSR_BITMAPS; @@ -5733,7 +5740,7 @@ static int handle_exception(struct kvm_vcpu *vcpu) (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) { vcpu->arch.dr6 &= ~15; vcpu->arch.dr6 |= dr6 | DR6_RTM; - if (!(dr6 & ~DR6_RESERVED)) /* icebp */ + if (is_icebp(intr_info)) skip_emulated_instruction(vcpu); kvm_queue_exception(vcpu, DB_VECTOR); -- GitLab From 678b405bff8be2ccfc1d3b86ac9119049c1ea718 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Mon, 19 Mar 2018 13:57:46 -0700 Subject: [PATCH 0816/1834] x86/build/64: Force the linker to use 2MB page size commit e3d03598e8ae7d195af5d3d049596dec336f569f upstream. Binutils 2.31 will enable -z separate-code by default for x86 to avoid mixing code pages with data to improve cache performance as well as security. To reduce x86-64 executable and shared object sizes, the maximum page size is reduced from 2MB to 4KB. But x86-64 kernel must be aligned to 2MB. Pass -z max-page-size=0x200000 to linker to force 2MB page size regardless of the default page size used by linker. Tested with Linux kernel 4.15.6 on x86-64. Signed-off-by: H.J. Lu Cc: Andy Shevchenko Cc: Eric Biederman Cc: H. Peter Anvin Cc: Juergen Gross Cc: Kees Cook Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/CAMe9rOp4_%3D_8twdpTyAP2DhONOCeaTOsniJLoppzhoNptL8xzA@mail.gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/x86/Makefile b/arch/x86/Makefile index b60996184fa4..f408babdf746 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -172,6 +172,15 @@ KBUILD_CFLAGS += $(cfi) $(cfi-sigframe) $(cfi-sections) $(asinstr) $(avx_instr) LDFLAGS := -m elf_$(UTS_MACHINE) +# +# The 64-bit kernel must be aligned to 2MB. Pass -z max-page-size=0x200000 to +# the linker to force 2MB page size regardless of the default page size used +# by the linker. +# +ifdef CONFIG_X86_64 +LDFLAGS += $(call ld-option, -z max-page-size=0x200000) +endif + # Speed up the build KBUILD_CFLAGS += -pipe # Workaround for a gcc prelease that unfortunately was shipped in a suse release -- GitLab From f9ed24457265f2dac9fa80a20d8d546b201b5540 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Mon, 19 Mar 2018 14:08:11 -0700 Subject: [PATCH 0817/1834] x86/boot/64: Verify alignment of the LOAD segment commit c55b8550fa57ba4f5e507be406ff9fc2845713e8 upstream. Since the x86-64 kernel must be aligned to 2MB, refuse to boot the kernel if the alignment of the LOAD segment isn't a multiple of 2MB. Signed-off-by: H.J. Lu Cc: Andy Shevchenko Cc: Eric Biederman Cc: H. Peter Anvin Cc: Juergen Gross Cc: Kees Cook Cc: Kirill A. Shutemov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/CAMe9rOrR7xSJgUfiCoZLuqWUwymRxXPoGBW38%2BpN%3D9g%2ByKNhZw@mail.gmail.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/boot/compressed/misc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index c945acd8fa33..d86e68d3c794 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -299,6 +299,10 @@ static void parse_elf(void *output) switch (phdr->p_type) { case PT_LOAD: +#ifdef CONFIG_X86_64 + if ((phdr->p_align % 0x200000) != 0) + error("Alignment of LOAD segment isn't multiple of 2MB"); +#endif #ifdef CONFIG_RELOCATABLE dest = output; dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); -- GitLab From 3681c24a7d096b092cf05c8338adbb9019bb1536 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Thu, 23 Jul 2015 15:37:48 -0700 Subject: [PATCH 0818/1834] x86/entry/64: Don't use IST entry for #BP stack commit d8ba61ba58c88d5207c1ba2f7d9a2280e7d03be9 upstream. There's nothing IST-worthy about #BP/int3. We don't allow kprobes in the small handful of places in the kernel that run at CPL0 with an invalid stack, and 32-bit kernels have used normal interrupt gates for #BP forever. Furthermore, we don't allow kprobes in places that have usergs while in kernel mode, so "paranoid" is also unnecessary. Signed-off-by: Andy Lutomirski Signed-off-by: Linus Torvalds Signed-off-by: Thomas Gleixner Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/x86/entry/entry_64.S | 2 +- arch/x86/kernel/traps.c | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S index 58610fe93f5d..d58d8dcb8245 100644 --- a/arch/x86/entry/entry_64.S +++ b/arch/x86/entry/entry_64.S @@ -943,7 +943,7 @@ apicinterrupt3 HYPERVISOR_CALLBACK_VECTOR \ #endif /* CONFIG_HYPERV */ idtentry debug do_debug has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK -idtentry int3 do_int3 has_error_code=0 paranoid=1 shift_ist=DEBUG_STACK +idtentry int3 do_int3 has_error_code=0 idtentry stack_segment do_stack_segment has_error_code=1 #ifdef CONFIG_XEN diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 322f433fbc76..f2142932ff0b 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -526,7 +526,6 @@ do_general_protection(struct pt_regs *regs, long error_code) } NOKPROBE_SYMBOL(do_general_protection); -/* May run on IST stack. */ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) { #ifdef CONFIG_DYNAMIC_FTRACE @@ -541,7 +540,15 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) if (poke_int3_handler(regs)) return; + /* + * Use ist_enter despite the fact that we don't use an IST stack. + * We can be called from a kprobe in non-CONTEXT_KERNEL kernel + * mode or even during context tracking state changes. + * + * This means that we can't schedule. That's okay. + */ ist_enter(regs); + RCU_LOCKDEP_WARN(!rcu_is_watching(), "entry code didn't wake RCU"); #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, @@ -558,17 +565,11 @@ dotraplinkage void notrace do_int3(struct pt_regs *regs, long error_code) SIGTRAP) == NOTIFY_STOP) goto exit; - /* - * Let others (NMI) know that the debug stack is in use - * as we may switch to the interrupt stack. - */ - debug_stack_usage_inc(); preempt_disable(); cond_local_irq_enable(regs); do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL); cond_local_irq_disable(regs); preempt_enable_no_resched(); - debug_stack_usage_dec(); exit: ist_exit(regs); } @@ -989,19 +990,16 @@ void __init trap_init(void) cpu_init(); /* - * X86_TRAP_DB and X86_TRAP_BP have been set - * in early_trap_init(). However, ITS works only after - * cpu_init() loads TSS. See comments in early_trap_init(). + * X86_TRAP_DB was installed in early_trap_init(). However, + * IST works only after cpu_init() loads TSS. See comments + * in early_trap_init(). */ set_intr_gate_ist(X86_TRAP_DB, &debug, DEBUG_STACK); - /* int3 can be called from all */ - set_system_intr_gate_ist(X86_TRAP_BP, &int3, DEBUG_STACK); x86_init.irqs.trap_init(); #ifdef CONFIG_X86_64 memcpy(&debug_idt_table, &idt_table, IDT_ENTRIES * 16); set_nmi_gate(X86_TRAP_DB, &debug); - set_nmi_gate(X86_TRAP_BP, &int3); #endif } -- GitLab From b3076abb678614363985d58a4b839148a47f5e82 Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 2 Mar 2018 07:22:30 -0800 Subject: [PATCH 0819/1834] perf/x86/intel/uncore: Fix Skylake UPI event format commit 317660940fd9dddd3201c2f92e25c27902c753fa upstream. There is no event extension (bit 21) for SKX UPI, so use 'event' instead of 'event_ext'. Reported-by: Stephane Eranian Signed-off-by: Kan Liang Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vince Weaver Fixes: cd34cd97b7b4 ("perf/x86/intel/uncore: Add Skylake server uncore support") Link: http://lkml.kernel.org/r/1520004150-4855-1-git-send-email-kan.liang@linux.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/uncore_snbep.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index afe8024e9e95..9c245dbc7d65 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -3566,7 +3566,7 @@ static struct intel_uncore_type skx_uncore_imc = { }; static struct attribute *skx_upi_uncore_formats_attr[] = { - &format_attr_event_ext.attr, + &format_attr_event.attr, &format_attr_umask_ext.attr, &format_attr_edge.attr, &format_attr_inv.attr, -- GitLab From a8b3a6a4ae5e7b790cdc62335a6f5952c3f9b6ea Mon Sep 17 00:00:00 2001 From: Ilya Pronin Date: Mon, 5 Mar 2018 22:43:53 -0800 Subject: [PATCH 0820/1834] perf stat: Fix CVS output format for non-supported counters commit 40c21898ba5372c14ef71717040529794a91ccc2 upstream. When printing stats in CSV mode, 'perf stat' appends extra separators when a counter is not supported: ,,L1-dcache-store-misses,mesos/bd442f34-2b4a-47df-b966-9b281f9f56fc,0,100.00,,,, Which causes a failure when parsing fields. The numbers of separators should be the same for each line, no matter if the counter is or not supported. Signed-off-by: Ilya Pronin Acked-by: Jiri Olsa Cc: Andi Kleen Link: http://lkml.kernel.org/r/20180306064353.31930-1-xiyou.wangcong@gmail.com Fixes: 92a61f6412d3 ("perf stat: Implement CSV metrics output") Signed-off-by: Cong Wang Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-stat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 5b60ec669e73..68861e81f06c 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -876,7 +876,7 @@ static void print_metric_csv(void *ctx, char buf[64], *vals, *ends; if (unit == NULL || fmt == NULL) { - fprintf(out, "%s%s%s%s", csv_sep, csv_sep, csv_sep, csv_sep); + fprintf(out, "%s%s", csv_sep, csv_sep); return; } snprintf(buf, sizeof(buf), fmt, val); -- GitLab From e91ec3494168e1d4505f413effe0dfbbbcc64208 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 17 Mar 2018 14:52:16 +0300 Subject: [PATCH 0821/1834] perf/x86/intel: Don't accidentally clear high bits in bdw_limit_period() commit e5ea9b54a055619160bbfe527ebb7d7191823d66 upstream. We intended to clear the lowest 6 bits but because of a type bug we clear the high 32 bits as well. Andi says that periods are rarely more than U32_MAX so this bug probably doesn't have a huge runtime impact. Signed-off-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: H. Peter Anvin Cc: Jiri Olsa Cc: Kan Liang Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sebastian Andrzej Siewior Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: 294fe0f52a44 ("perf/x86/intel: Add INST_RETIRED.ALL workarounds") Link: http://lkml.kernel.org/r/20180317115216.GB4035@mwanda Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 0bd0c1cc3228..6f353a874178 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3025,7 +3025,7 @@ static unsigned bdw_limit_period(struct perf_event *event, unsigned left) X86_CONFIG(.event=0xc0, .umask=0x01)) { if (left < 128) left = 128; - left &= ~0x3fu; + left &= ~0x3fULL; } return left; } -- GitLab From 9c0d0a0c79ee7e1c0834594a5a8f4e701067828f Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Tue, 13 Mar 2018 11:51:34 -0700 Subject: [PATCH 0822/1834] perf/x86/intel/uncore: Fix multi-domain PCI CHA enumeration bug on Skylake servers commit 320b0651f32b830add6497fcdcfdcb6ae8c7b8a0 upstream. The number of CHAs is miscalculated on multi-domain PCI Skylake server systems, resulting in an uncore driver initialization error. Gary Kroening explains: "For systems with a single PCI segment, it is sufficient to look for the bus number to change in order to determine that all of the CHa's have been counted for a single socket. However, for multi PCI segment systems, each socket is given a new segment and the bus number does NOT change. So looking only for the bus number to change ends up counting all of the CHa's on all sockets in the system. This leads to writing CPU MSRs beyond a valid range and causes an error in ivbep_uncore_msr_init_box()." To fix this bug, query the number of CHAs from the CAPID6 register: it should read bits 27:0 in the CAPID6 register located at Device 30, Function 3, Offset 0x9C. These 28 bits form a bit vector of available LLC slices and the CHAs that manage those slices. Reported-by: Kroening, Gary Tested-by: Kroening, Gary Signed-off-by: Kan Liang Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Andy Shevchenko Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Cc: abanman@hpe.com Cc: dimitri.sivanich@hpe.com Cc: hpa@zytor.com Cc: mike.travis@hpe.com Cc: russ.anderson@hpe.com Fixes: cd34cd97b7b4 ("perf/x86/intel/uncore: Add Skylake server uncore support") Link: http://lkml.kernel.org/r/1520967094-13219-1-git-send-email-kan.liang@linux.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- arch/x86/events/intel/uncore_snbep.c | 31 +++++++++++++++------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/arch/x86/events/intel/uncore_snbep.c b/arch/x86/events/intel/uncore_snbep.c index 9c245dbc7d65..6bc36944a8c1 100644 --- a/arch/x86/events/intel/uncore_snbep.c +++ b/arch/x86/events/intel/uncore_snbep.c @@ -3522,24 +3522,27 @@ static struct intel_uncore_type *skx_msr_uncores[] = { NULL, }; +/* + * To determine the number of CHAs, it should read bits 27:0 in the CAPID6 + * register which located at Device 30, Function 3, Offset 0x9C. PCI ID 0x2083. + */ +#define SKX_CAPID6 0x9c +#define SKX_CHA_BIT_MASK GENMASK(27, 0) + static int skx_count_chabox(void) { - struct pci_dev *chabox_dev = NULL; - int bus, count = 0; + struct pci_dev *dev = NULL; + u32 val = 0; - while (1) { - chabox_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x208d, chabox_dev); - if (!chabox_dev) - break; - if (count == 0) - bus = chabox_dev->bus->number; - if (bus != chabox_dev->bus->number) - break; - count++; - } + dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x2083, dev); + if (!dev) + goto out; - pci_dev_put(chabox_dev); - return count; + pci_read_config_dword(dev, SKX_CAPID6, &val); + val &= SKX_CHA_BIT_MASK; +out: + pci_dev_put(dev); + return hweight32(val); } void skx_uncore_cpu_init(void) -- GitLab From 162daa27140a592aa6bd524f4553f9678e1efcf8 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 5 Dec 2017 11:57:27 +0100 Subject: [PATCH 0823/1834] iio: ABI: Fix name of timestamp sysfs file commit b9a3589332c2a25fb7edad25a26fcaada3209126 upstream. The name of the file is "current_timetamp_clock" not "timestamp_clock". Fixes: bc2b7dab629a ("iio:core: timestamping clock selection support") Cc: Gregor Boirie Signed-off-by: Linus Walleij Signed-off-by: Jonathan Cameron Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-bus-iio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index fee35c00cc4e..0406076e4405 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -32,7 +32,7 @@ Description: Description of the physical chip / device for device X. Typically a part number. -What: /sys/bus/iio/devices/iio:deviceX/timestamp_clock +What: /sys/bus/iio/devices/iio:deviceX/current_timestamp_clock KernelVersion: 4.5 Contact: linux-iio@vger.kernel.org Description: -- GitLab From 1e0fc7dba23d8ecf8baee8ccf8440503f7013221 Mon Sep 17 00:00:00 2001 From: Nadav Amit Date: Tue, 5 Sep 2017 20:25:25 +0000 Subject: [PATCH 0824/1834] staging: lustre: ptlrpc: kfree used instead of kvfree commit c3eec59659cf25916647d2178c541302bb4822ad upstream. rq_reqbuf is allocated using kvmalloc() but released in one occasion using kfree() instead of kvfree(). The issue was found using grep based on a similar bug. Fixes: d7e09d0397e8 ("add Lustre file system client support") Fixes: ee0ec1946ec2 ("lustre: ptlrpc: Replace uses of OBD_{ALLOC,FREE}_LARGE") Cc: Peng Tao Cc: Oleg Drokin Cc: James Simmons Signed-off-by: Nadav Amit Signed-off-by: Andreas Dilger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/lustre/lustre/ptlrpc/sec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec.c b/drivers/staging/lustre/lustre/ptlrpc/sec.c index a7416cd9ac71..7b0587d8b176 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/sec.c +++ b/drivers/staging/lustre/lustre/ptlrpc/sec.c @@ -838,7 +838,7 @@ void sptlrpc_request_out_callback(struct ptlrpc_request *req) if (req->rq_pool || !req->rq_reqbuf) return; - kfree(req->rq_reqbuf); + kvfree(req->rq_reqbuf); req->rq_reqbuf = NULL; req->rq_reqbuf_len = 0; } -- GitLab From 26e9852f9d50945c7a3b245143eed8f7004cdaed Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 3 Feb 2017 10:51:35 -0800 Subject: [PATCH 0825/1834] selftests, x86, protection_keys: fix wrong offset in siginfo commit 2195bff041486eb7fcceaf058acaedcd057efbdc upstream. The siginfo contains a bunch of information about the fault. For protection keys, it tells us which protection key's permissions were violated. The wrong offset in here leads to reading garbage and thus failures in the tests. We should probably eventually move this over to using the kernel's headers defining the siginfo instead of a hard-coded offset. But, for now, just do the simplest fix. Signed-off-by: Dave Hansen Cc: Ingo Molnar Cc: Shuah Khan Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/protection_keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index 2842a5fa22b3..17c7d5833ccf 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -192,7 +192,7 @@ void lots_o_noops_around_write(int *write_to_me) #define SYS_pkey_alloc 381 #define SYS_pkey_free 382 #define REG_IP_IDX REG_EIP -#define si_pkey_offset 0x18 +#define si_pkey_offset 0x14 #else #define SYS_mprotect_key 329 #define SYS_pkey_alloc 330 -- GitLab From 93b4839239e3c76a31fe1e56e19405674c9948e7 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 4 Nov 2017 04:19:48 -0700 Subject: [PATCH 0826/1834] selftests/x86/protection_keys: Fix syscall NR redefinition warnings commit 693cb5580fdb026922363aa103add64b3ecd572e upstream. On new enough glibc, the pkey syscalls numbers are available. Check first before defining them to avoid warnings like: protection_keys.c:198:0: warning: "SYS_pkey_alloc" redefined Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Dave Hansen Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1fbef53a9e6befb7165ff855fc1a7d4788a191d6.1509794321.git.luto@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/protection_keys.c | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index 17c7d5833ccf..44548de3e69b 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -188,17 +188,29 @@ void lots_o_noops_around_write(int *write_to_me) #define u64 uint64_t #ifdef __i386__ -#define SYS_mprotect_key 380 -#define SYS_pkey_alloc 381 -#define SYS_pkey_free 382 + +#ifndef SYS_mprotect_key +# define SYS_mprotect_key 380 +#endif +#ifndef SYS_pkey_alloc +# define SYS_pkey_alloc 381 +# define SYS_pkey_free 382 +#endif #define REG_IP_IDX REG_EIP #define si_pkey_offset 0x14 + #else -#define SYS_mprotect_key 329 -#define SYS_pkey_alloc 330 -#define SYS_pkey_free 331 + +#ifndef SYS_mprotect_key +# define SYS_mprotect_key 329 +#endif +#ifndef SYS_pkey_alloc +# define SYS_pkey_alloc 330 +# define SYS_pkey_free 331 +#endif #define REG_IP_IDX REG_RIP #define si_pkey_offset 0x20 + #endif void dump_mem(void *dumpme, int len_bytes) -- GitLab From f41f8156aee5b69ef45f3e54a27ea85033973199 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 26 Jun 2017 16:36:57 -0500 Subject: [PATCH 0827/1834] signal/testing: Don't look for __SI_FAULT in userspace commit d12fe87e62d773e81e0cb3a123c5a480a10d7d91 upstream. Fix the debug print statements in these tests where they reference si_codes and in particular __SI_FAULT. __SI_FAULT is a kernel internal value and should never be seen by userspace. While I am in there also fix si_code_str. si_codes are an enumeration there are not a bitmap so == and not & is the apropriate operation to test for an si_code. Cc: Dave Hansen Fixes: 5f23f6d082a9 ("x86/pkeys: Add self-tests") Fixes: e754aedc26ef ("x86/mpx, selftests: Add MPX self test") Signed-off-by: "Eric W. Biederman" Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/mpx-mini-test.c | 3 +-- tools/testing/selftests/x86/protection_keys.c | 13 ++++++------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/x86/mpx-mini-test.c b/tools/testing/selftests/x86/mpx-mini-test.c index 79e1d13d1cda..58384189370c 100644 --- a/tools/testing/selftests/x86/mpx-mini-test.c +++ b/tools/testing/selftests/x86/mpx-mini-test.c @@ -419,8 +419,7 @@ void handler(int signum, siginfo_t *si, void *vucontext) br_count++; dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count); -#define __SI_FAULT (3 << 16) -#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ +#define SEGV_BNDERR 3 /* failed address bound checks */ dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n", status, ip, br_reason); diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index 44548de3e69b..d58ff87b1bb5 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -224,19 +224,18 @@ void dump_mem(void *dumpme, int len_bytes) } } -#define __SI_FAULT (3 << 16) -#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ -#define SEGV_PKUERR (__SI_FAULT|4) +#define SEGV_BNDERR 3 /* failed address bound checks */ +#define SEGV_PKUERR 4 static char *si_code_str(int si_code) { - if (si_code & SEGV_MAPERR) + if (si_code == SEGV_MAPERR) return "SEGV_MAPERR"; - if (si_code & SEGV_ACCERR) + if (si_code == SEGV_ACCERR) return "SEGV_ACCERR"; - if (si_code & SEGV_BNDERR) + if (si_code == SEGV_BNDERR) return "SEGV_BNDERR"; - if (si_code & SEGV_PKUERR) + if (si_code == SEGV_PKUERR) return "SEGV_PKUERR"; return "UNKNOWN"; } -- GitLab From 1443abc90332311982e0634b6ef762ede5f98e4a Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 10 Nov 2017 16:12:31 -0800 Subject: [PATCH 0828/1834] x86/pkeys/selftests: Rename 'si_pkey' to 'siginfo_pkey' commit 91c49c2deb96ffc3c461eaae70219d89224076b7 upstream. 'si_pkey' is now #defined to be the name of the new siginfo field that protection keys uses. Rename it not to conflict. Signed-off-by: Dave Hansen Acked-by: Thomas Gleixner Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20171111001231.DFFC8285@viggo.jf.intel.com Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/protection_keys.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c index d58ff87b1bb5..85a78eba0a93 100644 --- a/tools/testing/selftests/x86/protection_keys.c +++ b/tools/testing/selftests/x86/protection_keys.c @@ -249,7 +249,7 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) unsigned long ip; char *fpregs; u32 *pkru_ptr; - u64 si_pkey; + u64 siginfo_pkey; u32 *si_pkey_ptr; int pkru_offset; fpregset_t fpregset; @@ -291,9 +291,9 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) si_pkey_ptr = (u32 *)(((u8 *)si) + si_pkey_offset); dprintf1("si_pkey_ptr: %p\n", si_pkey_ptr); dump_mem(si_pkey_ptr - 8, 24); - si_pkey = *si_pkey_ptr; - pkey_assert(si_pkey < NR_PKEYS); - last_si_pkey = si_pkey; + siginfo_pkey = *si_pkey_ptr; + pkey_assert(siginfo_pkey < NR_PKEYS); + last_si_pkey = siginfo_pkey; if ((si->si_code == SEGV_MAPERR) || (si->si_code == SEGV_ACCERR) || @@ -305,7 +305,7 @@ void signal_handler(int signum, siginfo_t *si, void *vucontext) dprintf1("signal pkru from xsave: %08x\n", *pkru_ptr); /* need __rdpkru() version so we do not do shadow_pkru checking */ dprintf1("signal pkru from pkru: %08x\n", __rdpkru()); - dprintf1("si_pkey from siginfo: %jx\n", si_pkey); + dprintf1("pkey from siginfo: %jx\n", siginfo_pkey); *(u64 *)pkru_ptr = 0x00000000; dprintf1("WARNING: set PRKU=0 to allow faulting instruction to continue\n"); pkru_faults++; -- GitLab From 353f71fe3c07fabc3433d94c894c0acdeadb2a29 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 2 Oct 2017 16:16:13 -0600 Subject: [PATCH 0829/1834] selftests: x86: sysret_ss_attrs doesn't build on a PIE build commit 3346a6a4e5ba8c040360f753b26938cec31a4bdc upstream. sysret_ss_attrs fails to compile leading x86 test run to fail on systems configured to build using PIE by default. Add -no-pie fix it. Relocation might still fail if relocated above 4G. For now this change fixes the build and runs x86 tests. tools/testing/selftests/x86$ make gcc -m64 -o .../tools/testing/selftests/x86/single_step_syscall_64 -O2 -g -std=gnu99 -pthread -Wall single_step_syscall.c -lrt -ldl gcc -m64 -o .../tools/testing/selftests/x86/sysret_ss_attrs_64 -O2 -g -std=gnu99 -pthread -Wall sysret_ss_attrs.c thunks.S -lrt -ldl /usr/bin/ld: /tmp/ccS6pvIh.o: relocation R_X86_64_32S against `.text' can not be used when making a shared object; recompile with -fPIC /usr/bin/ld: final link failed: Nonrepresentable section on output collect2: error: ld returned 1 exit status Makefile:49: recipe for target '.../tools/testing/selftests/x86/sysret_ss_attrs_64' failed make: *** [.../tools/testing/selftests/x86/sysret_ss_attrs_64] Error 1 Suggested-by: Andy Lutomirski Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/x86/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index 6eb50152baf0..e5b459a09cff 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -17,7 +17,7 @@ TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) BINARIES_32 := $(TARGETS_C_32BIT_ALL:%=%_32) BINARIES_64 := $(TARGETS_C_64BIT_ALL:%=%_64) -CFLAGS := -O2 -g -std=gnu99 -pthread -Wall +CFLAGS := -O2 -g -std=gnu99 -pthread -Wall -no-pie UNAME_M := $(shell uname -m) CAN_BUILD_I386 := $(shell ./check_cc.sh $(CC) trivial_32bit_program.c -m32) -- GitLab From 733a4e1af803b1094b26040fc50e5c821fa2f28f Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 21 Mar 2018 01:18:24 +0100 Subject: [PATCH 0830/1834] kbuild: disable clang's default use of -fmerge-all-constants commit 87e0d4f0f37fb0c8c4aeeac46fff5e957738df79 upstream. Prasad reported that he has seen crashes in BPF subsystem with netd on Android with arm64 in the form of (note, the taint is unrelated): [ 4134.721483] Unable to handle kernel paging request at virtual address 800000001 [ 4134.820925] Mem abort info: [ 4134.901283] Exception class = DABT (current EL), IL = 32 bits [ 4135.016736] SET = 0, FnV = 0 [ 4135.119820] EA = 0, S1PTW = 0 [ 4135.201431] Data abort info: [ 4135.301388] ISV = 0, ISS = 0x00000021 [ 4135.359599] CM = 0, WnR = 0 [ 4135.470873] user pgtable: 4k pages, 39-bit VAs, pgd = ffffffe39b946000 [ 4135.499757] [0000000800000001] *pgd=0000000000000000, *pud=0000000000000000 [ 4135.660725] Internal error: Oops: 96000021 [#1] PREEMPT SMP [ 4135.674610] Modules linked in: [ 4135.682883] CPU: 5 PID: 1260 Comm: netd Tainted: G S W 4.14.19+ #1 [ 4135.716188] task: ffffffe39f4aa380 task.stack: ffffff801d4e0000 [ 4135.731599] PC is at bpf_prog_add+0x20/0x68 [ 4135.741746] LR is at bpf_prog_inc+0x20/0x2c [ 4135.751788] pc : [] lr : [] pstate: 60400145 [ 4135.769062] sp : ffffff801d4e3ce0 [...] [ 4136.258315] Process netd (pid: 1260, stack limit = 0xffffff801d4e0000) [ 4136.273746] Call trace: [...] [ 4136.442494] 3ca0: ffffff94ab7ad584 0000000060400145 ffffffe3a01bf8f8 0000000000000006 [ 4136.460936] 3cc0: 0000008000000000 ffffff94ab844204 ffffff801d4e3cf0 ffffff94ab7ad584 [ 4136.479241] [] bpf_prog_add+0x20/0x68 [ 4136.491767] [] bpf_prog_inc+0x20/0x2c [ 4136.504536] [] bpf_obj_get_user+0x204/0x22c [ 4136.518746] [] SyS_bpf+0x5a8/0x1a88 Android's netd was basically pinning the uid cookie BPF map in BPF fs (/sys/fs/bpf/traffic_cookie_uid_map) and later on retrieving it again resulting in above panic. Issue is that the map was wrongly identified as a prog! Above kernel was compiled with clang 4.0, and it turns out that clang decided to merge the bpf_prog_iops and bpf_map_iops into a single memory location, such that the two i_ops could then not be distinguished anymore. Reason for this miscompilation is that clang has the more aggressive -fmerge-all-constants enabled by default. In fact, clang source code has a comment about it in lib/AST/ExprConstant.cpp on why it is okay to do so: Pointers with different bases cannot represent the same object. (Note that clang defaults to -fmerge-all-constants, which can lead to inconsistent results for comparisons involving the address of a constant; this generally doesn't matter in practice.) The issue never appeared with gcc however, since gcc does not enable -fmerge-all-constants by default and even *explicitly* states in it's option description that using this flag results in non-conforming behavior, quote from man gcc: Languages like C or C++ require each variable, including multiple instances of the same variable in recursive calls, to have distinct locations, so using this option results in non-conforming behavior. There are also various clang bug reports open on that matter [1], where clang developers acknowledge the non-conforming behavior, and refer to disabling it with -fno-merge-all-constants. But even if this gets fixed in clang today, there are already users out there that triggered this. Thus, fix this issue by explicitly adding -fno-merge-all-constants to the kernel's Makefile to generically disable this optimization, since potentially other places in the kernel could subtly break as well. Note, there is also a flag called -fmerge-constants (not supported by clang), which is more conservative and only applies to strings and it's enabled in gcc's -O/-O2/-O3/-Os optimization levels. In gcc's code, the two flags -fmerge-{all-,}constants share the same variable internally, so when disabling it via -fno-merge-all-constants, then we really don't merge any const data (e.g. strings), and text size increases with gcc (14,927,214 -> 14,942,646 for vmlinux.o). $ gcc -fverbose-asm -O2 foo.c -S -o foo.S -> foo.S lists -fmerge-constants under options enabled $ gcc -fverbose-asm -O2 -fno-merge-all-constants foo.c -S -o foo.S -> foo.S doesn't list -fmerge-constants under options enabled $ gcc -fverbose-asm -O2 -fno-merge-all-constants -fmerge-constants foo.c -S -o foo.S -> foo.S lists -fmerge-constants under options enabled Thus, as a workaround we need to set both -fno-merge-all-constants *and* -fmerge-constants in the Makefile in order for text size to stay as is. [1] https://bugs.llvm.org/show_bug.cgi?id=18538 Reported-by: Prasad Sodagudi Signed-off-by: Daniel Borkmann Cc: Linus Torvalds Cc: Chenbo Feng Cc: Richard Smith Cc: Chandler Carruth Cc: linux-kernel@vger.kernel.org Tested-by: Prasad Sodagudi Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov Signed-off-by: Greg Kroah-Hartman --- Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Makefile b/Makefile index df3b20af0fdb..db0de0d2e6c2 100644 --- a/Makefile +++ b/Makefile @@ -790,6 +790,15 @@ KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign) # disable invalid "can't wrap" optimizations for signed / pointers KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) +# clang sets -fmerge-all-constants by default as optimization, but this +# is non-conforming behavior for C and in fact breaks the kernel, so we +# need to disable it here generally. +KBUILD_CFLAGS += $(call cc-option,-fno-merge-all-constants) + +# for gcc -fno-merge-all-constants disables everything, but it is fine +# to have actual conforming behavior enabled. +KBUILD_CFLAGS += $(call cc-option,-fmerge-constants) + # Make sure -fstack-check isn't enabled (like gentoo apparently did) KBUILD_CFLAGS += $(call cc-option,-fno-stack-check,) -- GitLab From 3eb88807b26daef1342d733d75956ad50d72b9d6 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 19 Mar 2018 17:57:27 -0700 Subject: [PATCH 0831/1834] bpf: skip unnecessary capability check commit 0fa4fe85f4724fff89b09741c437cbee9cf8b008 upstream. The current check statement in BPF syscall will do a capability check for CAP_SYS_ADMIN before checking sysctl_unprivileged_bpf_disabled. This code path will trigger unnecessary security hooks on capability checking and cause false alarms on unprivileged process trying to get CAP_SYS_ADMIN access. This can be resolved by simply switch the order of the statement and CAP_SYS_ADMIN is not required anyway if unprivileged bpf syscall is allowed. Signed-off-by: Chenbo Feng Acked-by: Lorenzo Colitti Signed-off-by: Daniel Borkmann Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/syscall.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 91a2d3752007..f8b4e3e16cef 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -801,7 +801,7 @@ SYSCALL_DEFINE3(bpf, int, cmd, union bpf_attr __user *, uattr, unsigned int, siz union bpf_attr attr = {}; int err; - if (!capable(CAP_SYS_ADMIN) && sysctl_unprivileged_bpf_disabled) + if (sysctl_unprivileged_bpf_disabled && !capable(CAP_SYS_ADMIN)) return -EPERM; if (!access_ok(VERIFY_READ, uattr, 1)) -- GitLab From c9e307194fcdcb750e88a0014f9222d5a37b8bf5 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 7 Mar 2018 22:10:01 +0100 Subject: [PATCH 0832/1834] bpf, x64: increase number of passes commit 6007b080d2e2adb7af22bf29165f0594ea12b34c upstream. In Cilium some of the main programs we run today are hitting 9 passes on x64's JIT compiler, and we've had cases already where we surpassed the limit where the JIT then punts the program to the interpreter instead, leading to insertion failures due to CONFIG_BPF_JIT_ALWAYS_ON or insertion failures due to the prog array owner being JITed but the program to insert not (both must have the same JITed/non-JITed property). One concrete case the program image shrunk from 12,767 bytes down to 10,288 bytes where the image converged after 16 steps. I've measured that this took 340us in the JIT until it converges on my i7-6600U. Thus, increase the original limit we had from day one where the JIT covered cBPF only back then before we run into the case (as similar with the complexity limit) where we trip over this and hit program rejections. Also add a cond_resched() into the compilation loop, the JIT process runs without any locks and may sleep anyway. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Reviewed-by: Eric Dumazet Signed-off-by: Alexei Starovoitov Signed-off-by: Greg Kroah-Hartman --- arch/x86/net/bpf_jit_comp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 1f7ed2ed6ff7..cd9764520851 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -1135,7 +1135,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) * may converge on the last pass. In such case do one more * pass to emit the final image */ - for (pass = 0; pass < 10 || image; pass++) { + for (pass = 0; pass < 20 || image; pass++) { proglen = do_jit(prog, addrs, image, oldproglen, &ctx); if (proglen <= 0) { image = NULL; @@ -1162,6 +1162,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) } } oldproglen = proglen; + cond_resched(); } if (bpf_jit_enable > 1) -- GitLab From c44cfe06dfe2a5f54527e87a48c92a6595d070cc Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 28 Mar 2018 18:39:26 +0200 Subject: [PATCH 0833/1834] Linux 4.9.91 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index db0de0d2e6c2..db3d37e18723 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 90 +SUBLEVEL = 91 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From dd4d08c98e95387b07739f0726e507a3ee425573 Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 6 Jul 2017 10:22:00 +0800 Subject: [PATCH 0834/1834] UPSTREAM: net: hns: Fix a skb used after free bug skb maybe freed in hns_nic_net_xmit_hw() and return NETDEV_TX_OK, which cause hns_nic_net_xmit to use a freed skb. BUG: KASAN: use-after-free in hns_nic_net_xmit_hw+0x62c/0x940... [17659.112635] alloc_debug_processing+0x18c/0x1a0 [17659.117208] __slab_alloc+0x52c/0x560 [17659.120909] kmem_cache_alloc_node+0xac/0x2c0 [17659.125309] __alloc_skb+0x6c/0x260 [17659.128837] tcp_send_ack+0x8c/0x280 [17659.132449] __tcp_ack_snd_check+0x9c/0xf0 [17659.136587] tcp_rcv_established+0x5a4/0xa70 [17659.140899] tcp_v4_do_rcv+0x27c/0x620 [17659.144687] tcp_prequeue_process+0x108/0x170 [17659.149085] tcp_recvmsg+0x940/0x1020 [17659.152787] inet_recvmsg+0x124/0x180 [17659.156488] sock_recvmsg+0x64/0x80 [17659.160012] SyS_recvfrom+0xd8/0x180 [17659.163626] __sys_trace_return+0x0/0x4 [17659.167506] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=23 cpu=1 pid=13 [17659.174000] free_debug_processing+0x1d4/0x2c0 [17659.178486] __slab_free+0x240/0x390 [17659.182100] kmem_cache_free+0x24c/0x270 [17659.186062] kfree_skbmem+0xa0/0xb0 [17659.189587] __kfree_skb+0x28/0x40 [17659.193025] napi_gro_receive+0x168/0x1c0 [17659.197074] hns_nic_rx_up_pro+0x58/0x90 [17659.201038] hns_nic_rx_poll_one+0x518/0xbc0 [17659.205352] hns_nic_common_poll+0x94/0x140 [17659.209576] net_rx_action+0x458/0x5e0 [17659.213363] __do_softirq+0x1b8/0x480 [17659.217062] run_ksoftirqd+0x64/0x80 [17659.220679] smpboot_thread_fn+0x224/0x310 [17659.224821] kthread+0x150/0x170 [17659.228084] ret_from_fork+0x10/0x40 BUG: KASAN: use-after-free in hns_nic_net_xmit+0x8c/0xc0... [17751.080490] __slab_alloc+0x52c/0x560 [17751.084188] kmem_cache_alloc+0x244/0x280 [17751.088238] __build_skb+0x40/0x150 [17751.091764] build_skb+0x28/0x100 [17751.095115] __alloc_rx_skb+0x94/0x150 [17751.098900] __napi_alloc_skb+0x34/0x90 [17751.102776] hns_nic_rx_poll_one+0x180/0xbc0 [17751.107097] hns_nic_common_poll+0x94/0x140 [17751.111333] net_rx_action+0x458/0x5e0 [17751.115123] __do_softirq+0x1b8/0x480 [17751.118823] run_ksoftirqd+0x64/0x80 [17751.122437] smpboot_thread_fn+0x224/0x310 [17751.126575] kthread+0x150/0x170 [17751.129838] ret_from_fork+0x10/0x40 [17751.133454] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=19 cpu=7 pid=43 [17751.139951] free_debug_processing+0x1d4/0x2c0 [17751.144436] __slab_free+0x240/0x390 [17751.148051] kmem_cache_free+0x24c/0x270 [17751.152014] kfree_skbmem+0xa0/0xb0 [17751.155543] __kfree_skb+0x28/0x40 [17751.159022] napi_gro_receive+0x168/0x1c0 [17751.163074] hns_nic_rx_up_pro+0x58/0x90 [17751.167041] hns_nic_rx_poll_one+0x518/0xbc0 [17751.171358] hns_nic_common_poll+0x94/0x140 [17751.175585] net_rx_action+0x458/0x5e0 [17751.179373] __do_softirq+0x1b8/0x480 [17751.183076] run_ksoftirqd+0x64/0x80 [17751.186691] smpboot_thread_fn+0x224/0x310 [17751.190826] kthread+0x150/0x170 [17751.194093] ret_from_fork+0x10/0x40 Commit 27463ad99f738ed93c7c8b3e2e5bc8c4853a2ff2 upstream Change-Id: Iad4205c6834669d41aad8169ec8cbc74c687a19d Fixes: 13ac695e7ea1 ("net:hns: Add support of Hip06 SoC to the Hislicon Network Subsystem") Signed-off-by: Yunsheng Lin Signed-off-by: lipeng Reported-by: Jun He Signed-off-by: David S. Miller Signed-off-by: Erick Reyes --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 +++++++++---------- drivers/net/ethernet/hisilicon/hns/hns_enet.h | 6 ++--- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index a79e0a1100aa..111e1aab7d83 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -299,9 +299,9 @@ static void fill_tso_desc(struct hnae_ring *ring, void *priv, mtu); } -int hns_nic_net_xmit_hw(struct net_device *ndev, - struct sk_buff *skb, - struct hns_nic_ring_data *ring_data) +netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev, + struct sk_buff *skb, + struct hns_nic_ring_data *ring_data) { struct hns_nic_priv *priv = netdev_priv(ndev); struct hnae_ring *ring = ring_data->ring; @@ -360,6 +360,10 @@ int hns_nic_net_xmit_hw(struct net_device *ndev, dev_queue = netdev_get_tx_queue(ndev, skb->queue_mapping); netdev_tx_sent_queue(dev_queue, skb->len); + netif_trans_update(ndev); + ndev->stats.tx_bytes += skb->len; + ndev->stats.tx_packets++; + wmb(); /* commit all data before submit */ assert(skb->queue_mapping < priv->ae_handle->q_num); hnae_queue_xmit(priv->ae_handle->qs[skb->queue_mapping], buf_num); @@ -1408,17 +1412,11 @@ static netdev_tx_t hns_nic_net_xmit(struct sk_buff *skb, struct net_device *ndev) { struct hns_nic_priv *priv = netdev_priv(ndev); - int ret; assert(skb->queue_mapping < ndev->ae_handle->q_num); - ret = hns_nic_net_xmit_hw(ndev, skb, - &tx_ring_data(priv, skb->queue_mapping)); - if (ret == NETDEV_TX_OK) { - netif_trans_update(ndev); - ndev->stats.tx_bytes += skb->len; - ndev->stats.tx_packets++; - } - return (netdev_tx_t)ret; + + return hns_nic_net_xmit_hw(ndev, skb, + &tx_ring_data(priv, skb->queue_mapping)); } static int hns_nic_change_mtu(struct net_device *ndev, int new_mtu) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.h b/drivers/net/ethernet/hisilicon/hns/hns_enet.h index 5b412de350aa..7bc6a6ecd666 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.h @@ -91,8 +91,8 @@ void hns_ethtool_set_ops(struct net_device *ndev); void hns_nic_net_reset(struct net_device *ndev); void hns_nic_net_reinit(struct net_device *netdev); int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h); -int hns_nic_net_xmit_hw(struct net_device *ndev, - struct sk_buff *skb, - struct hns_nic_ring_data *ring_data); +netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev, + struct sk_buff *skb, + struct hns_nic_ring_data *ring_data); #endif /**__HNS_ENET_H */ -- GitLab From cc88c05eca317a1d8cf9ca22fc275192329bf9a2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 30 Mar 2018 10:43:30 +0200 Subject: [PATCH 0835/1834] Revert "genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs" This reverts commit f2596a9808acfd02ce1ee389f0e1c37e64aec5f6 which is commit 382bd4de61827dbaaf5fb4fb7b1f4be4a86505e7 upstream. It causes too many problems with the stable tree, and would require too many other things to be backported, so just revert it. Reported-by: Guenter Roeck Cc: Thomas Gleixner Cc: Hans de Goede Cc: Marc Zyngier Cc: Thomas Gleixner Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ed18aa4dceab..ea41820ab12e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1210,10 +1210,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) * set the trigger type must match. Also all must * agree on ONESHOT. */ - unsigned int oldtype = irqd_get_trigger_type(&desc->irq_data); - if (!((old->flags & new->flags) & IRQF_SHARED) || - (oldtype != (new->flags & IRQF_TRIGGER_MASK)) || + ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || ((old->flags ^ new->flags) & IRQF_ONESHOT)) goto mismatch; -- GitLab From 6505dd1f7f55b180439c15d788bc5dea244a4781 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 10 May 2017 09:53:40 +0200 Subject: [PATCH 0836/1834] scsi: sg: don't return bogus Sg_requests commit 48ae8484e9fc324b4968d33c585e54bc98e44d61 upstream. If the list search in sg_get_rq_mark() fails to find a valid request, we return a bogus element. This then can later lead to a GPF in sg_remove_scat(). So don't return bogus Sg_requests in sg_get_rq_mark() but NULL in case the list search doesn't find a valid request. Signed-off-by: Johannes Thumshirn Reported-by: Andrey Konovalov Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Doug Gilbert Reviewed-by: Hannes Reinecke Acked-by: Doug Gilbert Signed-off-by: Martin K. Petersen Cc: Tony Battersby Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/sg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7592ac8514d2..f61b37109e5c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -2064,11 +2064,12 @@ sg_get_rq_mark(Sg_fd * sfp, int pack_id) if ((1 == resp->done) && (!resp->sg_io_owned) && ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { resp->done = 2; /* guard against other readers */ - break; + write_unlock_irqrestore(&sfp->rq_list_lock, iflags); + return resp; } } write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return resp; + return NULL; } /* always adds to end of list */ -- GitLab From 6c9ca571a979cdd8adfb741d536916ece6a50bdf Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 30 Mar 2018 10:53:44 +0200 Subject: [PATCH 0837/1834] Revert "genirq: Use irqd_get_trigger_type to compare the trigger type for shared IRQs" This reverts commit f2596a9808acfd02ce1ee389f0e1c37e64aec5f6 which is commit 382bd4de61827dbaaf5fb4fb7b1f4be4a86505e7 upstream. It causes too many problems with the stable tree, and would require too many other things to be backported, so just revert it. Reported-by: Guenter Roeck Cc: Thomas Gleixner Cc: Hans de Goede Cc: Marc Zyngier Cc: Thomas Gleixner Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ed18aa4dceab..ea41820ab12e 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -1210,10 +1210,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) * set the trigger type must match. Also all must * agree on ONESHOT. */ - unsigned int oldtype = irqd_get_trigger_type(&desc->irq_data); - if (!((old->flags & new->flags) & IRQF_SHARED) || - (oldtype != (new->flags & IRQF_TRIGGER_MASK)) || + ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || ((old->flags ^ new->flags) & IRQF_ONESHOT)) goto mismatch; -- GitLab From 4f2f7a07dbe54458ae36c0d56fdd637f353d09b1 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Mon, 12 Mar 2018 16:20:58 -0400 Subject: [PATCH 0838/1834] net sched actions: return explicit error when tunnel_key mode is not specified [ Upstream commit 51d4740f88affd85d49c04e3c9cd129c0e33bcb9 ] If set/unset mode of the tunnel_key action is not provided, ->init() still returns 0, and the caller proceeds with bogus 'struct tc_action *' object, this results in crash: % tc actions add action tunnel_key src_ip 1.1.1.1 dst_ip 2.2.2.1 id 7 index 1 [ 35.805515] general protection fault: 0000 [#1] SMP PTI [ 35.806161] Modules linked in: act_tunnel_key kvm_intel kvm irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel pcbc aesni_intel aes_x86_64 crypto_simd glue_helper cryptd serio_raw [ 35.808233] CPU: 1 PID: 428 Comm: tc Not tainted 4.16.0-rc4+ #286 [ 35.808929] RIP: 0010:tcf_action_init+0x90/0x190 [ 35.809457] RSP: 0018:ffffb8edc068b9a0 EFLAGS: 00010206 [ 35.810053] RAX: 1320c000000a0003 RBX: 0000000000000001 RCX: 0000000000000000 [ 35.810866] RDX: 0000000000000070 RSI: 0000000000007965 RDI: ffffb8edc068b910 [ 35.811660] RBP: ffffb8edc068b9d0 R08: 0000000000000000 R09: ffffb8edc068b808 [ 35.812463] R10: ffffffffc02bf040 R11: 0000000000000040 R12: ffffb8edc068bb38 [ 35.813235] R13: 0000000000000000 R14: 0000000000000000 R15: ffffb8edc068b910 [ 35.814006] FS: 00007f3d0d8556c0(0000) GS:ffff91d1dbc40000(0000) knlGS:0000000000000000 [ 35.814881] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 35.815540] CR2: 000000000043f720 CR3: 0000000019248001 CR4: 00000000001606a0 [ 35.816457] Call Trace: [ 35.817158] tc_ctl_action+0x11a/0x220 [ 35.817795] rtnetlink_rcv_msg+0x23d/0x2e0 [ 35.818457] ? __slab_alloc+0x1c/0x30 [ 35.819079] ? __kmalloc_node_track_caller+0xb1/0x2b0 [ 35.819544] ? rtnl_calcit.isra.30+0xe0/0xe0 [ 35.820231] netlink_rcv_skb+0xce/0x100 [ 35.820744] netlink_unicast+0x164/0x220 [ 35.821500] netlink_sendmsg+0x293/0x370 [ 35.822040] sock_sendmsg+0x30/0x40 [ 35.822508] ___sys_sendmsg+0x2c5/0x2e0 [ 35.823149] ? pagecache_get_page+0x27/0x220 [ 35.823714] ? filemap_fault+0xa2/0x640 [ 35.824423] ? page_add_file_rmap+0x108/0x200 [ 35.825065] ? alloc_set_pte+0x2aa/0x530 [ 35.825585] ? finish_fault+0x4e/0x70 [ 35.826140] ? __handle_mm_fault+0xbc1/0x10d0 [ 35.826723] ? __sys_sendmsg+0x41/0x70 [ 35.827230] __sys_sendmsg+0x41/0x70 [ 35.827710] do_syscall_64+0x68/0x120 [ 35.828195] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 35.828859] RIP: 0033:0x7f3d0ca4da67 [ 35.829331] RSP: 002b:00007ffc9f284338 EFLAGS: 00000246 ORIG_RAX: 000000000000002e [ 35.830304] RAX: ffffffffffffffda RBX: 00007ffc9f284460 RCX: 00007f3d0ca4da67 [ 35.831247] RDX: 0000000000000000 RSI: 00007ffc9f2843b0 RDI: 0000000000000003 [ 35.832167] RBP: 000000005aa6a7a9 R08: 0000000000000001 R09: 0000000000000000 [ 35.833075] R10: 00000000000005f1 R11: 0000000000000246 R12: 0000000000000000 [ 35.833997] R13: 00007ffc9f2884c0 R14: 0000000000000001 R15: 0000000000674640 [ 35.834923] Code: 24 30 bb 01 00 00 00 45 31 f6 eb 5e 8b 50 08 83 c2 07 83 e2 fc 83 c2 70 49 8b 07 48 8b 40 70 48 85 c0 74 10 48 89 14 24 4c 89 ff d0 48 8b 14 24 48 01 c2 49 01 d6 45 85 ed 74 05 41 83 47 2c [ 35.837442] RIP: tcf_action_init+0x90/0x190 RSP: ffffb8edc068b9a0 [ 35.838291] ---[ end trace a095c06ee4b97a26 ]--- Fixes: d0f6dd8a914f ("net/sched: Introduce act_tunnel_key") Signed-off-by: Roman Mashak Acked-by: Cong Wang Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_tunnel_key.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index af47bdf2f483..b6e3abe505ac 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -141,6 +141,7 @@ static int tunnel_key_init(struct net *net, struct nlattr *nla, metadata->u.tun_info.mode |= IP_TUNNEL_INFO_TX; break; default: + ret = -EINVAL; goto err_out; } -- GitLab From fe3627f6761c40a408d426488fb638bc3c6a8ab7 Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Tue, 20 Mar 2018 16:49:26 +0100 Subject: [PATCH 0839/1834] ppp: avoid loop in xmit recursion detection code [ Upstream commit 6d066734e9f09cdea4a3b9cb76136db3f29cfb02 ] We already detect situations where a PPP channel sends packets back to its upper PPP device. While this is enough to avoid deadlocking on xmit locks, this doesn't prevent packets from looping between the channel and the unit. The problem is that ppp_start_xmit() enqueues packets in ppp->file.xq before checking for xmit recursion. Therefore, __ppp_xmit_process() might dequeue a packet from ppp->file.xq and send it on the channel which, in turn, loops it back on the unit. Then ppp_start_xmit() queues the packet back to ppp->file.xq and __ppp_xmit_process() picks it up and sends it again through the channel. Therefore, the packet will loop between __ppp_xmit_process() and ppp_start_xmit() until some other part of the xmit path drops it. For L2TP, we rapidly fill the skb's headroom and pppol2tp_xmit() drops the packet after a few iterations. But PPTP reallocates the headroom if necessary, letting the loop run and exhaust the machine resources (as reported in https://bugzilla.kernel.org/show_bug.cgi?id=199109). Fix this by letting __ppp_xmit_process() enqueue the skb to ppp->file.xq, so that we can check for recursion before adding it to the queue. Now ppp_xmit_process() can drop the packet when recursion is detected. __ppp_channel_push() is a bit special. It calls __ppp_xmit_process() without having any actual packet to send. This is used by ppp_output_wakeup() to re-enable transmission on the parent unit (for implementations like ppp_async.c, where the .start_xmit() function might not consume the skb, leaving it in ppp->xmit_pending and disabling transmission). Therefore, __ppp_xmit_process() needs to handle the case where skb is NULL, dequeuing as many packets as possible from ppp->file.xq. Reported-by: xu heng Fixes: 55454a565836 ("ppp: avoid dealock on recursive xmit") Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/ppp_generic.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index 114457921890..1e4969d90f1a 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -255,7 +255,7 @@ struct ppp_net { /* Prototypes. */ static int ppp_unattached_ioctl(struct net *net, struct ppp_file *pf, struct file *file, unsigned int cmd, unsigned long arg); -static void ppp_xmit_process(struct ppp *ppp); +static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb); static void ppp_send_frame(struct ppp *ppp, struct sk_buff *skb); static void ppp_push(struct ppp *ppp); static void ppp_channel_push(struct channel *pch); @@ -511,13 +511,12 @@ static ssize_t ppp_write(struct file *file, const char __user *buf, goto out; } - skb_queue_tail(&pf->xq, skb); - switch (pf->kind) { case INTERFACE: - ppp_xmit_process(PF_TO_PPP(pf)); + ppp_xmit_process(PF_TO_PPP(pf), skb); break; case CHANNEL: + skb_queue_tail(&pf->xq, skb); ppp_channel_push(PF_TO_CHANNEL(pf)); break; } @@ -1261,8 +1260,8 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) put_unaligned_be16(proto, pp); skb_scrub_packet(skb, !net_eq(ppp->ppp_net, dev_net(dev))); - skb_queue_tail(&ppp->file.xq, skb); - ppp_xmit_process(ppp); + ppp_xmit_process(ppp, skb); + return NETDEV_TX_OK; outf: @@ -1416,13 +1415,14 @@ static void ppp_setup(struct net_device *dev) */ /* Called to do any work queued up on the transmit side that can now be done */ -static void __ppp_xmit_process(struct ppp *ppp) +static void __ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb) { - struct sk_buff *skb; - ppp_xmit_lock(ppp); if (!ppp->closing) { ppp_push(ppp); + + if (skb) + skb_queue_tail(&ppp->file.xq, skb); while (!ppp->xmit_pending && (skb = skb_dequeue(&ppp->file.xq))) ppp_send_frame(ppp, skb); @@ -1436,7 +1436,7 @@ static void __ppp_xmit_process(struct ppp *ppp) ppp_xmit_unlock(ppp); } -static void ppp_xmit_process(struct ppp *ppp) +static void ppp_xmit_process(struct ppp *ppp, struct sk_buff *skb) { local_bh_disable(); @@ -1444,7 +1444,7 @@ static void ppp_xmit_process(struct ppp *ppp) goto err; (*this_cpu_ptr(ppp->xmit_recursion))++; - __ppp_xmit_process(ppp); + __ppp_xmit_process(ppp, skb); (*this_cpu_ptr(ppp->xmit_recursion))--; local_bh_enable(); @@ -1454,6 +1454,8 @@ static void ppp_xmit_process(struct ppp *ppp) err: local_bh_enable(); + kfree_skb(skb); + if (net_ratelimit()) netdev_err(ppp->dev, "recursion detected\n"); } @@ -1938,7 +1940,7 @@ static void __ppp_channel_push(struct channel *pch) if (skb_queue_empty(&pch->file.xq)) { ppp = pch->ppp; if (ppp) - __ppp_xmit_process(ppp); + __ppp_xmit_process(ppp, NULL); } } -- GitLab From ad6217049ef4262b7926f4339095a41aaa7844a5 Mon Sep 17 00:00:00 2001 From: Paul Blakey Date: Sun, 4 Mar 2018 17:29:48 +0200 Subject: [PATCH 0840/1834] rhashtable: Fix rhlist duplicates insertion [ Upstream commit d3dcf8eb615537526bd42ff27a081d46d337816e ] When inserting duplicate objects (those with the same key), current rhlist implementation messes up the chain pointers by updating the bucket pointer instead of prev next pointer to the newly inserted node. This causes missing elements on removal and travesal. Fix that by properly updating pprev pointer to point to the correct rhash_head next pointer. Issue: 1241076 Change-Id: I86b2c140bcb4aeb10b70a72a267ff590bb2b17e7 Fixes: ca26893f05e8 ('rhashtable: Add rhlist interface') Signed-off-by: Paul Blakey Acked-by: Herbert Xu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/rhashtable.h | 4 +++- lib/rhashtable.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h index 5c132d3188be..85d1ffc90285 100644 --- a/include/linux/rhashtable.h +++ b/include/linux/rhashtable.h @@ -706,8 +706,10 @@ static inline void *__rhashtable_insert_fast( if (!key || (params.obj_cmpfn ? params.obj_cmpfn(&arg, rht_obj(ht, head)) : - rhashtable_compare(&arg, rht_obj(ht, head)))) + rhashtable_compare(&arg, rht_obj(ht, head)))) { + pprev = &head->next; continue; + } data = rht_obj(ht, head); diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 32d0ad058380..895961c53385 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -448,8 +448,10 @@ static void *rhashtable_lookup_one(struct rhashtable *ht, if (!key || (ht->p.obj_cmpfn ? ht->p.obj_cmpfn(&arg, rht_obj(ht, head)) : - rhashtable_compare(&arg, rht_obj(ht, head)))) + rhashtable_compare(&arg, rht_obj(ht, head)))) { + pprev = &head->next; continue; + } if (!ht->rhlist) return rht_obj(ht, head); -- GitLab From e927ffbf07c72d08d24a7eda9a1ede2d934a59fc Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Mon, 5 Mar 2018 20:52:54 +0300 Subject: [PATCH 0841/1834] sch_netem: fix skb leak in netem_enqueue() [ Upstream commit 35d889d10b649fda66121891ec05eca88150059d ] When we exceed current packets limit and we have more than one segment in the list returned by skb_gso_segment(), netem drops only the first one, skipping the rest, hence kmemleak reports: unreferenced object 0xffff880b5d23b600 (size 1024): comm "softirq", pid 0, jiffies 4384527763 (age 2770.629s) hex dump (first 32 bytes): 00 80 23 5d 0b 88 ff ff 00 00 00 00 00 00 00 00 ..#]............ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ backtrace: [<00000000d8a19b9d>] __alloc_skb+0xc9/0x520 [<000000001709b32f>] skb_segment+0x8c8/0x3710 [<00000000c7b9bb88>] tcp_gso_segment+0x331/0x1830 [<00000000c921cba1>] inet_gso_segment+0x476/0x1370 [<000000008b762dd4>] skb_mac_gso_segment+0x1f9/0x510 [<000000002182660a>] __skb_gso_segment+0x1dd/0x620 [<00000000412651b9>] netem_enqueue+0x1536/0x2590 [sch_netem] [<0000000005d3b2a9>] __dev_queue_xmit+0x1167/0x2120 [<00000000fc5f7327>] ip_finish_output2+0x998/0xf00 [<00000000d309e9d3>] ip_output+0x1aa/0x2c0 [<000000007ecbd3a4>] tcp_transmit_skb+0x18db/0x3670 [<0000000042d2a45f>] tcp_write_xmit+0x4d4/0x58c0 [<0000000056a44199>] tcp_tasklet_func+0x3d9/0x540 [<0000000013d06d02>] tasklet_action+0x1ca/0x250 [<00000000fcde0b8b>] __do_softirq+0x1b4/0x5a3 [<00000000e7ed027c>] irq_exit+0x1e2/0x210 Fix it by adding the rest of the segments, if any, to skb 'to_free' list. Add new __qdisc_drop_all() and qdisc_drop_all() functions because they can be useful in the future if we need to drop segmented GSO packets in other places. Fixes: 6071bd1aa13e ("netem: Segment GSO packets on enqueue") Signed-off-by: Alexey Kodanev Acked-by: Neil Horman Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/net/sch_generic.h | 19 +++++++++++++++++++ net/sched/sch_netem.c | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index f18fc1a0321f..538f3c4458b0 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -675,6 +675,16 @@ static inline void __qdisc_drop(struct sk_buff *skb, struct sk_buff **to_free) *to_free = skb; } +static inline void __qdisc_drop_all(struct sk_buff *skb, + struct sk_buff **to_free) +{ + if (skb->prev) + skb->prev->next = *to_free; + else + skb->next = *to_free; + *to_free = skb; +} + static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch, struct qdisc_skb_head *qh, struct sk_buff **to_free) @@ -795,6 +805,15 @@ static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch, return NET_XMIT_DROP; } +static inline int qdisc_drop_all(struct sk_buff *skb, struct Qdisc *sch, + struct sk_buff **to_free) +{ + __qdisc_drop_all(skb, to_free); + qdisc_qstats_drop(sch); + + return NET_XMIT_DROP; +} + /* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how long it will take to send a packet given its size. */ diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index c73d58872cf8..e899d9eb76cb 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -513,7 +513,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, } if (unlikely(sch->q.qlen >= sch->limit)) - return qdisc_drop(skb, sch, to_free); + return qdisc_drop_all(skb, sch, to_free); qdisc_qstats_backlog_inc(sch, skb); -- GitLab From e7d7956673d986001c2a4e564133e0c4d2e3a082 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 5 Mar 2018 08:51:03 -0800 Subject: [PATCH 0842/1834] ieee802154: 6lowpan: fix possible NULL deref in lowpan_device_event() [ Upstream commit ca0edb131bdf1e6beaeb2b8289fd6b374b74147d ] A tun device type can trivially be set to arbitrary value using TUNSETLINK ioctl(). Therefore, lowpan_device_event() must really check that ieee802154_ptr is not NULL. Fixes: 2c88b5283f60d ("ieee802154: 6lowpan: remove check on null") Signed-off-by: Eric Dumazet Cc: Alexander Aring Cc: Stefan Schmidt Reported-by: syzbot Acked-by: Stefan Schmidt Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ieee802154/6lowpan/core.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c index d7efbf0dad20..83af5339e582 100644 --- a/net/ieee802154/6lowpan/core.c +++ b/net/ieee802154/6lowpan/core.c @@ -204,9 +204,13 @@ static inline void lowpan_netlink_fini(void) static int lowpan_device_event(struct notifier_block *unused, unsigned long event, void *ptr) { - struct net_device *wdev = netdev_notifier_info_to_dev(ptr); + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct wpan_dev *wpan_dev; - if (wdev->type != ARPHRD_IEEE802154) + if (ndev->type != ARPHRD_IEEE802154) + return NOTIFY_DONE; + wpan_dev = ndev->ieee802154_ptr; + if (!wpan_dev) return NOTIFY_DONE; switch (event) { @@ -215,8 +219,8 @@ static int lowpan_device_event(struct notifier_block *unused, * also delete possible lowpan interfaces which belongs * to the wpan interface. */ - if (wdev->ieee802154_ptr->lowpan_dev) - lowpan_dellink(wdev->ieee802154_ptr->lowpan_dev, NULL); + if (wpan_dev->lowpan_dev) + lowpan_dellink(wpan_dev->lowpan_dev, NULL); break; default: return NOTIFY_DONE; -- GitLab From 28984ba0c4ec741da06fb4bb41bf7993193b27ea Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 14 Mar 2018 09:04:16 -0700 Subject: [PATCH 0843/1834] net: use skb_to_full_sk() in skb_update_prio() [ Upstream commit 4dcb31d4649df36297296b819437709f5407059c ] Andrei Vagin reported a KASAN: slab-out-of-bounds error in skb_update_prio() Since SYNACK might be attached to a request socket, we need to get back to the listener socket. Since this listener is manipulated without locks, add const qualifiers to sock_cgroup_prioidx() so that the const can also be used in skb_update_prio() Also add the const qualifier to sock_cgroup_classid() for consistency. Fixes: ca6fb0651883 ("tcp: attach SYNACK messages to request sockets instead of listener") Signed-off-by: Eric Dumazet Reported-by: Andrei Vagin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- include/linux/cgroup-defs.h | 4 ++-- net/core/dev.c | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 6fb1c34cf805..1619a3213af5 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -609,13 +609,13 @@ struct sock_cgroup_data { * updaters and return part of the previous pointer as the prioidx or * classid. Such races are short-lived and the result isn't critical. */ -static inline u16 sock_cgroup_prioidx(struct sock_cgroup_data *skcd) +static inline u16 sock_cgroup_prioidx(const struct sock_cgroup_data *skcd) { /* fallback to 1 which is always the ID of the root cgroup */ return (skcd->is_data & 1) ? skcd->prioidx : 1; } -static inline u32 sock_cgroup_classid(struct sock_cgroup_data *skcd) +static inline u32 sock_cgroup_classid(const struct sock_cgroup_data *skcd) { /* fallback to 0 which is the unconfigured default classid */ return (skcd->is_data & 1) ? skcd->classid : 0; diff --git a/net/core/dev.c b/net/core/dev.c index 272f84ad16e0..07d2c93c9636 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3179,15 +3179,23 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, #if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) static void skb_update_prio(struct sk_buff *skb) { - struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); + const struct netprio_map *map; + const struct sock *sk; + unsigned int prioidx; - if (!skb->priority && skb->sk && map) { - unsigned int prioidx = - sock_cgroup_prioidx(&skb->sk->sk_cgrp_data); + if (skb->priority) + return; + map = rcu_dereference_bh(skb->dev->priomap); + if (!map) + return; + sk = skb_to_full_sk(skb); + if (!sk) + return; - if (prioidx < map->priomap_len) - skb->priority = map->priomap[prioidx]; - } + prioidx = sock_cgroup_prioidx(&sk->sk_cgrp_data); + + if (prioidx < map->priomap_len) + skb->priority = map->priomap[prioidx]; } #else #define skb_update_prio(skb) -- GitLab From 1562f147ac2b30c85ce09a86f7c480c740e6b37a Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Tue, 6 Mar 2018 18:46:39 +0300 Subject: [PATCH 0844/1834] net: Fix hlist corruptions in inet_evict_bucket() [ Upstream commit a560002437d3646dafccecb1bf32d1685112ddda ] inet_evict_bucket() iterates global list, and several tasks may call it in parallel. All of them hash the same fq->list_evictor to different lists, which leads to list corruption. This patch makes fq be hashed to expired list only if this has not been made yet by another task. Since inet_frag_alloc() allocates fq using kmem_cache_zalloc(), we may rely on list_evictor is initially unhashed. The problem seems to exist before async pernet_operations, as there was possible to have exit method to be executed in parallel with inet_frags::frags_work, so I add two Fixes tags. This also may go to stable. Fixes: d1fe19444d82 "inet: frag: don't re-use chainlist for evictor" Fixes: f84c6821aa54 "net: Convert pernet_subsys, registered from inet_init()" Signed-off-by: Kirill Tkhai Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/inet_fragment.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 631c0d0d7cf8..8effac0f2219 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -119,6 +119,9 @@ static void inet_frag_secret_rebuild(struct inet_frags *f) static bool inet_fragq_should_evict(const struct inet_frag_queue *q) { + if (!hlist_unhashed(&q->list_evictor)) + return false; + return q->net->low_thresh == 0 || frag_mem_limit(q->net) >= q->net->low_thresh; } -- GitLab From 1fdc00c1503f2164893454958cf62c3bf4eff8d6 Mon Sep 17 00:00:00 2001 From: Alexey Kodanev Date: Tue, 6 Mar 2018 22:57:01 +0300 Subject: [PATCH 0845/1834] dccp: check sk for closed state in dccp_sendmsg() [ Upstream commit 67f93df79aeefc3add4e4b31a752600f834236e2 ] dccp_disconnect() sets 'dp->dccps_hc_tx_ccid' tx handler to NULL, therefore if DCCP socket is disconnected and dccp_sendmsg() is called after it, it will cause a NULL pointer dereference in dccp_write_xmit(). This crash and the reproducer was reported by syzbot. Looks like it is reproduced if commit 69c64866ce07 ("dccp: CVE-2017-8824: use-after-free in DCCP code") is applied. Reported-by: syzbot+f99ab3887ab65d70f816@syzkaller.appspotmail.com Signed-off-by: Alexey Kodanev Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/dccp/proto.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 9d43c1f40274..ff3b058cf58c 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -789,6 +789,11 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) if (skb == NULL) goto out_release; + if (sk->sk_state == DCCP_CLOSED) { + rc = -ENOTCONN; + goto out_discard; + } + skb_reserve(skb, sk->sk_prot->max_header); rc = memcpy_from_msg(skb_put(skb, len), msg, len); if (rc != 0) -- GitLab From c5e6439e71ace4fb5a123b962c03a00e08c41d50 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Thu, 8 Mar 2018 17:00:02 +0100 Subject: [PATCH 0846/1834] ipv6: fix access to non-linear packet in ndisc_fill_redirect_hdr_option() [ Upstream commit 9f62c15f28b0d1d746734666d88a79f08ba1e43e ] Fix the following slab-out-of-bounds kasan report in ndisc_fill_redirect_hdr_option when the incoming ipv6 packet is not linear and the accessed data are not in the linear data region of orig_skb. [ 1503.122508] ================================================================== [ 1503.122832] BUG: KASAN: slab-out-of-bounds in ndisc_send_redirect+0x94e/0x990 [ 1503.123036] Read of size 1184 at addr ffff8800298ab6b0 by task netperf/1932 [ 1503.123220] CPU: 0 PID: 1932 Comm: netperf Not tainted 4.16.0-rc2+ #124 [ 1503.123347] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.10.2-2.fc27 04/01/2014 [ 1503.123527] Call Trace: [ 1503.123579] [ 1503.123638] print_address_description+0x6e/0x280 [ 1503.123849] kasan_report+0x233/0x350 [ 1503.123946] memcpy+0x1f/0x50 [ 1503.124037] ndisc_send_redirect+0x94e/0x990 [ 1503.125150] ip6_forward+0x1242/0x13b0 [...] [ 1503.153890] Allocated by task 1932: [ 1503.153982] kasan_kmalloc+0x9f/0xd0 [ 1503.154074] __kmalloc_track_caller+0xb5/0x160 [ 1503.154198] __kmalloc_reserve.isra.41+0x24/0x70 [ 1503.154324] __alloc_skb+0x130/0x3e0 [ 1503.154415] sctp_packet_transmit+0x21a/0x1810 [ 1503.154533] sctp_outq_flush+0xc14/0x1db0 [ 1503.154624] sctp_do_sm+0x34e/0x2740 [ 1503.154715] sctp_primitive_SEND+0x57/0x70 [ 1503.154807] sctp_sendmsg+0xaa6/0x1b10 [ 1503.154897] sock_sendmsg+0x68/0x80 [ 1503.154987] ___sys_sendmsg+0x431/0x4b0 [ 1503.155078] __sys_sendmsg+0xa4/0x130 [ 1503.155168] do_syscall_64+0x171/0x3f0 [ 1503.155259] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 1503.155436] Freed by task 1932: [ 1503.155527] __kasan_slab_free+0x134/0x180 [ 1503.155618] kfree+0xbc/0x180 [ 1503.155709] skb_release_data+0x27f/0x2c0 [ 1503.155800] consume_skb+0x94/0xe0 [ 1503.155889] sctp_chunk_put+0x1aa/0x1f0 [ 1503.155979] sctp_inq_pop+0x2f8/0x6e0 [ 1503.156070] sctp_assoc_bh_rcv+0x6a/0x230 [ 1503.156164] sctp_inq_push+0x117/0x150 [ 1503.156255] sctp_backlog_rcv+0xdf/0x4a0 [ 1503.156346] __release_sock+0x142/0x250 [ 1503.156436] release_sock+0x80/0x180 [ 1503.156526] sctp_sendmsg+0xbb0/0x1b10 [ 1503.156617] sock_sendmsg+0x68/0x80 [ 1503.156708] ___sys_sendmsg+0x431/0x4b0 [ 1503.156799] __sys_sendmsg+0xa4/0x130 [ 1503.156889] do_syscall_64+0x171/0x3f0 [ 1503.156980] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 1503.157158] The buggy address belongs to the object at ffff8800298ab600 which belongs to the cache kmalloc-1024 of size 1024 [ 1503.157444] The buggy address is located 176 bytes inside of 1024-byte region [ffff8800298ab600, ffff8800298aba00) [ 1503.157702] The buggy address belongs to the page: [ 1503.157820] page:ffffea0000a62a00 count:1 mapcount:0 mapping:0000000000000000 index:0x0 compound_mapcount: 0 [ 1503.158053] flags: 0x4000000000008100(slab|head) [ 1503.158171] raw: 4000000000008100 0000000000000000 0000000000000000 00000001800e000e [ 1503.158350] raw: dead000000000100 dead000000000200 ffff880036002600 0000000000000000 [ 1503.158523] page dumped because: kasan: bad access detected [ 1503.158698] Memory state around the buggy address: [ 1503.158816] ffff8800298ab900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 1503.158988] ffff8800298ab980: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [ 1503.159165] >ffff8800298aba00: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc [ 1503.159338] ^ [ 1503.159436] ffff8800298aba80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 1503.159610] ffff8800298abb00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb [ 1503.159785] ================================================================== [ 1503.159964] Disabling lock debugging due to kernel taint The test scenario to trigger the issue consists of 4 devices: - H0: data sender, connected to LAN0 - H1: data receiver, connected to LAN1 - GW0 and GW1: routers between LAN0 and LAN1. Both of them have an ethernet connection on LAN0 and LAN1 On H{0,1} set GW0 as default gateway while on GW0 set GW1 as next hop for data from LAN0 to LAN1. Moreover create an ip6ip6 tunnel between H0 and H1 and send 3 concurrent data streams (TCP/UDP/SCTP) from H0 to H1 through ip6ip6 tunnel (send buffer size is set to 16K). While data streams are active flush the route cache on HA multiple times. I have not been able to identify a given commit that introduced the issue since, using the reproducer described above, the kasan report has been triggered from 4.14 and I have not gone back further. Reported-by: Jianlin Shi Reviewed-by: Stefano Brivio Reviewed-by: Eric Dumazet Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ndisc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 41c22cb33424..3fe80e104b58 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1516,7 +1516,8 @@ static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb, *(opt++) = (rd_len >> 3); opt += 6; - memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); + skb_copy_bits(orig_skb, skb_network_offset(orig_skb), opt, + rd_len - 8); } void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) -- GitLab From 84fc2d7c220324000afb3559d9b4a0cea7066004 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 6 Mar 2018 07:54:53 -0800 Subject: [PATCH 0847/1834] l2tp: do not accept arbitrary sockets [ Upstream commit 17cfe79a65f98abe535261856c5aef14f306dff7 ] syzkaller found an issue caused by lack of sufficient checks in l2tp_tunnel_create() RAW sockets can not be considered as UDP ones for instance. In another patch, we shall replace all pr_err() by less intrusive pr_debug() so that syzkaller can find other bugs faster. Acked-by: Guillaume Nault Acked-by: James Chapman ================================================================== BUG: KASAN: slab-out-of-bounds in setup_udp_tunnel_sock+0x3ee/0x5f0 net/ipv4/udp_tunnel.c:69 dst_release: dst:00000000d53d0d0f refcnt:-1 Write of size 1 at addr ffff8801d013b798 by task syz-executor3/6242 CPU: 1 PID: 6242 Comm: syz-executor3 Not tainted 4.16.0-rc2+ #253 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x24d lib/dump_stack.c:53 print_address_description+0x73/0x250 mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report+0x23b/0x360 mm/kasan/report.c:412 __asan_report_store1_noabort+0x17/0x20 mm/kasan/report.c:435 setup_udp_tunnel_sock+0x3ee/0x5f0 net/ipv4/udp_tunnel.c:69 l2tp_tunnel_create+0x1354/0x17f0 net/l2tp/l2tp_core.c:1596 pppol2tp_connect+0x14b1/0x1dd0 net/l2tp/l2tp_ppp.c:707 SYSC_connect+0x213/0x4a0 net/socket.c:1640 SyS_connect+0x24/0x30 net/socket.c:1621 do_syscall_64+0x280/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: fd558d186df2 ("l2tp: Split pppol2tp patch into separate l2tp and ppp parts") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index cfc4dd8997e5..ead98e8e0b1f 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -1612,9 +1612,14 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 encap = cfg->encap; /* Quick sanity checks */ + err = -EPROTONOSUPPORT; + if (sk->sk_type != SOCK_DGRAM) { + pr_debug("tunl %hu: fd %d wrong socket type\n", + tunnel_id, fd); + goto err; + } switch (encap) { case L2TP_ENCAPTYPE_UDP: - err = -EPROTONOSUPPORT; if (sk->sk_protocol != IPPROTO_UDP) { pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n", tunnel_id, fd, sk->sk_protocol, IPPROTO_UDP); @@ -1622,7 +1627,6 @@ int l2tp_tunnel_create(struct net *net, int fd, int version, u32 tunnel_id, u32 } break; case L2TP_ENCAPTYPE_IP: - err = -EPROTONOSUPPORT; if (sk->sk_protocol != IPPROTO_L2TP) { pr_err("tunl %hu: fd %d wrong protocol, got %d, expected %d\n", tunnel_id, fd, sk->sk_protocol, IPPROTO_L2TP); -- GitLab From e9f83a8b4aaba8f458c244c7455f8a4ea31e8a28 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 18 Mar 2018 23:59:36 +0100 Subject: [PATCH 0848/1834] net: ethernet: arc: Fix a potential memory leak if an optional regulator is deferred [ Upstream commit 00777fac28ba3e126b9e63e789a613e8bd2cab25 ] If the optional regulator is deferred, we must release some resources. They will be re-allocated when the probe function will be called again. Fixes: 6eacf31139bf ("ethernet: arc: Add support for Rockchip SoC layer device tree bindings") Signed-off-by: Christophe JAILLET Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/arc/emac_rockchip.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/arc/emac_rockchip.c b/drivers/net/ethernet/arc/emac_rockchip.c index c6163874e4e7..c770ca37c9b2 100644 --- a/drivers/net/ethernet/arc/emac_rockchip.c +++ b/drivers/net/ethernet/arc/emac_rockchip.c @@ -169,8 +169,10 @@ static int emac_rockchip_probe(struct platform_device *pdev) /* Optional regulator for PHY */ priv->regulator = devm_regulator_get_optional(dev, "phy"); if (IS_ERR(priv->regulator)) { - if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) - return -EPROBE_DEFER; + if (PTR_ERR(priv->regulator) == -EPROBE_DEFER) { + err = -EPROBE_DEFER; + goto out_clk_disable; + } dev_err(dev, "no regulator found\n"); priv->regulator = NULL; } -- GitLab From 1f7a395708b3b061109440f23e42de683a0bcdbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SZ=20Lin=20=28=E6=9E=97=E4=B8=8A=E6=99=BA=29?= Date: Fri, 16 Mar 2018 00:56:01 +0800 Subject: [PATCH 0849/1834] net: ethernet: ti: cpsw: add check for in-band mode setting with RGMII PHY interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit f9db50691db4a7d860fce985f080bb3fc23a7ede ] According to AM335x TRM[1] 14.3.6.2, AM437x TRM[2] 15.3.6.2 and DRA7 TRM[3] 24.11.4.8.7.3.3, in-band mode in EXT_EN(bit18) register is only available when PHY is configured in RGMII mode with 10Mbps speed. It will cause some networking issues without RGMII mode, such as carrier sense errors and low throughput. TI also mentioned this issue in their forum[4]. This patch adds the check mechanism for PHY interface with RGMII interface type, the in-band mode can only be set in RGMII mode with 10Mbps speed. References: [1]: https://www.ti.com/lit/ug/spruh73p/spruh73p.pdf [2]: http://www.ti.com/lit/ug/spruhl7h/spruhl7h.pdf [3]: http://www.ti.com/lit/ug/spruic2b/spruic2b.pdf [4]: https://e2e.ti.com/support/arm/sitara_arm/f/791/p/640765/2392155 Suggested-by: Holsety Chen (陳憲輝) Signed-off-by: SZ Lin (林上智) Signed-off-by: Schuyler Patton Reviewed-by: Grygorii Strashko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/cpsw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 3f1971d485f3..2bd1282735b0 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -901,7 +901,8 @@ static void _cpsw_adjust_link(struct cpsw_slave *slave, /* set speed_in input in case RMII mode is used in 100Mbps */ if (phy->speed == 100) mac_control |= BIT(15); - else if (phy->speed == 10) + /* in band mode only works in 10Mbps RGMII mode */ + else if ((phy->speed == 10) && phy_interface_is_rgmii(phy)) mac_control |= BIT(18); /* In Band mode */ if (priv->rx_pause) -- GitLab From c3860a3855e4445d215279561c02a7426c344949 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sun, 18 Mar 2018 12:49:51 -0700 Subject: [PATCH 0850/1834] net: fec: Fix unbalanced PM runtime calls [ Upstream commit a069215cf5985f3aa1bba550264907d6bd05c5f7 ] When unbinding/removing the driver, we will run into the following warnings: [ 259.655198] fec 400d1000.ethernet: 400d1000.ethernet supply phy not found, using dummy regulator [ 259.665065] fec 400d1000.ethernet: Unbalanced pm_runtime_enable! [ 259.672770] fec 400d1000.ethernet (unnamed net_device) (uninitialized): Invalid MAC address: 00:00:00:00:00:00 [ 259.683062] fec 400d1000.ethernet (unnamed net_device) (uninitialized): Using random MAC address: f2:3e:93:b7:29:c1 [ 259.696239] libphy: fec_enet_mii_bus: probed Avoid these warnings by balancing the runtime PM calls during fec_drv_remove(). Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/fec_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index dd6e07c748f5..05e5b38e4891 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3533,6 +3533,8 @@ fec_drv_remove(struct platform_device *pdev) fec_enet_mii_remove(fep); if (fep->reg_phy) regulator_disable(fep->reg_phy); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); if (of_phy_is_fixed_link(np)) of_phy_deregister_fixed_link(np); of_node_put(fep->phy_node); -- GitLab From 7d91487e4319baddd7580df4993d1478ea86ece8 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 13 Mar 2018 16:50:06 +0100 Subject: [PATCH 0851/1834] net/iucv: Free memory obtained by kzalloc [ Upstream commit fa6a91e9b907231d2e38ea5ed89c537b3525df3d ] Free memory by calling put_device(), if afiucv_iucv_init is not successful. Signed-off-by: Arvind Yadav Reviewed-by: Cornelia Huck Signed-off-by: Ursula Braun Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/iucv/af_iucv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index 91cbbf1c3f82..c2dfc32eb9f2 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -2418,9 +2418,11 @@ static int afiucv_iucv_init(void) af_iucv_dev->driver = &af_iucv_driver; err = device_register(af_iucv_dev); if (err) - goto out_driver; + goto out_iucv_dev; return 0; +out_iucv_dev: + put_device(af_iucv_dev); out_driver: driver_unregister(&af_iucv_driver); out_iucv: -- GitLab From 455fc99cb4e8222c40cf9ae97f4e5845bdcac17c Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Wed, 14 Mar 2018 21:10:23 +0100 Subject: [PATCH 0852/1834] netlink: avoid a double skb free in genlmsg_mcast() [ Upstream commit 02a2385f37a7c6594c9d89b64c4a1451276f08eb ] nlmsg_multicast() consumes always the skb, thus the original skb must be freed only when this function is called with a clone. Fixes: cb9f7a9a5c96 ("netlink: ensure to loop over all netns in genlmsg_multicast_allns()") Reported-by: Ben Hutchings Signed-off-by: Nicolas Dichtel Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/genetlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 11702016c900..9192a6143523 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -1128,7 +1128,7 @@ static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, if (!err) delivered = true; else if (err != -ESRCH) - goto error; + return err; return delivered ? 0 : -ESRCH; error: kfree_skb(skb); -- GitLab From 5f02dcec3653abb204cb23e25132f49eb314c84f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 16 Feb 2018 11:03:03 -0800 Subject: [PATCH 0853/1834] net: Only honor ifindex in IP_PKTINFO if non-0 [ Upstream commit 2cbb4ea7de167b02ffa63e9cdfdb07a7e7094615 ] Only allow ifindex from IP_PKTINFO to override SO_BINDTODEVICE settings if the index is actually set in the message. Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_sockglue.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index fd1e6b8562e0..5ddd64995e73 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -242,7 +242,8 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc, src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); if (!ipv6_addr_v4mapped(&src_info->ipi6_addr)) return -EINVAL; - ipc->oif = src_info->ipi6_ifindex; + if (src_info->ipi6_ifindex) + ipc->oif = src_info->ipi6_ifindex; ipc->addr = src_info->ipi6_addr.s6_addr32[3]; continue; } @@ -272,7 +273,8 @@ int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc, if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo))) return -EINVAL; info = (struct in_pktinfo *)CMSG_DATA(cmsg); - ipc->oif = info->ipi_ifindex; + if (info->ipi_ifindex) + ipc->oif = info->ipi_ifindex; ipc->addr = info->ipi_spec_dst.s_addr; break; } -- GitLab From d5862b05903c8b1f49dab92683872854581b9812 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Wed, 14 Mar 2018 13:32:09 -0700 Subject: [PATCH 0854/1834] skbuff: Fix not waking applications when errors are enqueued [ Upstream commit 6e5d58fdc9bedd0255a8781b258f10bbdc63e975 ] When errors are enqueued to the error queue via sock_queue_err_skb() function, it is possible that the waiting application is not notified. Calling 'sk->sk_data_ready()' would not notify applications that selected only POLLERR events in poll() (for example). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: Randy E. Witt Reviewed-by: Eric Dumazet Signed-off-by: Vinicius Costa Gomes Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/skbuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a64515583bc1..c5ac9f48f058 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3717,7 +3717,7 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) skb_queue_tail(&sk->sk_error_queue, skb); if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); + sk->sk_error_report(sk); return 0; } EXPORT_SYMBOL(sock_queue_err_skb); -- GitLab From b14031144e37fd5f53a6a4a1359d91b0210ca47f Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Thu, 8 Mar 2018 12:42:10 +0200 Subject: [PATCH 0855/1834] team: Fix double free in error path [ Upstream commit cbcc607e18422555db569b593608aec26111cb0b ] The __send_and_alloc_skb() receives a skb ptr as a parameter but in case it fails the skb is not valid: - Send failed and released the skb internally. - Allocation failed. The current code tries to release the skb in case of failure which causes redundant freeing. Fixes: 9b00cf2d1024 ("team: implement multipart netlink messages for options transfers") Signed-off-by: Arkadi Sharshevsky Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 26681707fc7a..a0a9c9d39f01 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2403,7 +2403,7 @@ static int team_nl_send_options_get(struct team *team, u32 portid, u32 seq, if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } @@ -2688,7 +2688,7 @@ static int team_nl_send_port_list_get(struct team *team, u32 portid, u32 seq, if (!nlh) { err = __send_and_alloc_skb(&skb, team, portid, send_func); if (err) - goto errout; + return err; goto send_done; } -- GitLab From a85c525bbff4d7467d7f0ab6fed8e2f787b073d6 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 14 Mar 2018 08:37:28 -0500 Subject: [PATCH 0856/1834] soc/fsl/qbman: fix issue in qman_delete_cgr_safe() [ Upstream commit 96f413f47677366e0ae03797409bfcc4151dbf9e ] The wait_for_completion() call in qman_delete_cgr_safe() was triggering a scheduling while atomic bug, replacing the kthread with a smp_call_function_single() call to fix it. Signed-off-by: Madalin Bucur Signed-off-by: Roy Pledge Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/soc/fsl/qbman/qman.c | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 119054bc922b..2caacd9d2526 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -2429,39 +2429,21 @@ struct cgr_comp { struct completion completion; }; -static int qman_delete_cgr_thread(void *p) +static void qman_delete_cgr_smp_call(void *p) { - struct cgr_comp *cgr_comp = (struct cgr_comp *)p; - int ret; - - ret = qman_delete_cgr(cgr_comp->cgr); - complete(&cgr_comp->completion); - - return ret; + qman_delete_cgr((struct qman_cgr *)p); } void qman_delete_cgr_safe(struct qman_cgr *cgr) { - struct task_struct *thread; - struct cgr_comp cgr_comp; - preempt_disable(); if (qman_cgr_cpus[cgr->cgrid] != smp_processor_id()) { - init_completion(&cgr_comp.completion); - cgr_comp.cgr = cgr; - thread = kthread_create(qman_delete_cgr_thread, &cgr_comp, - "cgr_del"); - - if (IS_ERR(thread)) - goto out; - - kthread_bind(thread, qman_cgr_cpus[cgr->cgrid]); - wake_up_process(thread); - wait_for_completion(&cgr_comp.completion); + smp_call_function_single(qman_cgr_cpus[cgr->cgrid], + qman_delete_cgr_smp_call, cgr, true); preempt_enable(); return; } -out: + qman_delete_cgr(cgr); preempt_enable(); } -- GitLab From 4593b4c08262434e8f662f12c171a9b8c85dcec4 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 20 Mar 2018 07:59:12 +0100 Subject: [PATCH 0857/1834] s390/qeth: free netdevice when removing a card [ Upstream commit 6be687395b3124f002a653c1a50b3260222b3cd7 ] On removal, a qeth card's netdevice is currently not properly freed because the call chain looks as follows: qeth_core_remove_device(card) lx_remove_device(card) unregister_netdev(card->dev) card->dev = NULL !!! qeth_core_free_card(card) if (card->dev) !!! free_netdev(card->dev) Fix it by free'ing the netdev straight after unregistering. This also fixes the sysfs-driven layer switch case (qeth_dev_layer2_store()), where the need to free the current netdevice was not considered at all. Note that free_netdev() takes care of the netif_napi_del() for us too. Fixes: 4a71df50047f ("qeth: new qeth device driver") Signed-off-by: Julian Wiedmann Reviewed-by: Ursula Braun Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core_main.c | 2 -- drivers/s390/net/qeth_l2_main.c | 2 +- drivers/s390/net/qeth_l3_main.c | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index cc28dda322b5..3e7d54c1437a 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -4989,8 +4989,6 @@ static void qeth_core_free_card(struct qeth_card *card) QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *)); qeth_clean_channel(&card->read); qeth_clean_channel(&card->write); - if (card->dev) - free_netdev(card->dev); qeth_free_qdio_buffers(card); unregister_service_level(&card->qeth_service_level); kfree(card); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 5082dfeacb95..e94e9579914e 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1057,8 +1057,8 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) qeth_l2_set_offline(cgdev); if (card->dev) { - netif_napi_del(&card->napi); unregister_netdev(card->dev); + free_netdev(card->dev); card->dev = NULL; } return; diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index a668e6b71a29..4ca161bdc696 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3192,8 +3192,8 @@ static void qeth_l3_remove_device(struct ccwgroup_device *cgdev) qeth_l3_set_offline(cgdev); if (card->dev) { - netif_napi_del(&card->napi); unregister_netdev(card->dev); + free_netdev(card->dev); card->dev = NULL; } -- GitLab From 9ff2636b3bbfcf4606d050fbbfa2f792ab566b93 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 20 Mar 2018 07:59:13 +0100 Subject: [PATCH 0858/1834] s390/qeth: when thread completes, wake up all waiters [ Upstream commit 1063e432bb45be209427ed3f1ca3908e4aa3c7d7 ] qeth_wait_for_threads() is potentially called by multiple users, make sure to notify all of them after qeth_clear_thread_running_bit() adjusted the thread_running_mask. With no timeout, callers would otherwise stall. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3e7d54c1437a..8b1763bf1840 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -957,7 +957,7 @@ void qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread) spin_lock_irqsave(&card->thread_mask_lock, flags); card->thread_running_mask &= ~thread; spin_unlock_irqrestore(&card->thread_mask_lock, flags); - wake_up(&card->wait_q); + wake_up_all(&card->wait_q); } EXPORT_SYMBOL_GPL(qeth_clear_thread_running_bit); -- GitLab From 3426c365e7f92a538ec7b067134fc42839e75ca7 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 20 Mar 2018 07:59:14 +0100 Subject: [PATCH 0859/1834] s390/qeth: lock read device while queueing next buffer [ Upstream commit 17bf8c9b3d499d5168537c98b61eb7a1fcbca6c2 ] For calling ccw_device_start(), issue_next_read() needs to hold the device's ccwlock. This is satisfied for the IRQ handler path (where qeth_irq() gets called under the ccwlock), but we need explicit locking for the initial call by the MPC initialization. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core_main.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 8b1763bf1840..3c44c80cc66c 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -522,8 +522,7 @@ static inline int qeth_is_cq(struct qeth_card *card, unsigned int queue) queue == card->qdio.no_in_queues - 1; } - -static int qeth_issue_next_read(struct qeth_card *card) +static int __qeth_issue_next_read(struct qeth_card *card) { int rc; struct qeth_cmd_buffer *iob; @@ -554,6 +553,17 @@ static int qeth_issue_next_read(struct qeth_card *card) return rc; } +static int qeth_issue_next_read(struct qeth_card *card) +{ + int ret; + + spin_lock_irq(get_ccwdev_lock(CARD_RDEV(card))); + ret = __qeth_issue_next_read(card); + spin_unlock_irq(get_ccwdev_lock(CARD_RDEV(card))); + + return ret; +} + static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) { struct qeth_reply *reply; @@ -1179,7 +1189,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, return; if (channel == &card->read && channel->state == CH_STATE_UP) - qeth_issue_next_read(card); + __qeth_issue_next_read(card); iob = channel->iob; index = channel->buf_no; -- GitLab From 4751804da25788691602663562bbadfa5f2cb9a1 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Tue, 20 Mar 2018 07:59:15 +0100 Subject: [PATCH 0860/1834] s390/qeth: on channel error, reject further cmd requests [ Upstream commit a6c3d93963e4b333c764fde69802c3ea9eaa9d5c ] When the IRQ handler determines that one of the cmd IO channels has failed and schedules recovery, block any further cmd requests from being submitted. The request would inevitably stall, and prevent the recovery from making progress until the request times out. This sort of error was observed after Live Guest Relocation, where the pending IO on the READ channel intentionally gets terminated to kick-start recovery. Simultaneously the guest executed SIOCETHTOOL, triggering qeth to issue a QUERY CARD INFO command. The command then stalled in the inoperabel WRITE channel. Signed-off-by: Julian Wiedmann Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/s390/net/qeth_core_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 3c44c80cc66c..283416aefa56 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1171,6 +1171,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, } rc = qeth_get_problem(cdev, irb); if (rc) { + card->read_or_write_problem = 1; qeth_clear_ipacmd_list(card); qeth_schedule_recovery(card); goto out; -- GitLab From 002f45571f6b498d417ba1dcc91bd59d386303a2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 13 Mar 2018 14:45:07 -0700 Subject: [PATCH 0861/1834] net: systemport: Rewrite __bcm_sysport_tx_reclaim() [ Upstream commit 484d802d0f2f29c335563fcac2a8facf174a1bbc ] There is no need for complex checking between the last consumed index and current consumed index, a simple subtraction will do. This also eliminates the possibility of a permanent transmit queue stall under the following conditions: - one CPU bursts ring->size worth of traffic (up to 256 buffers), to the point where we run out of free descriptors, so we stop the transmit queue at the end of bcm_sysport_xmit() - because of our locking, we have the transmit process disable interrupts which means we can be blocking the TX reclamation process - when TX reclamation finally runs, we will be computing the difference between ring->c_index (last consumed index by SW) and what the HW reports through its register - this register is masked with (ring->size - 1) = 0xff, which will lead to stripping the upper bits of the index (register is 16-bits wide) - we will be computing last_tx_cn as 0, which means there is no work to be done, and we never wake-up the transmit queue, leaving it permanently disabled A practical example is e.g: ring->c_index aka last_c_index = 12, we pushed 256 entries, HW consumer index = 268, we mask it with 0xff = 12, so last_tx_cn == 0, nothing happens. Fixes: 80105befdb4b ("net: systemport: add Broadcom SYSTEMPORT Ethernet MAC driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/broadcom/bcmsysport.c | 33 ++++++++++------------ drivers/net/ethernet/broadcom/bcmsysport.h | 2 +- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 744ed6ddaf37..91fbba58d033 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -707,37 +707,33 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, struct bcm_sysport_tx_ring *ring) { struct net_device *ndev = priv->netdev; - unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs; unsigned int pkts_compl = 0, bytes_compl = 0; + unsigned int txbds_processed = 0; struct bcm_sysport_cb *cb; + unsigned int txbds_ready; + unsigned int c_index; u32 hw_ind; /* Compute how many descriptors have been processed since last call */ hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index)); c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK; - ring->p_index = (hw_ind & RING_PROD_INDEX_MASK); - - last_c_index = ring->c_index; - num_tx_cbs = ring->size; - - c_index &= (num_tx_cbs - 1); - - if (c_index >= last_c_index) - last_tx_cn = c_index - last_c_index; - else - last_tx_cn = num_tx_cbs - last_c_index + c_index; + txbds_ready = (c_index - ring->c_index) & RING_CONS_INDEX_MASK; netif_dbg(priv, tx_done, ndev, - "ring=%d c_index=%d last_tx_cn=%d last_c_index=%d\n", - ring->index, c_index, last_tx_cn, last_c_index); + "ring=%d old_c_index=%u c_index=%u txbds_ready=%u\n", + ring->index, ring->c_index, c_index, txbds_ready); - while (last_tx_cn-- > 0) { - cb = ring->cbs + last_c_index; + while (txbds_processed < txbds_ready) { + cb = &ring->cbs[ring->clean_index]; bcm_sysport_tx_reclaim_one(priv, cb, &bytes_compl, &pkts_compl); ring->desc_count++; - last_c_index++; - last_c_index &= (num_tx_cbs - 1); + txbds_processed++; + + if (likely(ring->clean_index < ring->size - 1)) + ring->clean_index++; + else + ring->clean_index = 0; } ring->c_index = c_index; @@ -1207,6 +1203,7 @@ static int bcm_sysport_init_tx_ring(struct bcm_sysport_priv *priv, netif_tx_napi_add(priv->netdev, &ring->napi, bcm_sysport_tx_poll, 64); ring->index = index; ring->size = size; + ring->clean_index = 0; ring->alloc_size = ring->size; ring->desc_cpu = p; ring->desc_count = ring->size; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.h b/drivers/net/ethernet/broadcom/bcmsysport.h index 1c82e3da69a7..07b0aaa98de0 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.h +++ b/drivers/net/ethernet/broadcom/bcmsysport.h @@ -638,7 +638,7 @@ struct bcm_sysport_tx_ring { unsigned int desc_count; /* Number of descriptors */ unsigned int curr_desc; /* Current descriptor */ unsigned int c_index; /* Last consumer index */ - unsigned int p_index; /* Current producer index */ + unsigned int clean_index; /* Current clean index */ struct bcm_sysport_cb *cbs; /* Transmit control blocks */ struct dma_desc *desc_cpu; /* CPU view of the descriptor */ struct bcm_sysport_priv *priv; /* private context backpointer */ -- GitLab From 406996f36e01b5da0685e8e205302448b29feba3 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 13 Mar 2018 12:01:43 -0700 Subject: [PATCH 0862/1834] kcm: lock lower socket in kcm_attach [ Upstream commit 2cc683e88c0c993ac3721d9b702cb0630abe2879 ] Need to lock lower socket in order to provide mutual exclusion with kcm_unattach. v2: Add Reported-by for syzbot Fixes: ab7ac4eb9832e32a09f4e804 ("kcm: Kernel Connection Multiplexor module") Reported-by: syzbot+ea75c0ffcd353d32515f064aaebefc5279e6161e@syzkaller.appspotmail.com Signed-off-by: Tom Herbert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/kcm/kcmsock.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/net/kcm/kcmsock.c b/net/kcm/kcmsock.c index 179cd9b1b1f4..63e6d08388ab 100644 --- a/net/kcm/kcmsock.c +++ b/net/kcm/kcmsock.c @@ -1375,24 +1375,32 @@ static int kcm_attach(struct socket *sock, struct socket *csock, struct list_head *head; int index = 0; struct strp_callbacks cb; - int err; + int err = 0; csk = csock->sk; if (!csk) return -EINVAL; + lock_sock(csk); + /* Only allow TCP sockets to be attached for now */ if ((csk->sk_family != AF_INET && csk->sk_family != AF_INET6) || - csk->sk_protocol != IPPROTO_TCP) - return -EOPNOTSUPP; + csk->sk_protocol != IPPROTO_TCP) { + err = -EOPNOTSUPP; + goto out; + } /* Don't allow listeners or closed sockets */ - if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) - return -EOPNOTSUPP; + if (csk->sk_state == TCP_LISTEN || csk->sk_state == TCP_CLOSE) { + err = -EOPNOTSUPP; + goto out; + } psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL); - if (!psock) - return -ENOMEM; + if (!psock) { + err = -ENOMEM; + goto out; + } psock->mux = mux; psock->sk = csk; @@ -1406,7 +1414,7 @@ static int kcm_attach(struct socket *sock, struct socket *csock, err = strp_init(&psock->strp, csk, &cb); if (err) { kmem_cache_free(kcm_psockp, psock); - return err; + goto out; } write_lock_bh(&csk->sk_callback_lock); @@ -1418,7 +1426,8 @@ static int kcm_attach(struct socket *sock, struct socket *csock, write_unlock_bh(&csk->sk_callback_lock); strp_done(&psock->strp); kmem_cache_free(kcm_psockp, psock); - return -EALREADY; + err = -EALREADY; + goto out; } psock->save_data_ready = csk->sk_data_ready; @@ -1454,7 +1463,10 @@ static int kcm_attach(struct socket *sock, struct socket *csock, /* Schedule RX work in case there are already bytes queued */ strp_check_rcv(&psock->strp); - return 0; +out: + release_sock(csk); + + return err; } static int kcm_attach_ioctl(struct socket *sock, struct kcm_attach *info) @@ -1506,6 +1518,7 @@ static void kcm_unattach(struct kcm_psock *psock) if (WARN_ON(psock->rx_kcm)) { write_unlock_bh(&csk->sk_callback_lock); + release_sock(csk); return; } -- GitLab From a8f4be0168d5bf0c8838ca08301ae5341208dfba Mon Sep 17 00:00:00 2001 From: Yunsheng Lin Date: Thu, 6 Jul 2017 10:22:00 +0800 Subject: [PATCH 0863/1834] net: hns: Fix a skb used after free bug commit 27463ad99f738ed93c7c8b3e2e5bc8c4853a2ff2 upstream. skb maybe freed in hns_nic_net_xmit_hw() and return NETDEV_TX_OK, which cause hns_nic_net_xmit to use a freed skb. BUG: KASAN: use-after-free in hns_nic_net_xmit_hw+0x62c/0x940... [17659.112635] alloc_debug_processing+0x18c/0x1a0 [17659.117208] __slab_alloc+0x52c/0x560 [17659.120909] kmem_cache_alloc_node+0xac/0x2c0 [17659.125309] __alloc_skb+0x6c/0x260 [17659.128837] tcp_send_ack+0x8c/0x280 [17659.132449] __tcp_ack_snd_check+0x9c/0xf0 [17659.136587] tcp_rcv_established+0x5a4/0xa70 [17659.140899] tcp_v4_do_rcv+0x27c/0x620 [17659.144687] tcp_prequeue_process+0x108/0x170 [17659.149085] tcp_recvmsg+0x940/0x1020 [17659.152787] inet_recvmsg+0x124/0x180 [17659.156488] sock_recvmsg+0x64/0x80 [17659.160012] SyS_recvfrom+0xd8/0x180 [17659.163626] __sys_trace_return+0x0/0x4 [17659.167506] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=23 cpu=1 pid=13 [17659.174000] free_debug_processing+0x1d4/0x2c0 [17659.178486] __slab_free+0x240/0x390 [17659.182100] kmem_cache_free+0x24c/0x270 [17659.186062] kfree_skbmem+0xa0/0xb0 [17659.189587] __kfree_skb+0x28/0x40 [17659.193025] napi_gro_receive+0x168/0x1c0 [17659.197074] hns_nic_rx_up_pro+0x58/0x90 [17659.201038] hns_nic_rx_poll_one+0x518/0xbc0 [17659.205352] hns_nic_common_poll+0x94/0x140 [17659.209576] net_rx_action+0x458/0x5e0 [17659.213363] __do_softirq+0x1b8/0x480 [17659.217062] run_ksoftirqd+0x64/0x80 [17659.220679] smpboot_thread_fn+0x224/0x310 [17659.224821] kthread+0x150/0x170 [17659.228084] ret_from_fork+0x10/0x40 BUG: KASAN: use-after-free in hns_nic_net_xmit+0x8c/0xc0... [17751.080490] __slab_alloc+0x52c/0x560 [17751.084188] kmem_cache_alloc+0x244/0x280 [17751.088238] __build_skb+0x40/0x150 [17751.091764] build_skb+0x28/0x100 [17751.095115] __alloc_rx_skb+0x94/0x150 [17751.098900] __napi_alloc_skb+0x34/0x90 [17751.102776] hns_nic_rx_poll_one+0x180/0xbc0 [17751.107097] hns_nic_common_poll+0x94/0x140 [17751.111333] net_rx_action+0x458/0x5e0 [17751.115123] __do_softirq+0x1b8/0x480 [17751.118823] run_ksoftirqd+0x64/0x80 [17751.122437] smpboot_thread_fn+0x224/0x310 [17751.126575] kthread+0x150/0x170 [17751.129838] ret_from_fork+0x10/0x40 [17751.133454] INFO: Freed in kfree_skbmem+0xa0/0xb0 age=19 cpu=7 pid=43 [17751.139951] free_debug_processing+0x1d4/0x2c0 [17751.144436] __slab_free+0x240/0x390 [17751.148051] kmem_cache_free+0x24c/0x270 [17751.152014] kfree_skbmem+0xa0/0xb0 [17751.155543] __kfree_skb+0x28/0x40 [17751.159022] napi_gro_receive+0x168/0x1c0 [17751.163074] hns_nic_rx_up_pro+0x58/0x90 [17751.167041] hns_nic_rx_poll_one+0x518/0xbc0 [17751.171358] hns_nic_common_poll+0x94/0x140 [17751.175585] net_rx_action+0x458/0x5e0 [17751.179373] __do_softirq+0x1b8/0x480 [17751.183076] run_ksoftirqd+0x64/0x80 [17751.186691] smpboot_thread_fn+0x224/0x310 [17751.190826] kthread+0x150/0x170 [17751.194093] ret_from_fork+0x10/0x40 Fixes: 13ac695e7ea1 ("net:hns: Add support of Hip06 SoC to the Hislicon Network Subsystem") Signed-off-by: Yunsheng Lin Signed-off-by: lipeng Reported-by: Jun He Signed-off-by: David S. Miller Signed-off-by: Erick Reyes Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns/hns_enet.c | 22 +++++++++---------- drivers/net/ethernet/hisilicon/hns/hns_enet.h | 6 ++--- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index a79e0a1100aa..111e1aab7d83 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -299,9 +299,9 @@ static void fill_tso_desc(struct hnae_ring *ring, void *priv, mtu); } -int hns_nic_net_xmit_hw(struct net_device *ndev, - struct sk_buff *skb, - struct hns_nic_ring_data *ring_data) +netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev, + struct sk_buff *skb, + struct hns_nic_ring_data *ring_data) { struct hns_nic_priv *priv = netdev_priv(ndev); struct hnae_ring *ring = ring_data->ring; @@ -360,6 +360,10 @@ int hns_nic_net_xmit_hw(struct net_device *ndev, dev_queue = netdev_get_tx_queue(ndev, skb->queue_mapping); netdev_tx_sent_queue(dev_queue, skb->len); + netif_trans_update(ndev); + ndev->stats.tx_bytes += skb->len; + ndev->stats.tx_packets++; + wmb(); /* commit all data before submit */ assert(skb->queue_mapping < priv->ae_handle->q_num); hnae_queue_xmit(priv->ae_handle->qs[skb->queue_mapping], buf_num); @@ -1408,17 +1412,11 @@ static netdev_tx_t hns_nic_net_xmit(struct sk_buff *skb, struct net_device *ndev) { struct hns_nic_priv *priv = netdev_priv(ndev); - int ret; assert(skb->queue_mapping < ndev->ae_handle->q_num); - ret = hns_nic_net_xmit_hw(ndev, skb, - &tx_ring_data(priv, skb->queue_mapping)); - if (ret == NETDEV_TX_OK) { - netif_trans_update(ndev); - ndev->stats.tx_bytes += skb->len; - ndev->stats.tx_packets++; - } - return (netdev_tx_t)ret; + + return hns_nic_net_xmit_hw(ndev, skb, + &tx_ring_data(priv, skb->queue_mapping)); } static int hns_nic_change_mtu(struct net_device *ndev, int new_mtu) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.h b/drivers/net/ethernet/hisilicon/hns/hns_enet.h index 5b412de350aa..7bc6a6ecd666 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.h @@ -91,8 +91,8 @@ void hns_ethtool_set_ops(struct net_device *ndev); void hns_nic_net_reset(struct net_device *ndev); void hns_nic_net_reinit(struct net_device *netdev); int hns_nic_init_phy(struct net_device *ndev, struct hnae_handle *h); -int hns_nic_net_xmit_hw(struct net_device *ndev, - struct sk_buff *skb, - struct hns_nic_ring_data *ring_data); +netdev_tx_t hns_nic_net_xmit_hw(struct net_device *ndev, + struct sk_buff *skb, + struct hns_nic_ring_data *ring_data); #endif /**__HNS_ENET_H */ -- GitLab From f080bba272b1e3f9bbf0b6c1acef3efaf16b631d Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sat, 31 Mar 2018 18:11:36 +0200 Subject: [PATCH 0864/1834] Linux 4.9.92 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index db3d37e18723..3ab3b8203bf6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 91 +SUBLEVEL = 92 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 40a18300721d1bf4fb2e6fcfe0fd6784ff209b1c Mon Sep 17 00:00:00 2001 From: Ji Zhang Date: Fri, 26 Jan 2018 15:21:12 +0800 Subject: [PATCH 0865/1834] arm: fix show_data fallout from KERN_CONT changes The log format printed by show_data is illegible due to printk change "commit 4bcc595ccd80decb ("printk: reinstate KERN_CONT for printing continuation lines")". [47160.418043] PC: 0xc05fd830: [47160.418052] d830 [47160.418058] 51a00331 [47160.418064] 41800c11 [47160.418073] e1a01231 [47160.418079] e12fff1e [47160.418088] e2522001 [47160.418096] 4a000003 [47160.418104] e4d03001 [47160.418120] e1330001 [47160.418128] d850 [47160.418136] 1afffffa [47160.418144] e2400001 [47160.418149] 13a00000 [47160.418157] e12fff1e [47160.418164] e92d4011 [47160.418171] e2522004 [47160.418179] ba00002b [47160.418188] e210c003 To fix this, use pr_cont() instead of the printk() to print continuing lines. Signed-off-by: Ji Zhang Signed-off-by: Miles Chen --- arch/arm/kernel/process.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index c6324b534b9d..38ad8b956c6b 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -129,13 +129,13 @@ static void show_data(unsigned long addr, int nbytes, const char *name) for (j = 0; j < 8; j++) { u32 data; if (probe_kernel_address(p, data)) { - printk(" ********"); + pr_cont(" ********"); } else { - printk(" %08x", data); + pr_cont(" %08x", data); } ++p; } - printk("\n"); + pr_cont("\n"); } } -- GitLab From 13b40d327b49759119e86f3e9724e27d3aa3b538 Mon Sep 17 00:00:00 2001 From: Ji Zhang Date: Fri, 26 Jan 2018 15:04:26 +0800 Subject: [PATCH 0866/1834] arm64: fix show_data fallout from KERN_CONT changes The log format printed by show_data is illegible due to printk change "commit 4bcc595ccd80decb ("printk: reinstate KERN_CONT for printing continuation lines")". The output is like: [ 32.669636] SP: 0xffffffc0b01f7c50: [ 32.669647] 7c50 [ 32.669652] b01f7eb0 [ 32.669655] ffffffc0 [ 32.669659] 00000000 [ 32.669662] 00000000 [ 32.669665] 00000015 [ 32.669669] 00000000 [ 32.669672] 00000123 [ 32.669675] 00000000 [ 32.669674] [ 32.669680] 7c70 [ 32.669684] 0000003f [ 32.669687] 00000000 [ 32.669690] 08c82000 [ 32.669694] ffffff80 [ 32.669697] b01f4000 [ 32.669700] ffffffc0 [ 32.669703] b01f7cd0 [ 32.669706] ffffffc0 To fix this, use pr_cont() instead of the printk() to print continuing lines. Signed-off-by: Ji Zhang Signed-off-by: Miles Chen --- arch/arm64/kernel/process.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 7e365ffe1370..20a6d909f324 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -202,13 +202,13 @@ static void show_data(unsigned long addr, int nbytes, const char *name) for (j = 0; j < 8; j++) { u32 data; if (probe_kernel_address(p, data)) { - printk(" ********"); + pr_cont(" ********"); } else { - printk(" %08x", data); + pr_cont(" %08x", data); } ++p; } - printk("\n"); + pr_cont("\n"); } } -- GitLab From 6e7b83d80b5f81f41f3df9b3660acdf88532c879 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Wed, 31 Jan 2018 18:11:57 -0800 Subject: [PATCH 0867/1834] ANDROID: cpufreq: track per-task time in state Add time in state data to task structs, and create /proc//time_in_state files to show how long each individual task has run at each frequency. Create a CONFIG_CPU_FREQ_TIMES option to enable/disable this tracking. Signed-off-by: Connor O'Brien Bug: 72339335 Bug: 70951257 Test: Read /proc//time_in_state Change-Id: Ia6456754f4cb1e83b2bc35efa8fbe9f8696febc8 --- drivers/cpufreq/Kconfig | 9 ++ drivers/cpufreq/Makefile | 5 +- drivers/cpufreq/cpufreq.c | 3 + drivers/cpufreq/cpufreq_times.c | 204 ++++++++++++++++++++++++++++++++ fs/proc/base.c | 7 ++ include/linux/cpufreq_times.h | 36 ++++++ include/linux/sched.h | 4 + kernel/exit.c | 4 + kernel/sched/core.c | 5 + kernel/sched/cputime.c | 10 ++ 10 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 drivers/cpufreq/cpufreq_times.c create mode 100644 include/linux/cpufreq_times.h diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 1170bfea63eb..c70ed51daa15 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -45,6 +45,15 @@ config CPU_FREQ_STAT_DETAILS If in doubt, say N. +config CPU_FREQ_TIMES + bool "CPU frequency time-in-state statistics" + default y + help + This driver exports CPU time-in-state information through procfs file + system. + + If in doubt, say N. + choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index f0c9905d68a5..f10a18dcd685 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -4,7 +4,10 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o # CPUfreq stats obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o -# CPUfreq governors +# CPUfreq times +obj-$(CONFIG_CPU_FREQ_TIMES) += cpufreq_times.o + +# CPUfreq governors obj-$(CONFIG_CPU_FREQ_GOV_PERFORMANCE) += cpufreq_performance.o obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 434e729d94ee..f06b52a0a540 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -434,6 +435,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, (unsigned long)freqs->new, (unsigned long)freqs->cpu); trace_cpu_frequency(freqs->new, freqs->cpu); cpufreq_stats_record_transition(policy, freqs->new); + cpufreq_times_record_transition(freqs); srcu_notifier_call_chain(&cpufreq_transition_notifier_list, CPUFREQ_POSTCHANGE, freqs); if (likely(policy) && likely(policy->cpu == freqs->cpu)) @@ -1359,6 +1361,7 @@ static int cpufreq_online(unsigned int cpu) goto out_exit_policy; cpufreq_stats_create_table(policy); + cpufreq_times_create_policy(policy); blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_CREATE_POLICY, policy); diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c new file mode 100644 index 000000000000..16f53e94108d --- /dev/null +++ b/drivers/cpufreq/cpufreq_times.c @@ -0,0 +1,204 @@ +/* drivers/cpufreq/cpufreq_times.c + * + * Copyright (C) 2018 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */ + +/** + * struct cpu_freqs - per-cpu frequency information + * @offset: start of these freqs' stats in task time_in_state array + * @max_state: number of entries in freq_table + * @last_index: index in freq_table of last frequency switched to + * @freq_table: list of available frequencies + */ +struct cpu_freqs { + unsigned int offset; + unsigned int max_state; + unsigned int last_index; + unsigned int freq_table[0]; +}; + +static struct cpu_freqs *all_freqs[NR_CPUS]; + +static unsigned int next_offset; + +void cpufreq_task_times_init(struct task_struct *p) +{ + void *temp; + unsigned long flags; + unsigned int max_state; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + p->time_in_state = NULL; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + p->max_state = 0; + + max_state = READ_ONCE(next_offset); + + /* We use one array to avoid multiple allocs per task */ + temp = kcalloc(max_state, sizeof(p->time_in_state[0]), GFP_ATOMIC); + if (!temp) + return; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + p->time_in_state = temp; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + p->max_state = max_state; +} + +/* Caller must hold task_time_in_state_lock */ +static int cpufreq_task_times_realloc_locked(struct task_struct *p) +{ + void *temp; + unsigned int max_state = READ_ONCE(next_offset); + + temp = krealloc(p->time_in_state, max_state * sizeof(u64), GFP_ATOMIC); + if (!temp) + return -ENOMEM; + p->time_in_state = temp; + memset(p->time_in_state + p->max_state, 0, + (max_state - p->max_state) * sizeof(u64)); + p->max_state = max_state; + return 0; +} + +void cpufreq_task_times_exit(struct task_struct *p) +{ + unsigned long flags; + void *temp; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + temp = p->time_in_state; + p->time_in_state = NULL; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + kfree(temp); +} + +int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *p) +{ + unsigned int cpu, i; + cputime_t cputime; + unsigned long flags; + struct cpu_freqs *freqs; + struct cpu_freqs *last_freqs = NULL; + + spin_lock_irqsave(&task_time_in_state_lock, flags); + for_each_possible_cpu(cpu) { + freqs = all_freqs[cpu]; + if (!freqs || freqs == last_freqs) + continue; + last_freqs = freqs; + + seq_printf(m, "cpu%u\n", cpu); + for (i = 0; i < freqs->max_state; i++) { + if (freqs->freq_table[i] == CPUFREQ_ENTRY_INVALID) + continue; + cputime = 0; + if (freqs->offset + i < p->max_state && + p->time_in_state) + cputime = p->time_in_state[freqs->offset + i]; + seq_printf(m, "%u %lu\n", freqs->freq_table[i], + (unsigned long)cputime_to_clock_t(cputime)); + } + } + spin_unlock_irqrestore(&task_time_in_state_lock, flags); + return 0; +} + +void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime) +{ + unsigned long flags; + unsigned int state; + struct cpu_freqs *freqs = all_freqs[task_cpu(p)]; + + if (!freqs || p->flags & PF_EXITING) + return; + + state = freqs->offset + READ_ONCE(freqs->last_index); + + spin_lock_irqsave(&task_time_in_state_lock, flags); + if ((state < p->max_state || !cpufreq_task_times_realloc_locked(p)) && + p->time_in_state) + p->time_in_state[state] += cputime; + spin_unlock_irqrestore(&task_time_in_state_lock, flags); +} + +void cpufreq_times_create_policy(struct cpufreq_policy *policy) +{ + int cpu, index; + unsigned int count = 0; + struct cpufreq_frequency_table *pos, *table; + struct cpu_freqs *freqs; + void *tmp; + + if (all_freqs[policy->cpu]) + return; + + table = policy->freq_table; + if (!table) + return; + + cpufreq_for_each_entry(pos, table) + count++; + + tmp = kzalloc(sizeof(*freqs) + sizeof(freqs->freq_table[0]) * count, + GFP_KERNEL); + if (!tmp) + return; + + freqs = tmp; + freqs->max_state = count; + + index = cpufreq_frequency_table_get_index(policy, policy->cur); + if (index >= 0) + WRITE_ONCE(freqs->last_index, index); + + cpufreq_for_each_entry(pos, table) + freqs->freq_table[pos - table] = pos->frequency; + + freqs->offset = next_offset; + WRITE_ONCE(next_offset, freqs->offset + count); + for_each_cpu(cpu, policy->related_cpus) + all_freqs[cpu] = freqs; +} + +void cpufreq_times_record_transition(struct cpufreq_freqs *freq) +{ + int index; + struct cpu_freqs *freqs = all_freqs[freq->cpu]; + struct cpufreq_policy *policy; + + if (!freqs) + return; + + policy = cpufreq_cpu_get(freq->cpu); + if (!policy) + return; + + index = cpufreq_frequency_table_get_index(policy, freq->new); + if (index >= 0) + WRITE_ONCE(freqs->last_index, index); + + cpufreq_cpu_put(policy); +} diff --git a/fs/proc/base.c b/fs/proc/base.c index 27c4e8f4cea0..5e697d9bc6ac 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -87,6 +87,7 @@ #include #include #include +#include #ifdef CONFIG_HARDWALL #include #endif @@ -2940,6 +2941,9 @@ static const struct pid_entry tgid_base_stuff[] = { REG("timers", S_IRUGO, proc_timers_operations), #endif REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations), +#ifdef CONFIG_CPU_FREQ_TIMES + ONE("time_in_state", 0444, proc_time_in_state_show), +#endif }; static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) @@ -3324,6 +3328,9 @@ static const struct pid_entry tid_base_stuff[] = { REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), #endif +#ifdef CONFIG_CPU_FREQ_TIMES + ONE("time_in_state", 0444, proc_time_in_state_show), +#endif }; static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h new file mode 100644 index 000000000000..37222ac504c3 --- /dev/null +++ b/include/linux/cpufreq_times.h @@ -0,0 +1,36 @@ +/* drivers/cpufreq/cpufreq_times.c + * + * Copyright (C) 2018 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _LINUX_CPUFREQ_TIMES_H +#define _LINUX_CPUFREQ_TIMES_H + +#include +#include +#include + +#ifdef CONFIG_CPU_FREQ_TIMES +void cpufreq_task_times_init(struct task_struct *p); +void cpufreq_task_times_exit(struct task_struct *p); +int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *p); +void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime); +void cpufreq_times_create_policy(struct cpufreq_policy *policy); +void cpufreq_times_record_transition(struct cpufreq_freqs *freq); +#else +static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} +static inline void cpufreq_times_record_transition( + struct cpufreq_freqs *freq) {} +#endif /* CONFIG_CPU_FREQ_TIMES */ +#endif /* _LINUX_CPUFREQ_TIMES_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 8d4ce3fe049f..1459d8b770fc 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1792,6 +1792,10 @@ struct task_struct { cputime_t utime, stime, utimescaled, stimescaled; cputime_t gtime; +#ifdef CONFIG_CPU_FREQ_TIMES + u64 *time_in_state; + unsigned int max_state; +#endif struct prev_cputime prev_cputime; #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN seqcount_t vtime_seqcount; diff --git a/kernel/exit.c b/kernel/exit.c index 46a7c2bafda2..b285803f9914 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -54,6 +54,7 @@ #include #include #include +#include #include "sched/tune.h" @@ -171,6 +172,9 @@ void release_task(struct task_struct *p) { struct task_struct *leader; int zap_leader; +#ifdef CONFIG_CPU_FREQ_TIMES + cpufreq_task_times_exit(p); +#endif repeat: /* don't need to get the RCU readlock here - the process is dead and * can't be modifying its own credentials. But shut RCU-lockdep up */ diff --git a/kernel/sched/core.c b/kernel/sched/core.c index d5f4bbeaa5b1..47b01f63982c 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include @@ -2259,6 +2260,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p) memset(&p->se.statistics, 0, sizeof(p->se.statistics)); #endif +#ifdef CONFIG_CPU_FREQ_TIMES + cpufreq_task_times_init(p); +#endif + RB_CLEAR_NODE(&p->dl.rb_node); init_dl_task_timer(&p->dl); __dl_clear_params(p); diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index 5e9422b66f5f..366e50752c56 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "sched.h" #ifdef CONFIG_PARAVIRT #include @@ -162,6 +163,11 @@ void account_user_time(struct task_struct *p, cputime_t cputime, /* Account for user time used */ acct_account_cputime(p); + +#ifdef CONFIG_CPU_FREQ_TIMES + /* Account power usage for user time */ + cpufreq_acct_update_power(p, cputime); +#endif } /* @@ -212,6 +218,10 @@ void __account_system_time(struct task_struct *p, cputime_t cputime, /* Account for system time used */ acct_account_cputime(p); +#ifdef CONFIG_CPU_FREQ_TIMES + /* Account power usage for system time */ + cpufreq_acct_update_power(p, cputime); +#endif } /* -- GitLab From fcb3db160dbbe49abdf59bcb1c812c9bea5a2468 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 6 Feb 2018 13:30:27 -0800 Subject: [PATCH 0868/1834] ANDROID: cpufreq: times: track per-uid time in state Add /proc/uid_time_in_state showing per uid/frequency/cluster times. Allow uid removal through /proc/uid_cputime/remove_uid_range. Signed-off-by: Connor O'Brien Bug: 72339335 Bug: 70951257 Test: Read /proc/uid_time_in_state Change-Id: I20ba3546a27c25b7e7991e2a86986e158aafa58c --- drivers/cpufreq/cpufreq_times.c | 204 ++++++++++++++++++++++++++++++++ drivers/misc/uid_sys_stats.c | 5 + include/linux/cpufreq_times.h | 3 + 3 files changed, 212 insertions(+) diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 16f53e94108d..67560f7a2f94 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -16,13 +16,29 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#define UID_HASH_BITS 10 + +static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS); + static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */ +static DEFINE_SPINLOCK(uid_lock); /* uid_hash_table */ + +struct uid_entry { + uid_t uid; + unsigned int max_state; + struct hlist_node hash; + struct rcu_head rcu; + u64 time_in_state[0]; +}; /** * struct cpu_freqs - per-cpu frequency information @@ -42,6 +58,133 @@ static struct cpu_freqs *all_freqs[NR_CPUS]; static unsigned int next_offset; +/* Caller must hold uid lock */ +static struct uid_entry *find_uid_entry_locked(uid_t uid) +{ + struct uid_entry *uid_entry; + + hash_for_each_possible(uid_hash_table, uid_entry, hash, uid) { + if (uid_entry->uid == uid) + return uid_entry; + } + return NULL; +} + +/* Caller must hold uid lock */ +static struct uid_entry *find_or_register_uid_locked(uid_t uid) +{ + struct uid_entry *uid_entry, *temp; + unsigned int max_state = READ_ONCE(next_offset); + size_t alloc_size = sizeof(*uid_entry) + max_state * + sizeof(uid_entry->time_in_state[0]); + + uid_entry = find_uid_entry_locked(uid); + if (uid_entry) { + if (uid_entry->max_state == max_state) + return uid_entry; + /* uid_entry->time_in_state is too small to track all freqs, so + * expand it. + */ + temp = __krealloc(uid_entry, alloc_size, GFP_ATOMIC); + if (!temp) + return uid_entry; + temp->max_state = max_state; + memset(temp->time_in_state + uid_entry->max_state, 0, + (max_state - uid_entry->max_state) * + sizeof(uid_entry->time_in_state[0])); + if (temp != uid_entry) { + hlist_replace_rcu(&uid_entry->hash, &temp->hash); + kfree_rcu(uid_entry, rcu); + } + return temp; + } + + uid_entry = kzalloc(alloc_size, GFP_ATOMIC); + if (!uid_entry) + return NULL; + + uid_entry->uid = uid; + uid_entry->max_state = max_state; + + hash_add_rcu(uid_hash_table, &uid_entry->hash, uid); + + return uid_entry; +} + +static bool freq_index_invalid(unsigned int index) +{ + unsigned int cpu; + struct cpu_freqs *freqs; + + for_each_possible_cpu(cpu) { + freqs = all_freqs[cpu]; + if (!freqs || index < freqs->offset || + freqs->offset + freqs->max_state <= index) + continue; + return freqs->freq_table[index - freqs->offset] == + CPUFREQ_ENTRY_INVALID; + } + return true; +} + +static void *uid_seq_start(struct seq_file *seq, loff_t *pos) +{ + if (*pos >= HASH_SIZE(uid_hash_table)) + return NULL; + + return &uid_hash_table[*pos]; +} + +static void *uid_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + (*pos)++; + + if (*pos >= HASH_SIZE(uid_hash_table)) + return NULL; + + return &uid_hash_table[*pos]; +} + +static void uid_seq_stop(struct seq_file *seq, void *v) { } + +static int uid_time_in_state_seq_show(struct seq_file *m, void *v) +{ + struct uid_entry *uid_entry; + struct cpu_freqs *freqs, *last_freqs = NULL; + int i, cpu; + + if (v == uid_hash_table) { + seq_puts(m, "uid:"); + for_each_possible_cpu(cpu) { + freqs = all_freqs[cpu]; + if (!freqs || freqs == last_freqs) + continue; + last_freqs = freqs; + for (i = 0; i < freqs->max_state; i++) + seq_printf(m, " %d", freqs->freq_table[i]); + } + seq_putc(m, '\n'); + } + + rcu_read_lock(); + + hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) { + if (uid_entry->max_state) + seq_printf(m, "%d:", uid_entry->uid); + for (i = 0; i < uid_entry->max_state; ++i) { + if (freq_index_invalid(i)) + continue; + seq_printf(m, " %lu", (unsigned long)cputime_to_clock_t( + uid_entry->time_in_state[i])); + } + if (uid_entry->max_state) + seq_putc(m, '\n'); + } + + rcu_read_unlock(); + return 0; +} + void cpufreq_task_times_init(struct task_struct *p) { void *temp; @@ -87,6 +230,9 @@ void cpufreq_task_times_exit(struct task_struct *p) unsigned long flags; void *temp; + if (!p->time_in_state) + return; + spin_lock_irqsave(&task_time_in_state_lock, flags); temp = p->time_in_state; p->time_in_state = NULL; @@ -130,7 +276,9 @@ void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime) { unsigned long flags; unsigned int state; + struct uid_entry *uid_entry; struct cpu_freqs *freqs = all_freqs[task_cpu(p)]; + uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p)); if (!freqs || p->flags & PF_EXITING) return; @@ -142,6 +290,12 @@ void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime) p->time_in_state) p->time_in_state[state] += cputime; spin_unlock_irqrestore(&task_time_in_state_lock, flags); + + spin_lock_irqsave(&uid_lock, flags); + uid_entry = find_or_register_uid_locked(uid); + if (uid_entry && state < uid_entry->max_state) + uid_entry->time_in_state[state] += cputime; + spin_unlock_irqrestore(&uid_lock, flags); } void cpufreq_times_create_policy(struct cpufreq_policy *policy) @@ -183,6 +337,27 @@ void cpufreq_times_create_policy(struct cpufreq_policy *policy) all_freqs[cpu] = freqs; } +void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end) +{ + struct uid_entry *uid_entry; + struct hlist_node *tmp; + unsigned long flags; + + spin_lock_irqsave(&uid_lock, flags); + + for (; uid_start <= uid_end; uid_start++) { + hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp, + hash, uid_start) { + if (uid_start == uid_entry->uid) { + hash_del_rcu(&uid_entry->hash); + kfree_rcu(uid_entry, rcu); + } + } + } + + spin_unlock_irqrestore(&uid_lock, flags); +} + void cpufreq_times_record_transition(struct cpufreq_freqs *freq) { int index; @@ -202,3 +377,32 @@ void cpufreq_times_record_transition(struct cpufreq_freqs *freq) cpufreq_cpu_put(policy); } + +static const struct seq_operations uid_time_in_state_seq_ops = { + .start = uid_seq_start, + .next = uid_seq_next, + .stop = uid_seq_stop, + .show = uid_time_in_state_seq_show, +}; + +static int uid_time_in_state_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &uid_time_in_state_seq_ops); +} + +static const struct file_operations uid_time_in_state_fops = { + .open = uid_time_in_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int __init cpufreq_times_init(void) +{ + proc_create_data("uid_time_in_state", 0444, NULL, + &uid_time_in_state_fops, NULL); + + return 0; +} + +early_initcall(cpufreq_times_init); diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 42a513c97239..0014ad5ebd3f 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -422,6 +423,10 @@ static ssize_t uid_remove_write(struct file *file, kstrtol(end_uid, 10, &uid_end) != 0) { return -EINVAL; } + + /* Also remove uids from /proc/uid_time_in_state */ + cpufreq_task_times_remove_uids(uid_start, uid_end); + rt_mutex_lock(&uid_lock); for (; uid_start <= uid_end; uid_start++) { diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h index 37222ac504c3..4966f6583383 100644 --- a/include/linux/cpufreq_times.h +++ b/include/linux/cpufreq_times.h @@ -28,9 +28,12 @@ int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns, void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime); void cpufreq_times_create_policy(struct cpufreq_policy *policy); void cpufreq_times_record_transition(struct cpufreq_freqs *freq); +void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end); #else static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} static inline void cpufreq_times_record_transition( struct cpufreq_freqs *freq) {} +static inline void cpufreq_task_times_remove_uids(uid_t uid_start, + uid_t uid_end) {} #endif /* CONFIG_CPU_FREQ_TIMES */ #endif /* _LINUX_CPUFREQ_TIMES_H */ -- GitLab From 5b3d110f3432ecc7fcc84410c426a8e810057b34 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Mon, 16 Oct 2017 10:30:24 -0700 Subject: [PATCH 0869/1834] ANDROID: proc: Add /proc/uid directory Add support for reporting per-uid information through procfs, roughly following the approach used for per-tid and per-tgid directories in fs/proc/base.c. This also entails some new tracking of which uids have been used, to avoid losing information when the last task with a given uid exits. Signed-off-by: Connor O'Brien Bug: 72339335 Bug: 70951257 Test: ls /proc/uid/; compare with UIDs in /proc/uid_time_in_state Change-Id: I0908f0c04438b11ceb673d860e58441bf503d478 --- fs/proc/Kconfig | 7 + fs/proc/Makefile | 1 + fs/proc/internal.h | 9 ++ fs/proc/root.c | 2 +- fs/proc/uid.c | 279 ++++++++++++++++++++++++++++++++++++++++ include/linux/proc_fs.h | 6 + kernel/user.c | 3 + 7 files changed, 306 insertions(+), 1 deletion(-) create mode 100644 fs/proc/uid.c diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig index 1ade1206bb89..08dce22afec1 100644 --- a/fs/proc/Kconfig +++ b/fs/proc/Kconfig @@ -81,3 +81,10 @@ config PROC_CHILDREN Say Y if you are running any user-space software which takes benefit from this interface. For example, rkt is such a piece of software. + +config PROC_UID + bool "Include /proc/uid/ files" + default y + depends on PROC_FS && RT_MUTEXES + help + Provides aggregated per-uid information under /proc/uid. diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 12c6922c913c..dea53bac412e 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile @@ -25,6 +25,7 @@ proc-y += softirqs.o proc-y += namespaces.o proc-y += self.o proc-y += thread_self.o +proc-$(CONFIG_PROC_UID) += uid.o proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o proc-$(CONFIG_NET) += proc_net.o proc-$(CONFIG_PROC_KCORE) += kcore.o diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 5378441ec1b7..288a7eab2b4b 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -255,6 +255,15 @@ static inline void proc_sys_init(void) { } static inline void sysctl_head_put(struct ctl_table_header *head) { } #endif +/* + * uid.c + */ +#ifdef CONFIG_PROC_UID +extern int proc_uid_init(void); +#else +static inline void proc_uid_init(void) { } +#endif + /* * proc_tty.c */ diff --git a/fs/proc/root.c b/fs/proc/root.c index 8d3e484055a6..c2f5014d642d 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -131,7 +131,7 @@ void __init proc_root_init(void) proc_symlink("mounts", NULL, "self/mounts"); proc_net_init(); - + proc_uid_init(); #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); #endif diff --git a/fs/proc/uid.c b/fs/proc/uid.c new file mode 100644 index 000000000000..9997ade5299a --- /dev/null +++ b/fs/proc/uid.c @@ -0,0 +1,279 @@ +/* + * /proc/uid support + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +static struct proc_dir_entry *proc_uid; + +#define UID_HASH_BITS 10 + +static DECLARE_HASHTABLE(proc_uid_hash_table, UID_HASH_BITS); + +/* + * use rt_mutex here to avoid priority inversion between high-priority readers + * of these files and tasks calling proc_register_uid(). + */ +static DEFINE_RT_MUTEX(proc_uid_lock); /* proc_uid_hash_table */ + +struct uid_hash_entry { + uid_t uid; + struct hlist_node hash; +}; + +/* Caller must hold proc_uid_lock */ +static bool uid_hash_entry_exists_locked(uid_t uid) +{ + struct uid_hash_entry *entry; + + hash_for_each_possible(proc_uid_hash_table, entry, hash, uid) { + if (entry->uid == uid) + return true; + } + return false; +} + +void proc_register_uid(kuid_t kuid) +{ + struct uid_hash_entry *entry; + bool exists; + uid_t uid = from_kuid_munged(current_user_ns(), kuid); + + rt_mutex_lock(&proc_uid_lock); + exists = uid_hash_entry_exists_locked(uid); + rt_mutex_unlock(&proc_uid_lock); + if (exists) + return; + + entry = kzalloc(sizeof(struct uid_hash_entry), GFP_KERNEL); + if (!entry) + return; + entry->uid = uid; + + rt_mutex_lock(&proc_uid_lock); + if (uid_hash_entry_exists_locked(uid)) + kfree(entry); + else + hash_add(proc_uid_hash_table, &entry->hash, uid); + rt_mutex_unlock(&proc_uid_lock); +} + +struct uid_entry { + const char *name; + int len; + umode_t mode; + const struct inode_operations *iop; + const struct file_operations *fop; +}; + +#define NOD(NAME, MODE, IOP, FOP) { \ + .name = (NAME), \ + .len = sizeof(NAME) - 1, \ + .mode = MODE, \ + .iop = IOP, \ + .fop = FOP, \ +} + +static const struct uid_entry uid_base_stuff[] = {}; + +static const struct inode_operations proc_uid_def_inode_operations = { + .setattr = proc_setattr, +}; + +static struct inode *proc_uid_make_inode(struct super_block *sb, kuid_t kuid) +{ + struct inode *inode; + + inode = new_inode(sb); + if (!inode) + return NULL; + + inode->i_ino = get_next_ino(); + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &proc_uid_def_inode_operations; + inode->i_uid = kuid; + + return inode; +} + +static int proc_uident_instantiate(struct inode *dir, struct dentry *dentry, + struct task_struct *unused, const void *ptr) +{ + const struct uid_entry *u = ptr; + struct inode *inode; + + inode = proc_uid_make_inode(dir->i_sb, dir->i_uid); + if (!inode) + return -ENOENT; + + inode->i_mode = u->mode; + if (S_ISDIR(inode->i_mode)) + set_nlink(inode, 2); + if (u->iop) + inode->i_op = u->iop; + if (u->fop) + inode->i_fop = u->fop; + d_add(dentry, inode); + return 0; +} + +static struct dentry *proc_uid_base_lookup(struct inode *dir, + struct dentry *dentry, + unsigned int flags) +{ + const struct uid_entry *u, *last; + unsigned int nents = ARRAY_SIZE(uid_base_stuff); + + if (nents == 0) + return ERR_PTR(-ENOENT); + + last = &uid_base_stuff[nents - 1]; + for (u = uid_base_stuff; u <= last; u++) { + if (u->len != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, u->name, u->len)) + break; + } + if (u > last) + return ERR_PTR(-ENOENT); + + return ERR_PTR(proc_uident_instantiate(dir, dentry, NULL, u)); +} + +static int proc_uid_base_readdir(struct file *file, struct dir_context *ctx) +{ + unsigned int nents = ARRAY_SIZE(uid_base_stuff); + const struct uid_entry *u; + + if (!dir_emit_dots(file, ctx)) + return 0; + + if (ctx->pos >= nents + 2) + return 0; + + for (u = uid_base_stuff + (ctx->pos - 2); + u <= uid_base_stuff + nents - 1; u++) { + if (!proc_fill_cache(file, ctx, u->name, u->len, + proc_uident_instantiate, NULL, u)) + break; + ctx->pos++; + } + + return 0; +} + +static const struct inode_operations proc_uid_base_inode_operations = { + .lookup = proc_uid_base_lookup, + .setattr = proc_setattr, +}; + +static const struct file_operations proc_uid_base_operations = { + .read = generic_read_dir, + .iterate = proc_uid_base_readdir, + .llseek = default_llseek, +}; + +static int proc_uid_instantiate(struct inode *dir, struct dentry *dentry, + struct task_struct *unused, const void *ptr) +{ + unsigned int i, len; + nlink_t nlinks; + kuid_t *kuid = (kuid_t *)ptr; + struct inode *inode = proc_uid_make_inode(dir->i_sb, *kuid); + + if (!inode) + return -ENOENT; + + inode->i_mode = S_IFDIR | 0555; + inode->i_op = &proc_uid_base_inode_operations; + inode->i_fop = &proc_uid_base_operations; + inode->i_flags |= S_IMMUTABLE; + + nlinks = 2; + len = ARRAY_SIZE(uid_base_stuff); + for (i = 0; i < len; ++i) { + if (S_ISDIR(uid_base_stuff[i].mode)) + ++nlinks; + } + set_nlink(inode, nlinks); + + d_add(dentry, inode); + + return 0; +} + +static int proc_uid_readdir(struct file *file, struct dir_context *ctx) +{ + int last_shown, i; + unsigned long bkt; + struct uid_hash_entry *entry; + + if (!dir_emit_dots(file, ctx)) + return 0; + + i = 0; + last_shown = ctx->pos - 2; + rt_mutex_lock(&proc_uid_lock); + hash_for_each(proc_uid_hash_table, bkt, entry, hash) { + int len; + char buf[PROC_NUMBUF]; + + if (i < last_shown) + continue; + len = snprintf(buf, sizeof(buf), "%u", entry->uid); + if (!proc_fill_cache(file, ctx, buf, len, + proc_uid_instantiate, NULL, &entry->uid)) + break; + i++; + ctx->pos++; + } + rt_mutex_unlock(&proc_uid_lock); + return 0; +} + +static struct dentry *proc_uid_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + int result = -ENOENT; + + uid_t uid = name_to_int(&dentry->d_name); + bool uid_exists; + + rt_mutex_lock(&proc_uid_lock); + uid_exists = uid_hash_entry_exists_locked(uid); + rt_mutex_unlock(&proc_uid_lock); + if (uid_exists) { + kuid_t kuid = make_kuid(current_user_ns(), uid); + + result = proc_uid_instantiate(dir, dentry, NULL, &kuid); + } + return ERR_PTR(result); +} + +static const struct file_operations proc_uid_operations = { + .read = generic_read_dir, + .iterate = proc_uid_readdir, + .llseek = default_llseek, +}; + +static const struct inode_operations proc_uid_inode_operations = { + .lookup = proc_uid_lookup, + .setattr = proc_setattr, +}; + +int __init proc_uid_init(void) +{ + proc_uid = proc_mkdir("uid", NULL); + proc_uid->proc_iops = &proc_uid_inode_operations; + proc_uid->proc_fops = &proc_uid_operations; + + return 0; +} diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index b97bf2ef996e..b326d0a0cace 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -74,6 +74,12 @@ static inline int remove_proc_subtree(const char *name, struct proc_dir_entry *p #endif /* CONFIG_PROC_FS */ +#ifdef CONFIG_PROC_UID +extern void proc_register_uid(kuid_t uid); +#else +static inline void proc_register_uid(kuid_t uid) {} +#endif + struct net; static inline struct proc_dir_entry *proc_net_mkdir( diff --git a/kernel/user.c b/kernel/user.c index b069ccbfb0b0..41e94e453836 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -16,6 +16,7 @@ #include #include #include +#include #include /* @@ -201,6 +202,7 @@ struct user_struct *alloc_uid(kuid_t uid) } spin_unlock_irq(&uidhash_lock); } + proc_register_uid(uid); return up; @@ -222,6 +224,7 @@ static int __init uid_cache_init(void) spin_lock_irq(&uidhash_lock); uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID)); spin_unlock_irq(&uidhash_lock); + proc_register_uid(GLOBAL_ROOT_UID); return 0; } -- GitLab From f17f4fb515c8b3bc54a64bc12e8712e8ef45171f Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Mon, 22 Jan 2018 18:28:08 -0800 Subject: [PATCH 0870/1834] ANDROID: cpufreq: Add time_in_state to /proc/uid directories Add per-uid files that report the data in binary format rather than text, to allow faster reading & parsing by userspace. Signed-off-by: Connor O'Brien Bug: 72339335 Bug: 70951257 Test: compare values to those reported in /proc/uid_time_in_state Change-Id: I463039ea7f17b842be4c70024fe772539fe2ce02 --- drivers/cpufreq/cpufreq_times.c | 49 +++++++++++++++++++++++++++++++++ fs/proc/uid.c | 16 ++++++++++- include/linux/cpufreq_times.h | 1 + 3 files changed, 65 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 67560f7a2f94..19cf50bd427e 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -58,6 +58,19 @@ static struct cpu_freqs *all_freqs[NR_CPUS]; static unsigned int next_offset; + +/* Caller must hold rcu_read_lock() */ +static struct uid_entry *find_uid_entry_rcu(uid_t uid) +{ + struct uid_entry *uid_entry; + + hash_for_each_possible_rcu(uid_hash_table, uid_entry, hash, uid) { + if (uid_entry->uid == uid) + return uid_entry; + } + return NULL; +} + /* Caller must hold uid lock */ static struct uid_entry *find_uid_entry_locked(uid_t uid) { @@ -127,6 +140,36 @@ static bool freq_index_invalid(unsigned int index) return true; } +static int single_uid_time_in_state_show(struct seq_file *m, void *ptr) +{ + struct uid_entry *uid_entry; + unsigned int i; + u64 time; + uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private); + + if (uid == overflowuid) + return -EINVAL; + + rcu_read_lock(); + + uid_entry = find_uid_entry_rcu(uid); + if (!uid_entry) { + rcu_read_unlock(); + return 0; + } + + for (i = 0; i < uid_entry->max_state; ++i) { + if (freq_index_invalid(i)) + continue; + time = cputime_to_clock_t(uid_entry->time_in_state[i]); + seq_write(m, &time, sizeof(time)); + } + + rcu_read_unlock(); + + return 0; +} + static void *uid_seq_start(struct seq_file *seq, loff_t *pos) { if (*pos >= HASH_SIZE(uid_hash_table)) @@ -390,6 +433,12 @@ static int uid_time_in_state_open(struct inode *inode, struct file *file) return seq_open(file, &uid_time_in_state_seq_ops); } +int single_uid_time_in_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, single_uid_time_in_state_show, + &(inode->i_uid)); +} + static const struct file_operations uid_time_in_state_fops = { .open = uid_time_in_state_open, .read = seq_read, diff --git a/fs/proc/uid.c b/fs/proc/uid.c index 9997ade5299a..480338756b4c 100644 --- a/fs/proc/uid.c +++ b/fs/proc/uid.c @@ -2,6 +2,7 @@ * /proc/uid support */ +#include #include #include #include @@ -82,7 +83,20 @@ struct uid_entry { .fop = FOP, \ } -static const struct uid_entry uid_base_stuff[] = {}; +#ifdef CONFIG_CPU_FREQ_TIMES +static const struct file_operations proc_uid_time_in_state_operations = { + .open = single_uid_time_in_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +static const struct uid_entry uid_base_stuff[] = { +#ifdef CONFIG_CPU_FREQ_TIMES + NOD("time_in_state", 0444, NULL, &proc_uid_time_in_state_operations), +#endif +}; static const struct inode_operations proc_uid_def_inode_operations = { .setattr = proc_setattr, diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h index 4966f6583383..3fb38750c853 100644 --- a/include/linux/cpufreq_times.h +++ b/include/linux/cpufreq_times.h @@ -29,6 +29,7 @@ void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime); void cpufreq_times_create_policy(struct cpufreq_policy *policy); void cpufreq_times_record_transition(struct cpufreq_freqs *freq); void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end); +int single_uid_time_in_state_open(struct inode *inode, struct file *file); #else static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} static inline void cpufreq_times_record_transition( -- GitLab From 7cd9561963460b199ca556261754a3d87e9c5c11 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Tue, 3 Apr 2018 16:05:37 -0700 Subject: [PATCH 0871/1834] ANDROID: cpufreq: times: skip printing invalid frequencies The header of /proc/uid_time_in_state should match the logic used for the rest of the file by skipping invalid frequency table entries. Test: Read /proc/uid_time_in_state and check for invalid frequencies in header. Signed-off-by: Connor O'Brien Change-Id: I96888e7b71f4928383ff7080c98c988d5fe1a95c --- drivers/cpufreq/cpufreq_times.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 19cf50bd427e..6254f45ca907 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -203,8 +203,12 @@ static int uid_time_in_state_seq_show(struct seq_file *m, void *v) if (!freqs || freqs == last_freqs) continue; last_freqs = freqs; - for (i = 0; i < freqs->max_state; i++) + for (i = 0; i < freqs->max_state; i++) { + if (freqs->freq_table[i] == + CPUFREQ_ENTRY_INVALID) + continue; seq_printf(m, " %d", freqs->freq_table[i]); + } } seq_putc(m, '\n'); } -- GitLab From 55a84958e142738db7c157ba784955f0f965f2f0 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Mon, 19 Mar 2018 15:49:54 +0530 Subject: [PATCH 0872/1834] ANDROID: sdcardfs: Fix sdcardfs to stop creating cases-sensitive duplicate entries. sdcardfs_name_match gets a 'name' argument from the underlying FS. This need not be null terminated string. So in sdcardfs_name_match -> qstr_case_eq -> we should use str_n_case_eq. This happens because few of the entries in lower level FS may not be NULL terminated and may have some garbage characters passed while doing sdcardfs_name_match. For e.g. # dmesg |grep Download [ 103.646386] sdcardfs_name_match: q1->name=.nomedia, q1->len=8, q2->name=Download\x17\x80\x03, q2->len=8 [ 104.021340] sdcardfs_name_match: q1->name=.nomedia, q1->len=8, q2->name=Download\x17\x80\x03, q2->len=8 [ 105.196864] sdcardfs_name_match: q1->name=.nomedia, q1->len=8, q2->name=Download\x17\x80\x03, q2->len=8 [ 109.113521] sdcardfs_name_match: q1->name=logs, q1->len=4, q2->name=Download\x17\x80\x03, q2->len=8 Now when we try to create a directory with different case for a such files. SDCARDFS creates a entry if it could not find the underlying entry in it's dcache. To reproduce:- 1. bootup the device wait for some time after sdcardfs mounting to complete. 2. cd /storage/emulated/0 3. echo 3 > /proc/sys/vm/drop_caches 4. mkdir download We now start seeing two entries with name. Download & download. Change-Id: I976d92a220a607dd8cdb96c01c2041c5c2bc3326 Signed-off-by: Ritesh Harjani bug: 75987238 --- fs/sdcardfs/sdcardfs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h index 610466ad153d..826afb5c7e88 100644 --- a/fs/sdcardfs/sdcardfs.h +++ b/fs/sdcardfs/sdcardfs.h @@ -669,7 +669,7 @@ static inline bool str_n_case_eq(const char *s1, const char *s2, size_t len) static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2) { - return q1->len == q2->len && str_case_eq(q1->name, q2->name); + return q1->len == q2->len && str_n_case_eq(q1->name, q2->name, q2->len); } #define QSTR_LITERAL(string) QSTR_INIT(string, sizeof(string)-1) -- GitLab From 57104f6c2db4c3d06dfccf44bfc38e151c7787b3 Mon Sep 17 00:00:00 2001 From: Jigarkumar Zala Date: Thu, 22 Mar 2018 15:34:30 -0700 Subject: [PATCH 0873/1834] msm: camera: Add handle check for camera sensor modules Add handle check for data coming from user space for camera sensor modules. Change-Id: Id5b447817646dc0d7718e5efaabfabdbbbeeacd6 Signed-off-by: Jigarkumar Zala Signed-off-by: Vishalsingh Hajeri --- .../cam_actuator/cam_actuator_core.c | 7 +++++++ .../cam_csiphy/cam_csiphy_core.c | 6 ++++++ .../cam_eeprom/cam_eeprom_core.c | 17 +++++++++-------- .../cam_sensor_module/cam_flash/cam_flash_dev.c | 6 ++++++ .../cam_sensor_module/cam_ois/cam_ois_core.c | 10 ++++++++-- .../cam_sensor/cam_sensor_core.c | 9 +++++++++ 6 files changed, 45 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c index 56cb49a1baa3..2f74765f1437 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -636,6 +636,12 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, return -EINVAL; } + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_ACTUATOR, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + CAM_DBG(CAM_ACTUATOR, "Opcode to Actuator: %d", cmd->op_code); mutex_lock(&(a_ctrl->actuator_mutex)); @@ -769,6 +775,7 @@ int32_t cam_actuator_driver_cmd(struct cam_actuator_ctrl_t *a_ctrl, rc = cam_actuator_i2c_pkt_parse(a_ctrl, arg); if (rc < 0) { CAM_ERR(CAM_ACTUATOR, "Failed in actuator Parsing"); + goto release_mutex; } if (a_ctrl->setting_apply_state == diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c index e978a40bdddd..dbbac08a5879 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_csiphy/cam_csiphy_core.c @@ -438,6 +438,12 @@ int32_t cam_csiphy_core_cfg(void *phy_dev, return -EINVAL; } + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_CSIPHY, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + CAM_DBG(CAM_CSIPHY, "Opcode received: %d", cmd->op_code); mutex_lock(&csiphy_dev->mutex); switch (cmd->op_code) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index b0fbead43a43..30b9d967c405 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -707,11 +707,6 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) ioctl_ctrl = (struct cam_control *)arg; - if (ioctl_ctrl->handle_type != CAM_HANDLE_USER_POINTER) { - CAM_ERR(CAM_EEPROM, "Invalid Handle Type"); - return -EINVAL; - } - if (copy_from_user(&dev_config, (void __user *) ioctl_ctrl->handle, sizeof(dev_config))) return -EFAULT; @@ -852,8 +847,14 @@ int32_t cam_eeprom_driver_cmd(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) struct cam_eeprom_query_cap_t eeprom_cap = {0}; struct cam_control *cmd = (struct cam_control *)arg; - if (!e_ctrl) { - CAM_ERR(CAM_EEPROM, "e_ctrl is NULL"); + if (!e_ctrl || !cmd) { + CAM_ERR(CAM_EEPROM, "Invalid Arguments"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_EEPROM, "Invalid handle type: %d", + cmd->handle_type); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c index 6120e028d124..f9411fcfa4b3 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_flash/cam_flash_dev.c @@ -29,6 +29,12 @@ static int32_t cam_flash_driver_cmd(struct cam_flash_ctrl *fctrl, return -EINVAL; } + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_FLASH, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + mutex_lock(&(fctrl->flash_mutex)); switch (cmd->op_code) { case CAM_ACQUIRE_DEV: { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index c792be49b6e1..196df084d40b 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -672,8 +672,14 @@ int cam_ois_driver_cmd(struct cam_ois_ctrl_t *o_ctrl, void *arg) struct cam_ois_query_cap_t ois_cap = {0}; struct cam_control *cmd = (struct cam_control *)arg; - if (!o_ctrl) { - CAM_ERR(CAM_OIS, "e_ctrl is NULL"); + if (!o_ctrl || !arg) { + CAM_ERR(CAM_OIS, "Invalid arguments"); + return -EINVAL; + } + + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_OIS, "Invalid handle type: %d", + cmd->handle_type); return -EINVAL; } diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index e9dd1ade5107..d5bee96bfb63 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -568,6 +568,14 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, return -EINVAL; } + if (cmd->op_code != CAM_SENSOR_PROBE_CMD) { + if (cmd->handle_type != CAM_HANDLE_USER_POINTER) { + CAM_ERR(CAM_SENSOR, "Invalid handle type: %d", + cmd->handle_type); + return -EINVAL; + } + } + mutex_lock(&(s_ctrl->cam_sensor_mutex)); switch (cmd->op_code) { case CAM_SENSOR_PROBE_CMD: { @@ -607,6 +615,7 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } else { CAM_ERR(CAM_SENSOR, "Invalid Command Type: %d", cmd->handle_type); + return -EINVAL; } /* Parse and fill vreg params for powerup settings */ -- GitLab From 4fb542f2aa1414cea5686efcf72a411b7213c375 Mon Sep 17 00:00:00 2001 From: Ritesh Harjani Date: Mon, 19 Mar 2018 16:03:09 +0530 Subject: [PATCH 0874/1834] ANDROID: fuse: Add null terminator to path in canonical path to avoid issue page allocated in fuse_dentry_canonical_path to be handled in fuse_dev_do_write is allocated using __get_free_pages(GFP_KERNEL). This may not return a page with data filled with 0. Now this page may not have a null terminator at all. If this happens and userspace fuse daemon screws up by passing a string to kernel which is not NULL terminated (or did not fill anything), then inside fuse driver in kernel when we try to do strlen(fuse_dev_write->kern_path->getname_kernel) on that page data -> it may give us issue with kernel paging request. Unable to handle kernel paging request at virtual address ------------[ cut here ]------------ <..> PC is at strlen+0x10/0x90 LR is at getname_kernel+0x2c/0xf4 <..> strlen+0x10/0x90 kern_path+0x28/0x4c fuse_dev_do_write+0x5b8/0x694 fuse_dev_write+0x74/0x94 do_iter_readv_writev+0x80/0xb8 do_readv_writev+0xec/0x1cc vfs_writev+0x54/0x64 SyS_writev+0x64/0xe4 el0_svc_naked+0x24/0x28 To avoid this we should ensure in case of FUSE_CANONICAL_PATH, the page is null terminated. Change-Id: I33ca7cc76b4472eaa982c67bb20685df451121f5 Signed-off-by: Ritesh Harjani Bug: 75984715 [Daniel - small edit, using args size ] Signed-off-by: Daniel Rosenberg --- fs/fuse/dev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 83511cb8625f..2ca3c1ea1918 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -1885,8 +1885,10 @@ static ssize_t fuse_dev_do_write(struct fuse_dev *fud, err = copy_out_args(cs, &req->out, nbytes); if (req->in.h.opcode == FUSE_CANONICAL_PATH) { - req->out.h.error = kern_path((char *)req->out.args[0].value, 0, - req->canonical_path); + char *path = (char *)req->out.args[0].value; + + path[req->out.args[0].size - 1] = 0; + req->out.h.error = kern_path(path, 0, req->canonical_path); } fuse_copy_finish(cs); -- GitLab From 1313b04453e90208728e1c29ab4191c9a541cdc6 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Mon, 2 Apr 2018 21:53:44 +0530 Subject: [PATCH 0875/1834] msm: camera: icp: Avoid accessing released memory in abort/destroy In abort and destroy functions there are chances of accessing released memory if timeout happens and work is not scheduled. To handle this, removed the workqueue and submitted command directly to FW. Change-Id: I2eccb47d5db29fe0cb5fb8426812b33c961f365b Signed-off-by: Alok Pandey --- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 30 +++---------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index ba4385f5ca02..c7d5634edeb7 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -2260,13 +2260,7 @@ static int cam_icp_mgr_abort_handle( unsigned long rem_jiffies; size_t packet_size; int timeout = 100; - struct hfi_cmd_work_data *task_data; struct hfi_cmd_ipebps_async *abort_cmd; - struct crm_workq_task *task; - - task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); - if (!task) - return -ENOMEM; packet_size = sizeof(struct hfi_cmd_ipebps_async) + @@ -2292,13 +2286,7 @@ static int cam_icp_mgr_abort_handle( abort_cmd->user_data1 = (uint64_t)ctx_data; abort_cmd->user_data2 = (uint64_t)0x0; - task_data = (struct hfi_cmd_work_data *)task->payload; - task_data->data = (void *)abort_cmd; - task_data->request_id = 0; - task_data->type = ICP_WORKQ_TASK_CMD_TYPE; - task->process_cb = cam_icp_mgr_process_cmd; - rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, - CRM_TASK_PRIORITY_0); + rc = hfi_write_cmd(abort_cmd); if (rc) { kfree(abort_cmd); return rc; @@ -2312,6 +2300,7 @@ static int cam_icp_mgr_abort_handle( CAM_ERR(CAM_ICP, "FW timeout/err in abort handle command"); } + kfree(abort_cmd); return rc; } @@ -2322,13 +2311,7 @@ static int cam_icp_mgr_destroy_handle( int timeout = 100; unsigned long rem_jiffies; size_t packet_size; - struct hfi_cmd_work_data *task_data; struct hfi_cmd_ipebps_async *destroy_cmd; - struct crm_workq_task *task; - - task = cam_req_mgr_workq_get_task(icp_hw_mgr.cmd_work); - if (!task) - return -ENOMEM; packet_size = sizeof(struct hfi_cmd_ipebps_async) + @@ -2355,13 +2338,7 @@ static int cam_icp_mgr_destroy_handle( memcpy(destroy_cmd->payload.direct, &ctx_data->temp_payload, sizeof(uint64_t)); - task_data = (struct hfi_cmd_work_data *)task->payload; - task_data->data = (void *)destroy_cmd; - task_data->request_id = 0; - task_data->type = ICP_WORKQ_TASK_CMD_TYPE; - task->process_cb = cam_icp_mgr_process_cmd; - rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, - CRM_TASK_PRIORITY_0); + rc = hfi_write_cmd(destroy_cmd); if (rc) { kfree(destroy_cmd); return rc; @@ -2378,6 +2355,7 @@ static int cam_icp_mgr_destroy_handle( HFI_DEBUG_MODE_QUEUE) cam_icp_mgr_process_dbg_buf(); } + kfree(destroy_cmd); return rc; } -- GitLab From da789f7d683cbce7da4c008c62668cd5912f2dec Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 22 Jan 2018 12:20:26 +0100 Subject: [PATCH 0876/1834] ARM: 8746/1: vfp: Go back to clearing vfp_current_hw_state[] commit 1328f02005bbbaed15b9d5b7f3ab5ec9d4d5268a upstream. Commit 384b38b66947 ("ARM: 7873/1: vfp: clear vfp_current_hw_state for dying cpu") fixed the cpu dying notifier by clearing vfp_current_hw_state[]. However commit e5b61bafe704 ("arm: Convert VFP hotplug notifiers to state machine") incorrectly used the original vfp_force_reload() function in the cpu dying notifier. Fix it by going back to clearing vfp_current_hw_state[]. Fixes: e5b61bafe704 ("arm: Convert VFP hotplug notifiers to state machine") Cc: linux-stable Reported-by: Kohji Okuno Signed-off-by: Fabio Estevam Signed-off-by: Russell King Signed-off-by: Greg Kroah-Hartman --- arch/arm/vfp/vfpmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index da0b33deba6d..5629d7580973 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -648,7 +648,7 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp, */ static int vfp_dying_cpu(unsigned int cpu) { - vfp_force_reload(cpu, current_thread_info()); + vfp_current_hw_state[cpu] = NULL; return 0; } -- GitLab From 760adf5cc0e042ad1f0cd54c267c0377d4b40b1e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 3 Mar 2018 23:29:03 +0100 Subject: [PATCH 0877/1834] mtd: jedec_probe: Fix crash in jedec_read_mfr() commit 87a73eb5b56fd6e07c8e499fe8608ef2d8912b82 upstream. It turns out that the loop where we read manufacturer jedec_read_mfd() can under some circumstances get a CFI_MFR_CONTINUATION repeatedly, making the loop go over all banks and eventually hit the end of the map and crash because of an access violation: Unable to handle kernel paging request at virtual address c4980000 pgd = (ptrval) [c4980000] *pgd=03808811, *pte=00000000, *ppte=00000000 Internal error: Oops: 7 [#1] PREEMPT ARM CPU: 0 PID: 1 Comm: swapper Not tainted 4.16.0-rc1+ #150 Hardware name: Gemini (Device Tree) PC is at jedec_probe_chip+0x6ec/0xcd0 LR is at 0x4 pc : [] lr : [<00000004>] psr: 60000013 sp : c382dd18 ip : 0000ffff fp : 00000000 r10: c0626388 r9 : 00020000 r8 : c0626340 r7 : 00000000 r6 : 00000001 r5 : c3a71afc r4 : c382dd70 r3 : 00000001 r2 : c4900000 r1 : 00000002 r0 : 00080000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none Control: 0000397f Table: 00004000 DAC: 00000053 Process swapper (pid: 1, stack limit = 0x(ptrval)) Fix this by breaking the loop with a return 0 if the offset exceeds the map size. Fixes: 5c9c11e1c47c ("[MTD] [NOR] Add support for flash chips with ID in bank other than 0") Cc: Signed-off-by: Linus Walleij Signed-off-by: Boris Brezillon Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/chips/jedec_probe.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index 7c0b27d132b1..b479bd81120b 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1889,6 +1889,8 @@ static inline u32 jedec_read_mfr(struct map_info *map, uint32_t base, do { uint32_t ofs = cfi_build_cmd_addr(0 + (bank << 8), map, cfi); mask = (1 << (cfi->device_type * 8)) - 1; + if (ofs >= map->size) + return 0; result = map_read(map, base + ofs); bank++; } while ((result.x[0] & mask) == CFI_MFR_CONTINUATION); -- GitLab From c7200152be3f185202ec263dbb050cb88d99053f Mon Sep 17 00:00:00 2001 From: Nobutaka Okabe Date: Fri, 23 Mar 2018 19:49:44 +0900 Subject: [PATCH 0878/1834] ALSA: usb-audio: Add native DSD support for TEAC UD-301 commit b00214865d65100163574ba250008f182cf90869 upstream. Add native DSD support quirk for TEAC UD-301 DAC, by adding the PID/VID 0644:804a. Signed-off-by: Nobutaka Okabe Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/quirks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 1cd7f8b0bf77..45655b9108e8 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1175,6 +1175,7 @@ static bool is_teac_dsd_dac(unsigned int id) switch (id) { case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */ case USB_ID(0x0644, 0x8044): /* Esoteric D-05X */ + case USB_ID(0x0644, 0x804a): /* TEAC UD-301 */ return true; } return false; -- GitLab From d5a2bcb8db37ba9b9502dd94c646ef36ad6a2ef7 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Mon, 26 Mar 2018 16:10:21 +0200 Subject: [PATCH 0879/1834] ALSA: pcm: Use dma_bytes as size parameter in dma_mmap_coherent() commit 9066ae7ff5d89c0b5daa271e2d573540097a94fa upstream. When trying to use the driver (e.g. aplay *.wav), the 4MiB DMA buffer will get mmapp'ed in 16KiB chunks. But this fails with the 2nd 16KiB area, as the page offset is outside of the VMA range (size), which is currently used as size parameter in snd_pcm_lib_default_mmap(). By using the DMA buffer size (dma_bytes) instead, the complete DMA buffer can be mmapp'ed and the issue is fixed. This issue was detected on an ARM platform (TI AM57xx) using the RME HDSP MADI PCIe soundcard. Fixes: 657b1989dacf ("ALSA: pcm - Use dma_mmap_coherent() if available") Signed-off-by: Stefan Roese Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm_native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 9d33c1e85c79..d503285867e7 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3410,7 +3410,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream, area, substream->runtime->dma_area, substream->runtime->dma_addr, - area->vm_end - area->vm_start); + substream->runtime->dma_bytes); #endif /* CONFIG_X86 */ /* mmap with fault handler */ area->vm_ops = &snd_pcm_vm_ops_data_fault; -- GitLab From 43320b2902ab09647bab768ba00fbfdee14b66b6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 27 Mar 2018 16:07:52 +0300 Subject: [PATCH 0880/1834] ALSA: pcm: potential uninitialized return values commit 5607dddbfca774fb38bffadcb077fe03aa4ac5c6 upstream. Smatch complains that "tmp" can be uninitialized if we do a zero size write. Fixes: 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write") Signed-off-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 3e7c3573871d..fa8741afadf5 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1361,7 +1361,7 @@ static ssize_t snd_pcm_oss_write2(struct snd_pcm_substream *substream, const cha static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const char __user *buf, size_t bytes) { size_t xfer = 0; - ssize_t tmp; + ssize_t tmp = 0; struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) @@ -1468,7 +1468,7 @@ static ssize_t snd_pcm_oss_read2(struct snd_pcm_substream *substream, char *buf, static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __user *buf, size_t bytes) { size_t xfer = 0; - ssize_t tmp; + ssize_t tmp = 0; struct snd_pcm_runtime *runtime = substream->runtime; if (atomic_read(&substream->mmap_count)) -- GitLab From 7614f7db9bee160c5e8d298919af3f28941fc703 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 26 Mar 2018 15:39:07 -1000 Subject: [PATCH 0881/1834] perf/hwbp: Simplify the perf-hwbp code, fix documentation commit f67b15037a7a50c57f72e69a6d59941ad90a0f0f upstream. Annoyingly, modify_user_hw_breakpoint() unnecessarily complicates the modification of a breakpoint - simplify it and remove the pointless local variables. Also update the stale Docbook while at it. Signed-off-by: Linus Torvalds Acked-by: Thomas Gleixner Cc: Cc: Alexander Shishkin Cc: Andy Lutomirski Cc: Arnaldo Carvalho de Melo Cc: Frederic Weisbecker Cc: Jiri Olsa Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Vince Weaver Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/events/hw_breakpoint.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c index 3f8cb1e14588..253ae2da13c3 100644 --- a/kernel/events/hw_breakpoint.c +++ b/kernel/events/hw_breakpoint.c @@ -427,16 +427,9 @@ EXPORT_SYMBOL_GPL(register_user_hw_breakpoint); * modify_user_hw_breakpoint - modify a user-space hardware breakpoint * @bp: the breakpoint structure to modify * @attr: new breakpoint attributes - * @triggered: callback to trigger when we hit the breakpoint - * @tsk: pointer to 'task_struct' of the process to which the address belongs */ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr) { - u64 old_addr = bp->attr.bp_addr; - u64 old_len = bp->attr.bp_len; - int old_type = bp->attr.bp_type; - int err = 0; - /* * modify_user_hw_breakpoint can be invoked with IRQs disabled and hence it * will not be possible to raise IPIs that invoke __perf_event_disable. @@ -451,27 +444,18 @@ int modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *att bp->attr.bp_addr = attr->bp_addr; bp->attr.bp_type = attr->bp_type; bp->attr.bp_len = attr->bp_len; + bp->attr.disabled = 1; - if (attr->disabled) - goto end; - - err = validate_hw_breakpoint(bp); - if (!err) - perf_event_enable(bp); + if (!attr->disabled) { + int err = validate_hw_breakpoint(bp); - if (err) { - bp->attr.bp_addr = old_addr; - bp->attr.bp_type = old_type; - bp->attr.bp_len = old_len; - if (!bp->attr.disabled) - perf_event_enable(bp); + if (err) + return err; - return err; + perf_event_enable(bp); + bp->attr.disabled = 0; } -end: - bp->attr.disabled = attr->disabled; - return 0; } EXPORT_SYMBOL_GPL(modify_user_hw_breakpoint); -- GitLab From ff1c42b0c60a11dc0272ea02bcc01eafe1652964 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Fri, 16 Mar 2018 11:22:29 +0800 Subject: [PATCH 0882/1834] ceph: only dirty ITER_IOVEC pages for direct read commit 85784f9395987a422fa04263e7c0fb13da11eb5c upstream. If a page is already locked, attempting to dirty it leads to a deadlock in lock_page(). This is what currently happens to ITER_BVEC pages when a dio-enabled loop device is backed by ceph: $ losetup --direct-io /dev/loop0 /mnt/cephfs/img $ xfs_io -c 'pread 0 4k' /dev/loop0 Follow other file systems and only dirty ITER_IOVEC pages. Cc: stable@kernel.org Signed-off-by: "Yan, Zheng" Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov Signed-off-by: Greg Kroah-Hartman --- fs/ceph/file.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index ca3f630db90f..e7ddb23d9bb7 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -598,7 +598,8 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i, struct ceph_aio_request { struct kiocb *iocb; size_t total_len; - int write; + bool write; + bool should_dirty; int error; struct list_head osd_reqs; unsigned num_reqs; @@ -708,7 +709,7 @@ static void ceph_aio_complete_req(struct ceph_osd_request *req) } } - ceph_put_page_vector(osd_data->pages, num_pages, !aio_req->write); + ceph_put_page_vector(osd_data->pages, num_pages, aio_req->should_dirty); ceph_osdc_put_request(req); if (rc < 0) @@ -890,6 +891,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, size_t count = iov_iter_count(iter); loff_t pos = iocb->ki_pos; bool write = iov_iter_rw(iter) == WRITE; + bool should_dirty = !write && iter_is_iovec(iter); if (write && ceph_snap(file_inode(file)) != CEPH_NOSNAP) return -EROFS; @@ -954,6 +956,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, if (aio_req) { aio_req->iocb = iocb; aio_req->write = write; + aio_req->should_dirty = should_dirty; INIT_LIST_HEAD(&aio_req->osd_reqs); if (write) { aio_req->mtime = mtime; @@ -1012,7 +1015,7 @@ ceph_direct_read_write(struct kiocb *iocb, struct iov_iter *iter, len = ret; } - ceph_put_page_vector(pages, num_pages, !write); + ceph_put_page_vector(pages, num_pages, should_dirty); ceph_osdc_put_request(req); if (ret < 0) -- GitLab From 86c8c892d38fd80c8acc4b44b75213758eb5d9de Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Wed, 28 Mar 2018 16:01:01 -0700 Subject: [PATCH 0883/1834] ipc/shm.c: add split function to shm_vm_ops commit 3d942ee079b917b24e2a0c5f18d35ac8ec9fee48 upstream. If System V shmget/shmat operations are used to create a hugetlbfs backed mapping, it is possible to munmap part of the mapping and split the underlying vma such that it is not huge page aligned. This will untimately result in the following BUG: kernel BUG at /build/linux-jWa1Fv/linux-4.15.0/mm/hugetlb.c:3310! Oops: Exception in kernel mode, sig: 5 [#1] LE SMP NR_CPUS=2048 NUMA PowerNV Modules linked in: kcm nfc af_alg caif_socket caif phonet fcrypt CPU: 18 PID: 43243 Comm: trinity-subchil Tainted: G C E 4.15.0-10-generic #11-Ubuntu NIP: c00000000036e764 LR: c00000000036ee48 CTR: 0000000000000009 REGS: c000003fbcdcf810 TRAP: 0700 Tainted: G C E (4.15.0-10-generic) MSR: 9000000000029033 CR: 24002222 XER: 20040000 CFAR: c00000000036ee44 SOFTE: 1 NIP __unmap_hugepage_range+0xa4/0x760 LR __unmap_hugepage_range_final+0x28/0x50 Call Trace: 0x7115e4e00000 (unreliable) __unmap_hugepage_range_final+0x28/0x50 unmap_single_vma+0x11c/0x190 unmap_vmas+0x94/0x140 exit_mmap+0x9c/0x1d0 mmput+0xa8/0x1d0 do_exit+0x360/0xc80 do_group_exit+0x60/0x100 SyS_exit_group+0x24/0x30 system_call+0x58/0x6c ---[ end trace ee88f958a1c62605 ]--- This bug was introduced by commit 31383c6865a5 ("mm, hugetlbfs: introduce ->split() to vm_operations_struct"). A split function was added to vm_operations_struct to determine if a mapping can be split. This was mostly for device-dax and hugetlbfs mappings which have specific alignment constraints. Mappings initiated via shmget/shmat have their original vm_ops overwritten with shm_vm_ops. shm_vm_ops functions will call back to the original vm_ops if needed. Add such a split function to shm_vm_ops. Link: http://lkml.kernel.org/r/20180321161314.7711-1-mike.kravetz@oracle.com Fixes: 31383c6865a5 ("mm, hugetlbfs: introduce ->split() to vm_operations_struct") Signed-off-by: Mike Kravetz Reported-by: Laurent Dufour Reviewed-by: Laurent Dufour Tested-by: Laurent Dufour Reviewed-by: Dan Williams Acked-by: Michal Hocko Cc: Davidlohr Bueso Cc: Manfred Spraul Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- ipc/shm.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ipc/shm.c b/ipc/shm.c index e2072ae4f90e..de93d01bfce2 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -381,6 +381,17 @@ static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return sfd->vm_ops->fault(vma, vmf); } +static int shm_split(struct vm_area_struct *vma, unsigned long addr) +{ + struct file *file = vma->vm_file; + struct shm_file_data *sfd = shm_file_data(file); + + if (sfd->vm_ops && sfd->vm_ops->split) + return sfd->vm_ops->split(vma, addr); + + return 0; +} + #ifdef CONFIG_NUMA static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new) { @@ -503,6 +514,7 @@ static const struct vm_operations_struct shm_vm_ops = { .open = shm_open, /* callback for a new vm-area open */ .close = shm_close, /* callback for when the vm-area is released */ .fault = shm_fault, + .split = shm_split, #if defined(CONFIG_NUMA) .set_policy = shm_set_policy, .get_policy = shm_get_policy, -- GitLab From 812d42a5a9b64ac929fa24ee352908601a910fa3 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Wed, 21 Mar 2018 12:22:28 +1000 Subject: [PATCH 0884/1834] powerpc/64s: Fix lost pending interrupt due to race causing lost update to irq_happened commit ff6781fd1bb404d8a551c02c35c70cec1da17ff1 upstream. force_external_irq_replay() can be called in the do_IRQ path with interrupts hard enabled and soft disabled if may_hard_irq_enable() set MSR[EE]=1. It updates local_paca->irq_happened with a load, modify, store sequence. If a maskable interrupt hits during this sequence, it will go to the masked handler to be marked pending in irq_happened. This update will be lost when the interrupt returns and the store instruction executes. This can result in unpredictable latencies, timeouts, lockups, etc. Fix this by ensuring hard interrupts are disabled before modifying irq_happened. This could cause any maskable asynchronous interrupt to get lost, but it was noticed on P9 SMP system doing RDMA NVMe target over 100GbE, so very high external interrupt rate and high IPI rate. The hang was bisected down to enabling doorbell interrupts for IPIs. These provided an interrupt type that could run at high rates in the do_IRQ path, stressing the race. Fixes: 1d607bb3bd60 ("powerpc/irq: Add mechanism to force a replay of interrupts") Cc: stable@vger.kernel.org # v4.8+ Reported-by: Carol L. Soto Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/irq.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 028a22bfa90c..ad713f741ca8 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -372,6 +372,14 @@ void force_external_irq_replay(void) */ WARN_ON(!arch_irqs_disabled()); + /* + * Interrupts must always be hard disabled before irq_happened is + * modified (to prevent lost update in case of interrupt between + * load and store). + */ + __hard_irq_disable(); + local_paca->irq_happened |= PACA_IRQ_HARD_DIS; + /* Indicate in the PACA that we have an interrupt to replay */ local_paca->irq_happened |= PACA_IRQ_EE; } -- GitLab From e522e2ea300e2345d287478fe034d995fecf96e2 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Fri, 23 Mar 2018 15:53:38 +1000 Subject: [PATCH 0885/1834] powerpc/64s: Fix i-side SLB miss bad address handler saving nonvolatile GPRs commit 52396500f97c53860164debc7d4f759077853423 upstream. The SLB bad address handler's trap number fixup does not preserve the low bit that indicates nonvolatile GPRs have not been saved. This leads save_nvgprs to skip saving them, and subsequent functions and return from interrupt will think they are saved. This causes kernel branch-to-garbage debugging to not have correct registers, can also cause userspace to have its registers clobbered after a segfault. Fixes: f0f558b131db ("powerpc/mm: Preserve CFAR value on SLB miss caused by access to bogus address") Cc: stable@vger.kernel.org # v4.9+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/exceptions-64s.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 7614d1dd2c0b..94b5dfb087e9 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -723,7 +723,7 @@ EXC_COMMON_BEGIN(bad_addr_slb) ld r3, PACA_EXSLB+EX_DAR(r13) std r3, _DAR(r1) beq cr6, 2f - li r10, 0x480 /* fix trap number for I-SLB miss */ + li r10, 0x481 /* fix trap number for I-SLB miss */ std r10, _TRAP(r1) 2: bl save_nvgprs addi r3, r1, STACK_FRAME_OVERHEAD -- GitLab From bd94a2c744246617623c3d67a2511d5493250688 Mon Sep 17 00:00:00 2001 From: Richard Narron Date: Wed, 10 Jan 2018 09:12:16 -0700 Subject: [PATCH 0886/1834] partitions/msdos: Unable to mount UFS 44bsd partitions commit 5f15684bd5e5ef39d4337988864fec8012471dda upstream. UFS partitions from newer versions of FreeBSD 10 and 11 use relative addressing for their subpartitions. But older versions of FreeBSD still use absolute addressing just like OpenBSD and NetBSD. Instead of simply testing for a FreeBSD partition, the code needs to also test if the starting offset of the C subpartition is zero. https://bugzilla.kernel.org/show_bug.cgi?id=197733 Signed-off-by: Richard Narron Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/partitions/msdos.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/partitions/msdos.c b/block/partitions/msdos.c index 5610cd537da7..7d8d50c11ce7 100644 --- a/block/partitions/msdos.c +++ b/block/partitions/msdos.c @@ -300,7 +300,9 @@ static void parse_bsd(struct parsed_partitions *state, continue; bsd_start = le32_to_cpu(p->p_offset); bsd_size = le32_to_cpu(p->p_size); - if (memcmp(flavour, "bsd\0", 4) == 0) + /* FreeBSD has relative offset if C partition offset is zero */ + if (memcmp(flavour, "bsd\0", 4) == 0 && + le32_to_cpu(l->d_partitions[2].p_offset) == 0) bsd_start += offset; if (offset == bsd_start && size == bsd_size) /* full parent partition, we have it already */ -- GitLab From fd2f070985ea0eefdd503efbb9a5b9275161b893 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Thu, 25 May 2017 19:38:17 +0900 Subject: [PATCH 0887/1834] kprobes/x86: Fix to set RWX bits correctly before releasing trampoline commit c93f5cf571e7795f97d49ef51b766cf25e328545 upstream. Fix kprobes to set(recover) RWX bits correctly on trampoline buffer before releasing it. Releasing readonly page to module_memfree() crash the kernel. Without this fix, if kprobes user register a bunch of kprobes in function body (since kprobes on function entry usually use ftrace) and unregister it, kernel hits a BUG and crash. Link: http://lkml.kernel.org/r/149570868652.3518.14120169373590420503.stgit@devbox Signed-off-by: Masami Hiramatsu Fixes: d0381c81c2f7 ("kprobes/x86: Set kprobes pages read-only") Signed-off-by: Steven Rostedt (VMware) Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/kprobes/core.c | 9 +++++++++ kernel/kprobes.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index b8d3f1b60331..91c48cdfe81f 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -405,6 +406,14 @@ int __copy_instruction(u8 *dest, u8 *src) return length; } +/* Recover page to RW mode before releasing it */ +void free_insn_page(void *page) +{ + set_memory_nx((unsigned long)page & PAGE_MASK, 1); + set_memory_rw((unsigned long)page & PAGE_MASK, 1); + module_memfree(page); +} + static int arch_copy_kprobe(struct kprobe *p) { int ret; diff --git a/kernel/kprobes.c b/kernel/kprobes.c index a1a07cf1101f..69485183af79 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -125,7 +125,7 @@ static void *alloc_insn_page(void) return module_alloc(PAGE_SIZE); } -static void free_insn_page(void *page) +void __weak free_insn_page(void *page) { module_memfree(page); } -- GitLab From 4d9a121dc9b3c0907bc8bc23dd5445cea1192fb3 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 14 Apr 2017 13:38:02 -0700 Subject: [PATCH 0888/1834] PCI: Make PCI_ROM_ADDRESS_MASK a 32-bit constant commit 76dc52684d0f72971d9f6cc7d5ae198061b715bd upstream. A 64-bit value is not needed since a PCI ROM address consists in 32 bits. This fixes a clang warning about "implicit conversion from 'unsigned long' to 'u32'". Also remove now unnecessary casts to u32 from __pci_read_base() and pci_std_update_resource(). Signed-off-by: Matthias Kaehlcke Signed-off-by: Bjorn Helgaas Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/pci/probe.c | 2 +- drivers/pci/setup-res.c | 2 +- include/uapi/linux/pci_regs.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a98be6db7e93..56340abe4fc6 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -231,7 +231,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, res->flags |= IORESOURCE_ROM_ENABLE; l64 = l & PCI_ROM_ADDRESS_MASK; sz64 = sz & PCI_ROM_ADDRESS_MASK; - mask64 = (u32)PCI_ROM_ADDRESS_MASK; + mask64 = PCI_ROM_ADDRESS_MASK; } if (res->flags & IORESOURCE_MEM_64) { diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 4bc589ee78d0..85774b7a316a 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -63,7 +63,7 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno) mask = (u32)PCI_BASE_ADDRESS_IO_MASK; new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK; } else if (resno == PCI_ROM_RESOURCE) { - mask = (u32)PCI_ROM_ADDRESS_MASK; + mask = PCI_ROM_ADDRESS_MASK; } else { mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index e5a2e68b2236..ecc8e01c5616 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -106,7 +106,7 @@ #define PCI_SUBSYSTEM_ID 0x2e #define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ #define PCI_ROM_ADDRESS_ENABLE 0x01 -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) +#define PCI_ROM_ADDRESS_MASK (~0x7ffU) #define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ -- GitLab From 6be48fd6991f14f46f041fcd82614e3b2f5172f5 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 17 Apr 2017 11:05:03 -0700 Subject: [PATCH 0889/1834] dm ioctl: remove double parentheses commit e36215d87f301f9567c8c99fd34e6c3521a94ddf upstream. The extra pair of parantheses is not needed and causes clang to generate warnings about the DM_DEV_CREATE_CMD comparison in validate_params(). Also remove another double parentheses that doesn't cause a warning. Signed-off-by: Matthias Kaehlcke Signed-off-by: Mike Snitzer Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/md/dm-ioctl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index a68c650aad11..b67414b5a64e 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1777,12 +1777,12 @@ static int validate_params(uint cmd, struct dm_ioctl *param) cmd == DM_LIST_VERSIONS_CMD) return 0; - if ((cmd == DM_DEV_CREATE_CMD)) { + if (cmd == DM_DEV_CREATE_CMD) { if (!*param->name) { DMWARN("name not supplied when creating device"); return -EINVAL; } - } else if ((*param->uuid && *param->name)) { + } else if (*param->uuid && *param->name) { DMWARN("only supply one of name or uuid, cmd(%u)", cmd); return -EINVAL; } -- GitLab From b4361da43816836e2a28b266dc7ae4c12d754edb Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Sat, 24 Jun 2017 22:50:12 -0700 Subject: [PATCH 0890/1834] Input: mousedev - fix implicit conversion warning commit dae1a432ab1fe79ae53129ededeaece35a2dc14d upstream. Clang warns: drivers/input/mousedev.c:653:63: error: implicit conversion from 'int' to 'signed char' changes value from 200 to -56 [-Wconstant-conversion] client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; ~ ^~~ As the PS2 data is really a stream of bytes, let's switch to using u8 type for it, which silences this warning. Signed-off-by: Nick Desaulniers Signed-off-by: Dmitry Torokhov Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/input/mousedev.c | 62 ++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index b604564dec5c..30328e57fdda 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -15,6 +15,7 @@ #define MOUSEDEV_MINORS 31 #define MOUSEDEV_MIX 63 +#include #include #include #include @@ -103,7 +104,7 @@ struct mousedev_client { spinlock_t packet_lock; int pos_x, pos_y; - signed char ps2[6]; + u8 ps2[6]; unsigned char ready, buffer, bufsiz; unsigned char imexseq, impsseq; enum mousedev_emul mode; @@ -291,11 +292,10 @@ static void mousedev_notify_readers(struct mousedev *mousedev, } client->pos_x += packet->dx; - client->pos_x = client->pos_x < 0 ? - 0 : (client->pos_x >= xres ? xres : client->pos_x); + client->pos_x = clamp_val(client->pos_x, 0, xres); + client->pos_y += packet->dy; - client->pos_y = client->pos_y < 0 ? - 0 : (client->pos_y >= yres ? yres : client->pos_y); + client->pos_y = clamp_val(client->pos_y, 0, yres); p->dx += packet->dx; p->dy += packet->dy; @@ -571,44 +571,50 @@ static int mousedev_open(struct inode *inode, struct file *file) return error; } -static inline int mousedev_limit_delta(int delta, int limit) -{ - return delta > limit ? limit : (delta < -limit ? -limit : delta); -} - -static void mousedev_packet(struct mousedev_client *client, - signed char *ps2_data) +static void mousedev_packet(struct mousedev_client *client, u8 *ps2_data) { struct mousedev_motion *p = &client->packets[client->tail]; + s8 dx, dy, dz; + + dx = clamp_val(p->dx, -127, 127); + p->dx -= dx; + + dy = clamp_val(p->dy, -127, 127); + p->dy -= dy; - ps2_data[0] = 0x08 | - ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); - ps2_data[1] = mousedev_limit_delta(p->dx, 127); - ps2_data[2] = mousedev_limit_delta(p->dy, 127); - p->dx -= ps2_data[1]; - p->dy -= ps2_data[2]; + ps2_data[0] = BIT(3); + ps2_data[0] |= ((dx & BIT(7)) >> 3) | ((dy & BIT(7)) >> 2); + ps2_data[0] |= p->buttons & 0x07; + ps2_data[1] = dx; + ps2_data[2] = dy; switch (client->mode) { case MOUSEDEV_EMUL_EXPS: - ps2_data[3] = mousedev_limit_delta(p->dz, 7); - p->dz -= ps2_data[3]; - ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); + dz = clamp_val(p->dz, -7, 7); + p->dz -= dz; + + ps2_data[3] = (dz & 0x0f) | ((p->buttons & 0x18) << 1); client->bufsiz = 4; break; case MOUSEDEV_EMUL_IMPS: - ps2_data[0] |= - ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); - ps2_data[3] = mousedev_limit_delta(p->dz, 127); - p->dz -= ps2_data[3]; + dz = clamp_val(p->dz, -127, 127); + p->dz -= dz; + + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | + ((p->buttons & 0x08) >> 1); + ps2_data[3] = dz; + client->bufsiz = 4; break; case MOUSEDEV_EMUL_PS2: default: - ps2_data[0] |= - ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); p->dz = 0; + + ps2_data[0] |= ((p->buttons & 0x10) >> 3) | + ((p->buttons & 0x08) >> 1); + client->bufsiz = 3; break; } @@ -714,7 +720,7 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, { struct mousedev_client *client = file->private_data; struct mousedev *mousedev = client->mousedev; - signed char data[sizeof(client->ps2)]; + u8 data[sizeof(client->ps2)]; int retval = 0; if (!client->ready && !client->buffer && mousedev->exist && -- GitLab From 4d1fc27f41b24cdfa69413e1c03a50c591cbae9a Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Fri, 11 Aug 2017 11:16:07 -0700 Subject: [PATCH 0891/1834] netfilter: nf_nat_h323: fix logical-not-parentheses warning commit eee6ebbac18a189ef33d25ea9b8bcae176515e49 upstream. Clang produces the following warning: net/ipv4/netfilter/nf_nat_h323.c:553:6: error: logical not is only applied to the left hand side of this comparison [-Werror,-Wlogical-not-parentheses] if (!set_h225_addr(skb, protoff, data, dataoff, taddr, ^ add parentheses after the '!' to evaluate the comparison first add parentheses around left hand side expression to silence this warning There's not necessarily a bug here, but it's cleaner to return early, ex: if (x) return ... rather than: if (x == 0) ... else return Also added a return code check that seemed to be missing in one instance. Signed-off-by: Nick Desaulniers Signed-off-by: Pablo Neira Ayuso Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/ipv4/netfilter/nf_nat_h323.c | 57 +++++++++++++++++--------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c index 574f7ebba0b6..ac8342dcb55e 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -252,16 +252,16 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, if (set_h245_addr(skb, protoff, data, dataoff, taddr, &ct->tuplehash[!dir].tuple.dst.u3, htons((port & htons(1)) ? nated_port + 1 : - nated_port)) == 0) { - /* Save ports */ - info->rtp_port[i][dir] = rtp_port; - info->rtp_port[i][!dir] = htons(nated_port); - } else { + nated_port))) { nf_ct_unexpect_related(rtp_exp); nf_ct_unexpect_related(rtcp_exp); return -1; } + /* Save ports */ + info->rtp_port[i][dir] = rtp_port; + info->rtp_port[i][!dir] = htons(nated_port); + /* Success */ pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n", &rtp_exp->tuple.src.u3.ip, @@ -370,15 +370,15 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct, /* Modify signal */ if (set_h225_addr(skb, protoff, data, dataoff, taddr, &ct->tuplehash[!dir].tuple.dst.u3, - htons(nated_port)) == 0) { - /* Save ports */ - info->sig_port[dir] = port; - info->sig_port[!dir] = htons(nated_port); - } else { + htons(nated_port))) { nf_ct_unexpect_related(exp); return -1; } + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n", &exp->tuple.src.u3.ip, ntohs(exp->tuple.src.u.tcp.port), @@ -462,24 +462,27 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct, /* Modify signal */ if (set_h225_addr(skb, protoff, data, 0, &taddr[idx], &ct->tuplehash[!dir].tuple.dst.u3, - htons(nated_port)) == 0) { - /* Save ports */ - info->sig_port[dir] = port; - info->sig_port[!dir] = htons(nated_port); - - /* Fix for Gnomemeeting */ - if (idx > 0 && - get_h225_addr(ct, *data, &taddr[0], &addr, &port) && - (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { - set_h225_addr(skb, protoff, data, 0, &taddr[0], - &ct->tuplehash[!dir].tuple.dst.u3, - info->sig_port[!dir]); - } - } else { + htons(nated_port))) { nf_ct_unexpect_related(exp); return -1; } + /* Save ports */ + info->sig_port[dir] = port; + info->sig_port[!dir] = htons(nated_port); + + /* Fix for Gnomemeeting */ + if (idx > 0 && + get_h225_addr(ct, *data, &taddr[0], &addr, &port) && + (ntohl(addr.ip) & 0xff000000) == 0x7f000000) { + if (set_h225_addr(skb, protoff, data, 0, &taddr[0], + &ct->tuplehash[!dir].tuple.dst.u3, + info->sig_port[!dir])) { + nf_ct_unexpect_related(exp); + return -1; + } + } + /* Success */ pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n", &exp->tuple.src.u3.ip, @@ -550,9 +553,9 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, } /* Modify signal */ - if (!set_h225_addr(skb, protoff, data, dataoff, taddr, - &ct->tuplehash[!dir].tuple.dst.u3, - htons(nated_port)) == 0) { + if (set_h225_addr(skb, protoff, data, dataoff, taddr, + &ct->tuplehash[!dir].tuple.dst.u3, + htons(nated_port))) { nf_ct_unexpect_related(exp); return -1; } -- GitLab From 02e3a7d445c30d56d825599a7dea67cdc2bd3288 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 12 Apr 2017 11:20:30 -0700 Subject: [PATCH 0892/1834] genirq: Use cpumask_available() for check of cpumask variable commit d170fe7dd992b313d4851ae5ab77ee7a51ed8c72 upstream. This fixes the following clang warning when CONFIG_CPUMASK_OFFSTACK=n: kernel/irq/manage.c:839:28: error: address of array 'desc->irq_common_data.affinity' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] Signed-off-by: Matthias Kaehlcke Cc: Grant Grundler Cc: Rusty Russell Cc: Greg Hackmann Cc: Michael Davidson Cc: Andrew Morton Link: http://lkml.kernel.org/r/20170412182030.83657-2-mka@chromium.org Signed-off-by: Thomas Gleixner Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- kernel/irq/manage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index ea41820ab12e..5927da596d42 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -850,7 +850,7 @@ irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) * This code is triggered unconditionally. Check the affinity * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out. */ - if (desc->irq_common_data.affinity) + if (cpumask_available(desc->irq_common_data.affinity)) cpumask_copy(mask, desc->irq_common_data.affinity); else valid = false; -- GitLab From e78c59fda86c61b5c2a79ad9c4a52cd72a9c88ef Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 12 Apr 2017 11:20:29 -0700 Subject: [PATCH 0893/1834] cpumask: Add helper cpumask_available() commit f7e30f01a9e221067bb4b579e3cfc25cd2617467 upstream. With CONFIG_CPUMASK_OFFSTACK=y cpumask_var_t is a struct cpumask pointer, otherwise a struct cpumask array with a single element. Some code dealing with cpumasks needs to validate that a cpumask_var_t is not a NULL pointer when CONFIG_CPUMASK_OFFSTACK=y. This is typically done by performing the check always, regardless of the underlying type of cpumask_var_t. This works in both cases, however clang raises a warning like this when CONFIG_CPUMASK_OFFSTACK=n: kernel/irq/manage.c:839:28: error: address of array 'desc->irq_common_data.affinity' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] Add the inline helper cpumask_available() which only performs the pointer check if CONFIG_CPUMASK_OFFSTACK=y. Signed-off-by: Matthias Kaehlcke Cc: Grant Grundler Cc: Rusty Russell Cc: Greg Hackmann Cc: Michael Davidson Cc: Andrew Morton Link: http://lkml.kernel.org/r/20170412182030.83657-1-mka@chromium.org Signed-off-by: Thomas Gleixner Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- include/linux/cpumask.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h index 2d65bbd6dbd1..18ba29ff1449 100644 --- a/include/linux/cpumask.h +++ b/include/linux/cpumask.h @@ -680,6 +680,11 @@ void alloc_bootmem_cpumask_var(cpumask_var_t *mask); void free_cpumask_var(cpumask_var_t mask); void free_bootmem_cpumask_var(cpumask_var_t mask); +static inline bool cpumask_available(cpumask_var_t mask) +{ + return mask != NULL; +} + #else typedef struct cpumask cpumask_var_t[1]; @@ -720,6 +725,11 @@ static inline void free_cpumask_var(cpumask_var_t mask) static inline void free_bootmem_cpumask_var(cpumask_var_t mask) { } + +static inline bool cpumask_available(cpumask_var_t mask) +{ + return true; +} #endif /* CONFIG_CPUMASK_OFFSTACK */ /* It's common to want to use cpu_all_mask in struct member initializers, -- GitLab From 00972acdcf70f21548d9aa7915f7ceacf87dcf05 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 16 Mar 2017 15:26:52 -0700 Subject: [PATCH 0894/1834] selinux: Remove unnecessary check of array base in selinux_set_mapping() commit 342e91578eb6909529bc7095964cd44b9c057c4e upstream. 'perms' will never be NULL since it isn't a plain pointer but an array of u32 values. This fixes the following warning when building with clang: security/selinux/ss/services.c:158:16: error: address of array 'p_in->perms' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] while (p_in->perms && p_in->perms[k]) { Signed-off-by: Matthias Kaehlcke Signed-off-by: Paul Moore Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- security/selinux/ss/services.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 73275a92f2e2..d656b7c98394 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -155,7 +155,7 @@ static int selinux_set_mapping(struct policydb *pol, } k = 0; - while (p_in->perms && p_in->perms[k]) { + while (p_in->perms[k]) { /* An empty permission string skips ahead */ if (!*p_in->perms[k]) { k++; -- GitLab From a9b2c4a8f4bfd960d8c2dbe70e73c903309050a3 Mon Sep 17 00:00:00 2001 From: Mark Charlebois Date: Fri, 28 Apr 2017 15:15:12 -0700 Subject: [PATCH 0895/1834] fs: compat: Remove warning from COMPATIBLE_IOCTL commit 9280cdd6fe5b8287a726d24cc1d558b96c8491d7 upstream. cmd in COMPATIBLE_IOCTL is always a u32, so cast it so there isn't a warning about an overflow in XFORM. From: Mark Charlebois Signed-off-by: Mark Charlebois Signed-off-by: Behan Webster Signed-off-by: Matthias Kaehlcke Acked-by: Arnd Bergmann Signed-off-by: Al Viro Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- fs/compat_ioctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index f2d7402abe02..93c8e4a4bbd3 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -833,7 +833,7 @@ static int compat_ioctl_preallocate(struct file *file, */ #define XFORM(i) (((i) ^ ((i) << 27) ^ ((i) << 17)) & 0xffffffff) -#define COMPATIBLE_IOCTL(cmd) XFORM(cmd), +#define COMPATIBLE_IOCTL(cmd) XFORM((u32)cmd), /* ioctl should not be warned about even if it's not implemented. Valid reasons to use this: - It is implemented with ->compat_ioctl on some device, but programs -- GitLab From bbc5d42d5ec735a3716882ef87a9f57aceac8590 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 8 May 2017 15:55:05 -0700 Subject: [PATCH 0896/1834] jiffies.h: declare jiffies and jiffies_64 with ____cacheline_aligned_in_smp commit 7c30f352c852bae2715ad65ac4a38ca9af7d7696 upstream. jiffies_64 is defined in kernel/time/timer.c with ____cacheline_aligned_in_smp, however this macro is not part of the declaration of jiffies and jiffies_64 in jiffies.h. As a result clang generates the following warning: kernel/time/timer.c:57:26: error: section does not match previous declaration [-Werror,-Wsection] __visible u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; ^ include/linux/cache.h:39:36: note: expanded from macro '__cacheline_aligned_in_smp' ^ include/linux/cache.h:34:4: note: expanded from macro '__cacheline_aligned' __section__(".data..cacheline_aligned"))) ^ include/linux/jiffies.h:77:12: note: previous attribute is here extern u64 __jiffy_data jiffies_64; ^ include/linux/jiffies.h:70:38: note: expanded from macro '__jiffy_data' Link: http://lkml.kernel.org/r/20170403190200.70273-1-mka@chromium.org Signed-off-by: Matthias Kaehlcke Cc: "Jason A . Donenfeld" Cc: Grant Grundler Cc: Michael Davidson Cc: Greg Hackmann Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- include/linux/jiffies.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 589d14e970ad..175873a814fd 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -1,6 +1,7 @@ #ifndef _LINUX_JIFFIES_H #define _LINUX_JIFFIES_H +#include #include #include #include @@ -63,19 +64,13 @@ extern int register_refined_jiffies(long clock_tick_rate); /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) -/* some arch's have a small-data section that can be accessed register-relative - * but that can only take up to, say, 4-byte variables. jiffies being part of - * an 8-byte variable may not be correctly accessed unless we force the issue - */ -#define __jiffy_data __attribute__((section(".data"))) - /* * The 64-bit value is not atomic - you MUST NOT read it * without sampling the sequence number in jiffies_lock. * get_jiffies_64() will do this for you as appropriate. */ -extern u64 __jiffy_data jiffies_64; -extern unsigned long volatile __jiffy_data jiffies; +extern u64 __cacheline_aligned_in_smp jiffies_64; +extern unsigned long volatile __cacheline_aligned_in_smp jiffies; #if (BITS_PER_LONG < 64) u64 get_jiffies_64(void); -- GitLab From fc7a9eb0f88375fc27e2454b256dc19ebc283ac8 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 2 Jun 2017 14:46:16 -0700 Subject: [PATCH 0897/1834] frv: declare jiffies to be located in the .data section commit 60b0a8c3d2480f3b57282b47b7cae7ee71c48635 upstream. Commit 7c30f352c852 ("jiffies.h: declare jiffies and jiffies_64 with ____cacheline_aligned_in_smp") removed a section specification from the jiffies declaration that caused conflicts on some platforms. Unfortunately this change broke the build for frv: kernel/built-in.o: In function `__do_softirq': (.text+0x6460): relocation truncated to fit: R_FRV_GPREL12 against symbol `jiffies' defined in *ABS* section in .tmp_vmlinux1 kernel/built-in.o: In function `__do_softirq': (.text+0x6574): relocation truncated to fit: R_FRV_GPREL12 against symbol `jiffies' defined in *ABS* section in .tmp_vmlinux1 kernel/built-in.o: In function `pwq_activate_delayed_work': workqueue.c:(.text+0x15b9c): relocation truncated to fit: R_FRV_GPREL12 against symbol `jiffies' defined in *ABS* section in .tmp_vmlinux1 ... Add __jiffy_arch_data to the declaration of jiffies and use it on frv to include the section specification. For all other platforms __jiffy_arch_data (currently) has no effect. Fixes: 7c30f352c852 ("jiffies.h: declare jiffies and jiffies_64 with ____cacheline_aligned_in_smp") Link: http://lkml.kernel.org/r/20170516221333.177280-1-mka@chromium.org Signed-off-by: Matthias Kaehlcke Reported-by: Guenter Roeck Tested-by: Guenter Roeck Reviewed-by: David Howells Cc: Sudip Mukherjee Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- arch/frv/include/asm/timex.h | 6 ++++++ include/linux/jiffies.h | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/frv/include/asm/timex.h b/arch/frv/include/asm/timex.h index a89bddefdacf..139093fab326 100644 --- a/arch/frv/include/asm/timex.h +++ b/arch/frv/include/asm/timex.h @@ -16,5 +16,11 @@ static inline cycles_t get_cycles(void) #define vxtime_lock() do {} while (0) #define vxtime_unlock() do {} while (0) +/* This attribute is used in include/linux/jiffies.h alongside with + * __cacheline_aligned_in_smp. It is assumed that __cacheline_aligned_in_smp + * for frv does not contain another section specification. + */ +#define __jiffy_arch_data __attribute__((__section__(".data"))) + #endif diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index 175873a814fd..c2a0f0072274 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -64,13 +64,17 @@ extern int register_refined_jiffies(long clock_tick_rate); /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) +#ifndef __jiffy_arch_data +#define __jiffy_arch_data +#endif + /* * The 64-bit value is not atomic - you MUST NOT read it * without sampling the sequence number in jiffies_lock. * get_jiffies_64() will do this for you as appropriate. */ extern u64 __cacheline_aligned_in_smp jiffies_64; -extern unsigned long volatile __cacheline_aligned_in_smp jiffies; +extern unsigned long volatile __cacheline_aligned_in_smp __jiffy_arch_data jiffies; #if (BITS_PER_LONG < 64) u64 get_jiffies_64(void); -- GitLab From 17af7983691f9394e5e3619e910570f8897b5ab0 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Sun, 16 Apr 2017 20:12:50 -0700 Subject: [PATCH 0898/1834] usb: gadget: remove redundant self assignment commit 8a8b161df5ce06ef5a315899f83978e765be09e8 upstream. The assignment ret = ret is redundant and can be removed. Reviewed-by: Krzysztof Opasiak Reviewed-by: Peter Chen Signed-off-by: Stefan Agner Signed-off-by: Felipe Balbi Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index e97539fc127e..7d658565b20f 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -139,10 +139,8 @@ int usb_ep_disable(struct usb_ep *ep) goto out; ret = ep->ops->disable(ep); - if (ret) { - ret = ret; + if (ret) goto out; - } ep->enabled = false; -- GitLab From 54af0282954055bc5f866a6a449864ca61a86282 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 1 Feb 2017 17:46:02 +0100 Subject: [PATCH 0899/1834] xgene_enet: remove bogus forward declarations commit 1f3d62090d3ba4d0c14e5271be87812fc577b197 upstream. The device match tables for both the xgene_enet driver and its phy driver have forward declarations that declare an array without a length, leading to a clang warning when they are not followed by an actual defitinition: drivers/net/ethernet/apm/xgene/../../../phy/mdio-xgene.h:135:34: warning: tentative array definition assumed to have one element drivers/net/ethernet/apm/xgene/xgene_enet_main.c:33:36: warning: tentative array definition assumed to have one element The declarations for the mdio driver are even in a header file, so they cause duplicate definitions of the tables for each file that includes them. This removes all four forward declarations and moves the actual definitions up a little, so they are in front of their first user. For the OF match tables, this means having to remove the #ifdef around them, and passing the actual structure into of_match_device(). This has no effect on the generated object code though, as the of_match_device function has an empty stub that does not evaluate its argument, and the symbol gets dropped either way. Fixes: 43b3cf6634a4 ("drivers: net: phy: xgene: Add MDIO driver") Signed-off-by: Arnd Bergmann Signed-off-by: David S. Miller Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/apm/xgene/xgene_enet_main.c | 50 +++++++++---------- drivers/net/phy/mdio-xgene.c | 50 +++++++++---------- drivers/net/phy/mdio-xgene.h | 4 -- 3 files changed, 48 insertions(+), 56 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 651f308cdc60..fca2e428cd86 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -1680,6 +1680,30 @@ static void xgene_enet_napi_add(struct xgene_enet_pdata *pdata) } } +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_enet_acpi_match[] = { + { "APMC0D05", XGENE_ENET1}, + { "APMC0D30", XGENE_ENET1}, + { "APMC0D31", XGENE_ENET1}, + { "APMC0D3F", XGENE_ENET1}, + { "APMC0D26", XGENE_ENET2}, + { "APMC0D25", XGENE_ENET2}, + { } +}; +MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); +#endif + +static const struct of_device_id xgene_enet_of_match[] = { + {.compatible = "apm,xgene-enet", .data = (void *)XGENE_ENET1}, + {.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1}, + {.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1}, + {.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2}, + {.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2}, + {}, +}; + +MODULE_DEVICE_TABLE(of, xgene_enet_of_match); + static int xgene_enet_probe(struct platform_device *pdev) { struct net_device *ndev; @@ -1826,32 +1850,6 @@ static void xgene_enet_shutdown(struct platform_device *pdev) xgene_enet_remove(pdev); } -#ifdef CONFIG_ACPI -static const struct acpi_device_id xgene_enet_acpi_match[] = { - { "APMC0D05", XGENE_ENET1}, - { "APMC0D30", XGENE_ENET1}, - { "APMC0D31", XGENE_ENET1}, - { "APMC0D3F", XGENE_ENET1}, - { "APMC0D26", XGENE_ENET2}, - { "APMC0D25", XGENE_ENET2}, - { } -}; -MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match); -#endif - -#ifdef CONFIG_OF -static const struct of_device_id xgene_enet_of_match[] = { - {.compatible = "apm,xgene-enet", .data = (void *)XGENE_ENET1}, - {.compatible = "apm,xgene1-sgenet", .data = (void *)XGENE_ENET1}, - {.compatible = "apm,xgene1-xgenet", .data = (void *)XGENE_ENET1}, - {.compatible = "apm,xgene2-sgenet", .data = (void *)XGENE_ENET2}, - {.compatible = "apm,xgene2-xgenet", .data = (void *)XGENE_ENET2}, - {}, -}; - -MODULE_DEVICE_TABLE(of, xgene_enet_of_match); -#endif - static struct platform_driver xgene_enet_driver = { .driver = { .name = "xgene-enet", diff --git a/drivers/net/phy/mdio-xgene.c b/drivers/net/phy/mdio-xgene.c index 39be3b82608f..20fbcc9c4687 100644 --- a/drivers/net/phy/mdio-xgene.c +++ b/drivers/net/phy/mdio-xgene.c @@ -314,6 +314,30 @@ static acpi_status acpi_register_phy(acpi_handle handle, u32 lvl, } #endif +static const struct of_device_id xgene_mdio_of_match[] = { + { + .compatible = "apm,xgene-mdio-rgmii", + .data = (void *)XGENE_MDIO_RGMII + }, + { + .compatible = "apm,xgene-mdio-xfi", + .data = (void *)XGENE_MDIO_XFI + }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_mdio_of_match); + +#ifdef CONFIG_ACPI +static const struct acpi_device_id xgene_mdio_acpi_match[] = { + { "APMC0D65", XGENE_MDIO_RGMII }, + { "APMC0D66", XGENE_MDIO_XFI }, + { } +}; + +MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match); +#endif + + static int xgene_mdio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -439,32 +463,6 @@ static int xgene_mdio_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF -static const struct of_device_id xgene_mdio_of_match[] = { - { - .compatible = "apm,xgene-mdio-rgmii", - .data = (void *)XGENE_MDIO_RGMII - }, - { - .compatible = "apm,xgene-mdio-xfi", - .data = (void *)XGENE_MDIO_XFI - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, xgene_mdio_of_match); -#endif - -#ifdef CONFIG_ACPI -static const struct acpi_device_id xgene_mdio_acpi_match[] = { - { "APMC0D65", XGENE_MDIO_RGMII }, - { "APMC0D66", XGENE_MDIO_XFI }, - { } -}; - -MODULE_DEVICE_TABLE(acpi, xgene_mdio_acpi_match); -#endif - static struct platform_driver xgene_mdio_driver = { .driver = { .name = "xgene-mdio", diff --git a/drivers/net/phy/mdio-xgene.h b/drivers/net/phy/mdio-xgene.h index 354241b53c1d..594a11d42401 100644 --- a/drivers/net/phy/mdio-xgene.h +++ b/drivers/net/phy/mdio-xgene.h @@ -132,10 +132,6 @@ static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) #define GET_BIT(field, src) \ xgene_enet_get_field_value(field ## _POS, 1, src) -static const struct of_device_id xgene_mdio_of_match[]; -#ifdef CONFIG_ACPI -static const struct acpi_device_id xgene_mdio_acpi_match[]; -#endif int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg); int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data); struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr); -- GitLab From 7164cb7360fe981fc4748afec4528f5c46091c86 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 17 Apr 2017 15:59:52 -0700 Subject: [PATCH 0900/1834] nl80211: Fix enum type of variable in nl80211_put_sta_rate() commit bbf67e450a5dc2a595e1e7a67b4869f1a7f5a338 upstream. rate_flg is of type 'enum nl80211_attrs', however it is assigned with 'enum nl80211_rate_info' values. Change the type of rate_flg accordingly. Signed-off-by: Matthias Kaehlcke Signed-off-by: Johannes Berg Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/wireless/nl80211.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index a89061d59c74..36280e114959 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -4081,7 +4081,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, struct nlattr *rate; u32 bitrate; u16 bitrate_compat; - enum nl80211_attrs rate_flg; + enum nl80211_rate_info rate_flg; rate = nla_nest_start(msg, attr); if (!rate) -- GitLab From 4bb797afd7ba5d76fa6fa5a8d4fe930c2c2e029d Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 13 Apr 2017 10:05:04 -0700 Subject: [PATCH 0901/1834] cfg80211: Fix array-bounds warning in fragment copy commit aa1702dd162f420bf85ecef0c77686ef0dbc1496 upstream. __ieee80211_amsdu_copy_frag intentionally initializes a pointer to array[-1] to increment it later to valid values. clang rightfully generates an array-bounds warning on the initialization statement. Initialize the pointer to array[0] and change the algorithm from increment before to increment after consume. Signed-off-by: Matthias Kaehlcke Signed-off-by: Johannes Berg Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/wireless/util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/wireless/util.c b/net/wireless/util.c index c921c2eed15d..bb54d9db82df 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -663,7 +663,7 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, int offset, int len) { struct skb_shared_info *sh = skb_shinfo(skb); - const skb_frag_t *frag = &sh->frags[-1]; + const skb_frag_t *frag = &sh->frags[0]; struct page *frag_page; void *frag_ptr; int frag_len, frag_size; @@ -676,10 +676,10 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, while (offset >= frag_size) { offset -= frag_size; - frag++; frag_page = skb_frag_page(frag); frag_ptr = skb_frag_address(frag); frag_size = skb_frag_size(frag); + frag++; } frag_ptr += offset; @@ -691,12 +691,12 @@ __ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, len -= cur_len; while (len > 0) { - frag++; frag_len = skb_frag_size(frag); cur_len = min(len, frag_len); __frame_add_frag(frame, skb_frag_page(frag), skb_frag_address(frag), cur_len, frag_len); len -= cur_len; + frag++; } } -- GitLab From e6061c11c3b5a8f1bba97bfe3cd1af5f95cfca95 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 8 Feb 2017 13:58:43 -0500 Subject: [PATCH 0902/1834] HID: sony: Use LED_CORE_SUSPENDRESUME commit 765a1077c85e5f2efcc43582f80caf43a052e903 upstream. The LED subsystem provides the LED_CORE_SUSPENDRESUME flag to handle automatically turning off and restoring the state of device LEDs during suspend/resume. Use this flag instead of saving and restoring the state locally. Signed-off-by: Frank Praznik Signed-off-by: Jiri Kosina Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-sony.c | 45 ++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index b0bb99a821bd..1b1dccd37fbd 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1056,7 +1056,6 @@ struct sony_sc { u8 battery_charging; u8 battery_capacity; u8 led_state[MAX_LEDS]; - u8 resume_led_state[MAX_LEDS]; u8 led_delay_on[MAX_LEDS]; u8 led_delay_off[MAX_LEDS]; u8 led_count; @@ -1793,6 +1792,7 @@ static int sony_leds_init(struct sony_sc *sc) led->name = name; led->brightness = sc->led_state[n]; led->max_brightness = max_brightness[n]; + led->flags = LED_CORE_SUSPENDRESUME; led->brightness_get = sony_led_get_brightness; led->brightness_set = sony_led_set_brightness; @@ -2509,47 +2509,32 @@ static void sony_remove(struct hid_device *hdev) static int sony_suspend(struct hid_device *hdev, pm_message_t message) { - /* - * On suspend save the current LED state, - * stop running force-feedback and blank the LEDS. - */ - if (SONY_LED_SUPPORT || SONY_FF_SUPPORT) { - struct sony_sc *sc = hid_get_drvdata(hdev); - #ifdef CONFIG_SONY_FF - sc->left = sc->right = 0; -#endif - memcpy(sc->resume_led_state, sc->led_state, - sizeof(sc->resume_led_state)); - memset(sc->led_state, 0, sizeof(sc->led_state)); + /* On suspend stop any running force-feedback events */ + if (SONY_FF_SUPPORT) { + struct sony_sc *sc = hid_get_drvdata(hdev); + sc->left = sc->right = 0; sony_send_output_report(sc); } +#endif return 0; } static int sony_resume(struct hid_device *hdev) { - /* Restore the state of controller LEDs on resume */ - if (SONY_LED_SUPPORT) { - struct sony_sc *sc = hid_get_drvdata(hdev); - - memcpy(sc->led_state, sc->resume_led_state, - sizeof(sc->led_state)); - - /* - * The Sixaxis and navigation controllers on USB need to be - * reinitialized on resume or they won't behave properly. - */ - if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || - (sc->quirks & NAVIGATION_CONTROLLER_USB)) { - sixaxis_set_operational_usb(sc->hdev); - sc->defer_initialization = 1; - } + struct sony_sc *sc = hid_get_drvdata(hdev); - sony_set_leds(sc); + /* + * The Sixaxis and navigation controllers on USB need to be + * reinitialized on resume or they won't behave properly. + */ + if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { + sixaxis_set_operational_usb(sc->hdev); + sc->defer_initialization = 1; } return 0; -- GitLab From 3e8f962da78c89b96c7ed718d77e35a1caf469da Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Wed, 19 Apr 2017 11:39:20 -0700 Subject: [PATCH 0903/1834] netfilter: ctnetlink: Make some parameters integer to avoid enum mismatch commit a2b7cbdd2559aff06cebc28a7150f81c307a90d3 upstream. Not all parameters passed to ctnetlink_parse_tuple() and ctnetlink_exp_dump_tuple() match the enum type in the signatures of these functions. Since this is intended change the argument type of to be an unsigned integer value. Signed-off-by: Matthias Kaehlcke Signed-off-by: Pablo Neira Ayuso Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_netlink.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index d5caed5bcfb1..d49a4639465f 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1008,9 +1008,8 @@ static const struct nla_policy tuple_nla_policy[CTA_TUPLE_MAX+1] = { static int ctnetlink_parse_tuple(const struct nlattr * const cda[], - struct nf_conntrack_tuple *tuple, - enum ctattr_type type, u_int8_t l3num, - struct nf_conntrack_zone *zone) + struct nf_conntrack_tuple *tuple, u32 type, + u_int8_t l3num, struct nf_conntrack_zone *zone) { struct nlattr *tb[CTA_TUPLE_MAX+1]; int err; @@ -2409,7 +2408,7 @@ static struct nfnl_ct_hook ctnetlink_glue_hook = { static int ctnetlink_exp_dump_tuple(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple, - enum ctattr_expect type) + u32 type) { struct nlattr *nest_parms; -- GitLab From 2bb306460188d3200e42e1431d24d19df4159505 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 6 Apr 2017 16:31:41 -0700 Subject: [PATCH 0904/1834] mac80211: Fix clang warning about constant operand in logical operation commit 93f56de259376d7e4fff2b2d104082e1fa66e237 upstream. When clang detects a non-boolean constant in a logical operation it generates a 'constant-logical-operand' warning. In ieee80211_try_rate_control_ops_get() the result of strlen() is used in a logical operation, clang resolves the expression to an (integer) constant at compile time when clang's builtin strlen function is used. Change the condition to check for strlen() > 0 to make the constant operand boolean and thus avoid the warning. Signed-off-by: Matthias Kaehlcke Signed-off-by: Johannes Berg Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/mac80211/rate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index dbceb42c2a8e..e6096dfd0210 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -173,9 +173,11 @@ ieee80211_rate_control_ops_get(const char *name) /* try default if specific alg requested but not found */ ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); - /* try built-in one if specific alg requested but not found */ - if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT)) + /* Note: check for > 0 is intentional to avoid clang warning */ + if (!ops && (strlen(CONFIG_MAC80211_RC_DEFAULT) > 0)) + /* try built-in one if specific alg requested but not found */ ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT); + kernel_param_unlock(THIS_MODULE); return ops; -- GitLab From 471d4a48d8d19cce4afcb02072b19108cbbf2571 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 17 Apr 2017 13:59:53 -0700 Subject: [PATCH 0905/1834] mac80211: ibss: Fix channel type enum in ieee80211_sta_join_ibss() commit a4ac6f2e53e568a77a2eb3710efd99ca08634c0a upstream. cfg80211_chandef_create() expects an 'enum nl80211_channel_type' as channel type however in ieee80211_sta_join_ibss() NL80211_CHAN_WIDTH_20_NOHT is passed in two occasions, which is of the enum type 'nl80211_chan_width'. Change the value to NL80211_CHAN_NO_HT (20 MHz, non-HT channel) of the channel type enum. Signed-off-by: Matthias Kaehlcke Signed-off-by: Johannes Berg Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/mac80211/ibss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index d31818e7d10c..a5acaf1efaab 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -427,7 +427,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, case NL80211_CHAN_WIDTH_5: case NL80211_CHAN_WIDTH_10: cfg80211_chandef_create(&chandef, cbss->channel, - NL80211_CHAN_WIDTH_20_NOHT); + NL80211_CHAN_NO_HT); chandef.width = sdata->u.ibss.chandef.width; break; case NL80211_CHAN_WIDTH_80: @@ -439,7 +439,7 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, default: /* fall back to 20 MHz for unsupported modes */ cfg80211_chandef_create(&chandef, cbss->channel, - NL80211_CHAN_WIDTH_20_NOHT); + NL80211_CHAN_NO_HT); break; } -- GitLab From e7f42b03fbfb8309a2169aa7c1917b366a886506 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 27 Jul 2017 14:30:23 -0700 Subject: [PATCH 0906/1834] btrfs: Remove extra parentheses from condition in copy_items() commit 0dde10bed2c44a4024eb446cc72fe4e0cb97ec06 upstream. There is no need for the extra pair of parentheses, remove it. This fixes the following warning when building with clang: fs/btrfs/tree-log.c:3694:10: warning: equality comparison with extraneous parentheses [-Wparentheses-equality] if ((i == (nr - 1))) ~~^~~~~~~~~~~ Also remove the unnecessary parentheses around the substraction. Signed-off-by: Matthias Kaehlcke Signed-off-by: David Sterba Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/tree-log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 5539f0b95efa..52401732cddc 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -3664,7 +3664,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, src_offset = btrfs_item_ptr_offset(src, start_slot + i); - if ((i == (nr - 1))) + if (i == nr - 1) last_key = ins_keys[i]; if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { -- GitLab From a29152831bb2906f486501ff309a15a35e81a24f Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 3 Aug 2017 11:03:58 -0700 Subject: [PATCH 0907/1834] arm64: avoid overflow in VA_START and PAGE_OFFSET commit 82cd588052815eb4146f9f7c5347ca5e32c56360 upstream. The bitmask used to define these values produces overflow, as seen by this compiler warning: arch/arm64/kernel/head.S:47:8: warning: integer overflow in preprocessor expression #elif (PAGE_OFFSET & 0x1fffff) != 0 ^~~~~~~~~~~ arch/arm64/include/asm/memory.h:52:46: note: expanded from macro 'PAGE_OFFSET' #define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1)) ~~~~~~~~~~~~~~~~~~ ^ It would be preferrable to use GENMASK_ULL() instead, but it's not set up to be used from assembly (the UL() macro token pastes UL suffixes when not included in assembly sources). Suggested-by: Ard Biesheuvel Suggested-by: Yury Norov Suggested-by: Matthias Kaehlcke Signed-off-by: Nick Desaulniers Signed-off-by: Will Deacon Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/memory.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 53211a0acf0f..5e3faba689e0 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -64,8 +64,10 @@ * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. */ #define VA_BITS (CONFIG_ARM64_VA_BITS) -#define VA_START (UL(0xffffffffffffffff) << VA_BITS) -#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1)) +#define VA_START (UL(0xffffffffffffffff) - \ + (UL(1) << VA_BITS) + 1) +#define PAGE_OFFSET (UL(0xffffffffffffffff) - \ + (UL(1) << (VA_BITS - 1)) + 1) #define KIMAGE_VADDR (MODULES_END) #define MODULES_END (MODULES_VADDR + MODULES_VSIZE) #define MODULES_VADDR (VA_START + KASAN_SHADOW_SIZE) -- GitLab From 1978d829a63177b1cc679da74b5dbddef3264636 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Fri, 19 May 2017 10:09:32 -0700 Subject: [PATCH 0908/1834] selinux: Remove redundant check for unknown labeling behavior commit 270e8573145a26de924e2dc644596332d400445b upstream. The check is already performed in ocontext_read() when the policy is loaded. Removing the array also fixes the following warning when building with clang: security/selinux/hooks.c:338:20: error: variable 'labeling_behaviors' is not needed and will not be emitted [-Werror,-Wunneeded-internal-declaration] Signed-off-by: Matthias Kaehlcke Acked-by: Stephen Smalley Signed-off-by: Paul Moore Cc: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- security/selinux/hooks.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index b8278f3af9da..17627d8d5a26 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -406,18 +406,6 @@ static void superblock_free_security(struct super_block *sb) kfree(sbsec); } -/* The file system's label must be initialized prior to use. */ - -static const char *labeling_behaviors[7] = { - "uses xattr", - "uses transition SIDs", - "uses task SIDs", - "uses genfs_contexts", - "not configured for labeling", - "uses mountpoint labeling", - "uses native labeling", -}; - static inline int inode_doinit(struct inode *inode) { return inode_doinit_with_dentry(inode, NULL); @@ -528,10 +516,6 @@ static int sb_finish_set_opts(struct super_block *sb) } } - if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) - printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", - sb->s_id, sb->s_type->name); - sbsec->flags |= SE_SBINITIALIZED; if (selinux_is_sblabel_mnt(sb)) sbsec->flags |= SBLABEL_MNT; -- GitLab From c2a3e4f77de1c99f26d3454530da8f9066a03c03 Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Thu, 6 Jul 2017 15:36:50 -0700 Subject: [PATCH 0909/1834] mm/vmscan.c: fix unsequenced modification and access warning commit f2f43e566a02a3bdde0a65e6a2e88d707c212a29 upstream. Clang and its -Wunsequenced emits a warning mm/vmscan.c:2961:25: error: unsequenced modification and access to 'gfp_mask' [-Wunsequenced] .gfp_mask = (gfp_mask = current_gfp_context(gfp_mask)), ^ While it is not clear to me whether the initialization code violates the specification (6.7.8 par 19 (ISO/IEC 9899) looks like it disagrees) the code is quite confusing and worth cleaning up anyway. Fix this by reusing sc.gfp_mask rather than the updated input gfp_mask parameter. Link: http://lkml.kernel.org/r/20170510154030.10720-1-nick.desaulniers@gmail.com Signed-off-by: Nick Desaulniers Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [natechancellor: Adjust context due to abscence of 7dea19f9ee63] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- mm/vmscan.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index cdd5c3b5c357..557ad1367595 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -2966,7 +2966,7 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order, unsigned long nr_reclaimed; struct scan_control sc = { .nr_to_reclaim = SWAP_CLUSTER_MAX, - .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)), + .gfp_mask = memalloc_noio_flags(gfp_mask), .reclaim_idx = gfp_zone(gfp_mask), .order = order, .nodemask = nodemask, @@ -2981,12 +2981,12 @@ unsigned long try_to_free_pages(struct zonelist *zonelist, int order, * 1 is returned so that the page allocator does not OOM kill at this * point. */ - if (throttle_direct_reclaim(gfp_mask, zonelist, nodemask)) + if (throttle_direct_reclaim(sc.gfp_mask, zonelist, nodemask)) return 1; trace_mm_vmscan_direct_reclaim_begin(order, sc.may_writepage, - gfp_mask, + sc.gfp_mask, sc.reclaim_idx); nr_reclaimed = do_try_to_free_pages(zonelist, &sc); @@ -3749,16 +3749,15 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in const unsigned long nr_pages = 1 << order; struct task_struct *p = current; struct reclaim_state reclaim_state; - int classzone_idx = gfp_zone(gfp_mask); struct scan_control sc = { .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX), - .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)), + .gfp_mask = memalloc_noio_flags(gfp_mask), .order = order, .priority = NODE_RECLAIM_PRIORITY, .may_writepage = !!(node_reclaim_mode & RECLAIM_WRITE), .may_unmap = !!(node_reclaim_mode & RECLAIM_UNMAP), .may_swap = 1, - .reclaim_idx = classzone_idx, + .reclaim_idx = gfp_zone(gfp_mask), }; cond_resched(); @@ -3768,7 +3767,7 @@ static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned in * and RECLAIM_UNMAP. */ p->flags |= PF_MEMALLOC | PF_SWAPWRITE; - lockdep_set_current_reclaim_state(gfp_mask); + lockdep_set_current_reclaim_state(sc.gfp_mask); reclaim_state.reclaimed_slab = 0; p->reclaim_state = &reclaim_state; -- GitLab From 0355a9f6d8bad8dfbe36f9081e9767263a206d78 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 12 Feb 2018 14:42:01 +0100 Subject: [PATCH 0910/1834] xfrm_user: uncoditionally validate esn replay attribute struct commit d97ca5d714a5334aecadadf696875da40f1fbf3e upstream. The sanity test added in ecd7918745234 can be bypassed, validation only occurs if XFRM_STATE_ESN flag is set, but rest of code doesn't care and just checks if the attribute itself is present. So always validate. Alternative is to reject if we have the attribute without the flag but that would change abi. Reported-by: syzbot+0ab777c27d2bb7588f73@syzkaller.appspotmail.com Cc: Mathias Krause Fixes: ecd7918745234 ("xfrm_user: ensure user supplied esn replay window is valid") Fixes: d8647b79c3b7e ("xfrm: Add user interface for esn and big anti-replay windows") Signed-off-by: Florian Westphal Signed-off-by: Steffen Klassert Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_user.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5d33967d9aa1..6a029358bfd1 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -121,22 +121,17 @@ static inline int verify_replay(struct xfrm_usersa_info *p, struct nlattr *rt = attrs[XFRMA_REPLAY_ESN_VAL]; struct xfrm_replay_state_esn *rs; - if (p->flags & XFRM_STATE_ESN) { - if (!rt) - return -EINVAL; + if (!rt) + return (p->flags & XFRM_STATE_ESN) ? -EINVAL : 0; - rs = nla_data(rt); + rs = nla_data(rt); - if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) - return -EINVAL; - - if (nla_len(rt) < xfrm_replay_state_esn_len(rs) && - nla_len(rt) != sizeof(*rs)) - return -EINVAL; - } + if (rs->bmp_len > XFRMA_REPLAY_ESN_MAX / sizeof(rs->bmp[0]) / 8) + return -EINVAL; - if (!rt) - return 0; + if (nla_len(rt) < xfrm_replay_state_esn_len(rs) && + nla_len(rt) != sizeof(*rs)) + return -EINVAL; /* As only ESP and AH support ESN feature. */ if ((p->id.proto != IPPROTO_ESP) && (p->id.proto != IPPROTO_AH)) -- GitLab From 510d52da02ae6c8ebaa8c760bde50f141906ac87 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 15 Mar 2018 15:33:02 +0200 Subject: [PATCH 0911/1834] RDMA/ucma: Check AF family prior resolving address commit 2975d5de6428ff6d9317e9948f0968f7d42e5d74 upstream. Garbage supplied by user will cause to UCMA module provide zero memory size for memcpy(), because it wasn't checked, it will produce unpredictable results in rdma_resolve_addr(). [ 42.873814] BUG: KASAN: null-ptr-deref in rdma_resolve_addr+0xc8/0xfb0 [ 42.874816] Write of size 28 at addr 00000000000000a0 by task resaddr/1044 [ 42.876765] [ 42.876960] CPU: 1 PID: 1044 Comm: resaddr Not tainted 4.16.0-rc1-00057-gaa56a5293d7e #34 [ 42.877840] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 42.879691] Call Trace: [ 42.880236] dump_stack+0x5c/0x77 [ 42.880664] kasan_report+0x163/0x380 [ 42.881354] ? rdma_resolve_addr+0xc8/0xfb0 [ 42.881864] memcpy+0x34/0x50 [ 42.882692] rdma_resolve_addr+0xc8/0xfb0 [ 42.883366] ? deref_stack_reg+0x88/0xd0 [ 42.883856] ? vsnprintf+0x31a/0x770 [ 42.884686] ? rdma_bind_addr+0xc40/0xc40 [ 42.885327] ? num_to_str+0x130/0x130 [ 42.885773] ? deref_stack_reg+0x88/0xd0 [ 42.886217] ? __read_once_size_nocheck.constprop.6+0x10/0x10 [ 42.887698] ? unwind_get_return_address_ptr+0x50/0x50 [ 42.888302] ? replace_slot+0x147/0x170 [ 42.889176] ? delete_node+0x12c/0x340 [ 42.890223] ? __radix_tree_lookup+0xa9/0x160 [ 42.891196] ? ucma_resolve_ip+0xb7/0x110 [ 42.891917] ucma_resolve_ip+0xb7/0x110 [ 42.893003] ? ucma_resolve_addr+0x190/0x190 [ 42.893531] ? _copy_from_user+0x5e/0x90 [ 42.894204] ucma_write+0x174/0x1f0 [ 42.895162] ? ucma_resolve_route+0xf0/0xf0 [ 42.896309] ? dequeue_task_fair+0x67e/0xd90 [ 42.897192] ? put_prev_entity+0x7d/0x170 [ 42.897870] ? ring_buffer_record_is_on+0xd/0x20 [ 42.898439] ? tracing_record_taskinfo_skip+0x20/0x50 [ 42.899686] __vfs_write+0xc4/0x350 [ 42.900142] ? kernel_read+0xa0/0xa0 [ 42.900602] ? firmware_map_remove+0xdf/0xdf [ 42.901135] ? do_task_dead+0x5d/0x60 [ 42.901598] ? do_exit+0xcc6/0x1220 [ 42.902789] ? __fget+0xa8/0xf0 [ 42.903190] vfs_write+0xf7/0x280 [ 42.903600] SyS_write+0xa1/0x120 [ 42.904206] ? SyS_read+0x120/0x120 [ 42.905710] ? compat_start_thread+0x60/0x60 [ 42.906423] ? SyS_read+0x120/0x120 [ 42.908716] do_syscall_64+0xeb/0x250 [ 42.910760] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 42.912735] RIP: 0033:0x7f138b0afe99 [ 42.914734] RSP: 002b:00007f138b799e98 EFLAGS: 00000287 ORIG_RAX: 0000000000000001 [ 42.917134] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f138b0afe99 [ 42.919487] RDX: 000000000000002e RSI: 0000000020000c40 RDI: 0000000000000004 [ 42.922393] RBP: 00007f138b799ec0 R08: 00007f138b79a700 R09: 0000000000000000 [ 42.925266] R10: 00007f138b79a700 R11: 0000000000000287 R12: 00007f138b799fc0 [ 42.927570] R13: 0000000000000000 R14: 00007ffdbae757c0 R15: 00007f138b79a9c0 [ 42.930047] [ 42.932681] Disabling lock debugging due to kernel taint [ 42.934795] BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 [ 42.936939] IP: memcpy_erms+0x6/0x10 [ 42.938864] PGD 80000001bea92067 P4D 80000001bea92067 PUD 1bea96067 PMD 0 [ 42.941576] Oops: 0002 [#1] SMP KASAN PTI [ 42.943952] CPU: 1 PID: 1044 Comm: resaddr Tainted: G B 4.16.0-rc1-00057-gaa56a5293d7e #34 [ 42.946964] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 42.952336] RIP: 0010:memcpy_erms+0x6/0x10 [ 42.954707] RSP: 0018:ffff8801c8b479c8 EFLAGS: 00010286 [ 42.957227] RAX: 00000000000000a0 RBX: ffff8801c8b47ba0 RCX: 000000000000001c [ 42.960543] RDX: 000000000000001c RSI: ffff8801c8b47bbc RDI: 00000000000000a0 [ 42.963867] RBP: ffff8801c8b47b60 R08: 0000000000000000 R09: ffffed0039168ed1 [ 42.967303] R10: 0000000000000001 R11: ffffed0039168ed0 R12: ffff8801c8b47bbc [ 42.970685] R13: 00000000000000a0 R14: 1ffff10039168f4a R15: 0000000000000000 [ 42.973631] FS: 00007f138b79a700(0000) GS:ffff8801e5d00000(0000) knlGS:0000000000000000 [ 42.976831] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 42.979239] CR2: 00000000000000a0 CR3: 00000001be908002 CR4: 00000000003606a0 [ 42.982060] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 42.984877] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 42.988033] Call Trace: [ 42.990487] rdma_resolve_addr+0xc8/0xfb0 [ 42.993202] ? deref_stack_reg+0x88/0xd0 [ 42.996055] ? vsnprintf+0x31a/0x770 [ 42.998707] ? rdma_bind_addr+0xc40/0xc40 [ 43.000985] ? num_to_str+0x130/0x130 [ 43.003410] ? deref_stack_reg+0x88/0xd0 [ 43.006302] ? __read_once_size_nocheck.constprop.6+0x10/0x10 [ 43.008780] ? unwind_get_return_address_ptr+0x50/0x50 [ 43.011178] ? replace_slot+0x147/0x170 [ 43.013517] ? delete_node+0x12c/0x340 [ 43.016019] ? __radix_tree_lookup+0xa9/0x160 [ 43.018755] ? ucma_resolve_ip+0xb7/0x110 [ 43.021270] ucma_resolve_ip+0xb7/0x110 [ 43.023968] ? ucma_resolve_addr+0x190/0x190 [ 43.026312] ? _copy_from_user+0x5e/0x90 [ 43.029384] ucma_write+0x174/0x1f0 [ 43.031861] ? ucma_resolve_route+0xf0/0xf0 [ 43.034782] ? dequeue_task_fair+0x67e/0xd90 [ 43.037483] ? put_prev_entity+0x7d/0x170 [ 43.040215] ? ring_buffer_record_is_on+0xd/0x20 [ 43.042990] ? tracing_record_taskinfo_skip+0x20/0x50 [ 43.045595] __vfs_write+0xc4/0x350 [ 43.048624] ? kernel_read+0xa0/0xa0 [ 43.051604] ? firmware_map_remove+0xdf/0xdf [ 43.055379] ? do_task_dead+0x5d/0x60 [ 43.058000] ? do_exit+0xcc6/0x1220 [ 43.060783] ? __fget+0xa8/0xf0 [ 43.063133] vfs_write+0xf7/0x280 [ 43.065677] SyS_write+0xa1/0x120 [ 43.068647] ? SyS_read+0x120/0x120 [ 43.071179] ? compat_start_thread+0x60/0x60 [ 43.074025] ? SyS_read+0x120/0x120 [ 43.076705] do_syscall_64+0xeb/0x250 [ 43.079006] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 43.081606] RIP: 0033:0x7f138b0afe99 [ 43.083679] RSP: 002b:00007f138b799e98 EFLAGS: 00000287 ORIG_RAX: 0000000000000001 [ 43.086802] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f138b0afe99 [ 43.089989] RDX: 000000000000002e RSI: 0000000020000c40 RDI: 0000000000000004 [ 43.092866] RBP: 00007f138b799ec0 R08: 00007f138b79a700 R09: 0000000000000000 [ 43.096233] R10: 00007f138b79a700 R11: 0000000000000287 R12: 00007f138b799fc0 [ 43.098913] R13: 0000000000000000 R14: 00007ffdbae757c0 R15: 00007f138b79a9c0 [ 43.101809] Code: 90 90 90 90 90 eb 1e 0f 1f 00 48 89 f8 48 89 d1 48 c1 e9 03 83 e2 07 f3 48 a5 89 d1 f3 a4 c3 66 0f 1f 44 00 00 48 89 f8 48 89 d1 a4 c3 0f 1f 80 00 00 00 00 48 89 f8 48 83 fa 20 72 7e 40 38 [ 43.107950] RIP: memcpy_erms+0x6/0x10 RSP: ffff8801c8b479c8 Reported-by: Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Signed-off-by: Leon Romanovsky Reviewed-by: Sean Hefty Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 017a09ceba3f..6b8bb3af9b40 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -662,19 +662,23 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_ip cmd; + struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; + src = (struct sockaddr *) &cmd.src_addr; + dst = (struct sockaddr *) &cmd.dst_addr; + if (!rdma_addr_size(src) || !rdma_addr_size(dst)) + return -EINVAL; + ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, - (struct sockaddr *) &cmd.dst_addr, - cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } -- GitLab From a7d0333a87b3a9b68c9d4351fbd9e0f76f6ac913 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 19 Mar 2018 14:20:15 +0200 Subject: [PATCH 0912/1834] RDMA/ucma: Fix use-after-free access in ucma_close commit ed65a4dc22083e73bac599ded6a262318cad7baf upstream. The error in ucma_create_id() left ctx in the list of contexts belong to ucma file descriptor. The attempt to close this file descriptor causes to use-after-free accesses while iterating over such list. Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Reported-by: Signed-off-by: Leon Romanovsky Reviewed-by: Sean Hefty Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 6b8bb3af9b40..4a42a95be601 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -495,6 +495,9 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, mutex_lock(&mut); idr_remove(&ctx_idr, ctx->id); mutex_unlock(&mut); + mutex_lock(&file->mut); + list_del(&ctx->list); + mutex_unlock(&file->mut); kfree(ctx); return ret; } -- GitLab From a6cd10d9940282804d45a139bc14ccf93bd34769 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Tue, 20 Mar 2018 17:05:13 +0200 Subject: [PATCH 0913/1834] RDMA/ucma: Ensure that CM_ID exists prior to access it commit e8980d67d6017c8eee8f9c35f782c4bd68e004c9 upstream. Prior to access UCMA commands, the context should be initialized and connected to CM_ID with ucma_create_id(). In case user skips this step, he can provide non-valid ctx without CM_ID and cause to multiple NULL dereferences. Also there are situations where the create_id can be raced with other user access, ensure that the context is only shared to other threads once it is fully initialized to avoid the races. [ 109.088108] BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 [ 109.090315] IP: ucma_connect+0x138/0x1d0 [ 109.092595] PGD 80000001dc02d067 P4D 80000001dc02d067 PUD 1da9ef067 PMD 0 [ 109.095384] Oops: 0000 [#1] SMP KASAN PTI [ 109.097834] CPU: 0 PID: 663 Comm: uclose Tainted: G B 4.16.0-rc1-00062-g2975d5de6428 #45 [ 109.100816] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 109.105943] RIP: 0010:ucma_connect+0x138/0x1d0 [ 109.108850] RSP: 0018:ffff8801c8567a80 EFLAGS: 00010246 [ 109.111484] RAX: 0000000000000000 RBX: 1ffff100390acf50 RCX: ffffffff9d7812e2 [ 109.114496] RDX: 1ffffffff3f507a5 RSI: 0000000000000297 RDI: 0000000000000297 [ 109.117490] RBP: ffff8801daa15600 R08: 0000000000000000 R09: ffffed00390aceeb [ 109.120429] R10: 0000000000000001 R11: ffffed00390aceea R12: 0000000000000000 [ 109.123318] R13: 0000000000000120 R14: ffff8801de6459c0 R15: 0000000000000118 [ 109.126221] FS: 00007fabb68d6700(0000) GS:ffff8801e5c00000(0000) knlGS:0000000000000000 [ 109.129468] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 109.132523] CR2: 0000000000000020 CR3: 00000001d45d8003 CR4: 00000000003606b0 [ 109.135573] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 109.138716] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 109.142057] Call Trace: [ 109.144160] ? ucma_listen+0x110/0x110 [ 109.146386] ? wake_up_q+0x59/0x90 [ 109.148853] ? futex_wake+0x10b/0x2a0 [ 109.151297] ? save_stack+0x89/0xb0 [ 109.153489] ? _copy_from_user+0x5e/0x90 [ 109.155500] ucma_write+0x174/0x1f0 [ 109.157933] ? ucma_resolve_route+0xf0/0xf0 [ 109.160389] ? __mod_node_page_state+0x1d/0x80 [ 109.162706] __vfs_write+0xc4/0x350 [ 109.164911] ? kernel_read+0xa0/0xa0 [ 109.167121] ? path_openat+0x1b10/0x1b10 [ 109.169355] ? fsnotify+0x899/0x8f0 [ 109.171567] ? fsnotify_unmount_inodes+0x170/0x170 [ 109.174145] ? __fget+0xa8/0xf0 [ 109.177110] vfs_write+0xf7/0x280 [ 109.179532] SyS_write+0xa1/0x120 [ 109.181885] ? SyS_read+0x120/0x120 [ 109.184482] ? compat_start_thread+0x60/0x60 [ 109.187124] ? SyS_read+0x120/0x120 [ 109.189548] do_syscall_64+0xeb/0x250 [ 109.192178] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 109.194725] RIP: 0033:0x7fabb61ebe99 [ 109.197040] RSP: 002b:00007fabb68d5e98 EFLAGS: 00000202 ORIG_RAX: 0000000000000001 [ 109.200294] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fabb61ebe99 [ 109.203399] RDX: 0000000000000120 RSI: 00000000200001c0 RDI: 0000000000000004 [ 109.206548] RBP: 00007fabb68d5ec0 R08: 0000000000000000 R09: 0000000000000000 [ 109.209902] R10: 0000000000000000 R11: 0000000000000202 R12: 00007fabb68d5fc0 [ 109.213327] R13: 0000000000000000 R14: 00007fff40ab2430 R15: 00007fabb68d69c0 [ 109.216613] Code: 88 44 24 2c 0f b6 84 24 6e 01 00 00 88 44 24 2d 0f b6 84 24 69 01 00 00 88 44 24 2e 8b 44 24 60 89 44 24 30 e8 da f6 06 ff 31 c0 <66> 41 83 7c 24 20 1b 75 04 8b 44 24 64 48 8d 74 24 20 4c 89 e7 [ 109.223602] RIP: ucma_connect+0x138/0x1d0 RSP: ffff8801c8567a80 [ 109.226256] CR2: 0000000000000020 Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Reported-by: Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 4a42a95be601..0ef2f6a3b8df 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -132,7 +132,7 @@ static inline struct ucma_context *_ucma_find_context(int id, ctx = idr_find(&ctx_idr, id); if (!ctx) ctx = ERR_PTR(-ENOENT); - else if (ctx->file != file) + else if (ctx->file != file || !ctx->cm_id) ctx = ERR_PTR(-EINVAL); return ctx; } @@ -454,6 +454,7 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, struct rdma_ucm_create_id cmd; struct rdma_ucm_create_id_resp resp; struct ucma_context *ctx; + struct rdma_cm_id *cm_id; enum ib_qp_type qp_type; int ret; @@ -474,10 +475,10 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, return -ENOMEM; ctx->uid = cmd.uid; - ctx->cm_id = rdma_create_id(current->nsproxy->net_ns, - ucma_event_handler, ctx, cmd.ps, qp_type); - if (IS_ERR(ctx->cm_id)) { - ret = PTR_ERR(ctx->cm_id); + cm_id = rdma_create_id(current->nsproxy->net_ns, + ucma_event_handler, ctx, cmd.ps, qp_type); + if (IS_ERR(cm_id)) { + ret = PTR_ERR(cm_id); goto err1; } @@ -487,10 +488,12 @@ static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, ret = -EFAULT; goto err2; } + + ctx->cm_id = cm_id; return 0; err2: - rdma_destroy_id(ctx->cm_id); + rdma_destroy_id(cm_id); err1: mutex_lock(&mut); idr_remove(&ctx_idr, ctx->id); -- GitLab From 269f3734f20cf1ffe97f54db5e822a381b6994b7 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 25 Mar 2018 11:23:55 +0300 Subject: [PATCH 0914/1834] RDMA/ucma: Check that device is connected prior to access it commit 4b658d1bbc16605330694bb3ef2570c465ef383d upstream. Add missing check that device is connected prior to access it. [ 55.358652] BUG: KASAN: null-ptr-deref in rdma_init_qp_attr+0x4a/0x2c0 [ 55.359389] Read of size 8 at addr 00000000000000b0 by task qp/618 [ 55.360255] [ 55.360432] CPU: 1 PID: 618 Comm: qp Not tainted 4.16.0-rc1-00071-gcaf61b1b8b88 #91 [ 55.361693] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.0-0-g63451fca13-prebuilt.qemu-project.org 04/01/2014 [ 55.363264] Call Trace: [ 55.363833] dump_stack+0x5c/0x77 [ 55.364215] kasan_report+0x163/0x380 [ 55.364610] ? rdma_init_qp_attr+0x4a/0x2c0 [ 55.365238] rdma_init_qp_attr+0x4a/0x2c0 [ 55.366410] ucma_init_qp_attr+0x111/0x200 [ 55.366846] ? ucma_notify+0xf0/0xf0 [ 55.367405] ? _get_random_bytes+0xea/0x1b0 [ 55.367846] ? urandom_read+0x2f0/0x2f0 [ 55.368436] ? kmem_cache_alloc_trace+0xd2/0x1e0 [ 55.369104] ? refcount_inc_not_zero+0x9/0x60 [ 55.369583] ? refcount_inc+0x5/0x30 [ 55.370155] ? rdma_create_id+0x215/0x240 [ 55.370937] ? _copy_to_user+0x4f/0x60 [ 55.371620] ? mem_cgroup_commit_charge+0x1f5/0x290 [ 55.372127] ? _copy_from_user+0x5e/0x90 [ 55.372720] ucma_write+0x174/0x1f0 [ 55.373090] ? ucma_close_id+0x40/0x40 [ 55.373805] ? __lru_cache_add+0xa8/0xd0 [ 55.374403] __vfs_write+0xc4/0x350 [ 55.374774] ? kernel_read+0xa0/0xa0 [ 55.375173] ? fsnotify+0x899/0x8f0 [ 55.375544] ? fsnotify_unmount_inodes+0x170/0x170 [ 55.376689] ? __fsnotify_update_child_dentry_flags+0x30/0x30 [ 55.377522] ? handle_mm_fault+0x174/0x320 [ 55.378169] vfs_write+0xf7/0x280 [ 55.378864] SyS_write+0xa1/0x120 [ 55.379270] ? SyS_read+0x120/0x120 [ 55.379643] ? mm_fault_error+0x180/0x180 [ 55.380071] ? task_work_run+0x7d/0xd0 [ 55.380910] ? __task_pid_nr_ns+0x120/0x140 [ 55.381366] ? SyS_read+0x120/0x120 [ 55.381739] do_syscall_64+0xeb/0x250 [ 55.382143] entry_SYSCALL_64_after_hwframe+0x21/0x86 [ 55.382841] RIP: 0033:0x7fc2ef803e99 [ 55.383227] RSP: 002b:00007fffcc5f3be8 EFLAGS: 00000217 ORIG_RAX: 0000000000000001 [ 55.384173] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fc2ef803e99 [ 55.386145] RDX: 0000000000000057 RSI: 0000000020000080 RDI: 0000000000000003 [ 55.388418] RBP: 00007fffcc5f3c00 R08: 0000000000000000 R09: 0000000000000000 [ 55.390542] R10: 0000000000000000 R11: 0000000000000217 R12: 0000000000400480 [ 55.392916] R13: 00007fffcc5f3cf0 R14: 0000000000000000 R15: 0000000000000000 [ 55.521088] Code: e5 4d 1e ff 48 89 df 44 0f b6 b3 b8 01 00 00 e8 65 50 1e ff 4c 8b 2b 49 8d bd b0 00 00 00 e8 56 50 1e ff 41 0f b6 c6 48 c1 e0 04 <49> 03 85 b0 00 00 00 48 8d 78 08 48 89 04 24 e8 3a 4f 1e ff 48 [ 55.525980] RIP: rdma_init_qp_attr+0x52/0x2c0 RSP: ffff8801e2c2f9d8 [ 55.532648] CR2: 00000000000000b0 [ 55.534396] ---[ end trace 70cee64090251c0b ]--- Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Fixes: d541e45500bd ("IB/core: Convert ah_attr from OPA to IB when copying to user") Reported-by: Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 0ef2f6a3b8df..dd0c5037c9cf 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1156,6 +1156,11 @@ static ssize_t ucma_init_qp_attr(struct ucma_file *file, if (IS_ERR(ctx)) return PTR_ERR(ctx); + if (!ctx->cm_id->device) { + ret = -EINVAL; + goto out; + } + resp.qp_attr_mask = 0; memset(&qp_attr, 0, sizeof qp_attr); qp_attr.qp_state = cmd.qp_state; -- GitLab From 5eaa1b1e089708c1afab79bca3950fe93e7c3b35 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Sun, 25 Mar 2018 11:39:05 +0300 Subject: [PATCH 0915/1834] RDMA/ucma: Check that device exists prior to accessing it commit c8d3bcbfc5eab3f01cf373d039af725f3b488813 upstream. Ensure that device exists prior to accessing its properties. Reported-by: Fixes: 75216638572f ("RDMA/cma: Export rdma cm interface to userspace") Signed-off-by: Leon Romanovsky Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index dd0c5037c9cf..307d6f577900 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1317,7 +1317,7 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, { struct rdma_ucm_notify cmd; struct ucma_context *ctx; - int ret; + int ret = -EINVAL; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; @@ -1326,7 +1326,9 @@ static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event); + if (ctx->cm_id->device) + ret = rdma_notify(ctx->cm_id, (enum ib_event_type)cmd.event); + ucma_put_ctx(ctx); return ret; } -- GitLab From d0253af4a15b81f7f9d033917c3fd64b65df0154 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Wed, 28 Mar 2018 11:27:22 -0700 Subject: [PATCH 0916/1834] RDMA/ucma: Introduce safer rdma_addr_size() variants commit 84652aefb347297aa08e91e283adf7b18f77c2d5 upstream. There are several places in the ucma ABI where userspace can pass in a sockaddr but set the address family to AF_IB. When that happens, rdma_addr_size() will return a size bigger than sizeof struct sockaddr_in6, and the ucma kernel code might end up copying past the end of a buffer not sized for a struct sockaddr_ib. Fix this by introducing new variants int rdma_addr_size_in6(struct sockaddr_in6 *addr); int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); that are type-safe for the types used in the ucma ABI and return 0 if the size computed is bigger than the size of the type passed in. We can use these new variants to check what size userspace has passed in before copying any addresses. Reported-by: Signed-off-by: Roland Dreier Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/addr.c | 16 ++++++++++++++++ drivers/infiniband/core/ucma.c | 34 +++++++++++++++++----------------- include/rdma/ib_addr.h | 2 ++ 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index fb4ce0394ac7..978b8d94f9a4 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -209,6 +209,22 @@ int rdma_addr_size(struct sockaddr *addr) } EXPORT_SYMBOL(rdma_addr_size); +int rdma_addr_size_in6(struct sockaddr_in6 *addr) +{ + int ret = rdma_addr_size((struct sockaddr *) addr); + + return ret <= sizeof(*addr) ? ret : 0; +} +EXPORT_SYMBOL(rdma_addr_size_in6); + +int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr) +{ + int ret = rdma_addr_size((struct sockaddr *) addr); + + return ret <= sizeof(*addr) ? ret : 0; +} +EXPORT_SYMBOL(rdma_addr_size_kss); + static struct rdma_addr_client self; void rdma_addr_register_client(struct rdma_addr_client *client) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 307d6f577900..4d732810f6fc 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -630,6 +630,9 @@ static ssize_t ucma_bind_ip(struct ucma_file *file, const char __user *inbuf, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; + if (!rdma_addr_size_in6(&cmd.addr)) + return -EINVAL; + ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); @@ -643,22 +646,21 @@ static ssize_t ucma_bind(struct ucma_file *file, const char __user *inbuf, int in_len, int out_len) { struct rdma_ucm_bind cmd; - struct sockaddr *addr; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - addr = (struct sockaddr *) &cmd.addr; - if (cmd.reserved || !cmd.addr_size || (cmd.addr_size != rdma_addr_size(addr))) + if (cmd.reserved || !cmd.addr_size || + cmd.addr_size != rdma_addr_size_kss(&cmd.addr)) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_bind_addr(ctx->cm_id, addr); + ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr); ucma_put_ctx(ctx); return ret; } @@ -668,23 +670,22 @@ static ssize_t ucma_resolve_ip(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_ip cmd; - struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - src = (struct sockaddr *) &cmd.src_addr; - dst = (struct sockaddr *) &cmd.dst_addr; - if (!rdma_addr_size(src) || !rdma_addr_size(dst)) + if (!rdma_addr_size_in6(&cmd.src_addr) || + !rdma_addr_size_in6(&cmd.dst_addr)) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, + (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } @@ -694,24 +695,23 @@ static ssize_t ucma_resolve_addr(struct ucma_file *file, int in_len, int out_len) { struct rdma_ucm_resolve_addr cmd; - struct sockaddr *src, *dst; struct ucma_context *ctx; int ret; if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - src = (struct sockaddr *) &cmd.src_addr; - dst = (struct sockaddr *) &cmd.dst_addr; - if (cmd.reserved || (cmd.src_size && (cmd.src_size != rdma_addr_size(src))) || - !cmd.dst_size || (cmd.dst_size != rdma_addr_size(dst))) + if (cmd.reserved || + (cmd.src_size && (cmd.src_size != rdma_addr_size_kss(&cmd.src_addr))) || + !cmd.dst_size || (cmd.dst_size != rdma_addr_size_kss(&cmd.dst_addr))) return -EINVAL; ctx = ucma_get_ctx(file, cmd.id); if (IS_ERR(ctx)) return PTR_ERR(ctx); - ret = rdma_resolve_addr(ctx->cm_id, src, dst, cmd.timeout_ms); + ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, + (struct sockaddr *) &cmd.dst_addr, cmd.timeout_ms); ucma_put_ctx(ctx); return ret; } @@ -1414,7 +1414,7 @@ static ssize_t ucma_join_ip_multicast(struct ucma_file *file, join_cmd.response = cmd.response; join_cmd.uid = cmd.uid; join_cmd.id = cmd.id; - join_cmd.addr_size = rdma_addr_size((struct sockaddr *) &cmd.addr); + join_cmd.addr_size = rdma_addr_size_in6(&cmd.addr); if (!join_cmd.addr_size) return -EINVAL; @@ -1433,7 +1433,7 @@ static ssize_t ucma_join_multicast(struct ucma_file *file, if (copy_from_user(&cmd, inbuf, sizeof(cmd))) return -EFAULT; - if (!rdma_addr_size((struct sockaddr *)&cmd.addr)) + if (!rdma_addr_size_kss(&cmd.addr)) return -EINVAL; return ucma_process_join(file, &cmd, out_len); diff --git a/include/rdma/ib_addr.h b/include/rdma/ib_addr.h index 818a38f99221..f888263fd757 100644 --- a/include/rdma/ib_addr.h +++ b/include/rdma/ib_addr.h @@ -129,6 +129,8 @@ int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev, const unsigned char *dst_dev_addr); int rdma_addr_size(struct sockaddr *addr); +int rdma_addr_size_in6(struct sockaddr_in6 *addr); +int rdma_addr_size_kss(struct __kernel_sockaddr_storage *addr); int rdma_addr_find_smac_by_sgid(union ib_gid *sgid, u8 *smac, u16 *vlan_id); int rdma_addr_find_l2_eth_by_grh(const union ib_gid *sgid, -- GitLab From 30df7fb50d323c05ae7913c404753047335cf0fa Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Wed, 7 Mar 2018 14:42:53 -0800 Subject: [PATCH 0917/1834] net: xfrm: use preempt-safe this_cpu_read() in ipcomp_alloc_tfms() commit 0dcd7876029b58770f769cbb7b484e88e4a305e5 upstream. f7c83bcbfaf5 ("net: xfrm: use __this_cpu_read per-cpu helper") added a __this_cpu_read() call inside ipcomp_alloc_tfms(). At the time, __this_cpu_read() required the caller to either not care about races or to handle preemption/interrupt issues. 3.15 tightened the rules around some per-cpu operations, and now __this_cpu_read() should never be used in a preemptible context. On 3.15 and later, we need to use this_cpu_read() instead. syzkaller reported this leading to the following kernel BUG while fuzzing sendmsg: BUG: using __this_cpu_read() in preemptible [00000000] code: repro/3101 caller is ipcomp_init_state+0x185/0x990 CPU: 3 PID: 3101 Comm: repro Not tainted 4.16.0-rc4-00123-g86f84779d8e9 #154 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 Call Trace: dump_stack+0xb9/0x115 check_preemption_disabled+0x1cb/0x1f0 ipcomp_init_state+0x185/0x990 ? __xfrm_init_state+0x876/0xc20 ? lock_downgrade+0x5e0/0x5e0 ipcomp4_init_state+0xaa/0x7c0 __xfrm_init_state+0x3eb/0xc20 xfrm_init_state+0x19/0x60 pfkey_add+0x20df/0x36f0 ? pfkey_broadcast+0x3dd/0x600 ? pfkey_sock_destruct+0x340/0x340 ? pfkey_seq_stop+0x80/0x80 ? __skb_clone+0x236/0x750 ? kmem_cache_alloc+0x1f6/0x260 ? pfkey_sock_destruct+0x340/0x340 ? pfkey_process+0x62a/0x6f0 pfkey_process+0x62a/0x6f0 ? pfkey_send_new_mapping+0x11c0/0x11c0 ? mutex_lock_io_nested+0x1390/0x1390 pfkey_sendmsg+0x383/0x750 ? dump_sp+0x430/0x430 sock_sendmsg+0xc0/0x100 ___sys_sendmsg+0x6c8/0x8b0 ? copy_msghdr_from_user+0x3b0/0x3b0 ? pagevec_lru_move_fn+0x144/0x1f0 ? find_held_lock+0x32/0x1c0 ? do_huge_pmd_anonymous_page+0xc43/0x11e0 ? lock_downgrade+0x5e0/0x5e0 ? get_kernel_page+0xb0/0xb0 ? _raw_spin_unlock+0x29/0x40 ? do_huge_pmd_anonymous_page+0x400/0x11e0 ? __handle_mm_fault+0x553/0x2460 ? __fget_light+0x163/0x1f0 ? __sys_sendmsg+0xc7/0x170 __sys_sendmsg+0xc7/0x170 ? SyS_shutdown+0x1a0/0x1a0 ? __do_page_fault+0x5a0/0xca0 ? lock_downgrade+0x5e0/0x5e0 SyS_sendmsg+0x27/0x40 ? __sys_sendmsg+0x170/0x170 do_syscall_64+0x19f/0x640 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x7f0ee73dfb79 RSP: 002b:00007ffe14fc15a8 EFLAGS: 00000207 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007f0ee73dfb79 RDX: 0000000000000000 RSI: 00000000208befc8 RDI: 0000000000000004 RBP: 00007ffe14fc15b0 R08: 00007ffe14fc15c0 R09: 00007ffe14fc15c0 R10: 0000000000000000 R11: 0000000000000207 R12: 0000000000400440 R13: 00007ffe14fc16b0 R14: 0000000000000000 R15: 0000000000000000 Signed-off-by: Greg Hackmann Signed-off-by: Steffen Klassert Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_ipcomp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_ipcomp.c b/net/xfrm/xfrm_ipcomp.c index ccfdc7115a83..a00ec715aa46 100644 --- a/net/xfrm/xfrm_ipcomp.c +++ b/net/xfrm/xfrm_ipcomp.c @@ -283,7 +283,7 @@ static struct crypto_comp * __percpu *ipcomp_alloc_tfms(const char *alg_name) struct crypto_comp *tfm; /* This can be any valid CPU ID so we don't need locking. */ - tfm = __this_cpu_read(*pos->tfms); + tfm = this_cpu_read(*pos->tfms); if (!strcmp(crypto_comp_name(tfm), alg_name)) { pos->users++; -- GitLab From 02a5b414bf929922d84bb2289c7ef78eb060a426 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Thu, 1 Feb 2018 08:49:23 +0100 Subject: [PATCH 0918/1834] xfrm: Refuse to insert 32 bit userspace socket policies on 64 bit systems commit 19d7df69fdb2636856dc8919de72fc1bf8f79598 upstream. We don't have a compat layer for xfrm, so userspace and kernel structures have different sizes in this case. This results in a broken configuration, so refuse to configure socket policies when trying to insert from 32 bit userspace as we do it already with policies inserted via netlink. Reported-and-tested-by: syzbot+e1a1577ca8bcb47b769a@syzkaller.appspotmail.com Signed-off-by: Steffen Klassert Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_state.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 13e0611a9085..fdb9742d934e 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1883,6 +1883,11 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen struct xfrm_mgr *km; struct xfrm_policy *pol = NULL; +#ifdef CONFIG_COMPAT + if (in_compat_syscall()) + return -EOPNOTSUPP; +#endif + if (!optval && !optlen) { xfrm_sk_policy_insert(sk, XFRM_POLICY_IN, NULL); xfrm_sk_policy_insert(sk, XFRM_POLICY_OUT, NULL); -- GitLab From ccf38b31223edd9dd1852e43dafe347308629a46 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 9 Mar 2018 14:27:31 +0100 Subject: [PATCH 0919/1834] netfilter: bridge: ebt_among: add more missing match size checks commit c8d70a700a5b486bfa8e5a7d33d805389f6e59f9 upstream. ebt_among is special, it has a dynamic match size and is exempt from the central size checks. commit c4585a2823edf ("bridge: ebt_among: add missing match size checks") added validation for pool size, but missed fact that the macros ebt_among_wh_src/dst can already return out-of-bound result because they do not check value of wh_src/dst_ofs (an offset) vs. the size of the match that userspace gave to us. v2: check that offset has correct alignment. Paolo Abeni points out that we should also check that src/dst wormhash arrays do not overlap, and src + length lines up with start of dst (or vice versa). v3: compact wormhash_sizes_valid() part NB: Fixes tag is intentionally wrong, this bug exists from day one when match was added for 2.6 kernel. Tag is there so stable maintainers will notice this one too. Tested with same rules from the earlier patch. Fixes: c4585a2823edf ("bridge: ebt_among: add missing match size checks") Reported-by: Signed-off-by: Florian Westphal Reviewed-by: Eric Dumazet Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- net/bridge/netfilter/ebt_among.c | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/net/bridge/netfilter/ebt_among.c b/net/bridge/netfilter/ebt_among.c index 9637a681bdda..9adf16258cab 100644 --- a/net/bridge/netfilter/ebt_among.c +++ b/net/bridge/netfilter/ebt_among.c @@ -177,6 +177,28 @@ static bool poolsize_invalid(const struct ebt_mac_wormhash *w) return w && w->poolsize >= (INT_MAX / sizeof(struct ebt_mac_wormhash_tuple)); } +static bool wormhash_offset_invalid(int off, unsigned int len) +{ + if (off == 0) /* not present */ + return false; + + if (off < (int)sizeof(struct ebt_among_info) || + off % __alignof__(struct ebt_mac_wormhash)) + return true; + + off += sizeof(struct ebt_mac_wormhash); + + return off > len; +} + +static bool wormhash_sizes_valid(const struct ebt_mac_wormhash *wh, int a, int b) +{ + if (a == 0) + a = sizeof(struct ebt_among_info); + + return ebt_mac_wormhash_size(wh) + a == b; +} + static int ebt_among_mt_check(const struct xt_mtchk_param *par) { const struct ebt_among_info *info = par->matchinfo; @@ -189,6 +211,10 @@ static int ebt_among_mt_check(const struct xt_mtchk_param *par) if (expected_length > em->match_size) return -EINVAL; + if (wormhash_offset_invalid(info->wh_dst_ofs, em->match_size) || + wormhash_offset_invalid(info->wh_src_ofs, em->match_size)) + return -EINVAL; + wh_dst = ebt_among_wh_dst(info); if (poolsize_invalid(wh_dst)) return -EINVAL; @@ -201,6 +227,14 @@ static int ebt_among_mt_check(const struct xt_mtchk_param *par) if (poolsize_invalid(wh_src)) return -EINVAL; + if (info->wh_src_ofs < info->wh_dst_ofs) { + if (!wormhash_sizes_valid(wh_src, info->wh_src_ofs, info->wh_dst_ofs)) + return -EINVAL; + } else { + if (!wormhash_sizes_valid(wh_dst, info->wh_dst_ofs, info->wh_src_ofs)) + return -EINVAL; + } + expected_length += ebt_mac_wormhash_size(wh_src); if (em->match_size != EBT_ALIGN(expected_length)) { -- GitLab From c6ab7c6ceba551319e968e46d82f745d9ca1535a Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 10 Mar 2018 01:15:45 +0100 Subject: [PATCH 0920/1834] netfilter: x_tables: add and use xt_check_proc_name commit b1d0a5d0cba4597c0394997b2d5fced3e3841b4e upstream. recent and hashlimit both create /proc files, but only check that name is 0 terminated. This can trigger WARN() from procfs when name is "" or "/". Add helper for this and then use it for both. Cc: Eric Dumazet Reported-by: Eric Dumazet Reported-by: Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Greg Kroah-Hartman --- include/linux/netfilter/x_tables.h | 2 ++ net/netfilter/x_tables.c | 30 ++++++++++++++++++++++++++++++ net/netfilter/xt_hashlimit.c | 11 +++++++---- net/netfilter/xt_recent.c | 6 +++--- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 9bfeb88fb940..69111fa2e578 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -254,6 +254,8 @@ unsigned int *xt_alloc_entry_offsets(unsigned int size); bool xt_find_jump_offset(const unsigned int *offsets, unsigned int target, unsigned int size); +int xt_check_proc_name(const char *name, unsigned int size); + int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto, bool inv_proto); int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto, diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 7ad1a863587a..59be89813a29 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -367,6 +367,36 @@ textify_hooks(char *buf, size_t size, unsigned int mask, uint8_t nfproto) return buf; } +/** + * xt_check_proc_name - check that name is suitable for /proc file creation + * + * @name: file name candidate + * @size: length of buffer + * + * some x_tables modules wish to create a file in /proc. + * This function makes sure that the name is suitable for this + * purpose, it checks that name is NUL terminated and isn't a 'special' + * name, like "..". + * + * returns negative number on error or 0 if name is useable. + */ +int xt_check_proc_name(const char *name, unsigned int size) +{ + if (name[0] == '\0') + return -EINVAL; + + if (strnlen(name, size) == size) + return -ENAMETOOLONG; + + if (strcmp(name, ".") == 0 || + strcmp(name, "..") == 0 || + strchr(name, '/')) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(xt_check_proc_name); + int xt_check_match(struct xt_mtchk_param *par, unsigned int size, u_int8_t proto, bool inv_proto) { diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index b89b688e9d01..a1a29cdc58fc 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -794,8 +794,9 @@ static int hashlimit_mt_check_v1(const struct xt_mtchk_param *par) struct hashlimit_cfg2 cfg = {}; int ret; - if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; ret = cfg_copy(&cfg, (void *)&info->cfg, 1); @@ -809,9 +810,11 @@ static int hashlimit_mt_check_v1(const struct xt_mtchk_param *par) static int hashlimit_mt_check(const struct xt_mtchk_param *par) { struct xt_hashlimit_mtinfo2 *info = par->matchinfo; + int ret; - if (info->name[sizeof(info->name) - 1] != '\0') - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; return hashlimit_mt_check_common(par, &info->hinfo, &info->cfg, info->name, 2); diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index e3b7a09b103e..79d7ad621a80 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -361,9 +361,9 @@ static int recent_mt_check(const struct xt_mtchk_param *par, info->hit_count, XT_RECENT_MAX_NSTAMPS - 1); return -EINVAL; } - if (info->name[0] == '\0' || - strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN) - return -EINVAL; + ret = xt_check_proc_name(info->name, sizeof(info->name)); + if (ret) + return ret; if (ip_pkt_list_tot && info->hit_count < ip_pkt_list_tot) nstamp_mask = roundup_pow_of_two(ip_pkt_list_tot) - 1; -- GitLab From 24382a60331d6be571b09eb2165815dbab2457cc Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 26 Feb 2018 15:41:53 +0100 Subject: [PATCH 0921/1834] Bluetooth: Fix missing encryption refresh on Security Request commit 64e759f58f128730b97a3c3a26d283c075ad7c86 upstream. If Security Request is received on connection that is already encrypted with sufficient security master should perform encryption key refresh procedure instead of just ignoring Slave Security Request (Core Spec 5.0 Vol 3 Part H 2.4.6). > ACL Data RX: Handle 3585 flags 0x02 dlen 6 SMP: Security Request (0x0b) len 1 Authentication requirement: Bonding, No MITM, SC, No Keypresses (0x09) < HCI Command: LE Start Encryption (0x08|0x0019) plen 28 Handle: 3585 Random number: 0x0000000000000000 Encrypted diversifier: 0x0000 Long term key: 44264272a5c426a9e868f034cf0e69f3 > HCI Event: Command Status (0x0f) plen 4 LE Start Encryption (0x08|0x0019) ncmd 1 Status: Success (0x00) > HCI Event: Encryption Key Refresh Complete (0x30) plen 3 Status: Success (0x00) Handle: 3585 Signed-off-by: Szymon Janc Signed-off-by: Marcel Holtmann Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/smp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 658c900752c6..ead4d1baeaa6 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -2233,8 +2233,14 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) else sec_level = authreq_to_seclevel(auth); - if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) + if (smp_sufficient_security(hcon, sec_level, SMP_USE_LTK)) { + /* If link is already encrypted with sufficient security we + * still need refresh encryption as per Core Spec 5.0 Vol 3, + * Part H 2.4.6 + */ + smp_ltk_encrypt(conn, hcon->sec_level); return 0; + } if (sec_level > hcon->pending_sec_level) hcon->pending_sec_level = sec_level; -- GitLab From ecd508abb0fa6716a6b397e9bf9e3efbfa4c5864 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Wed, 19 Jul 2017 20:27:30 +0200 Subject: [PATCH 0922/1834] llist: clang: introduce member_address_is_nonnull() commit beaec533fc2701a28a4d667f67c9f59c6e4e0d13 upstream. Currently llist_for_each_entry() and llist_for_each_entry_safe() iterate until &pos->member != NULL. But when building the kernel with Clang, the compiler assumes &pos->member cannot be NULL if the member's offset is greater than 0 (which would be equivalent to the object being non-contiguous in memory). Therefore the loop condition is always true, and the loops become infinite. To work around this, introduce the member_address_is_nonnull() macro, which casts object pointer to uintptr_t, thus letting the member pointer to be NULL. Signed-off-by: Alexander Potapenko Tested-by: Sodagudi Prasad Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- include/linux/llist.h | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/include/linux/llist.h b/include/linux/llist.h index fd4ca0b4fe0f..ac6796138ba0 100644 --- a/include/linux/llist.h +++ b/include/linux/llist.h @@ -87,6 +87,23 @@ static inline void init_llist_head(struct llist_head *list) #define llist_entry(ptr, type, member) \ container_of(ptr, type, member) +/** + * member_address_is_nonnull - check whether the member address is not NULL + * @ptr: the object pointer (struct type * that contains the llist_node) + * @member: the name of the llist_node within the struct. + * + * This macro is conceptually the same as + * &ptr->member != NULL + * but it works around the fact that compilers can decide that taking a member + * address is never a NULL pointer. + * + * Real objects that start at a high address and have a member at NULL are + * unlikely to exist, but such pointers may be returned e.g. by the + * container_of() macro. + */ +#define member_address_is_nonnull(ptr, member) \ + ((uintptr_t)(ptr) + offsetof(typeof(*(ptr)), member) != 0) + /** * llist_for_each - iterate over some deleted entries of a lock-less list * @pos: the &struct llist_node to use as a loop cursor @@ -121,7 +138,7 @@ static inline void init_llist_head(struct llist_head *list) */ #define llist_for_each_entry(pos, node, member) \ for ((pos) = llist_entry((node), typeof(*(pos)), member); \ - &(pos)->member != NULL; \ + member_address_is_nonnull(pos, member); \ (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member)) /** @@ -143,7 +160,7 @@ static inline void init_llist_head(struct llist_head *list) */ #define llist_for_each_entry_safe(pos, n, node, member) \ for (pos = llist_entry((node), typeof(*pos), member); \ - &pos->member != NULL && \ + member_address_is_nonnull(pos, member) && \ (n = llist_entry(pos->member.next, typeof(*n), member), true); \ pos = n) -- GitLab From cfde23842ab214e3de39beb7e68970c502e849e8 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 5 Jul 2017 10:30:56 +0200 Subject: [PATCH 0923/1834] scsi: virtio_scsi: always read VPD pages for multiqueue too commit a680f1d463aeaeb00d22af257a56e111967c2f18 upstream. Multi-queue virtio-scsi uses a different scsi_host_template struct. Add the .device_alloc field there, too. Fixes: 25d1d50e23275e141e3a3fe06c25a99f4c4bf4e0 Cc: stable@vger.kernel.org Cc: David Gibson Signed-off-by: Paolo Bonzini Reviewed-by: Fam Zheng Reviewed-by: Stefan Hajnoczi Signed-off-by: Martin K. Petersen Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/virtio_scsi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index 8f4adc1d9588..cbc8e9388268 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -819,6 +819,7 @@ static struct scsi_host_template virtscsi_host_template_multi = { .change_queue_depth = virtscsi_change_queue_depth, .eh_abort_handler = virtscsi_abort, .eh_device_reset_handler = virtscsi_device_reset, + .slave_alloc = virtscsi_device_alloc, .can_queue = 1024, .dma_boundary = UINT_MAX, -- GitLab From 7e59524527a5ce0cbca047f3ad0fb8f7997713fe Mon Sep 17 00:00:00 2001 From: John Stultz Date: Mon, 23 Oct 2017 14:32:48 -0700 Subject: [PATCH 0924/1834] usb: dwc2: Improve gadget state disconnection handling commit d2471d4a24dfbff5e463d382e2c6fec7d7e25a09 upstream. In the earlier commit dad3f793f20f ("usb: dwc2: Make sure we disconnect the gadget state"), I was trying to fix up the fact that we somehow weren't disconnecting the gadget state, so that when the OTG port was plugged in the second time we would get warnings about the state tracking being wrong. (This seems to be due to a quirk of the HiKey board where we do not ever get any otg interrupts, particularly the session end detected signal. Instead we only see status change interrupt.) The fix there was somewhat simple, as it just made sure to call dwc2_hsotg_disconnect() before we connected things up in OTG mode, ensuring the state handling didn't throw errors. But in looking at a different issue I was seeing with UDC state handling, I realized that it would be much better to call dwc2_hsotg_disconnect when we get the state change signal moving to host mode. Thus, this patch removes the earlier disconnect call I added and moves it (and the needed locking) to the host mode transition. Cc: Wei Xu Cc: Guodong Xu Cc: Amit Pundir Cc: YongQin Liu Cc: John Youn Cc: Minas Harutyunyan Cc: Douglas Anderson Cc: Chen Yu Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Acked-by: Minas Harutyunyan Tested-by: Minas Harutyunyan Signed-off-by: John Stultz Signed-off-by: Felipe Balbi Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc2/hcd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index dfc0566bb155..919a32153060 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -3220,7 +3220,6 @@ static void dwc2_conn_id_status_change(struct work_struct *work) dwc2_core_init(hsotg, false); dwc2_enable_global_interrupts(hsotg); spin_lock_irqsave(&hsotg->lock, flags); - dwc2_hsotg_disconnect(hsotg); dwc2_hsotg_core_init_disconnected(hsotg, false); spin_unlock_irqrestore(&hsotg->lock, flags); dwc2_hsotg_core_connect(hsotg); @@ -3238,8 +3237,12 @@ static void dwc2_conn_id_status_change(struct work_struct *work) if (count > 250) dev_err(hsotg->dev, "Connection id status change timed out\n"); - hsotg->op_state = OTG_STATE_A_HOST; + spin_lock_irqsave(&hsotg->lock, flags); + dwc2_hsotg_disconnect(hsotg); + spin_unlock_irqrestore(&hsotg->lock, flags); + + hsotg->op_state = OTG_STATE_A_HOST; /* Initialize the Core for Host mode */ dwc2_core_init(hsotg, false); dwc2_enable_global_interrupts(hsotg); -- GitLab From 8e4e9770667fc96e50b2bf69377333b587834fae Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:08:57 +0100 Subject: [PATCH 0925/1834] arm64: mm: Use non-global mappings for kernel space commit e046eb0c9bf2 upstream. In preparation for unmapping the kernel whilst running in userspace, make the kernel mappings non-global so we can avoid expensive TLB invalidation on kernel exit to userspace. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/kernel-pgtable.h | 12 ++++++++++-- arch/arm64/include/asm/pgtable-prot.h | 21 +++++++++++++++------ 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h index 7e51d1b57c0c..e4ddac983640 100644 --- a/arch/arm64/include/asm/kernel-pgtable.h +++ b/arch/arm64/include/asm/kernel-pgtable.h @@ -71,8 +71,16 @@ /* * Initial memory map attributes. */ -#define SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) -#define SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) +#define _SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) +#define _SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define SWAPPER_PTE_FLAGS (_SWAPPER_PTE_FLAGS | PTE_NG) +#define SWAPPER_PMD_FLAGS (_SWAPPER_PMD_FLAGS | PMD_SECT_NG) +#else +#define SWAPPER_PTE_FLAGS _SWAPPER_PTE_FLAGS +#define SWAPPER_PMD_FLAGS _SWAPPER_PMD_FLAGS +#endif #if ARM64_SWAPPER_USES_SECTION_MAPS #define SWAPPER_MM_MMUFLAGS (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS) diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index 2142c7726e76..84b5283d2e7f 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -34,8 +34,16 @@ #include -#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) -#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) +#define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) +#define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define PROT_DEFAULT (_PROT_DEFAULT | PTE_NG) +#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_SECT_NG) +#else +#define PROT_DEFAULT _PROT_DEFAULT +#define PROT_SECT_DEFAULT _PROT_SECT_DEFAULT +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ #define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE)) @@ -48,6 +56,7 @@ #define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) #define _PAGE_DEFAULT (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) +#define _HYP_PAGE_DEFAULT (_PAGE_DEFAULT & ~PTE_NG) #define PAGE_KERNEL __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE) #define PAGE_KERNEL_RO __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY) @@ -55,15 +64,15 @@ #define PAGE_KERNEL_EXEC __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE) #define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT) -#define PAGE_HYP __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN) -#define PAGE_HYP_EXEC __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY) -#define PAGE_HYP_RO __pgprot(_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN) +#define PAGE_HYP __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN) +#define PAGE_HYP_EXEC __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY) +#define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN) #define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP) #define PAGE_S2 __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY) #define PAGE_S2_DEVICE __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN) -#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_PXN | PTE_UXN) +#define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_NG | PTE_PXN | PTE_UXN) #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) #define PAGE_SHARED_EXEC __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE) #define PAGE_COPY __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN) -- GitLab From 984e60a9d110ef00938e3fc8d74831893f7cab7d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:08:58 +0100 Subject: [PATCH 0926/1834] arm64: mm: Move ASID from TTBR0 to TTBR1 commit 7655abb95386 upstream. In preparation for mapping kernelspace and userspace with different ASIDs, move the ASID to TTBR1 and update switch_mm to context-switch TTBR0 via an invalid mapping (the zero page). Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/mmu_context.h | 7 +++++++ arch/arm64/include/asm/pgtable-hwdef.h | 1 + arch/arm64/include/asm/proc-fns.h | 6 ------ arch/arm64/mm/proc.S | 9 ++++++--- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h index a50185375f09..b96c4799f881 100644 --- a/arch/arm64/include/asm/mmu_context.h +++ b/arch/arm64/include/asm/mmu_context.h @@ -50,6 +50,13 @@ static inline void cpu_set_reserved_ttbr0(void) isb(); } +static inline void cpu_switch_mm(pgd_t *pgd, struct mm_struct *mm) +{ + BUG_ON(pgd == swapper_pg_dir); + cpu_set_reserved_ttbr0(); + cpu_do_switch_mm(virt_to_phys(pgd),mm); +} + /* * TCR.T0SZ value to use when the ID map is active. Usually equals * TCR_T0SZ(VA_BITS), unless system RAM is positioned very high in diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index eb0c2bd90de9..8df4cb6ac6f7 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -272,6 +272,7 @@ #define TCR_TG1_4K (UL(2) << TCR_TG1_SHIFT) #define TCR_TG1_64K (UL(3) << TCR_TG1_SHIFT) +#define TCR_A1 (UL(1) << 22) #define TCR_ASID16 (UL(1) << 36) #define TCR_TBI0 (UL(1) << 37) #define TCR_HA (UL(1) << 39) diff --git a/arch/arm64/include/asm/proc-fns.h b/arch/arm64/include/asm/proc-fns.h index 14ad6e4e87d1..16cef2e8449e 100644 --- a/arch/arm64/include/asm/proc-fns.h +++ b/arch/arm64/include/asm/proc-fns.h @@ -35,12 +35,6 @@ extern u64 cpu_do_resume(phys_addr_t ptr, u64 idmap_ttbr); #include -#define cpu_switch_mm(pgd,mm) \ -do { \ - BUG_ON(pgd == swapper_pg_dir); \ - cpu_do_switch_mm(virt_to_phys(pgd),mm); \ -} while (0) - #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* __ASM_PROCFNS_H */ diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 352c73b6a59e..3378f3e21224 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -132,9 +132,12 @@ ENDPROC(cpu_do_resume) * - pgd_phys - physical address of new TTB */ ENTRY(cpu_do_switch_mm) + mrs x2, ttbr1_el1 mmid x1, x1 // get mm->context.id - bfi x0, x1, #48, #16 // set the ASID - msr ttbr0_el1, x0 // set TTBR0 + bfi x2, x1, #48, #16 // set the ASID + msr ttbr1_el1, x2 // in TTBR1 (since TCR.A1 is set) + isb + msr ttbr0_el1, x0 // now update TTBR0 isb alternative_if ARM64_WORKAROUND_CAVIUM_27456 ic iallu @@ -222,7 +225,7 @@ ENTRY(__cpu_setup) * both user and kernel. */ ldr x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \ - TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 + TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0 | TCR_A1 tcr_set_idmap_t0sz x10, x9 /* -- GitLab From 8919d317bb7f3f7d0e26aae9eb6e430f0f821ca9 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:08:59 +0100 Subject: [PATCH 0927/1834] arm64: mm: Allocate ASIDs in pairs commit 0c8ea531b774 upstream. In preparation for separate kernel/user ASIDs, allocate them in pairs for each mm_struct. The bottom bit distinguishes the two: if it is set, then the ASID will map only userspace. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/mmu.h | 2 ++ arch/arm64/mm/context.c | 25 +++++++++++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 8d9fce037b2f..49924e56048e 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -16,6 +16,8 @@ #ifndef __ASM_MMU_H #define __ASM_MMU_H +#define USER_ASID_FLAG (UL(1) << 48) + typedef struct { atomic64_t id; void *vdso; diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index efcf1f7ef1e4..f00f5eeb556f 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -39,7 +39,16 @@ static cpumask_t tlb_flush_pending; #define ASID_MASK (~GENMASK(asid_bits - 1, 0)) #define ASID_FIRST_VERSION (1UL << asid_bits) -#define NUM_USER_ASIDS ASID_FIRST_VERSION + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define NUM_USER_ASIDS (ASID_FIRST_VERSION >> 1) +#define asid2idx(asid) (((asid) & ~ASID_MASK) >> 1) +#define idx2asid(idx) (((idx) << 1) & ~ASID_MASK) +#else +#define NUM_USER_ASIDS (ASID_FIRST_VERSION) +#define asid2idx(asid) ((asid) & ~ASID_MASK) +#define idx2asid(idx) asid2idx(idx) +#endif /* Get the ASIDBits supported by the current CPU */ static u32 get_cpu_asid_bits(void) @@ -104,7 +113,7 @@ static void flush_context(unsigned int cpu) */ if (asid == 0) asid = per_cpu(reserved_asids, i); - __set_bit(asid & ~ASID_MASK, asid_map); + __set_bit(asid2idx(asid), asid_map); per_cpu(reserved_asids, i) = asid; } @@ -159,16 +168,16 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) * We had a valid ASID in a previous life, so try to re-use * it if possible. */ - asid &= ~ASID_MASK; - if (!__test_and_set_bit(asid, asid_map)) + if (!__test_and_set_bit(asid2idx(asid), asid_map)) return newasid; } /* * Allocate a free ASID. If we can't find one, take a note of the - * currently active ASIDs and mark the TLBs as requiring flushes. - * We always count from ASID #1, as we use ASID #0 when setting a - * reserved TTBR0 for the init_mm. + * currently active ASIDs and mark the TLBs as requiring flushes. We + * always count from ASID #2 (index 1), as we use ASID #0 when setting + * a reserved TTBR0 for the init_mm and we allocate ASIDs in even/odd + * pairs. */ asid = find_next_zero_bit(asid_map, NUM_USER_ASIDS, cur_idx); if (asid != NUM_USER_ASIDS) @@ -185,7 +194,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu) set_asid: __set_bit(asid, asid_map); cur_idx = asid; - return asid | generation; + return idx2asid(asid) | generation; } void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) -- GitLab From 93116842895ec062e3e700f00477bb6c7f3b09ee Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:00 +0100 Subject: [PATCH 0928/1834] arm64: mm: Add arm64_kernel_unmapped_at_el0 helper commit fc0e1299da54 upstream. In order for code such as TLB invalidation to operate efficiently when the decision to map the kernel at EL0 is determined at runtime, this patch introduces a helper function, arm64_kernel_unmapped_at_el0, to determine whether or not the kernel is mapped whilst running in userspace. Currently, this just reports the value of CONFIG_UNMAP_KERNEL_AT_EL0, but will later be hooked up to a fake CPU capability using a static key. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/mmu.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 49924e56048e..279e75b8a49e 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -18,6 +18,8 @@ #define USER_ASID_FLAG (UL(1) << 48) +#ifndef __ASSEMBLY__ + typedef struct { atomic64_t id; void *vdso; @@ -30,6 +32,11 @@ typedef struct { */ #define ASID(mm) ((mm)->context.id.counter & 0xffff) +static inline bool arm64_kernel_unmapped_at_el0(void) +{ + return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0); +} + extern void paging_init(void); extern void bootmem_init(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); @@ -39,4 +46,5 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, pgprot_t prot, bool allow_block_mappings); extern void *fixmap_remap_fdt(phys_addr_t dt_phys); +#endif /* !__ASSEMBLY__ */ #endif -- GitLab From 0e800ba7a62e5f204d87782c2f0a823512e9d5f3 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:01 +0100 Subject: [PATCH 0929/1834] arm64: mm: Invalidate both kernel and user ASIDs when performing TLBI commit 9b0de864b5bc upstream. Since an mm has both a kernel and a user ASID, we need to ensure that broadcast TLB maintenance targets both address spaces so that things like CoW continue to work with the uaccess primitives in the kernel. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/tlbflush.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index deab52374119..ad6bd8b26ada 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -23,6 +23,7 @@ #include #include +#include /* * Raw TLBI operations. @@ -42,6 +43,11 @@ #define __tlbi(op, ...) __TLBI_N(op, ##__VA_ARGS__, 1, 0) +#define __tlbi_user(op, arg) do { \ + if (arm64_kernel_unmapped_at_el0()) \ + __tlbi(op, (arg) | USER_ASID_FLAG); \ +} while (0) + /* * TLB Management * ============== @@ -103,6 +109,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm) dsb(ishst); __tlbi(aside1is, asid); + __tlbi_user(aside1is, asid); dsb(ish); } @@ -113,6 +120,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, dsb(ishst); __tlbi(vale1is, addr); + __tlbi_user(vale1is, addr); dsb(ish); } @@ -139,10 +147,13 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, dsb(ishst); for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) { - if (last_level) + if (last_level) { __tlbi(vale1is, addr); - else + __tlbi_user(vale1is, addr); + } else { __tlbi(vae1is, addr); + __tlbi_user(vae1is, addr); + } } dsb(ish); } @@ -182,6 +193,7 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm, unsigned long addr = uaddr >> 12 | (ASID(mm) << 48); __tlbi(vae1is, addr); + __tlbi_user(vae1is, addr); dsb(ish); } -- GitLab From e355d4b6a2757a72826383c32b88eb2e76e77f66 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 3 Apr 2018 12:09:02 +0100 Subject: [PATCH 0930/1834] arm64: factor out entry stack manipulation commit b11e5759bfac upstream. In subsequent patches, we will detect stack overflow in our exception entry code, by verifying the SP after it has been decremented to make space for the exception regs. This verification code is small, and we can minimize its impact by placing it directly in the vectors. To avoid redundant modification of the SP, we also need to move the initial decrement of the SP into the vectors. As a preparatory step, this patch introduces kernel_ventry, which performs this decrement, and updates the entry code accordingly. Subsequent patches will fold SP verification into kernel_ventry. There should be no functional change as a result of this patch. Signed-off-by: Ard Biesheuvel [Mark: turn into prep patch, expand commit msg] Signed-off-by: Mark Rutland Reviewed-by: Will Deacon Tested-by: Laura Abbott Cc: Catalin Marinas Cc: James Morse Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 47 ++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index b4c7db434654..f5aa8f010254 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -68,8 +68,13 @@ #define BAD_FIQ 2 #define BAD_ERROR 3 - .macro kernel_entry, el, regsize = 64 + .macro kernel_ventry label + .align 7 sub sp, sp, #S_FRAME_SIZE + b \label + .endm + + .macro kernel_entry, el, regsize = 64 .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0 .endif @@ -257,31 +262,31 @@ tsk .req x28 // current thread_info .align 11 ENTRY(vectors) - ventry el1_sync_invalid // Synchronous EL1t - ventry el1_irq_invalid // IRQ EL1t - ventry el1_fiq_invalid // FIQ EL1t - ventry el1_error_invalid // Error EL1t + kernel_ventry el1_sync_invalid // Synchronous EL1t + kernel_ventry el1_irq_invalid // IRQ EL1t + kernel_ventry el1_fiq_invalid // FIQ EL1t + kernel_ventry el1_error_invalid // Error EL1t - ventry el1_sync // Synchronous EL1h - ventry el1_irq // IRQ EL1h - ventry el1_fiq_invalid // FIQ EL1h - ventry el1_error_invalid // Error EL1h + kernel_ventry el1_sync // Synchronous EL1h + kernel_ventry el1_irq // IRQ EL1h + kernel_ventry el1_fiq_invalid // FIQ EL1h + kernel_ventry el1_error_invalid // Error EL1h - ventry el0_sync // Synchronous 64-bit EL0 - ventry el0_irq // IRQ 64-bit EL0 - ventry el0_fiq_invalid // FIQ 64-bit EL0 - ventry el0_error_invalid // Error 64-bit EL0 + kernel_ventry el0_sync // Synchronous 64-bit EL0 + kernel_ventry el0_irq // IRQ 64-bit EL0 + kernel_ventry el0_fiq_invalid // FIQ 64-bit EL0 + kernel_ventry el0_error_invalid // Error 64-bit EL0 #ifdef CONFIG_COMPAT - ventry el0_sync_compat // Synchronous 32-bit EL0 - ventry el0_irq_compat // IRQ 32-bit EL0 - ventry el0_fiq_invalid_compat // FIQ 32-bit EL0 - ventry el0_error_invalid_compat // Error 32-bit EL0 + kernel_ventry el0_sync_compat // Synchronous 32-bit EL0 + kernel_ventry el0_irq_compat // IRQ 32-bit EL0 + kernel_ventry el0_fiq_invalid_compat // FIQ 32-bit EL0 + kernel_ventry el0_error_invalid_compat // Error 32-bit EL0 #else - ventry el0_sync_invalid // Synchronous 32-bit EL0 - ventry el0_irq_invalid // IRQ 32-bit EL0 - ventry el0_fiq_invalid // FIQ 32-bit EL0 - ventry el0_error_invalid // Error 32-bit EL0 + kernel_ventry el0_sync_invalid // Synchronous 32-bit EL0 + kernel_ventry el0_irq_invalid // IRQ 32-bit EL0 + kernel_ventry el0_fiq_invalid // FIQ 32-bit EL0 + kernel_ventry el0_error_invalid // Error 32-bit EL0 #endif END(vectors) -- GitLab From 7f9a93b30bcb7d78f09c86ed47aa86f7340e42e8 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 3 Apr 2018 12:09:03 +0100 Subject: [PATCH 0931/1834] module: extend 'rodata=off' boot cmdline parameter to module mappings commit 39290b389ea upstream. The current "rodata=off" parameter disables read-only kernel mappings under CONFIG_DEBUG_RODATA: commit d2aa1acad22f ("mm/init: Add 'rodata=off' boot cmdline parameter to disable read-only kernel mappings") This patch is a logical extension to module mappings ie. read-only mappings at module loading can be disabled even if CONFIG_DEBUG_SET_MODULE_RONX (mainly for debug use). Please note, however, that it only affects RO/RW permissions, keeping NX set. This is the first step to make CONFIG_DEBUG_SET_MODULE_RONX mandatory (always-on) in the future as CONFIG_DEBUG_RODATA on x86 and arm64. Suggested-by: and Acked-by: Mark Rutland Signed-off-by: AKASHI Takahiro Reviewed-by: Kees Cook Acked-by: Rusty Russell Link: http://lkml.kernel.org/r/20161114061505.15238-1-takahiro.akashi@linaro.org Signed-off-by: Jessica Yu Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- include/linux/init.h | 3 +++ init/main.c | 7 +++++-- kernel/module.c | 20 +++++++++++++++++--- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/include/linux/init.h b/include/linux/init.h index 683508f6bb4e..0cca4142987f 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -133,6 +133,9 @@ void prepare_namespace(void); void __init load_default_modules(void); int __init init_rootfs(void); +#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_DEBUG_SET_MODULE_RONX) +extern bool rodata_enabled; +#endif #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void); #endif diff --git a/init/main.c b/init/main.c index 99f026565608..f22957afb37e 100644 --- a/init/main.c +++ b/init/main.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include @@ -914,14 +915,16 @@ static int try_to_run_init_process(const char *init_filename) static noinline void __init kernel_init_freeable(void); -#ifdef CONFIG_DEBUG_RODATA -static bool rodata_enabled = true; +#if defined(CONFIG_DEBUG_RODATA) || defined(CONFIG_SET_MODULE_RONX) +bool rodata_enabled __ro_after_init = true; static int __init set_debug_rodata(char *str) { return strtobool(str, &rodata_enabled); } __setup("rodata=", set_debug_rodata); +#endif +#ifdef CONFIG_DEBUG_RODATA static void mark_readonly(void) { if (rodata_enabled) diff --git a/kernel/module.c b/kernel/module.c index 07bfb9971f2f..0651f2d25fc9 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1911,6 +1911,9 @@ static void frob_writable_data(const struct module_layout *layout, /* livepatching wants to disable read-only so it can frob module. */ void module_disable_ro(const struct module *mod) { + if (!rodata_enabled) + return; + frob_text(&mod->core_layout, set_memory_rw); frob_rodata(&mod->core_layout, set_memory_rw); frob_ro_after_init(&mod->core_layout, set_memory_rw); @@ -1920,6 +1923,9 @@ void module_disable_ro(const struct module *mod) void module_enable_ro(const struct module *mod, bool after_init) { + if (!rodata_enabled) + return; + frob_text(&mod->core_layout, set_memory_ro); frob_rodata(&mod->core_layout, set_memory_ro); frob_text(&mod->init_layout, set_memory_ro); @@ -1952,6 +1958,9 @@ void set_all_modules_text_rw(void) { struct module *mod; + if (!rodata_enabled) + return; + mutex_lock(&module_mutex); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) @@ -1968,6 +1977,9 @@ void set_all_modules_text_ro(void) { struct module *mod; + if (!rodata_enabled) + return; + mutex_lock(&module_mutex); list_for_each_entry_rcu(mod, &modules, list) { if (mod->state == MODULE_STATE_UNFORMED) @@ -1981,10 +1993,12 @@ void set_all_modules_text_ro(void) static void disable_ro_nx(const struct module_layout *layout) { - frob_text(layout, set_memory_rw); - frob_rodata(layout, set_memory_rw); + if (rodata_enabled) { + frob_text(layout, set_memory_rw); + frob_rodata(layout, set_memory_rw); + frob_ro_after_init(layout, set_memory_rw); + } frob_rodata(layout, set_memory_x); - frob_ro_after_init(layout, set_memory_rw); frob_ro_after_init(layout, set_memory_x); frob_writable_data(layout, set_memory_x); } -- GitLab From 78a0cec5fe4399dced66e70cdec793618590d932 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:04 +0100 Subject: [PATCH 0932/1834] arm64: entry: Add exception trampoline page for exceptions from EL0 commit c7b9adaf85f8 upstream. To allow unmapping of the kernel whilst running at EL0, we need to point the exception vectors at an entry trampoline that can map/unmap the kernel on entry/exit respectively. This patch adds the trampoline page, although it is not yet plugged into the vector table and is therefore unused. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon [Alex: avoid dependency on SW PAN patches] Signed-off-by: Alex Shi [v4.9 backport] [Mark: remove dummy SW PAN definitions] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 86 +++++++++++++++++++++++++++++++++ arch/arm64/kernel/vmlinux.lds.S | 17 +++++++ 2 files changed, 103 insertions(+) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index f5aa8f010254..08f6f059e960 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -29,9 +29,11 @@ #include #include #include +#include #include #include #include +#include /* * Context tracking subsystem. Used to instrument transitions @@ -806,6 +808,90 @@ __ni_sys_trace: .popsection // .entry.text +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +/* + * Exception vectors trampoline. + */ + .pushsection ".entry.tramp.text", "ax" + + .macro tramp_map_kernel, tmp + mrs \tmp, ttbr1_el1 + sub \tmp, \tmp, #SWAPPER_DIR_SIZE + bic \tmp, \tmp, #USER_ASID_FLAG + msr ttbr1_el1, \tmp + .endm + + .macro tramp_unmap_kernel, tmp + mrs \tmp, ttbr1_el1 + add \tmp, \tmp, #SWAPPER_DIR_SIZE + orr \tmp, \tmp, #USER_ASID_FLAG + msr ttbr1_el1, \tmp + /* + * We avoid running the post_ttbr_update_workaround here because the + * user and kernel ASIDs don't have conflicting mappings, so any + * "blessing" as described in: + * + * http://lkml.kernel.org/r/56BB848A.6060603@caviumnetworks.com + * + * will not hurt correctness. Whilst this may partially defeat the + * point of using split ASIDs in the first place, it avoids + * the hit of invalidating the entire I-cache on every return to + * userspace. + */ + .endm + + .macro tramp_ventry, regsize = 64 + .align 7 +1: + .if \regsize == 64 + msr tpidrro_el0, x30 // Restored in kernel_ventry + .endif + tramp_map_kernel x30 + ldr x30, =vectors + prfm plil1strm, [x30, #(1b - tramp_vectors)] + msr vbar_el1, x30 + add x30, x30, #(1b - tramp_vectors) + isb + br x30 + .endm + + .macro tramp_exit, regsize = 64 + adr x30, tramp_vectors + msr vbar_el1, x30 + tramp_unmap_kernel x30 + .if \regsize == 64 + mrs x30, far_el1 + .endif + eret + .endm + + .align 11 +ENTRY(tramp_vectors) + .space 0x400 + + tramp_ventry + tramp_ventry + tramp_ventry + tramp_ventry + + tramp_ventry 32 + tramp_ventry 32 + tramp_ventry 32 + tramp_ventry 32 +END(tramp_vectors) + +ENTRY(tramp_exit_native) + tramp_exit +END(tramp_exit_native) + +ENTRY(tramp_exit_compat) + tramp_exit 32 +END(tramp_exit_compat) + + .ltorg + .popsection // .entry.tramp.text +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ + /* * Special system call wrappers. */ diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 1105aab1e6d6..466a43adec9f 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -56,6 +56,17 @@ jiffies = jiffies_64; #define HIBERNATE_TEXT #endif +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +#define TRAMP_TEXT \ + . = ALIGN(PAGE_SIZE); \ + VMLINUX_SYMBOL(__entry_tramp_text_start) = .; \ + *(.entry.tramp.text) \ + . = ALIGN(PAGE_SIZE); \ + VMLINUX_SYMBOL(__entry_tramp_text_end) = .; +#else +#define TRAMP_TEXT +#endif + /* * The size of the PE/COFF section that covers the kernel image, which * runs from stext to _edata, must be a round multiple of the PE/COFF @@ -128,6 +139,7 @@ SECTIONS HYPERVISOR_TEXT IDMAP_TEXT HIBERNATE_TEXT + TRAMP_TEXT *(.fixup) *(.gnu.warning) . = ALIGN(16); @@ -216,6 +228,11 @@ SECTIONS swapper_pg_dir = .; . += SWAPPER_DIR_SIZE; +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + tramp_pg_dir = .; + . += PAGE_SIZE; +#endif + _end = .; STABS_DEBUG -- GitLab From 1809afd71b9c419ab8b57c3ea5c870b5285f442a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:05 +0100 Subject: [PATCH 0933/1834] arm64: mm: Map entry trampoline into trampoline and kernel page tables commit 51a0048beb44 upstream. The exception entry trampoline needs to be mapped at the same virtual address in both the trampoline page table (which maps nothing else) and also the kernel page table, so that we can swizzle TTBR1_EL1 on exceptions from and return to EL0. This patch maps the trampoline at a fixed virtual address in the fixmap area of the kernel virtual address space, which allows the kernel proper to be randomized with respect to the trampoline when KASLR is enabled. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/fixmap.h | 5 +++++ arch/arm64/include/asm/pgtable.h | 1 + arch/arm64/kernel/asm-offsets.c | 6 +++++- arch/arm64/mm/mmu.c | 23 +++++++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index caf86be815ba..7b1d88c18143 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -51,6 +51,11 @@ enum fixed_addresses { FIX_EARLYCON_MEM_BASE, FIX_TEXT_POKE0, + +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + FIX_ENTRY_TRAMP_TEXT, +#define TRAMP_VALIAS (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT)) +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ __end_of_permanent_fixed_addresses, /* diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 7acd3c5c7643..3a30a3994e4a 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -692,6 +692,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; +extern pgd_t tramp_pg_dir[PTRS_PER_PGD]; /* * Encode and decode a swap entry: diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index c58ddf8c4062..5f4bf3c6f016 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -144,11 +145,14 @@ int main(void) DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2)); DEFINE(ARM_SMCCC_QUIRK_ID_OFFS, offsetof(struct arm_smccc_quirk, id)); DEFINE(ARM_SMCCC_QUIRK_STATE_OFFS, offsetof(struct arm_smccc_quirk, state)); - BLANK(); DEFINE(HIBERN_PBE_ORIG, offsetof(struct pbe, orig_address)); DEFINE(HIBERN_PBE_ADDR, offsetof(struct pbe, address)); DEFINE(HIBERN_PBE_NEXT, offsetof(struct pbe, next)); DEFINE(ARM64_FTR_SYSVAL, offsetof(struct arm64_ftr_reg, sys_val)); + BLANK(); +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + DEFINE(TRAMP_VALIAS, TRAMP_VALIAS); +#endif return 0; } diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 638f7f2bd79c..3a57fec16b32 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -419,6 +419,29 @@ static void __init map_kernel_segment(pgd_t *pgd, void *va_start, void *va_end, vm_area_add_early(vma); } +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +static int __init map_entry_trampoline(void) +{ + extern char __entry_tramp_text_start[]; + + pgprot_t prot = rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC; + phys_addr_t pa_start = __pa_symbol(__entry_tramp_text_start); + + /* The trampoline is always mapped and can therefore be global */ + pgprot_val(prot) &= ~PTE_NG; + + /* Map only the text into the trampoline page table */ + memset(tramp_pg_dir, 0, PGD_SIZE); + __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE, + prot, pgd_pgtable_alloc, 0); + + /* ...as well as the kernel page table */ + __set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot); + return 0; +} +core_initcall(map_entry_trampoline); +#endif + /* * Create fine-grained mappings for the kernel. */ -- GitLab From d0b3c71fbc87a8db3f2f841287bfcb6e7d78635c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:06 +0100 Subject: [PATCH 0934/1834] arm64: entry: Explicitly pass exception level to kernel_ventry macro commit 5b1f7fe41909 upstream. We will need to treat exceptions from EL0 differently in kernel_ventry, so rework the macro to take the exception level as an argument and construct the branch target using that. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] [Mark: avoid dependency on C error handler backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 44 +++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 08f6f059e960..0a9f6e7a76d6 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -70,10 +70,10 @@ #define BAD_FIQ 2 #define BAD_ERROR 3 - .macro kernel_ventry label + .macro kernel_ventry, el, label, regsize = 64 .align 7 sub sp, sp, #S_FRAME_SIZE - b \label + b el\()\el\()_\label .endm .macro kernel_entry, el, regsize = 64 @@ -264,31 +264,31 @@ tsk .req x28 // current thread_info .align 11 ENTRY(vectors) - kernel_ventry el1_sync_invalid // Synchronous EL1t - kernel_ventry el1_irq_invalid // IRQ EL1t - kernel_ventry el1_fiq_invalid // FIQ EL1t - kernel_ventry el1_error_invalid // Error EL1t + kernel_ventry 1, sync_invalid // Synchronous EL1t + kernel_ventry 1, irq_invalid // IRQ EL1t + kernel_ventry 1, fiq_invalid // FIQ EL1t + kernel_ventry 1, error_invalid // Error EL1t - kernel_ventry el1_sync // Synchronous EL1h - kernel_ventry el1_irq // IRQ EL1h - kernel_ventry el1_fiq_invalid // FIQ EL1h - kernel_ventry el1_error_invalid // Error EL1h + kernel_ventry 1, sync // Synchronous EL1h + kernel_ventry 1, irq // IRQ EL1h + kernel_ventry 1, fiq_invalid // FIQ EL1h + kernel_ventry 1, error_invalid // Error EL1h - kernel_ventry el0_sync // Synchronous 64-bit EL0 - kernel_ventry el0_irq // IRQ 64-bit EL0 - kernel_ventry el0_fiq_invalid // FIQ 64-bit EL0 - kernel_ventry el0_error_invalid // Error 64-bit EL0 + kernel_ventry 0, sync // Synchronous 64-bit EL0 + kernel_ventry 0, irq // IRQ 64-bit EL0 + kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0 + kernel_ventry 0, error_invalid // Error 64-bit EL0 #ifdef CONFIG_COMPAT - kernel_ventry el0_sync_compat // Synchronous 32-bit EL0 - kernel_ventry el0_irq_compat // IRQ 32-bit EL0 - kernel_ventry el0_fiq_invalid_compat // FIQ 32-bit EL0 - kernel_ventry el0_error_invalid_compat // Error 32-bit EL0 + kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0 + kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0 + kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0 + kernel_ventry 0, error_invalid_compat, 32 // Error 32-bit EL0 #else - kernel_ventry el0_sync_invalid // Synchronous 32-bit EL0 - kernel_ventry el0_irq_invalid // IRQ 32-bit EL0 - kernel_ventry el0_fiq_invalid // FIQ 32-bit EL0 - kernel_ventry el0_error_invalid // Error 32-bit EL0 + kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0 + kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0 + kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0 + kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0 #endif END(vectors) -- GitLab From ded93ce56e9a96f94397699be447ba8e9e4b45c3 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:07 +0100 Subject: [PATCH 0935/1834] arm64: entry: Hook up entry trampoline to exception vectors commit 4bf3286d29f3 upstream. Hook up the entry trampoline to our exception vectors so that all exceptions from and returns to EL0 go via the trampoline, which swizzles the vector base register accordingly. Transitioning to and from the kernel clobbers x30, so we use tpidrro_el0 and far_el1 as scratch registers for native tasks. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 0a9f6e7a76d6..623c160bf68e 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -72,10 +72,26 @@ .macro kernel_ventry, el, label, regsize = 64 .align 7 +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + .if \el == 0 + .if \regsize == 64 + mrs x30, tpidrro_el0 + msr tpidrro_el0, xzr + .else + mov x30, xzr + .endif + .endif +#endif + sub sp, sp, #S_FRAME_SIZE b el\()\el\()_\label .endm + .macro tramp_alias, dst, sym + mov_q \dst, TRAMP_VALIAS + add \dst, \dst, #(\sym - .entry.tramp.text) + .endm + .macro kernel_entry, el, regsize = 64 .if \regsize == 32 mov w0, w0 // zero upper 32 bits of x0 @@ -157,18 +173,20 @@ ct_user_enter ldr x23, [sp, #S_SP] // load return stack pointer msr sp_el0, x23 + tst x22, #PSR_MODE32_BIT // native task? + b.eq 3f + #ifdef CONFIG_ARM64_ERRATUM_845719 alternative_if ARM64_WORKAROUND_845719 - tbz x22, #4, 1f #ifdef CONFIG_PID_IN_CONTEXTIDR mrs x29, contextidr_el1 msr contextidr_el1, x29 #else msr contextidr_el1, xzr #endif -1: alternative_else_nop_endif #endif +3: .endif msr elr_el1, x21 // set up the return data msr spsr_el1, x22 @@ -189,7 +207,22 @@ alternative_else_nop_endif ldp x28, x29, [sp, #16 * 14] ldr lr, [sp, #S_LR] add sp, sp, #S_FRAME_SIZE // restore sp - eret // return to kernel + +#ifndef CONFIG_UNMAP_KERNEL_AT_EL0 + eret +#else + .if \el == 0 + bne 4f + msr far_el1, x30 + tramp_alias x30, tramp_exit_native + br x30 +4: + tramp_alias x30, tramp_exit_compat + br x30 + .else + eret + .endif +#endif .endm .macro get_thread_info, rd -- GitLab From 6e7fb7cc6bc4053382477f64322251717d110d83 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:08 +0100 Subject: [PATCH 0936/1834] arm64: tls: Avoid unconditional zeroing of tpidrro_el0 for native tasks commit 18011eac28c7 upstream. When unmapping the kernel at EL0, we use tpidrro_el0 as a scratch register during exception entry from native tasks and subsequently zero it in the kernel_ventry macro. We can therefore avoid zeroing tpidrro_el0 in the context-switch path for native tasks using the entry trampoline. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/process.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 0e7394915c70..0972ce58316d 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -306,17 +306,17 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, static void tls_thread_switch(struct task_struct *next) { - unsigned long tpidr, tpidrro; + unsigned long tpidr; tpidr = read_sysreg(tpidr_el0); *task_user_tls(current) = tpidr; - tpidr = *task_user_tls(next); - tpidrro = is_compat_thread(task_thread_info(next)) ? - next->thread.tp_value : 0; + if (is_compat_thread(task_thread_info(next))) + write_sysreg(next->thread.tp_value, tpidrro_el0); + else if (!arm64_kernel_unmapped_at_el0()) + write_sysreg(0, tpidrro_el0); - write_sysreg(tpidr, tpidr_el0); - write_sysreg(tpidrro, tpidrro_el0); + write_sysreg(*task_user_tls(next), tpidr_el0); } /* Restore the UAO state depending on next's addr_limit */ -- GitLab From bfca15762de353a87ebca2fe39ff6d769cebf0b2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:09 +0100 Subject: [PATCH 0937/1834] arm64: entry: Add fake CPU feature for unmapping the kernel at EL0 commit ea1e3de85e94 upstream. Allow explicit disabling of the entry trampoline on the kernel command line (kpti=off) by adding a fake CPU feature (ARM64_UNMAP_KERNEL_AT_EL0) that can be used to toggle the alternative sequences in our entry code and avoid use of the trampoline altogether if desired. This also allows us to make use of a static key in arm64_kernel_unmapped_at_el0(). Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon [Alex: use first free cpucap number, use cpus_have_cap] Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cpucaps.h | 3 ++- arch/arm64/include/asm/mmu.h | 3 ++- arch/arm64/kernel/cpufeature.c | 41 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/entry.S | 9 +++---- 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index 87b446535185..7ddf233f05bd 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -34,7 +34,8 @@ #define ARM64_HAS_32BIT_EL0 13 #define ARM64_HYP_OFFSET_LOW 14 #define ARM64_MISMATCHED_CACHE_LINE_SIZE 15 +#define ARM64_UNMAP_KERNEL_AT_EL0 16 -#define ARM64_NCAPS 16 +#define ARM64_NCAPS 17 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 279e75b8a49e..a813edf28737 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -34,7 +34,8 @@ typedef struct { static inline bool arm64_kernel_unmapped_at_el0(void) { - return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0); + return IS_ENABLED(CONFIG_UNMAP_KERNEL_AT_EL0) && + cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); } extern void paging_init(void); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 3a129d48674e..74b168c51abd 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -746,6 +746,40 @@ static bool hyp_offset_low(const struct arm64_cpu_capabilities *entry, return idmap_addr > GENMASK(VA_BITS - 2, 0) && !is_kernel_in_hyp_mode(); } +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ + +static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, + int __unused) +{ + /* Forced on command line? */ + if (__kpti_forced) { + pr_info_once("kernel page table isolation forced %s by command line option\n", + __kpti_forced > 0 ? "ON" : "OFF"); + return __kpti_forced > 0; + } + + /* Useful for KASLR robustness */ + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) + return true; + + return false; +} + +static int __init parse_kpti(char *str) +{ + bool enabled; + int ret = strtobool(str, &enabled); + + if (ret) + return ret; + + __kpti_forced = enabled ? 1 : -1; + return 0; +} +__setup("kpti=", parse_kpti); +#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -829,6 +863,13 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .def_scope = SCOPE_SYSTEM, .matches = hyp_offset_low, }, +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + { + .capability = ARM64_UNMAP_KERNEL_AT_EL0, + .def_scope = SCOPE_SYSTEM, + .matches = unmap_kernel_at_el0, + }, +#endif {}, }; diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 623c160bf68e..b16d0534cda3 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -73,6 +73,7 @@ .macro kernel_ventry, el, label, regsize = 64 .align 7 #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +alternative_if ARM64_UNMAP_KERNEL_AT_EL0 .if \el == 0 .if \regsize == 64 mrs x30, tpidrro_el0 @@ -81,6 +82,7 @@ mov x30, xzr .endif .endif +alternative_else_nop_endif #endif sub sp, sp, #S_FRAME_SIZE @@ -208,10 +210,9 @@ alternative_else_nop_endif ldr lr, [sp, #S_LR] add sp, sp, #S_FRAME_SIZE // restore sp -#ifndef CONFIG_UNMAP_KERNEL_AT_EL0 - eret -#else .if \el == 0 +alternative_insn eret, nop, ARM64_UNMAP_KERNEL_AT_EL0 +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 bne 4f msr far_el1, x30 tramp_alias x30, tramp_exit_native @@ -219,10 +220,10 @@ alternative_else_nop_endif 4: tramp_alias x30, tramp_exit_compat br x30 +#endif .else eret .endif -#endif .endm .macro get_thread_info, rd -- GitLab From 96750422f84e74dfac4e4572fd9fa9fc274d5dc5 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:10 +0100 Subject: [PATCH 0938/1834] arm64: kaslr: Put kernel vectors address in separate data page commit 6c27c4082f4f upstream. The literal pool entry for identifying the vectors base is the only piece of information in the trampoline page that identifies the true location of the kernel. This patch moves it into a page-aligned region of the .rodata section and maps this adjacent to the trampoline text via an additional fixmap entry, which protects against any accidental leakage of the trampoline contents. Suggested-by: Ard Biesheuvel Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon [Alex: avoid ARM64_WORKAROUND_QCOM_FALKOR_E1003 dependency] Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/fixmap.h | 1 + arch/arm64/kernel/entry.S | 14 ++++++++++++++ arch/arm64/kernel/vmlinux.lds.S | 5 ++++- arch/arm64/mm/mmu.c | 10 +++++++++- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index 7b1d88c18143..d8e58051f32d 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -53,6 +53,7 @@ enum fixed_addresses { FIX_TEXT_POKE0, #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + FIX_ENTRY_TRAMP_DATA, FIX_ENTRY_TRAMP_TEXT, #define TRAMP_VALIAS (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT)) #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index b16d0534cda3..805dc76517c3 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -881,7 +881,13 @@ __ni_sys_trace: msr tpidrro_el0, x30 // Restored in kernel_ventry .endif tramp_map_kernel x30 +#ifdef CONFIG_RANDOMIZE_BASE + adr x30, tramp_vectors + PAGE_SIZE + isb + ldr x30, [x30] +#else ldr x30, =vectors +#endif prfm plil1strm, [x30, #(1b - tramp_vectors)] msr vbar_el1, x30 add x30, x30, #(1b - tramp_vectors) @@ -924,6 +930,14 @@ END(tramp_exit_compat) .ltorg .popsection // .entry.tramp.text +#ifdef CONFIG_RANDOMIZE_BASE + .pushsection ".rodata", "a" + .align PAGE_SHIFT + .globl __entry_tramp_data_start +__entry_tramp_data_start: + .quad vectors + .popsection // .rodata +#endif /* CONFIG_RANDOMIZE_BASE */ #endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ /* diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S index 466a43adec9f..6a584558b29d 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -252,7 +252,10 @@ ASSERT(__idmap_text_end - (__idmap_text_start & ~(SZ_4K - 1)) <= SZ_4K, ASSERT(__hibernate_exit_text_end - (__hibernate_exit_text_start & ~(SZ_4K - 1)) <= SZ_4K, "Hibernate exit text too big or misaligned") #endif - +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 +ASSERT((__entry_tramp_text_end - __entry_tramp_text_start) == PAGE_SIZE, + "Entry trampoline text too big") +#endif /* * If padding is applied before .head.text, virt<->phys conversions will fail. */ diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 3a57fec16b32..4cd4862845cd 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -435,8 +435,16 @@ static int __init map_entry_trampoline(void) __create_pgd_mapping(tramp_pg_dir, pa_start, TRAMP_VALIAS, PAGE_SIZE, prot, pgd_pgtable_alloc, 0); - /* ...as well as the kernel page table */ + /* Map both the text and data into the kernel page table */ __set_fixmap(FIX_ENTRY_TRAMP_TEXT, pa_start, prot); + if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) { + extern char __entry_tramp_data_start[]; + + __set_fixmap(FIX_ENTRY_TRAMP_DATA, + __pa_symbol(__entry_tramp_data_start), + PAGE_KERNEL_RO); + } + return 0; } core_initcall(map_entry_trampoline); -- GitLab From f6af5324fbda14e56247c60f1fd7d6a50abe32cf Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:11 +0100 Subject: [PATCH 0939/1834] arm64: use RET instruction for exiting the trampoline commit be04a6d1126b upstream. Speculation attacks against the entry trampoline can potentially resteer the speculative instruction stream through the indirect branch and into arbitrary gadgets within the kernel. This patch defends against these attacks by forcing a misprediction through the return stack: a dummy BL instruction loads an entry into the stack, so that the predicted program flow of the subsequent RET instruction is to a branch-to-self instruction which is finally resolved as a branch to the kernel vectors with speculation suppressed. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 805dc76517c3..f35ca1e54b5a 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -880,6 +880,14 @@ __ni_sys_trace: .if \regsize == 64 msr tpidrro_el0, x30 // Restored in kernel_ventry .endif + /* + * Defend against branch aliasing attacks by pushing a dummy + * entry onto the return stack and using a RET instruction to + * enter the full-fat kernel vectors. + */ + bl 2f + b . +2: tramp_map_kernel x30 #ifdef CONFIG_RANDOMIZE_BASE adr x30, tramp_vectors + PAGE_SIZE @@ -892,7 +900,7 @@ __ni_sys_trace: msr vbar_el1, x30 add x30, x30, #(1b - tramp_vectors) isb - br x30 + ret .endm .macro tramp_exit, regsize = 64 -- GitLab From 531a0eb24fb70137714b33956cab71a26d408fcd Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:12 +0100 Subject: [PATCH 0940/1834] arm64: Kconfig: Add CONFIG_UNMAP_KERNEL_AT_EL0 commit 084eb77cd3a8 upstream. Add a Kconfig entry to control use of the entry trampoline, which allows us to unmap the kernel whilst running in userspace and improve the robustness of KASLR. Reviewed-by: Mark Rutland Tested-by: Laura Abbott Tested-by: Shanker Donthineni Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 7769c2e27788..6b6e9f89e40a 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -733,6 +733,19 @@ config FORCE_MAX_ZONEORDER However for 4K, we choose a higher default value, 11 as opposed to 10, giving us 4M allocations matching the default size used by generic code. +config UNMAP_KERNEL_AT_EL0 + bool "Unmap kernel when running in userspace (aka \"KAISER\")" + default y + help + Some attacks against KASLR make use of the timing difference between + a permission fault which could arise from a page table entry that is + present in the TLB, and a translation fault which always requires a + page table walk. This option defends against these attacks by unmapping + the kernel whilst running in userspace, therefore forcing translation + faults for all of kernel space. + + If unsure, say Y. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT -- GitLab From ded98c668a71e28a769a04051df7973cafad73f2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:13 +0100 Subject: [PATCH 0941/1834] arm64: Kconfig: Reword UNMAP_KERNEL_AT_EL0 kconfig entry commit 0617052ddde3 upstream. Although CONFIG_UNMAP_KERNEL_AT_EL0 does make KASLR more robust, it's actually more useful as a mitigation against speculation attacks that can leak arbitrary kernel data to userspace through speculation. Reword the Kconfig help message to reflect this, and make the option depend on EXPERT so that it is on by default for the majority of users. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/Kconfig | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 6b6e9f89e40a..c8471cf46cbb 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -734,15 +734,14 @@ config FORCE_MAX_ZONEORDER 4M allocations matching the default size used by generic code. config UNMAP_KERNEL_AT_EL0 - bool "Unmap kernel when running in userspace (aka \"KAISER\")" + bool "Unmap kernel when running in userspace (aka \"KAISER\")" if EXPERT default y help - Some attacks against KASLR make use of the timing difference between - a permission fault which could arise from a page table entry that is - present in the TLB, and a translation fault which always requires a - page table walk. This option defends against these attacks by unmapping - the kernel whilst running in userspace, therefore forcing translation - faults for all of kernel space. + Speculation attacks against some high-performance processors can + be used to bypass MMU permission checks and leak kernel data to + userspace. This can be defended against by unmapping the kernel + when running in userspace, mapping it back in on exception entry + via a trampoline page in the vector table. If unsure, say Y. -- GitLab From 7354772afe1bfdcabc1eb218bedf736516daff50 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:14 +0100 Subject: [PATCH 0942/1834] arm64: Take into account ID_AA64PFR0_EL1.CSV3 commit 179a56f6f9fb upstream. For non-KASLR kernels where the KPTI behaviour has not been overridden on the command line we can use ID_AA64PFR0_EL1.CSV3 to determine whether or not we should unmap the kernel whilst running at EL0. Reviewed-by: Suzuki K Poulose Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas [Alex: s/read_sanitised_ftr_reg/read_system_reg/ to match v4.9 naming] Signed-off-by: Alex Shi [v4.9 backport] [Mark: correct zero bits in ftr_id_aa64pfr0 to account for CSV3] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/sysreg.h | 1 + arch/arm64/kernel/cpufeature.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 7393cc767edb..7cb7f7cdcfbc 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -117,6 +117,7 @@ #define ID_AA64ISAR0_AES_SHIFT 4 /* id_aa64pfr0 */ +#define ID_AA64PFR0_CSV3_SHIFT 60 #define ID_AA64PFR0_GIC_SHIFT 24 #define ID_AA64PFR0_ASIMD_SHIFT 20 #define ID_AA64PFR0_FP_SHIFT 16 diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 74b168c51abd..d24e59cedae5 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -93,7 +93,8 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = { }; static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = { - ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0), + ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 28, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0), S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI), @@ -752,6 +753,8 @@ static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, int __unused) { + u64 pfr0 = read_system_reg(SYS_ID_AA64PFR0_EL1); + /* Forced on command line? */ if (__kpti_forced) { pr_info_once("kernel page table isolation forced %s by command line option\n", @@ -763,7 +766,9 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) return true; - return false; + /* Defer to CPU feature registers */ + return !cpuid_feature_extract_unsigned_field(pfr0, + ID_AA64PFR0_CSV3_SHIFT); } static int __init parse_kpti(char *str) @@ -865,6 +870,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { }, #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 { + .desc = "Kernel page table isolation (KPTI)", .capability = ARM64_UNMAP_KERNEL_AT_EL0, .def_scope = SCOPE_SYSTEM, .matches = unmap_kernel_at_el0, -- GitLab From 1d648e44e902e063f8a34c1acdd1fbe06df19cb0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 3 Apr 2018 12:09:15 +0100 Subject: [PATCH 0943/1834] arm64: Allow checking of a CPU-local erratum commit 8f4137588261d7504f4aa022dc9d1a1fd1940e8e upstream. this_cpu_has_cap() only checks the feature array, and not the errata one. In order to be able to check for a CPU-local erratum, allow it to inspect the latter as well. This is consistent with cpus_have_cap()'s behaviour, which includes errata already. Acked-by: Thomas Gleixner Acked-by: Daniel Lezcano Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index d24e59cedae5..810f8bf7c57f 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1103,20 +1103,29 @@ static void __init setup_feature_capabilities(void) * Check if the current CPU has a given feature capability. * Should be called from non-preemptible context. */ -bool this_cpu_has_cap(unsigned int cap) +static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array, + unsigned int cap) { const struct arm64_cpu_capabilities *caps; if (WARN_ON(preemptible())) return false; - for (caps = arm64_features; caps->desc; caps++) + for (caps = cap_array; caps->desc; caps++) if (caps->capability == cap && caps->matches) return caps->matches(caps, SCOPE_LOCAL_CPU); return false; } +extern const struct arm64_cpu_capabilities arm64_errata[]; + +bool this_cpu_has_cap(unsigned int cap) +{ + return (__this_cpu_has_cap(arm64_features, cap) || + __this_cpu_has_cap(arm64_errata, cap)); +} + void __init setup_cpu_features(void) { u32 cwg; -- GitLab From 1e0946de6224fd8fdea333f6523100e9625cb26e Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Tue, 3 Apr 2018 12:09:16 +0100 Subject: [PATCH 0944/1834] arm64: capabilities: Handle duplicate entries for a capability commit 67948af41f2e upstream. Sometimes a single capability could be listed multiple times with differing matches(), e.g, CPU errata for different MIDR versions. This breaks verify_local_cpu_feature() and this_cpu_has_cap() as we stop checking for a capability on a CPU with the first entry in the given table, which is not sufficient. Make sure we run the checks for all entries of the same capability. We do this by fixing __this_cpu_has_cap() to run through all the entries in the given table for a match and reuse it for verify_local_cpu_feature(). Cc: Mark Rutland Cc: Will Deacon Acked-by: Marc Zyngier Signed-off-by: Suzuki K Poulose Signed-off-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 44 ++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 810f8bf7c57f..2d7c7796cce1 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -969,6 +969,26 @@ static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps) cap_set_elf_hwcap(hwcaps); } +/* + * Check if the current CPU has a given feature capability. + * Should be called from non-preemptible context. + */ +static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array, + unsigned int cap) +{ + const struct arm64_cpu_capabilities *caps; + + if (WARN_ON(preemptible())) + return false; + + for (caps = cap_array; caps->desc; caps++) + if (caps->capability == cap && + caps->matches && + caps->matches(caps, SCOPE_LOCAL_CPU)) + return true; + return false; +} + void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, const char *info) { @@ -1037,8 +1057,9 @@ verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps) } static void -verify_local_cpu_features(const struct arm64_cpu_capabilities *caps) +verify_local_cpu_features(const struct arm64_cpu_capabilities *caps_list) { + const struct arm64_cpu_capabilities *caps = caps_list; for (; caps->matches; caps++) { if (!cpus_have_cap(caps->capability)) continue; @@ -1046,7 +1067,7 @@ verify_local_cpu_features(const struct arm64_cpu_capabilities *caps) * If the new CPU misses an advertised feature, we cannot proceed * further, park the cpu. */ - if (!caps->matches(caps, SCOPE_LOCAL_CPU)) { + if (!__this_cpu_has_cap(caps_list, caps->capability)) { pr_crit("CPU%d: missing feature: %s\n", smp_processor_id(), caps->desc); cpu_die_early(); @@ -1099,25 +1120,6 @@ static void __init setup_feature_capabilities(void) enable_cpu_capabilities(arm64_features); } -/* - * Check if the current CPU has a given feature capability. - * Should be called from non-preemptible context. - */ -static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array, - unsigned int cap) -{ - const struct arm64_cpu_capabilities *caps; - - if (WARN_ON(preemptible())) - return false; - - for (caps = cap_array; caps->desc; caps++) - if (caps->capability == cap && caps->matches) - return caps->matches(caps, SCOPE_LOCAL_CPU); - - return false; -} - extern const struct arm64_cpu_capabilities arm64_errata[]; bool this_cpu_has_cap(unsigned int cap) -- GitLab From f93aea3da223df5a79b4d103b1e4e6d30296b527 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 3 Apr 2018 12:09:17 +0100 Subject: [PATCH 0945/1834] arm64: cputype: Add MIDR values for Cavium ThunderX2 CPUs commit 0d90718871fe upstream. Add the older Broadcom ID as well as the new Cavium ID for ThunderX2 CPUs. Signed-off-by: Jayachandran C Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cputype.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 26a68ddb11c1..1d47930c30dc 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -81,6 +81,7 @@ #define CAVIUM_CPU_PART_THUNDERX 0x0A1 #define CAVIUM_CPU_PART_THUNDERX_81XX 0x0A2 +#define CAVIUM_CPU_PART_THUNDERX2 0x0AF #define BRCM_CPU_PART_VULCAN 0x516 @@ -88,6 +89,8 @@ #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) #define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX) +#define MIDR_CAVIUM_THUNDERX2 MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX2) +#define MIDR_BRCM_VULCAN MIDR_CPU_MODEL(ARM_CPU_IMP_BRCM, BRCM_CPU_PART_VULCAN) #ifndef __ASSEMBLY__ -- GitLab From 2adcb1fb389f1e4d650ecbd25b9ecace0fe5d014 Mon Sep 17 00:00:00 2001 From: Jayachandran C Date: Tue, 3 Apr 2018 12:09:18 +0100 Subject: [PATCH 0946/1834] arm64: Turn on KPTI only on CPUs that need it commit 0ba2e29c7fc1 upstream. Whitelist Broadcom Vulcan/Cavium ThunderX2 processors in unmap_kernel_at_el0(). These CPUs are not vulnerable to CVE-2017-5754 and do not need KPTI when KASLR is off. Acked-by: Will Deacon Signed-off-by: Jayachandran C Signed-off-by: Catalin Marinas Signed-off-by: Will Deacon Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 2d7c7796cce1..6015a3cac930 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -766,6 +766,13 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, if (IS_ENABLED(CONFIG_RANDOMIZE_BASE)) return true; + /* Don't force KPTI for CPUs that are not vulnerable */ + switch (read_cpuid_id() & MIDR_CPU_MODEL_MASK) { + case MIDR_CAVIUM_THUNDERX2: + case MIDR_BRCM_VULCAN: + return false; + } + /* Defer to CPU feature registers */ return !cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV3_SHIFT); -- GitLab From fefeffe1973f7a5ee57ad4b593f270747b4c784b Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:19 +0100 Subject: [PATCH 0947/1834] arm64: kpti: Make use of nG dependent on arm64_kernel_unmapped_at_el0() commit 41acec624087 upstream. To allow systems which do not require kpti to continue running with global kernel mappings (which appears to be a requirement for Cavium ThunderX due to a CPU erratum), make the use of nG in the kernel page tables dependent on arm64_kernel_unmapped_at_el0(), which is resolved at runtime. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/kernel-pgtable.h | 12 ++-------- arch/arm64/include/asm/pgtable-prot.h | 30 ++++++++++++------------- 2 files changed, 16 insertions(+), 26 deletions(-) diff --git a/arch/arm64/include/asm/kernel-pgtable.h b/arch/arm64/include/asm/kernel-pgtable.h index e4ddac983640..7e51d1b57c0c 100644 --- a/arch/arm64/include/asm/kernel-pgtable.h +++ b/arch/arm64/include/asm/kernel-pgtable.h @@ -71,16 +71,8 @@ /* * Initial memory map attributes. */ -#define _SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) -#define _SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) - -#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 -#define SWAPPER_PTE_FLAGS (_SWAPPER_PTE_FLAGS | PTE_NG) -#define SWAPPER_PMD_FLAGS (_SWAPPER_PMD_FLAGS | PMD_SECT_NG) -#else -#define SWAPPER_PTE_FLAGS _SWAPPER_PTE_FLAGS -#define SWAPPER_PMD_FLAGS _SWAPPER_PMD_FLAGS -#endif +#define SWAPPER_PTE_FLAGS (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) +#define SWAPPER_PMD_FLAGS (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) #if ARM64_SWAPPER_USES_SECTION_MAPS #define SWAPPER_MM_MMUFLAGS (PMD_ATTRINDX(MT_NORMAL) | SWAPPER_PMD_FLAGS) diff --git a/arch/arm64/include/asm/pgtable-prot.h b/arch/arm64/include/asm/pgtable-prot.h index 84b5283d2e7f..f705d96a76f2 100644 --- a/arch/arm64/include/asm/pgtable-prot.h +++ b/arch/arm64/include/asm/pgtable-prot.h @@ -37,13 +37,11 @@ #define _PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) #define _PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) -#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 -#define PROT_DEFAULT (_PROT_DEFAULT | PTE_NG) -#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_SECT_NG) -#else -#define PROT_DEFAULT _PROT_DEFAULT -#define PROT_SECT_DEFAULT _PROT_SECT_DEFAULT -#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */ +#define PTE_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PTE_NG : 0) +#define PMD_MAYBE_NG (arm64_kernel_unmapped_at_el0() ? PMD_SECT_NG : 0) + +#define PROT_DEFAULT (_PROT_DEFAULT | PTE_MAYBE_NG) +#define PROT_SECT_DEFAULT (_PROT_SECT_DEFAULT | PMD_MAYBE_NG) #define PROT_DEVICE_nGnRnE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRnE)) #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_ATTRINDX(MT_DEVICE_nGnRE)) @@ -55,22 +53,22 @@ #define PROT_SECT_NORMAL (PROT_SECT_DEFAULT | PMD_SECT_PXN | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) #define PROT_SECT_NORMAL_EXEC (PROT_SECT_DEFAULT | PMD_SECT_UXN | PMD_ATTRINDX(MT_NORMAL)) -#define _PAGE_DEFAULT (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) -#define _HYP_PAGE_DEFAULT (_PAGE_DEFAULT & ~PTE_NG) +#define _PAGE_DEFAULT (_PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL)) +#define _HYP_PAGE_DEFAULT _PAGE_DEFAULT -#define PAGE_KERNEL __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE) -#define PAGE_KERNEL_RO __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY) -#define PAGE_KERNEL_ROX __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY) -#define PAGE_KERNEL_EXEC __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE) -#define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT) +#define PAGE_KERNEL __pgprot(PROT_NORMAL) +#define PAGE_KERNEL_RO __pgprot((PROT_NORMAL & ~PTE_WRITE) | PTE_RDONLY) +#define PAGE_KERNEL_ROX __pgprot((PROT_NORMAL & ~(PTE_WRITE | PTE_PXN)) | PTE_RDONLY) +#define PAGE_KERNEL_EXEC __pgprot(PROT_NORMAL & ~PTE_PXN) +#define PAGE_KERNEL_EXEC_CONT __pgprot((PROT_NORMAL & ~PTE_PXN) | PTE_CONT) #define PAGE_HYP __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_HYP_XN) #define PAGE_HYP_EXEC __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY) #define PAGE_HYP_RO __pgprot(_HYP_PAGE_DEFAULT | PTE_HYP | PTE_RDONLY | PTE_HYP_XN) #define PAGE_HYP_DEVICE __pgprot(PROT_DEVICE_nGnRE | PTE_HYP) -#define PAGE_S2 __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY) -#define PAGE_S2_DEVICE __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN) +#define PAGE_S2 __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY) +#define PAGE_S2_DEVICE __pgprot(_PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDONLY | PTE_UXN) #define PAGE_NONE __pgprot(((_PAGE_DEFAULT) & ~PTE_VALID) | PTE_PROT_NONE | PTE_NG | PTE_PXN | PTE_UXN) #define PAGE_SHARED __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE) -- GitLab From 4025fe1291e4d0b1de6a12c4e5fa68fadd388f3d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:20 +0100 Subject: [PATCH 0948/1834] arm64: kpti: Add ->enable callback to remap swapper using nG mappings commit f992b4dfd58b upstream. Defaulting to global mappings for kernel space is generally good for performance and appears to be necessary for Cavium ThunderX. If we subsequently decide that we need to enable kpti, then we need to rewrite our existing page table entries to be non-global. This is fiddly, and made worse by the possible use of contiguous mappings, which require a strict break-before-make sequence. Since the enable callback runs on each online CPU from stop_machine context, we can have all CPUs enter the idmap, where secondaries can wait for the primary CPU to rewrite swapper with its MMU off. It's all fairly horrible, but at least it only runs once. Nicolas Dechesne found a bug on this commit which cause boot failure on db410c etc board. Ard Biesheuvel found it writting wrong contenct to ttbr1_el1 in __idmap_cpu_set_reserved_ttbr1 macro and fixed it by give it the right content. Tested-by: Marc Zyngier Reviewed-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Ard Biesheuvel [Alex: avoid dependency on 52-bit PA patches and TTBR/MMU erratum patches] Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/assembler.h | 3 + arch/arm64/kernel/cpufeature.c | 25 ++++ arch/arm64/mm/proc.S | 201 ++++++++++++++++++++++++++++- 3 files changed, 222 insertions(+), 7 deletions(-) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 851290d2bfe3..7193bf97b8da 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -413,4 +413,7 @@ alternative_endif movk \reg, :abs_g0_nc:\val .endm + .macro pte_to_phys, phys, pte + and \phys, \pte, #(((1 << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT) + .endm #endif /* __ASM_ASSEMBLER_H */ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 6015a3cac930..8d41a3f94954 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -778,6 +778,30 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, ID_AA64PFR0_CSV3_SHIFT); } +static int kpti_install_ng_mappings(void *__unused) +{ + typedef void (kpti_remap_fn)(int, int, phys_addr_t); + extern kpti_remap_fn idmap_kpti_install_ng_mappings; + kpti_remap_fn *remap_fn; + + static bool kpti_applied = false; + int cpu = smp_processor_id(); + + if (kpti_applied) + return 0; + + remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings); + + cpu_install_idmap(); + remap_fn(cpu, num_online_cpus(), __pa_symbol(swapper_pg_dir)); + cpu_uninstall_idmap(); + + if (!cpu) + kpti_applied = true; + + return 0; +} + static int __init parse_kpti(char *str) { bool enabled; @@ -881,6 +905,7 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .capability = ARM64_UNMAP_KERNEL_AT_EL0, .def_scope = SCOPE_SYSTEM, .matches = unmap_kernel_at_el0, + .enable = kpti_install_ng_mappings, }, #endif {}, diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 3378f3e21224..5c268f5767b4 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -148,6 +148,16 @@ alternative_else_nop_endif ENDPROC(cpu_do_switch_mm) .pushsection ".idmap.text", "ax" + +.macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2 + adrp \tmp1, empty_zero_page + msr ttbr1_el1, \tmp1 + isb + tlbi vmalle1 + dsb nsh + isb +.endm + /* * void idmap_cpu_replace_ttbr1(phys_addr_t new_pgd) * @@ -158,13 +168,7 @@ ENTRY(idmap_cpu_replace_ttbr1) mrs x2, daif msr daifset, #0xf - adrp x1, empty_zero_page - msr ttbr1_el1, x1 - isb - - tlbi vmalle1 - dsb nsh - isb + __idmap_cpu_set_reserved_ttbr1 x1, x3 msr ttbr1_el1, x0 isb @@ -175,6 +179,189 @@ ENTRY(idmap_cpu_replace_ttbr1) ENDPROC(idmap_cpu_replace_ttbr1) .popsection +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0 + .pushsection ".idmap.text", "ax" + + .macro __idmap_kpti_get_pgtable_ent, type + dc cvac, cur_\()\type\()p // Ensure any existing dirty + dmb sy // lines are written back before + ldr \type, [cur_\()\type\()p] // loading the entry + tbz \type, #0, next_\()\type // Skip invalid entries + .endm + + .macro __idmap_kpti_put_pgtable_ent_ng, type + orr \type, \type, #PTE_NG // Same bit for blocks and pages + str \type, [cur_\()\type\()p] // Update the entry and ensure it + dc civac, cur_\()\type\()p // is visible to all CPUs. + .endm + +/* + * void __kpti_install_ng_mappings(int cpu, int num_cpus, phys_addr_t swapper) + * + * Called exactly once from stop_machine context by each CPU found during boot. + */ +__idmap_kpti_flag: + .long 1 +ENTRY(idmap_kpti_install_ng_mappings) + cpu .req w0 + num_cpus .req w1 + swapper_pa .req x2 + swapper_ttb .req x3 + flag_ptr .req x4 + cur_pgdp .req x5 + end_pgdp .req x6 + pgd .req x7 + cur_pudp .req x8 + end_pudp .req x9 + pud .req x10 + cur_pmdp .req x11 + end_pmdp .req x12 + pmd .req x13 + cur_ptep .req x14 + end_ptep .req x15 + pte .req x16 + + mrs swapper_ttb, ttbr1_el1 + adr flag_ptr, __idmap_kpti_flag + + cbnz cpu, __idmap_kpti_secondary + + /* We're the boot CPU. Wait for the others to catch up */ + sevl +1: wfe + ldaxr w18, [flag_ptr] + eor w18, w18, num_cpus + cbnz w18, 1b + + /* We need to walk swapper, so turn off the MMU. */ + mrs x18, sctlr_el1 + bic x18, x18, #SCTLR_ELx_M + msr sctlr_el1, x18 + isb + + /* Everybody is enjoying the idmap, so we can rewrite swapper. */ + /* PGD */ + mov cur_pgdp, swapper_pa + add end_pgdp, cur_pgdp, #(PTRS_PER_PGD * 8) +do_pgd: __idmap_kpti_get_pgtable_ent pgd + tbnz pgd, #1, walk_puds + __idmap_kpti_put_pgtable_ent_ng pgd +next_pgd: + add cur_pgdp, cur_pgdp, #8 + cmp cur_pgdp, end_pgdp + b.ne do_pgd + + /* Publish the updated tables and nuke all the TLBs */ + dsb sy + tlbi vmalle1is + dsb ish + isb + + /* We're done: fire up the MMU again */ + mrs x18, sctlr_el1 + orr x18, x18, #SCTLR_ELx_M + msr sctlr_el1, x18 + isb + + /* Set the flag to zero to indicate that we're all done */ + str wzr, [flag_ptr] + ret + + /* PUD */ +walk_puds: + .if CONFIG_PGTABLE_LEVELS > 3 + pte_to_phys cur_pudp, pgd + add end_pudp, cur_pudp, #(PTRS_PER_PUD * 8) +do_pud: __idmap_kpti_get_pgtable_ent pud + tbnz pud, #1, walk_pmds + __idmap_kpti_put_pgtable_ent_ng pud +next_pud: + add cur_pudp, cur_pudp, 8 + cmp cur_pudp, end_pudp + b.ne do_pud + b next_pgd + .else /* CONFIG_PGTABLE_LEVELS <= 3 */ + mov pud, pgd + b walk_pmds +next_pud: + b next_pgd + .endif + + /* PMD */ +walk_pmds: + .if CONFIG_PGTABLE_LEVELS > 2 + pte_to_phys cur_pmdp, pud + add end_pmdp, cur_pmdp, #(PTRS_PER_PMD * 8) +do_pmd: __idmap_kpti_get_pgtable_ent pmd + tbnz pmd, #1, walk_ptes + __idmap_kpti_put_pgtable_ent_ng pmd +next_pmd: + add cur_pmdp, cur_pmdp, #8 + cmp cur_pmdp, end_pmdp + b.ne do_pmd + b next_pud + .else /* CONFIG_PGTABLE_LEVELS <= 2 */ + mov pmd, pud + b walk_ptes +next_pmd: + b next_pud + .endif + + /* PTE */ +walk_ptes: + pte_to_phys cur_ptep, pmd + add end_ptep, cur_ptep, #(PTRS_PER_PTE * 8) +do_pte: __idmap_kpti_get_pgtable_ent pte + __idmap_kpti_put_pgtable_ent_ng pte +next_pte: + add cur_ptep, cur_ptep, #8 + cmp cur_ptep, end_ptep + b.ne do_pte + b next_pmd + + /* Secondary CPUs end up here */ +__idmap_kpti_secondary: + /* Uninstall swapper before surgery begins */ + __idmap_cpu_set_reserved_ttbr1 x18, x17 + + /* Increment the flag to let the boot CPU we're ready */ +1: ldxr w18, [flag_ptr] + add w18, w18, #1 + stxr w17, w18, [flag_ptr] + cbnz w17, 1b + + /* Wait for the boot CPU to finish messing around with swapper */ + sevl +1: wfe + ldxr w18, [flag_ptr] + cbnz w18, 1b + + /* All done, act like nothing happened */ + msr ttbr1_el1, swapper_ttb + isb + ret + + .unreq cpu + .unreq num_cpus + .unreq swapper_pa + .unreq swapper_ttb + .unreq flag_ptr + .unreq cur_pgdp + .unreq end_pgdp + .unreq pgd + .unreq cur_pudp + .unreq end_pudp + .unreq pud + .unreq cur_pmdp + .unreq end_pmdp + .unreq pmd + .unreq cur_ptep + .unreq end_ptep + .unreq pte +ENDPROC(idmap_kpti_install_ng_mappings) + .popsection +#endif + /* * __cpu_setup * -- GitLab From da93510bae26c62cc6171d8cdbe177a091a1ab79 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 3 Apr 2018 12:09:21 +0100 Subject: [PATCH 0949/1834] arm64: Force KPTI to be disabled on Cavium ThunderX commit 6dc52b15c4a4 upstream. Cavium ThunderX's erratum 27456 results in a corruption of icache entries that are loaded from memory that is mapped as non-global (i.e. ASID-tagged). As KPTI is based on memory being mapped non-global, let's prevent it from kicking in if this erratum is detected. Signed-off-by: Marc Zyngier [will: Update comment] Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas [Alex: use cpus_have_cap as cpus_have_const_cap doesn't exist in v4.9] Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 8d41a3f94954..5056fc597ae9 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -753,12 +753,23 @@ static int __kpti_forced; /* 0: not forced, >0: forced on, <0: forced off */ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, int __unused) { + char const *str = "command line option"; u64 pfr0 = read_system_reg(SYS_ID_AA64PFR0_EL1); - /* Forced on command line? */ + /* + * For reasons that aren't entirely clear, enabling KPTI on Cavium + * ThunderX leads to apparent I-cache corruption of kernel text, which + * ends as well as you might imagine. Don't even try. + */ + if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_27456)) { + str = "ARM64_WORKAROUND_CAVIUM_27456"; + __kpti_forced = -1; + } + + /* Forced? */ if (__kpti_forced) { - pr_info_once("kernel page table isolation forced %s by command line option\n", - __kpti_forced > 0 ? "ON" : "OFF"); + pr_info_once("kernel page table isolation forced %s by %s\n", + __kpti_forced > 0 ? "ON" : "OFF", str); return __kpti_forced > 0; } -- GitLab From a80d8e2979f32113df09b844d5e12e771162db40 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:22 +0100 Subject: [PATCH 0950/1834] arm64: entry: Reword comment about post_ttbr_update_workaround commit f167211a93ac upstream. We don't fully understand the Cavium ThunderX erratum, but it appears that mapping the kernel as nG can lead to horrible consequences such as attempting to execute userspace from kernel context. Since kpti isn't enabled for these CPUs anyway, simplify the comment justifying the lack of post_ttbr_update_workaround in the exception trampoline. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index f35ca1e54b5a..8d1600b18562 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -861,16 +861,9 @@ __ni_sys_trace: orr \tmp, \tmp, #USER_ASID_FLAG msr ttbr1_el1, \tmp /* - * We avoid running the post_ttbr_update_workaround here because the - * user and kernel ASIDs don't have conflicting mappings, so any - * "blessing" as described in: - * - * http://lkml.kernel.org/r/56BB848A.6060603@caviumnetworks.com - * - * will not hurt correctness. Whilst this may partially defeat the - * point of using split ASIDs in the first place, it avoids - * the hit of invalidating the entire I-cache on every return to - * userspace. + * We avoid running the post_ttbr_update_workaround here because + * it's only needed by Cavium ThunderX, which requires KPTI to be + * disabled. */ .endm -- GitLab From 574e44dc36676a13af084a9d5f42cc71a59b8066 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Apr 2018 12:09:23 +0100 Subject: [PATCH 0951/1834] arm64: idmap: Use "awx" flags for .idmap.text .pushsection directives commit 439e70e27a51 upstream. The identity map is mapped as both writeable and executable by the SWAPPER_MM_MMUFLAGS and this is relied upon by the kpti code to manage a synchronisation flag. Update the .pushsection flags to reflect the actual mapping attributes. Reported-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Alex Shi [v4.9 backport] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Will Deacon Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpu-reset.S | 2 +- arch/arm64/kernel/head.S | 2 +- arch/arm64/kernel/sleep.S | 2 +- arch/arm64/mm/proc.S | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/cpu-reset.S b/arch/arm64/kernel/cpu-reset.S index 65f42d257414..f736a6f81ecd 100644 --- a/arch/arm64/kernel/cpu-reset.S +++ b/arch/arm64/kernel/cpu-reset.S @@ -16,7 +16,7 @@ #include .text -.pushsection .idmap.text, "ax" +.pushsection .idmap.text, "awx" /* * __cpu_soft_restart(el2_switch, entry, arg0, arg1, arg2) - Helper for diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index 539bebc1222f..fa52817d84c5 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -473,7 +473,7 @@ ENDPROC(__primary_switched) * end early head section, begin head code that is also used for * hotplug and needs to have the same protections as the text region */ - .section ".idmap.text","ax" + .section ".idmap.text","awx" ENTRY(kimage_vaddr) .quad _text - TEXT_OFFSET diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 1bec41b5fda3..0030d6964e65 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -95,7 +95,7 @@ ENTRY(__cpu_suspend_enter) ret ENDPROC(__cpu_suspend_enter) - .pushsection ".idmap.text", "ax" + .pushsection ".idmap.text", "awx" ENTRY(cpu_resume) bl el2_setup // if in EL2 drop to EL1 cleanly bl __cpu_setup diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 5c268f5767b4..c07d9cc057e6 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -83,7 +83,7 @@ ENDPROC(cpu_do_suspend) * * x0: Address of context pointer */ - .pushsection ".idmap.text", "ax" + .pushsection ".idmap.text", "awx" ENTRY(cpu_do_resume) ldp x2, x3, [x0] ldp x4, x5, [x0, #16] @@ -147,7 +147,7 @@ alternative_else_nop_endif ret ENDPROC(cpu_do_switch_mm) - .pushsection ".idmap.text", "ax" + .pushsection ".idmap.text", "awx" .macro __idmap_cpu_set_reserved_ttbr1, tmp1, tmp2 adrp \tmp1, empty_zero_page @@ -180,7 +180,7 @@ ENDPROC(idmap_cpu_replace_ttbr1) .popsection #ifdef CONFIG_UNMAP_KERNEL_AT_EL0 - .pushsection ".idmap.text", "ax" + .pushsection ".idmap.text", "awx" .macro __idmap_kpti_get_pgtable_ent, type dc cvac, cur_\()\type\()p // Ensure any existing dirty @@ -368,7 +368,7 @@ ENDPROC(idmap_kpti_install_ng_mappings) * Initialise the processor for turning the MMU on. Return in x0 the * value of the SCTLR_EL1 register. */ - .pushsection ".idmap.text", "ax" + .pushsection ".idmap.text", "awx" ENTRY(__cpu_setup) tlbi vmalle1 // Invalidate local TLB dsb nsh -- GitLab From 04e624e76153d65541a062d82b851e95b3eae581 Mon Sep 17 00:00:00 2001 From: Major Hayden Date: Fri, 23 Feb 2018 14:29:54 -0600 Subject: [PATCH 0952/1834] USB: serial: ftdi_sio: add RT Systems VX-8 cable commit 9608e5c0f079390473b484ef92334dfd3431bb89 upstream. This patch adds a device ID for the RT Systems cable used to program Yaesu VX-8R/VX-8DR handheld radios. It uses the main FTDI VID instead of the common RT Systems VID. Signed-off-by: Major Hayden Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0c743e4cca1e..d7e1273352c4 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -773,6 +773,7 @@ static const struct usb_device_id id_table_combined[] = { .driver_info = (kernel_ulong_t)&ftdi_NDI_device_quirk }, { USB_DEVICE(TELLDUS_VID, TELLDUS_TELLSTICK_PID) }, { USB_DEVICE(NOVITUS_VID, NOVITUS_BONO_E_PID) }, + { USB_DEVICE(FTDI_VID, RTSYSTEMS_USB_VX8_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_S03_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_59_PID) }, { USB_DEVICE(RTSYSTEMS_VID, RTSYSTEMS_USB_57A_PID) }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 543d2801632b..a154b922ede8 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -922,6 +922,9 @@ /* * RT Systems programming cables for various ham radios */ +/* This device uses the VID of FTDI */ +#define RTSYSTEMS_USB_VX8_PID 0x9e50 /* USB-VX8 USB to 7 pin modular plug for Yaesu VX-8 radio */ + #define RTSYSTEMS_VID 0x2100 /* Vendor ID */ #define RTSYSTEMS_USB_S03_PID 0x9001 /* RTS-03 USB to Serial Adapter */ #define RTSYSTEMS_USB_59_PID 0x9e50 /* USB-59 USB to 8 pin plug */ -- GitLab From 6424b64c8a6dcf505242b18286dce5d0931c6ee4 Mon Sep 17 00:00:00 2001 From: Clemens Werther Date: Fri, 16 Mar 2018 10:20:46 +0100 Subject: [PATCH 0953/1834] USB: serial: ftdi_sio: add support for Harman FirmwareHubEmulator commit 6555ad13a01952c16485c82a52ad1f3e07e34b3a upstream. Add device id for Harman FirmwareHubEmulator to make the device auto-detectable by the driver. Signed-off-by: Clemens Werther Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 1 + drivers/usb/serial/ftdi_sio_ids.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d7e1273352c4..71cbc6890ac4 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -936,6 +936,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_LS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCIENCESCOPE_HS_LOGBOOK_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CINTERION_MC55I_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_FHE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_DOTEC_PID) }, { USB_DEVICE(QIHARDWARE_VID, MILKYMISTONE_JTAGSERIAL_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index a154b922ede8..76a10b222ff9 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1443,6 +1443,12 @@ */ #define FTDI_CINTERION_MC55I_PID 0xA951 +/* + * Product: FirmwareHubEmulator + * Manufacturer: Harman Becker Automotive Systems + */ +#define FTDI_FHE_PID 0xA9A0 + /* * Product: Comet Caller ID decoder * Manufacturer: Crucible Technologies -- GitLab From f213d151e8927d3486a0a21e7031179a358e52bf Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 6 Mar 2018 09:32:43 +0100 Subject: [PATCH 0954/1834] USB: serial: cp210x: add ELDAT Easywave RX09 id commit 1f1e82f74c0947e40144688c9e36abe4b3999f49 upstream. Add device id for ELDAT Easywave RX09 tranceiver. Reported-by: Jan Jansen Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 3178d8afb3e6..cab80acace4e 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -152,6 +152,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x12B8, 0xEC62) }, /* Link G4+ ECU */ { USB_DEVICE(0x13AD, 0x9999) }, /* Baltech card reader */ { USB_DEVICE(0x1555, 0x0004) }, /* Owen AC4 USB-RS485 Converter */ + { USB_DEVICE(0x155A, 0x1006) }, /* ELDAT Easywave RX09 */ { USB_DEVICE(0x166A, 0x0201) }, /* Clipsal 5500PACA C-Bus Pascal Automation Controller */ { USB_DEVICE(0x166A, 0x0301) }, /* Clipsal 5800PC C-Bus Wireless PC Interface */ { USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */ -- GitLab From 666dc4c8378f77b9815fd8b317339f22025bcc3c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 27 Feb 2018 16:21:05 +0000 Subject: [PATCH 0955/1834] mei: remove dev_err message on an unsupported ioctl commit bb0829a741792b56c908d7745bc0b2b540293bcc upstream. Currently the driver spams the kernel log on unsupported ioctls which is unnecessary as the ioctl returns -ENOIOCTLCMD to indicate this anyway. I suspect this was originally for debugging purposes but it really is not required so remove it. Signed-off-by: Colin Ian King Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index 41f318631c6d..60f5a8ded8dd 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -551,7 +551,6 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) break; default: - dev_err(dev->dev, ": unsupported ioctl %d.\n", cmd); rets = -ENOIOCTLCMD; } -- GitLab From 50cd7759a34104c3acb510e644355d4ae8010851 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 8 Jan 2018 09:21:07 -0500 Subject: [PATCH 0956/1834] media: usbtv: prevent double free in error case commit 50e7044535537b2a54c7ab798cd34c7f6d900bd2 upstream. Quoting the original report: It looks like there is a double-free vulnerability in Linux usbtv driver on an error path of usbtv_probe function. When audio registration fails, usbtv_video_free function ends up freeing usbtv data structure, which gets freed the second time under usbtv_video_fail label. usbtv_audio_fail: usbtv_video_free(usbtv); => v4l2_device_put(&usbtv->v4l2_dev); => v4l2_device_put => kref_put => v4l2_device_release => usbtv_release (CALLBACK) => kfree(usbtv) (1st time) usbtv_video_fail: usb_set_intfdata(intf, NULL); usb_put_dev(usbtv->udev); kfree(usbtv); (2nd time) So, as we have refcounting, use it Reported-by: Yavuz, Tuba Signed-off-by: Oliver Neukum CC: stable@vger.kernel.org Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/usb/usbtv/usbtv-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 0324633ede42..e56a49a5e8b1 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -109,6 +109,8 @@ static int usbtv_probe(struct usb_interface *intf, return 0; usbtv_audio_fail: + /* we must not free at this point */ + usb_get_dev(usbtv->udev); usbtv_video_free(usbtv); usbtv_video_fail: -- GitLab From 5104b330e75be2fafd65e4affdd2c70691677817 Mon Sep 17 00:00:00 2001 From: Alexander Gerasiov Date: Sun, 4 Feb 2018 02:50:22 +0300 Subject: [PATCH 0957/1834] parport_pc: Add support for WCH CH382L PCI-E single parallel port card. commit 823f7923833c6cc2b16e601546d607dcfb368004 upstream. WCH CH382L is a PCI-E adapter with 1 parallel port. It is similair to CH382 but serial ports are not soldered on board. Detected as Serial controller: Device 1c00:3050 (rev 10) (prog-if 05 [16850]) Signed-off-by: Alexander Gerasiov Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/parport/parport_pc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 78530d1714dc..bdce0679674c 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2646,6 +2646,7 @@ enum parport_pc_pci_cards { netmos_9901, netmos_9865, quatech_sppxp100, + wch_ch382l, }; @@ -2708,6 +2709,7 @@ static struct parport_pc_pci { /* netmos_9901 */ { 1, { { 0, -1 }, } }, /* netmos_9865 */ { 1, { { 0, -1 }, } }, /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, + /* wch_ch382l */ { 1, { { 2, -1 }, } }, }; static const struct pci_device_id parport_pc_pci_tbl[] = { @@ -2797,6 +2799,8 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { /* Quatech SPPXP-100 Parallel port PCI ExpressCard */ { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, + /* WCH CH382L PCI-E single parallel port card */ + { 0x1c00, 0x3050, 0x1c00, 0x3050, 0, 0, wch_ch382l }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci, parport_pc_pci_tbl); -- GitLab From 7246bf30088f570aaa87b6de6bfbe3cd7510e4c6 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 26 Mar 2018 08:53:25 +0800 Subject: [PATCH 0958/1834] crypto: ahash - Fix early termination in hash walk commit 900a081f6912a8985dc15380ec912752cb66025a upstream. When we have an unaligned SG list entry where there is no leftover aligned data, the hash walk code will incorrectly return zero as if the entire SG list has been processed. This patch fixes it by moving onto the next page instead. Reported-by: Eli Cooper Cc: Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- crypto/ahash.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crypto/ahash.c b/crypto/ahash.c index 14402ef6d826..90d73a22f129 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -91,13 +91,14 @@ int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) if (nbytes && walk->offset & alignmask && !err) { walk->offset = ALIGN(walk->offset, alignmask + 1); - walk->data += walk->offset; - nbytes = min(nbytes, ((unsigned int)(PAGE_SIZE)) - walk->offset); walk->entrylen -= nbytes; - return nbytes; + if (nbytes) { + walk->data += walk->offset; + return nbytes; + } } if (walk->flags & CRYPTO_ALG_ASYNC) -- GitLab From 27bb1e0ce8c15e175867ef25f8ac111af5b2faf1 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 19 Feb 2018 23:48:12 -0800 Subject: [PATCH 0959/1834] crypto: x86/cast5-avx - fix ECB encryption when long sg follows short one commit 8f461b1e02ed546fbd0f11611138da67fd85a30f upstream. With ecb-cast5-avx, if a 128+ byte scatterlist element followed a shorter one, then the algorithm accidentally encrypted/decrypted only 8 bytes instead of the expected 128 bytes. Fix it by setting the encryption/decryption 'fn' correctly. Fixes: c12ab20b162c ("crypto: cast5/avx - avoid using temporary stack buffers") Cc: # v3.8+ Signed-off-by: Eric Biggers Signed-off-by: Herbert Xu Signed-off-by: Greg Kroah-Hartman --- arch/x86/crypto/cast5_avx_glue.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c index 8648158f3916..f8fe11d24cde 100644 --- a/arch/x86/crypto/cast5_avx_glue.c +++ b/arch/x86/crypto/cast5_avx_glue.c @@ -66,8 +66,6 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, void (*fn)(struct cast5_ctx *ctx, u8 *dst, const u8 *src); int err; - fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way; - err = blkcipher_walk_virt(desc, walk); desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; @@ -79,6 +77,7 @@ static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, /* Process multi-block batch */ if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) { + fn = (enc) ? cast5_ecb_enc_16way : cast5_ecb_dec_16way; do { fn(ctx, wdst, wsrc); -- GitLab From baa392b075f84359c79264a2482be434313ba25d Mon Sep 17 00:00:00 2001 From: Frank Mori Hess Date: Thu, 15 Mar 2018 10:25:44 +0000 Subject: [PATCH 0960/1834] staging: comedi: ni_mio_common: ack ai fifo error interrupts. commit e1d9fc04c41840a4688ef6ce90b6dcca157ea4d7 upstream. Ack ai fifo error interrupts in interrupt handler to clear interrupt after fifo overflow. It should prevent lock-ups after the ai fifo overflows. Cc: # v4.2+ Signed-off-by: Frank Mori Hess Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/ni_mio_common.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index a574885ffba9..18c5312f7886 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -1284,6 +1284,8 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) ack |= NISTC_INTA_ACK_AI_START; if (a_status & NISTC_AI_STATUS1_STOP) ack |= NISTC_INTA_ACK_AI_STOP; + if (a_status & NISTC_AI_STATUS1_OVER) + ack |= NISTC_INTA_ACK_AI_ERR; if (ack) ni_stc_writew(dev, ack, NISTC_INTA_ACK_REG); } -- GitLab From 61981aa00364a3b52c217a3150038ecebc5abdec Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Mon, 29 Jan 2018 14:36:54 -0800 Subject: [PATCH 0961/1834] Input: ALPS - fix TrackStick detection on Thinkpad L570 and Latitude 7370 commit 567b9b549cfa1cbc202762ae97b5385c29ade1e3 upstream. The primary interface for the touchpad device in Thinkpad L570 is SMBus, so ALPS overlooked PS2 interface Firmware setting of TrackStick, and shipped with TrackStick otp bit is disabled. The address 0xD7 contains device number information, so we can identify the device by checking this value, but to access it we need to enable Command mode, and then re-enable the device. Devices shipped in Thinkpad L570 report either 0x0C or 0x1D as device numbers, if we see them we assume that the devices are DualPoints. The same issue exists on Dell Latitude 7370. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=196929 Fixes: 646580f793 ("Input: ALPS - fix multi-touch decoding on SS4 plus touchpads") Signed-off-by: Masaki Ota Tested-by: Aaron Ma Tested-by: Jonathan Liu Tested-by: Jaak Ristioja Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/alps.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index af83d2e34913..a8a96def0ba2 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -2538,13 +2538,31 @@ static int alps_update_btn_info_ss4_v2(unsigned char otp[][4], } static int alps_update_dual_info_ss4_v2(unsigned char otp[][4], - struct alps_data *priv) + struct alps_data *priv, + struct psmouse *psmouse) { bool is_dual = false; + int reg_val = 0; + struct ps2dev *ps2dev = &psmouse->ps2dev; - if (IS_SS4PLUS_DEV(priv->dev_id)) + if (IS_SS4PLUS_DEV(priv->dev_id)) { is_dual = (otp[0][0] >> 4) & 0x01; + if (!is_dual) { + /* For support TrackStick of Thinkpad L/E series */ + if (alps_exit_command_mode(psmouse) == 0 && + alps_enter_command_mode(psmouse) == 0) { + reg_val = alps_command_mode_read_reg(psmouse, + 0xD7); + } + alps_exit_command_mode(psmouse); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + + if (reg_val == 0x0C || reg_val == 0x1D) + is_dual = true; + } + } + if (is_dual) priv->flags |= ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE; @@ -2567,7 +2585,7 @@ static int alps_set_defaults_ss4_v2(struct psmouse *psmouse, alps_update_btn_info_ss4_v2(otp, priv); - alps_update_dual_info_ss4_v2(otp, priv); + alps_update_dual_info_ss4_v2(otp, priv, psmouse); return 0; } -- GitLab From 8f00faad73188d1a4d628658bbc47aafeee2f495 Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Thu, 8 Mar 2018 15:32:09 -0800 Subject: [PATCH 0962/1834] Input: i8042 - add Lenovo ThinkPad L460 to i8042 reset list commit b56af54ac78c54a519d82813836f305d7f76ef27 upstream. Reset i8042 before probing because of insufficient BIOS initialisation of the i8042 serial controller. This makes Synaptics touchpad detection possible. Without resetting the Synaptics touchpad is not detected because there are always NACK messages from AUX port. Signed-off-by: Dennis Wassenberg Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index d1051e3ce819..c92fb8532fed 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -692,6 +692,13 @@ static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "20046"), }, }, + { + /* Lenovo ThinkPad L460 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad L460"), + }, + }, { /* Clevo P650RS, 650RP6, Sager NP8152-S, and others */ .matches = { -- GitLab From 8f662f40fce81d7a5d7f0a14f6e0ab4a01321cc2 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Tue, 3 Apr 2018 10:24:34 -0700 Subject: [PATCH 0963/1834] Input: i8042 - enable MUX on Sony VAIO VGN-CS series to fix touchpad commit 04bb1719c4de94700056241d4c0fe3c1413f5aff upstream. The touch sensor buttons on Sony VAIO VGN-CS series laptops (e.g. VGN-CS31S) are a separate PS/2 device. As the MUX is disabled for all VAIO machines by the nomux blacklist, the data from touch sensor buttons and touchpad are combined. The protocol used by the buttons is probably similar to the touchpad protocol (both are Synaptics) so both devices get enabled. The controller combines the data, creating a mess which results in random button clicks, touchpad stopping working and lost sync error messages: psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 4 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: TouchPad at isa0060/serio1/input0 lost sync at byte 1 psmouse serio1: issuing reconnect request Add a new i8042_dmi_forcemux_table whitelist with VGN-CS. With MUX enabled, touch sensor buttons are detected as separate device (and left disabled as there's currently no driver), fixing all touchpad problems. Signed-off-by: Ondrej Zary Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/i8042-x86ia64io.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index c92fb8532fed..e484ea2dc787 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -530,6 +530,20 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { { } }; +static const struct dmi_system_id i8042_dmi_forcemux_table[] __initconst = { + { + /* + * Sony Vaio VGN-CS series require MUX or the touch sensor + * buttons will disturb touchpad operation + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-CS"), + }, + }, + { } +}; + /* * On some Asus laptops, just running self tests cause problems. */ @@ -1230,6 +1244,9 @@ static int __init i8042_platform_init(void) if (dmi_check_system(i8042_dmi_nomux_table)) i8042_nomux = true; + if (dmi_check_system(i8042_dmi_forcemux_table)) + i8042_nomux = false; + if (dmi_check_system(i8042_dmi_notimeout_table)) i8042_notimeout = true; -- GitLab From 4d2e98ce445b10b2f1f4f44ff096a6a9381726e1 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Mon, 29 Jan 2018 17:08:21 -0500 Subject: [PATCH 0964/1834] vt: change SGR 21 to follow the standards commit 65d9982d7e523a1a8e7c9af012da0d166f72fc56 upstream. ECMA-48 [1] (aka ISO 6429) has defined SGR 21 as "doubly underlined" since at least March 1984. The Linux kernel has treated it as SGR 22 "normal intensity" since it was added in Linux-0.96b in June 1992. Before that, it was simply ignored. Other terminal emulators have either ignored it, or treat it as double underline now. xterm for example added support in its 304 release (May 2014) [2] where it was previously ignoring it. Changing this behavior shouldn't be an issue: - It isn't a named capability in ncurses's terminfo database, so no script is using libtinfo/libcurses to look this up, or using tput to query & output the right sequence. - Any script assuming SGR 21 will reset intensity in all terminals already do not work correctly on non-Linux VTs (including running under screen/tmux/etc...). - If someone has written a script that only runs in the Linux VT, and they're using SGR 21 (instead of SGR 22), the output should still be readable. imo it's important to change this as the Linux VT's non-conformance is sometimes used as an argument for other terminal emulators to not implement SGR 21 at all, or do so incorrectly. [1]: https://www.ecma-international.org/publications/standards/Ecma-048.htm [2]: https://github.com/ThomasDickey/xterm-snapshots/commit/2fd29cb98d214cb536bcafbee00bc73b3f1eeb9d Signed-off-by: Mike Frysinger Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/vt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 68c7bb0b7991..9e1ac58e269e 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1354,6 +1354,11 @@ static void csi_m(struct vc_data *vc) case 3: vc->vc_italic = 1; break; + case 21: + /* + * No console drivers support double underline, so + * convert it to a single underline. + */ case 4: vc->vc_underline = 1; break; @@ -1389,7 +1394,6 @@ static void csi_m(struct vc_data *vc) vc->vc_disp_ctrl = 1; vc->vc_toggle_meta = 1; break; - case 21: case 22: vc->vc_intensity = 1; break; -- GitLab From 98a7f813e9c984afaf09c651b160dd3c2a66b22e Mon Sep 17 00:00:00 2001 From: Keerthy Date: Mon, 28 Nov 2016 09:31:58 +0530 Subject: [PATCH 0965/1834] Documentation: pinctrl: palmas: Add ti,palmas-powerhold-override property definition commit 0ea66f76ba17a4b229caaadd77de694111b21769 upstream. GPIO7 is configured in POWERHOLD mode which has higher priority over DEV_ON bit and keeps the PMIC supplies on even after the DEV_ON bit is turned off. This property enables driver to over ride the POWERHOLD value to GPIO7 so as to turn off the PMIC in power off scenarios. Signed-off-by: Keerthy Acked-by: Rob Herring Signed-off-by: Linus Walleij Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/pinctrl/pinctrl-palmas.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt index caf297bee1fb..c28d4eb83b76 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-palmas.txt @@ -35,6 +35,15 @@ Optional properties: - ti,palmas-enable-dvfs2: Enable DVFS2. Configure pins for DVFS2 mode. Selection primary or secondary function associated to GPADC_START and SYSEN2 pin/pad for DVFS2 interface +- ti,palmas-override-powerhold: This is applicable for PMICs for which + GPIO7 is configured in POWERHOLD mode which has higher priority + over DEV_ON bit and keeps the PMIC supplies on even after the DEV_ON + bit is turned off. This property enables driver to over ride the + POWERHOLD value to GPIO7 so as to turn off the PMIC in power off + scenarios. So for GPIO7 if ti,palmas-override-powerhold is set + then the GPIO_7 field should never be muxed to anything else. + It should be set to POWERHOLD by default and only in case of + power off scenarios the driver will over ride the mux value. This binding uses the following generic properties as defined in pinctrl-bindings.txt: -- GitLab From 4cae986d2b5eb5cbe43f02688e495684f068da0a Mon Sep 17 00:00:00 2001 From: Keerthy Date: Thu, 13 Apr 2017 10:21:21 +0530 Subject: [PATCH 0966/1834] ARM: dts: dra7: Add power hold and power controller properties to palmas commit 7c62de5f3fc92291decc0dac5f36949bdc3fb575 upstream. Add power hold and power controller properties to palmas node. This is needed to shutdown pmic correctly on boards with powerhold set. Signed-off-by: Keerthy Signed-off-by: Tony Lindgren Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/dra7-evm.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts index 132f2be10889..56311fd34f81 100644 --- a/arch/arm/boot/dts/dra7-evm.dts +++ b/arch/arm/boot/dts/dra7-evm.dts @@ -398,6 +398,8 @@ tps659038: tps659038@58 { compatible = "ti,tps659038"; reg = <0x58>; + ti,palmas-override-powerhold; + ti,system-power-controller; tps659038_pmic { compatible = "ti,tps659038-pmic"; -- GitLab From e284effe33905be28268bebe6d0c7de3d5283a2f Mon Sep 17 00:00:00 2001 From: Keerthy Date: Thu, 10 Nov 2016 10:39:19 +0530 Subject: [PATCH 0967/1834] ARM: dts: am57xx-beagle-x15-common: Add overide powerhold property commit 1f166499ce006b3770a3166122eda64e160736ab upstream. The PMICs have POWERHOLD set by default which prevents PMIC shutdown even on DEV_CTRL On bit set to 0 as the Powerhold has higher priority. So to enable pmic power off this property lets one over ride the default value and enable pmic power off. Signed-off-by: Keerthy Signed-off-by: Tony Lindgren Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi index 6df7829a2c15..78bee26361f1 100644 --- a/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi +++ b/arch/arm/boot/dts/am57xx-beagle-x15-common.dtsi @@ -204,6 +204,7 @@ interrupt-controller; ti,system-power-controller; + ti,palmas-override-powerhold; tps659038_pmic { compatible = "ti,tps659038-pmic"; -- GitLab From afda607daa76f3991ca256b9e10ee4a3727ca8cd Mon Sep 17 00:00:00 2001 From: Keerthy Date: Thu, 10 Nov 2016 10:39:20 +0530 Subject: [PATCH 0968/1834] ARM: dts: am57xx-idk-common: Add overide powerhold property commit 8804755bfb1f3cbc003e4ebe99eac491672f354c upstream. The PMICs have POWERHOLD set by default which prevents PMIC shutdown even on DEV_CTRL On bit set to 0 as the Powerhold has higher priority. So to enable pmic power off this property lets one over ride the default value and enable pmic power off. Signed-off-by: Keerthy Signed-off-by: Tony Lindgren Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am57xx-idk-common.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/am57xx-idk-common.dtsi b/arch/arm/boot/dts/am57xx-idk-common.dtsi index db858fff4e18..1cc62727e43a 100644 --- a/arch/arm/boot/dts/am57xx-idk-common.dtsi +++ b/arch/arm/boot/dts/am57xx-idk-common.dtsi @@ -57,6 +57,7 @@ #interrupt-cells = <2>; interrupt-controller; ti,system-power-controller; + ti,palmas-override-powerhold; tps659038_pmic { compatible = "ti,tps659038-pmic"; -- GitLab From 4e4321c232c75230bd1579eba6c5b3f54571328d Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Thu, 6 Apr 2017 09:12:18 +0800 Subject: [PATCH 0969/1834] md/raid10: reset the 'first' at the end of loop commit 6f287ca6046edd34ed83aafb7f9033c9c2e809e2 upstream. We need to set "first = 0' at the end of rdev_for_each loop, so we can get the array's min_offset_diff correctly otherwise min_offset_diff just means the last rdev's offset diff. [only the first chunk, due to b506335e5d2b ("md/raid10: skip spare disk as 'first' disk") being already applied - gregkh] Suggested-by: NeilBrown Signed-off-by: Guoqing Jiang Reviewed-by: NeilBrown Signed-off-by: Shaohua Li Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid10.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 18a4271bf569..6a7b9b1dcfe3 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -3681,6 +3681,7 @@ static int raid10_run(struct mddev *mddev) if (blk_queue_discard(bdev_get_queue(rdev->bdev))) discard_supported = true; + first = 0; } if (mddev->queue) { -- GitLab From 83216cbbfda8c7091fffa8260e4436355f1d49a7 Mon Sep 17 00:00:00 2001 From: Matthias Brugger Date: Thu, 15 Mar 2018 17:54:20 +0100 Subject: [PATCH 0970/1834] net: hns: Fix ethtool private flags commit d61d263c8d82db7c4404a29ebc29674b1c0c05c9 upstream. The driver implementation returns support for private flags, while no private flags are present. When asked for the number of private flags it returns the number of statistic flag names. Fix this by returning EOPNOTSUPP for not implemented ethtool flags. Signed-off-by: Matthias Brugger Signed-off-by: David S. Miller Cc: Ben Hutchings Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c | 2 +- drivers/net/ethernet/hisilicon/hns/hns_ethtool.c | 4 +++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c index 34b5e699a1d5..02a03bccde7b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_gmac.c @@ -671,7 +671,7 @@ static void hns_gmac_get_strings(u32 stringset, u8 *data) static int hns_gmac_get_sset_count(int stringset) { - if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) + if (stringset == ETH_SS_STATS) return ARRAY_SIZE(g_gmac_stats_string); return 0; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c index 4ecb809785f9..6ea872287307 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_ppe.c @@ -422,7 +422,7 @@ void hns_ppe_update_stats(struct hns_ppe_cb *ppe_cb) int hns_ppe_get_sset_count(int stringset) { - if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) + if (stringset == ETH_SS_STATS) return ETH_PPE_STATIC_NUM; return 0; } diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c index fbbbbffd58dc..f3be9ac47bfb 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_rcb.c @@ -798,7 +798,7 @@ void hns_rcb_get_stats(struct hnae_queue *queue, u64 *data) */ int hns_rcb_get_ring_sset_count(int stringset) { - if (stringset == ETH_SS_STATS || stringset == ETH_SS_PRIV_FLAGS) + if (stringset == ETH_SS_STATS) return HNS_RING_STATIC_REG_NUM; return 0; diff --git a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c index 86a496d71995..6be0cae44e9b 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_ethtool.c @@ -1017,8 +1017,10 @@ int hns_get_sset_count(struct net_device *netdev, int stringset) cnt--; return cnt; - } else { + } else if (stringset == ETH_SS_STATS) { return (HNS_NET_STATS_CNT + ops->get_sset_count(h, stringset)); + } else { + return -EOPNOTSUPP; } } -- GitLab From 6bae91221eea93a2a7d9a9dda22cf28c1c392db0 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 21 Mar 2018 12:49:29 -0400 Subject: [PATCH 0971/1834] Fix slab name "biovec-(1<<(21-12))" commit bd5c4facf59648581d2f1692dad7b107bf429954 upstream. I'm getting a slab named "biovec-(1<<(21-12))". It is caused by unintended expansion of the macro BIO_MAX_PAGES. This patch renames it to biovec-max. Signed-off-by: Mikulas Patocka Cc: stable@vger.kernel.org # v4.14+ Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- block/bio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/bio.c b/block/bio.c index 07f287b14cff..4f93345c6a82 100644 --- a/block/bio.c +++ b/block/bio.c @@ -42,9 +42,9 @@ * break badly! cannot be bigger than what you can fit into an * unsigned short */ -#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) } +#define BV(x, n) { .nr_vecs = x, .name = "biovec-"#n } static struct biovec_slab bvec_slabs[BVEC_POOL_NR] __read_mostly = { - BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES), + BV(1, 1), BV(4, 4), BV(16, 16), BV(64, 64), BV(128, 128), BV(BIO_MAX_PAGES, max), }; #undef BV -- GitLab From 95563efd4578250d8b85906cdab8e7dcb83d4cca Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 08:47:29 +0200 Subject: [PATCH 0972/1834] Revert "ARM: dts: am335x-pepper: Fix the audio CODEC's reset pin" This reverts commit 272b5eef085c23cd71eec30fe040fb1592682508 which was comit e153db03c6b7a035c797bcdf35262586f003ee93 upstream. It requires a driver that was not merged until 4.16, so remove it from this stable tree as it is pointless. Reported-by: Ben Hutchings Cc: Andrew F. Davis Cc: Tony Lindgren Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/am335x-pepper.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/am335x-pepper.dts b/arch/arm/boot/dts/am335x-pepper.dts index 42b62f54e4b7..30e2f8770aaf 100644 --- a/arch/arm/boot/dts/am335x-pepper.dts +++ b/arch/arm/boot/dts/am335x-pepper.dts @@ -139,7 +139,7 @@ &audio_codec { status = "okay"; - reset-gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; + gpio-reset = <&gpio1 16 GPIO_ACTIVE_LOW>; AVDD-supply = <&ldo3_reg>; IOVDD-supply = <&ldo3_reg>; DRVDD-supply = <&ldo3_reg>; -- GitLab From c201211feaa089699bc28356899ed0a6a01db8e7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 08:56:45 +0200 Subject: [PATCH 0973/1834] Revert "ARM: dts: omap3-n900: Fix the audio CODEC's reset pin" This reverts commit e5ca83f556925b86133af12ef7f17c1a52c39d7e which was commit 7be4b5dc7ffa9499ac6ef33a5ffa9ff43f9b7057 upstream. It requires a driver that was not merged until 4.16, so remove it from this stable tree as it is pointless. Reported-by: Ben Hutchings Cc: Andrew F. Davis Cc: Tony Lindgren Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/omap3-n900.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts index 6003b29c0fc0..4d448f145ed1 100644 --- a/arch/arm/boot/dts/omap3-n900.dts +++ b/arch/arm/boot/dts/omap3-n900.dts @@ -510,7 +510,7 @@ tlv320aic3x: tlv320aic3x@18 { compatible = "ti,tlv320aic3x"; reg = <0x18>; - reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ + gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ ai3x-gpio-func = < 0 /* AIC3X_GPIO1_FUNC_DISABLED */ 5 /* AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT */ @@ -527,7 +527,7 @@ tlv320aic3x_aux: tlv320aic3x@19 { compatible = "ti,tlv320aic3x"; reg = <0x19>; - reset-gpios = <&gpio2 28 GPIO_ACTIVE_LOW>; /* 60 */ + gpio-reset = <&gpio2 28 GPIO_ACTIVE_HIGH>; /* 60 */ AVDD-supply = <&vmmc2>; DRVDD-supply = <&vmmc2>; -- GitLab From 182ab70f61d18ed231ab4357bb2059a2be27f257 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 09:08:12 +0200 Subject: [PATCH 0974/1834] Revert "spi: bcm-qspi: shut up warning about cfi header inclusion" This reverts commit c30e6636ce101fd61331092c490b9d9c55b2d143. Florian writes: Sorry for noticing so late, but this appears to be bogus, there is no MTD_NORFLASH symbol being defined in 4.9, in fact I can't find this Kconfig symbol in any kernel version, so this effectively results in the driver no longer being selectable, so this sure does silence the warning. It's not good to just disable a whole driver :( So let's revert the patch for now, Arnd can work on a better build fix... Reported-by: Florian Fainelli Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/spi/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 0e7415f6d093..b7995474148c 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -156,7 +156,6 @@ config SPI_BCM63XX_HSSPI config SPI_BCM_QSPI tristate "Broadcom BSPI and MSPI controller support" depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST - depends on MTD_NORFLASH default ARCH_BCM_IPROC help Enables support for the Broadcom SPI flash and MSPI controller. -- GitLab From 39639c49bc5046b3279d8dd400defb5d32884ff3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 09:28:46 +0200 Subject: [PATCH 0975/1834] Revert "mtip32xx: use runtime tag to initialize command header" This reverts commit db54facd56a40e7766bf7f7cda1ae138e72a691c which was commit a4e84aae8139aca9fbfbced1f45c51ca81b57488 upstream. Ben writes: MQ IO schedulers were introduced in 4.11, so this shouldn't be needed in older branches. It also causes a performance regression (fixed upstream). Please revert this for 4.4 and 4.9. So let's revert it! Reported-by: Ben Hutchings Cc: Ming Lei Cc: Jens Axboe Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/block/mtip32xx/mtip32xx.c | 36 +++++++++++-------------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index b86273fdf48e..3cfd879267b2 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -169,25 +169,6 @@ static bool mtip_check_surprise_removal(struct pci_dev *pdev) return false; /* device present */ } -/* we have to use runtime tag to setup command header */ -static void mtip_init_cmd_header(struct request *rq) -{ - struct driver_data *dd = rq->q->queuedata; - struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); - u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64; - - /* Point the command headers at the command tables. */ - cmd->command_header = dd->port->command_list + - (sizeof(struct mtip_cmd_hdr) * rq->tag); - cmd->command_header_dma = dd->port->command_list_dma + - (sizeof(struct mtip_cmd_hdr) * rq->tag); - - if (host_cap_64) - cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16); - - cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF); -} - static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd) { struct request *rq; @@ -199,9 +180,6 @@ static struct mtip_cmd *mtip_get_int_command(struct driver_data *dd) if (IS_ERR(rq)) return NULL; - /* Internal cmd isn't submitted via .queue_rq */ - mtip_init_cmd_header(rq); - return blk_mq_rq_to_pdu(rq); } @@ -3833,8 +3811,6 @@ static int mtip_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *rq = bd->rq; int ret; - mtip_init_cmd_header(rq); - if (unlikely(mtip_check_unal_depth(hctx, rq))) return BLK_MQ_RQ_QUEUE_BUSY; @@ -3866,6 +3842,7 @@ static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx, { struct driver_data *dd = data; struct mtip_cmd *cmd = blk_mq_rq_to_pdu(rq); + u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64; /* * For flush requests, request_idx starts at the end of the @@ -3882,6 +3859,17 @@ static int mtip_init_cmd(void *data, struct request *rq, unsigned int hctx_idx, memset(cmd->command, 0, CMD_DMA_ALLOC_SZ); + /* Point the command headers at the command tables. */ + cmd->command_header = dd->port->command_list + + (sizeof(struct mtip_cmd_hdr) * request_idx); + cmd->command_header_dma = dd->port->command_list_dma + + (sizeof(struct mtip_cmd_hdr) * request_idx); + + if (host_cap_64) + cmd->command_header->ctbau = __force_bit2int cpu_to_le32((cmd->command_dma >> 16) >> 16); + + cmd->command_header->ctba = __force_bit2int cpu_to_le32(cmd->command_dma & 0xFFFFFFFF); + sg_init_table(cmd->sg, MTIP_MAX_SG); return 0; } -- GitLab From 0151aaf5dd738460ef2d21a5579d56df09cc4e51 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 09:45:22 +0200 Subject: [PATCH 0976/1834] Revert "ip6_vti: adjust vti mtu according to mtu of lower device" This reverts commit 1139d77d8a7f9aa6b6ae0a1c902f94775dad2f52 which is commit 53c81e95df1793933f87748d36070a721f6cb287 upstream. Ben writes that there are a number of follow-on patches needed to fix this up, but they get complex to backport, and some custom fixes are needed, so let's just revert this and wait for a "real" set of patches to resolve this to be submitted if it is really needed. Reported-by: Ben Hutchings Cc: Petr Vorel Cc: Alexey Kodanev Cc: David S. Miller Cc: Stefano Brivio Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_vti.c | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 345efeb887ef..912333586de6 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -625,7 +625,6 @@ static void vti6_link_config(struct ip6_tnl *t) { struct net_device *dev = t->dev; struct __ip6_tnl_parm *p = &t->parms; - struct net_device *tdev = NULL; memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); @@ -638,25 +637,6 @@ static void vti6_link_config(struct ip6_tnl *t) dev->flags |= IFF_POINTOPOINT; else dev->flags &= ~IFF_POINTOPOINT; - - if (p->flags & IP6_TNL_F_CAP_XMIT) { - int strict = (ipv6_addr_type(&p->raddr) & - (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); - struct rt6_info *rt = rt6_lookup(t->net, - &p->raddr, &p->laddr, - p->link, strict); - - if (rt) - tdev = rt->dst.dev; - ip6_rt_put(rt); - } - - if (!tdev && p->link) - tdev = __dev_get_by_index(t->net, p->link); - - if (tdev) - dev->mtu = max_t(int, tdev->mtu - dev->hard_header_len, - IPV6_MIN_MTU); } /** -- GitLab From bf7eb32f77e2b509942feff4bdf124a962e3ab52 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 6 Apr 2018 10:18:25 +0200 Subject: [PATCH 0977/1834] spi: davinci: fix up dma_mapping_error() incorrect patch commit aabb797b4c1204b2e8518538b2616e476f2bac92, which is commit c5a2a394835f473ae23931eda5066d3771d7b2f8 upstream had an error in it. Ben writes: The '!' needs to be deleted. This appears to have been fixed upstream by: commit 8aedbf580d21121d2a032e4c8ea12d8d2d85e275 Author: Fabien Parent Date: Thu Feb 23 19:01:56 2017 +0100 spi: davinci: Use SPI framework to handle DMA mapping which is not suitable for stable. So I'm just fixing this up directly. Reported-by: Ben Hutchings Cc: Kevin Hilman Cc: Mark Brown Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 02fb96797ac8..0d8f43a17edb 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -646,7 +646,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) buf = t->rx_buf; t->rx_dma = dma_map_single(&spi->dev, buf, t->len, DMA_FROM_DEVICE); - if (dma_mapping_error(&spi->dev, !t->rx_dma)) { + if (dma_mapping_error(&spi->dev, t->rx_dma)) { ret = -EFAULT; goto err_rx_map; } -- GitLab From d32da5bd9fd2e6eafa25c82318b55124c54d3a66 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Sun, 8 Apr 2018 12:13:01 +0200 Subject: [PATCH 0978/1834] Linux 4.9.93 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3ab3b8203bf6..f5cf4159fc20 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 92 +SUBLEVEL = 93 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From cad53e4872969876bc6fc7132cbbe90919ba2529 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Wed, 14 Mar 2018 11:55:17 -0700 Subject: [PATCH 0979/1834] msm: camera: reqmgr: Add frame drop log message Add log to indicate if for a given frame no request was applied, leading to that frame getting dropped. Change-Id: I56bc1ee11a7ce11d5c040e33642d23e38b565d58 Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 12 +++++++++++- .../msm/camera/cam_req_mgr/cam_req_mgr_core.h | 5 +++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index aaba48112821..45d81fcf06b2 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -230,7 +230,7 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) traverse_data->in_q, curr_idx); apply_data[tbl->pd].idx = curr_idx; - CAM_DBG(CAM_CRM, "req_id: %d with pd of %d", + CAM_DBG(CAM_CRM, "req_id: %lld with pd of %d", apply_data[tbl->pd].req_id, apply_data[tbl->pd].pd); /* @@ -248,6 +248,11 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) } } else { /* This pd table is not ready to proceed with asked idx */ + CAM_INFO(CAM_CRM, + "Skip Frame: req: %lld not ready pd: %d open_req count: %d", + CRM_GET_REQ_ID(traverse_data->in_q, curr_idx), + tbl->pd, + traverse_data->open_req_cnt); SET_FAILURE_BIT(traverse_data->result, tbl->pd); return -EAGAIN; } @@ -450,6 +455,9 @@ static int __cam_req_mgr_send_req(struct cam_req_mgr_core_link *link, rc = dev->ops->apply_req(&apply_req); if (rc < 0) break; + + if (pd == link->max_delay) + link->open_req_cnt--; } } } @@ -509,6 +517,7 @@ static int __cam_req_mgr_check_link_is_ready(struct cam_req_mgr_core_link *link, traverse_data.result = 0; traverse_data.validate_only = validate_only; traverse_data.self_link = self_link; + traverse_data.open_req_cnt = link->open_req_cnt; /* * Traverse through all pd tables, if result is success, * apply the settings @@ -1513,6 +1522,7 @@ int cam_req_mgr_process_sched_req(void *priv, void *data) slot->sync_mode = sched_req->sync_mode; slot->skip_idx = 0; slot->recover = sched_req->bubble_enable; + link->open_req_cnt++; __cam_req_mgr_inc_idx(&in_q->wr_idx, 1, in_q->num_slots); mutex_unlock(&link->req.lock); diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h index e15b3b0294bc..5ad23b7d7c24 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h @@ -134,6 +134,7 @@ enum cam_req_mgr_link_state { * @validate_only : Whether to validate only and/or update settings * @self_link : To indicate whether the check is for the given link or the * other sync link + * @open_req_cnt : Count of open requests yet to be serviced in the kernel. */ struct cam_req_mgr_traverse { int32_t idx; @@ -143,6 +144,7 @@ struct cam_req_mgr_traverse { struct cam_req_mgr_req_queue *in_q; bool validate_only; bool self_link; + int32_t open_req_cnt; }; /** @@ -301,6 +303,8 @@ struct cam_req_mgr_connected_device { * @sync_link_sof_skip : flag determines if a pkt is not available for a given * frame in a particular link skip corresponding * frame in sync link as well. + * @open_req_cnt : Counter to keep track of open requests that are yet + * to be serviced in the kernel. * */ struct cam_req_mgr_core_link { @@ -324,6 +328,7 @@ struct cam_req_mgr_core_link { int64_t sync_self_ref; bool frame_skip_flag; bool sync_link_sof_skip; + int32_t open_req_cnt; }; /** -- GitLab From eba1ffe631bc5e379ebce8342c287c47f4549c16 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Mon, 9 Apr 2018 13:48:49 -0700 Subject: [PATCH 0980/1834] ANDROID: arm64: mark kpti_install_ng_mappings as __nocfi 4.9.93 panics on boot when CFI_CLANG and UNMAP_KERNEL_AT_EL0 are both enabled. From Sami Tolvanen: "kpti_install_ng_mappings makes an indirect call to a physical address, which trips CFI. Adding the __nocfi attribute to this function should fix the problem." Bug: 77811249 Change-Id: I87d1ceb29f1ba2caee8954547596f4236bdfc31f Reported-by: Jean-Baptiste Theou Signed-off-by: Greg Hackmann --- arch/arm64/kernel/cpufeature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 785a54e2b6bc..08344c914c59 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -791,7 +791,7 @@ static bool unmap_kernel_at_el0(const struct arm64_cpu_capabilities *entry, ID_AA64PFR0_CSV3_SHIFT); } -static int kpti_install_ng_mappings(void *__unused) +static int __nocfi kpti_install_ng_mappings(void *__unused) { typedef void (kpti_remap_fn)(int, int, phys_addr_t); extern kpti_remap_fn idmap_kpti_install_ng_mappings; -- GitLab From 148f849c45b99840a31aeb6b23210f5030e4a635 Mon Sep 17 00:00:00 2001 From: Abhilash Kumar Date: Tue, 10 Apr 2018 11:15:58 +0530 Subject: [PATCH 0981/1834] msm: camera: icp: Add support for firmware hangdump Created debugfs entry to support firmware hangdump with three levels. The three levels are to disable the dumping of data, to enable the dump only during firmware failure and enable dump for each frame. For disabling: adb shell echo 0 > /sys/kernel/debug/camera_icp/a5_fw_dump_lvl For dump on failure: adb shell echo 1 > /sys/kernel/debug/camera_icp/a5_fw_dump_lvl For dump on each frame: adb shell echo 2 > /sys/kernel/debug/camera_icp/a5_fw_dump_lvl Change-Id: I2c6a2b92563196306bc2baded2d3316de054ecb2 Signed-off-by: Abhilash Kumar Signed-off-by: Tony Lijo Jose --- .../msm/camera/cam_icp/fw_inc/hfi_intf.h | 6 ++++ .../msm/camera/cam_icp/fw_inc/hfi_sys_defs.h | 13 +++++++ .../media/platform/msm/camera/cam_icp/hfi.c | 36 +++++++++++++++++++ .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c | 31 ++++++++++++++-- .../icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h | 2 ++ 5 files changed, 86 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h index f5567801d95f..2c364e0181e6 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_intf.h @@ -120,6 +120,12 @@ void cam_hfi_deinit(void __iomem *icp_base); */ int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl); +/** + * hfi_set_fw_dump_level() - set firmware dump level + * @lvl: level of firmware dump level + */ +int hfi_set_fw_dump_level(uint32_t lvl); + /** * hfi_enable_ipe_bps_pc() - Enable interframe pc * Host sends a command to firmware to enable interframe diff --git a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h index 91190b6fa420..311886ffd6da 100644 --- a/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h +++ b/drivers/media/platform/msm/camera/cam_icp/fw_inc/hfi_sys_defs.h @@ -160,6 +160,7 @@ #define HFI_PROP_SYS_IMAGE_VER (HFI_PROPERTY_ICP_COMMON_START + 0x3) #define HFI_PROP_SYS_SUPPORTED (HFI_PROPERTY_ICP_COMMON_START + 0x4) #define HFI_PROP_SYS_IPEBPS_PC (HFI_PROPERTY_ICP_COMMON_START + 0x5) +#define HFI_PROP_SYS_FW_DUMP_CFG (HFI_PROPERTY_ICP_COMMON_START + 0x8) /* Capabilities reported at sys init */ #define HFI_CAPS_PLACEHOLDER_1 (HFI_COMMON_BASE + 0x1) @@ -180,6 +181,18 @@ /* Disable ARM9 watchdog. */ #define HFI_DEBUG_CFG_ARM9WD 0x10000000 + +/* + * HFI_FW_DUMP levels + * HFI_FW_DUMP_xx + */ +#define HFI_FW_DUMP_DISABLED 0x00000000 +#define HFI_FW_DUMP_ON_FAILURE 0x00000001 +#define HFI_FW_DUMP_ALWAYS 0x00000002 + +/* Number of available dump levels. */ +#define NUM_HFI_DUMP_LVL 0x00000003 + /* Debug Msg Communication types: * Section describes different modes (HFI_DEBUG_MODE_X) * available to communicate the debug messages diff --git a/drivers/media/platform/msm/camera/cam_icp/hfi.c b/drivers/media/platform/msm/camera/cam_icp/hfi.c index b75719b78c82..a0752f596c96 100644 --- a/drivers/media/platform/msm/camera/cam_icp/hfi.c +++ b/drivers/media/platform/msm/camera/cam_icp/hfi.c @@ -324,6 +324,42 @@ int hfi_set_debug_level(u64 a5_dbg_type, uint32_t lvl) return 0; } +int hfi_set_fw_dump_level(uint32_t lvl) +{ + uint8_t *prop = NULL; + struct hfi_cmd_prop *fw_dump_level_switch_prop = NULL; + uint32_t size = 0; + + CAM_DBG(CAM_HFI, "fw dump ENTER"); + + size = sizeof(struct hfi_cmd_prop) + sizeof(lvl); + prop = kzalloc(size, GFP_KERNEL); + if (!prop) + return -ENOMEM; + + fw_dump_level_switch_prop = (struct hfi_cmd_prop *)prop; + fw_dump_level_switch_prop->size = size; + fw_dump_level_switch_prop->pkt_type = HFI_CMD_SYS_SET_PROPERTY; + fw_dump_level_switch_prop->num_prop = 1; + fw_dump_level_switch_prop->prop_data[0] = HFI_PROP_SYS_FW_DUMP_CFG; + fw_dump_level_switch_prop->prop_data[1] = lvl; + + CAM_DBG(CAM_HFI, "prop->size = %d\n" + "prop->pkt_type = %d\n" + "prop->num_prop = %d\n" + "prop->prop_data[0] = %d\n" + "prop->prop_data[1] = %d\n", + fw_dump_level_switch_prop->size, + fw_dump_level_switch_prop->pkt_type, + fw_dump_level_switch_prop->num_prop, + fw_dump_level_switch_prop->prop_data[0], + fw_dump_level_switch_prop->prop_data[1]); + + hfi_write_cmd(prop); + kfree(prop); + return 0; +} + void hfi_send_system_cmd(uint32_t type, uint64_t data, uint32_t size) { switch (type) { diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index ba4385f5ca02..1c36664147e3 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -1285,6 +1285,22 @@ static int cam_icp_get_a5_dbg_type(void *data, u64 *val) DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_type_fs, cam_icp_get_a5_dbg_type, cam_icp_set_a5_dbg_type, "%08llu"); +static int cam_icp_set_a5_fw_dump_lvl(void *data, u64 val) +{ + if (val < NUM_HFI_DUMP_LVL) + icp_hw_mgr.a5_fw_dump_lvl = val; + return 0; +} + +static int cam_icp_get_a5_fw_dump_lvl(void *data, u64 *val) +{ + *val = icp_hw_mgr.a5_fw_dump_lvl; + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(cam_icp_debug_fw_dump, cam_icp_get_a5_fw_dump_lvl, + cam_icp_set_a5_fw_dump_lvl, "%08llu"); + static int cam_icp_hw_mgr_create_debugfs_entry(void) { int rc = 0; @@ -1335,7 +1351,7 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) 0644, icp_hw_mgr.dentry, NULL, &cam_icp_debug_type_fs)) { - CAM_ERR(CAM_ICP, "failed to create a5_debug_type\n"); + CAM_ERR(CAM_ICP, "failed to create a5_debug_type"); rc = -ENOMEM; goto err; } @@ -1344,7 +1360,16 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void) 0644, icp_hw_mgr.dentry, NULL, &cam_icp_debug_fs)) { - CAM_ERR(CAM_ICP, "failed to create a5_dbg_lvl\n"); + CAM_ERR(CAM_ICP, "failed to create a5_dbg_lvl"); + rc = -ENOMEM; + goto err; + } + + if (!debugfs_create_file("a5_fw_dump_lvl", + 0644, + icp_hw_mgr.dentry, + NULL, &cam_icp_debug_fw_dump)) { + CAM_ERR(CAM_ICP, "failed to create a5_fw_dump_lvl"); rc = -ENOMEM; goto err; } @@ -3866,6 +3891,8 @@ static int cam_icp_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) hfi_set_debug_level(icp_hw_mgr.a5_debug_type, icp_hw_mgr.a5_dbg_lvl); + hfi_set_fw_dump_level(icp_hw_mgr.a5_fw_dump_lvl); + rc = cam_icp_send_ubwc_cfg(hw_mgr); if (rc) goto ubwc_cfg_failed; diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index c94550d770b1..8746ee264f31 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h @@ -279,6 +279,7 @@ struct cam_icp_clk_info { * @a5_jtag_debug: entry to enable A5 JTAG debugging * @a5_debug_type : entry to enable FW debug message/qdss * @a5_dbg_lvl : debug level set to FW. + * @a5_fw_dump_lvl : level set for dumping the FW data * @ipe0_enable: Flag for IPE0 * @ipe1_enable: Flag for IPE1 * @bps_enable: Flag for BPS @@ -325,6 +326,7 @@ struct cam_icp_hw_mgr { bool a5_jtag_debug; u64 a5_debug_type; u64 a5_dbg_lvl; + u64 a5_fw_dump_lvl; bool ipe0_enable; bool ipe1_enable; bool bps_enable; -- GitLab From 71184089b8ce5e46cc5377962e04f885b86e9cbd Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Wed, 21 Jun 2017 09:22:45 +0530 Subject: [PATCH 0982/1834] ANDROID: uid_sys_stats: Replace tasklist lock with RCU in uid_cputime_show Tasklist lock is acuquired in uid_cputime_show for updating the stats for all tasks in the system. This can potentially disable preemption for several milli seconds. Replace tasklist_lock with RCU read side primitives. Change-Id: Ife69cb577bfdceaae6eb21b9bda09a0fe687e140 Signed-off-by: Pavankumar Kondeti --- drivers/misc/uid_sys_stats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/uid_sys_stats.c b/drivers/misc/uid_sys_stats.c index 0014ad5ebd3f..a940f977fe31 100644 --- a/drivers/misc/uid_sys_stats.c +++ b/drivers/misc/uid_sys_stats.c @@ -346,13 +346,13 @@ static int uid_cputime_show(struct seq_file *m, void *v) uid_entry->active_utime = 0; } - read_lock(&tasklist_lock); + rcu_read_lock(); do_each_thread(temp, task) { uid = from_kuid_munged(user_ns, task_uid(task)); if (!uid_entry || uid_entry->uid != uid) uid_entry = find_or_register_uid(uid); if (!uid_entry) { - read_unlock(&tasklist_lock); + rcu_read_unlock(); rt_mutex_unlock(&uid_lock); pr_err("%s: failed to find the uid_entry for uid %d\n", __func__, uid); @@ -362,7 +362,7 @@ static int uid_cputime_show(struct seq_file *m, void *v) uid_entry->active_utime += utime; uid_entry->active_stime += stime; } while_each_thread(temp, task); - read_unlock(&tasklist_lock); + rcu_read_unlock(); hash_for_each(hash_table, bkt, uid_entry, hash) { cputime_t total_utime = uid_entry->utime + -- GitLab From f6bec4e8c771741b44df10fed829093fb61f0d6a Mon Sep 17 00:00:00 2001 From: Vikram Mulukutla Date: Thu, 21 Sep 2017 17:24:24 -0700 Subject: [PATCH 0983/1834] Revert "ANDROID: sched/tune: Initialize raw_spin_lock in boosted_groups" This reverts commit c5616f2f874faa20b59b116177b99bf3948586df. If we re-init the per-cpu boostgroup spinlock every time that we add a new boosted cgroup, we can easily wipe out (reinit) a spinlock struct while in a critical section. We should only be setting up the per-cpu boostgroup data, and the spin_lock initialization need only happen once - which we're already doing in a postcore_initcall. For example: -------- CPU 0 -------- | -------- CPU1 -------- cgroupX boost group added | schedtune_enqueue_task | acquires(bg->lock) | cgroupY boost group added | for_each_cpu() | raw_spin_lock_init(bg->lock) releases(bg->lock) | BUG (already unlocked) | | This results in the following BUG from the debug spinlock code: BUG: spinlock already unlocked on CPU#5, rcuop/6/68 Bug: 32668852 Change-Id: I3016702780b461a0cd95e26c538cd18df27d6316 Signed-off-by: Vikram Mulukutla --- kernel/sched/tune.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/sched/tune.c b/kernel/sched/tune.c index 9be1bb0d69b1..d20f758522b8 100644 --- a/kernel/sched/tune.c +++ b/kernel/sched/tune.c @@ -647,7 +647,6 @@ schedtune_boostgroup_init(struct schedtune *st) bg = &per_cpu(cpu_boost_groups, cpu); bg->group[st->idx].boost = 0; bg->group[st->idx].tasks = 0; - raw_spin_lock_init(&bg->lock); } return 0; -- GitLab From 5e0abc2bbb8b3d8bc20e627f10663f885ef70c99 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Wed, 11 Apr 2018 18:20:19 -0700 Subject: [PATCH 0984/1834] msm: camera: isp: Use a lock when getting a payload for bus IRQs The payloads for VFE bus IRQs are saved on a list when not in use. Protect this list with a lock since the top- and bottom-halves can access this list at the same time. Change-Id: I86fb4186684de221b2bc4d070505c07988cc1b31 Signed-off-by: Vishalsingh Hajeri --- .../isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c index be4db8a9d39d..3c37b83a2256 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver2.c @@ -106,6 +106,7 @@ struct cam_vfe_bus_ver2_common_data { struct cam_vfe_bus_irq_evt_payload evt_payload[ CAM_VFE_BUS_VER2_PAYLOAD_MAX]; struct list_head free_payload_list; + spinlock_t spin_lock; struct mutex bus_mutex; uint32_t secure_mode; uint32_t num_sec_out; @@ -214,16 +215,23 @@ static int cam_vfe_bus_get_evt_payload( struct cam_vfe_bus_ver2_common_data *common_data, struct cam_vfe_bus_irq_evt_payload **evt_payload) { + int rc; + + spin_lock(&common_data->spin_lock); if (list_empty(&common_data->free_payload_list)) { *evt_payload = NULL; CAM_ERR_RATE_LIMIT(CAM_ISP, "No free payload"); - return -ENODEV; + rc = -ENODEV; + goto done; } *evt_payload = list_first_entry(&common_data->free_payload_list, struct cam_vfe_bus_irq_evt_payload, list); list_del_init(&(*evt_payload)->list); - return 0; + rc = 0; +done: + spin_unlock(&common_data->spin_lock); + return rc; } static enum cam_vfe_bus_comp_grp_id @@ -254,6 +262,7 @@ static int cam_vfe_bus_put_evt_payload(void *core_info, struct cam_vfe_bus_ver2_common_data *common_data = NULL; uint32_t *ife_irq_regs = NULL; uint32_t status_reg0, status_reg1, status_reg2; + unsigned long flags; if (!core_info) { CAM_ERR(CAM_ISP, "Invalid param core_info NULL"); @@ -276,8 +285,12 @@ static int cam_vfe_bus_put_evt_payload(void *core_info, } common_data = core_info; + + spin_lock_irqsave(&common_data->spin_lock, flags); list_add_tail(&(*evt_payload)->list, &common_data->free_payload_list); + spin_unlock_irqrestore(&common_data->spin_lock, flags); + *evt_payload = NULL; CAM_DBG(CAM_ISP, "Done"); @@ -2943,6 +2956,7 @@ int cam_vfe_bus_ver2_init( } } + spin_lock_init(&bus_priv->common_data.spin_lock); INIT_LIST_HEAD(&bus_priv->common_data.free_payload_list); for (i = 0; i < CAM_VFE_BUS_VER2_PAYLOAD_MAX; i++) { INIT_LIST_HEAD(&bus_priv->common_data.evt_payload[i].list); -- GitLab From d9197657587748e3cbcf01f32962fea765ca42f4 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 5 Jan 2018 10:44:52 -0800 Subject: [PATCH 0985/1834] f2fs/fscrypt: updates to v4.17-rc1 Pull f2fs update from Jaegeuk Kim: "In this round, we've mainly focused on performance tuning and critical bug fixes occurred in low-end devices. Sheng Yong introduced lost_found feature to keep missing files during recovery instead of thrashing them. We're preparing coming fsverity implementation. And, we've got more features to communicate with users for better performance. In low-end devices, some memory-related issues were fixed, and subtle race condtions and corner cases were addressed as well. Enhancements: - large nat bitmaps for more free node ids - add three block allocation policies to pass down write hints given by user - expose extension list to user and introduce hot file extension - tune small devices seamlessly for low-end devices - set readdir_ra by default - give more resources under gc_urgent mode regarding to discard and cleaning - introduce fsync_mode to enforce posix or not - nowait aio support - add lost_found feature to keep dangling inodes - reserve bits for future fsverity feature - add test_dummy_encryption for FBE Bug fixes: - don't use highmem for dentry pages - align memory boundary for bitops - truncate preallocated blocks in write errors - guarantee i_times on fsync call - clear CP_TRIMMED_FLAG correctly - prevent node chain loop during recovery - avoid data race between atomic write and background cleaning - avoid unnecessary selinux violation warnings on resgid option - GFP_NOFS to avoid deadlock in quota and read paths - fix f2fs_skip_inode_update to allow i_size recovery In addition to the above, there are several minor bug fixes and clean-ups" Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: ac389af190fb f2fs: remain written times to update inode during fsync 270deeb87125 f2fs: make assignment of t->dentry_bitmap more readable a4fa11c8da10 f2fs: truncate preallocated blocks in error case 4478970f0e73 f2fs: fix a wrong condition in f2fs_skip_inode_update 29cead58f5ea f2fs: reserve bits for fs-verity 848b293a5d95 f2fs: Add a segment type check in inplace write 2dc8f5a3a640 f2fs: no need to initialize zero value for GFP_F2FS_ZERO 83b9bb95a628 f2fs: don't track new nat entry in nat set a33ce03ac477 f2fs: clean up with F2FS_BLK_ALIGN a3f8ec8082e3 f2fs: check blkaddr more accuratly before issue a bio 034f11eadb16 f2fs: Set GF_NOFS in read_cache_page_gfp while doing f2fs_quota_read aa5bcfd8f488 f2fs: introduce a new mount option test_dummy_encryption 9b880fe6e6e2 f2fs: introduce F2FS_FEATURE_LOST_FOUND feature 80d6489a08c1 f2fs: release locks before return in f2fs_ioc_gc_range() 9f1896c490eb f2fs: align memory boundary for bitops c7930ee88334 f2fs: remove unneeded set_cold_node() 355d2346409a f2fs: add nowait aio support e9a50e6b9479 f2fs: wrap all options with f2fs_sb_info.mount_opt b6d2ec83e0c0 f2fs: Don't overwrite all types of node to keep node chain 9a954816298c f2fs: introduce mount option for fsync mode 4ce4eb697068 f2fs: fix to restore old mount option in ->remount_fs 8f711c344e61 f2fs: wrap sb_rdonly with f2fs_readonly c07478ee84bf f2fs: avoid selinux denial on CAP_SYS_RESOURCE ac734c416fa9 f2fs: support hot file extension f4f10221accc f2fs: fix to avoid race in between atomic write and background GC e87b13ec160b f2fs: do gc in greedy mode for whole range if gc_urgent mode is set e9878588de94 f2fs: issue discard aggressively in the gc_urgent mode ad3ce479e6e4 f2fs: set readdir_ra by default 5aae2026bbd2 f2fs: add auto tuning for small devices 78c1fc2d8f27 f2fs: add mount option for segment allocation policy ecd02f564631 f2fs: don't stop GC if GC is contended 1e72cb27d2d6 f2fs: expose extension_list sysfs entry 061839d178ab f2fs: fix to set KEEP_SIZE bit in f2fs_zero_range 4951ebcbc4e2 f2fs: introduce sb_lock to make encrypt pwsalt update exclusive 939f6be0420f f2fs: remove redundant initialization of pointer 'p' 39bea4bc8ef2 f2fs: flush cp pack except cp pack 2 page at first 770611eb2ab4 f2fs: clean up f2fs_sb_has_xxx functions 4d8e4a8965f9 f2fs: remove redundant check of page type when submit bio e9878588de94 f2fs: issue discard aggressively in the gc_urgent mode ad3ce479e6e4 f2fs: set readdir_ra by default 5aae2026bbd2 f2fs: add auto tuning for small devices 78c1fc2d8f27 f2fs: add mount option for segment allocation policy ecd02f564631 f2fs: don't stop GC if GC is contended 1e72cb27d2d6 f2fs: expose extension_list sysfs entry 061839d178ab f2fs: fix to set KEEP_SIZE bit in f2fs_zero_range 4951ebcbc4e2 f2fs: introduce sb_lock to make encrypt pwsalt update exclusive 939f6be0420f f2fs: remove redundant initialization of pointer 'p' 39bea4bc8ef2 f2fs: flush cp pack except cp pack 2 page at first 770611eb2ab4 f2fs: clean up f2fs_sb_has_xxx functions 4d8e4a8965f9 f2fs: remove redundant check of page type when submit bio b57a37f01fda f2fs: fix to handle looped node chain during recovery 9ac5b8c54083 f2fs: handle quota for orphan inodes 87c18066016a f2fs: support passing down write hints to block layer with F2FS policy bcdc571e8d8b f2fs: support passing down write hints given by users to block layer 92413bc12e32 f2fs: fix to clear CP_TRIMMED_FLAG a1afb55f9784 f2fs: support large nat bitmap 636039140493 f2fs: fix to check extent cache in f2fs_drop_extent_tree 7de4fccdbce1 f2fs: restrict inline_xattr_size configuration aae506a8b704 f2fs: fix heap mode to reset it back 8fa455bb6ea0 f2fs: fix potential corruption in area before F2FS_SUPER_OFFSET 9d9cb0ef73f9 fscrypt: fix build with pre-4.6 gcc versions 401052ffc6b4 fscrypt: remove 'ci' parameter from fscrypt_put_encryption_info() 549b2061b3b5 fscrypt: fix up fscrypt_fname_encrypted_size() for internal use c440b5091a0c fscrypt: define fscrypt_fname_alloc_buffer() to be for presented names 7d82f0e1c39a ext4: switch to fscrypt ->symlink() helper functions ba4efe560438 ext4: switch to fscrypt_get_symlink() b0edc2f22d24 fscrypt: calculate NUL-padding length in one place only 62cfdd9868c7 fscrypt: move fscrypt_symlink_data to fscrypt_private.h e4e6776522bc fscrypt: remove fscrypt_fname_usr_to_disk() 45028b5aaa4e f2fs: switch to fscrypt_get_symlink() f62d3d31e0c7 f2fs: switch to fscrypt ->symlink() helper functions da32a1633ad3 fscrypt: new helper function - fscrypt_get_symlink() a7e05c731d11 fscrypt: new helper functions for ->symlink() eb9c5fd896de fscrypt: trim down fscrypt.h includes 0a02472d8ae2 fscrypt: move fscrypt_is_dot_dotdot() to fs/crypto/fname.c 9d51ca80274c fscrypt: move fscrypt_valid_enc_modes() to fscrypt_private.h efbfa8c6a056 fscrypt: move fscrypt_operations declaration to fscrypt_supp.h 616dbd2bdc6a fscrypt: split fscrypt_dummy_context_enabled() into supp/notsupp versions f0c472bcbf1c fscrypt: move fscrypt_ctx declaration to fscrypt_supp.h bc76f39109b1 fscrypt: move fscrypt_info_cachep declaration to fscrypt_private.h b67b07ec4964 fscrypt: move fscrypt_control_page() to supp/notsupp headers d8dfb89961d0 fscrypt: move fscrypt_has_encryption_key() to supp/notsupp headers Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 11 + Documentation/filesystems/f2fs.txt | 17 ++ fs/crypto/crypto.c | 1 + fs/crypto/fname.c | 140 +++++----- fs/crypto/fscrypt_private.h | 31 +++ fs/crypto/hooks.c | 158 +++++++++++ fs/crypto/keyinfo.c | 17 +- fs/ext4/namei.c | 58 +--- fs/ext4/super.c | 4 +- fs/ext4/symlink.c | 43 +-- fs/f2fs/checkpoint.c | 101 ++++--- fs/f2fs/data.c | 91 +++++-- fs/f2fs/dir.c | 9 +- fs/f2fs/extent_cache.c | 5 +- fs/f2fs/f2fs.h | 190 +++++++------ fs/f2fs/file.c | 94 +++++-- fs/f2fs/gc.c | 23 +- fs/f2fs/inode.c | 11 +- fs/f2fs/namei.c | 247 +++++++++-------- fs/f2fs/node.c | 55 +++- fs/f2fs/node.h | 5 +- fs/f2fs/recovery.c | 14 + fs/f2fs/segment.c | 133 ++++++++- fs/f2fs/segment.h | 27 +- fs/f2fs/super.c | 348 +++++++++++++++++------- fs/f2fs/sysfs.c | 73 ++++- include/linux/blk_types.h | 1 + include/linux/f2fs_fs.h | 19 +- include/linux/fs.h | 21 +- include/linux/fscrypt.h | 174 +++++------- include/linux/fscrypt_notsupp.h | 59 ++-- include/linux/fscrypt_supp.h | 68 ++++- include/uapi/linux/fcntl.h | 21 ++ 33 files changed, 1516 insertions(+), 753 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index db7aab1516de..b8d0a30f1644 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -192,3 +192,14 @@ Date: November 2017 Contact: "Sheng Yong" Description: Controls readahead inode block in readdir. + +What: /sys/fs/f2fs//extension_list +Date: Feburary 2018 +Contact: "Chao Yu" +Description: + Used to control configure extension list: + - Query: cat /sys/fs/f2fs//extension_list + - Add: echo '[h/c]extension' > /sys/fs/f2fs//extension_list + - Del: echo '[h/c]!extension' > /sys/fs/f2fs//extension_list + - [h] means add/del hot file extension + - [c] means add/del cold file extension diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index e7fb61ee6583..e85f9e1848d1 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt @@ -171,6 +171,23 @@ offgrpjquota Turn off group journelled quota. offprjjquota Turn off project journelled quota. quota Enable plain user disk quota accounting. noquota Disable all plain disk quota option. +whint_mode=%s Control which write hints are passed down to block + layer. This supports "off", "user-based", and + "fs-based". In "off" mode (default), f2fs does not pass + down hints. In "user-based" mode, f2fs tries to pass + down hints given by users. And in "fs-based" mode, f2fs + passes down hints with its policy. +alloc_mode=%s Adjust block allocation policy, which supports "reuse" + and "default". +fsync_mode=%s Control the policy of fsync. Currently supports "posix" + and "strict". In "posix" mode, which is default, fsync + will follow POSIX semantics and does a light operation + to improve the filesystem performance. In "strict" mode, + fsync will be heavy and behaves in line with xfs, ext4 + and btrfs, where xfstest generic/342 will pass, but the + performance will regress. +test_dummy_encryption Enable dummy encryption, which provides a fake fscrypt + context. The fake fscrypt context is used by xfstests. ================================================================================ DEBUGFS ENTRIES diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 732a786cce9d..ce654526c0fb 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "fscrypt_private.h" static unsigned int num_prealloc_crypto_pages = 32; diff --git a/fs/crypto/fname.c b/fs/crypto/fname.c index 6eb434363ff2..b18fa323d1d9 100644 --- a/fs/crypto/fname.c +++ b/fs/crypto/fname.c @@ -12,42 +12,46 @@ #include #include +#include #include "fscrypt_private.h" +static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) +{ + if (str->len == 1 && str->name[0] == '.') + return true; + + if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') + return true; + + return false; +} + /** * fname_encrypt() - encrypt a filename * - * The caller must have allocated sufficient memory for the @oname string. + * The output buffer must be at least as large as the input buffer. + * Any extra space is filled with NUL padding before encryption. * * Return: 0 on success, -errno on failure */ -static int fname_encrypt(struct inode *inode, - const struct qstr *iname, struct fscrypt_str *oname) +int fname_encrypt(struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen) { struct skcipher_request *req = NULL; DECLARE_CRYPTO_WAIT(wait); - struct fscrypt_info *ci = inode->i_crypt_info; - struct crypto_skcipher *tfm = ci->ci_ctfm; + struct crypto_skcipher *tfm = inode->i_crypt_info->ci_ctfm; int res = 0; char iv[FS_CRYPTO_BLOCK_SIZE]; struct scatterlist sg; - int padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); - unsigned int lim; - unsigned int cryptlen; - - lim = inode->i_sb->s_cop->max_namelen(inode); - if (iname->len <= 0 || iname->len > lim) - return -EIO; /* * Copy the filename to the output buffer for encrypting in-place and * pad it with the needed number of NUL bytes. */ - cryptlen = max_t(unsigned int, iname->len, FS_CRYPTO_BLOCK_SIZE); - cryptlen = round_up(cryptlen, padding); - cryptlen = min(cryptlen, lim); - memcpy(oname->name, iname->name, iname->len); - memset(oname->name + iname->len, 0, cryptlen - iname->len); + if (WARN_ON(olen < iname->len)) + return -ENOBUFS; + memcpy(out, iname->name, iname->len); + memset(out + iname->len, 0, olen - iname->len); /* Initialize the IV */ memset(iv, 0, FS_CRYPTO_BLOCK_SIZE); @@ -62,8 +66,8 @@ static int fname_encrypt(struct inode *inode, skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, crypto_req_done, &wait); - sg_init_one(&sg, oname->name, cryptlen); - skcipher_request_set_crypt(req, &sg, &sg, cryptlen, iv); + sg_init_one(&sg, out, olen); + skcipher_request_set_crypt(req, &sg, &sg, olen, iv); /* Do the encryption */ res = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); @@ -74,7 +78,6 @@ static int fname_encrypt(struct inode *inode, return res; } - oname->len = cryptlen; return 0; } @@ -187,50 +190,52 @@ static int digest_decode(const char *src, int len, char *dst) return cp - dst; } -u32 fscrypt_fname_encrypted_size(const struct inode *inode, u32 ilen) +bool fscrypt_fname_encrypted_size(const struct inode *inode, u32 orig_len, + u32 max_len, u32 *encrypted_len_ret) { - int padding = 32; - struct fscrypt_info *ci = inode->i_crypt_info; - - if (ci) - padding = 4 << (ci->ci_flags & FS_POLICY_FLAGS_PAD_MASK); - ilen = max(ilen, (u32)FS_CRYPTO_BLOCK_SIZE); - return round_up(ilen, padding); + int padding = 4 << (inode->i_crypt_info->ci_flags & + FS_POLICY_FLAGS_PAD_MASK); + u32 encrypted_len; + + if (orig_len > max_len) + return false; + encrypted_len = max(orig_len, (u32)FS_CRYPTO_BLOCK_SIZE); + encrypted_len = round_up(encrypted_len, padding); + *encrypted_len_ret = min(encrypted_len, max_len); + return true; } -EXPORT_SYMBOL(fscrypt_fname_encrypted_size); /** - * fscrypt_fname_crypto_alloc_obuff() - + * fscrypt_fname_alloc_buffer - allocate a buffer for presented filenames + * + * Allocate a buffer that is large enough to hold any decrypted or encoded + * filename (null-terminated), for the given maximum encrypted filename length. * - * Allocates an output buffer that is sufficient for the crypto operation - * specified by the context and the direction. + * Return: 0 on success, -errno on failure */ int fscrypt_fname_alloc_buffer(const struct inode *inode, - u32 ilen, struct fscrypt_str *crypto_str) + u32 max_encrypted_len, + struct fscrypt_str *crypto_str) { - u32 olen = fscrypt_fname_encrypted_size(inode, ilen); const u32 max_encoded_len = max_t(u32, BASE64_CHARS(FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE), 1 + BASE64_CHARS(sizeof(struct fscrypt_digested_name))); + u32 max_presented_len; - crypto_str->len = olen; - olen = max(olen, max_encoded_len); + max_presented_len = max(max_encoded_len, max_encrypted_len); - /* - * Allocated buffer can hold one more character to null-terminate the - * string - */ - crypto_str->name = kmalloc(olen + 1, GFP_NOFS); - if (!(crypto_str->name)) + crypto_str->name = kmalloc(max_presented_len + 1, GFP_NOFS); + if (!crypto_str->name) return -ENOMEM; + crypto_str->len = max_presented_len; return 0; } EXPORT_SYMBOL(fscrypt_fname_alloc_buffer); /** - * fscrypt_fname_crypto_free_buffer() - + * fscrypt_fname_free_buffer - free the buffer for presented filenames * - * Frees the buffer allocated for crypto operation. + * Free the buffer allocated by fscrypt_fname_alloc_buffer(). */ void fscrypt_fname_free_buffer(struct fscrypt_str *crypto_str) { @@ -296,35 +301,6 @@ int fscrypt_fname_disk_to_usr(struct inode *inode, } EXPORT_SYMBOL(fscrypt_fname_disk_to_usr); -/** - * fscrypt_fname_usr_to_disk() - converts a filename from user space to disk - * space - * - * The caller must have allocated sufficient memory for the @oname string. - * - * Return: 0 on success, -errno on failure - */ -int fscrypt_fname_usr_to_disk(struct inode *inode, - const struct qstr *iname, - struct fscrypt_str *oname) -{ - if (fscrypt_is_dot_dotdot(iname)) { - oname->name[0] = '.'; - oname->name[iname->len - 1] = '.'; - oname->len = iname->len; - return 0; - } - if (inode->i_crypt_info) - return fname_encrypt(inode, iname, oname); - /* - * Without a proper key, a user is not allowed to modify the filenames - * in a directory. Consequently, a user space name cannot be mapped to - * a disk-space name - */ - return -ENOKEY; -} -EXPORT_SYMBOL(fscrypt_fname_usr_to_disk); - /** * fscrypt_setup_filename() - prepare to search a possibly encrypted directory * @dir: the directory that will be searched @@ -368,11 +344,17 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return ret; if (dir->i_crypt_info) { - ret = fscrypt_fname_alloc_buffer(dir, iname->len, - &fname->crypto_buf); - if (ret) - return ret; - ret = fname_encrypt(dir, iname, &fname->crypto_buf); + if (!fscrypt_fname_encrypted_size(dir, iname->len, + dir->i_sb->s_cop->max_namelen(dir), + &fname->crypto_buf.len)) + return -ENAMETOOLONG; + fname->crypto_buf.name = kmalloc(fname->crypto_buf.len, + GFP_NOFS); + if (!fname->crypto_buf.name) + return -ENOMEM; + + ret = fname_encrypt(dir, iname, fname->crypto_buf.name, + fname->crypto_buf.len); if (ret) goto errout; fname->disk_name.name = fname->crypto_buf.name; @@ -424,7 +406,7 @@ int fscrypt_setup_filename(struct inode *dir, const struct qstr *iname, return 0; errout: - fscrypt_fname_free_buffer(&fname->crypto_buf); + kfree(fname->crypto_buf.name); return ret; } EXPORT_SYMBOL(fscrypt_setup_filename); diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 4688a645cd63..1fe00fd2f49e 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -49,6 +49,15 @@ struct fscrypt_context { #define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1 +/** + * For encrypted symlinks, the ciphertext length is stored at the beginning + * of the string in little-endian format. + */ +struct fscrypt_symlink_data { + __le16 len; + char encrypted_path[1]; +} __packed; + /* * A pointer to this structure is stored in the file system's in-core * representation of an inode. @@ -70,7 +79,22 @@ typedef enum { #define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 #define FS_CTX_HAS_BOUNCE_BUFFER_FL 0x00000002 +static inline bool fscrypt_valid_enc_modes(u32 contents_mode, + u32 filenames_mode) +{ + if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC && + filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS) + return true; + + if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS && + filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) + return true; + + return false; +} + /* crypto.c */ +extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); extern struct workqueue_struct *fscrypt_read_workqueue; extern int fscrypt_do_page_crypto(const struct inode *inode, @@ -82,6 +106,13 @@ extern int fscrypt_do_page_crypto(const struct inode *inode, extern struct page *fscrypt_alloc_bounce_page(struct fscrypt_ctx *ctx, gfp_t gfp_flags); +/* fname.c */ +extern int fname_encrypt(struct inode *inode, const struct qstr *iname, + u8 *out, unsigned int olen); +extern bool fscrypt_fname_encrypted_size(const struct inode *inode, + u32 orig_len, u32 max_len, + u32 *encrypted_len_ret); + /* keyinfo.c */ extern void __exit fscrypt_essiv_cleanup(void); diff --git a/fs/crypto/hooks.c b/fs/crypto/hooks.c index 9f5fb2eb9cf7..bec06490fb13 100644 --- a/fs/crypto/hooks.c +++ b/fs/crypto/hooks.c @@ -110,3 +110,161 @@ int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry) return 0; } EXPORT_SYMBOL_GPL(__fscrypt_prepare_lookup); + +int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link) +{ + int err; + + /* + * To calculate the size of the encrypted symlink target we need to know + * the amount of NUL padding, which is determined by the flags set in + * the encryption policy which will be inherited from the directory. + * The easiest way to get access to this is to just load the directory's + * fscrypt_info, since we'll need it to create the dir_entry anyway. + * + * Note: in test_dummy_encryption mode, @dir may be unencrypted. + */ + err = fscrypt_get_encryption_info(dir); + if (err) + return err; + if (!fscrypt_has_encryption_key(dir)) + return -ENOKEY; + + /* + * Calculate the size of the encrypted symlink and verify it won't + * exceed max_len. Note that for historical reasons, encrypted symlink + * targets are prefixed with the ciphertext length, despite this + * actually being redundant with i_size. This decreases by 2 bytes the + * longest symlink target we can accept. + * + * We could recover 1 byte by not counting a null terminator, but + * counting it (even though it is meaningless for ciphertext) is simpler + * for now since filesystems will assume it is there and subtract it. + */ + if (!fscrypt_fname_encrypted_size(dir, len, + max_len - sizeof(struct fscrypt_symlink_data), + &disk_link->len)) + return -ENAMETOOLONG; + disk_link->len += sizeof(struct fscrypt_symlink_data); + + disk_link->name = NULL; + return 0; +} +EXPORT_SYMBOL_GPL(__fscrypt_prepare_symlink); + +int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, + unsigned int len, struct fscrypt_str *disk_link) +{ + int err; + struct qstr iname = QSTR_INIT(target, len); + struct fscrypt_symlink_data *sd; + unsigned int ciphertext_len; + + err = fscrypt_require_key(inode); + if (err) + return err; + + if (disk_link->name) { + /* filesystem-provided buffer */ + sd = (struct fscrypt_symlink_data *)disk_link->name; + } else { + sd = kmalloc(disk_link->len, GFP_NOFS); + if (!sd) + return -ENOMEM; + } + ciphertext_len = disk_link->len - sizeof(*sd); + sd->len = cpu_to_le16(ciphertext_len); + + err = fname_encrypt(inode, &iname, sd->encrypted_path, ciphertext_len); + if (err) { + if (!disk_link->name) + kfree(sd); + return err; + } + /* + * Null-terminating the ciphertext doesn't make sense, but we still + * count the null terminator in the length, so we might as well + * initialize it just in case the filesystem writes it out. + */ + sd->encrypted_path[ciphertext_len] = '\0'; + + if (!disk_link->name) + disk_link->name = (unsigned char *)sd; + return 0; +} +EXPORT_SYMBOL_GPL(__fscrypt_encrypt_symlink); + +/** + * fscrypt_get_symlink - get the target of an encrypted symlink + * @inode: the symlink inode + * @caddr: the on-disk contents of the symlink + * @max_size: size of @caddr buffer + * @done: if successful, will be set up to free the returned target + * + * If the symlink's encryption key is available, we decrypt its target. + * Otherwise, we encode its target for presentation. + * + * This may sleep, so the filesystem must have dropped out of RCU mode already. + * + * Return: the presentable symlink target or an ERR_PTR() + */ +const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, + unsigned int max_size, + struct delayed_call *done) +{ + const struct fscrypt_symlink_data *sd; + struct fscrypt_str cstr, pstr; + int err; + + /* This is for encrypted symlinks only */ + if (WARN_ON(!IS_ENCRYPTED(inode))) + return ERR_PTR(-EINVAL); + + /* + * Try to set up the symlink's encryption key, but we can continue + * regardless of whether the key is available or not. + */ + err = fscrypt_get_encryption_info(inode); + if (err) + return ERR_PTR(err); + + /* + * For historical reasons, encrypted symlink targets are prefixed with + * the ciphertext length, even though this is redundant with i_size. + */ + + if (max_size < sizeof(*sd)) + return ERR_PTR(-EUCLEAN); + sd = caddr; + cstr.name = (unsigned char *)sd->encrypted_path; + cstr.len = le16_to_cpu(sd->len); + + if (cstr.len == 0) + return ERR_PTR(-EUCLEAN); + + if (cstr.len + sizeof(*sd) - 1 > max_size) + return ERR_PTR(-EUCLEAN); + + err = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); + if (err) + return ERR_PTR(err); + + err = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); + if (err) + goto err_kfree; + + err = -EUCLEAN; + if (pstr.name[0] == '\0') + goto err_kfree; + + pstr.name[pstr.len] = '\0'; + set_delayed_call(done, kfree_link, pstr.name); + return pstr.name; + +err_kfree: + kfree(pstr.name); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(fscrypt_get_symlink); diff --git a/fs/crypto/keyinfo.c b/fs/crypto/keyinfo.c index c891d2ea9d24..aae68c0924f1 100644 --- a/fs/crypto/keyinfo.c +++ b/fs/crypto/keyinfo.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "fscrypt_private.h" static struct crypto_shash *essiv_hash_tfm; @@ -353,19 +354,9 @@ int fscrypt_get_encryption_info(struct inode *inode) } EXPORT_SYMBOL(fscrypt_get_encryption_info); -void fscrypt_put_encryption_info(struct inode *inode, struct fscrypt_info *ci) +void fscrypt_put_encryption_info(struct inode *inode) { - struct fscrypt_info *prev; - - if (ci == NULL) - ci = ACCESS_ONCE(inode->i_crypt_info); - if (ci == NULL) - return; - - prev = cmpxchg(&inode->i_crypt_info, ci, NULL); - if (prev != ci) - return; - - put_crypt_info(ci); + put_crypt_info(inode->i_crypt_info); + inode->i_crypt_info = NULL; } EXPORT_SYMBOL(fscrypt_put_encryption_info); diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 8338cd4f19c3..e3183e83e2a8 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3027,36 +3027,16 @@ static int ext4_symlink(struct inode *dir, struct inode *inode; int err, len = strlen(symname); int credits; - bool encryption_required; struct fscrypt_str disk_link; - struct fscrypt_symlink_data *sd = NULL; - disk_link.len = len + 1; - disk_link.name = (char *) symname; - - encryption_required = (ext4_encrypted_inode(dir) || - DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))); - if (encryption_required) { - err = fscrypt_get_encryption_info(dir); - if (err) - return err; - if (!fscrypt_has_encryption_key(dir)) - return -ENOKEY; - disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + - sizeof(struct fscrypt_symlink_data)); - sd = kzalloc(disk_link.len, GFP_KERNEL); - if (!sd) - return -ENOMEM; - } - - if (disk_link.len > dir->i_sb->s_blocksize) { - err = -ENAMETOOLONG; - goto err_free_sd; - } + err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, + &disk_link); + if (err) + return err; err = dquot_initialize(dir); if (err) - goto err_free_sd; + return err; if ((disk_link.len > EXT4_N_BLOCKS * 4)) { /* @@ -3085,27 +3065,18 @@ static int ext4_symlink(struct inode *dir, if (IS_ERR(inode)) { if (handle) ext4_journal_stop(handle); - err = PTR_ERR(inode); - goto err_free_sd; + return PTR_ERR(inode); } - if (encryption_required) { - struct qstr istr; - struct fscrypt_str ostr = - FSTR_INIT(sd->encrypted_path, disk_link.len); - - istr.name = (const unsigned char *) symname; - istr.len = len; - err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); + if (IS_ENCRYPTED(inode)) { + err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); if (err) goto err_drop_inode; - sd->len = cpu_to_le16(ostr.len); - disk_link.name = (char *) sd; inode->i_op = &ext4_encrypted_symlink_inode_operations; } if ((disk_link.len > EXT4_N_BLOCKS * 4)) { - if (!encryption_required) + if (!IS_ENCRYPTED(inode)) inode->i_op = &ext4_symlink_inode_operations; inode_nohighmem(inode); ext4_set_aops(inode); @@ -3147,7 +3118,7 @@ static int ext4_symlink(struct inode *dir, } else { /* clear the extent format for fast symlink */ ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); - if (!encryption_required) { + if (!IS_ENCRYPTED(inode)) { inode->i_op = &ext4_fast_symlink_inode_operations; inode->i_link = (char *)&EXT4_I(inode)->i_data; } @@ -3162,16 +3133,17 @@ static int ext4_symlink(struct inode *dir, if (handle) ext4_journal_stop(handle); - kfree(sd); - return err; + goto out_free_encrypted_link; + err_drop_inode: if (handle) ext4_journal_stop(handle); clear_nlink(inode); unlock_new_inode(inode); iput(inode); -err_free_sd: - kfree(sd); +out_free_encrypted_link: + if (disk_link.name != (unsigned char *)symname) + kfree(disk_link.name); return err; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 43ce5fce47bf..70a1bcd43978 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1028,9 +1028,7 @@ void ext4_clear_inode(struct inode *inode) jbd2_free_inode(EXT4_I(inode)->jinode); EXT4_I(inode)->jinode = NULL; } -#ifdef CONFIG_EXT4_FS_ENCRYPTION - fscrypt_put_encryption_info(inode, NULL); -#endif + fscrypt_put_encryption_info(inode); } static struct inode *ext4_nfs_get_inode(struct super_block *sb, diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index 557b3b0d668c..d4ce3af418a0 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -27,59 +27,28 @@ static const char *ext4_encrypted_get_link(struct dentry *dentry, struct delayed_call *done) { struct page *cpage = NULL; - char *caddr, *paddr = NULL; - struct fscrypt_str cstr, pstr; - struct fscrypt_symlink_data *sd; - int res; - u32 max_size = inode->i_sb->s_blocksize; + const void *caddr; + unsigned int max_size; + const char *paddr; if (!dentry) return ERR_PTR(-ECHILD); - res = fscrypt_get_encryption_info(inode); - if (res) - return ERR_PTR(res); - if (ext4_inode_is_fast_symlink(inode)) { - caddr = (char *) EXT4_I(inode)->i_data; + caddr = EXT4_I(inode)->i_data; max_size = sizeof(EXT4_I(inode)->i_data); } else { cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); caddr = page_address(cpage); + max_size = inode->i_sb->s_blocksize; } - /* Symlink is encrypted */ - sd = (struct fscrypt_symlink_data *)caddr; - cstr.name = sd->encrypted_path; - cstr.len = le16_to_cpu(sd->len); - if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { - /* Symlink data on the disk is corrupted */ - res = -EFSCORRUPTED; - goto errout; - } - - res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); - if (res) - goto errout; - paddr = pstr.name; - - res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); - if (res) - goto errout; - - /* Null-terminate the name */ - paddr[pstr.len] = '\0'; + paddr = fscrypt_get_symlink(inode, caddr, max_size, done); if (cpage) put_page(cpage); - set_delayed_call(done, kfree_link, paddr); return paddr; -errout: - if (cpage) - put_page(cpage); - kfree(paddr); - return ERR_PTR(res); } const struct inode_operations ext4_encrypted_symlink_inode_operations = { diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 701781a372f3..6c7b0547a307 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -68,6 +68,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, .old_blkaddr = index, .new_blkaddr = index, .encrypted_page = NULL, + .is_meta = is_meta, }; if (unlikely(!is_meta)) @@ -162,6 +163,7 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD, .encrypted_page = NULL, .in_list = false, + .is_meta = (type != META_POR), }; struct blk_plug plug; @@ -572,13 +574,8 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) struct node_info ni; int err = acquire_orphan_inode(sbi); - if (err) { - set_sbi_flag(sbi, SBI_NEED_FSCK); - f2fs_msg(sbi->sb, KERN_WARNING, - "%s: orphan failed (ino=%x), run fsck to fix.", - __func__, ino); - return err; - } + if (err) + goto err_out; __add_ino_entry(sbi, ino, 0, ORPHAN_INO); @@ -592,6 +589,11 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) return PTR_ERR(inode); } + err = dquot_initialize(inode); + if (err) + goto err_out; + + dquot_initialize(inode); clear_nlink(inode); /* truncate all the data during iput */ @@ -601,14 +603,18 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino) /* ENOMEM was fully retried in f2fs_evict_inode. */ if (ni.blk_addr != NULL_ADDR) { - set_sbi_flag(sbi, SBI_NEED_FSCK); - f2fs_msg(sbi->sb, KERN_WARNING, - "%s: orphan failed (ino=%x) by kernel, retry mount.", - __func__, ino); - return -EIO; + err = -EIO; + goto err_out; } __remove_ino_entry(sbi, ino, ORPHAN_INO); return 0; + +err_out: + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_msg(sbi->sb, KERN_WARNING, + "%s: orphan failed (ino=%x), run fsck to fix.", + __func__, ino); + return err; } int recover_orphan_inodes(struct f2fs_sb_info *sbi) @@ -1139,6 +1145,8 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) if (cpc->reason & CP_TRIMMED) __set_ckpt_flags(ckpt, CP_TRIMMED_FLAG); + else + __clear_ckpt_flags(ckpt, CP_TRIMMED_FLAG); if (cpc->reason & CP_UMOUNT) __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG); @@ -1165,6 +1173,39 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc) spin_unlock_irqrestore(&sbi->cp_lock, flags); } +static void commit_checkpoint(struct f2fs_sb_info *sbi, + void *src, block_t blk_addr) +{ + struct writeback_control wbc = { + .for_reclaim = 0, + }; + + /* + * pagevec_lookup_tag and lock_page again will take + * some extra time. Therefore, update_meta_pages and + * sync_meta_pages are combined in this function. + */ + struct page *page = grab_meta_page(sbi, blk_addr); + int err; + + memcpy(page_address(page), src, PAGE_SIZE); + set_page_dirty(page); + + f2fs_wait_on_page_writeback(page, META, true); + f2fs_bug_on(sbi, PageWriteback(page)); + if (unlikely(!clear_page_dirty_for_io(page))) + f2fs_bug_on(sbi, 1); + + /* writeout cp pack 2 page */ + err = __f2fs_write_meta_page(page, &wbc, FS_CP_META_IO); + f2fs_bug_on(sbi, err); + + f2fs_put_page(page, 0); + + /* submit checkpoint (with barrier if NOBARRIER is not set) */ + f2fs_submit_merged_write(sbi, META_FLUSH); +} + static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) { struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); @@ -1267,16 +1308,6 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) } } - /* need to wait for end_io results */ - wait_on_all_pages_writeback(sbi); - if (unlikely(f2fs_cp_error(sbi))) - return -EIO; - - /* flush all device cache */ - err = f2fs_flush_device_cache(sbi); - if (err) - return err; - /* write out checkpoint buffer at block 0 */ update_meta_page(sbi, ckpt, start_blk++); @@ -1304,26 +1335,26 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) start_blk += NR_CURSEG_NODE_TYPE; } - /* writeout checkpoint block */ - update_meta_page(sbi, ckpt, start_blk); + /* update user_block_counts */ + sbi->last_valid_block_count = sbi->total_valid_block_count; + percpu_counter_set(&sbi->alloc_valid_block_count, 0); + + /* Here, we have one bio having CP pack except cp pack 2 page */ + sync_meta_pages(sbi, META, LONG_MAX, FS_CP_META_IO); - /* wait for previous submitted node/meta pages writeback */ + /* wait for previous submitted meta pages writeback */ wait_on_all_pages_writeback(sbi); if (unlikely(f2fs_cp_error(sbi))) return -EIO; - filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LLONG_MAX); - filemap_fdatawait_range(META_MAPPING(sbi), 0, LLONG_MAX); - - /* update user_block_counts */ - sbi->last_valid_block_count = sbi->total_valid_block_count; - percpu_counter_set(&sbi->alloc_valid_block_count, 0); - - /* Here, we only have one bio having CP pack */ - sync_meta_pages(sbi, META_FLUSH, LONG_MAX, FS_CP_META_IO); + /* flush all device cache */ + err = f2fs_flush_device_cache(sbi); + if (err) + return err; - /* wait for previous submitted meta pages writeback */ + /* barrier and flush checkpoint cp pack 2 page if it can */ + commit_checkpoint(sbi, ckpt, start_blk); wait_on_all_pages_writeback(sbi); release_ino_entry(sbi, false); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 6c13ee3a80ef..c676c78919bc 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -174,15 +174,22 @@ static bool __same_bdev(struct f2fs_sb_info *sbi, */ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr, struct writeback_control *wbc, - int npages, bool is_read) + int npages, bool is_read, + enum page_type type, enum temp_type temp) { struct bio *bio; bio = f2fs_bio_alloc(sbi, npages, true); f2fs_target_device(sbi, blk_addr, bio); - bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io; - bio->bi_private = is_read ? NULL : sbi; + if (is_read) { + bio->bi_end_io = f2fs_read_end_io; + bio->bi_private = NULL; + } else { + bio->bi_end_io = f2fs_write_end_io; + bio->bi_private = sbi; + bio->bi_write_hint = io_type_to_rw_hint(sbi, type, temp); + } if (wbc) wbc_init_bio(wbc, bio); @@ -195,13 +202,12 @@ static inline void __submit_bio(struct f2fs_sb_info *sbi, if (!is_read_io(bio_op(bio))) { unsigned int start; - if (f2fs_sb_mounted_blkzoned(sbi->sb) && - current->plug && (type == DATA || type == NODE)) - blk_finish_plug(current->plug); - if (type != DATA && type != NODE) goto submit_io; + if (f2fs_sb_has_blkzoned(sbi->sb) && current->plug) + blk_finish_plug(current->plug); + start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS; start %= F2FS_IO_SIZE(sbi); @@ -376,12 +382,13 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) struct page *page = fio->encrypted_page ? fio->encrypted_page : fio->page; + verify_block_addr(fio, fio->new_blkaddr); trace_f2fs_submit_page_bio(page, fio); f2fs_trace_ios(fio, 0); /* Allocate a new bio */ bio = __bio_alloc(fio->sbi, fio->new_blkaddr, fio->io_wbc, - 1, is_read_io(fio->op)); + 1, is_read_io(fio->op), fio->type, fio->temp); if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) { bio_put(bio); @@ -421,8 +428,8 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) } if (fio->old_blkaddr != NEW_ADDR) - verify_block_addr(sbi, fio->old_blkaddr); - verify_block_addr(sbi, fio->new_blkaddr); + verify_block_addr(fio, fio->old_blkaddr); + verify_block_addr(fio, fio->new_blkaddr); bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page; @@ -444,7 +451,8 @@ int f2fs_submit_page_write(struct f2fs_io_info *fio) goto out_fail; } io->bio = __bio_alloc(sbi, fio->new_blkaddr, fio->io_wbc, - BIO_MAX_PAGES, false); + BIO_MAX_PAGES, false, + fio->type, fio->temp); io->fio = *fio; } @@ -831,13 +839,6 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) return 0; } -static inline bool __force_buffered_io(struct inode *inode, int rw) -{ - return (f2fs_encrypted_file(inode) || - (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || - F2FS_I_SB(inode)->s_ndevs); -} - int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) { struct inode *inode = file_inode(iocb->ki_filp); @@ -868,9 +869,8 @@ int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *from) map.m_seg_type = NO_CHECK_TYPE; if (direct_io) { - /* map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint); */ - map.m_seg_type = rw_hint_to_seg_type(WRITE_LIFE_NOT_SET); - flag = __force_buffered_io(inode, WRITE) ? + map.m_seg_type = rw_hint_to_seg_type(iocb->ki_hint); + flag = f2fs_force_buffered_io(inode, WRITE) ? F2FS_GET_BLOCK_PRE_AIO : F2FS_GET_BLOCK_PRE_DIO; goto map_blocks; @@ -1114,6 +1114,31 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, return err; } +bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len) +{ + struct f2fs_map_blocks map; + block_t last_lblk; + int err; + + if (pos + len > i_size_read(inode)) + return false; + + map.m_lblk = F2FS_BYTES_TO_BLK(pos); + map.m_next_pgofs = NULL; + map.m_next_extent = NULL; + map.m_seg_type = NO_CHECK_TYPE; + last_lblk = F2FS_BLK_ALIGN(pos + len); + + while (map.m_lblk < last_lblk) { + map.m_len = last_lblk - map.m_lblk; + err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + if (err || map.m_len == 0) + return false; + map.m_lblk += map.m_len; + } + return true; +} + static int __get_data_block(struct inode *inode, sector_t iblock, struct buffer_head *bh, int create, int flag, pgoff_t *next_pgofs, int seg_type) @@ -1151,8 +1176,7 @@ static int get_data_block_dio(struct inode *inode, sector_t iblock, return __get_data_block(inode, iblock, bh_result, create, F2FS_GET_BLOCK_DEFAULT, NULL, rw_hint_to_seg_type( - WRITE_LIFE_NOT_SET)); - /* inode->i_write_hint)); */ + inode->i_write_hint)); } static int get_data_block_bmap(struct inode *inode, sector_t iblock, @@ -2304,16 +2328,19 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) { struct address_space *mapping = iocb->ki_filp->f_mapping; struct inode *inode = mapping->host; + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); size_t count = iov_iter_count(iter); loff_t offset = iocb->ki_pos; int rw = iov_iter_rw(iter); int err; + enum rw_hint hint = iocb->ki_hint; + int whint_mode = F2FS_OPTION(sbi).whint_mode; err = check_direct_IO(inode, iter, offset); if (err) return err; - if (__force_buffered_io(inode, rw)) + if (f2fs_force_buffered_io(inode, rw)) return 0; trace_f2fs_direct_IO_enter(inode, offset, count, rw); @@ -2340,12 +2367,24 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) current->pid, path, current->comm); } + if (rw == WRITE && whint_mode == WHINT_MODE_OFF) + iocb->ki_hint = WRITE_LIFE_NOT_SET; + + if (!down_read_trylock(&F2FS_I(inode)->dio_rwsem[rw])) { + if (iocb->ki_flags & IOCB_NOWAIT) { + iocb->ki_hint = hint; + err = -EAGAIN; + goto out; + } + down_read(&F2FS_I(inode)->dio_rwsem[rw]); + } - down_read(&F2FS_I(inode)->dio_rwsem[rw]); err = blockdev_direct_IO(iocb, inode, iter, get_data_block_dio); up_read(&F2FS_I(inode)->dio_rwsem[rw]); if (rw == WRITE) { + if (whint_mode == WHINT_MODE_OFF) + iocb->ki_hint = hint; if (err > 0) { f2fs_update_iostat(F2FS_I_SB(inode), APP_DIRECT_IO, err); @@ -2354,7 +2393,7 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) f2fs_write_failed(mapping, offset + count); } } - +out: if (trace_android_fs_dataread_start_enabled() && (rw == READ)) trace_android_fs_dataread_end(inode, offset, count); diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index a352ace5f7cd..f9a1e182bf55 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -361,6 +361,7 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, struct page *dpage) { struct page *page; + int dummy_encrypt = DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(dir)); int err; if (is_inode_flag_set(inode, FI_NEW_INODE)) { @@ -387,7 +388,8 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, if (err) goto put_error; - if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) { + if ((f2fs_encrypted_inode(dir) || dummy_encrypt) && + f2fs_may_encrypt(inode)) { err = fscrypt_inherit_context(dir, inode, page, false); if (err) goto put_error; @@ -396,8 +398,6 @@ struct page *init_inode_metadata(struct inode *inode, struct inode *dir, page = get_node_page(F2FS_I_SB(dir), inode->i_ino); if (IS_ERR(page)) return page; - - set_cold_node(inode, page); } if (new_name) { @@ -704,7 +704,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page, f2fs_update_time(F2FS_I_SB(dir), REQ_TIME); - add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO); + if (F2FS_OPTION(F2FS_I_SB(dir)).fsync_mode == FSYNC_MODE_STRICT) + add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO); if (f2fs_has_inline_dentry(dir)) return f2fs_delete_inline_entry(dentry, page, dir, inode); diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index ff2352a0ed15..d5a861bf2b42 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -460,7 +460,7 @@ static struct extent_node *__insert_extent_tree(struct inode *inode, struct rb_node *insert_parent) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct rb_node **p = &et->root.rb_node; + struct rb_node **p; struct rb_node *parent = NULL; struct extent_node *en = NULL; @@ -706,6 +706,9 @@ void f2fs_drop_extent_tree(struct inode *inode) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et = F2FS_I(inode)->extent_tree; + if (!f2fs_may_extent_tree(inode)) + return; + set_inode_flag(inode, FI_NO_EXTENT); write_lock(&et->lock); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index e5d3e22629b3..95434234d810 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -99,9 +99,10 @@ extern char *fault_name[FAULT_MAX]; #define F2FS_MOUNT_INLINE_XATTR_SIZE 0x00800000 #define F2FS_MOUNT_RESERVE_ROOT 0x01000000 -#define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option) -#define set_opt(sbi, option) ((sbi)->mount_opt.opt |= F2FS_MOUNT_##option) -#define test_opt(sbi, option) ((sbi)->mount_opt.opt & F2FS_MOUNT_##option) +#define F2FS_OPTION(sbi) ((sbi)->mount_opt) +#define clear_opt(sbi, option) (F2FS_OPTION(sbi).opt &= ~F2FS_MOUNT_##option) +#define set_opt(sbi, option) (F2FS_OPTION(sbi).opt |= F2FS_MOUNT_##option) +#define test_opt(sbi, option) (F2FS_OPTION(sbi).opt & F2FS_MOUNT_##option) #define ver_after(a, b) (typecheck(unsigned long long, a) && \ typecheck(unsigned long long, b) && \ @@ -114,7 +115,26 @@ typedef u32 block_t; /* typedef u32 nid_t; struct f2fs_mount_info { - unsigned int opt; + unsigned int opt; + int write_io_size_bits; /* Write IO size bits */ + block_t root_reserved_blocks; /* root reserved blocks */ + kuid_t s_resuid; /* reserved blocks for uid */ + kgid_t s_resgid; /* reserved blocks for gid */ + int active_logs; /* # of active logs */ + int inline_xattr_size; /* inline xattr size */ +#ifdef CONFIG_F2FS_FAULT_INJECTION + struct f2fs_fault_info fault_info; /* For fault injection */ +#endif +#ifdef CONFIG_QUOTA + /* Names of quota files with journalled quota */ + char *s_qf_names[MAXQUOTAS]; + int s_jquota_fmt; /* Format of quota to use */ +#endif + /* For which write hints are passed down to block layer */ + int whint_mode; + int alloc_mode; /* segment allocation policy */ + int fsync_mode; /* fsync policy */ + bool test_dummy_encryption; /* test dummy encryption */ }; #define F2FS_FEATURE_ENCRYPT 0x0001 @@ -126,6 +146,8 @@ struct f2fs_mount_info { #define F2FS_FEATURE_FLEXIBLE_INLINE_XATTR 0x0040 #define F2FS_FEATURE_QUOTA_INO 0x0080 #define F2FS_FEATURE_INODE_CRTIME 0x0100 +#define F2FS_FEATURE_LOST_FOUND 0x0200 +#define F2FS_FEATURE_VERITY 0x0400 /* reserved */ #define F2FS_HAS_FEATURE(sb, mask) \ ((F2FS_SB(sb)->raw_super->feature & cpu_to_le32(mask)) != 0) @@ -448,7 +470,7 @@ static inline void make_dentry_ptr_block(struct inode *inode, d->inode = inode; d->max = NR_DENTRY_IN_BLOCK; d->nr_bitmap = SIZE_OF_DENTRY_BITMAP; - d->bitmap = &t->dentry_bitmap; + d->bitmap = t->dentry_bitmap; d->dentry = t->dentry; d->filename = t->filename; } @@ -574,6 +596,8 @@ enum { #define FADVISE_ENCRYPT_BIT 0x04 #define FADVISE_ENC_NAME_BIT 0x08 #define FADVISE_KEEP_SIZE_BIT 0x10 +#define FADVISE_HOT_BIT 0x20 +#define FADVISE_VERITY_BIT 0x40 /* reserved */ #define file_is_cold(inode) is_file(inode, FADVISE_COLD_BIT) #define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT) @@ -588,6 +612,9 @@ enum { #define file_set_enc_name(inode) set_file(inode, FADVISE_ENC_NAME_BIT) #define file_keep_isize(inode) is_file(inode, FADVISE_KEEP_SIZE_BIT) #define file_set_keep_isize(inode) set_file(inode, FADVISE_KEEP_SIZE_BIT) +#define file_is_hot(inode) is_file(inode, FADVISE_HOT_BIT) +#define file_set_hot(inode) set_file(inode, FADVISE_HOT_BIT) +#define file_clear_hot(inode) clear_file(inode, FADVISE_HOT_BIT) #define DEF_DIR_LEVEL 0 @@ -635,6 +662,7 @@ struct f2fs_inode_info { kprojid_t i_projid; /* id for project quota */ int i_inline_xattr_size; /* inline xattr size */ struct timespec i_crtime; /* inode creation time */ + struct timespec i_disk_time[4]; /* inode disk times */ }; static inline void get_extent_info(struct extent_info *ext, @@ -741,7 +769,7 @@ struct f2fs_nm_info { unsigned int nid_cnt[MAX_NID_STATE]; /* the number of free node id */ spinlock_t nid_list_lock; /* protect nid lists ops */ struct mutex build_lock; /* lock for build free nids */ - unsigned char (*free_nid_bitmap)[NAT_ENTRY_BITMAP_SIZE]; + unsigned char **free_nid_bitmap; unsigned char *nat_block_bitmap; unsigned short *free_nid_count; /* free nid count of NAT block */ @@ -974,6 +1002,7 @@ struct f2fs_io_info { bool submitted; /* indicate IO submission */ int need_lock; /* indicate we need to lock cp_rwsem */ bool in_list; /* indicate fio is in io_list */ + bool is_meta; /* indicate borrow meta inode mapping or not */ enum iostat_type io_type; /* io type */ struct writeback_control *io_wbc; /* writeback control */ }; @@ -1035,10 +1064,34 @@ enum { MAX_TIME, }; +enum { + WHINT_MODE_OFF, /* not pass down write hints */ + WHINT_MODE_USER, /* try to pass down hints given by users */ + WHINT_MODE_FS, /* pass down hints with F2FS policy */ +}; + +enum { + ALLOC_MODE_DEFAULT, /* stay default */ + ALLOC_MODE_REUSE, /* reuse segments as much as possible */ +}; + +enum fsync_mode { + FSYNC_MODE_POSIX, /* fsync follows posix semantics */ + FSYNC_MODE_STRICT, /* fsync behaves in line with ext4 */ +}; + +#ifdef CONFIG_F2FS_FS_ENCRYPTION +#define DUMMY_ENCRYPTION_ENABLED(sbi) \ + (unlikely(F2FS_OPTION(sbi).test_dummy_encryption)) +#else +#define DUMMY_ENCRYPTION_ENABLED(sbi) (0) +#endif + struct f2fs_sb_info { struct super_block *sb; /* pointer to VFS super block */ struct proc_dir_entry *s_proc; /* proc entry */ struct f2fs_super_block *raw_super; /* raw super block pointer */ + struct rw_semaphore sb_lock; /* lock for raw super block */ int valid_super_block; /* valid super block no */ unsigned long s_flag; /* flags for sbi */ @@ -1058,7 +1111,6 @@ struct f2fs_sb_info { struct f2fs_bio_info *write_io[NR_PAGE_TYPE]; /* for write bios */ struct mutex wio_mutex[NR_PAGE_TYPE - 1][NR_TEMP_TYPE]; /* bio ordering for NODE/DATA */ - int write_io_size_bits; /* Write IO size bits */ mempool_t *write_io_dummy; /* Dummy pages */ /* for checkpoint */ @@ -1108,9 +1160,7 @@ struct f2fs_sb_info { unsigned int total_node_count; /* total node block count */ unsigned int total_valid_node_count; /* valid node block count */ loff_t max_file_blocks; /* max block index of file */ - int active_logs; /* # of active logs */ int dir_level; /* directory level */ - int inline_xattr_size; /* inline xattr size */ unsigned int trigger_ssr_threshold; /* threshold to trigger ssr */ int readdir_ra; /* readahead inode in readdir */ @@ -1120,9 +1170,6 @@ struct f2fs_sb_info { block_t last_valid_block_count; /* for recovery */ block_t reserved_blocks; /* configurable reserved blocks */ block_t current_reserved_blocks; /* current reserved blocks */ - block_t root_reserved_blocks; /* root reserved blocks */ - kuid_t s_resuid; /* reserved blocks for uid */ - kgid_t s_resgid; /* reserved blocks for gid */ unsigned int nquota_files; /* # of quota sysfile */ @@ -1207,17 +1254,6 @@ struct f2fs_sb_info { /* Precomputed FS UUID checksum for seeding other checksums */ __u32 s_chksum_seed; - - /* For fault injection */ -#ifdef CONFIG_F2FS_FAULT_INJECTION - struct f2fs_fault_info fault_info; -#endif - -#ifdef CONFIG_QUOTA - /* Names of quota files with journalled quota */ - char *s_qf_names[MAXQUOTAS]; - int s_jquota_fmt; /* Format of quota to use */ -#endif }; #ifdef CONFIG_F2FS_FAULT_INJECTION @@ -1227,7 +1263,7 @@ struct f2fs_sb_info { __func__, __builtin_return_address(0)) static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) { - struct f2fs_fault_info *ffi = &sbi->fault_info; + struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info; if (!ffi->inject_rate) return false; @@ -1584,12 +1620,12 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, return false; if (IS_NOQUOTA(inode)) return true; - if (capable(CAP_SYS_RESOURCE)) + if (uid_eq(F2FS_OPTION(sbi).s_resuid, current_fsuid())) return true; - if (uid_eq(sbi->s_resuid, current_fsuid())) + if (!gid_eq(F2FS_OPTION(sbi).s_resgid, GLOBAL_ROOT_GID) && + in_group_p(F2FS_OPTION(sbi).s_resgid)) return true; - if (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && - in_group_p(sbi->s_resgid)) + if (capable(CAP_SYS_RESOURCE)) return true; return false; } @@ -1625,7 +1661,7 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, sbi->current_reserved_blocks; if (!__allow_reserved_blocks(sbi, inode)) - avail_user_block_count -= sbi->root_reserved_blocks; + avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { diff = sbi->total_valid_block_count - avail_user_block_count; @@ -1760,6 +1796,12 @@ static inline void *__bitmap_ptr(struct f2fs_sb_info *sbi, int flag) struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi); int offset; + if (is_set_ckpt_flags(sbi, CP_LARGE_NAT_BITMAP_FLAG)) { + offset = (flag == SIT_BITMAP) ? + le32_to_cpu(ckpt->nat_ver_bitmap_bytesize) : 0; + return &ckpt->sit_nat_version_bitmap + offset; + } + if (__cp_payload(sbi) > 0) { if (flag == NAT_BITMAP) return &ckpt->sit_nat_version_bitmap; @@ -1826,7 +1868,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, sbi->current_reserved_blocks + 1; if (!__allow_reserved_blocks(sbi, inode)) - valid_block_count += sbi->root_reserved_blocks; + valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(valid_block_count > sbi->user_block_count)) { spin_unlock(&sbi->stat_lock); @@ -2428,7 +2470,17 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync) } if (!is_inode_flag_set(inode, FI_AUTO_RECOVER) || file_keep_isize(inode) || - i_size_read(inode) & PAGE_MASK) + i_size_read(inode) & ~PAGE_MASK) + return false; + + if (!timespec_equal(F2FS_I(inode)->i_disk_time, &inode->i_atime)) + return false; + if (!timespec_equal(F2FS_I(inode)->i_disk_time + 1, &inode->i_ctime)) + return false; + if (!timespec_equal(F2FS_I(inode)->i_disk_time + 2, &inode->i_mtime)) + return false; + if (!timespec_equal(F2FS_I(inode)->i_disk_time + 3, + &F2FS_I(inode)->i_crtime)) return false; down_read(&F2FS_I(inode)->i_sem); @@ -2438,8 +2490,7 @@ static inline bool f2fs_skip_inode_update(struct inode *inode, int dsync) return ret; } -#define sb_rdonly f2fs_readonly -static inline int f2fs_readonly(struct super_block *sb) +static inline bool f2fs_readonly(struct super_block *sb) { return sb->s_flags & MS_RDONLY; } @@ -2501,15 +2552,6 @@ static inline void *kvzalloc(size_t size, gfp_t flags) return ret; } -enum rw_hint { - WRITE_LIFE_NOT_SET = 0, - WRITE_LIFE_NONE = 1, /* RWH_WRITE_LIFE_NONE */ - WRITE_LIFE_SHORT = 2, /* RWH_WRITE_LIFE_SHORT */ - WRITE_LIFE_MEDIUM = 3, /* RWH_WRITE_LIFE_MEDIUM */ - WRITE_LIFE_LONG = 4, /* RWH_WRITE_LIFE_LONG */ - WRITE_LIFE_EXTREME = 5, /* RWH_WRITE_LIFE_EXTREME */ -}; - static inline int wbc_to_write_flags(struct writeback_control *wbc) { if (wbc->sync_mode == WB_SYNC_ALL) @@ -2628,6 +2670,8 @@ void handle_failed_inode(struct inode *inode); /* * namei.c */ +int update_extension_list(struct f2fs_sb_info *sbi, const char *name, + bool hot, bool set); struct dentry *f2fs_get_parent(struct dentry *child); /* @@ -2800,6 +2844,8 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi); int __init create_segment_manager_caches(void); void destroy_segment_manager_caches(void); int rw_hint_to_seg_type(enum rw_hint hint); +enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi, enum page_type type, + enum temp_type temp); /* * checkpoint.c @@ -2882,6 +2928,7 @@ int f2fs_release_page(struct page *page, gfp_t wait); int f2fs_migrate_page(struct address_space *mapping, struct page *newpage, struct page *page, enum migrate_mode mode); #endif +bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len); /* * gc.c @@ -3204,45 +3251,21 @@ static inline bool f2fs_bio_encrypted(struct bio *bio) return bio->bi_private != NULL; } -static inline int f2fs_sb_has_crypto(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_ENCRYPT); -} - -static inline int f2fs_sb_mounted_blkzoned(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_BLKZONED); -} - -static inline int f2fs_sb_has_extra_attr(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_EXTRA_ATTR); -} - -static inline int f2fs_sb_has_project_quota(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_PRJQUOTA); -} - -static inline int f2fs_sb_has_inode_chksum(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CHKSUM); -} - -static inline int f2fs_sb_has_flexible_inline_xattr(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_FLEXIBLE_INLINE_XATTR); -} - -static inline int f2fs_sb_has_quota_ino(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_QUOTA_INO); +#define F2FS_FEATURE_FUNCS(name, flagname) \ +static inline int f2fs_sb_has_##name(struct super_block *sb) \ +{ \ + return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_##flagname); \ } -static inline int f2fs_sb_has_inode_crtime(struct super_block *sb) -{ - return F2FS_HAS_FEATURE(sb, F2FS_FEATURE_INODE_CRTIME); -} +F2FS_FEATURE_FUNCS(encrypt, ENCRYPT); +F2FS_FEATURE_FUNCS(blkzoned, BLKZONED); +F2FS_FEATURE_FUNCS(extra_attr, EXTRA_ATTR); +F2FS_FEATURE_FUNCS(project_quota, PRJQUOTA); +F2FS_FEATURE_FUNCS(inode_chksum, INODE_CHKSUM); +F2FS_FEATURE_FUNCS(flexible_inline_xattr, FLEXIBLE_INLINE_XATTR); +F2FS_FEATURE_FUNCS(quota_ino, QUOTA_INO); +F2FS_FEATURE_FUNCS(inode_crtime, INODE_CRTIME); +F2FS_FEATURE_FUNCS(lost_found, LOST_FOUND); #ifdef CONFIG_BLK_DEV_ZONED static inline int get_blkz_type(struct f2fs_sb_info *sbi, @@ -3262,7 +3285,7 @@ static inline bool f2fs_discard_en(struct f2fs_sb_info *sbi) { struct request_queue *q = bdev_get_queue(sbi->sb->s_bdev); - return blk_queue_discard(q) || f2fs_sb_mounted_blkzoned(sbi->sb); + return blk_queue_discard(q) || f2fs_sb_has_blkzoned(sbi->sb); } static inline void set_opt_mode(struct f2fs_sb_info *sbi, unsigned int mt) @@ -3291,4 +3314,11 @@ static inline bool f2fs_may_encrypt(struct inode *inode) #endif } +static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) +{ + return (f2fs_encrypted_file(inode) || + (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || + F2FS_I_SB(inode)->s_ndevs); +} + #endif diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index b926df73d75d..7ed0463dc56e 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -165,9 +165,10 @@ static inline enum cp_reason_type need_do_checkpoint(struct inode *inode) cp_reason = CP_NODE_NEED_CP; else if (test_opt(sbi, FASTBOOT)) cp_reason = CP_FASTBOOT_MODE; - else if (sbi->active_logs == 2) + else if (F2FS_OPTION(sbi).active_logs == 2) cp_reason = CP_SPEC_LOG_NUM; - else if (need_dentry_mark(sbi, inode->i_ino) && + else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT && + need_dentry_mark(sbi, inode->i_ino) && exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO)) cp_reason = CP_RECOVER_DIR; @@ -480,6 +481,9 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) if (err) return err; + + filp->f_mode |= FMODE_NOWAIT; + return dquot_file_open(inode, filp); } @@ -570,7 +574,6 @@ static int truncate_partial_data_page(struct inode *inode, u64 from, int truncate_blocks(struct inode *inode, u64 from, bool lock) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - unsigned int blocksize = inode->i_sb->s_blocksize; struct dnode_of_data dn; pgoff_t free_from; int count = 0, err = 0; @@ -579,7 +582,7 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock) trace_f2fs_truncate_blocks_enter(inode, from); - free_from = (pgoff_t)F2FS_BYTES_TO_BLK(from + blocksize - 1); + free_from = (pgoff_t)F2FS_BLK_ALIGN(from); if (free_from >= sbi->max_file_blocks) goto free_partial; @@ -1350,8 +1353,12 @@ static int f2fs_zero_range(struct inode *inode, loff_t offset, loff_t len, } out: - if (!(mode & FALLOC_FL_KEEP_SIZE) && i_size_read(inode) < new_size) - f2fs_i_size_write(inode, new_size); + if (new_size > i_size_read(inode)) { + if (mode & FALLOC_FL_KEEP_SIZE) + file_set_keep_isize(inode); + else + f2fs_i_size_write(inode, new_size); + } out_sem: up_write(&F2FS_I(inode)->i_mmap_sem); @@ -1705,6 +1712,8 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) inode_lock(inode); + down_write(&F2FS_I(inode)->dio_rwsem[WRITE]); + if (f2fs_is_volatile_file(inode)) goto err_out; @@ -1723,6 +1732,7 @@ static int f2fs_ioc_commit_atomic_write(struct file *filp) ret = f2fs_do_sync_file(filp, 0, LLONG_MAX, 1, false); } err_out: + up_write(&F2FS_I(inode)->dio_rwsem[WRITE]); inode_unlock(inode); mnt_drop_write_file(filp); return ret; @@ -1932,7 +1942,7 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); - if (!f2fs_sb_has_crypto(inode->i_sb)) + if (!f2fs_sb_has_encrypt(inode->i_sb)) return -EOPNOTSUPP; f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); @@ -1942,7 +1952,7 @@ static int f2fs_ioc_set_encryption_policy(struct file *filp, unsigned long arg) static int f2fs_ioc_get_encryption_policy(struct file *filp, unsigned long arg) { - if (!f2fs_sb_has_crypto(file_inode(filp)->i_sb)) + if (!f2fs_sb_has_encrypt(file_inode(filp)->i_sb)) return -EOPNOTSUPP; return fscrypt_ioctl_get_policy(filp, (void __user *)arg); } @@ -1953,16 +1963,18 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); int err; - if (!f2fs_sb_has_crypto(inode->i_sb)) + if (!f2fs_sb_has_encrypt(inode->i_sb)) return -EOPNOTSUPP; - if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt)) - goto got_it; - err = mnt_want_write_file(filp); if (err) return err; + down_write(&sbi->sb_lock); + + if (uuid_is_nonzero(sbi->raw_super->encrypt_pw_salt)) + goto got_it; + /* update superblock with uuid */ generate_random_uuid(sbi->raw_super->encrypt_pw_salt); @@ -1970,15 +1982,16 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) if (err) { /* undo new data */ memset(sbi->raw_super->encrypt_pw_salt, 0, 16); - mnt_drop_write_file(filp); - return err; + goto out_err; } - mnt_drop_write_file(filp); got_it: if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt, 16)) - return -EFAULT; - return 0; + err = -EFAULT; +out_err: + up_write(&sbi->sb_lock); + mnt_drop_write_file(filp); + return err; } static int f2fs_ioc_gc(struct file *filp, unsigned long arg) @@ -2039,8 +2052,10 @@ static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg) return ret; end = range.start + range.len; - if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) - return -EINVAL; + if (range.start < MAIN_BLKADDR(sbi) || end >= MAX_BLKADDR(sbi)) { + ret = -EINVAL; + goto out; + } do_more: if (!range.sync) { if (!mutex_trylock(&sbi->gc_mutex)) { @@ -2681,25 +2696,54 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (unlikely(f2fs_cp_error(F2FS_I_SB(inode)))) return -EIO; - inode_lock(inode); + if ((iocb->ki_flags & IOCB_NOWAIT) && !(iocb->ki_flags & IOCB_DIRECT)) + return -EINVAL; + + if (!inode_trylock(inode)) { + if (iocb->ki_flags & IOCB_NOWAIT) + return -EAGAIN; + inode_lock(inode); + } + ret = generic_write_checks(iocb, from); if (ret > 0) { + bool preallocated = false; + size_t target_size = 0; int err; if (iov_iter_fault_in_readable(from, iov_iter_count(from))) set_inode_flag(inode, FI_NO_PREALLOC); - err = f2fs_preallocate_blocks(iocb, from); - if (err) { - clear_inode_flag(inode, FI_NO_PREALLOC); - inode_unlock(inode); - return err; + if ((iocb->ki_flags & IOCB_NOWAIT) && + (iocb->ki_flags & IOCB_DIRECT)) { + if (!f2fs_overwrite_io(inode, iocb->ki_pos, + iov_iter_count(from)) || + f2fs_has_inline_data(inode) || + f2fs_force_buffered_io(inode, WRITE)) { + inode_unlock(inode); + return -EAGAIN; + } + + } else { + preallocated = true; + target_size = iocb->ki_pos + iov_iter_count(from); + + err = f2fs_preallocate_blocks(iocb, from); + if (err) { + clear_inode_flag(inode, FI_NO_PREALLOC); + inode_unlock(inode); + return err; + } } blk_start_plug(&plug); ret = __generic_file_write_iter(iocb, from); blk_finish_plug(&plug); clear_inode_flag(inode, FI_NO_PREALLOC); + /* if we couldn't write data, we should deallocate blocks. */ + if (preallocated && i_size_read(inode) < target_size) + f2fs_truncate(inode); + if (ret > 0) f2fs_update_iostat(F2FS_I_SB(inode), APP_WRITE_IO, ret); } diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 3b26aa19430b..0ad8b3a7a74d 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -76,14 +76,15 @@ static int gc_thread_func(void *data) * invalidated soon after by user update or deletion. * So, I'd like to wait some time to collect dirty segments. */ - if (!mutex_trylock(&sbi->gc_mutex)) - goto next; - if (gc_th->gc_urgent) { wait_ms = gc_th->urgent_sleep_time; + mutex_lock(&sbi->gc_mutex); goto do_gc; } + if (!mutex_trylock(&sbi->gc_mutex)) + goto next; + if (!is_idle(sbi)) { increase_sleep_time(gc_th, &wait_ms); mutex_unlock(&sbi->gc_mutex); @@ -161,12 +162,17 @@ static int select_gc_type(struct f2fs_gc_kthread *gc_th, int gc_type) { int gc_mode = (gc_type == BG_GC) ? GC_CB : GC_GREEDY; - if (gc_th && gc_th->gc_idle) { + if (!gc_th) + return gc_mode; + + if (gc_th->gc_idle) { if (gc_th->gc_idle == 1) gc_mode = GC_CB; else if (gc_th->gc_idle == 2) gc_mode = GC_GREEDY; } + if (gc_th->gc_urgent) + gc_mode = GC_GREEDY; return gc_mode; } @@ -188,11 +194,14 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type, } /* we need to check every dirty segments in the FG_GC case */ - if (gc_type != FG_GC && p->max_search > sbi->max_victim_search) + if (gc_type != FG_GC && + (sbi->gc_thread && !sbi->gc_thread->gc_urgent) && + p->max_search > sbi->max_victim_search) p->max_search = sbi->max_victim_search; - /* let's select beginning hot/small space first */ - if (type == CURSEG_HOT_DATA || IS_NODESEG(type)) + /* let's select beginning hot/small space first in no_heap mode*/ + if (test_opt(sbi, NOHEAP) && + (type == CURSEG_HOT_DATA || IS_NODESEG(type))) p->offset = 0; else p->offset = SIT_I(sbi)->last_victim[p->gc_mode]; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 10be247ca421..e0d9e8f27ed2 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -284,6 +284,10 @@ static int do_read_inode(struct inode *inode) fi->i_crtime.tv_nsec = le32_to_cpu(ri->i_crtime_nsec); } + F2FS_I(inode)->i_disk_time[0] = inode->i_atime; + F2FS_I(inode)->i_disk_time[1] = inode->i_ctime; + F2FS_I(inode)->i_disk_time[2] = inode->i_mtime; + F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime; f2fs_put_page(node_page, 1); stat_inc_inline_xattr(inode); @@ -439,12 +443,15 @@ void update_inode(struct inode *inode, struct page *node_page) } __set_inode_rdev(inode, ri); - set_cold_node(inode, node_page); /* deleted inode */ if (inode->i_nlink == 0) clear_inline_node(node_page); + F2FS_I(inode)->i_disk_time[0] = inode->i_atime; + F2FS_I(inode)->i_disk_time[1] = inode->i_ctime; + F2FS_I(inode)->i_disk_time[2] = inode->i_mtime; + F2FS_I(inode)->i_disk_time[3] = F2FS_I(inode)->i_crtime; } void update_inode_page(struct inode *inode) @@ -585,7 +592,7 @@ void f2fs_evict_inode(struct inode *inode) !exist_written_data(sbi, inode->i_ino, ORPHAN_INO)); } out_clear: - fscrypt_put_encryption_info(inode, NULL); + fscrypt_put_encryption_info(inode); clear_inode(inode); } diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 59e8dca77aa3..2d49029b392d 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -78,7 +78,8 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) set_inode_flag(inode, FI_NEW_INODE); /* If the directory encrypted, then we should encrypt the inode. */ - if (f2fs_encrypted_inode(dir) && f2fs_may_encrypt(inode)) + if ((f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) && + f2fs_may_encrypt(inode)) f2fs_set_encrypted_inode(inode); if (f2fs_sb_has_extra_attr(sbi->sb)) { @@ -97,7 +98,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) if (f2fs_sb_has_flexible_inline_xattr(sbi->sb)) { f2fs_bug_on(sbi, !f2fs_has_extra_attr(inode)); if (f2fs_has_inline_xattr(inode)) - xattr_size = sbi->inline_xattr_size; + xattr_size = F2FS_OPTION(sbi).inline_xattr_size; /* Otherwise, will be 0 */ } else if (f2fs_has_inline_xattr(inode) || f2fs_has_inline_dentry(inode)) { @@ -142,7 +143,7 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode) return ERR_PTR(err); } -static int is_multimedia_file(const unsigned char *s, const char *sub) +static int is_extension_exist(const unsigned char *s, const char *sub) { size_t slen = strlen(s); size_t sublen = strlen(sub); @@ -168,19 +169,94 @@ static int is_multimedia_file(const unsigned char *s, const char *sub) /* * Set multimedia files as cold files for hot/cold data separation */ -static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode, +static inline void set_file_temperature(struct f2fs_sb_info *sbi, struct inode *inode, const unsigned char *name) { - int i; - __u8 (*extlist)[8] = sbi->raw_super->extension_list; + __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; + int i, cold_count, hot_count; + + down_read(&sbi->sb_lock); + + cold_count = le32_to_cpu(sbi->raw_super->extension_count); + hot_count = sbi->raw_super->hot_ext_count; - int count = le32_to_cpu(sbi->raw_super->extension_count); - for (i = 0; i < count; i++) { - if (is_multimedia_file(name, extlist[i])) { + for (i = 0; i < cold_count + hot_count; i++) { + if (!is_extension_exist(name, extlist[i])) + continue; + if (i < cold_count) file_set_cold(inode); - break; - } + else + file_set_hot(inode); + break; } + + up_read(&sbi->sb_lock); +} + +int update_extension_list(struct f2fs_sb_info *sbi, const char *name, + bool hot, bool set) +{ + __u8 (*extlist)[F2FS_EXTENSION_LEN] = sbi->raw_super->extension_list; + int cold_count = le32_to_cpu(sbi->raw_super->extension_count); + int hot_count = sbi->raw_super->hot_ext_count; + int total_count = cold_count + hot_count; + int start, count; + int i; + + if (set) { + if (total_count == F2FS_MAX_EXTENSION) + return -EINVAL; + } else { + if (!hot && !cold_count) + return -EINVAL; + if (hot && !hot_count) + return -EINVAL; + } + + if (hot) { + start = cold_count; + count = total_count; + } else { + start = 0; + count = cold_count; + } + + for (i = start; i < count; i++) { + if (strcmp(name, extlist[i])) + continue; + + if (set) + return -EINVAL; + + memcpy(extlist[i], extlist[i + 1], + F2FS_EXTENSION_LEN * (total_count - i - 1)); + memset(extlist[total_count - 1], 0, F2FS_EXTENSION_LEN); + if (hot) + sbi->raw_super->hot_ext_count = hot_count - 1; + else + sbi->raw_super->extension_count = + cpu_to_le32(cold_count - 1); + return 0; + } + + if (!set) + return -EINVAL; + + if (hot) { + strncpy(extlist[count], name, strlen(name)); + sbi->raw_super->hot_ext_count = hot_count + 1; + } else { + char buf[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN]; + + memcpy(buf, &extlist[cold_count], + F2FS_EXTENSION_LEN * hot_count); + memset(extlist[cold_count], 0, F2FS_EXTENSION_LEN); + strncpy(extlist[cold_count], name, strlen(name)); + memcpy(&extlist[cold_count + 1], buf, + F2FS_EXTENSION_LEN * hot_count); + sbi->raw_super->extension_count = cpu_to_le32(cold_count + 1); + } + return 0; } static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, @@ -203,7 +279,7 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, return PTR_ERR(inode); if (!test_opt(sbi, DISABLE_EXT_IDENTIFY)) - set_cold_files(sbi, inode, dentry->d_name.name); + set_file_temperature(sbi, inode, dentry->d_name.name); inode->i_op = &f2fs_file_inode_operations; inode->i_fop = &f2fs_file_operations; @@ -481,27 +557,16 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, struct f2fs_sb_info *sbi = F2FS_I_SB(dir); struct inode *inode; size_t len = strlen(symname); - struct fscrypt_str disk_link = FSTR_INIT((char *)symname, len + 1); - struct fscrypt_symlink_data *sd = NULL; + struct fscrypt_str disk_link; int err; if (unlikely(f2fs_cp_error(sbi))) return -EIO; - if (f2fs_encrypted_inode(dir)) { - err = fscrypt_get_encryption_info(dir); - if (err) - return err; - - if (!fscrypt_has_encryption_key(dir)) - return -ENOKEY; - - disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + - sizeof(struct fscrypt_symlink_data)); - } - - if (disk_link.len > dir->i_sb->s_blocksize) - return -ENAMETOOLONG; + err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize, + &disk_link); + if (err) + return err; err = dquot_initialize(dir); if (err) @@ -511,7 +576,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, if (IS_ERR(inode)) return PTR_ERR(inode); - if (f2fs_encrypted_inode(inode)) + if (IS_ENCRYPTED(inode)) inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; @@ -521,38 +586,13 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, f2fs_lock_op(sbi); err = f2fs_add_link(dentry, inode); if (err) - goto out; + goto out_handle_failed_inode; f2fs_unlock_op(sbi); alloc_nid_done(sbi, inode->i_ino); - if (f2fs_encrypted_inode(inode)) { - struct qstr istr = QSTR_INIT(symname, len); - struct fscrypt_str ostr; - - sd = f2fs_kzalloc(sbi, disk_link.len, GFP_NOFS); - if (!sd) { - err = -ENOMEM; - goto err_out; - } - - err = fscrypt_get_encryption_info(inode); - if (err) - goto err_out; - - if (!fscrypt_has_encryption_key(inode)) { - err = -ENOKEY; - goto err_out; - } - - ostr.name = sd->encrypted_path; - ostr.len = disk_link.len; - err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); - if (err) - goto err_out; - - sd->len = cpu_to_le16(ostr.len); - disk_link.name = (char *)sd; - } + err = fscrypt_encrypt_symlink(inode, symname, len, &disk_link); + if (err) + goto err_out; err = page_symlink(inode, disk_link.name, disk_link.len); @@ -579,12 +619,14 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, f2fs_unlink(dir, dentry); } - kfree(sd); - f2fs_balance_fs(sbi, true); - return err; -out: + goto out_free_encrypted_link; + +out_handle_failed_inode: handle_failed_inode(inode); +out_free_encrypted_link: + if (disk_link.name != (unsigned char *)symname) + kfree(disk_link.name); return err; } @@ -746,10 +788,12 @@ static int __f2fs_tmpfile(struct inode *dir, struct dentry *dentry, static int f2fs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) { - if (unlikely(f2fs_cp_error(F2FS_I_SB(dir)))) + struct f2fs_sb_info *sbi = F2FS_I_SB(dir); + + if (unlikely(f2fs_cp_error(sbi))) return -EIO; - if (f2fs_encrypted_inode(dir)) { + if (f2fs_encrypted_inode(dir) || DUMMY_ENCRYPTION_ENABLED(sbi)) { int err = fscrypt_get_encryption_info(dir); if (err) return err; @@ -929,7 +973,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry, f2fs_put_page(old_dir_page, 0); f2fs_i_links_write(old_dir, false); } - add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) + add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); f2fs_unlock_op(sbi); @@ -1079,8 +1124,10 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry, } f2fs_mark_inode_dirty_sync(new_dir, false); - add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO); - add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) { + add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO); + add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO); + } f2fs_unlock_op(sbi); @@ -1132,68 +1179,20 @@ static const char *f2fs_encrypted_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { - struct page *cpage = NULL; - char *caddr, *paddr = NULL; - struct fscrypt_str cstr = FSTR_INIT(NULL, 0); - struct fscrypt_str pstr = FSTR_INIT(NULL, 0); - struct fscrypt_symlink_data *sd; - u32 max_size = inode->i_sb->s_blocksize; - int res; + struct page *page; + const char *target; if (!dentry) return ERR_PTR(-ECHILD); - res = fscrypt_get_encryption_info(inode); - if (res) - return ERR_PTR(res); - - cpage = read_mapping_page(inode->i_mapping, 0, NULL); - if (IS_ERR(cpage)) - return ERR_CAST(cpage); - caddr = page_address(cpage); - - /* Symlink is encrypted */ - sd = (struct fscrypt_symlink_data *)caddr; - cstr.name = sd->encrypted_path; - cstr.len = le16_to_cpu(sd->len); - - /* this is broken symlink case */ - if (unlikely(cstr.len == 0)) { - res = -ENOENT; - goto errout; - } - - if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { - /* Symlink data on the disk is corrupted */ - res = -EIO; - goto errout; - } - res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); - if (res) - goto errout; - - res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); - if (res) - goto errout; - - /* this is broken symlink case */ - if (unlikely(pstr.name[0] == 0)) { - res = -ENOENT; - goto errout; - } - - paddr = pstr.name; - - /* Null-terminate the name */ - paddr[pstr.len] = '\0'; + page = read_mapping_page(inode->i_mapping, 0, NULL); + if (IS_ERR(page)) + return ERR_CAST(page); - put_page(cpage); - set_delayed_call(done, kfree_link, paddr); - return paddr; -errout: - fscrypt_fname_free_buffer(&pstr); - put_page(cpage); - return ERR_PTR(res); + target = fscrypt_get_symlink(inode, page_address(page), + inode->i_sb->s_blocksize, done); + put_page(page); + return target; } const struct inode_operations f2fs_encrypted_symlink_inode_operations = { diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 7cded843cf18..199170e2e221 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -193,8 +193,8 @@ static void __del_from_nat_cache(struct f2fs_nm_info *nm_i, struct nat_entry *e) __free_nat_entry(e); } -static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, - struct nat_entry *ne) +static struct nat_entry_set *__grab_nat_entry_set(struct f2fs_nm_info *nm_i, + struct nat_entry *ne) { nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid); struct nat_entry_set *head; @@ -209,15 +209,36 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, head->entry_cnt = 0; f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head); } + return head; +} + +static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, + struct nat_entry *ne) +{ + struct nat_entry_set *head; + bool new_ne = nat_get_blkaddr(ne) == NEW_ADDR; + + if (!new_ne) + head = __grab_nat_entry_set(nm_i, ne); + + /* + * update entry_cnt in below condition: + * 1. update NEW_ADDR to valid block address; + * 2. update old block address to new one; + */ + if (!new_ne && (get_nat_flag(ne, IS_PREALLOC) || + !get_nat_flag(ne, IS_DIRTY))) + head->entry_cnt++; + + set_nat_flag(ne, IS_PREALLOC, new_ne); if (get_nat_flag(ne, IS_DIRTY)) goto refresh_list; nm_i->dirty_nat_cnt++; - head->entry_cnt++; set_nat_flag(ne, IS_DIRTY, true); refresh_list: - if (nat_get_blkaddr(ne) == NEW_ADDR) + if (new_ne) list_del_init(&ne->list); else list_move_tail(&ne->list, &head->entry_list); @@ -1076,7 +1097,7 @@ struct page *new_node_page(struct dnode_of_data *dn, unsigned int ofs) f2fs_wait_on_page_writeback(page, NODE, true); fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true); - set_cold_node(dn->inode, page); + set_cold_node(page, S_ISDIR(dn->inode->i_mode)); if (!PageUptodate(page)) SetPageUptodate(page); if (set_page_dirty(page)) @@ -2310,6 +2331,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page) if (!PageUptodate(ipage)) SetPageUptodate(ipage); fill_node_footer(ipage, ino, ino, 0, true); + set_cold_node(page, false); src = F2FS_INODE(page); dst = F2FS_INODE(ipage); @@ -2599,8 +2621,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi) if (!enabled_nat_bits(sbi, NULL)) return 0; - nm_i->nat_bits_blocks = F2FS_BYTES_TO_BLK((nat_bits_bytes << 1) + 8 + - F2FS_BLKSIZE - 1); + nm_i->nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8); nm_i->nat_bits = f2fs_kzalloc(sbi, nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL); if (!nm_i->nat_bits) @@ -2726,12 +2747,20 @@ static int init_node_manager(struct f2fs_sb_info *sbi) static int init_free_nid_cache(struct f2fs_sb_info *sbi) { struct f2fs_nm_info *nm_i = NM_I(sbi); + int i; - nm_i->free_nid_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks * - NAT_ENTRY_BITMAP_SIZE, GFP_KERNEL); + nm_i->free_nid_bitmap = f2fs_kzalloc(sbi, nm_i->nat_blocks * + sizeof(unsigned char *), GFP_KERNEL); if (!nm_i->free_nid_bitmap) return -ENOMEM; + for (i = 0; i < nm_i->nat_blocks; i++) { + nm_i->free_nid_bitmap[i] = f2fs_kvzalloc(sbi, + NAT_ENTRY_BITMAP_SIZE_ALIGNED, GFP_KERNEL); + if (!nm_i->free_nid_bitmap) + return -ENOMEM; + } + nm_i->nat_block_bitmap = f2fs_kvzalloc(sbi, nm_i->nat_blocks / 8, GFP_KERNEL); if (!nm_i->nat_block_bitmap) @@ -2822,7 +2851,13 @@ void destroy_node_manager(struct f2fs_sb_info *sbi) up_write(&nm_i->nat_tree_lock); kvfree(nm_i->nat_block_bitmap); - kvfree(nm_i->free_nid_bitmap); + if (nm_i->free_nid_bitmap) { + int i; + + for (i = 0; i < nm_i->nat_blocks; i++) + kvfree(nm_i->free_nid_bitmap[i]); + kfree(nm_i->free_nid_bitmap); + } kvfree(nm_i->free_nid_count); kfree(nm_i->nat_bitmap); diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h index 081ef0d672bf..b95e49e4a928 100644 --- a/fs/f2fs/node.h +++ b/fs/f2fs/node.h @@ -44,6 +44,7 @@ enum { HAS_FSYNCED_INODE, /* is the inode fsynced before? */ HAS_LAST_FSYNC, /* has the latest node fsync mark? */ IS_DIRTY, /* this nat entry is dirty? */ + IS_PREALLOC, /* nat entry is preallocated */ }; /* @@ -422,12 +423,12 @@ static inline void clear_inline_node(struct page *page) ClearPageChecked(page); } -static inline void set_cold_node(struct inode *inode, struct page *page) +static inline void set_cold_node(struct page *page, bool is_dir) { struct f2fs_node *rn = F2FS_NODE(page); unsigned int flag = le32_to_cpu(rn->footer.flag); - if (S_ISDIR(inode->i_mode)) + if (is_dir) flag &= ~(0x1 << COLD_BIT_SHIFT); else flag |= (0x1 << COLD_BIT_SHIFT); diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 210de28c9cd2..4ddc2262baf1 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -242,6 +242,9 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, struct curseg_info *curseg; struct page *page = NULL; block_t blkaddr; + unsigned int loop_cnt = 0; + unsigned int free_blocks = sbi->user_block_count - + valid_user_blocks(sbi); int err = 0; /* get node pages in the current segment */ @@ -294,6 +297,17 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head, if (IS_INODE(page) && is_dent_dnode(page)) entry->last_dentry = blkaddr; next: + /* sanity check in order to detect looped node chain */ + if (++loop_cnt >= free_blocks || + blkaddr == next_blkaddr_of_node(page)) { + f2fs_msg(sbi->sb, KERN_NOTICE, + "%s: detect looped node chain, " + "blkaddr:%u, next:%u", + __func__, blkaddr, next_blkaddr_of_node(page)); + err = -EINVAL; + break; + } + /* check next segment */ blkaddr = next_blkaddr_of_node(page); f2fs_put_page(page, 1); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index cc34d8852438..fc4ee3835f1d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1411,12 +1411,11 @@ static int issue_discard_thread(void *data) if (kthread_should_stop()) return 0; - if (dcc->discard_wake) { + if (dcc->discard_wake) dcc->discard_wake = 0; - if (sbi->gc_thread && sbi->gc_thread->gc_urgent) - init_discard_policy(&dpolicy, - DPOLICY_FORCE, 1); - } + + if (sbi->gc_thread && sbi->gc_thread->gc_urgent) + init_discard_policy(&dpolicy, DPOLICY_FORCE, 1); sb_start_intwrite(sbi->sb); @@ -1485,7 +1484,7 @@ static int __issue_discard_async(struct f2fs_sb_info *sbi, struct block_device *bdev, block_t blkstart, block_t blklen) { #ifdef CONFIG_BLK_DEV_ZONED - if (f2fs_sb_mounted_blkzoned(sbi->sb) && + if (f2fs_sb_has_blkzoned(sbi->sb) && bdev_zoned_model(bdev) != BLK_ZONED_NONE) return __f2fs_issue_discard_zone(sbi, bdev, blkstart, blklen); #endif @@ -1683,7 +1682,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) sbi->blocks_per_seg, cur_pos); len = next_pos - cur_pos; - if (f2fs_sb_mounted_blkzoned(sbi->sb) || + if (f2fs_sb_has_blkzoned(sbi->sb) || (force && len < cpc->trim_minlen)) goto skip; @@ -1727,7 +1726,7 @@ void init_discard_policy(struct discard_policy *dpolicy, } else if (discard_type == DPOLICY_FORCE) { dpolicy->min_interval = DEF_MIN_DISCARD_ISSUE_TIME; dpolicy->max_interval = DEF_MAX_DISCARD_ISSUE_TIME; - dpolicy->io_aware = true; + dpolicy->io_aware = false; } else if (discard_type == DPOLICY_FSTRIM) { dpolicy->io_aware = false; } else if (discard_type == DPOLICY_UMOUNT) { @@ -1863,7 +1862,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) sbi->discard_blks--; /* don't overwrite by SSR to keep node chain */ - if (se->type == CURSEG_WARM_NODE) { + if (IS_NODESEG(se->type)) { if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map)) se->ckpt_valid_blocks++; } @@ -2164,11 +2163,17 @@ static unsigned int __get_next_segno(struct f2fs_sb_info *sbi, int type) if (sbi->segs_per_sec != 1) return CURSEG_I(sbi, type)->segno; - if (type == CURSEG_HOT_DATA || IS_NODESEG(type)) + if (test_opt(sbi, NOHEAP) && + (type == CURSEG_HOT_DATA || IS_NODESEG(type))) return 0; if (SIT_I(sbi)->last_victim[ALLOC_NEXT]) return SIT_I(sbi)->last_victim[ALLOC_NEXT]; + + /* find segments from 0 to reuse freed segments */ + if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) + return 0; + return CURSEG_I(sbi, type)->segno; } @@ -2455,6 +2460,101 @@ int rw_hint_to_seg_type(enum rw_hint hint) } } +/* This returns write hints for each segment type. This hints will be + * passed down to block layer. There are mapping tables which depend on + * the mount option 'whint_mode'. + * + * 1) whint_mode=off. F2FS only passes down WRITE_LIFE_NOT_SET. + * + * 2) whint_mode=user-based. F2FS tries to pass down hints given by users. + * + * User F2FS Block + * ---- ---- ----- + * META WRITE_LIFE_NOT_SET + * HOT_NODE " + * WARM_NODE " + * COLD_NODE " + * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME + * extension list " " + * + * -- buffered io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE " " + * WRITE_LIFE_MEDIUM " " + * WRITE_LIFE_LONG " " + * + * -- direct io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE " WRITE_LIFE_NONE + * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM + * WRITE_LIFE_LONG " WRITE_LIFE_LONG + * + * 3) whint_mode=fs-based. F2FS passes down hints with its policy. + * + * User F2FS Block + * ---- ---- ----- + * META WRITE_LIFE_MEDIUM; + * HOT_NODE WRITE_LIFE_NOT_SET + * WARM_NODE " + * COLD_NODE WRITE_LIFE_NONE + * ioctl(COLD) COLD_DATA WRITE_LIFE_EXTREME + * extension list " " + * + * -- buffered io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_LONG + * WRITE_LIFE_NONE " " + * WRITE_LIFE_MEDIUM " " + * WRITE_LIFE_LONG " " + * + * -- direct io + * WRITE_LIFE_EXTREME COLD_DATA WRITE_LIFE_EXTREME + * WRITE_LIFE_SHORT HOT_DATA WRITE_LIFE_SHORT + * WRITE_LIFE_NOT_SET WARM_DATA WRITE_LIFE_NOT_SET + * WRITE_LIFE_NONE " WRITE_LIFE_NONE + * WRITE_LIFE_MEDIUM " WRITE_LIFE_MEDIUM + * WRITE_LIFE_LONG " WRITE_LIFE_LONG + */ + +enum rw_hint io_type_to_rw_hint(struct f2fs_sb_info *sbi, + enum page_type type, enum temp_type temp) +{ + if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) { + if (type == DATA) { + if (temp == WARM) + return WRITE_LIFE_NOT_SET; + else if (temp == HOT) + return WRITE_LIFE_SHORT; + else if (temp == COLD) + return WRITE_LIFE_EXTREME; + } else { + return WRITE_LIFE_NOT_SET; + } + } else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) { + if (type == DATA) { + if (temp == WARM) + return WRITE_LIFE_LONG; + else if (temp == HOT) + return WRITE_LIFE_SHORT; + else if (temp == COLD) + return WRITE_LIFE_EXTREME; + } else if (type == NODE) { + if (temp == WARM || temp == HOT) + return WRITE_LIFE_NOT_SET; + else if (temp == COLD) + return WRITE_LIFE_NONE; + } else if (type == META) { + return WRITE_LIFE_MEDIUM; + } + } + return WRITE_LIFE_NOT_SET; +} + static int __get_segment_type_2(struct f2fs_io_info *fio) { if (fio->type == DATA) @@ -2487,7 +2587,8 @@ static int __get_segment_type_6(struct f2fs_io_info *fio) if (is_cold_data(fio->page) || file_is_cold(inode)) return CURSEG_COLD_DATA; - if (is_inode_flag_set(inode, FI_HOT_DATA)) + if (file_is_hot(inode) || + is_inode_flag_set(inode, FI_HOT_DATA)) return CURSEG_HOT_DATA; /* rw_hint_to_seg_type(inode->i_write_hint); */ return CURSEG_WARM_DATA; @@ -2503,7 +2604,7 @@ static int __get_segment_type(struct f2fs_io_info *fio) { int type = 0; - switch (fio->sbi->active_logs) { + switch (F2FS_OPTION(fio->sbi).active_logs) { case 2: type = __get_segment_type_2(fio); break; @@ -2643,6 +2744,7 @@ void write_meta_page(struct f2fs_sb_info *sbi, struct page *page, struct f2fs_io_info fio = { .sbi = sbi, .type = META, + .temp = HOT, .op = REQ_OP_WRITE, .op_flags = REQ_SYNC | REQ_META | REQ_PRIO, .old_blkaddr = page->index, @@ -2689,8 +2791,15 @@ void write_data_page(struct dnode_of_data *dn, struct f2fs_io_info *fio) int rewrite_data_page(struct f2fs_io_info *fio) { int err; + struct f2fs_sb_info *sbi = fio->sbi; fio->new_blkaddr = fio->old_blkaddr; + /* i/o temperature is needed for passing down write hints */ + __get_segment_type(fio); + + f2fs_bug_on(sbi, !IS_DATASEG(get_seg_entry(sbi, + GET_SEGNO(sbi, fio->new_blkaddr))->type)); + stat_inc_inplace_blocks(fio->sbi); err = f2fs_submit_page_bio(fio); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index f11c4bc82c78..3325d0769723 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -53,13 +53,19 @@ ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ (sbi)->segs_per_sec)) \ -#define MAIN_BLKADDR(sbi) (SM_I(sbi)->main_blkaddr) -#define SEG0_BLKADDR(sbi) (SM_I(sbi)->seg0_blkaddr) +#define MAIN_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->main_blkaddr)) +#define SEG0_BLKADDR(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->seg0_blkaddr : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment0_blkaddr)) #define MAIN_SEGS(sbi) (SM_I(sbi)->main_segments) #define MAIN_SECS(sbi) ((sbi)->total_sections) -#define TOTAL_SEGS(sbi) (SM_I(sbi)->segment_count) +#define TOTAL_SEGS(sbi) \ + (SM_I(sbi) ? SM_I(sbi)->segment_count : \ + le32_to_cpu(F2FS_RAW_SUPER(sbi)->segment_count)) #define TOTAL_BLKS(sbi) (TOTAL_SEGS(sbi) << (sbi)->log_blocks_per_seg) #define MAX_BLKADDR(sbi) (SEG0_BLKADDR(sbi) + TOTAL_BLKS(sbi)) @@ -596,6 +602,8 @@ static inline int utilization(struct f2fs_sb_info *sbi) #define DEF_MIN_FSYNC_BLOCKS 8 #define DEF_MIN_HOT_BLOCKS 16 +#define SMALL_VOLUME_SEGMENTS (16 * 512) /* 16GB */ + enum { F2FS_IPU_FORCE, F2FS_IPU_SSR, @@ -630,10 +638,17 @@ static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1); } -static inline void verify_block_addr(struct f2fs_sb_info *sbi, block_t blk_addr) +static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr) { - BUG_ON(blk_addr < SEG0_BLKADDR(sbi) - || blk_addr >= MAX_BLKADDR(sbi)); + struct f2fs_sb_info *sbi = fio->sbi; + + if (PAGE_TYPE_OF_BIO(fio->type) == META && + (!is_read_io(fio->op) || fio->is_meta)) + BUG_ON(blk_addr < SEG0_BLKADDR(sbi) || + blk_addr >= MAIN_BLKADDR(sbi)); + else + BUG_ON(blk_addr < MAIN_BLKADDR(sbi) || + blk_addr >= MAX_BLKADDR(sbi)); } /* diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 1692c263a810..510c91b3a23b 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -60,7 +60,7 @@ char *fault_name[FAULT_MAX] = { static void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate) { - struct f2fs_fault_info *ffi = &sbi->fault_info; + struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info; if (rate) { atomic_set(&ffi->inject_ops, 0); @@ -129,6 +129,10 @@ enum { Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, + Opt_whint, + Opt_alloc, + Opt_fsync, + Opt_test_dummy_encryption, Opt_err, }; @@ -182,6 +186,10 @@ static match_table_t f2fs_tokens = { {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, + {Opt_whint, "whint_mode=%s"}, + {Opt_alloc, "alloc_mode=%s"}, + {Opt_fsync, "fsync_mode=%s"}, + {Opt_test_dummy_encryption, "test_dummy_encryption"}, {Opt_err, NULL}, }; @@ -202,21 +210,24 @@ static inline void limit_reserve_root(struct f2fs_sb_info *sbi) block_t limit = (sbi->user_block_count << 1) / 1000; /* limit is 0.2% */ - if (test_opt(sbi, RESERVE_ROOT) && sbi->root_reserved_blocks > limit) { - sbi->root_reserved_blocks = limit; + if (test_opt(sbi, RESERVE_ROOT) && + F2FS_OPTION(sbi).root_reserved_blocks > limit) { + F2FS_OPTION(sbi).root_reserved_blocks = limit; f2fs_msg(sbi->sb, KERN_INFO, "Reduce reserved blocks for root = %u", - sbi->root_reserved_blocks); + F2FS_OPTION(sbi).root_reserved_blocks); } if (!test_opt(sbi, RESERVE_ROOT) && - (!uid_eq(sbi->s_resuid, + (!uid_eq(F2FS_OPTION(sbi).s_resuid, make_kuid(&init_user_ns, F2FS_DEF_RESUID)) || - !gid_eq(sbi->s_resgid, + !gid_eq(F2FS_OPTION(sbi).s_resgid, make_kgid(&init_user_ns, F2FS_DEF_RESGID)))) f2fs_msg(sbi->sb, KERN_INFO, "Ignore s_resuid=%u, s_resgid=%u w/o reserve_root", - from_kuid_munged(&init_user_ns, sbi->s_resuid), - from_kgid_munged(&init_user_ns, sbi->s_resgid)); + from_kuid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resuid), + from_kgid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resgid)); } static void init_once(void *foo) @@ -236,7 +247,7 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype, char *qname; int ret = -EINVAL; - if (sb_any_quota_loaded(sb) && !sbi->s_qf_names[qtype]) { + if (sb_any_quota_loaded(sb) && !F2FS_OPTION(sbi).s_qf_names[qtype]) { f2fs_msg(sb, KERN_ERR, "Cannot change journaled " "quota options when quota turned on"); @@ -254,8 +265,8 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype, "Not enough memory for storing quotafile name"); return -EINVAL; } - if (sbi->s_qf_names[qtype]) { - if (strcmp(sbi->s_qf_names[qtype], qname) == 0) + if (F2FS_OPTION(sbi).s_qf_names[qtype]) { + if (strcmp(F2FS_OPTION(sbi).s_qf_names[qtype], qname) == 0) ret = 0; else f2fs_msg(sb, KERN_ERR, @@ -268,7 +279,7 @@ static int f2fs_set_qf_name(struct super_block *sb, int qtype, "quotafile must be on filesystem root"); goto errout; } - sbi->s_qf_names[qtype] = qname; + F2FS_OPTION(sbi).s_qf_names[qtype] = qname; set_opt(sbi, QUOTA); return 0; errout: @@ -280,13 +291,13 @@ static int f2fs_clear_qf_name(struct super_block *sb, int qtype) { struct f2fs_sb_info *sbi = F2FS_SB(sb); - if (sb_any_quota_loaded(sb) && sbi->s_qf_names[qtype]) { + if (sb_any_quota_loaded(sb) && F2FS_OPTION(sbi).s_qf_names[qtype]) { f2fs_msg(sb, KERN_ERR, "Cannot change journaled quota options" " when quota turned on"); return -EINVAL; } - kfree(sbi->s_qf_names[qtype]); - sbi->s_qf_names[qtype] = NULL; + kfree(F2FS_OPTION(sbi).s_qf_names[qtype]); + F2FS_OPTION(sbi).s_qf_names[qtype] = NULL; return 0; } @@ -302,15 +313,19 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi) "Cannot enable project quota enforcement."); return -1; } - if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA] || - sbi->s_qf_names[PRJQUOTA]) { - if (test_opt(sbi, USRQUOTA) && sbi->s_qf_names[USRQUOTA]) + if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA] || + F2FS_OPTION(sbi).s_qf_names[GRPQUOTA] || + F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) { + if (test_opt(sbi, USRQUOTA) && + F2FS_OPTION(sbi).s_qf_names[USRQUOTA]) clear_opt(sbi, USRQUOTA); - if (test_opt(sbi, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA]) + if (test_opt(sbi, GRPQUOTA) && + F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]) clear_opt(sbi, GRPQUOTA); - if (test_opt(sbi, PRJQUOTA) && sbi->s_qf_names[PRJQUOTA]) + if (test_opt(sbi, PRJQUOTA) && + F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) clear_opt(sbi, PRJQUOTA); if (test_opt(sbi, GRPQUOTA) || test_opt(sbi, USRQUOTA) || @@ -320,19 +335,19 @@ static int f2fs_check_quota_options(struct f2fs_sb_info *sbi) return -1; } - if (!sbi->s_jquota_fmt) { + if (!F2FS_OPTION(sbi).s_jquota_fmt) { f2fs_msg(sbi->sb, KERN_ERR, "journaled quota format " "not specified"); return -1; } } - if (f2fs_sb_has_quota_ino(sbi->sb) && sbi->s_jquota_fmt) { + if (f2fs_sb_has_quota_ino(sbi->sb) && F2FS_OPTION(sbi).s_jquota_fmt) { f2fs_msg(sbi->sb, KERN_INFO, "QUOTA feature is enabled, so ignore jquota_fmt"); - sbi->s_jquota_fmt = 0; + F2FS_OPTION(sbi).s_jquota_fmt = 0; } - if (f2fs_sb_has_quota_ino(sbi->sb) && sb_rdonly(sbi->sb)) { + if (f2fs_sb_has_quota_ino(sbi->sb) && f2fs_readonly(sbi->sb)) { f2fs_msg(sbi->sb, KERN_INFO, "Filesystem with quota feature cannot be mounted RDWR " "without CONFIG_QUOTA"); @@ -403,14 +418,14 @@ static int parse_options(struct super_block *sb, char *options) q = bdev_get_queue(sb->s_bdev); if (blk_queue_discard(q)) { set_opt(sbi, DISCARD); - } else if (!f2fs_sb_mounted_blkzoned(sb)) { + } else if (!f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_WARNING, "mounting with \"discard\" option, but " "the device does not support discard"); } break; case Opt_nodiscard: - if (f2fs_sb_mounted_blkzoned(sb)) { + if (f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_WARNING, "discard is required for zoned block devices"); return -EINVAL; @@ -440,7 +455,7 @@ static int parse_options(struct super_block *sb, char *options) if (args->from && match_int(args, &arg)) return -EINVAL; set_opt(sbi, INLINE_XATTR_SIZE); - sbi->inline_xattr_size = arg; + F2FS_OPTION(sbi).inline_xattr_size = arg; break; #else case Opt_user_xattr: @@ -480,7 +495,7 @@ static int parse_options(struct super_block *sb, char *options) return -EINVAL; if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE) return -EINVAL; - sbi->active_logs = arg; + F2FS_OPTION(sbi).active_logs = arg; break; case Opt_disable_ext_identify: set_opt(sbi, DISABLE_EXT_IDENTIFY); @@ -524,9 +539,9 @@ static int parse_options(struct super_block *sb, char *options) if (test_opt(sbi, RESERVE_ROOT)) { f2fs_msg(sb, KERN_INFO, "Preserve previous reserve_root=%u", - sbi->root_reserved_blocks); + F2FS_OPTION(sbi).root_reserved_blocks); } else { - sbi->root_reserved_blocks = arg; + F2FS_OPTION(sbi).root_reserved_blocks = arg; set_opt(sbi, RESERVE_ROOT); } break; @@ -539,7 +554,7 @@ static int parse_options(struct super_block *sb, char *options) "Invalid uid value %d", arg); return -EINVAL; } - sbi->s_resuid = uid; + F2FS_OPTION(sbi).s_resuid = uid; break; case Opt_resgid: if (args->from && match_int(args, &arg)) @@ -550,7 +565,7 @@ static int parse_options(struct super_block *sb, char *options) "Invalid gid value %d", arg); return -EINVAL; } - sbi->s_resgid = gid; + F2FS_OPTION(sbi).s_resgid = gid; break; case Opt_mode: name = match_strdup(&args[0]); @@ -559,7 +574,7 @@ static int parse_options(struct super_block *sb, char *options) return -ENOMEM; if (strlen(name) == 8 && !strncmp(name, "adaptive", 8)) { - if (f2fs_sb_mounted_blkzoned(sb)) { + if (f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_WARNING, "adaptive mode is not allowed with " "zoned block device feature"); @@ -585,7 +600,7 @@ static int parse_options(struct super_block *sb, char *options) 1 << arg, BIO_MAX_PAGES); return -EINVAL; } - sbi->write_io_size_bits = arg; + F2FS_OPTION(sbi).write_io_size_bits = arg; break; case Opt_fault_injection: if (args->from && match_int(args, &arg)) @@ -646,13 +661,13 @@ static int parse_options(struct super_block *sb, char *options) return ret; break; case Opt_jqfmt_vfsold: - sbi->s_jquota_fmt = QFMT_VFS_OLD; + F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_OLD; break; case Opt_jqfmt_vfsv0: - sbi->s_jquota_fmt = QFMT_VFS_V0; + F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V0; break; case Opt_jqfmt_vfsv1: - sbi->s_jquota_fmt = QFMT_VFS_V1; + F2FS_OPTION(sbi).s_jquota_fmt = QFMT_VFS_V1; break; case Opt_noquota: clear_opt(sbi, QUOTA); @@ -679,6 +694,73 @@ static int parse_options(struct super_block *sb, char *options) "quota operations not supported"); break; #endif + case Opt_whint: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + if (strlen(name) == 10 && + !strncmp(name, "user-based", 10)) { + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_USER; + } else if (strlen(name) == 3 && + !strncmp(name, "off", 3)) { + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; + } else if (strlen(name) == 8 && + !strncmp(name, "fs-based", 8)) { + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_FS; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_alloc: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + + if (strlen(name) == 7 && + !strncmp(name, "default", 7)) { + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; + } else if (strlen(name) == 5 && + !strncmp(name, "reuse", 5)) { + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_fsync: + name = match_strdup(&args[0]); + if (!name) + return -ENOMEM; + if (strlen(name) == 5 && + !strncmp(name, "posix", 5)) { + F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; + } else if (strlen(name) == 6 && + !strncmp(name, "strict", 6)) { + F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_STRICT; + } else { + kfree(name); + return -EINVAL; + } + kfree(name); + break; + case Opt_test_dummy_encryption: +#ifdef CONFIG_F2FS_FS_ENCRYPTION + if (!f2fs_sb_has_encrypt(sb)) { + f2fs_msg(sb, KERN_ERR, "Encrypt feature is off"); + return -EINVAL; + } + + F2FS_OPTION(sbi).test_dummy_encryption = true; + f2fs_msg(sb, KERN_INFO, + "Test dummy encryption mode enabled"); +#else + f2fs_msg(sb, KERN_INFO, + "Test dummy encryption mount option ignored"); +#endif + break; default: f2fs_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" or missing value", @@ -699,14 +781,22 @@ static int parse_options(struct super_block *sb, char *options) } if (test_opt(sbi, INLINE_XATTR_SIZE)) { + if (!f2fs_sb_has_extra_attr(sb) || + !f2fs_sb_has_flexible_inline_xattr(sb)) { + f2fs_msg(sb, KERN_ERR, + "extra_attr or flexible_inline_xattr " + "feature is off"); + return -EINVAL; + } if (!test_opt(sbi, INLINE_XATTR)) { f2fs_msg(sb, KERN_ERR, "inline_xattr_size option should be " "set with inline_xattr option"); return -EINVAL; } - if (!sbi->inline_xattr_size || - sbi->inline_xattr_size >= DEF_ADDRS_PER_INODE - + if (!F2FS_OPTION(sbi).inline_xattr_size || + F2FS_OPTION(sbi).inline_xattr_size >= + DEF_ADDRS_PER_INODE - F2FS_TOTAL_EXTRA_ATTR_SIZE - DEF_INLINE_RESERVED_SIZE - DEF_MIN_INLINE_SIZE) { @@ -715,6 +805,12 @@ static int parse_options(struct super_block *sb, char *options) return -EINVAL; } } + + /* Not pass down write hints if the number of active logs is lesser + * than NR_CURSEG_TYPE. + */ + if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE) + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; return 0; } @@ -731,7 +827,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) /* Initialize f2fs-specific inode info */ atomic_set(&fi->dirty_pages, 0); fi->i_current_depth = 1; - fi->i_advise = 0; init_rwsem(&fi->i_sem); INIT_LIST_HEAD(&fi->dirty_list); INIT_LIST_HEAD(&fi->gdirty_list); @@ -743,10 +838,6 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) init_rwsem(&fi->i_mmap_sem); init_rwsem(&fi->i_xattr_sem); -#ifdef CONFIG_QUOTA - memset(&fi->i_dquot, 0, sizeof(fi->i_dquot)); - fi->i_reserved_quota = 0; -#endif /* Will be used by directory only */ fi->i_dir_level = F2FS_SB(sb)->dir_level; @@ -956,7 +1047,7 @@ static void f2fs_put_super(struct super_block *sb) mempool_destroy(sbi->write_io_dummy); #ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); + kfree(F2FS_OPTION(sbi).s_qf_names[i]); #endif destroy_percpu_info(sbi); for (i = 0; i < NR_PAGE_TYPE; i++) @@ -1070,8 +1161,9 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_blocks = total_count - start_count; buf->f_bfree = user_block_count - valid_user_blocks(sbi) - sbi->current_reserved_blocks; - if (buf->f_bfree > sbi->root_reserved_blocks) - buf->f_bavail = buf->f_bfree - sbi->root_reserved_blocks; + if (buf->f_bfree > F2FS_OPTION(sbi).root_reserved_blocks) + buf->f_bavail = buf->f_bfree - + F2FS_OPTION(sbi).root_reserved_blocks; else buf->f_bavail = 0; @@ -1106,10 +1198,10 @@ static inline void f2fs_show_quota_options(struct seq_file *seq, #ifdef CONFIG_QUOTA struct f2fs_sb_info *sbi = F2FS_SB(sb); - if (sbi->s_jquota_fmt) { + if (F2FS_OPTION(sbi).s_jquota_fmt) { char *fmtname = ""; - switch (sbi->s_jquota_fmt) { + switch (F2FS_OPTION(sbi).s_jquota_fmt) { case QFMT_VFS_OLD: fmtname = "vfsold"; break; @@ -1123,14 +1215,17 @@ static inline void f2fs_show_quota_options(struct seq_file *seq, seq_printf(seq, ",jqfmt=%s", fmtname); } - if (sbi->s_qf_names[USRQUOTA]) - seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]); + if (F2FS_OPTION(sbi).s_qf_names[USRQUOTA]) + seq_show_option(seq, "usrjquota", + F2FS_OPTION(sbi).s_qf_names[USRQUOTA]); - if (sbi->s_qf_names[GRPQUOTA]) - seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]); + if (F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]) + seq_show_option(seq, "grpjquota", + F2FS_OPTION(sbi).s_qf_names[GRPQUOTA]); - if (sbi->s_qf_names[PRJQUOTA]) - seq_show_option(seq, "prjjquota", sbi->s_qf_names[PRJQUOTA]); + if (F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]) + seq_show_option(seq, "prjjquota", + F2FS_OPTION(sbi).s_qf_names[PRJQUOTA]); #endif } @@ -1165,7 +1260,7 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",noinline_xattr"); if (test_opt(sbi, INLINE_XATTR_SIZE)) seq_printf(seq, ",inline_xattr_size=%u", - sbi->inline_xattr_size); + F2FS_OPTION(sbi).inline_xattr_size); #endif #ifdef CONFIG_F2FS_FS_POSIX_ACL if (test_opt(sbi, POSIX_ACL)) @@ -1201,18 +1296,20 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, "adaptive"); else if (test_opt(sbi, LFS)) seq_puts(seq, "lfs"); - seq_printf(seq, ",active_logs=%u", sbi->active_logs); + seq_printf(seq, ",active_logs=%u", F2FS_OPTION(sbi).active_logs); if (test_opt(sbi, RESERVE_ROOT)) seq_printf(seq, ",reserve_root=%u,resuid=%u,resgid=%u", - sbi->root_reserved_blocks, - from_kuid_munged(&init_user_ns, sbi->s_resuid), - from_kgid_munged(&init_user_ns, sbi->s_resgid)); + F2FS_OPTION(sbi).root_reserved_blocks, + from_kuid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resuid), + from_kgid_munged(&init_user_ns, + F2FS_OPTION(sbi).s_resgid)); if (F2FS_IO_SIZE_BITS(sbi)) seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi)); #ifdef CONFIG_F2FS_FAULT_INJECTION if (test_opt(sbi, FAULT_INJECTION)) seq_printf(seq, ",fault_injection=%u", - sbi->fault_info.inject_rate); + F2FS_OPTION(sbi).fault_info.inject_rate); #endif #ifdef CONFIG_QUOTA if (test_opt(sbi, QUOTA)) @@ -1225,15 +1322,37 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",prjquota"); #endif f2fs_show_quota_options(seq, sbi->sb); + if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_USER) + seq_printf(seq, ",whint_mode=%s", "user-based"); + else if (F2FS_OPTION(sbi).whint_mode == WHINT_MODE_FS) + seq_printf(seq, ",whint_mode=%s", "fs-based"); +#ifdef CONFIG_F2FS_FS_ENCRYPTION + if (F2FS_OPTION(sbi).test_dummy_encryption) + seq_puts(seq, ",test_dummy_encryption"); +#endif + + if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_DEFAULT) + seq_printf(seq, ",alloc_mode=%s", "default"); + else if (F2FS_OPTION(sbi).alloc_mode == ALLOC_MODE_REUSE) + seq_printf(seq, ",alloc_mode=%s", "reuse"); + if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_POSIX) + seq_printf(seq, ",fsync_mode=%s", "posix"); + else if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) + seq_printf(seq, ",fsync_mode=%s", "strict"); return 0; } static void default_options(struct f2fs_sb_info *sbi) { /* init some FS parameters */ - sbi->active_logs = NR_CURSEG_TYPE; - sbi->inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; + F2FS_OPTION(sbi).active_logs = NR_CURSEG_TYPE; + F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS; + F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF; + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT; + F2FS_OPTION(sbi).fsync_mode = FSYNC_MODE_POSIX; + F2FS_OPTION(sbi).test_dummy_encryption = false; + sbi->readdir_ra = 1; set_opt(sbi, BG_GC); set_opt(sbi, INLINE_XATTR); @@ -1243,7 +1362,7 @@ static void default_options(struct f2fs_sb_info *sbi) set_opt(sbi, NOHEAP); sbi->sb->s_flags |= MS_LAZYTIME; set_opt(sbi, FLUSH_MERGE); - if (f2fs_sb_mounted_blkzoned(sbi->sb)) { + if (f2fs_sb_has_blkzoned(sbi->sb)) { set_opt_mode(sbi, F2FS_MOUNT_LFS); set_opt(sbi, DISCARD); } else { @@ -1270,16 +1389,11 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_mount_info org_mount_opt; unsigned long old_sb_flags; - int err, active_logs; + int err; bool need_restart_gc = false; bool need_stop_gc = false; bool no_extent_cache = !test_opt(sbi, EXTENT_CACHE); -#ifdef CONFIG_F2FS_FAULT_INJECTION - struct f2fs_fault_info ffi = sbi->fault_info; -#endif #ifdef CONFIG_QUOTA - int s_jquota_fmt; - char *s_qf_names[MAXQUOTAS]; int i, j; #endif @@ -1289,21 +1403,21 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) */ org_mount_opt = sbi->mount_opt; old_sb_flags = sb->s_flags; - active_logs = sbi->active_logs; #ifdef CONFIG_QUOTA - s_jquota_fmt = sbi->s_jquota_fmt; + org_mount_opt.s_jquota_fmt = F2FS_OPTION(sbi).s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) { - if (sbi->s_qf_names[i]) { - s_qf_names[i] = kstrdup(sbi->s_qf_names[i], - GFP_KERNEL); - if (!s_qf_names[i]) { + if (F2FS_OPTION(sbi).s_qf_names[i]) { + org_mount_opt.s_qf_names[i] = + kstrdup(F2FS_OPTION(sbi).s_qf_names[i], + GFP_KERNEL); + if (!org_mount_opt.s_qf_names[i]) { for (j = 0; j < i; j++) - kfree(s_qf_names[j]); + kfree(org_mount_opt.s_qf_names[j]); return -ENOMEM; } } else { - s_qf_names[i] = NULL; + org_mount_opt.s_qf_names[i] = NULL; } } #endif @@ -1373,7 +1487,8 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) need_stop_gc = true; } - if (*flags & MS_RDONLY) { + if (*flags & MS_RDONLY || + F2FS_OPTION(sbi).whint_mode != org_mount_opt.whint_mode) { writeback_inodes_sb(sb, WB_REASON_SYNC); sync_inodes_sb(sb); @@ -1399,7 +1514,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) #ifdef CONFIG_QUOTA /* Release old quota file names */ for (i = 0; i < MAXQUOTAS; i++) - kfree(s_qf_names[i]); + kfree(org_mount_opt.s_qf_names[i]); #endif /* Update the POSIXACL Flag */ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | @@ -1417,18 +1532,14 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) } restore_opts: #ifdef CONFIG_QUOTA - sbi->s_jquota_fmt = s_jquota_fmt; + F2FS_OPTION(sbi).s_jquota_fmt = org_mount_opt.s_jquota_fmt; for (i = 0; i < MAXQUOTAS; i++) { - kfree(sbi->s_qf_names[i]); - sbi->s_qf_names[i] = s_qf_names[i]; + kfree(F2FS_OPTION(sbi).s_qf_names[i]); + F2FS_OPTION(sbi).s_qf_names[i] = org_mount_opt.s_qf_names[i]; } #endif sbi->mount_opt = org_mount_opt; - sbi->active_logs = active_logs; sb->s_flags = old_sb_flags; -#ifdef CONFIG_F2FS_FAULT_INJECTION - sbi->fault_info = ffi; -#endif return err; } @@ -1456,7 +1567,7 @@ static ssize_t f2fs_quota_read(struct super_block *sb, int type, char *data, while (toread > 0) { tocopy = min_t(unsigned long, sb->s_blocksize - offset, toread); repeat: - page = read_mapping_page(mapping, blkidx, NULL); + page = read_cache_page_gfp(mapping, blkidx, GFP_NOFS); if (IS_ERR(page)) { if (PTR_ERR(page) == -ENOMEM) { congestion_wait(BLK_RW_ASYNC, HZ/50); @@ -1550,8 +1661,8 @@ static qsize_t *f2fs_get_reserved_space(struct inode *inode) static int f2fs_quota_on_mount(struct f2fs_sb_info *sbi, int type) { - return dquot_quota_on_mount(sbi->sb, sbi->s_qf_names[type], - sbi->s_jquota_fmt, type); + return dquot_quota_on_mount(sbi->sb, F2FS_OPTION(sbi).s_qf_names[type], + F2FS_OPTION(sbi).s_jquota_fmt, type); } int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly) @@ -1570,7 +1681,7 @@ int f2fs_enable_quota_files(struct f2fs_sb_info *sbi, bool rdonly) } for (i = 0; i < MAXQUOTAS; i++) { - if (sbi->s_qf_names[i]) { + if (F2FS_OPTION(sbi).s_qf_names[i]) { err = f2fs_quota_on_mount(sbi, i); if (!err) { enabled = 1; @@ -1797,11 +1908,28 @@ static int f2fs_get_context(struct inode *inode, void *ctx, size_t len) static int f2fs_set_context(struct inode *inode, const void *ctx, size_t len, void *fs_data) { + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + /* + * Encrypting the root directory is not allowed because fsck + * expects lost+found directory to exist and remain unencrypted + * if LOST_FOUND feature is enabled. + * + */ + if (f2fs_sb_has_lost_found(sbi->sb) && + inode->i_ino == F2FS_ROOT_INO(sbi)) + return -EPERM; + return f2fs_setxattr(inode, F2FS_XATTR_INDEX_ENCRYPTION, F2FS_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len, fs_data, XATTR_CREATE); } +static bool f2fs_dummy_context(struct inode *inode) +{ + return DUMMY_ENCRYPTION_ENABLED(F2FS_I_SB(inode)); +} + static unsigned f2fs_max_namelen(struct inode *inode) { return S_ISLNK(inode->i_mode) ? @@ -1812,6 +1940,7 @@ static const struct fscrypt_operations f2fs_cryptops = { .key_prefix = "f2fs:", .get_context = f2fs_get_context, .set_context = f2fs_set_context, + .dummy_context = f2fs_dummy_context, .empty_dir = f2fs_empty_dir, .max_namelen = f2fs_max_namelen, }; @@ -1894,7 +2023,6 @@ static int __f2fs_commit_super(struct buffer_head *bh, lock_buffer(bh); if (super) memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super)); - set_buffer_uptodate(bh); set_buffer_dirty(bh); unlock_buffer(bh); @@ -2181,6 +2309,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi) sbi->dirty_device = 0; spin_lock_init(&sbi->dev_lock); + + init_rwsem(&sbi->sb_lock); } static int init_percpu_info(struct f2fs_sb_info *sbi) @@ -2206,7 +2336,7 @@ static int init_blkz_info(struct f2fs_sb_info *sbi, int devi) unsigned int n = 0; int err = -EIO; - if (!f2fs_sb_mounted_blkzoned(sbi->sb)) + if (!f2fs_sb_has_blkzoned(sbi->sb)) return 0; if (sbi->blocks_per_blkz && sbi->blocks_per_blkz != @@ -2334,7 +2464,7 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) } /* write back-up superblock first */ - bh = sb_getblk(sbi->sb, sbi->valid_super_block ? 0: 1); + bh = sb_bread(sbi->sb, sbi->valid_super_block ? 0 : 1); if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); @@ -2345,7 +2475,7 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover) return err; /* write current valid superblock */ - bh = sb_getblk(sbi->sb, sbi->valid_super_block); + bh = sb_bread(sbi->sb, sbi->valid_super_block); if (!bh) return -EIO; err = __f2fs_commit_super(bh, F2FS_RAW_SUPER(sbi)); @@ -2417,7 +2547,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) #ifdef CONFIG_BLK_DEV_ZONED if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM && - !f2fs_sb_mounted_blkzoned(sbi->sb)) { + !f2fs_sb_has_blkzoned(sbi->sb)) { f2fs_msg(sbi->sb, KERN_ERR, "Zoned block device feature not enabled\n"); return -EINVAL; @@ -2451,6 +2581,18 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi) return 0; } +static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) +{ + struct f2fs_sm_info *sm_i = SM_I(sbi); + + /* adjust parameters according to the volume size */ + if (sm_i->main_segments <= SMALL_VOLUME_SEGMENTS) { + F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_REUSE; + sm_i->dcc_info->discard_granularity = 1; + sm_i->ipu_policy = 1 << F2FS_IPU_FORCE; + } +} + static int f2fs_fill_super(struct super_block *sb, void *data, int silent) { struct f2fs_sb_info *sbi; @@ -2498,8 +2640,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) sb->s_fs_info = sbi; sbi->raw_super = raw_super; - sbi->s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); - sbi->s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID); + F2FS_OPTION(sbi).s_resuid = make_kuid(&init_user_ns, F2FS_DEF_RESUID); + F2FS_OPTION(sbi).s_resgid = make_kgid(&init_user_ns, F2FS_DEF_RESGID); /* precompute checksum seed for metadata */ if (f2fs_sb_has_inode_chksum(sb)) @@ -2512,7 +2654,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) * devices, but mandatory for host-managed zoned block devices. */ #ifndef CONFIG_BLK_DEV_ZONED - if (f2fs_sb_mounted_blkzoned(sb)) { + if (f2fs_sb_has_blkzoned(sb)) { f2fs_msg(sb, KERN_ERR, "Zoned block device support is not enabled\n"); err = -EOPNOTSUPP; @@ -2728,7 +2870,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) * Turn on quotas which were not enabled for read-only mounts if * filesystem has quota feature, so that they are updated correctly. */ - if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) { + if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) { err = f2fs_enable_quotas(sb); if (err) { f2fs_msg(sb, KERN_ERR, @@ -2803,6 +2945,8 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) f2fs_join_shrinker(sbi); + f2fs_tuning_parameters(sbi); + f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx", cur_cp_version(F2FS_CKPT(sbi))); f2fs_update_time(sbi, CP_TIME); @@ -2811,7 +2955,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) free_meta: #ifdef CONFIG_QUOTA - if (f2fs_sb_has_quota_ino(sb) && !sb_rdonly(sb)) + if (f2fs_sb_has_quota_ino(sb) && !f2fs_readonly(sb)) f2fs_quota_off_umount(sbi->sb); #endif f2fs_sync_inode_meta(sbi); @@ -2855,7 +2999,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) free_options: #ifdef CONFIG_QUOTA for (i = 0; i < MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); + kfree(F2FS_OPTION(sbi).s_qf_names[i]); #endif kfree(options); free_sb_buf: diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index d978c7b6ea04..f33a56d6e6dd 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -58,7 +58,7 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) #ifdef CONFIG_F2FS_FAULT_INJECTION else if (struct_type == FAULT_INFO_RATE || struct_type == FAULT_INFO_TYPE) - return (unsigned char *)&sbi->fault_info; + return (unsigned char *)&F2FS_OPTION(sbi).fault_info; #endif return NULL; } @@ -92,10 +92,10 @@ static ssize_t features_show(struct f2fs_attr *a, if (!sb->s_bdev->bd_part) return snprintf(buf, PAGE_SIZE, "0\n"); - if (f2fs_sb_has_crypto(sb)) + if (f2fs_sb_has_encrypt(sb)) len += snprintf(buf, PAGE_SIZE - len, "%s", "encryption"); - if (f2fs_sb_mounted_blkzoned(sb)) + if (f2fs_sb_has_blkzoned(sb)) len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "blkzoned"); if (f2fs_sb_has_extra_attr(sb)) @@ -116,6 +116,9 @@ static ssize_t features_show(struct f2fs_attr *a, if (f2fs_sb_has_inode_crtime(sb)) len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", len ? ", " : "", "inode_crtime"); + if (f2fs_sb_has_lost_found(sb)) + len += snprintf(buf + len, PAGE_SIZE - len, "%s%s", + len ? ", " : "", "lost_found"); len += snprintf(buf + len, PAGE_SIZE - len, "\n"); return len; } @@ -136,6 +139,27 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a, if (!ptr) return -EINVAL; + if (!strcmp(a->attr.name, "extension_list")) { + __u8 (*extlist)[F2FS_EXTENSION_LEN] = + sbi->raw_super->extension_list; + int cold_count = le32_to_cpu(sbi->raw_super->extension_count); + int hot_count = sbi->raw_super->hot_ext_count; + int len = 0, i; + + len += snprintf(buf + len, PAGE_SIZE - len, + "cold file extenstion:\n"); + for (i = 0; i < cold_count; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", + extlist[i]); + + len += snprintf(buf + len, PAGE_SIZE - len, + "hot file extenstion:\n"); + for (i = cold_count; i < cold_count + hot_count; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "%s\n", + extlist[i]); + return len; + } + ui = (unsigned int *)(ptr + a->offset); return snprintf(buf, PAGE_SIZE, "%u\n", *ui); @@ -154,6 +178,41 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, if (!ptr) return -EINVAL; + if (!strcmp(a->attr.name, "extension_list")) { + const char *name = strim((char *)buf); + bool set = true, hot; + + if (!strncmp(name, "[h]", 3)) + hot = true; + else if (!strncmp(name, "[c]", 3)) + hot = false; + else + return -EINVAL; + + name += 3; + + if (*name == '!') { + name++; + set = false; + } + + if (strlen(name) >= F2FS_EXTENSION_LEN) + return -EINVAL; + + down_write(&sbi->sb_lock); + + ret = update_extension_list(sbi, name, hot, set); + if (ret) + goto out; + + ret = f2fs_commit_super(sbi, false); + if (ret) + update_extension_list(sbi, name, hot, !set); +out: + up_write(&sbi->sb_lock); + return ret ? ret : count; + } + ui = (unsigned int *)(ptr + a->offset); ret = kstrtoul(skip_spaces(buf), 0, &t); @@ -166,7 +225,7 @@ static ssize_t f2fs_sbi_store(struct f2fs_attr *a, if (a->struct_type == RESERVED_BLOCKS) { spin_lock(&sbi->stat_lock); if (t > (unsigned long)(sbi->user_block_count - - sbi->root_reserved_blocks)) { + F2FS_OPTION(sbi).root_reserved_blocks)) { spin_unlock(&sbi->stat_lock); return -EINVAL; } @@ -236,6 +295,7 @@ enum feat_id { FEAT_FLEXIBLE_INLINE_XATTR, FEAT_QUOTA_INO, FEAT_INODE_CRTIME, + FEAT_LOST_FOUND, }; static ssize_t f2fs_feature_show(struct f2fs_attr *a, @@ -251,6 +311,7 @@ static ssize_t f2fs_feature_show(struct f2fs_attr *a, case FEAT_FLEXIBLE_INLINE_XATTR: case FEAT_QUOTA_INO: case FEAT_INODE_CRTIME: + case FEAT_LOST_FOUND: return snprintf(buf, PAGE_SIZE, "supported\n"); } return 0; @@ -307,6 +368,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, idle_interval, interval_time[REQ_TIME]); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, iostat_enable, iostat_enable); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, readdir_ra, readdir_ra); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, gc_pin_file_thresh, gc_pin_file_threshold); +F2FS_RW_ATTR(F2FS_SBI, f2fs_super_block, extension_list, extension_list); #ifdef CONFIG_F2FS_FAULT_INJECTION F2FS_RW_ATTR(FAULT_INFO_RATE, f2fs_fault_info, inject_rate, inject_rate); F2FS_RW_ATTR(FAULT_INFO_TYPE, f2fs_fault_info, inject_type, inject_type); @@ -329,6 +391,7 @@ F2FS_FEATURE_RO_ATTR(inode_checksum, FEAT_INODE_CHECKSUM); F2FS_FEATURE_RO_ATTR(flexible_inline_xattr, FEAT_FLEXIBLE_INLINE_XATTR); F2FS_FEATURE_RO_ATTR(quota_ino, FEAT_QUOTA_INO); F2FS_FEATURE_RO_ATTR(inode_crtime, FEAT_INODE_CRTIME); +F2FS_FEATURE_RO_ATTR(lost_found, FEAT_LOST_FOUND); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -357,6 +420,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(iostat_enable), ATTR_LIST(readdir_ra), ATTR_LIST(gc_pin_file_thresh), + ATTR_LIST(extension_list), #ifdef CONFIG_F2FS_FAULT_INJECTION ATTR_LIST(inject_rate), ATTR_LIST(inject_type), @@ -383,6 +447,7 @@ static struct attribute *f2fs_feat_attrs[] = { ATTR_LIST(flexible_inline_xattr), ATTR_LIST(quota_ino), ATTR_LIST(inode_crtime), + ATTR_LIST(lost_found), NULL, }; diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index cd395ecec99d..99ad6101320b 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -25,6 +25,7 @@ typedef void (bio_end_io_t) (struct bio *); struct bio { struct bio *bi_next; /* request queue link */ struct block_device *bi_bdev; + unsigned short bi_write_hint; int bi_error; unsigned int bi_opf; /* bottom bits req flags, * top bits REQ_OP. Use diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h index 393b880afc9a..aa5db8b5521a 100644 --- a/include/linux/f2fs_fs.h +++ b/include/linux/f2fs_fs.h @@ -21,6 +21,7 @@ #define F2FS_BLKSIZE 4096 /* support only 4KB block */ #define F2FS_BLKSIZE_BITS 12 /* bits for F2FS_BLKSIZE */ #define F2FS_MAX_EXTENSION 64 /* # of extension entries */ +#define F2FS_EXTENSION_LEN 8 /* max size of extension */ #define F2FS_BLK_ALIGN(x) (((x) + F2FS_BLKSIZE - 1) >> F2FS_BLKSIZE_BITS) #define NULL_ADDR ((block_t)0) /* used as block_t addresses */ @@ -38,10 +39,10 @@ #define F2FS_MAX_QUOTAS 3 -#define F2FS_IO_SIZE(sbi) (1 << (sbi)->write_io_size_bits) /* Blocks */ -#define F2FS_IO_SIZE_KB(sbi) (1 << ((sbi)->write_io_size_bits + 2)) /* KB */ -#define F2FS_IO_SIZE_BYTES(sbi) (1 << ((sbi)->write_io_size_bits + 12)) /* B */ -#define F2FS_IO_SIZE_BITS(sbi) ((sbi)->write_io_size_bits) /* power of 2 */ +#define F2FS_IO_SIZE(sbi) (1 << F2FS_OPTION(sbi).write_io_size_bits) /* Blocks */ +#define F2FS_IO_SIZE_KB(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 2)) /* KB */ +#define F2FS_IO_SIZE_BYTES(sbi) (1 << (F2FS_OPTION(sbi).write_io_size_bits + 12)) /* B */ +#define F2FS_IO_SIZE_BITS(sbi) (F2FS_OPTION(sbi).write_io_size_bits) /* power of 2 */ #define F2FS_IO_SIZE_MASK(sbi) (F2FS_IO_SIZE(sbi) - 1) /* This flag is used by node and meta inodes, and by recovery */ @@ -101,7 +102,7 @@ struct f2fs_super_block { __u8 uuid[16]; /* 128-bit uuid for volume */ __le16 volume_name[MAX_VOLUME_NAME]; /* volume name */ __le32 extension_count; /* # of extensions below */ - __u8 extension_list[F2FS_MAX_EXTENSION][8]; /* extension array */ + __u8 extension_list[F2FS_MAX_EXTENSION][F2FS_EXTENSION_LEN];/* extension array */ __le32 cp_payload; __u8 version[VERSION_LEN]; /* the kernel version */ __u8 init_version[VERSION_LEN]; /* the initial kernel version */ @@ -110,12 +111,14 @@ struct f2fs_super_block { __u8 encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ struct f2fs_device devs[MAX_DEVICES]; /* device list */ __le32 qf_ino[F2FS_MAX_QUOTAS]; /* quota inode numbers */ - __u8 reserved[315]; /* valid reserved region */ + __u8 hot_ext_count; /* # of hot file extension */ + __u8 reserved[314]; /* valid reserved region */ } __packed; /* * For checkpoint */ +#define CP_LARGE_NAT_BITMAP_FLAG 0x00000400 #define CP_NOCRC_RECOVERY_FLAG 0x00000200 #define CP_TRIMMED_FLAG 0x00000100 #define CP_NAT_BITS_FLAG 0x00000080 @@ -302,6 +305,10 @@ struct f2fs_node { */ #define NAT_ENTRY_PER_BLOCK (PAGE_SIZE / sizeof(struct f2fs_nat_entry)) #define NAT_ENTRY_BITMAP_SIZE ((NAT_ENTRY_PER_BLOCK + 7) / 8) +#define NAT_ENTRY_BITMAP_SIZE_ALIGNED \ + ((NAT_ENTRY_BITMAP_SIZE + BITS_PER_LONG - 1) / \ + BITS_PER_LONG * BITS_PER_LONG) + struct f2fs_nat_entry { __u8 version; /* latest version of cached nat entry */ diff --git a/include/linux/fs.h b/include/linux/fs.h index b2708af3e5c0..d5f41f4e2f0a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -144,6 +145,9 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, /* File was opened by fanotify and shouldn't generate fanotify events */ #define FMODE_NONOTIFY ((__force fmode_t)0x4000000) +/* File is capable of returning -EAGAIN if I/O will block */ +#define FMODE_NOWAIT ((__force fmode_t)0x8000000) + /* * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector * that indicates that they should check the contents of the iovec are @@ -316,6 +320,18 @@ struct page; struct address_space; struct writeback_control; +/* + * Write life time hint values. + */ +enum rw_hint { + WRITE_LIFE_NOT_SET = 0, + WRITE_LIFE_NONE = RWH_WRITE_LIFE_NONE, + WRITE_LIFE_SHORT = RWH_WRITE_LIFE_SHORT, + WRITE_LIFE_MEDIUM = RWH_WRITE_LIFE_MEDIUM, + WRITE_LIFE_LONG = RWH_WRITE_LIFE_LONG, + WRITE_LIFE_EXTREME = RWH_WRITE_LIFE_EXTREME, +}; + #define IOCB_EVENTFD (1 << 0) #define IOCB_APPEND (1 << 1) #define IOCB_DIRECT (1 << 2) @@ -323,6 +339,7 @@ struct writeback_control; #define IOCB_DSYNC (1 << 4) #define IOCB_SYNC (1 << 5) #define IOCB_WRITE (1 << 6) +#define IOCB_NOWAIT (1 << 7) struct kiocb { struct file *ki_filp; @@ -330,6 +347,7 @@ struct kiocb { void (*ki_complete)(struct kiocb *iocb, long ret, long ret2); void *private; int ki_flags; + enum rw_hint ki_hint; }; static inline bool is_sync_kiocb(struct kiocb *kiocb) @@ -643,6 +661,7 @@ struct inode { spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ unsigned short i_bytes; unsigned int i_blkbits; + enum rw_hint i_write_hint; blkcnt_t i_blocks; #ifdef __NEED_I_SIZE_ORDERED @@ -1070,8 +1089,6 @@ struct file_lock_context { #define OFFT_OFFSET_MAX INT_LIMIT(off_t) #endif -#include - extern void send_sigio(struct fown_struct *fown, int fd, int band); /* diff --git a/include/linux/fscrypt.h b/include/linux/fscrypt.h index 8641e56b8f8a..9e535af579e8 100644 --- a/include/linux/fscrypt.h +++ b/include/linux/fscrypt.h @@ -13,42 +13,13 @@ #ifndef _LINUX_FSCRYPT_H #define _LINUX_FSCRYPT_H -#include #include -#include -#include -#include -#include -#include #define FS_CRYPTO_BLOCK_SIZE 16 +struct fscrypt_ctx; struct fscrypt_info; -struct fscrypt_ctx { - union { - struct { - struct page *bounce_page; /* Ciphertext page */ - struct page *control_page; /* Original page */ - } w; - struct { - struct bio *bio; - struct work_struct work; - } r; - struct list_head free_list; /* Free list */ - }; - u8 flags; /* Flags */ -}; - -/** - * For encrypted symlinks, the ciphertext length is stored at the beginning - * of the string in little-endian format. - */ -struct fscrypt_symlink_data { - __le16 len; - char encrypted_path[1]; -} __packed; - struct fscrypt_str { unsigned char *name; u32 len; @@ -67,86 +38,11 @@ struct fscrypt_name { #define fname_name(p) ((p)->disk_name.name) #define fname_len(p) ((p)->disk_name.len) -/* - * fscrypt superblock flags - */ -#define FS_CFLG_OWN_PAGES (1U << 1) - -/* - * crypto opertions for filesystems - */ -struct fscrypt_operations { - unsigned int flags; - const char *key_prefix; - int (*get_context)(struct inode *, void *, size_t); - int (*set_context)(struct inode *, const void *, size_t, void *); - bool (*dummy_context)(struct inode *); - bool (*empty_dir)(struct inode *); - unsigned (*max_namelen)(struct inode *); -}; - -static inline bool fscrypt_dummy_context_enabled(struct inode *inode) -{ - if (inode->i_sb->s_cop->dummy_context && - inode->i_sb->s_cop->dummy_context(inode)) - return true; - return false; -} - -static inline bool fscrypt_valid_enc_modes(u32 contents_mode, - u32 filenames_mode) -{ - if (contents_mode == FS_ENCRYPTION_MODE_AES_128_CBC && - filenames_mode == FS_ENCRYPTION_MODE_AES_128_CTS) - return true; - - if (contents_mode == FS_ENCRYPTION_MODE_AES_256_XTS && - filenames_mode == FS_ENCRYPTION_MODE_AES_256_CTS) - return true; - - return false; -} - -static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) -{ - if (str->len == 1 && str->name[0] == '.') - return true; - - if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') - return true; - - return false; -} - #if __FS_HAS_ENCRYPTION - -static inline struct page *fscrypt_control_page(struct page *page) -{ - return ((struct fscrypt_ctx *)page_private(page))->w.control_page; -} - -static inline bool fscrypt_has_encryption_key(const struct inode *inode) -{ - return (inode->i_crypt_info != NULL); -} - #include - -#else /* !__FS_HAS_ENCRYPTION */ - -static inline struct page *fscrypt_control_page(struct page *page) -{ - WARN_ON_ONCE(1); - return ERR_PTR(-EINVAL); -} - -static inline bool fscrypt_has_encryption_key(const struct inode *inode) -{ - return 0; -} - +#else #include -#endif /* __FS_HAS_ENCRYPTION */ +#endif /** * fscrypt_require_key - require an inode's encryption key @@ -287,4 +183,68 @@ static inline int fscrypt_prepare_setattr(struct dentry *dentry, return 0; } +/** + * fscrypt_prepare_symlink - prepare to create a possibly-encrypted symlink + * @dir: directory in which the symlink is being created + * @target: plaintext symlink target + * @len: length of @target excluding null terminator + * @max_len: space the filesystem has available to store the symlink target + * @disk_link: (out) the on-disk symlink target being prepared + * + * This function computes the size the symlink target will require on-disk, + * stores it in @disk_link->len, and validates it against @max_len. An + * encrypted symlink may be longer than the original. + * + * Additionally, @disk_link->name is set to @target if the symlink will be + * unencrypted, but left NULL if the symlink will be encrypted. For encrypted + * symlinks, the filesystem must call fscrypt_encrypt_symlink() to create the + * on-disk target later. (The reason for the two-step process is that some + * filesystems need to know the size of the symlink target before creating the + * inode, e.g. to determine whether it will be a "fast" or "slow" symlink.) + * + * Return: 0 on success, -ENAMETOOLONG if the symlink target is too long, + * -ENOKEY if the encryption key is missing, or another -errno code if a problem + * occurred while setting up the encryption key. + */ +static inline int fscrypt_prepare_symlink(struct inode *dir, + const char *target, + unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link) +{ + if (IS_ENCRYPTED(dir) || fscrypt_dummy_context_enabled(dir)) + return __fscrypt_prepare_symlink(dir, len, max_len, disk_link); + + disk_link->name = (unsigned char *)target; + disk_link->len = len + 1; + if (disk_link->len > max_len) + return -ENAMETOOLONG; + return 0; +} + +/** + * fscrypt_encrypt_symlink - encrypt the symlink target if needed + * @inode: symlink inode + * @target: plaintext symlink target + * @len: length of @target excluding null terminator + * @disk_link: (in/out) the on-disk symlink target being prepared + * + * If the symlink target needs to be encrypted, then this function encrypts it + * into @disk_link->name. fscrypt_prepare_symlink() must have been called + * previously to compute @disk_link->len. If the filesystem did not allocate a + * buffer for @disk_link->name after calling fscrypt_prepare_link(), then one + * will be kmalloc()'ed and the filesystem will be responsible for freeing it. + * + * Return: 0 on success, -errno on failure + */ +static inline int fscrypt_encrypt_symlink(struct inode *inode, + const char *target, + unsigned int len, + struct fscrypt_str *disk_link) +{ + if (IS_ENCRYPTED(inode)) + return __fscrypt_encrypt_symlink(inode, target, len, disk_link); + return 0; +} + #endif /* _LINUX_FSCRYPT_H */ diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index c4c6bf2c390e..ecf2ac80128c 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -13,6 +13,16 @@ #ifndef _LINUX_FSCRYPT_NOTSUPP_H #define _LINUX_FSCRYPT_NOTSUPP_H +static inline bool fscrypt_has_encryption_key(const struct inode *inode) +{ + return false; +} + +static inline bool fscrypt_dummy_context_enabled(struct inode *inode) +{ + return false; +} + /* crypto.c */ static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags) @@ -42,6 +52,11 @@ static inline int fscrypt_decrypt_page(const struct inode *inode, return -EOPNOTSUPP; } +static inline struct page *fscrypt_control_page(struct page *page) +{ + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); +} static inline void fscrypt_restore_control_page(struct page *page) { @@ -89,8 +104,7 @@ static inline int fscrypt_get_encryption_info(struct inode *inode) return -EOPNOTSUPP; } -static inline void fscrypt_put_encryption_info(struct inode *inode, - struct fscrypt_info *ci) +static inline void fscrypt_put_encryption_info(struct inode *inode) { return; } @@ -115,16 +129,8 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) return; } -static inline u32 fscrypt_fname_encrypted_size(const struct inode *inode, - u32 ilen) -{ - /* never happens */ - WARN_ON(1); - return 0; -} - static inline int fscrypt_fname_alloc_buffer(const struct inode *inode, - u32 ilen, + u32 max_encrypted_len, struct fscrypt_str *crypto_str) { return -EOPNOTSUPP; @@ -143,13 +149,6 @@ static inline int fscrypt_fname_disk_to_usr(struct inode *inode, return -EOPNOTSUPP; } -static inline int fscrypt_fname_usr_to_disk(struct inode *inode, - const struct qstr *iname, - struct fscrypt_str *oname) -{ - return -EOPNOTSUPP; -} - static inline bool fscrypt_match_name(const struct fscrypt_name *fname, const u8 *de_name, u32 de_name_len) { @@ -207,4 +206,28 @@ static inline int __fscrypt_prepare_lookup(struct inode *dir, return -EOPNOTSUPP; } +static inline int __fscrypt_prepare_symlink(struct inode *dir, + unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link) +{ + return -EOPNOTSUPP; +} + +static inline int __fscrypt_encrypt_symlink(struct inode *inode, + const char *target, + unsigned int len, + struct fscrypt_str *disk_link) +{ + return -EOPNOTSUPP; +} + +static inline const char *fscrypt_get_symlink(struct inode *inode, + const void *caddr, + unsigned int max_size, + struct delayed_call *done) +{ + return ERR_PTR(-EOPNOTSUPP); +} + #endif /* _LINUX_FSCRYPT_NOTSUPP_H */ diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index 2db5e9706f60..f382cf36cc2e 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -10,8 +10,54 @@ #ifndef _LINUX_FSCRYPT_SUPP_H #define _LINUX_FSCRYPT_SUPP_H +#include +#include + +/* + * fscrypt superblock flags + */ +#define FS_CFLG_OWN_PAGES (1U << 1) + +/* + * crypto operations for filesystems + */ +struct fscrypt_operations { + unsigned int flags; + const char *key_prefix; + int (*get_context)(struct inode *, void *, size_t); + int (*set_context)(struct inode *, const void *, size_t, void *); + bool (*dummy_context)(struct inode *); + bool (*empty_dir)(struct inode *); + unsigned (*max_namelen)(struct inode *); +}; + +struct fscrypt_ctx { + union { + struct { + struct page *bounce_page; /* Ciphertext page */ + struct page *control_page; /* Original page */ + } w; + struct { + struct bio *bio; + struct work_struct work; + } r; + struct list_head free_list; /* Free list */ + }; + u8 flags; /* Flags */ +}; + +static inline bool fscrypt_has_encryption_key(const struct inode *inode) +{ + return (inode->i_crypt_info != NULL); +} + +static inline bool fscrypt_dummy_context_enabled(struct inode *inode) +{ + return inode->i_sb->s_cop->dummy_context && + inode->i_sb->s_cop->dummy_context(inode); +} + /* crypto.c */ -extern struct kmem_cache *fscrypt_info_cachep; extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, @@ -19,6 +65,12 @@ extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, u64, gfp_t); extern int fscrypt_decrypt_page(const struct inode *, struct page *, unsigned int, unsigned int, u64); + +static inline struct page *fscrypt_control_page(struct page *page) +{ + return ((struct fscrypt_ctx *)page_private(page))->w.control_page; +} + extern void fscrypt_restore_control_page(struct page *); extern const struct dentry_operations fscrypt_d_ops; @@ -43,7 +95,7 @@ extern int fscrypt_inherit_context(struct inode *, struct inode *, void *, bool); /* keyinfo.c */ extern int fscrypt_get_encryption_info(struct inode *); -extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); +extern void fscrypt_put_encryption_info(struct inode *); /* fname.c */ extern int fscrypt_setup_filename(struct inode *, const struct qstr *, @@ -54,14 +106,11 @@ static inline void fscrypt_free_filename(struct fscrypt_name *fname) kfree(fname->crypto_buf.name); } -extern u32 fscrypt_fname_encrypted_size(const struct inode *, u32); extern int fscrypt_fname_alloc_buffer(const struct inode *, u32, struct fscrypt_str *); extern void fscrypt_fname_free_buffer(struct fscrypt_str *); extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, const struct fscrypt_str *, struct fscrypt_str *); -extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, - struct fscrypt_str *); #define FSCRYPT_FNAME_MAX_UNDIGESTED_SIZE 32 @@ -152,5 +201,14 @@ extern int __fscrypt_prepare_rename(struct inode *old_dir, struct dentry *new_dentry, unsigned int flags); extern int __fscrypt_prepare_lookup(struct inode *dir, struct dentry *dentry); +extern int __fscrypt_prepare_symlink(struct inode *dir, unsigned int len, + unsigned int max_len, + struct fscrypt_str *disk_link); +extern int __fscrypt_encrypt_symlink(struct inode *inode, const char *target, + unsigned int len, + struct fscrypt_str *disk_link); +extern const char *fscrypt_get_symlink(struct inode *inode, const void *caddr, + unsigned int max_size, + struct delayed_call *done); #endif /* _LINUX_FSCRYPT_SUPP_H */ diff --git a/include/uapi/linux/fcntl.h b/include/uapi/linux/fcntl.h index beed138bd359..f85ed3a5ef4d 100644 --- a/include/uapi/linux/fcntl.h +++ b/include/uapi/linux/fcntl.h @@ -42,6 +42,27 @@ #define F_SEAL_WRITE 0x0008 /* prevent writes */ /* (1U << 31) is reserved for signed error codes */ +/* + * Set/Get write life time hints. {GET,SET}_RW_HINT operate on the + * underlying inode, while {GET,SET}_FILE_RW_HINT operate only on + * the specific file. + */ +#define F_GET_RW_HINT (F_LINUX_SPECIFIC_BASE + 11) +#define F_SET_RW_HINT (F_LINUX_SPECIFIC_BASE + 12) +#define F_GET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 13) +#define F_SET_FILE_RW_HINT (F_LINUX_SPECIFIC_BASE + 14) + +/* + * Valid hint values for F_{GET,SET}_RW_HINT. 0 is "not set", or can be + * used to clear any hints previously set. + */ +#define RWF_WRITE_LIFE_NOT_SET 0 +#define RWH_WRITE_LIFE_NONE 1 +#define RWH_WRITE_LIFE_SHORT 2 +#define RWH_WRITE_LIFE_MEDIUM 3 +#define RWH_WRITE_LIFE_LONG 4 +#define RWH_WRITE_LIFE_EXTREME 5 + /* * Types of directory notifications that may be requested. */ -- GitLab From cb023581bd03420f8b4261b2501be18b4bae8de6 Mon Sep 17 00:00:00 2001 From: Connor O'Brien Date: Mon, 9 Apr 2018 15:54:08 -0700 Subject: [PATCH 0986/1834] ANDROID: proc: add null check in proc_uid_init Check for case when proc_mkdir returns null. Bug: 75236413 Test: Build & boot device; run 'ls /proc/uid/' Change-Id: Ie8dd71cc724787286a5f7bc19b5a611ac87a2697 Signed-off-by: Connor O'Brien --- fs/proc/uid.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/proc/uid.c b/fs/proc/uid.c index 480338756b4c..3fd7b9fe974e 100644 --- a/fs/proc/uid.c +++ b/fs/proc/uid.c @@ -286,6 +286,8 @@ static const struct inode_operations proc_uid_inode_operations = { int __init proc_uid_init(void) { proc_uid = proc_mkdir("uid", NULL); + if (!proc_uid) + return -ENOMEM; proc_uid->proc_iops = &proc_uid_inode_operations; proc_uid->proc_fops = &proc_uid_operations; -- GitLab From 25fc5107fc3ea1dc37f104c4e4f843a8a5c5d1b9 Mon Sep 17 00:00:00 2001 From: Karthik Anantha Ram Date: Mon, 9 Apr 2018 18:35:54 -0700 Subject: [PATCH 0987/1834] msm: camera: reqmgr: Handle inject delay per req_id Currently inject delay is incorporated as part of the pd table. This change applies the delay for the specified request thereby ensuring that when multiple requests are added we don't manipulate the inject delay in the wrong way. Change-Id: I29fdee97531891bcd9d3087fbef17caa0a461bf7 Signed-off-by: Karthik Anantha Ram --- .../msm/camera/cam_req_mgr/cam_req_mgr_core.c | 15 ++++++++++----- .../msm/camera/cam_req_mgr/cam_req_mgr_core.h | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c index 65052e18da5e..adfac57d3678 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.c @@ -183,6 +183,7 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) int32_t curr_idx = traverse_data->idx; struct cam_req_mgr_req_tbl *tbl; struct cam_req_mgr_apply *apply_data; + struct cam_req_mgr_tbl_slot *slot = NULL; if (!traverse_data->tbl || !traverse_data->apply_data) { CAM_ERR(CAM_CRM, "NULL pointer %pK %pK", @@ -193,17 +194,18 @@ static int __cam_req_mgr_traverse(struct cam_req_mgr_traverse *traverse_data) tbl = traverse_data->tbl; apply_data = traverse_data->apply_data; + slot = &tbl->slot[curr_idx]; CAM_DBG(CAM_CRM, "Enter pd %d idx %d state %d skip %d status %d skip_idx %d", tbl->pd, curr_idx, tbl->slot[curr_idx].state, tbl->skip_traverse, traverse_data->in_q->slot[curr_idx].status, traverse_data->in_q->slot[curr_idx].skip_idx); - if ((tbl->inject_delay > 0) && + if ((slot->inject_delay > 0) && (traverse_data->self_link == true)) { CAM_DBG(CAM_CRM, "Injecting Delay of one frame"); apply_data[tbl->pd].req_id = -1; - tbl->inject_delay--; + slot->inject_delay--; /* This pd table is not ready to proceed with asked idx */ SET_FAILURE_BIT(traverse_data->result, tbl->pd); return -EAGAIN; @@ -1593,10 +1595,13 @@ int cam_req_mgr_process_add_req(void *priv, void *data) goto end; } - if (add_req->skip_before_applying > tbl->inject_delay) - tbl->inject_delay = add_req->skip_before_applying; - slot = &tbl->slot[idx]; + if (add_req->skip_before_applying > slot->inject_delay) { + slot->inject_delay = add_req->skip_before_applying; + CAM_DBG(CAM_CRM, "Req_id %llu injecting delay %u", + add_req->req_id, add_req->skip_before_applying); + } + if (slot->state != CRM_REQ_STATE_PENDING && slot->state != CRM_REQ_STATE_EMPTY) { CAM_WARN(CAM_CRM, "Unexpected state %d for slot %d map %x", diff --git a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h index 5ad23b7d7c24..73ffb81dd953 100644 --- a/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h +++ b/drivers/media/platform/msm/camera/cam_req_mgr/cam_req_mgr_core.h @@ -166,11 +166,13 @@ struct cam_req_mgr_apply { * @idx : slot index * @req_ready_map : mask tracking which all devices have request ready * @state : state machine for life cycle of a slot + * @inject_delay : insert extra bubbling for flash type of use cases */ struct cam_req_mgr_tbl_slot { int32_t idx; uint32_t req_ready_map; enum crm_req_state state; + uint32_t inject_delay; }; /** @@ -185,7 +187,6 @@ struct cam_req_mgr_tbl_slot { * @pd_delta : differnce between this table's pipeline delay and next * @num_slots : number of request slots present in the table * @slot : array of slots tracking requests availability at devices - * @inject_delay : insert extra bubbling for flash type of use cases */ struct cam_req_mgr_req_tbl { int32_t id; @@ -197,7 +198,6 @@ struct cam_req_mgr_req_tbl { int32_t pd_delta; int32_t num_slots; struct cam_req_mgr_tbl_slot slot[MAX_REQ_SLOTS]; - uint32_t inject_delay; }; /** -- GitLab From ddeedda6e71c5919adae5419297fb27a622128b4 Mon Sep 17 00:00:00 2001 From: "sudarsana.kalluru@cavium.com" Date: Thu, 4 May 2017 08:15:04 -0700 Subject: [PATCH 0988/1834] qed: Fix overriding of supported autoneg value. [ Upstream commit 34f9199ce7b7e5c641b96e928bd60e086bf7f278 ] Driver currently uses advertised-autoneg value to populate the supported-autoneg field. When advertised field is updated, user gets the same value for supported field. Supported-autoneg value need to be populated from the link capabilities value returned by the MFW. Signed-off-by: Sudarsana Reddy Kalluru Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 3 +++ drivers/net/ethernet/qlogic/qed/qed_main.c | 6 +++++- drivers/net/ethernet/qlogic/qed/qed_mcp.h | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index afe5e57d9acb..9a6adbd9ed34 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -1628,6 +1628,9 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) DP_NOTICE(p_hwfn, "Unknown Speed in 0x%08x\n", link_temp); } + p_hwfn->mcp_info->link_capabilities.default_speed_autoneg = + link->speed.autoneg; + link_temp &= NVM_CFG1_PORT_DRV_FLOW_CONTROL_MASK; link_temp >>= NVM_CFG1_PORT_DRV_FLOW_CONTROL_OFFSET; link->pause.autoneg = !!(link_temp & diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index dba3fbe4800e..0b949c6d83fc 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -1240,7 +1240,7 @@ static void qed_fill_link(struct qed_hwfn *hwfn, /* TODO - at the moment assume supported and advertised speed equal */ if_link->supported_caps = QED_LM_FIBRE_BIT; - if (params.speed.autoneg) + if (link_caps.default_speed_autoneg) if_link->supported_caps |= QED_LM_Autoneg_BIT; if (params.pause.autoneg || (params.pause.forced_rx && params.pause.forced_tx)) @@ -1250,6 +1250,10 @@ static void qed_fill_link(struct qed_hwfn *hwfn, if_link->supported_caps |= QED_LM_Pause_BIT; if_link->advertised_caps = if_link->supported_caps; + if (params.speed.autoneg) + if_link->advertised_caps |= QED_LM_Autoneg_BIT; + else + if_link->advertised_caps &= ~QED_LM_Autoneg_BIT; if (params.speed.advertised_speeds & NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G) if_link->advertised_caps |= QED_LM_1000baseT_Half_BIT | diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h index dff520ed069b..7b7a84d2c839 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h @@ -35,6 +35,7 @@ struct qed_mcp_link_params { struct qed_mcp_link_capabilities { u32 speed_capabilities; + bool default_speed_autoneg; }; struct qed_mcp_link_state { -- GitLab From 9abd45b5e52c7221ded50fd1512d5f85d64f8261 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 4 May 2017 08:42:30 +0200 Subject: [PATCH 0989/1834] cfg80211: make RATE_INFO_BW_20 the default [ Upstream commit 842be75c77cb72ee546a2b19da9c285fb3ded660 ] Due to the way I did the RX bitrate conversions in mac80211 with spatch, going setting flags to setting the value, many drivers now don't set the bandwidth value for 20 MHz, since with the flags it wasn't necessary to (there was no 20 MHz flag, only the others.) Rather than go through and try to fix up all the drivers, instead renumber the enum so that 20 MHz, which is the typical bandwidth, actually has the value 0, making those drivers all work again. If VHT was hit used with a driver not reporting it, e.g. iwlmvm, this manifested in hitting the bandwidth warning in cfg80211_calculate_bitrate_vht(). Reported-by: Linus Torvalds Tested-by: Jens Axboe Signed-off-by: Johannes Berg Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/net/cfg80211.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 66167138120a..9d57639223c3 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -947,9 +947,9 @@ enum rate_info_flags { * @RATE_INFO_BW_160: 160 MHz bandwidth */ enum rate_info_bw { + RATE_INFO_BW_20 = 0, RATE_INFO_BW_5, RATE_INFO_BW_10, - RATE_INFO_BW_20, RATE_INFO_BW_40, RATE_INFO_BW_80, RATE_INFO_BW_160, -- GitLab From beaf445bdd0677d45032aa082faa8dc106526bd5 Mon Sep 17 00:00:00 2001 From: Julia Cartwright Date: Fri, 28 Apr 2017 12:41:02 -0500 Subject: [PATCH 0990/1834] md/raid5: make use of spin_lock_irq over local_irq_disable + spin_lock [ Upstream commit 3d05f3aed5d721c2c77d20288c29ab26c6193ed5 ] On mainline, there is no functional difference, just less code, and symmetric lock/unlock paths. On PREEMPT_RT builds, this fixes the following warning, seen by Alexander GQ Gerasiov, due to the sleeping nature of spinlocks. BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:993 in_atomic(): 0, irqs_disabled(): 1, pid: 58, name: kworker/u12:1 CPU: 5 PID: 58 Comm: kworker/u12:1 Tainted: G W 4.9.20-rt16-stand6-686 #1 Hardware name: Supermicro SYS-5027R-WRF/X9SRW-F, BIOS 3.2a 10/28/2015 Workqueue: writeback wb_workfn (flush-253:0) Call Trace: dump_stack+0x47/0x68 ? migrate_enable+0x4a/0xf0 ___might_sleep+0x101/0x180 rt_spin_lock+0x17/0x40 add_stripe_bio+0x4e3/0x6c0 [raid456] ? preempt_count_add+0x42/0xb0 raid5_make_request+0x737/0xdd0 [raid456] Reported-by: Alexander GQ Gerasiov Tested-by: Alexander GQ Gerasiov Signed-off-by: Julia Cartwright Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/raid5.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 4493be50fc6a..86ba7851e881 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -110,8 +110,7 @@ static inline void unlock_device_hash_lock(struct r5conf *conf, int hash) static inline void lock_all_device_hash_locks_irq(struct r5conf *conf) { int i; - local_irq_disable(); - spin_lock(conf->hash_locks); + spin_lock_irq(conf->hash_locks); for (i = 1; i < NR_STRIPE_HASH_LOCKS; i++) spin_lock_nest_lock(conf->hash_locks + i, conf->hash_locks); spin_lock(&conf->device_lock); @@ -121,9 +120,9 @@ static inline void unlock_all_device_hash_locks_irq(struct r5conf *conf) { int i; spin_unlock(&conf->device_lock); - for (i = NR_STRIPE_HASH_LOCKS; i; i--) - spin_unlock(conf->hash_locks + i - 1); - local_irq_enable(); + for (i = NR_STRIPE_HASH_LOCKS - 1; i; i--) + spin_unlock(conf->hash_locks + i); + spin_unlock_irq(conf->hash_locks); } /* bio's attached to a stripe+device for I/O are linked together in bi_sector @@ -732,12 +731,11 @@ static bool is_full_stripe_write(struct stripe_head *sh) static void lock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2) { - local_irq_disable(); if (sh1 > sh2) { - spin_lock(&sh2->stripe_lock); + spin_lock_irq(&sh2->stripe_lock); spin_lock_nested(&sh1->stripe_lock, 1); } else { - spin_lock(&sh1->stripe_lock); + spin_lock_irq(&sh1->stripe_lock); spin_lock_nested(&sh2->stripe_lock, 1); } } @@ -745,8 +743,7 @@ static void lock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2) static void unlock_two_stripes(struct stripe_head *sh1, struct stripe_head *sh2) { spin_unlock(&sh1->stripe_lock); - spin_unlock(&sh2->stripe_lock); - local_irq_enable(); + spin_unlock_irq(&sh2->stripe_lock); } /* Only freshly new full stripe normal write stripe can be added to a batch list */ -- GitLab From d36d6e43078a6ccc1e984534f292e19ab2733935 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 13:43:24 +0800 Subject: [PATCH 0991/1834] rtc: snvs: fix an incorrect check of return value [ Upstream commit 758929005f06f954b7e1c87a1c9fdb44157b228f ] Function devm_regmap_init_mmio() returns an ERR_PTR on error. However, in function snvs_rtc_probe() its return value is checked against NULL. This patch fixes it by checking the return value with IS_ERR(). Signed-off-by: Pan Bian Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-snvs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 0f11c2a228e3..a753ef9c1459 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -257,7 +257,7 @@ static int snvs_rtc_probe(struct platform_device *pdev) of_property_read_u32(pdev->dev.of_node, "offset", &data->offset); } - if (!data->regmap) { + if (IS_ERR(data->regmap)) { dev_err(&pdev->dev, "Can't find snvs syscon\n"); return -ENODEV; } -- GitLab From 82652acdd73a0c2b0e1cddeccfc8ab9dc90e2432 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Thu, 4 May 2017 09:51:40 -0500 Subject: [PATCH 0992/1834] x86/asm: Don't use RBP as a temporary register in csum_partial_copy_generic() [ Upstream commit 42fc6c6cb1662ba2fa727dd01c9473c63be4e3b6 ] Andrey Konovalov reported the following warning while fuzzing the kernel with syzkaller: WARNING: kernel stack regs at ffff8800686869f8 in a.out:4933 has bad 'bp' value c3fc855a10167ec0 The unwinder dump revealed that RBP had a bad value when an interrupt occurred in csum_partial_copy_generic(). That function saves RBP on the stack and then overwrites it, using it as a scratch register. That's problematic because it breaks stack traces if an interrupt occurs in the middle of the function. Replace the usage of RBP with another callee-saved register (R15) so stack traces are no longer affected. Reported-by: Andrey Konovalov Tested-by: Andrey Konovalov Signed-off-by: Josh Poimboeuf Cc: Cong Wang Cc: David S . Miller Cc: Dmitry Vyukov Cc: Eric Dumazet Cc: Kostya Serebryany Cc: Linus Torvalds Cc: Marcelo Ricardo Leitner Cc: Neil Horman Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Vlad Yasevich Cc: linux-sctp@vger.kernel.org Cc: netdev Cc: syzkaller Link: http://lkml.kernel.org/r/4b03a961efda5ec9bfe46b7b9c9ad72d1efad343.1493909486.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/lib/csum-copy_64.S | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/x86/lib/csum-copy_64.S b/arch/x86/lib/csum-copy_64.S index 7e48807b2fa1..45a53dfe1859 100644 --- a/arch/x86/lib/csum-copy_64.S +++ b/arch/x86/lib/csum-copy_64.S @@ -55,7 +55,7 @@ ENTRY(csum_partial_copy_generic) movq %r12, 3*8(%rsp) movq %r14, 4*8(%rsp) movq %r13, 5*8(%rsp) - movq %rbp, 6*8(%rsp) + movq %r15, 6*8(%rsp) movq %r8, (%rsp) movq %r9, 1*8(%rsp) @@ -74,7 +74,7 @@ ENTRY(csum_partial_copy_generic) /* main loop. clear in 64 byte blocks */ /* r9: zero, r8: temp2, rbx: temp1, rax: sum, rcx: saved length */ /* r11: temp3, rdx: temp4, r12 loopcnt */ - /* r10: temp5, rbp: temp6, r14 temp7, r13 temp8 */ + /* r10: temp5, r15: temp6, r14 temp7, r13 temp8 */ .p2align 4 .Lloop: source @@ -89,7 +89,7 @@ ENTRY(csum_partial_copy_generic) source movq 32(%rdi), %r10 source - movq 40(%rdi), %rbp + movq 40(%rdi), %r15 source movq 48(%rdi), %r14 source @@ -103,7 +103,7 @@ ENTRY(csum_partial_copy_generic) adcq %r11, %rax adcq %rdx, %rax adcq %r10, %rax - adcq %rbp, %rax + adcq %r15, %rax adcq %r14, %rax adcq %r13, %rax @@ -121,7 +121,7 @@ ENTRY(csum_partial_copy_generic) dest movq %r10, 32(%rsi) dest - movq %rbp, 40(%rsi) + movq %r15, 40(%rsi) dest movq %r14, 48(%rsi) dest @@ -203,7 +203,7 @@ ENTRY(csum_partial_copy_generic) movq 3*8(%rsp), %r12 movq 4*8(%rsp), %r14 movq 5*8(%rsp), %r13 - movq 6*8(%rsp), %rbp + movq 6*8(%rsp), %r15 addq $7*8, %rsp ret -- GitLab From c49892015f528ccf4d53d9e388a9ce0cdd1cba37 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 1 May 2017 15:47:41 -0700 Subject: [PATCH 0993/1834] x86/mm/kaslr: Use the _ASM_MUL macro for multiplication to work around Clang incompatibility [ Upstream commit 121843eb02a6e2fa30aefab64bfe183c97230c75 ] The constraint "rm" allows the compiler to put mix_const into memory. When the input operand is a memory location then MUL needs an operand size suffix, since Clang can't infer the multiplication width from the operand. Add and use the _ASM_MUL macro which determines the operand size and resolves to the NUL instruction with the corresponding suffix. This fixes the following error when building with clang: CC arch/x86/lib/kaslr.o /tmp/kaslr-dfe1ad.s: Assembler messages: /tmp/kaslr-dfe1ad.s:182: Error: no instruction mnemonic suffix given and no register operands; can't size instruction Signed-off-by: Matthias Kaehlcke Cc: Grant Grundler Cc: Greg Hackmann Cc: Kees Cook Cc: Linus Torvalds Cc: Michael Davidson Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20170501224741.133938-1-mka@chromium.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/include/asm/asm.h | 1 + arch/x86/lib/kaslr.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index f35f246a26bf..8d8c24f3a963 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -34,6 +34,7 @@ #define _ASM_ADD __ASM_SIZE(add) #define _ASM_SUB __ASM_SIZE(sub) #define _ASM_XADD __ASM_SIZE(xadd) +#define _ASM_MUL __ASM_SIZE(mul) #define _ASM_AX __ASM_REG(ax) #define _ASM_BX __ASM_REG(bx) diff --git a/arch/x86/lib/kaslr.c b/arch/x86/lib/kaslr.c index 121f59c6ee54..0c7fe444dcdd 100644 --- a/arch/x86/lib/kaslr.c +++ b/arch/x86/lib/kaslr.c @@ -5,6 +5,7 @@ * kernel starts. This file is included in the compressed kernel and * normally linked in the regular. */ +#include #include #include #include @@ -79,7 +80,7 @@ unsigned long kaslr_get_random_long(const char *purpose) } /* Circular multiply for better bit diffusion */ - asm("mul %3" + asm(_ASM_MUL "%3" : "=a" (random), "=d" (raw) : "a" (random), "rm" (mix_const)); random += raw; -- GitLab From 6371afaf56f87c31299cea40b63f02b69a994e0f Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Mon, 24 Apr 2017 19:54:13 +0300 Subject: [PATCH 0994/1834] ovl: persistent inode numbers for upper hardlinks [ Upstream commit 5b6c9053fb38a66fd5c6177fcf5022b24767811a ] An upper type non directory dentry that is a copy up target should have a reference to its lower copy up origin. There are three ways for an upper type dentry to be instantiated: 1. A lower type dentry that is being copied up 2. An entry that is found in upper dir by ovl_lookup() 3. A negative dentry is hardlinked to an upper type dentry In the first case, the lower reference is set before copy up. In the second case, the lower reference is found by ovl_lookup(). In the last case of hardlinked upper dentry, it is not easy to update the lower reference of the negative dentry. Instead, drop the newly hardlinked negative dentry from dcache and let the next access call ovl_lookup() to find its lower reference. This makes sure that the inode number reported by stat(2) after the hardlink is created is the same inode number that will be reported by stat(2) after mount cycle, which is the inode number of the lower copy up origin of the hardlink source. NOTE that this does not fix breaking of lower hardlinks on copy up, but only fixes the case of lower nlink == 1, whose upper copy up inode is hardlinked in upper dir. Signed-off-by: Amir Goldstein Signed-off-by: Miklos Szeredi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/dir.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 306b6c161840..8546384a5fdf 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -180,6 +180,9 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode, inc_nlink(inode); } d_instantiate(dentry, inode); + /* Force lookup of new upper hardlink to find its lower */ + if (hardlink) + d_drop(dentry); } static int ovl_create_upper(struct dentry *dentry, struct inode *inode, -- GitLab From 3032bccf250d792ab64eee2af9df47e94e58b7d3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 4 May 2017 13:44:04 -0400 Subject: [PATCH 0995/1834] NFSv4.1: RECLAIM_COMPLETE must handle NFS4ERR_CONN_NOT_BOUND_TO_SESSION [ Upstream commit 0048fdd06614a4ea088f9fcad11511956b795698 ] If the server returns NFS4ERR_CONN_NOT_BOUND_TO_SESSION because we are trunking, then RECLAIM_COMPLETE must handle that by calling nfs4_schedule_session_recovery() and then retrying. Reported-by: Chuck Lever Signed-off-by: Trond Myklebust Tested-by: Chuck Lever Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 7 ++++++- fs/nfs/nfs4state.c | 10 +++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4638654e26f3..d0d2a5e980aa 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -8173,6 +8173,12 @@ static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nf /* fall through */ case -NFS4ERR_RETRY_UNCACHED_REP: return -EAGAIN; + case -NFS4ERR_BADSESSION: + case -NFS4ERR_DEADSESSION: + case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION: + nfs4_schedule_session_recovery(clp->cl_session, + task->tk_status); + break; default: nfs4_schedule_lease_recovery(clp); } @@ -8251,7 +8257,6 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp, if (status == 0) status = task->tk_status; rpc_put_task(task); - return 0; out: dprintk("<-- %s status=%d\n", __func__, status); return status; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 71deeae6eefd..0bb0e620cf42 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1637,13 +1637,14 @@ static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp) nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot); } -static void nfs4_reclaim_complete(struct nfs_client *clp, +static int nfs4_reclaim_complete(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops, struct rpc_cred *cred) { /* Notify the server we're done reclaiming our state */ if (ops->reclaim_complete) - (void)ops->reclaim_complete(clp, cred); + return ops->reclaim_complete(clp, cred); + return 0; } static void nfs4_clear_reclaim_server(struct nfs_server *server) @@ -1690,13 +1691,16 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp) { const struct nfs4_state_recovery_ops *ops; struct rpc_cred *cred; + int err; if (!nfs4_state_clear_reclaim_reboot(clp)) return; ops = clp->cl_mvops->reboot_recovery_ops; cred = nfs4_get_clid_cred(clp); - nfs4_reclaim_complete(clp, ops, cred); + err = nfs4_reclaim_complete(clp, ops, cred); put_rpccred(cred); + if (err == -NFS4ERR_CONN_NOT_BOUND_TO_SESSION) + set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); } static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp) -- GitLab From b1b547afdbeb241ca7a253c10d6e7b767cad75f2 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 5 May 2017 21:51:16 -0700 Subject: [PATCH 0996/1834] x86/boot: Declare error() as noreturn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 60854a12d281e2fa25662fa32ac8022bbff17432 ] The compressed boot function error() is used to halt execution, but it wasn't marked with "noreturn". This fixes that in preparation for supporting kernel FORTIFY_SOURCE, which uses the noreturn annotation on panic, and calls error(). GCC would warn about a noreturn function calling a non-noreturn function: arch/x86/boot/compressed/misc.c: In function ‘fortify_panic’: arch/x86/boot/compressed/misc.c:416:1: warning: ‘noreturn’ function does return } ^ Signed-off-by: Kees Cook Cc: Daniel Micay Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: H. Peter Anvin Link: http://lkml.kernel.org/r/20170506045116.GA2879@beast Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/boot/compressed/error.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/boot/compressed/error.h b/arch/x86/boot/compressed/error.h index 2e59dac07f9e..d732e608e3af 100644 --- a/arch/x86/boot/compressed/error.h +++ b/arch/x86/boot/compressed/error.h @@ -1,7 +1,9 @@ #ifndef BOOT_COMPRESSED_ERROR_H #define BOOT_COMPRESSED_ERROR_H +#include + void warn(char *m); -void error(char *m); +void error(char *m) __noreturn; #endif /* BOOT_COMPRESSED_ERROR_H */ -- GitLab From f9800a1f5797c48ab9de6488077a869a59061470 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 4 May 2017 15:50:53 -0700 Subject: [PATCH 0997/1834] IB/srpt: Fix abort handling [ Upstream commit 55d694275f41a1c0eef4ef49044ff29bc3999490 ] Let the target core check the CMD_T_ABORTED flag instead of the SRP target driver. Hence remove the transport_check_aborted_status() call. Since state == SRPT_STATE_CMD_RSP_SENT is something that really should not happen, do not try to recover if srpt_queue_response() is called for an I/O context that is in that state. This patch is a bug fix because the srpt_abort_cmd() call is misplaced - if that function is called from srpt_queue_response() it should either be called before the command state is changed or after the response has been sent. Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Cc: Doug Ledford Cc: Christoph Hellwig Cc: Andy Grover Cc: David Disseldorp Signed-off-by: Nicholas Bellinger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srpt/ib_srpt.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 29ab814693fc..860bb59f6326 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2292,12 +2292,8 @@ static void srpt_queue_response(struct se_cmd *cmd) } spin_unlock_irqrestore(&ioctx->spinlock, flags); - if (unlikely(transport_check_aborted_status(&ioctx->cmd, false) - || WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) { - atomic_inc(&ch->req_lim_delta); - srpt_abort_cmd(ioctx); + if (unlikely(WARN_ON_ONCE(state == SRPT_STATE_CMD_RSP_SENT))) return; - } /* For read commands, transfer the data to the initiator. */ if (ioctx->cmd.data_direction == DMA_FROM_DEVICE && -- GitLab From 84284968156340dce4e942b1cebea66c3d4f8146 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 4 May 2017 15:50:54 -0700 Subject: [PATCH 0998/1834] IB/srpt: Avoid that aborting a command triggers a kernel warning [ Upstream commit bd2c52d733f126ff75f99c537a27655b2db07e28 ] Avoid that the following warning is triggered: WARNING: CPU: 10 PID: 166 at ../drivers/infiniband/ulp/srpt/ib_srpt.c:2674 srpt_release_cmd+0x139/0x140 [ib_srpt] CPU: 10 PID: 166 Comm: kworker/u24:8 Not tainted 4.9.4-1-default #1 Workqueue: tmr-fileio target_tmr_work [target_core_mod] Call Trace: [] dump_stack+0x63/0x83 [] __warn+0xcb/0xf0 [] warn_slowpath_null+0x1d/0x20 [] srpt_release_cmd+0x139/0x140 [ib_srpt] [] target_release_cmd_kref+0xb7/0x120 [target_core_mod] [] target_put_sess_cmd+0x2f/0x60 [target_core_mod] [] core_tmr_lun_reset+0x340/0x790 [target_core_mod] [] target_tmr_work+0xe6/0x140 [target_core_mod] [] process_one_work+0x1f3/0x4d0 [] worker_thread+0x48/0x4e0 [] ? process_one_work+0x4d0/0x4d0 [] kthread+0xca/0xe0 [] ? kthread_park+0x60/0x60 [] ret_from_fork+0x25/0x30 Signed-off-by: Bart Van Assche Reviewed-by: Hannes Reinecke Cc: Doug Ledford Cc: Christoph Hellwig Cc: David Disseldorp Signed-off-by: Nicholas Bellinger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srpt/ib_srpt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 860bb59f6326..876f438aa048 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -2666,7 +2666,8 @@ static void srpt_release_cmd(struct se_cmd *se_cmd) struct srpt_rdma_ch *ch = ioctx->ch; unsigned long flags; - WARN_ON(ioctx->state != SRPT_STATE_DONE); + WARN_ON_ONCE(ioctx->state != SRPT_STATE_DONE && + !(ioctx->cmd.transport_state & CMD_T_ABORTED)); if (ioctx->n_rw_ctx) { srpt_free_rw_ctxs(ch, ioctx); -- GitLab From a587acdbb01fa549b9fdc272d079398379b0e25e Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 5 May 2017 07:40:42 +0200 Subject: [PATCH 0999/1834] af_key: Fix slab-out-of-bounds in pfkey_compile_policy. [ Upstream commit d90c902449a7561f1b1d58ba5a0d11728ce8b0b2 ] The sadb_x_sec_len is stored in the unit 'byte divided by eight'. So we have to multiply this value by eight before we can do size checks. Otherwise we may get a slab-out-of-bounds when we memcpy the user sec_ctx. Fixes: df71837d502 ("[LSM-IPSec]: Security association restriction.") Reported-by: Andrey Konovalov Tested-by: Andrey Konovalov Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/key/af_key.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/key/af_key.c b/net/key/af_key.c index 6482b001f19a..15150b412930 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -3305,7 +3305,7 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, p += pol->sadb_x_policy_len*8; sec_ctx = (struct sadb_x_sec_ctx *)p; if (len < pol->sadb_x_policy_len*8 + - sec_ctx->sadb_x_sec_len) { + sec_ctx->sadb_x_sec_len*8) { *dir = -EINVAL; goto out; } -- GitLab From a4e074608e2d9cd40802ed10b877ffb202aae95c Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 2 May 2017 17:56:21 +0300 Subject: [PATCH 1000/1834] mac80211: bail out from prep_connection() if a reconfig is ongoing [ Upstream commit f8860ce836f2d502b07ef99559707fe55d90f5bc ] If ieee80211_hw_restart() is called during authentication, the authentication process will continue, causing the driver to be called in a wrong state. This ultimately causes an oops in the iwlwifi driver (at least). This fixes bugzilla 195299 partly. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195299 Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/mlme.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index fdab4f1390d2..e6f42d12222e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4332,6 +4332,10 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!ifmgd->auth_data && !ifmgd->assoc_data)) return -EINVAL; + /* If a reconfig is happening, bail out */ + if (local->in_reconfig) + return -EBUSY; + if (assoc) { rcu_read_lock(); have_sta = sta_info_get(sdata, cbss->bssid); -- GitLab From 68e356469b2ecdfc4777c3329753183cc40a9227 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 5 May 2017 15:25:32 -0700 Subject: [PATCH 1001/1834] bna: Avoid reading past end of buffer [ Upstream commit 9e4eb1ce472fbf7b007f23c88ec11c37265e401c ] Using memcpy() from a string that is shorter than the length copied means the destination buffer is being filled with arbitrary data from the kernel rodata segment. Instead, use strncpy() which will fill the trailing bytes with zeros. This was found with the future CONFIG_FORTIFY_SOURCE feature. Cc: Daniel Micay Signed-off-by: Kees Cook Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/brocade/bna/bfa_ioc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/brocade/bna/bfa_ioc.c b/drivers/net/ethernet/brocade/bna/bfa_ioc.c index 0f6811860ad5..a36e38676640 100644 --- a/drivers/net/ethernet/brocade/bna/bfa_ioc.c +++ b/drivers/net/ethernet/brocade/bna/bfa_ioc.c @@ -2845,7 +2845,7 @@ bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc *ioc, char *optrom_ver) static void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc *ioc, char *manufacturer) { - memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN); + strncpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN); } static void -- GitLab From 694fb34bebb6de95eb1293b2ca190edf7a909f18 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 5 May 2017 15:34:34 -0700 Subject: [PATCH 1002/1834] qlge: Avoid reading past end of buffer [ Upstream commit df5303a8aa9a0a6934f4cea7427f1edf771f21c2 ] Using memcpy() from a string that is shorter than the length copied means the destination buffer is being filled with arbitrary data from the kernel rodata segment. Instead, use strncpy() which will fill the trailing bytes with zeros. This was found with the future CONFIG_FORTIFY_SOURCE feature. Cc: Daniel Micay Signed-off-by: Kees Cook Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qlge/qlge_dbg.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c index be258d90de9e..e3223f2fe2ff 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_dbg.c @@ -765,7 +765,7 @@ int ql_core_dump(struct ql_adapter *qdev, struct ql_mpi_coredump *mpi_coredump) sizeof(struct mpi_coredump_global_header); mpi_coredump->mpi_global_header.imageSize = sizeof(struct ql_mpi_coredump); - memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", + strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", sizeof(mpi_coredump->mpi_global_header.idString)); /* Get generic NIC reg dump */ @@ -1255,7 +1255,7 @@ static void ql_gen_reg_dump(struct ql_adapter *qdev, sizeof(struct mpi_coredump_global_header); mpi_coredump->mpi_global_header.imageSize = sizeof(struct ql_reg_dump); - memcpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", + strncpy(mpi_coredump->mpi_global_header.idString, "MPI Coredump", sizeof(mpi_coredump->mpi_global_header.idString)); -- GitLab From 0d84e3b5a64ac3405a103e579d8a903fad916798 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Mon, 3 Apr 2017 13:44:11 +0200 Subject: [PATCH 1003/1834] ubi: fastmap: Fix slab corruption [ Upstream commit 8a1435880f452430b41374d27ac4a33e7bd381ea ] Booting with UBI fastmap and SLUB debugging enabled results in the following splats. The problem is that ubi_scan_fastmap() moves the fastmap blocks from the scan_ai (allocated in scan_fast()) to the ai allocated in ubi_attach(). This results in two problems: - When the scan_ai is freed, aebs which were allocated from its slab cache are still in use. - When the other ai is being destroyed in destroy_ai(), the arguments to kmem_cache_free() call are incorrect since aebs on its ->fastmap list were allocated with a slab cache from a differnt ai. Fix this by making a copy of the aebs in ubi_scan_fastmap() instead of moving them. ============================================================================= BUG ubi_aeb_slab_cache (Not tainted): Objects remaining in ubi_aeb_slab_cache on __kmem_cache_shutdown() ----------------------------------------------------------------------------- INFO: Slab 0xbfd2da3c objects=17 used=1 fp=0xb33d7748 flags=0x40000080 CPU: 1 PID: 118 Comm: ubiattach Tainted: G B 4.9.15 #3 [<80111910>] (unwind_backtrace) from [<8010d498>] (show_stack+0x18/0x1c) [<8010d498>] (show_stack) from [<804a3274>] (dump_stack+0xb4/0xe0) [<804a3274>] (dump_stack) from [<8026c47c>] (slab_err+0x78/0x88) [<8026c47c>] (slab_err) from [<802735bc>] (__kmem_cache_shutdown+0x180/0x3e0) [<802735bc>] (__kmem_cache_shutdown) from [<8024e13c>] (shutdown_cache+0x1c/0x60) [<8024e13c>] (shutdown_cache) from [<8024ed64>] (kmem_cache_destroy+0x19c/0x20c) [<8024ed64>] (kmem_cache_destroy) from [<8057cc14>] (destroy_ai+0x1dc/0x1e8) [<8057cc14>] (destroy_ai) from [<8057f04c>] (ubi_attach+0x3f4/0x450) [<8057f04c>] (ubi_attach) from [<8056fe70>] (ubi_attach_mtd_dev+0x60c/0xff8) [<8056fe70>] (ubi_attach_mtd_dev) from [<80571d78>] (ctrl_cdev_ioctl+0x110/0x2b8) [<80571d78>] (ctrl_cdev_ioctl) from [<8029c77c>] (do_vfs_ioctl+0xac/0xa00) [<8029c77c>] (do_vfs_ioctl) from [<8029d10c>] (SyS_ioctl+0x3c/0x64) [<8029d10c>] (SyS_ioctl) from [<80108860>] (ret_fast_syscall+0x0/0x1c) INFO: Object 0xb33d7e88 @offset=3720 INFO: Allocated in scan_peb+0x608/0x81c age=72 cpu=1 pid=118 kmem_cache_alloc+0x3b0/0x43c scan_peb+0x608/0x81c ubi_attach+0x124/0x450 ubi_attach_mtd_dev+0x60c/0xff8 ctrl_cdev_ioctl+0x110/0x2b8 do_vfs_ioctl+0xac/0xa00 SyS_ioctl+0x3c/0x64 ret_fast_syscall+0x0/0x1c kmem_cache_destroy ubi_aeb_slab_cache: Slab cache still has objects CPU: 1 PID: 118 Comm: ubiattach Tainted: G B 4.9.15 #3 [<80111910>] (unwind_backtrace) from [<8010d498>] (show_stack+0x18/0x1c) [<8010d498>] (show_stack) from [<804a3274>] (dump_stack+0xb4/0xe0) [<804a3274>] (dump_stack) from [<8024ed80>] (kmem_cache_destroy+0x1b8/0x20c) [<8024ed80>] (kmem_cache_destroy) from [<8057cc14>] (destroy_ai+0x1dc/0x1e8) [<8057cc14>] (destroy_ai) from [<8057f04c>] (ubi_attach+0x3f4/0x450) [<8057f04c>] (ubi_attach) from [<8056fe70>] (ubi_attach_mtd_dev+0x60c/0xff8) [<8056fe70>] (ubi_attach_mtd_dev) from [<80571d78>] (ctrl_cdev_ioctl+0x110/0x2b8) [<80571d78>] (ctrl_cdev_ioctl) from [<8029c77c>] (do_vfs_ioctl+0xac/0xa00) [<8029c77c>] (do_vfs_ioctl) from [<8029d10c>] (SyS_ioctl+0x3c/0x64) [<8029d10c>] (SyS_ioctl) from [<80108860>] (ret_fast_syscall+0x0/0x1c) cache_from_obj: Wrong slab cache. ubi_aeb_slab_cache but object is from ubi_aeb_slab_cache ------------[ cut here ]------------ WARNING: CPU: 1 PID: 118 at mm/slab.h:354 kmem_cache_free+0x39c/0x450 Modules linked in: CPU: 1 PID: 118 Comm: ubiattach Tainted: G B 4.9.15 #3 [<80111910>] (unwind_backtrace) from [<8010d498>] (show_stack+0x18/0x1c) [<8010d498>] (show_stack) from [<804a3274>] (dump_stack+0xb4/0xe0) [<804a3274>] (dump_stack) from [<80120e40>] (__warn+0xf4/0x10c) [<80120e40>] (__warn) from [<80120f20>] (warn_slowpath_null+0x28/0x30) [<80120f20>] (warn_slowpath_null) from [<80271fe0>] (kmem_cache_free+0x39c/0x450) [<80271fe0>] (kmem_cache_free) from [<8057cb88>] (destroy_ai+0x150/0x1e8) [<8057cb88>] (destroy_ai) from [<8057ef1c>] (ubi_attach+0x2c4/0x450) [<8057ef1c>] (ubi_attach) from [<8056fe70>] (ubi_attach_mtd_dev+0x60c/0xff8) [<8056fe70>] (ubi_attach_mtd_dev) from [<80571d78>] (ctrl_cdev_ioctl+0x110/0x2b8) [<80571d78>] (ctrl_cdev_ioctl) from [<8029c77c>] (do_vfs_ioctl+0xac/0xa00) [<8029c77c>] (do_vfs_ioctl) from [<8029d10c>] (SyS_ioctl+0x3c/0x64) [<8029d10c>] (SyS_ioctl) from [<80108860>] (ret_fast_syscall+0x0/0x1c) ---[ end trace 2bd8396277fd0a0b ]--- ============================================================================= BUG ubi_aeb_slab_cache (Tainted: G B W ): page slab pointer corrupt. ----------------------------------------------------------------------------- INFO: Allocated in scan_peb+0x608/0x81c age=104 cpu=1 pid=118 kmem_cache_alloc+0x3b0/0x43c scan_peb+0x608/0x81c ubi_attach+0x124/0x450 ubi_attach_mtd_dev+0x60c/0xff8 ctrl_cdev_ioctl+0x110/0x2b8 do_vfs_ioctl+0xac/0xa00 SyS_ioctl+0x3c/0x64 ret_fast_syscall+0x0/0x1c INFO: Slab 0xbfd2da3c objects=17 used=1 fp=0xb33d7748 flags=0x40000081 INFO: Object 0xb33d7e88 @offset=3720 fp=0xb33d7da0 Redzone b33d7e80: cc cc cc cc cc cc cc cc ........ Object b33d7e88: 02 00 00 00 01 00 00 00 00 f0 ff 7f ff ff ff ff ................ Object b33d7e98: 00 00 00 00 00 00 00 00 bd 16 00 00 00 00 00 00 ................ Object b33d7ea8: 00 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 ................ Redzone b33d7eb8: cc cc cc cc .... Padding b33d7f60: 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZ CPU: 1 PID: 118 Comm: ubiattach Tainted: G B W 4.9.15 #3 [<80111910>] (unwind_backtrace) from [<8010d498>] (show_stack+0x18/0x1c) [<8010d498>] (show_stack) from [<804a3274>] (dump_stack+0xb4/0xe0) [<804a3274>] (dump_stack) from [<80271770>] (free_debug_processing+0x320/0x3c4) [<80271770>] (free_debug_processing) from [<80271ad0>] (__slab_free+0x2bc/0x430) [<80271ad0>] (__slab_free) from [<80272024>] (kmem_cache_free+0x3e0/0x450) [<80272024>] (kmem_cache_free) from [<8057cb88>] (destroy_ai+0x150/0x1e8) [<8057cb88>] (destroy_ai) from [<8057ef1c>] (ubi_attach+0x2c4/0x450) [<8057ef1c>] (ubi_attach) from [<8056fe70>] (ubi_attach_mtd_dev+0x60c/0xff8) [<8056fe70>] (ubi_attach_mtd_dev) from [<80571d78>] (ctrl_cdev_ioctl+0x110/0x2b8) [<80571d78>] (ctrl_cdev_ioctl) from [<8029c77c>] (do_vfs_ioctl+0xac/0xa00) [<8029c77c>] (do_vfs_ioctl) from [<8029d10c>] (SyS_ioctl+0x3c/0x64) [<8029d10c>] (SyS_ioctl) from [<80108860>] (ret_fast_syscall+0x0/0x1c) FIX ubi_aeb_slab_cache: Object at 0xb33d7e88 not freed Signed-off-by: Rabin Vincent Signed-off-by: Richard Weinberger Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/fastmap.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index c1f5c29e458e..b44c8d348e78 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -828,6 +828,24 @@ static int find_fm_anchor(struct ubi_attach_info *ai) return ret; } +static struct ubi_ainf_peb *clone_aeb(struct ubi_attach_info *ai, + struct ubi_ainf_peb *old) +{ + struct ubi_ainf_peb *new; + + new = ubi_alloc_aeb(ai, old->pnum, old->ec); + if (!new) + return NULL; + + new->vol_id = old->vol_id; + new->sqnum = old->sqnum; + new->lnum = old->lnum; + new->scrub = old->scrub; + new->copy_flag = old->copy_flag; + + return new; +} + /** * ubi_scan_fastmap - scan the fastmap. * @ubi: UBI device object @@ -847,7 +865,7 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, struct ubi_vid_hdr *vh; struct ubi_ec_hdr *ech; struct ubi_fastmap_layout *fm; - struct ubi_ainf_peb *tmp_aeb, *aeb; + struct ubi_ainf_peb *aeb; int i, used_blocks, pnum, fm_anchor, ret = 0; size_t fm_size; __be32 crc, tmp_crc; @@ -857,9 +875,16 @@ int ubi_scan_fastmap(struct ubi_device *ubi, struct ubi_attach_info *ai, if (fm_anchor < 0) return UBI_NO_FASTMAP; - /* Move all (possible) fastmap blocks into our new attach structure. */ - list_for_each_entry_safe(aeb, tmp_aeb, &scan_ai->fastmap, u.list) - list_move_tail(&aeb->u.list, &ai->fastmap); + /* Copy all (possible) fastmap blocks into our new attach structure. */ + list_for_each_entry(aeb, &scan_ai->fastmap, u.list) { + struct ubi_ainf_peb *new; + + new = clone_aeb(ai, aeb); + if (!new) + return -ENOMEM; + + list_add(&new->u.list, &ai->fastmap); + } down_write(&ubi->fm_protect); memset(ubi->fm_buf, 0, ubi->fm_size); -- GitLab From ad741ccdd88e8ab7d42f44509280abe5f615a1cf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 May 2017 08:33:24 +0300 Subject: [PATCH 1004/1834] ipmi_ssif: unlock on allocation failure [ Upstream commit cf9806f32ef63b745f2486e0dbb2ac21f4ca44f0 ] We should unlock and re-enable IRQs if this allocation fails. Fixes: 259307074bfc ("ipmi: Add SMBus interface driver (SSIF) ") Signed-off-by: Dan Carpenter Signed-off-by: Corey Minyard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/char/ipmi/ipmi_ssif.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 510fc104bcdc..f11c1c7e84c6 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -409,6 +409,7 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags) msg = ipmi_alloc_smi_msg(); if (!msg) { ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); return; } @@ -431,6 +432,7 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info, msg = ipmi_alloc_smi_msg(); if (!msg) { ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); return; } -- GitLab From 2d11840e917e3f014ac4480b1a9e29977220aadf Mon Sep 17 00:00:00 2001 From: Jim Baxter Date: Mon, 8 May 2017 13:49:57 +0100 Subject: [PATCH 1005/1834] net: cdc_ncm: Fix TX zero padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit aeca3a77b1e0ed06a095933b89c86aed007383eb ] The zero padding that is added to NTB's does not zero the memory correctly. This is because the skb_put modifies the value of skb_out->len which results in the memset command not setting any memory to zero as (ctx->tx_max - skb_out->len) == 0. I have resolved this by storing the size of the memory to be zeroed before the skb_put and using this in the memset call. Signed-off-by: Jim Baxter Reviewed-by: Bjørn Mork Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ncm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index dc6d3b0a0be8..feb61eaffe32 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -1118,6 +1118,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) u16 n = 0, index, ndplen; u8 ready2send = 0; u32 delayed_ndp_size; + size_t padding_count; /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated * accordingly. Otherwise, we should check here. @@ -1274,11 +1275,13 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign) * a ZLP after full sized NTBs. */ if (!(dev->driver_info->flags & FLAG_SEND_ZLP) && - skb_out->len > ctx->min_tx_pkt) - memset(skb_put(skb_out, ctx->tx_max - skb_out->len), 0, - ctx->tx_max - skb_out->len); - else if (skb_out->len < ctx->tx_max && (skb_out->len % dev->maxpacket) == 0) + skb_out->len > ctx->min_tx_pkt) { + padding_count = ctx->tx_max - skb_out->len; + memset(skb_put(skb_out, padding_count), 0, padding_count); + } else if (skb_out->len < ctx->tx_max && + (skb_out->len % dev->maxpacket) == 0) { *skb_put(skb_out, 1) = 0; /* force short packet */ + } /* set final frame length */ nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data; -- GitLab From 988ef9c8c29ccc9949a18b599df463ebd653daef Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 8 May 2017 14:21:21 -0500 Subject: [PATCH 1006/1834] net: ethernet: ti: cpsw: adjust cpsw fifos depth for fullduplex flow control [ Upstream commit 48f5bccc60675f8426a6159935e8636a1fd89f56 ] When users set flow control using ethtool the bits are set properly in the CPGMAC_SL MACCONTROL register, but the FIFO depth in the respective Port n Maximum FIFO Blocks (Pn_MAX_BLKS) registers remains set to the minimum size reset value. When receive flow control is enabled on a port, the port's associated FIFO block allocation must be adjusted. The port RX allocation must increase to accommodate the flow control runout. The TRM recommends numbers of 5 or 6. Hence, apply required Port FIFO configuration to Pn_MAX_BLKS.Pn_TX_MAX_BLKS=0xF and Pn_MAX_BLKS.Pn_RX_MAX_BLKS=0x5 during interface initialization. Cc: Schuyler Patton Signed-off-by: Grygorii Strashko Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ti/cpsw.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 2bd1282735b0..552de9c490c6 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -282,6 +282,10 @@ struct cpsw_ss_regs { /* Bit definitions for the CPSW1_TS_SEQ_LTYPE register */ #define CPSW_V1_SEQ_ID_OFS_SHIFT 16 +#define CPSW_MAX_BLKS_TX 15 +#define CPSW_MAX_BLKS_TX_SHIFT 4 +#define CPSW_MAX_BLKS_RX 5 + struct cpsw_host_regs { u32 max_blks; u32 blk_cnt; @@ -1160,11 +1164,23 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) switch (cpsw->version) { case CPSW_VERSION_1: slave_write(slave, TX_PRIORITY_MAPPING, CPSW1_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW1_MAX_BLKS); break; case CPSW_VERSION_2: case CPSW_VERSION_3: case CPSW_VERSION_4: slave_write(slave, TX_PRIORITY_MAPPING, CPSW2_TX_PRI_MAP); + /* Increase RX FIFO size to 5 for supporting fullduplex + * flow control mode + */ + slave_write(slave, + (CPSW_MAX_BLKS_TX << CPSW_MAX_BLKS_TX_SHIFT) | + CPSW_MAX_BLKS_RX, CPSW2_MAX_BLKS); break; } -- GitLab From 75d34f1c60072a8d4e9cb1905c32272f23f6dcef Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 28 Mar 2017 21:25:08 -0400 Subject: [PATCH 1007/1834] lockd: fix lockd shutdown race [ Upstream commit efda760fe95ea15291853c8fa9235c32d319cd98 ] As reported by David Jeffery: "a signal was sent to lockd while lockd was shutting down from a request to stop nfs. The signal causes lockd to call restart_grace() which puts the lockd_net structure on the grace list. If this signal is received at the wrong time, it will occur after lockd_down_net() has called locks_end_grace() but before lockd_down_net() stops the lockd thread. This leads to lockd putting the lockd_net structure back on the grace list, then exiting without anything removing it from the list." So, perform the final locks_end_grace() from the the lockd thread; this ensures it's serialized with respect to restart_grace(). Reported-by: David Jeffery Signed-off-by: J. Bruce Fields Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/lockd/svc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 9d373247222c..85135df0eb34 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -132,6 +132,8 @@ lockd(void *vrqstp) { int err = 0; struct svc_rqst *rqstp = vrqstp; + struct net *net = &init_net; + struct lockd_net *ln = net_generic(net, lockd_net_id); /* try_to_freeze() is called from svc_recv() */ set_freezable(); @@ -176,6 +178,8 @@ lockd(void *vrqstp) if (nlmsvc_ops) nlmsvc_invalidate_all(); nlm_shutdown_hosts(); + cancel_delayed_work_sync(&ln->grace_period_end); + locks_end_grace(&ln->lockd_manager); return 0; } @@ -270,8 +274,6 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) if (ln->nlmsvc_users) { if (--ln->nlmsvc_users == 0) { nlm_shutdown_hosts_net(net); - cancel_delayed_work_sync(&ln->grace_period_end); - locks_end_grace(&ln->lockd_manager); svc_shutdown_net(serv, net); dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net); } -- GitLab From a90e9ee704b291125d0dda967e14a3340567afab Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 8 May 2017 15:55:14 -0700 Subject: [PATCH 1008/1834] drivers/misc/vmw_vmci/vmci_queue_pair.c: fix a couple integer overflow tests [ Upstream commit 146180c052a00172f4dc08eaade836fd02f61fb5 ] The "DIV_ROUND_UP(size, PAGE_SIZE)" operation can overflow if "size" is more than ULLONG_MAX - PAGE_SIZE. Link: http://lkml.kernel.org/r/20170322111950.GA11279@mwanda Signed-off-by: Dan Carpenter Cc: Jorgen Hansen Cc: Masahiro Yamada Cc: Michal Hocko Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_queue_pair.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c index f84a4275ca29..f735ab4ba84e 100644 --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c @@ -298,8 +298,11 @@ static void *qp_alloc_queue(u64 size, u32 flags) size_t pas_size; size_t vas_size; size_t queue_size = sizeof(*queue) + sizeof(*queue->kernel_if); - const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1; + u64 num_pages; + if (size > SIZE_MAX - PAGE_SIZE) + return NULL; + num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1; if (num_pages > (SIZE_MAX - queue_size) / (sizeof(*queue->kernel_if->u.g.pas) + @@ -624,9 +627,12 @@ static struct vmci_queue *qp_host_alloc_queue(u64 size) { struct vmci_queue *queue; size_t queue_page_size; - const u64 num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1; + u64 num_pages; const size_t queue_size = sizeof(*queue) + sizeof(*(queue->kernel_if)); + if (size > SIZE_MAX - PAGE_SIZE) + return NULL; + num_pages = DIV_ROUND_UP(size, PAGE_SIZE) + 1; if (num_pages > (SIZE_MAX - queue_size) / sizeof(*queue->kernel_if->u.h.page)) return NULL; -- GitLab From a2095be2ad9106ad92cfb906088ffc5831f0e74c Mon Sep 17 00:00:00 2001 From: Kirill Tkhai Date: Mon, 8 May 2017 15:56:34 -0700 Subject: [PATCH 1009/1834] pidns: disable pid allocation if pid_ns_prepare_proc() is failed in alloc_pid() [ Upstream commit 8896c23d2ef803f1883fea73117a435925c2b4c4 ] alloc_pidmap() advances pid_namespace::last_pid. When first pid allocation fails, then next created process will have pid 2 and pid_ns_prepare_proc() won't be called. So, pid_namespace::proc_mnt will never be initialized (not to mention that there won't be a child reaper). I saw crash stack of such case on kernel 3.10: BUG: unable to handle kernel NULL pointer dereference at (null) IP: proc_flush_task+0x8f/0x1b0 Call Trace: release_task+0x3f/0x490 wait_consider_task.part.10+0x7ff/0xb00 do_wait+0x11f/0x280 SyS_wait4+0x7d/0x110 We may fix this by restore of last_pid in 0 or by prohibiting of futher allocations. Since there was a similar issue in Oleg Nesterov's commit 314a8ad0f18a ("pidns: fix free_pid() to handle the first fork failure"). and it was fixed via prohibiting allocation, let's follow this way, and do the same. Link: http://lkml.kernel.org/r/149201021004.4863.6762095011554287922.stgit@localhost.localdomain Signed-off-by: Kirill Tkhai Acked-by: Cyrill Gorcunov Cc: Andrei Vagin Cc: Andreas Gruenbacher Cc: Kees Cook Cc: Michael Kerrisk Cc: Al Viro Cc: Oleg Nesterov Cc: Paul Moore Cc: Eric Biederman Cc: Andy Lutomirski Cc: Ingo Molnar Cc: Serge Hallyn Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/pid.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/pid.c b/kernel/pid.c index 693a64385d59..fa704f88ff8e 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -322,8 +322,10 @@ struct pid *alloc_pid(struct pid_namespace *ns) } if (unlikely(is_child_reaper(pid))) { - if (pid_ns_prepare_proc(ns)) + if (pid_ns_prepare_proc(ns)) { + disable_pid_allocation(ns); goto out_free; + } } get_pid_ns(ns); -- GitLab From 26c18cb8ca7231b51d1c96c02db650738438266d Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 4 May 2017 09:42:22 +0200 Subject: [PATCH 1010/1834] s390: move _text symbol to address higher than zero [ Upstream commit d04a4c76f71dd5335f8e499b59617382d84e2b8d ] The perf tool assumes that kernel symbols are never present at address zero. In fact it assumes if functions that map symbols to addresses return zero, that the symbol was not found. Given that s390's _text symbol historically is located at address zero this yields at least a couple of false errors and warnings in one of perf's test cases about not present symbols ("perf test 1"). To fix this simply move the _text symbol to address 0x200, just behind the initial psw and channel program located at the beginning of the kernel image. This is now hard coded within the linker script. I tried a nicer solution which moves the initial psw and channel program into an own section. However that would move the symbols within the "real" head.text section to different addresses, since the ".org" statements within head.S are relative to the head.text section. If there is a new section in front, everything else will be moved. Alternatively I could have adjusted all ".org" statements. But this current solution seems to be the easiest one, since nobody really cares where the _text symbol is actually located. Reported-by: Zvonko Kosic Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/vmlinux.lds.S | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S index 3667d20e997f..115bda280d50 100644 --- a/arch/s390/kernel/vmlinux.lds.S +++ b/arch/s390/kernel/vmlinux.lds.S @@ -31,8 +31,14 @@ SECTIONS { . = 0x00000000; .text : { - _text = .; /* Text and read-only data */ + /* Text and read-only data */ HEAD_TEXT + /* + * E.g. perf doesn't like symbols starting at address zero, + * therefore skip the initial PSW and channel program located + * at address zero and let _text start at 0x200. + */ + _text = 0x200; TEXT_TEXT SCHED_TEXT CPUIDLE_TEXT -- GitLab From ae1b31453e6e59bc68f11ba6efb2effc3d3b6b1a Mon Sep 17 00:00:00 2001 From: Talat Batheesh Date: Tue, 9 May 2017 14:45:23 +0300 Subject: [PATCH 1011/1834] net/mlx4_en: Avoid adding steering rules with invalid ring [ Upstream commit 89c557687a32c294e9d25670a96e9287c09f2d5f ] Inserting steering rules with illegal ring is an invalid operation, block it. Fixes: 820672812f82 ('net/mlx4_en: Manage flow steering rules with ethtool') Signed-off-by: Talat Batheesh Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index bdda17d2ea0f..674246b189c2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1520,6 +1520,11 @@ static int mlx4_en_flow_replace(struct net_device *dev, qpn = priv->drop_qp.qpn; else if (cmd->fs.ring_cookie & EN_ETHTOOL_QP_ATTACH) { qpn = cmd->fs.ring_cookie & (EN_ETHTOOL_QP_ATTACH - 1); + if (qpn < priv->rss_map.base_qpn || + qpn >= priv->rss_map.base_qpn + priv->rx_ring_num) { + en_warn(priv, "rxnfc: QP (0x%x) doesn't exist\n", qpn); + return -EINVAL; + } } else { if (cmd->fs.ring_cookie >= priv->rx_ring_num) { en_warn(priv, "rxnfc: RX ring (%llu) doesn't exist\n", -- GitLab From 408719afbc61e388b1dc311d96a85e5d5e6e8f39 Mon Sep 17 00:00:00 2001 From: Ram Amrani Date: Tue, 9 May 2017 15:07:50 +0300 Subject: [PATCH 1012/1834] qed: Correct doorbell configuration for !4Kb pages [ Upstream commit a82dadbce47395747824971db08a128130786fdc ] When configuring the doorbell DPI address, driver aligns the start address to 4KB [HW-pages] instead of host PAGE_SIZE. As a result, RoCE applications might receive addresses which are unaligned to pages [when PAGE_SIZE > 4KB], which is a security risk. Fixes: 51ff17251c9c ("qed: Add support for RoCE hw init") Signed-off-by: Ram Amrani Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qed/qed_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c index 9a6adbd9ed34..d02313770fc2 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c @@ -850,7 +850,7 @@ qed_hw_init_pf_doorbell_bar(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) NULL) + qed_cxt_get_proto_cid_count(p_hwfn, PROTOCOLID_ETH, NULL); - norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, 4096); + norm_regsize = roundup(QED_PF_DEMS_SIZE * non_pwm_conn, PAGE_SIZE); min_addr_reg1 = norm_regsize / 4096; pwm_regsize = db_bar_size - norm_regsize; -- GitLab From fca22d52b70fe72d9b8f55177ccc01ea743aa76a Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 9 May 2017 15:47:15 -0400 Subject: [PATCH 1013/1834] NFSv4.1: Work around a Linux server bug... [ Upstream commit f4b23de3dda1536590787c9e5c3d16b8738ab108 ] It turns out the Linux server has a bug in its implementation of supattr_exclcreat; it returns the set of all attributes, whether or not they are supported by minor version 1. In order to avoid a regression, we therefore apply the supported_attrs as a mask on top of whatever the server sent us. Reported-by: Anna Schumaker Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/nfs4proc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index d0d2a5e980aa..1b1b616a6171 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3300,6 +3300,7 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f .rpc_resp = &res, }; int status; + int i; bitmask[0] = FATTR4_WORD0_SUPPORTED_ATTRS | FATTR4_WORD0_FH_EXPIRE_TYPE | @@ -3365,8 +3366,13 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; server->cache_consistency_bitmask[2] = 0; + + /* Avoid a regression due to buggy server */ + for (i = 0; i < ARRAY_SIZE(res.exclcreat_bitmask); i++) + res.exclcreat_bitmask[i] &= res.attr_bitmask[i]; memcpy(server->exclcreat_bitmask, res.exclcreat_bitmask, sizeof(server->exclcreat_bitmask)); + server->acl_bitmask = res.acl_bitmask; server->fh_expire_type = res.fh_expire_type; } -- GitLab From 6ed24ef46757007f3f8f0dd342bbfbb16bf92bf7 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 3 May 2017 17:17:21 +0200 Subject: [PATCH 1014/1834] CIFS: silence lockdep splat in cifs_relock_file() [ Upstream commit 560d388950ceda5e7c7cdef7f3d9a8ff297bbf9d ] cifs_relock_file() can perform a down_write() on the inode's lock_sem even though it was already performed in cifs_strict_readv(). Lockdep complains about this. AFAICS, there is no problem here, and lockdep just needs to be told that this nesting is OK. ============================================= [ INFO: possible recursive locking detected ] 4.11.0+ #20 Not tainted --------------------------------------------- cat/701 is trying to acquire lock: (&cifsi->lock_sem){++++.+}, at: cifs_reopen_file+0x7a7/0xc00 but task is already holding lock: (&cifsi->lock_sem){++++.+}, at: cifs_strict_readv+0x177/0x310 other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(&cifsi->lock_sem); lock(&cifsi->lock_sem); *** DEADLOCK *** May be due to missing lock nesting notation 1 lock held by cat/701: #0: (&cifsi->lock_sem){++++.+}, at: cifs_strict_readv+0x177/0x310 stack backtrace: CPU: 0 PID: 701 Comm: cat Not tainted 4.11.0+ #20 Call Trace: dump_stack+0x85/0xc2 __lock_acquire+0x17dd/0x2260 ? trace_hardirqs_on_thunk+0x1a/0x1c ? preempt_schedule_irq+0x6b/0x80 lock_acquire+0xcc/0x260 ? lock_acquire+0xcc/0x260 ? cifs_reopen_file+0x7a7/0xc00 down_read+0x2d/0x70 ? cifs_reopen_file+0x7a7/0xc00 cifs_reopen_file+0x7a7/0xc00 ? printk+0x43/0x4b cifs_readpage_worker+0x327/0x8a0 cifs_readpage+0x8c/0x2a0 generic_file_read_iter+0x692/0xd00 cifs_strict_readv+0x29f/0x310 generic_file_splice_read+0x11c/0x1c0 do_splice_to+0xa5/0xc0 splice_direct_to_actor+0xfa/0x350 ? generic_pipe_buf_nosteal+0x10/0x10 do_splice_direct+0xb5/0xe0 do_sendfile+0x278/0x3a0 SyS_sendfile64+0xc4/0xe0 entry_SYSCALL_64_fastpath+0x1f/0xbe Signed-off-by: Rabin Vincent Acked-by: Pavel Shilovsky Signed-off-by: Steve French Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/cifs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 02e403af9518..49eeed25f200 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -589,7 +589,7 @@ cifs_relock_file(struct cifsFileInfo *cfile) struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); int rc = 0; - down_read(&cinode->lock_sem); + down_read_nested(&cinode->lock_sem, SINGLE_DEPTH_NESTING); if (cinode->can_cache_brlcks) { /* can cache locks - no need to relock */ up_read(&cinode->lock_sem); -- GitLab From 5daab7259a6ec50415c1dcfb1a3ef3302f9281f6 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 9 May 2017 18:00:04 +0100 Subject: [PATCH 1015/1834] perf/callchain: Force USER_DS when invoking perf_callchain_user() [ Upstream commit 88b0193d9418c00340e45e0a913a0813bc6c8c96 ] Perf can generate and record a user callchain in response to a synchronous request, such as a tracepoint firing. If this happens under set_fs(KERNEL_DS), then we can end up walking the user stack (and dereferencing/saving whatever we find there) without the protections usually afforded by checks such as access_ok. Rather than play whack-a-mole with each architecture's stack unwinding implementation, fix the root of the problem by ensuring that we force USER_DS when invoking perf_callchain_user from the perf core. Reported-by: Al Viro Signed-off-by: Will Deacon Acked-by: Peter Zijlstra Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Thomas Gleixner Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/events/callchain.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c index e9fdb5203de5..411226b26bca 100644 --- a/kernel/events/callchain.c +++ b/kernel/events/callchain.c @@ -227,12 +227,18 @@ get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, } if (regs) { + mm_segment_t fs; + if (crosstask) goto exit_put; if (add_mark) perf_callchain_store_context(&ctx, PERF_CONTEXT_USER); + + fs = get_fs(); + set_fs(USER_DS); perf_callchain_user(&ctx, regs); + set_fs(fs); } } -- GitLab From 2005c4f3019a8ead93fd14aea1e8684a827b225c Mon Sep 17 00:00:00 2001 From: Wen Xiong Date: Wed, 10 May 2017 08:54:11 -0500 Subject: [PATCH 1016/1834] blk-mq: NVMe 512B/4K+T10 DIF/DIX format returns I/O error on dd with split op [ Upstream commit f36ea50ca0043e7b1204feaf1d2ba6bd68c08d36 ] When formatting NVMe to 512B/4K + T10 DIf/DIX, dd with split op returns "Input/output error". Looks block layer split the bio after calling bio_integrity_prep(bio). This patch fixes the issue. Below is how we debug this issue: (1)format nvme to 4K block # size with type 2 DIF (2)dd with block size bigger than 1024k. oflag=direct dd: error writing '/dev/nvme0n1': Input/output error We added some debug code in nvme device driver. It showed us the first op and the second op have the same bi and pi address. This is not correct. 1st op: nvme0n1 Op:Wr slba 0x505 length 0x100, PI ctrl=0x1400, dsmgmt=0x0, AT=0x0 & RT=0x505 Guard 0x00b1, AT 0x0000, RT physical 0x00000505 RT virtual 0x00002828 2nd op: nvme0n1 Op:Wr slba 0x605 length 0x1, PI ctrl=0x1400, dsmgmt=0x0, AT=0x0 & RT=0x605 ==> This op fails and subsequent 5 retires.. Guard 0x00b1, AT 0x0000, RT physical 0x00000605 RT virtual 0x00002828 With the fix, It showed us both of the first op and the second op have correct bi and pi address. 1st op: nvme2n1 Op:Wr slba 0x505 length 0x100, PI ctrl=0x1400, dsmgmt=0x0, AT=0x0 & RT=0x505 Guard 0x5ccb, AT 0x0000, RT physical 0x00000505 RT virtual 0x00002828 2nd op: nvme2n1 Op:Wr slba 0x605 length 0x1, PI ctrl=0x1400, dsmgmt=0x0, AT=0x0 & RT=0x605 Guard 0xab4c, AT 0x0000, RT physical 0x00000605 RT virtual 0x00003028 Signed-off-by: Wen Xiong Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index c6572ffc1e87..84c1efc70d3b 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1265,13 +1265,13 @@ static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) blk_queue_bounce(q, &bio); + blk_queue_split(q, &bio, q->bio_split); + if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { bio_io_error(bio); return BLK_QC_T_NONE; } - blk_queue_split(q, &bio, q->bio_split); - if (!is_flush_fua && !blk_queue_nomerges(q) && blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq)) return BLK_QC_T_NONE; -- GitLab From 485c108e820d217a9ca597841d6e5667fa8c5e05 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Tue, 9 May 2017 15:40:38 +0200 Subject: [PATCH 1017/1834] net: qca_spi: Fix alignment issues in rx path [ Upstream commit 8d66c30b12ed3cb533696dea8b9a9eadd5da426a ] The qca_spi driver causes alignment issues on ARM devices. So fix this by using netdev_alloc_skb_ip_align(). Signed-off-by: Stefan Wahren Fixes: 291ab06ecf67 ("net: qualcomm: new Ethernet over SPI driver for QCA7000") Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qualcomm/qca_spi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c index 6e2add979471..8bbb55f31909 100644 --- a/drivers/net/ethernet/qualcomm/qca_spi.c +++ b/drivers/net/ethernet/qualcomm/qca_spi.c @@ -296,8 +296,9 @@ qcaspi_receive(struct qcaspi *qca) /* Allocate rx SKB if we don't have one available. */ if (!qca->rx_skb) { - qca->rx_skb = netdev_alloc_skb(net_dev, - net_dev->mtu + VLAN_ETH_HLEN); + qca->rx_skb = netdev_alloc_skb_ip_align(net_dev, + net_dev->mtu + + VLAN_ETH_HLEN); if (!qca->rx_skb) { netdev_dbg(net_dev, "out of RX resources\n"); qca->stats.out_of_mem++; @@ -377,7 +378,7 @@ qcaspi_receive(struct qcaspi *qca) qca->rx_skb, qca->rx_skb->dev); qca->rx_skb->ip_summed = CHECKSUM_UNNECESSARY; netif_rx_ni(qca->rx_skb); - qca->rx_skb = netdev_alloc_skb(net_dev, + qca->rx_skb = netdev_alloc_skb_ip_align(net_dev, net_dev->mtu + VLAN_ETH_HLEN); if (!qca->rx_skb) { netdev_dbg(net_dev, "out of RX resources\n"); @@ -759,7 +760,8 @@ qcaspi_netdev_init(struct net_device *dev) if (!qca->rx_buffer) return -ENOBUFS; - qca->rx_skb = netdev_alloc_skb(dev, qca->net_dev->mtu + VLAN_ETH_HLEN); + qca->rx_skb = netdev_alloc_skb_ip_align(dev, qca->net_dev->mtu + + VLAN_ETH_HLEN); if (!qca->rx_skb) { kfree(qca->rx_buffer); netdev_info(qca->net_dev, "Failed to allocate RX sk_buff.\n"); -- GitLab From 014c8ea230972d327bb685d7d53cb7d7ff06b172 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 9 May 2017 17:19:42 +0100 Subject: [PATCH 1018/1834] netxen_nic: set rcode to the return status from the call to netxen_issue_cmd [ Upstream commit 0fe20fafd1791f993806d417048213ec57b81045 ] Currently rcode is being initialized to NX_RCODE_SUCCESS and later it is checked to see if it is not NX_RCODE_SUCCESS which is never true. It appears that there is an unintentional missing assignment of rcode from the return of the call to netxen_issue_cmd() that was dropped in an earlier fix, so add it in. Detected by CoverityScan, CID#401900 ("Logically dead code") Fixes: 2dcd5d95ad6b2 ("netxen_nic: fix cdrp race condition") Signed-off-by: Colin Ian King Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c index b8d5270359cd..e30676515529 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_ctx.c @@ -247,7 +247,7 @@ nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu) cmd.req.arg3 = 0; if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE) - netxen_issue_cmd(adapter, &cmd); + rcode = netxen_issue_cmd(adapter, &cmd); if (rcode != NX_RCODE_SUCCESS) return -EIO; -- GitLab From fdf3b78df4d24933df840a27e7bf836b7b6042a3 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Wed, 10 May 2017 11:20:27 -0400 Subject: [PATCH 1019/1834] mdio: mux: Correct mdio_mux_init error path issues [ Upstream commit b60161668199ac62011c024adc9e66713b9554e7 ] There is a potential unnecessary refcount decrement on error path of put_device(&pb->mii_bus->dev), as it is possible to avoid the of_mdio_find_bus() call if mux_bus is specified by the calling function. The same put_device() is not called in the error path if the devm_kzalloc of pb fails. This caused the variable used in the put_device() to be changed, as the pb pointer was obviously not set up. There is an unnecessary of_node_get() on child_bus_node if the of_mdiobus_register() is successful, as the for_each_available_child_of_node() automatically increments this. Thus the refcount on this node will always be +1 more than it should be. There is no of_node_put() on child_bus_node if the of_mdiobus_register() call fails. Finally, it is lacking devm_kfree() of pb in the error path. While this might not be technically necessary, it was present in other parts of the function. So, I am adding it where necessary to make it uniform. Signed-off-by: Jon Mason Fixes: f20e6657a875 ("mdio: mux: Enhanced MDIO mux framework for integrated multiplexers") Fixes: 0ca2997d1452 ("netdev/of/phy: Add MDIO bus multiplexer support.") Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mdio-mux.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 963838d4fac1..6943c5ece44a 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -122,10 +122,9 @@ int mdio_mux_init(struct device *dev, pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL); if (pb == NULL) { ret_val = -ENOMEM; - goto err_parent_bus; + goto err_pb_kz; } - pb->switch_data = data; pb->switch_fn = switch_fn; pb->current_child = -1; @@ -154,6 +153,7 @@ int mdio_mux_init(struct device *dev, cb->mii_bus = mdiobus_alloc(); if (!cb->mii_bus) { ret_val = -ENOMEM; + devm_kfree(dev, cb); of_node_put(child_bus_node); break; } @@ -169,8 +169,8 @@ int mdio_mux_init(struct device *dev, if (r) { mdiobus_free(cb->mii_bus); devm_kfree(dev, cb); + of_node_put(child_bus_node); } else { - of_node_get(child_bus_node); cb->next = pb->children; pb->children = cb; } @@ -181,9 +181,11 @@ int mdio_mux_init(struct device *dev, return 0; } + devm_kfree(dev, pb); +err_pb_kz: /* balance the reference of_mdio_find_bus() took */ - put_device(&pb->mii_bus->dev); - + if (!mux_bus) + put_device(&parent_bus->dev); err_parent_bus: of_node_put(parent_bus_node); return ret_val; -- GitLab From 97e885c7d1c806ec9d602644cb9c6eee094b25a1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 19 Dec 2014 12:57:49 -0800 Subject: [PATCH 1020/1834] Input: elan_i2c - check if device is there before really probing [ Upstream commit c5928551fd41b2eecdad78fa2be2a4a13ed5fde9 ] Before trying to properly initialize the touchpad and generate bunch of errors, let's first see it there is anything at the given address. If we get error, fail silently with -ENXIO. Reviewed-by: Guenter Roeck Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elan_i2c_core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index c9d491bc85e0..3851d5715772 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1082,6 +1082,13 @@ static int elan_probe(struct i2c_client *client, return error; } + /* Make sure there is something at this address */ + error = i2c_smbus_read_byte(client); + if (error < 0) { + dev_dbg(&client->dev, "nothing at this address: %d\n", error); + return -ENXIO; + } + /* Initialize the touchpad. */ error = elan_initialize(data); if (error) -- GitLab From e0709814a17f0eeed84fa593f7a3057aa38cba56 Mon Sep 17 00:00:00 2001 From: KT Liao Date: Mon, 12 Dec 2016 11:03:42 -0800 Subject: [PATCH 1021/1834] Input: elantech - force relative mode on a certain module [ Upstream commit d899520b0431e70279bfb5066ecb6dc91d0b7072 ] One of Elan modules with sample version is 0x74 and hw_version is 0x03 has a bug in absolute mode implementation, so let it run in default PS/2 relative mode. Signed-off-by: KT Liao Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elantech.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 59603a5728f7..c519c0b09568 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1711,6 +1711,17 @@ int elantech_init(struct psmouse *psmouse) etd->samples[0], etd->samples[1], etd->samples[2]); } + if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) { + /* + * This module has a bug which makes absolute mode + * unusable, so let's abort so we'll be using standard + * PS/2 protocol. + */ + psmouse_info(psmouse, + "absolute mode broken, forcing standard PS/2 protocol\n"); + goto init_fail; + } + if (elantech_set_absolute_mode(psmouse)) { psmouse_err(psmouse, "failed to put touchpad into absolute mode.\n"); -- GitLab From a41dbfe8fd0282840a56274e71a0b3dc96c5bc17 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 11 May 2017 11:33:30 +1000 Subject: [PATCH 1022/1834] KVM: PPC: Book3S PR: Check copy_to/from_user return values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 67325e988faea735d663799b6d152b5f4254093c ] The PR KVM implementation of the PAPR HPT hypercalls (H_ENTER etc.) access an image of the HPT in userspace memory using copy_from_user and copy_to_user. Recently, the declarations of those functions were annotated to indicate that the return value must be checked. Since this code doesn't currently check the return value, this causes compile warnings like the ones shown below, and since on PPC the default is to compile arch/powerpc with -Werror, this causes the build to fail. To fix this, we check the return values, and if non-zero, fail the hypercall being processed with a H_FUNCTION error return value. There is really no good error return value to use since PAPR didn't envisage the possibility that the hypervisor may not be able to access the guest's HPT, and H_FUNCTION (function not supported) seems as good as any. The typical compile warnings look like this: CC arch/powerpc/kvm/book3s_pr_papr.o /home/paulus/kernel/kvm/arch/powerpc/kvm/book3s_pr_papr.c: In function ‘kvmppc_h_pr_enter’: /home/paulus/kernel/kvm/arch/powerpc/kvm/book3s_pr_papr.c:53:2: error: ignoring return value of ‘copy_from_user’, declared with attribute warn_unused_result [-Werror=unused-result] copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)); ^ /home/paulus/kernel/kvm/arch/powerpc/kvm/book3s_pr_papr.c:74:2: error: ignoring return value of ‘copy_to_user’, declared with attribute warn_unused_result [-Werror=unused-result] copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE); ^ ... etc. Signed-off-by: Paul Mackerras Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kvm/book3s_pr_papr.c | 34 +++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c index 02176fd52f84..286a3b051ff6 100644 --- a/arch/powerpc/kvm/book3s_pr_papr.c +++ b/arch/powerpc/kvm/book3s_pr_papr.c @@ -50,7 +50,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) pteg_addr = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); - copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg)); + ret = H_FUNCTION; + if (copy_from_user(pteg, (void __user *)pteg_addr, sizeof(pteg))) + goto done; hpte = pteg; ret = H_PTEG_FULL; @@ -71,7 +73,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu) hpte[0] = cpu_to_be64(kvmppc_get_gpr(vcpu, 6)); hpte[1] = cpu_to_be64(kvmppc_get_gpr(vcpu, 7)); pteg_addr += i * HPTE_SIZE; - copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE); + ret = H_FUNCTION; + if (copy_to_user((void __user *)pteg_addr, hpte, HPTE_SIZE)) + goto done; kvmppc_set_gpr(vcpu, 4, pte_index | i); ret = H_SUCCESS; @@ -93,7 +97,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); - copy_from_user(pte, (void __user *)pteg, sizeof(pte)); + ret = H_FUNCTION; + if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) + goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); @@ -103,7 +109,9 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu) ((flags & H_ANDCOND) && (pte[0] & avpn) != 0)) goto done; - copy_to_user((void __user *)pteg, &v, sizeof(v)); + ret = H_FUNCTION; + if (copy_to_user((void __user *)pteg, &v, sizeof(v))) + goto done; rb = compute_tlbie_rb(pte[0], pte[1], pte_index); vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); @@ -171,7 +179,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) } pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX); - copy_from_user(pte, (void __user *)pteg, sizeof(pte)); + if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) { + ret = H_FUNCTION; + break; + } pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); @@ -184,7 +195,10 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu) tsh |= H_BULK_REMOVE_NOT_FOUND; } else { /* Splat the pteg in (userland) hpt */ - copy_to_user((void __user *)pteg, &v, sizeof(v)); + if (copy_to_user((void __user *)pteg, &v, sizeof(v))) { + ret = H_FUNCTION; + break; + } rb = compute_tlbie_rb(pte[0], pte[1], tsh & H_BULK_REMOVE_PTEX); @@ -211,7 +225,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) pteg = get_pteg_addr(vcpu, pte_index); mutex_lock(&vcpu->kvm->arch.hpt_mutex); - copy_from_user(pte, (void __user *)pteg, sizeof(pte)); + ret = H_FUNCTION; + if (copy_from_user(pte, (void __user *)pteg, sizeof(pte))) + goto done; pte[0] = be64_to_cpu((__force __be64)pte[0]); pte[1] = be64_to_cpu((__force __be64)pte[1]); @@ -234,7 +250,9 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu) vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false); pte[0] = (__force u64)cpu_to_be64(pte[0]); pte[1] = (__force u64)cpu_to_be64(pte[1]); - copy_to_user((void __user *)pteg, pte, sizeof(pte)); + ret = H_FUNCTION; + if (copy_to_user((void __user *)pteg, pte, sizeof(pte))) + goto done; ret = H_SUCCESS; done: -- GitLab From 3a743c429f47a204a7b3bb0972daa4ad960c9088 Mon Sep 17 00:00:00 2001 From: MaJun Date: Fri, 12 May 2017 11:55:28 +0800 Subject: [PATCH 1023/1834] irqchip/mbigen: Fix the clear register offset calculation [ Upstream commit 9459a04b6a5a09967eec94a1b66f0a74312819d9 ] The register array offset for clearing an interrupt is calculated by: offset = (hwirq - RESERVED_IRQ_PER_MBIGEN_CHIP) / 32; This is wrong because the clear register array includes the reserved interrupts. So the clear operation ends up in the wrong register. This went unnoticed so far, because the hardware clears the real bit through a timeout mechanism when the hardware is configured in debug mode. That debug mode was enabled on early generations of the hardware, so the problem was papered over. On newer hardware with updated firmware the debug mode was disabled, so the bits did not get cleared which causes the system to malfunction. Remove the subtraction of RESERVED_IRQ_PER_MBIGEN_CHIP, so the correct register is accessed. [ tglx: Rewrote changelog ] Fixes: a6c2f87b8820 ("irqchip/mbigen: Implement the mbigen irq chip operation functions") Signed-off-by: MaJun Signed-off-by: Hanjun Guo Acked-by: Marc Zyngier Cc: Kefeng Wang Cc: linuxarm@huawei.com Cc: Wei Yongjun Link: http://lkml.kernel.org/r/1494561328-39514-4-git-send-email-guohanjun@huawei.com Signed-off-by: Thomas Gleixner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-mbigen.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c index 03b79b061d24..05d87f60d929 100644 --- a/drivers/irqchip/irq-mbigen.c +++ b/drivers/irqchip/irq-mbigen.c @@ -105,10 +105,7 @@ static inline void get_mbigen_type_reg(irq_hw_number_t hwirq, static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq, u32 *mask, u32 *addr) { - unsigned int ofst; - - hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP; - ofst = hwirq / 32 * 4; + unsigned int ofst = (hwirq / 32) * 4; *mask = 1 << (hwirq % 32); *addr = ofst + REG_MBIGEN_CLEAR_OFFSET; -- GitLab From 00b475072e4942036b1992fc0c9ab39cd84d1c9e Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 12 May 2017 12:00:01 -0400 Subject: [PATCH 1024/1834] vmxnet3: ensure that adapter is in proper state during force_close [ Upstream commit 1c4d5f51a812a82de97beee24f48ed05c65ebda5 ] There are several paths in vmxnet3, where settings changes cause the adapter to be brought down and back up (vmxnet3_set_ringparam among them). Should part of the reset operation fail, these paths call vmxnet3_force_close, which enables all napi instances prior to calling dev_close (with the expectation that vmxnet3_close will then properly disable them again). However, vmxnet3_force_close neglects to clear VMXNET3_STATE_BIT_QUIESCED prior to calling dev_close. As a result vmxnet3_quiesce_dev (called from vmxnet3_close), returns early, and leaves all the napi instances in a enabled state while the device itself is closed. If a device in this state is activated again, napi_enable will be called on already enabled napi_instances, leading to a BUG halt. The fix is to simply enausre that the QUIESCED bit is cleared in vmxnet3_force_close to allow quesence to be completed properly on close. Signed-off-by: Neil Horman CC: Shrikrishna Khare CC: "VMware, Inc." CC: "David S. Miller" Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/vmxnet3/vmxnet3_drv.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 4afba17e2403..f809eed0343c 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2962,6 +2962,11 @@ vmxnet3_force_close(struct vmxnet3_adapter *adapter) /* we need to enable NAPI, otherwise dev_close will deadlock */ for (i = 0; i < adapter->num_rx_queues; i++) napi_enable(&adapter->rx_queue[i].napi); + /* + * Need to clear the quiesce bit to ensure that vmxnet3_close + * can quiesce the device properly + */ + clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state); dev_close(adapter->netdev); } -- GitLab From 91d64606bb456f801b4d677c9dc20a15f5ce1c63 Mon Sep 17 00:00:00 2001 From: Reza Arbab Date: Fri, 12 May 2017 15:46:32 -0700 Subject: [PATCH 1025/1834] mm, vmstat: Remove spurious WARN() during zoneinfo print [ Upstream commit 8d35bb310698c69d73073b26fc581f2e3f7f621d ] After commit e2ecc8a79ed4 ("mm, vmstat: print non-populated zones in zoneinfo"), /proc/zoneinfo will show unpopulated zones. A memoryless node, having no populated zones at all, was previously ignored, but will now trigger the WARN() in is_zone_first_populated(). Remove this warning, as its only purpose was to warn of a situation that has since been enabled. Aside: The "per-node stats" are still printed under the first populated zone, but that's not necessarily the first stanza any more. I'm not sure which criteria is more important with regard to not breaking parsers, but it looks a little weird to the eye. Fixes: e2ecc8a79ed4 ("mm, vmstat: print node-based stats in zoneinfo file") Link: http://lkml.kernel.org/r/1493854905-10918-1-git-send-email-arbab@linux.vnet.ibm.com Signed-off-by: Reza Arbab Cc: David Rientjes Cc: Anshuman Khandual Cc: Vlastimil Babka Cc: Mel Gorman Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- mm/vmstat.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mm/vmstat.c b/mm/vmstat.c index 68b3193e4493..5f658b6a684f 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1351,8 +1351,6 @@ static bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone) return zone == compare; } - /* The zone must be somewhere! */ - WARN_ON_ONCE(1); return false; } -- GitLab From cfea563e71b021ac4d64b422688e821dd52fbd60 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 12 May 2017 17:59:32 +0200 Subject: [PATCH 1026/1834] SMB2: Fix share type handling [ Upstream commit cd1230070ae1c12fd34cf6a557bfa81bf9311009 ] In fs/cifs/smb2pdu.h, we have: #define SMB2_SHARE_TYPE_DISK 0x01 #define SMB2_SHARE_TYPE_PIPE 0x02 #define SMB2_SHARE_TYPE_PRINT 0x03 Knowing that, with the current code, the SMB2_SHARE_TYPE_PRINT case can never trigger and printer share would be interpreted as disk share. So, test the ShareType value for equality instead. Fixes: faaf946a7d5b ("CIFS: Add tree connect/disconnect capability for SMB2") Signed-off-by: Christophe JAILLET Acked-by: Aurelien Aptel Signed-off-by: Steve French Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/cifs/smb2pdu.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 7c26286a525d..44b7ccbe4b08 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -1151,15 +1151,19 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, goto tcon_exit; } - if (rsp->ShareType & SMB2_SHARE_TYPE_DISK) + switch (rsp->ShareType) { + case SMB2_SHARE_TYPE_DISK: cifs_dbg(FYI, "connection to disk share\n"); - else if (rsp->ShareType & SMB2_SHARE_TYPE_PIPE) { + break; + case SMB2_SHARE_TYPE_PIPE: tcon->ipc = true; cifs_dbg(FYI, "connection to pipe share\n"); - } else if (rsp->ShareType & SMB2_SHARE_TYPE_PRINT) { - tcon->print = true; + break; + case SMB2_SHARE_TYPE_PRINT: + tcon->ipc = true; cifs_dbg(FYI, "connection to printer\n"); - } else { + break; + default: cifs_dbg(VFS, "unknown share type %d\n", rsp->ShareType); rc = -EOPNOTSUPP; goto tcon_error_exit; -- GitLab From 95fbdbb60501bbc2bf5ae8d0736199714925ccd1 Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Wed, 29 Mar 2017 17:29:09 -0700 Subject: [PATCH 1027/1834] bus: brcmstb_gisb: Use register offsets with writes too [ Upstream commit 856c7ccb9ce7a061f04bdf586f649cb93654e294 ] This commit corrects the bug introduced in commit f80835875d3d ("bus: brcmstb_gisb: Look up register offsets in a table") such that gisb_write() translates the register enumeration into an offset from the base address for writes as well as reads. Fixes: f80835875d3d ("bus: brcmstb_gisb: Look up register offsets in a table") Signed-off-by: Doug Berger Acked-by: Gregory Fong Signed-off-by: Florian Fainelli Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bus/brcmstb_gisb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index 72fe0a5a8bf3..a94598d0945a 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Broadcom Corporation + * Copyright (C) 2014-2017 Broadcom * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -127,9 +127,9 @@ static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg) return; if (gdev->big_endian) - iowrite32be(val, gdev->base + reg); + iowrite32be(val, gdev->base + offset); else - iowrite32(val, gdev->base + reg); + iowrite32(val, gdev->base + offset); } static ssize_t gisb_arb_get_timeout(struct device *dev, -- GitLab From 69df2501c0902550d45f0b762788df7b9ab89bf6 Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Wed, 29 Mar 2017 17:29:10 -0700 Subject: [PATCH 1028/1834] bus: brcmstb_gisb: correct support for 64-bit address output [ Upstream commit 0c2aa0e4b308815e877601845c1a89913f9bd2b9 ] The GISB bus can support addresses beyond 32-bits. So this commit corrects support for reading a captured 64-bit address into a 64-bit variable by obtaining the high bits from the ARB_ERR_CAP_HI_ADDR register (when present) and then outputting the full 64-bit value. It also removes unused definitions. Fixes: 44127b771d9c ("bus: add Broadcom GISB bus arbiter timeout/error handler") Signed-off-by: Doug Berger Acked-by: Gregory Fong Signed-off-by: Florian Fainelli Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/bus/brcmstb_gisb.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index a94598d0945a..017c37b9c7c1 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -37,8 +37,6 @@ #define ARB_ERR_CAP_CLEAR (1 << 0) #define ARB_ERR_CAP_STATUS_TIMEOUT (1 << 12) #define ARB_ERR_CAP_STATUS_TEA (1 << 11) -#define ARB_ERR_CAP_STATUS_BS_SHIFT (1 << 2) -#define ARB_ERR_CAP_STATUS_BS_MASK 0x3c #define ARB_ERR_CAP_STATUS_WRITE (1 << 1) #define ARB_ERR_CAP_STATUS_VALID (1 << 0) @@ -47,7 +45,6 @@ enum { ARB_ERR_CAP_CLR, ARB_ERR_CAP_HI_ADDR, ARB_ERR_CAP_ADDR, - ARB_ERR_CAP_DATA, ARB_ERR_CAP_STATUS, ARB_ERR_CAP_MASTER, }; @@ -57,7 +54,6 @@ static const int gisb_offsets_bcm7038[] = { [ARB_ERR_CAP_CLR] = 0x0c4, [ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_ADDR] = 0x0c8, - [ARB_ERR_CAP_DATA] = 0x0cc, [ARB_ERR_CAP_STATUS] = 0x0d0, [ARB_ERR_CAP_MASTER] = -1, }; @@ -67,7 +63,6 @@ static const int gisb_offsets_bcm7400[] = { [ARB_ERR_CAP_CLR] = 0x0c8, [ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_ADDR] = 0x0cc, - [ARB_ERR_CAP_DATA] = 0x0d0, [ARB_ERR_CAP_STATUS] = 0x0d4, [ARB_ERR_CAP_MASTER] = 0x0d8, }; @@ -77,7 +72,6 @@ static const int gisb_offsets_bcm7435[] = { [ARB_ERR_CAP_CLR] = 0x168, [ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_ADDR] = 0x16c, - [ARB_ERR_CAP_DATA] = 0x170, [ARB_ERR_CAP_STATUS] = 0x174, [ARB_ERR_CAP_MASTER] = 0x178, }; @@ -87,7 +81,6 @@ static const int gisb_offsets_bcm7445[] = { [ARB_ERR_CAP_CLR] = 0x7e4, [ARB_ERR_CAP_HI_ADDR] = 0x7e8, [ARB_ERR_CAP_ADDR] = 0x7ec, - [ARB_ERR_CAP_DATA] = 0x7f0, [ARB_ERR_CAP_STATUS] = 0x7f4, [ARB_ERR_CAP_MASTER] = 0x7f8, }; @@ -109,9 +102,13 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg) { int offset = gdev->gisb_offsets[reg]; - /* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */ - if (offset == -1) - return 1; + if (offset < 0) { + /* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */ + if (reg == ARB_ERR_CAP_MASTER) + return 1; + else + return 0; + } if (gdev->big_endian) return ioread32be(gdev->base + offset); @@ -119,6 +116,16 @@ static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg) return ioread32(gdev->base + offset); } +static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev) +{ + u64 value; + + value = gisb_read(gdev, ARB_ERR_CAP_ADDR); + value |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32; + + return value; +} + static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg) { int offset = gdev->gisb_offsets[reg]; @@ -185,7 +192,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev, const char *reason) { u32 cap_status; - unsigned long arb_addr; + u64 arb_addr; u32 master; const char *m_name; char m_fmt[11]; @@ -197,10 +204,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev, return 1; /* Read the address and master */ - arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff; -#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT)) - arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32; -#endif + arb_addr = gisb_read_address(gdev); master = gisb_read(gdev, ARB_ERR_CAP_MASTER); m_name = brcmstb_gisb_master_to_str(gdev, master); @@ -209,7 +213,7 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev, m_name = m_fmt; } - pr_crit("%s: %s at 0x%lx [%c %s], core: %s\n", + pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n", __func__, reason, arb_addr, cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R', cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "", -- GitLab From d6701d258d3c916aca4515c9d32dc7340b0e22b4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 10 May 2017 22:40:06 +0300 Subject: [PATCH 1029/1834] PowerCap: Fix an error code in powercap_register_zone() [ Upstream commit 216c4e9db4c9d1d2a382b42880442dc632cd47d9 ] In the current code we accidentally return the successful result from idr_alloc() instead of a negative error pointer. The caller is looking for an error pointer and so it treats the returned value as a valid pointer. This one might be a bit serious because if it lets people get around the kernel's protection for remapping NULL. I'm not sure. Fixes: 75d2364ea0ca (PowerCap: Add class driver) Signed-off-by: Dan Carpenter Reviewed-by: Srinivas Pandruvada Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/powercap/powercap_sys.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c index 14bde0db8c24..5b10b50f8686 100644 --- a/drivers/powercap/powercap_sys.c +++ b/drivers/powercap/powercap_sys.c @@ -538,6 +538,7 @@ struct powercap_zone *powercap_register_zone( power_zone->id = result; idr_init(&power_zone->idr); + result = -ENOMEM; power_zone->name = kstrdup(name, GFP_KERNEL); if (!power_zone->name) goto err_name_alloc; -- GitLab From c5eb48c6331d8773d707facbb8950f8fd7ef1682 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 14 May 2017 10:43:55 +0200 Subject: [PATCH 1030/1834] iio: pressure: zpa2326: report interrupted case as failure [ Upstream commit e7215fe4d51e69c9d2608ad0c409d48e844d0adc ] If the timeout-case prints a warning message then probably the interrupted case should also. Further, wait_for_completion_interruptible_timeout() returns long not int. Fixes: commit 03b262f2bbf4 ("iio:pressure: initial zpa2326 barometer support") Signed-off-by: Nicholas Mc Guire Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iio/pressure/zpa2326.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 19d2eb46fda6..2a4a62ebfd8d 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -871,12 +871,13 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, { int ret; unsigned int val; + long timeout; zpa2326_dbg(indio_dev, "waiting for one shot completion interrupt"); - ret = wait_for_completion_interruptible_timeout( + timeout = wait_for_completion_interruptible_timeout( &private->data_ready, ZPA2326_CONVERSION_JIFFIES); - if (ret > 0) + if (timeout > 0) /* * Interrupt handler completed before timeout: return operation * status. @@ -886,13 +887,16 @@ static int zpa2326_wait_oneshot_completion(const struct iio_dev *indio_dev, /* Clear all interrupts just to be sure. */ regmap_read(private->regmap, ZPA2326_INT_SOURCE_REG, &val); - if (!ret) + if (!timeout) { /* Timed out. */ + zpa2326_warn(indio_dev, "no one shot interrupt occurred (%ld)", + timeout); ret = -ETIME; - - if (ret != -ERESTARTSYS) - zpa2326_warn(indio_dev, "no one shot interrupt occurred (%d)", - ret); + } else if (timeout < 0) { + zpa2326_warn(indio_dev, + "wait for one shot interrupt cancelled"); + ret = -ERESTARTSYS; + } return ret; } -- GitLab From 8587ce2174002aaa0eea09b23fa99b30cd11677e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 12 Apr 2017 18:31:18 -0300 Subject: [PATCH 1031/1834] ARM: dts: imx53-qsrb: Pulldown PMIC IRQ pin [ Upstream commit 2fe4bff3516924a37e083e3211364abe59db1161 ] Currently the following errors are seen: [ 14.015056] mc13xxx 0-0008: Failed to read IRQ status: -6 [ 27.321093] mc13xxx 0-0008: Failed to read IRQ status: -6 [ 27.411681] mc13xxx 0-0008: Failed to read IRQ status: -6 [ 27.456281] mc13xxx 0-0008: Failed to read IRQ status: -6 [ 30.527106] mc13xxx 0-0008: Failed to read IRQ status: -6 [ 36.596900] mc13xxx 0-0008: Failed to read IRQ status: -6 Also when reading the interrupts via 'cat /proc/interrupts' the PMIC GPIO interrupt counter does not stop increasing. The reason for the storm of interrupts is that the PUS field of register IOMUXC_SW_PAD_CTL_PAD_CSI0_DAT5 is currently configured as: 10 : 100k pullup and the PMIC interrupt is being registered as IRQ_TYPE_LEVEL_HIGH type, which is the correct type as per the MC34708 datasheet. Use the default power on value for the IOMUX, which sets PUS field as: 00: 360k pull down This prevents the spurious PMIC interrupts from happening. Commit e1ffceb078c6 ("ARM: imx53: qsrb: fix PMIC interrupt level") correctly described the irq type as IRQ_TYPE_LEVEL_HIGH, but missed to update the IOMUX of the PMIC GPIO as pull down. Fixes: e1ffceb078c6 ("ARM: imx53: qsrb: fix PMIC interrupt level") Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx53-qsrb.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/imx53-qsrb.dts b/arch/arm/boot/dts/imx53-qsrb.dts index 96d7eede412e..036c9bd9bf75 100644 --- a/arch/arm/boot/dts/imx53-qsrb.dts +++ b/arch/arm/boot/dts/imx53-qsrb.dts @@ -23,7 +23,7 @@ imx53-qsrb { pinctrl_pmic: pmicgrp { fsl,pins = < - MX53_PAD_CSI0_DAT5__GPIO5_23 0x1e4 /* IRQ */ + MX53_PAD_CSI0_DAT5__GPIO5_23 0x1c4 /* IRQ */ >; }; }; -- GitLab From c019b6ef720f2fbc612969e817090be9f1b8865a Mon Sep 17 00:00:00 2001 From: Andrea della Porta Date: Sat, 29 Apr 2017 07:30:23 +0100 Subject: [PATCH 1032/1834] staging: wlan-ng: prism2mgmt.c: fixed a double endian conversion before calling hfa384x_drvr_setconfig16, also fixes relative sparse warning [ Upstream commit dea20579a69ab68cdca6adf79bb7c0c162eb9b72 ] staging: wlan-ng: prism2mgmt.c: This patches fixes a double endian conversion. cpu_to_le16() was called twice first in prism2mgmt_scan and again inside hfa384x_drvr_setconfig16() for the same variable, hence it was swapped twice. Incidentally, it also fixed the following sparse warning: drivers/staging/wlan-ng/prism2mgmt.c:173:30: warning: incorrect type in assignment (different base types) drivers/staging/wlan-ng/prism2mgmt.c:173:30: expected unsigned short [unsigned] [usertype] word drivers/staging/wlan-ng/prism2mgmt.c:173:30: got restricted __le16 [usertype] Unfortunately, only compile tested. Signed-off-by: Andrea della Porta Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/prism2mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wlan-ng/prism2mgmt.c b/drivers/staging/wlan-ng/prism2mgmt.c index 170de1c9eac4..f815f9d5045f 100644 --- a/drivers/staging/wlan-ng/prism2mgmt.c +++ b/drivers/staging/wlan-ng/prism2mgmt.c @@ -169,7 +169,7 @@ int prism2mgmt_scan(struct wlandevice *wlandev, void *msgp) hw->ident_sta_fw.variant) > HFA384x_FIRMWARE_VERSION(1, 5, 0)) { if (msg->scantype.data != P80211ENUM_scantype_active) - word = cpu_to_le16(msg->maxchanneltime.data); + word = msg->maxchanneltime.data; else word = 0; -- GitLab From 0babe22bda12dee55de6a3ba306cdb925db12923 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 29 Mar 2017 17:22:44 +0200 Subject: [PATCH 1033/1834] clk: renesas: rcar-gen2: Fix PLL0 on R-Car V2H and E2 [ Upstream commit b7c563c489e94417efbad68d057ea5d2030ae44c ] R-Car V2H and E2 do not have the PLL0CR register, but use a fixed multiplier (depending on mode pins) and divider. This corrects the clock rate of "pll0" (PLL0 VCO after post divider) on R-Car V2H and E2 from 1.5 GHz to 1 GHz. Inspired by Sergei Shtylyov's work for the common R-Car Gen2 and RZ/G Clock Pulse Generator support core. Fixes: 7c4163aae3d8e5b9 ("ARM: dts: r8a7792: initial SoC device tree") Fixes: 0dce5454d5c25858 ("ARM: shmobile: Initial r8a7794 SoC device tree") Signed-off-by: Geert Uytterhoeven Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/renesas/clk-rcar-gen2.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c index 00e6aba4b9c0..c55d5fe116d6 100644 --- a/drivers/clk/renesas/clk-rcar-gen2.c +++ b/drivers/clk/renesas/clk-rcar-gen2.c @@ -271,11 +271,14 @@ struct cpg_pll_config { unsigned int extal_div; unsigned int pll1_mult; unsigned int pll3_mult; + unsigned int pll0_mult; /* For R-Car V2H and E2 only */ }; static const struct cpg_pll_config cpg_pll_configs[8] __initconst = { - { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 }, - { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 }, + { 1, 208, 106, 200 }, { 1, 208, 88, 200 }, + { 1, 156, 80, 150 }, { 1, 156, 66, 150 }, + { 2, 240, 122, 230 }, { 2, 240, 102, 230 }, + { 2, 208, 106, 200 }, { 2, 208, 88, 200 }, }; /* SDHI divisors */ @@ -297,6 +300,12 @@ static const struct clk_div_table cpg_sd01_div_table[] = { static u32 cpg_mode __initdata; +static const char * const pll0_mult_match[] = { + "renesas,r8a7792-cpg-clocks", + "renesas,r8a7794-cpg-clocks", + NULL +}; + static struct clk * __init rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, const struct cpg_pll_config *config, @@ -317,9 +326,15 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, * clock implementation and we currently have no need to change * the multiplier value. */ - u32 value = clk_readl(cpg->reg + CPG_PLL0CR); + if (of_device_compatible_match(np, pll0_mult_match)) { + /* R-Car V2H and E2 do not have PLL0CR */ + mult = config->pll0_mult; + div = 3; + } else { + u32 value = clk_readl(cpg->reg + CPG_PLL0CR); + mult = ((value >> 24) & ((1 << 7) - 1)) + 1; + } parent_name = "main"; - mult = ((value >> 24) & ((1 << 7) - 1)) + 1; } else if (!strcmp(name, "pll1")) { parent_name = "main"; mult = config->pll1_mult / 2; -- GitLab From c4f8fbce84e2a0c6df3bfafc7bae7be59846c4b8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 13 Apr 2017 14:56:44 +0200 Subject: [PATCH 1034/1834] x86/tsc: Provide 'tsc=unstable' boot parameter [ Upstream commit 8309f86cd41e8714526867177facf7a316d9be53 ] Since the clocksource watchdog will only detect broken TSC after the fact, all TSC based clocks will likely have observed non-continuous values before/when switching away from TSC. Therefore only thing to fully avoid random clock movement when your BIOS randomly mucks with TSC values from SMI handlers is reporting the TSC as unstable at boot. Signed-off-by: Peter Zijlstra (Intel) Cc: Linus Torvalds Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kernel/tsc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index d07a9390023e..bbfb03eccb7f 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -366,6 +366,8 @@ static int __init tsc_setup(char *str) tsc_clocksource_reliable = 1; if (!strncmp(str, "noirqtime", 9)) no_sched_irq_time = 1; + if (!strcmp(str, "unstable")) + mark_tsc_unstable("boot parameter"); return 1; } -- GitLab From 6bdfab8084fb18e00ee5ea4681e312518d6f5d1a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 10 May 2017 16:57:49 +1000 Subject: [PATCH 1035/1834] powerpc/modules: If mprofile-kernel is enabled add it to vermagic [ Upstream commit 43e24e82f35291d4c1ca78877ce1b20d3aeb78f1 ] On powerpc we can build the kernel with two different ABIs for mcount(), which is used by ftrace. Kernels built with one ABI do not know how to load modules built with the other ABI. The new style ABI is called "mprofile-kernel", for want of a better name. Currently if we build a module using the old style ABI, and the kernel with mprofile-kernel, when we load the module we'll oops something like: # insmod autofs4-no-mprofile-kernel.ko ftrace-powerpc: Unexpected instruction f8810028 around bl _mcount ------------[ cut here ]------------ WARNING: CPU: 6 PID: 3759 at ../kernel/trace/ftrace.c:2024 ftrace_bug+0x2b8/0x3c0 CPU: 6 PID: 3759 Comm: insmod Not tainted 4.11.0-rc3-gcc-5.4.1-00017-g5a61ef74f269 #11 ... NIP [c0000000001eaa48] ftrace_bug+0x2b8/0x3c0 LR [c0000000001eaff8] ftrace_process_locs+0x4a8/0x590 Call Trace: alloc_pages_current+0xc4/0x1d0 (unreliable) ftrace_process_locs+0x4a8/0x590 load_module+0x1c8c/0x28f0 SyS_finit_module+0x110/0x140 system_call+0x38/0xfc ... ftrace failed to modify [] 0xd000000002a31024 actual: 35:65:00:48 We can avoid this by including in the vermagic whether the kernel/module was built with mprofile-kernel. Which results in: # insmod autofs4-pg.ko autofs4: version magic '4.11.0-rc3-gcc-5.4.1-00017-g5a61ef74f269 SMP mod_unload modversions ' should be '4.11.0-rc3-gcc-5.4.1-00017-g5a61ef74f269-dirty SMP mod_unload modversions mprofile-kernel' insmod: ERROR: could not insert module autofs4-pg.ko: Invalid module format Fixes: 8c50b72a3b4f ("powerpc/ftrace: Add Kconfig & Make glue for mprofile-kernel") Signed-off-by: Michael Ellerman Acked-by: Balbir Singh Acked-by: Jessica Yu Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/module.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index cd4ffd86765f..bb9073a2b2ae 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h @@ -14,6 +14,10 @@ #include +#ifdef CC_USING_MPROFILE_KERNEL +#define MODULE_ARCH_VERMAGIC "mprofile-kernel" +#endif + #ifndef __powerpc64__ /* * Thanks to Paul M for explaining this. -- GitLab From c53c4ad96242e868da492f424535bf4b45f80503 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 14 May 2017 11:50:50 -0300 Subject: [PATCH 1036/1834] ARM: dts: imx6qdl-wandboard: Fix audio channel swap [ Upstream commit 79935915300c5eb88a0e94fa9148a7505c14a02a ] When running a stress playback/stop loop test on a mx6wandboard channel swaps can be noticed randomly. Increasing the SGTL5000 LRCLK pad strength to its maximum value fixes the issue, so add the 'lrclk-strength' property to avoid the audio channel swaps. Signed-off-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi index 2b9c2be436f9..47c955458a77 100644 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi @@ -88,6 +88,7 @@ clocks = <&clks IMX6QDL_CLK_CKO>; VDDA-supply = <®_2p5v>; VDDIO-supply = <®_3p3v>; + lrclk-strength = <3>; }; }; -- GitLab From 3743e05f5d4084d0d08a1490118a4996080def87 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Sun, 7 May 2017 07:16:30 +0200 Subject: [PATCH 1037/1834] i2c: mux: reg: put away the parent i2c adapter on probe failure [ Upstream commit 68118e0e73aa3a6291c8b9eb1ee708e05f110cea ] It is only prudent to let go of resources that are not used. Fixes: b3fdd32799d8 ("i2c: mux: Add register-based mux i2c-mux-reg") Signed-off-by: Peter Rosin Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/i2c/muxes/i2c-mux-reg.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index c6a90b4a9c62..91b10afc8c34 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -196,20 +196,25 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mux->data.reg_size = resource_size(res); mux->data.reg = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mux->data.reg)) - return PTR_ERR(mux->data.reg); + if (IS_ERR(mux->data.reg)) { + ret = PTR_ERR(mux->data.reg); + goto err_put_parent; + } } if (mux->data.reg_size != 4 && mux->data.reg_size != 2 && mux->data.reg_size != 1) { dev_err(&pdev->dev, "Invalid register size\n"); - return -EINVAL; + ret = -EINVAL; + goto err_put_parent; } muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0, i2c_mux_reg_select, NULL); - if (!muxc) - return -ENOMEM; + if (!muxc) { + ret = -ENOMEM; + goto err_put_parent; + } muxc->priv = mux; platform_set_drvdata(pdev, muxc); @@ -235,6 +240,8 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) add_adapter_failed: i2c_mux_del_adapters(muxc); +err_put_parent: + i2c_put_adapter(parent); return ret; } -- GitLab From bffb84bf5a63288a65cbdbd0be860b780322f857 Mon Sep 17 00:00:00 2001 From: Ganapatrao Kulkarni Date: Tue, 2 May 2017 21:59:34 +0530 Subject: [PATCH 1038/1834] arm64: perf: Ignore exclude_hv when kernel is running in HYP [ Upstream commit 78a19cfdf37d19002c83c8790853c1cc10feccdc ] commit d98ecdaca296 ("arm64: perf: Count EL2 events if the kernel is running in HYP") returns -EINVAL when perf system call perf_event_open is called with exclude_hv != exclude_kernel. This change breaks applications on VHE enabled ARMv8.1 platforms. The issue was observed with HHVM application, which calls perf_event_open with exclude_hv = 1 and exclude_kernel = 0. There is no separate hypervisor privilege level when VHE is enabled, the host kernel runs at EL2. So when VHE is enabled, we should ignore exclude_hv from the application. This behaviour is consistent with PowerPC where the exclude_hv is ignored when the hypervisor is not present and with x86 where this flag is ignored. Signed-off-by: Ganapatrao Kulkarni [will: added comment to justify the behaviour of exclude_hv] Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/perf_event.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 57ae9d9ed9bb..199a23f058d5 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -871,15 +871,24 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event, if (attr->exclude_idle) return -EPERM; - if (is_kernel_in_hyp_mode() && - attr->exclude_kernel != attr->exclude_hv) - return -EINVAL; + + /* + * If we're running in hyp mode, then we *are* the hypervisor. + * Therefore we ignore exclude_hv in this configuration, since + * there's no hypervisor to sample anyway. This is consistent + * with other architectures (x86 and Power). + */ + if (is_kernel_in_hyp_mode()) { + if (!attr->exclude_kernel) + config_base |= ARMV8_PMU_INCLUDE_EL2; + } else { + if (attr->exclude_kernel) + config_base |= ARMV8_PMU_EXCLUDE_EL1; + if (!attr->exclude_hv) + config_base |= ARMV8_PMU_INCLUDE_EL2; + } if (attr->exclude_user) config_base |= ARMV8_PMU_EXCLUDE_EL0; - if (!is_kernel_in_hyp_mode() && attr->exclude_kernel) - config_base |= ARMV8_PMU_EXCLUDE_EL1; - if (!attr->exclude_hv) - config_base |= ARMV8_PMU_INCLUDE_EL2; /* * Install the filter into config_base as this is used to -- GitLab From 6c9b7010fba9585ad21d26a7eeaca666be3008d8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 12 May 2017 22:54:23 +0800 Subject: [PATCH 1039/1834] mdio: mux: fix device_node_continue.cocci warnings [ Upstream commit 8c977f5a856a7276450ddf3a7b57b4a8815b63f9 ] Device node iterators put the previous value of the index variable, so an explicit put causes a double put. In particular, of_mdiobus_register can fail before doing anything interesting, so one could view it as a no-op from the reference count point of view. Generated by: scripts/coccinelle/iterators/device_node_continue.cocci CC: Jon Mason Signed-off-by: Julia Lawall Signed-off-by: Fengguang Wu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/mdio-mux.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 6943c5ece44a..599ce24c514f 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -169,7 +169,6 @@ int mdio_mux_init(struct device *dev, if (r) { mdiobus_free(cb->mii_bus); devm_kfree(dev, cb); - of_node_put(child_bus_node); } else { cb->next = pb->children; pb->children = cb; -- GitLab From eb5562d076c32904e8e7fc65f597815b021dc30b Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Fri, 12 May 2017 17:03:39 -0700 Subject: [PATCH 1040/1834] ipv6: avoid dad-failures for addresses with NODAD [ Upstream commit 66eb9f86e50547ec2a8ff7a75997066a74ef584b ] Every address gets added with TENTATIVE flag even for the addresses with IFA_F_NODAD flag and dad-work is scheduled for them. During this DAD process we realize it's an address with NODAD and complete the process without sending any probe. However the TENTATIVE flags stays on the address for sometime enough to cause misinterpretation when we receive a NS. While processing NS, if the address has TENTATIVE flag, we mark it DADFAILED and endup with an address that was originally configured as NODAD with DADFAILED. We can't avoid scheduling dad_work for addresses with NODAD but we can avoid adding TENTATIVE flag to avoid this racy situation. Signed-off-by: Mahesh Bandewar Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/addrconf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1594d9fc9c92..3a27cf762da1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -988,7 +988,10 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, INIT_HLIST_NODE(&ifa->addr_lst); ifa->scope = scope; ifa->prefix_len = pfxlen; - ifa->flags = flags | IFA_F_TENTATIVE; + ifa->flags = flags; + /* No need to add the TENTATIVE flag for addresses with NODAD */ + if (!(flags & IFA_F_NODAD)) + ifa->flags |= IFA_F_TENTATIVE; ifa->valid_lft = valid_lft; ifa->prefered_lft = prefered_lft; ifa->cstamp = ifa->tstamp = jiffies; -- GitLab From e226b4e898c90a16d09e66eaf1fe939df02ccd6e Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Mon, 15 May 2017 10:34:53 +0530 Subject: [PATCH 1041/1834] async_tx: Fix DMA_PREP_FENCE usage in do_async_gen_syndrome() [ Upstream commit baae03a0e2497f49704628fd0aaf993cf98e1b99 ] The DMA_PREP_FENCE is to be used when preparing Tx descriptor if output of Tx descriptor is to be used by next/dependent Tx descriptor. The DMA_PREP_FENSE will not be set correctly in do_async_gen_syndrome() when calling dma->device_prep_dma_pq() under following conditions: 1. ASYNC_TX_FENCE not set in submit->flags 2. DMA_PREP_FENCE not set in dma_flags 3. src_cnt (= (disks - 2)) is greater than dma_maxpq(dma, dma_flags) This patch fixes DMA_PREP_FENCE usage in do_async_gen_syndrome() taking inspiration from do_async_xor() implementation. Signed-off-by: Anup Patel Reviewed-by: Ray Jui Reviewed-by: Scott Branden Acked-by: Dan Williams Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- crypto/async_tx/async_pq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c index f83de99d7d71..56bd612927ab 100644 --- a/crypto/async_tx/async_pq.c +++ b/crypto/async_tx/async_pq.c @@ -62,9 +62,6 @@ do_async_gen_syndrome(struct dma_chan *chan, dma_addr_t dma_dest[2]; int src_off = 0; - if (submit->flags & ASYNC_TX_FENCE) - dma_flags |= DMA_PREP_FENCE; - while (src_cnt > 0) { submit->flags = flags_orig; pq_src_cnt = min(src_cnt, dma_maxpq(dma, dma_flags)); @@ -83,6 +80,8 @@ do_async_gen_syndrome(struct dma_chan *chan, if (cb_fn_orig) dma_flags |= DMA_PREP_INTERRUPT; } + if (submit->flags & ASYNC_TX_FENCE) + dma_flags |= DMA_PREP_FENCE; /* Drivers force forward progress in case they can not provide * a descriptor -- GitLab From 318cc6982af730bb0b91fc1c385e5c8e65a974f8 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 25 Apr 2017 18:02:44 +0100 Subject: [PATCH 1042/1834] KVM: arm: Restore banked registers and physical timer access on hyp_panic() [ Upstream commit d2e19368848ce6065daa785efca26faed54732b6 ] When KVM panics, it hurridly restores the host context and parachutes into the host's panic() code. This looks like it was copied from arm64, the 32bit KVM panic code needs to restore the host's banked registers too. At some point panic() touches the physical timer/counter, this will trap back to HYP. If we're lucky, we panic again. Add a __timer_save_state() call to KVMs hyp_panic() path, this saves the guest registers and disables the traps for the host. Fixes: c36b6db5f3e4 ("ARM: KVM: Add panic handling code") Signed-off-by: James Morse Reviewed-by: Marc Zyngier Reviewed-by: Christoffer Dall Signed-off-by: Christoffer Dall Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/hyp/switch.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c index 624a510d31df..ebd2dd46adf7 100644 --- a/arch/arm/kvm/hyp/switch.c +++ b/arch/arm/kvm/hyp/switch.c @@ -237,8 +237,10 @@ void __hyp_text __noreturn __hyp_panic(int cause) vcpu = (struct kvm_vcpu *)read_sysreg(HTPIDR); host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context); + __timer_save_state(vcpu); __deactivate_traps(vcpu); __deactivate_vm(vcpu); + __banked_restore_state(host_ctxt); __sysreg_restore_state(host_ctxt); } -- GitLab From afeabec4eb81100ab194cd515dbe0456e84a00f1 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 25 Apr 2017 18:02:45 +0100 Subject: [PATCH 1043/1834] KVM: arm64: Restore host physical timer access on hyp_panic() [ Upstream commit e8ec032b182cd4841605de4fc297a8edffe55972 ] When KVM panics, it hurridly restores the host context and parachutes into the host's panic() code. At some point panic() touches the physical timer/counter. Unless we are an arm64 system with VHE, this traps back to EL2. If we're lucky, we panic again. Add a __timer_save_state() call to KVMs hyp_panic() path, this saves the guest registers and disables the traps for the host. Fixes: 53fd5b6487e4 ("arm64: KVM: Add panic handling") Signed-off-by: James Morse Reviewed-by: Marc Zyngier Reviewed-by: Christoffer Dall Signed-off-by: Christoffer Dall Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kvm/hyp/switch.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 0c848c18ca44..9174ba917d65 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -404,6 +404,7 @@ void __hyp_text __noreturn __hyp_panic(void) vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2); host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context); + __timer_save_state(vcpu); __deactivate_traps(vcpu); __deactivate_vm(vcpu); __sysreg_restore_host_state(host_ctxt); -- GitLab From 04030f5931b40e9c627b5fea9ac515d5e3d827c3 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 13:55:13 +0800 Subject: [PATCH 1044/1834] usb: dwc3: keystone: check return value [ Upstream commit 018047a1dba7636e1f7fdae2cc290a528991d648 ] Function devm_clk_get() returns an ERR_PTR when it fails. However, in function kdwc3_probe(), its return value is not checked, which may result in a bad memory access bug. This patch fixes the bug. Signed-off-by: Pan Bian Signed-off-by: Felipe Balbi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-keystone.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 72664700b8a2..12ee23f53cdd 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -107,6 +107,10 @@ static int kdwc3_probe(struct platform_device *pdev) return PTR_ERR(kdwc->usbss); kdwc->clk = devm_clk_get(kdwc->dev, "usb"); + if (IS_ERR(kdwc->clk)) { + dev_err(kdwc->dev, "unable to get usb clock\n"); + return PTR_ERR(kdwc->clk); + } error = clk_prepare_enable(kdwc->clk); if (error < 0) { -- GitLab From e09fd7c6449b758738ca46c8f6390f00ad61c1ee Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 9 May 2017 18:14:01 +0100 Subject: [PATCH 1045/1834] btrfs: fix incorrect error return ret being passed to mapping_set_error [ Upstream commit bff5baf8aa37a97293725a16c03f49872249c07e ] The setting of return code ret should be based on the error code passed into function end_extent_writepage and not on ret. Thanks to Liu Bo for spotting this mistake in the original fix I submitted. Detected by CoverityScan, CID#1414312 ("Logically dead code") Fixes: 5dca6eea91653e ("Btrfs: mark mapping with error flag to report errors to userspace") Signed-off-by: Colin Ian King Reviewed-by: Liu Bo Signed-off-by: David Sterba Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/btrfs/extent_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 8ed05d95584a..03ac3ab4b3b4 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -2453,7 +2453,7 @@ void end_extent_writepage(struct page *page, int err, u64 start, u64 end) if (!uptodate) { ClearPageUptodate(page); SetPageError(page); - ret = ret < 0 ? ret : -EIO; + ret = err < 0 ? err : -EIO; mapping_set_error(page->mapping, ret); } } -- GitLab From 088c77a8005bf839bbf3ae2882a48dd87cf2a4c4 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Tue, 16 May 2017 14:06:12 +0200 Subject: [PATCH 1046/1834] ata: libahci: properly propagate return value of platform_get_irq() [ Upstream commit c034640a32f8456018d9c8c83799ead683046b95 ] When platform_get_irq() fails, it returns an error code, which libahci_platform and replaces it by -EINVAL. This commit fixes that by propagating the error code. It fixes the situation where platform_get_irq() returns -EPROBE_DEFER because the interrupt controller is not available yet, and generally looks like the right thing to do. We pay attention to not show the "no irq" message when we are in an EPROBE_DEFER situation, because the driver probing will be retried later on, once the interrupt controller becomes available to provide the interrupt. Signed-off-by: Thomas Petazzoni Reviewed-by: Hans de Goede Signed-off-by: Tejun Heo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/ata/libahci_platform.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index aaa761b9081c..cd2eab6aa92e 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -514,8 +514,9 @@ int ahci_platform_init_host(struct platform_device *pdev, irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(dev, "no irq\n"); - return -EINVAL; + if (irq != -EPROBE_DEFER) + dev_err(dev, "no irq\n"); + return irq; } hpriv->irq = irq; -- GitLab From c4eca7ee0ed886529c6446bad7fb5ead5e8129d6 Mon Sep 17 00:00:00 2001 From: Thomas Winter Date: Tue, 16 May 2017 10:14:44 +1200 Subject: [PATCH 1047/1834] ipmr: vrf: Find VIFs using the actual device [ Upstream commit bcfc7d33110b0f33069d74138eeb7ca9acbb3c85 ] The skb->dev that is passed into ip_mr_input is the loX device for VRFs. When we lookup a vif for this dev, none is found as we do not create vifs for loopbacks. Instead lookup a vif for the actual device that the packet was received on, eg the vlan. Signed-off-by: Thomas Winter cc: David Ahern cc: Nikolay Aleksandrov cc: roopa Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ipmr.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 27089f5ebbb1..742a3432c3ea 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1929,6 +1929,20 @@ int ip_mr_input(struct sk_buff *skb) struct net *net = dev_net(skb->dev); int local = skb_rtable(skb)->rt_flags & RTCF_LOCAL; struct mr_table *mrt; + struct net_device *dev; + + /* skb->dev passed in is the loX master dev for vrfs. + * As there are no vifs associated with loopback devices, + * get the proper interface that does have a vif associated with it. + */ + dev = skb->dev; + if (netif_is_l3_master(skb->dev)) { + dev = dev_get_by_index_rcu(net, IPCB(skb)->iif); + if (!dev) { + kfree_skb(skb); + return -ENODEV; + } + } /* Packet is looped back after forward, it should not be * forwarded second time, but still can be delivered locally. @@ -1966,7 +1980,7 @@ int ip_mr_input(struct sk_buff *skb) /* already under rcu_read_lock() */ cache = ipmr_cache_find(mrt, ip_hdr(skb)->saddr, ip_hdr(skb)->daddr); if (!cache) { - int vif = ipmr_find_vif(mrt, skb->dev); + int vif = ipmr_find_vif(mrt, dev); if (vif >= 0) cache = ipmr_cache_find_any(mrt, ip_hdr(skb)->daddr, @@ -1986,7 +2000,7 @@ int ip_mr_input(struct sk_buff *skb) } read_lock(&mrt_lock); - vif = ipmr_find_vif(mrt, skb->dev); + vif = ipmr_find_vif(mrt, dev); if (vif >= 0) { int err2 = ipmr_cache_unresolved(mrt, vif, skb); read_unlock(&mrt_lock); -- GitLab From 4cc339e66447d8bee92a7f8ecbc23d8aa517fba1 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 9 May 2017 18:58:24 -0500 Subject: [PATCH 1048/1834] uio: fix incorrect memory leak cleanup [ Upstream commit 0d83539092ddb1ab79b4d65bccb866bf07ea2ccd ] Commit 75f0aef6220d ("uio: fix memory leak") has fixed up some memory leaks during the failure paths of the addition of uio attributes, but still is not correct entirely. A kobject_uevent() failure still needs a kobject_put() and the kobject container structure allocation failure before the kobject_init() doesn't need a kobject_put(). Fix this properly. Fixes: 75f0aef6220d ("uio: fix memory leak") Signed-off-by: Suman Anna Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/uio/uio.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index fba021f5736a..208bc52fc84d 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -279,7 +279,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) map = kzalloc(sizeof(*map), GFP_KERNEL); if (!map) { ret = -ENOMEM; - goto err_map_kobj; + goto err_map; } kobject_init(&map->kobj, &map_attr_type); map->mem = mem; @@ -289,7 +289,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) goto err_map_kobj; ret = kobject_uevent(&map->kobj, KOBJ_ADD); if (ret) - goto err_map; + goto err_map_kobj; } for (pi = 0; pi < MAX_UIO_PORT_REGIONS; pi++) { @@ -308,7 +308,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) portio = kzalloc(sizeof(*portio), GFP_KERNEL); if (!portio) { ret = -ENOMEM; - goto err_portio_kobj; + goto err_portio; } kobject_init(&portio->kobj, &portio_attr_type); portio->port = port; @@ -319,7 +319,7 @@ static int uio_dev_add_attributes(struct uio_device *idev) goto err_portio_kobj; ret = kobject_uevent(&portio->kobj, KOBJ_ADD); if (ret) - goto err_portio; + goto err_portio_kobj; } return 0; -- GitLab From 2c2605209a11ea43edcbfa1f02b7814c3213dda3 Mon Sep 17 00:00:00 2001 From: Ihar Hrachyshka Date: Tue, 16 May 2017 08:44:24 -0700 Subject: [PATCH 1049/1834] neighbour: update neigh timestamps iff update is effective [ Upstream commit 77d7123342dcf6442341b67816321d71da8b2b16 ] It's a common practice to send gratuitous ARPs after moving an IP address to another device to speed up healing of a service. To fulfill service availability constraints, the timing of network peers updating their caches to point to a new location of an IP address can be particularly important. Sometimes neigh_update calls won't touch neither lladdr nor state, for example if an update arrives in locktime interval. The neigh->updated value is tested by the protocol specific neigh code, which in turn will influence whether NEIGH_UPDATE_F_OVERRIDE gets set in the call to neigh_update() or not. As a result, we may effectively ignore the update request, bailing out of touching the neigh entry, except that we still bump its timestamps inside neigh_update. This may be a problem for updates arriving in quick succession. For example, consider the following scenario: A service is moved to another device with its IP address. The new device sends three gratuitous ARP requests into the network with ~1 seconds interval between them. Just before the first request arrives to one of network peer nodes, its neigh entry for the IP address transitions from STALE to DELAY. This transition, among other things, updates neigh->updated. Once the kernel receives the first gratuitous ARP, it ignores it because its arrival time is inside the locktime interval. The kernel still bumps neigh->updated. Then the second gratuitous ARP request arrives, and it's also ignored because it's still in the (new) locktime interval. Same happens for the third request. The node eventually heals itself (after delay_first_probe_time seconds since the initial transition to DELAY state), but it just wasted some time and require a new ARP request/reply round trip. This unfortunate behaviour both puts more load on the network, as well as reduces service availability. This patch changes neigh_update so that it bumps neigh->updated (as well as neigh->confirmed) only once we are sure that either lladdr or entry state will change). In the scenario described above, it means that the second gratuitous ARP request will actually update the entry lladdr. Ideally, we would update the neigh entry on the very first gratuitous ARP request. The locktime mechanism is designed to ignore ARP updates in a short timeframe after a previous ARP update was honoured by the kernel layer. This would require tracking timestamps for state transitions separately from timestamps when actual updates are received. This would probably involve changes in neighbour struct. Therefore, the patch doesn't tackle the issue of the first gratuitous APR ignored, leaving it for a follow-up. Signed-off-by: Ihar Hrachyshka Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/core/neighbour.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 7b315663f840..a426790b0688 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1130,10 +1130,6 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, lladdr = neigh->ha; } - if (new & NUD_CONNECTED) - neigh->confirmed = jiffies; - neigh->updated = jiffies; - /* If entry was valid and address is not changed, do not change entry state, if new one is STALE. */ @@ -1155,6 +1151,16 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, } } + /* Update timestamps only once we know we will make a change to the + * neighbour entry. Otherwise we risk to move the locktime window with + * noop updates and ignore relevant ARP updates. + */ + if (new != old || lladdr != neigh->ha) { + if (new & NUD_CONNECTED) + neigh->confirmed = jiffies; + neigh->updated = jiffies; + } + if (new != old) { neigh_del_timer(neigh); if (new & NUD_PROBE) -- GitLab From a20049d8fb7ed17638ada8c76fb11555b1d43367 Mon Sep 17 00:00:00 2001 From: Ihar Hrachyshka Date: Tue, 16 May 2017 07:53:43 -0700 Subject: [PATCH 1050/1834] arp: honour gratuitous ARP _replies_ [ Upstream commit 23d268eb240954e6e78f7cfab04f2b1e79f84489 ] When arp_accept is 1, gratuitous ARPs are supposed to override matching entries irrespective of whether they arrive during locktime. This was implemented in commit 56022a8fdd87 ("ipv4: arp: update neighbour address when a gratuitous arp is received and arp_accept is set") There is a glitch in the patch though. RFC 2002, section 4.6, "ARP, Proxy ARP, and Gratuitous ARP", defines gratuitous ARPs so that they can be either of Request or Reply type. Those Reply gratuitous ARPs can be triggered with standard tooling, for example, arping -A option does just that. This patch fixes the glitch, making both Request and Reply flavours of gratuitous ARPs to behave identically. As per RFC, if gratuitous ARPs are of Reply type, their Target Hardware Address field should also be set to the link-layer address to which this cache entry should be updated. The field is present in ARP over Ethernet but not in IEEE 1394. In this patch, I don't consider any broadcasted ARP replies as gratuitous if the field is not present, to conform the standard. It's not clear whether there is such a thing for IEEE 1394 as a gratuitous ARP reply; until it's cleared up, we will ignore such broadcasts. Note that they will still update existing ARP cache entries, assuming they arrive out of locktime time interval. Signed-off-by: Ihar Hrachyshka Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/arp.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index e60517eb1c3a..43bacf65dbab 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -658,6 +658,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) unsigned char *arp_ptr; struct rtable *rt; unsigned char *sha; + unsigned char *tha = NULL; __be32 sip, tip; u16 dev_type = dev->type; int addr_type; @@ -729,6 +730,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) break; #endif default: + tha = arp_ptr; arp_ptr += dev->addr_len; } memcpy(&tip, arp_ptr, 4); @@ -847,8 +849,18 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) It is possible, that this option should be enabled for some devices (strip is candidate) */ - is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && - addr_type == RTN_UNICAST; + is_garp = tip == sip && addr_type == RTN_UNICAST; + + /* Unsolicited ARP _replies_ also require target hwaddr to be + * the same as source. + */ + if (is_garp && arp->ar_op == htons(ARPOP_REPLY)) + is_garp = + /* IPv4 over IEEE 1394 doesn't provide target + * hardware address field in its ARP payload. + */ + tha && + !memcmp(tha, sha, dev->addr_len); if (!n && ((arp->ar_op == htons(ARPOP_REPLY) && -- GitLab From 8207552a7be8e24ceb5ad26e4f7069891b1ddc3f Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 17 May 2017 17:52:24 +0800 Subject: [PATCH 1051/1834] ARM: dts: rockchip: fix rk322x i2s1 pinctrl error [ Upstream commit 9d420e9b4140f8938ad6aa0d29e2428a2af6122b ] Refer to Chapter 5.3.2 of rk3229 TRM, we can see that GPIO1A[2,4,5] using RK_FUNC_2 not RK_FUNC_1. This patch fixes it. Signed-off-by: Sugar Zhang Signed-off-by: Frank Wang Signed-off-by: Heiko Stuebner Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/rk322x.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi index 9e6bf0e311bb..2679dc80f831 100644 --- a/arch/arm/boot/dts/rk322x.dtsi +++ b/arch/arm/boot/dts/rk322x.dtsi @@ -617,9 +617,9 @@ <0 12 RK_FUNC_1 &pcfg_pull_none>, <0 13 RK_FUNC_1 &pcfg_pull_none>, <0 14 RK_FUNC_1 &pcfg_pull_none>, - <1 2 RK_FUNC_1 &pcfg_pull_none>, - <1 4 RK_FUNC_1 &pcfg_pull_none>, - <1 5 RK_FUNC_1 &pcfg_pull_none>; + <1 2 RK_FUNC_2 &pcfg_pull_none>, + <1 4 RK_FUNC_2 &pcfg_pull_none>, + <1 5 RK_FUNC_2 &pcfg_pull_none>; }; }; -- GitLab From d84a1c8e3228cf43d2dea63e480a0dd230a663dd Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Wed, 26 Apr 2017 16:59:34 +0800 Subject: [PATCH 1052/1834] usb: chipidea: properly handle host or gadget initialization failure [ Upstream commit c4a0bbbdb7f6e3c37fa6deb3ef28c5ed99da6175 ] If ci_hdrc_host_init() or ci_hdrc_gadget_init() returns error and the error != -ENXIO, as Peter pointed out, "it stands for initialization for host or gadget has failed", so we'd better return failure rather continue. And before destroying the otg, i.e ci_hdrc_otg_destroy(ci), we should also check ci->roles[CI_ROLE_GADGET]. Signed-off-by: Jisheng Zhang Signed-off-by: Peter Chen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/chipidea/core.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 6e0d614a8075..64c6af2c8559 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -839,7 +839,7 @@ static inline void ci_role_destroy(struct ci_hdrc *ci) { ci_hdrc_gadget_destroy(ci); ci_hdrc_host_destroy(ci); - if (ci->is_otg) + if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) ci_hdrc_otg_destroy(ci); } @@ -939,27 +939,35 @@ static int ci_hdrc_probe(struct platform_device *pdev) /* initialize role(s) before the interrupt is requested */ if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { ret = ci_hdrc_host_init(ci); - if (ret) - dev_info(dev, "doesn't support host\n"); + if (ret) { + if (ret == -ENXIO) + dev_info(dev, "doesn't support host\n"); + else + goto deinit_phy; + } } if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { ret = ci_hdrc_gadget_init(ci); - if (ret) - dev_info(dev, "doesn't support gadget\n"); + if (ret) { + if (ret == -ENXIO) + dev_info(dev, "doesn't support gadget\n"); + else + goto deinit_host; + } } if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { dev_err(dev, "no supported roles\n"); ret = -ENODEV; - goto deinit_phy; + goto deinit_gadget; } if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) { ret = ci_hdrc_otg_init(ci); if (ret) { dev_err(dev, "init otg fails, ret = %d\n", ret); - goto stop; + goto deinit_gadget; } } @@ -1024,7 +1032,12 @@ static int ci_hdrc_probe(struct platform_device *pdev) ci_extcon_unregister(ci); stop: - ci_role_destroy(ci); + if (ci->is_otg && ci->roles[CI_ROLE_GADGET]) + ci_hdrc_otg_destroy(ci); +deinit_gadget: + ci_hdrc_gadget_destroy(ci); +deinit_host: + ci_hdrc_host_destroy(ci); deinit_phy: ci_usb_phy_exit(ci); -- GitLab From c3231c038ae7dc4e3c3647ec7c1903744303549c Mon Sep 17 00:00:00 2001 From: Petr Cvek Date: Mon, 24 Apr 2017 22:51:58 -0300 Subject: [PATCH 1053/1834] pxa_camera: fix module remove codepath for v4l2 clock [ Upstream commit e3b4d10cc057522353c4a02f2f90dca6a52e006f ] The conversion from soc_camera omitted a correct handling of the clock gating for a sensor. When the pxa_camera driver module was removed it tried to unregister clk, but this caused a similar warning: WARNING: CPU: 0 PID: 6740 at drivers/media/v4l2-core/v4l2-clk.c:278 v4l2_clk_unregister(): Refusing to unregister ref-counted 0-0030 clock! The clock was at time still refcounted by the sensor driver. Before the removing of the pxa_camera the clock must be dropped by the sensor driver. This should be triggered by v4l2_async_notifier_unregister() call which removes sensor driver module too, calls unbind() function and then tries to probe sensor driver again. Inside unbind() we can safely unregister the v4l2 clock as the sensor driver got removed. The original v4l2_clk_unregister() should be put inside test as the clock can be already unregistered from unbind(). If there was not any bound sensor the clock is still present. The codepath is practically a copy from the old soc_camera. The bug was tested with a pxa_camera+ov9640 combination during the conversion of the ov9640 from the soc_camera. Signed-off-by: Petr Cvek Tested-by: Robert Jarzmik Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/platform/pxa_camera.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index c12209c701d3..390d708c807a 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2169,6 +2169,12 @@ static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier, pxa_dma_stop_channels(pcdev); pxa_camera_destroy_formats(pcdev); + + if (pcdev->mclk_clk) { + v4l2_clk_unregister(pcdev->mclk_clk); + pcdev->mclk_clk = NULL; + } + video_unregister_device(&pcdev->vdev); pcdev->sensor = NULL; @@ -2495,7 +2501,13 @@ static int pxa_camera_remove(struct platform_device *pdev) dma_release_channel(pcdev->dma_chans[1]); dma_release_channel(pcdev->dma_chans[2]); - v4l2_clk_unregister(pcdev->mclk_clk); + v4l2_async_notifier_unregister(&pcdev->notifier); + + if (pcdev->mclk_clk) { + v4l2_clk_unregister(pcdev->mclk_clk); + pcdev->mclk_clk = NULL; + } + v4l2_device_unregister(&pcdev->v4l2_dev); dev_info(&pdev->dev, "PXA Camera driver unloaded\n"); -- GitLab From 651688ba685a9079c3ec9dfa5fa72936594e7f2d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 May 2017 11:47:42 -0400 Subject: [PATCH 1054/1834] USB: ene_usb6250: fix first command execution [ Upstream commit 4b309f1c4972c8f09e03ac64fc63510dbf5591a4 ] In the ene_usb6250 sub-driver for usb-storage, the ene_transport() routine is supposed to initialize the driver before executing the current command, if the initialization has not already been performed. However, a bug in the routine causes it to skip the command after doing the initialization. Also, the routine does not return an appropriate error code if either the initialization or the command fails. As a result of the first bug, the first command (a SCSI INQUIRY) is not carried out. The results can be seen in the system log, in the form of a warning message and empty or garbage INQUIRY data: Apr 18 22:40:08 notebook2 kernel: scsi host6: scsi scan: INQUIRY result too short (5), using 36 Apr 18 22:40:08 notebook2 kernel: scsi 6:0:0:0: Direct-Access PQ: 0 ANSI: 0 This patch fixes both errors. Signed-off-by: Alan Stern Reported-and-tested-by: Andreas Hartmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/ene_ub6250.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 4340b4925daa..4199fe563c71 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -2295,21 +2295,22 @@ static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) static int ene_transport(struct scsi_cmnd *srb, struct us_data *us) { - int result = 0; + int result = USB_STOR_XFER_GOOD; struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); /*US_DEBUG(usb_stor_show_command(us, srb)); */ scsi_set_resid(srb, 0); - if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) { + if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) result = ene_init(us); - } else { + if (result == USB_STOR_XFER_GOOD) { + result = USB_STOR_TRANSPORT_ERROR; if (info->SD_Status.Ready) result = sd_scsi_irp(us, srb); if (info->MS_Status.Ready) result = ms_scsi_irp(us, srb); } - return 0; + return result; } static struct scsi_host_template ene_ub6250_host_template; -- GitLab From 53678836e3bc3d06ca1be22a185d839de557ef45 Mon Sep 17 00:00:00 2001 From: linzhang Date: Wed, 17 May 2017 12:05:07 +0800 Subject: [PATCH 1055/1834] net: x25: fix one potential use-after-free issue [ Upstream commit 64df6d525fcff1630098db9238bfd2b3e092d5c1 ] The function x25_init is not properly unregister related resources on error handler.It is will result in kernel oops if x25_init init failed, so add properly unregister call on error handler. Also, i adjust the coding style and make x25_register_sysctl properly return failure. Signed-off-by: linzhang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/net/x25.h | 4 ++-- net/x25/af_x25.c | 24 ++++++++++++++++-------- net/x25/sysctl_net_x25.c | 5 ++++- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/net/x25.h b/include/net/x25.h index c383aa4edbf0..6d30a01d281d 100644 --- a/include/net/x25.h +++ b/include/net/x25.h @@ -298,10 +298,10 @@ void x25_check_rbuf(struct sock *); /* sysctl_net_x25.c */ #ifdef CONFIG_SYSCTL -void x25_register_sysctl(void); +int x25_register_sysctl(void); void x25_unregister_sysctl(void); #else -static inline void x25_register_sysctl(void) {}; +static inline int x25_register_sysctl(void) { return 0; }; static inline void x25_unregister_sysctl(void) {}; #endif /* CONFIG_SYSCTL */ diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index f83b74d3e2ac..007721632b07 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1790,32 +1790,40 @@ void x25_kill_by_neigh(struct x25_neigh *nb) static int __init x25_init(void) { - int rc = proto_register(&x25_proto, 0); + int rc; - if (rc != 0) + rc = proto_register(&x25_proto, 0); + if (rc) goto out; rc = sock_register(&x25_family_ops); - if (rc != 0) + if (rc) goto out_proto; dev_add_pack(&x25_packet_type); rc = register_netdevice_notifier(&x25_dev_notifier); - if (rc != 0) + if (rc) goto out_sock; - pr_info("Linux Version 0.2\n"); + rc = x25_register_sysctl(); + if (rc) + goto out_dev; - x25_register_sysctl(); rc = x25_proc_init(); - if (rc != 0) - goto out_dev; + if (rc) + goto out_sysctl; + + pr_info("Linux Version 0.2\n"); + out: return rc; +out_sysctl: + x25_unregister_sysctl(); out_dev: unregister_netdevice_notifier(&x25_dev_notifier); out_sock: + dev_remove_pack(&x25_packet_type); sock_unregister(AF_X25); out_proto: proto_unregister(&x25_proto); diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c index 43239527a205..703d46aae7a2 100644 --- a/net/x25/sysctl_net_x25.c +++ b/net/x25/sysctl_net_x25.c @@ -73,9 +73,12 @@ static struct ctl_table x25_table[] = { { 0, }, }; -void __init x25_register_sysctl(void) +int __init x25_register_sysctl(void) { x25_table_header = register_net_sysctl(&init_net, "net/x25", x25_table); + if (!x25_table_header) + return -ENOMEM; + return 0; } void x25_unregister_sysctl(void) -- GitLab From c85669ef1e34371658bf17021ad139a44fea43b1 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 16 May 2017 11:47:52 -0400 Subject: [PATCH 1056/1834] USB: ene_usb6250: fix SCSI residue overwriting [ Upstream commit aa18c4b6e0e39bfb00af48734ec24bc189ac9909 ] In the ene_usb6250 sub-driver for usb-storage, the SCSI residue is not reported correctly. The residue is initialized to 0, but this value is overwritten whenever the driver sends firmware to the card reader before performing the current command. As a result, a valid READ or WRITE operation appears to have failed, causing the SCSI core to retry the command multiple times and eventually fail. This patch fixes the problem by resetting the SCSI residue to 0 after sending firmware to the device. Signed-off-by: Alan Stern Reported-and-tested-by: Andreas Hartmann Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/ene_ub6250.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 4199fe563c71..4d6eb48b2c45 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -1942,6 +1942,8 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag) bcb->CDB[0] = 0xEF; result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0); + if (us->srb != NULL) + scsi_set_resid(us->srb, 0); info->BIN_FLAG = flag; kfree(buf); -- GitLab From 65db56497574362f0f57f18f1f7ac8ff03926d17 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Sat, 22 Apr 2017 18:37:19 +0530 Subject: [PATCH 1057/1834] serial: 8250: omap: Disable DMA for console UART [ Upstream commit 84b40e3b57eef1417479c00490dd4c9f6e5ffdbc ] Kernel always writes log messages to console via serial8250_console_write()->serial8250_console_putchar() which directly accesses UART_TX register _without_ using DMA. But, if other processes like systemd using same UART port, then these writes are handled by a different code flow using 8250_omap driver where there is provision to use DMA. It seems that it is possible that both DMA and CPU might simultaneously put data to UART FIFO and lead to potential loss of data due to FIFO overflow and weird data corruption. This happens when both kernel console and userspace tries to write simultaneously to the same UART port. Therefore, disable DMA on kernel console port to avoid potential race between CPU and DMA. Signed-off-by: Vignesh R Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index da31159a03ec..e8b34f16ba2c 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -613,6 +613,10 @@ static int omap_8250_startup(struct uart_port *port) up->lsr_saved_flags = 0; up->msr_saved_flags = 0; + /* Disable DMA for console UART */ + if (uart_console(port)) + up->dma = NULL; + if (up->dma) { ret = serial8250_request_dma(up); if (ret) { -- GitLab From 13b9c31db4f2627920328f7010ed6a3bcb958e60 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Apr 2017 20:15:35 +0200 Subject: [PATCH 1058/1834] serial: sh-sci: Fix race condition causing garbage during shutdown [ Upstream commit 1cf4a7efdc71cab84c42cfea7200608711ea954f ] If DMA is enabled and used, a burst of old data may be seen on the serial console during "poweroff" or "reboot". uart_flush_buffer() clears the circular buffer, but sci_port.tx_dma_len is not reset. This leads to a circular buffer overflow, dumping (UART_XMIT_SIZE - sci_port.tx_dma_len) bytes. To fix this, add a .flush_buffer() callback that resets sci_port.tx_dma_len. Inspired by commit 31ca2c63fdc0aee7 ("tty/serial: atmel: fix race condition (TX+DMA)"). Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index a55c94dfefd2..107f0d194ac5 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1545,7 +1545,16 @@ static void sci_free_dma(struct uart_port *port) if (s->chan_rx) sci_rx_dma_release(s, false); } -#else + +static void sci_flush_buffer(struct uart_port *port) +{ + /* + * In uart_flush_buffer(), the xmit circular buffer has just been + * cleared, so we have to reset tx_dma_len accordingly. + */ + to_sci_port(port)->tx_dma_len = 0; +} +#else /* !CONFIG_SERIAL_SH_SCI_DMA */ static inline void sci_request_dma(struct uart_port *port) { } @@ -1553,7 +1562,9 @@ static inline void sci_request_dma(struct uart_port *port) static inline void sci_free_dma(struct uart_port *port) { } -#endif + +#define sci_flush_buffer NULL +#endif /* !CONFIG_SERIAL_SH_SCI_DMA */ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) { @@ -2551,6 +2562,7 @@ static const struct uart_ops sci_uart_ops = { .break_ctl = sci_break_ctl, .startup = sci_startup, .shutdown = sci_shutdown, + .flush_buffer = sci_flush_buffer, .set_termios = sci_set_termios, .pm = sci_pm, .type = sci_type, -- GitLab From f74050ed6ba48d032e130e462e24c87fb627bd38 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:33 +0200 Subject: [PATCH 1059/1834] net/wan/fsl_ucc_hdlc: fix unitialized variable warnings [ Upstream commit 66bb144bd9096dd5268ef736ba769b8b6f4ef100 ] This fixes the following compiler warnings: drivers/net/wan/fsl_ucc_hdlc.c: In function 'ucc_hdlc_poll': warning: 'skb' may be used uninitialized in this function [-Wmaybe-uninitialized] skb->mac_header = skb->data - skb->head; and drivers/net/wan/fsl_ucc_hdlc.c: In function 'ucc_hdlc_probe': drivers/net/wan/fsl_ucc_hdlc.c:1127:3: warning: 'utdm' may be used uninitialized in this function [-Wmaybe-uninitialized] kfree(utdm); Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/fsl_ucc_hdlc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 65647533b401..4c49410c3a1b 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -454,7 +454,7 @@ static int hdlc_tx_done(struct ucc_hdlc_private *priv) static int hdlc_rx_done(struct ucc_hdlc_private *priv, int rx_work_limit) { struct net_device *dev = priv->ndev; - struct sk_buff *skb; + struct sk_buff *skb = NULL; hdlc_device *hdlc = dev_to_hdlc(dev); struct qe_bd *bd; u32 bd_status; @@ -1002,7 +1002,7 @@ static int ucc_hdlc_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct ucc_hdlc_private *uhdlc_priv = NULL; struct ucc_tdm_info *ut_info; - struct ucc_tdm *utdm; + struct ucc_tdm *utdm = NULL; struct resource res; struct net_device *dev; hdlc_device *hdlc; -- GitLab From 6b3a9354cd0b2dae4d2d3e19e63173e30eec74d7 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:35 +0200 Subject: [PATCH 1060/1834] net/wan/fsl_ucc_hdlc: fix incorrect memory allocation [ Upstream commit 5b8aad93c52bdda6a731cab8497998cfa0f2df07 ] We need space for the struct qe_bd and not for a pointer to this struct. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/fsl_ucc_hdlc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index 4c49410c3a1b..dcd5ff43a946 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -137,7 +137,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) priv->tx_ring_size = TX_BD_RING_LEN; /* Alloc Rx BD */ priv->rx_bd_base = dma_alloc_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), &priv->dma_rx_bd, GFP_KERNEL); if (!priv->rx_bd_base) { @@ -148,7 +148,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) /* Alloc Tx BD */ priv->tx_bd_base = dma_alloc_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), &priv->dma_tx_bd, GFP_KERNEL); if (!priv->tx_bd_base) { @@ -295,11 +295,11 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) qe_muram_free(priv->ucc_pram_offset); free_tx_bd: dma_free_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), priv->tx_bd_base, priv->dma_tx_bd); free_rx_bd: dma_free_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), priv->rx_bd_base, priv->dma_rx_bd); free_uccf: ucc_fast_free(priv->uccf); @@ -688,7 +688,7 @@ static void uhdlc_memclean(struct ucc_hdlc_private *priv) if (priv->rx_bd_base) { dma_free_coherent(priv->dev, - RX_BD_RING_LEN * sizeof(struct qe_bd *), + RX_BD_RING_LEN * sizeof(struct qe_bd), priv->rx_bd_base, priv->dma_rx_bd); priv->rx_bd_base = NULL; @@ -697,7 +697,7 @@ static void uhdlc_memclean(struct ucc_hdlc_private *priv) if (priv->tx_bd_base) { dma_free_coherent(priv->dev, - TX_BD_RING_LEN * sizeof(struct qe_bd *), + TX_BD_RING_LEN * sizeof(struct qe_bd), priv->tx_bd_base, priv->dma_tx_bd); priv->tx_bd_base = NULL; -- GitLab From 247e2136c3f98dc287116492cfa78ab2f060dc3b Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Wed, 17 May 2017 17:24:37 +0200 Subject: [PATCH 1061/1834] fsl/qe: add bit description for SYNL register for GUMR [ Upstream commit c7f235a7c2d09b1b83671ba2d93ebee981554467 ] Add the bitmask for the two bit SYNL register according to the QUICK Engine Reference Manual. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/soc/fsl/qe/qe.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/soc/fsl/qe/qe.h b/include/soc/fsl/qe/qe.h index 0cd4c11479b1..226f915a68c2 100644 --- a/include/soc/fsl/qe/qe.h +++ b/include/soc/fsl/qe/qe.h @@ -668,6 +668,10 @@ struct ucc_slow_pram { #define UCC_FAST_GUMR_CTSS 0x00800000 #define UCC_FAST_GUMR_TXSY 0x00020000 #define UCC_FAST_GUMR_RSYN 0x00010000 +#define UCC_FAST_GUMR_SYNL_MASK 0x0000C000 +#define UCC_FAST_GUMR_SYNL_16 0x0000C000 +#define UCC_FAST_GUMR_SYNL_8 0x00008000 +#define UCC_FAST_GUMR_SYNL_AUTO 0x00004000 #define UCC_FAST_GUMR_RTSM 0x00002000 #define UCC_FAST_GUMR_REVD 0x00000400 #define UCC_FAST_GUMR_ENR 0x00000020 -- GitLab From eed386e2e286f1d187b293b84ab53d0740b549c3 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 18 May 2017 15:01:34 +0200 Subject: [PATCH 1062/1834] sh_eth: Use platform device for printing before register_netdev() [ Upstream commit 5f5c5449acad0cd3322e53e1ac68c044483b0aa5 ] The MDIO initialization failure message is printed using the network device, before it has been registered, leading to: (null): failed to initialise MDIO Use the platform device instead to fix this: sh-eth ee700000.ethernet: failed to initialise MDIO Fixes: daacf03f0bbfefee ("sh_eth: Register MDIO bus before registering the network device") Signed-off-by: Geert Uytterhoeven Reviewed-by: Laurent Pinchart Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/renesas/sh_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index b6816ae00b7a..c8fd99b3ca29 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3133,7 +3133,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) /* MDIO bus init */ ret = sh_mdio_init(mdp, pd); if (ret) { - dev_err(&ndev->dev, "failed to initialise MDIO\n"); + dev_err(&pdev->dev, "failed to initialise MDIO\n"); goto out_release; } -- GitLab From c8799579ff4b1970c519ab664dffca1e9d1198de Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 18 May 2017 13:03:52 +0200 Subject: [PATCH 1063/1834] mlxsw: spectrum: Avoid possible NULL pointer dereference [ Upstream commit c0e01eac7ada785fdeaea1ae5476ec1cf3b00374 ] In case we got an FDB notification for a port that doesn't exist we execute an FDB entry delete to prevent it from re-appearing the next time we poll for notifications. If the operation failed we would trigger a NULL pointer dereference as 'mlxsw_sp_port' is NULL. Fix it by reporting the error using the underlying bus device instead. Fixes: 12f1501e7511 ("mlxsw: spectrum: remove FDB entry in case we get unknown object notification") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c index bea9ae31a769..60e1edcbe573 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_switchdev.c @@ -1448,8 +1448,7 @@ static void mlxsw_sp_fdb_notify_mac_process(struct mlxsw_sp *mlxsw_sp, err = mlxsw_sp_port_fdb_uc_op(mlxsw_sp, local_port, mac, fid, adding, true); if (err) { - if (net_ratelimit()) - netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n"); + dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n"); return; } @@ -1509,8 +1508,7 @@ static void mlxsw_sp_fdb_notify_mac_lag_process(struct mlxsw_sp *mlxsw_sp, err = mlxsw_sp_port_fdb_uc_lag_op(mlxsw_sp, lag_id, mac, fid, lag_vid, adding, true); if (err) { - if (net_ratelimit()) - netdev_err(mlxsw_sp_port->dev, "Failed to set FDB entry\n"); + dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to set FDB entry\n"); return; } -- GitLab From 2fb42f008bb8540ef0f12250e7c44508fd795824 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Wed, 17 May 2017 20:30:43 +0530 Subject: [PATCH 1064/1834] scsi: csiostor: fix use after free in csio_hw_use_fwconfig() [ Upstream commit a351e40b6de550049423a26f7ded7b639e363d89 ] mbp pointer is passed to csio_hw_validate_caps() so call mempool_free() after calling csio_hw_validate_caps(). Signed-off-by: Varun Prakash Fixes: 541c571fa2fd ("csiostor:Use firmware version from cxgb4/t4fw_version.h") Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/csiostor/csio_hw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c index 622bdabc8894..dab195f04da7 100644 --- a/drivers/scsi/csiostor/csio_hw.c +++ b/drivers/scsi/csiostor/csio_hw.c @@ -1769,7 +1769,6 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) goto bye; } - mempool_free(mbp, hw->mb_mempool); if (finicsum != cfcsum) { csio_warn(hw, "Config File checksum mismatch: csum=%#x, computed=%#x\n", @@ -1780,6 +1779,10 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param) rv = csio_hw_validate_caps(hw, mbp); if (rv != 0) goto bye; + + mempool_free(mbp, hw->mb_mempool); + mbp = NULL; + /* * Note that we're operating with parameters * not supplied by the driver, rather than from hard-wired -- GitLab From e88f1e3a8b3aedfd2dacc6cec1c051295a65e045 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Thu, 18 May 2017 20:37:31 +1000 Subject: [PATCH 1065/1834] powerpc/mm: Fix virt_addr_valid() etc. on 64-bit hash [ Upstream commit e41e53cd4fe331d0d1f06f8e4ed7e2cc63ee2c34 ] virt_addr_valid() is supposed to tell you if it's OK to call virt_to_page() on an address. What this means in practice is that it should only return true for addresses in the linear mapping which are backed by a valid PFN. We are failing to properly check that the address is in the linear mapping, because virt_to_pfn() will return a valid looking PFN for more or less any address. That bug is actually caused by __pa(), used in virt_to_pfn(). eg: __pa(0xc000000000010000) = 0x10000 # Good __pa(0xd000000000010000) = 0x10000 # Bad! __pa(0x0000000000010000) = 0x10000 # Bad! This started happening after commit bdbc29c19b26 ("powerpc: Work around gcc miscompilation of __pa() on 64-bit") (Aug 2013), where we changed the definition of __pa() to work around a GCC bug. Prior to that we subtracted PAGE_OFFSET from the value passed to __pa(), meaning __pa() of a 0xd or 0x0 address would give you something bogus back. Until we can verify if that GCC bug is no longer an issue, or come up with another solution, this commit does the minimal fix to make virt_addr_valid() work, by explicitly checking that the address is in the linear mapping region. Fixes: bdbc29c19b26 ("powerpc: Work around gcc miscompilation of __pa() on 64-bit") Signed-off-by: Michael Ellerman Reviewed-by: Paul Mackerras Reviewed-by: Balbir Singh Tested-by: Breno Leitao Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/page.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index 56398e7e6100..71c69883125a 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h @@ -132,7 +132,19 @@ extern long long virt_phys_offset; #define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) #define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr)) #define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) + +#ifdef CONFIG_PPC_BOOK3S_64 +/* + * On hash the vmalloc and other regions alias to the kernel region when passed + * through __pa(), which virt_to_pfn() uses. That means virt_addr_valid() can + * return true for some vmalloc addresses, which is incorrect. So explicitly + * check that the address is in the kernel region. + */ +#define virt_addr_valid(kaddr) (REGION_ID(kaddr) == KERNEL_REGION_ID && \ + pfn_valid(virt_to_pfn(kaddr))) +#else #define virt_addr_valid(kaddr) pfn_valid(virt_to_pfn(kaddr)) +#endif /* * On Book-E parts we need __va to parse the device tree and we can't -- GitLab From acf6bfef15fac288f68e1b9a1e63f8b5fee5771b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 May 2017 15:26:00 +0100 Subject: [PATCH 1066/1834] ath5k: fix memory leak on buf on failed eeprom read [ Upstream commit 8fed6823e06e43ee9cf7c0ffecec2f9111ce6201 ] The AR5K_EEPROM_READ macro returns with -EIO if a read error occurs causing a memory leak on the allocated buffer buf. Fix this by explicitly calling ath5k_hw_nvram_read and exiting on the via the freebuf label that performs the necessary free'ing of buf when a read error occurs. Detected by CoverityScan, CID#1248782 ("Resource Leak") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath5k/debug.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index 4f8d9ed04f5e..4a1054408f1a 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -939,7 +939,10 @@ static int open_file_eeprom(struct inode *inode, struct file *file) } for (i = 0; i < eesize; ++i) { - AR5K_EEPROM_READ(i, val); + if (!ath5k_hw_nvram_read(ah, i, &val)) { + ret = -EIO; + goto freebuf; + } buf[i] = val; } -- GitLab From 35253ff9e9134f4c65718573d274d97941a9ba70 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 19 May 2017 11:29:04 +1000 Subject: [PATCH 1067/1834] selftests/powerpc: Fix TM resched DSCR test with some compilers [ Upstream commit fe06fe860250a4f01d0eaf70a2563b1997174a74 ] The tm-resched-dscr test has started failing sometimes, depending on what compiler it's built with, eg: test: tm_resched_dscr Check DSCR TM context switch: tm-resched-dscr: tm-resched-dscr.c:76: test_body: Assertion `rv' failed. !! child died by signal 6 When it fails we see that the compiler doesn't initialise rv to 1 before entering the inline asm block. Although that's counter intuitive, it is allowed because we tell the compiler that the inline asm will write to rv (using "=r"), meaning the original value is irrelevant. Marking it as a read/write parameter would presumably work, but it seems simpler to fix it by setting the initial value of rv in the inline asm. Fixes: 96d016108640 ("powerpc: Correct DSCR during TM context switch") Signed-off-by: Michael Ellerman Acked-by: Michael Neuling Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/powerpc/tm/tm-resched-dscr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c index d9c49f41515e..e79ccd6aada1 100644 --- a/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c +++ b/tools/testing/selftests/powerpc/tm/tm-resched-dscr.c @@ -42,12 +42,12 @@ int test_body(void) printf("Check DSCR TM context switch: "); fflush(stdout); for (;;) { - rv = 1; asm __volatile__ ( /* set a known value into the DSCR */ "ld 3, %[dscr1];" "mtspr %[sprn_dscr], 3;" + "li %[rv], 1;" /* start and suspend a transaction */ "tbegin.;" "beq 1f;" -- GitLab From c4c3203761117c041bb457d05201935131e351f1 Mon Sep 17 00:00:00 2001 From: Antony Antony Date: Fri, 19 May 2017 12:47:00 +0200 Subject: [PATCH 1068/1834] xfrm: fix state migration copy replay sequence numbers [ Upstream commit a486cd23661c9387fb076c3f6ae8b2aa9d20d54a ] During xfrm migration copy replay and preplay sequence numbers from the previous state. Here is a tcpdump output showing the problem. 10.0.10.46 is running vanilla kernel, is the IKE/IPsec responder. After the migration it sent wrong sequence number, reset to 1. The migration is from 10.0.0.52 to 10.0.0.53. IP 10.0.0.52.4500 > 10.0.10.46.4500: UDP-encap: ESP(spi=0x43ef462d,seq=0x7cf), length 136 IP 10.0.10.46.4500 > 10.0.0.52.4500: UDP-encap: ESP(spi=0xca1c282d,seq=0x7cf), length 136 IP 10.0.0.52.4500 > 10.0.10.46.4500: UDP-encap: ESP(spi=0x43ef462d,seq=0x7d0), length 136 IP 10.0.10.46.4500 > 10.0.0.52.4500: UDP-encap: ESP(spi=0xca1c282d,seq=0x7d0), length 136 IP 10.0.0.53.4500 > 10.0.10.46.4500: NONESP-encap: isakmp: child_sa inf2[I] IP 10.0.10.46.4500 > 10.0.0.53.4500: NONESP-encap: isakmp: child_sa inf2[R] IP 10.0.0.53.4500 > 10.0.10.46.4500: NONESP-encap: isakmp: child_sa inf2[I] IP 10.0.10.46.4500 > 10.0.0.53.4500: NONESP-encap: isakmp: child_sa inf2[R] IP 10.0.0.53.4500 > 10.0.10.46.4500: UDP-encap: ESP(spi=0x43ef462d,seq=0x7d1), length 136 NOTE: next sequence is wrong 0x1 IP 10.0.10.46.4500 > 10.0.0.53.4500: UDP-encap: ESP(spi=0xca1c282d,seq=0x1), length 136 IP 10.0.0.53.4500 > 10.0.10.46.4500: UDP-encap: ESP(spi=0x43ef462d,seq=0x7d2), length 136 IP 10.0.10.46.4500 > 10.0.0.53.4500: UDP-encap: ESP(spi=0xca1c282d,seq=0x2), length 136 Signed-off-by: Antony Antony Reviewed-by: Richard Guy Briggs Signed-off-by: Steffen Klassert Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/xfrm/xfrm_state.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index fdb9742d934e..6f5635770d6a 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -1246,6 +1246,8 @@ static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig) x->curlft.add_time = orig->curlft.add_time; x->km.state = orig->km.state; x->km.seq = orig->km.seq; + x->replay = orig->replay; + x->preplay = orig->preplay; return x; -- GitLab From 581ec36f26ad69b70ec3ed4ee552bd38b961d917 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Mon, 15 May 2017 14:00:31 -0700 Subject: [PATCH 1069/1834] ASoC: simple-card: fix mic jack initialization [ Upstream commit f746aa5e8636c83e53bbb2d988bb614f732b2b80 ] Initialize asoc_simple_card_init_mic with the correct struct asoc_simple_jack. Fixes: 9eac361877b3 ("ASoC: simple-card: add new asoc_simple_jack and use it") Signed-off-by: Stefan Agner Acked-by: Kuninori Morimoto Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/generic/simple-card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index dd88c2cb6470..48804e4ab530 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -201,7 +201,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) if (ret < 0) return ret; - ret = asoc_simple_card_init_mic(rtd->card, &priv->hp_jack, PREFIX); + ret = asoc_simple_card_init_mic(rtd->card, &priv->mic_jack, PREFIX); if (ret < 0) return ret; -- GitLab From a1aeeacc646dc2e576512988b7f721751c0373ef Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Fri, 19 May 2017 17:48:00 +0300 Subject: [PATCH 1070/1834] iio: hi8435: avoid garbage event at first enable [ Upstream commit ee19ac340c5fdfd89c6348be4563453c61ab54a9 ] Currently, driver generates events for channels if new reading differs from previous one. This "previous value" is initialized to zero, which results into event if value is constant-one. Fix that by initializing "previous value" by reading at event enable time. This provides reliable sequence for userspace: - enable event, - AFTER THAT read current value, - AFTER THAT each event will correspond to change. Signed-off-by: Nikita Yushchenko Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/hi8435.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 678e8c7ea763..52b2dcf1d942 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -121,10 +121,21 @@ static int hi8435_write_event_config(struct iio_dev *idev, enum iio_event_direction dir, int state) { struct hi8435_priv *priv = iio_priv(idev); + int ret; + u32 tmp; + + if (state) { + ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp); + if (ret < 0) + return ret; + if (tmp & BIT(chan->channel)) + priv->event_prev_val |= BIT(chan->channel); + else + priv->event_prev_val &= ~BIT(chan->channel); - priv->event_scan_mask &= ~BIT(chan->channel); - if (state) priv->event_scan_mask |= BIT(chan->channel); + } else + priv->event_scan_mask &= ~BIT(chan->channel); return 0; } -- GitLab From e187c0c9104db9271afa0c2b63c403ace286b93d Mon Sep 17 00:00:00 2001 From: Nikita Yushchenko Date: Fri, 19 May 2017 17:48:02 +0300 Subject: [PATCH 1071/1834] iio: hi8435: cleanup reset gpio [ Upstream commit 61305664a542f874283f74bf0b27ddb31f5045d7 ] Reset GPIO is active low. Currently driver uses gpiod_set_value(1) to clean reset, which depends on device tree to contain GPIO_ACTIVE_HIGH - that does not match reality. This fixes driver to use _raw version of gpiod_set_value() to enforce active-low semantics despite of what's written in device tree. Allowing device tree to override that only opens possibility for errors and does not add any value. Additionally, use _cansleep version to make things work with i2c-gpio and other sleeping gpio drivers. Signed-off-by: Nikita Yushchenko Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iio/adc/hi8435.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c index 52b2dcf1d942..fec696ec3fd1 100644 --- a/drivers/iio/adc/hi8435.c +++ b/drivers/iio/adc/hi8435.c @@ -453,13 +453,15 @@ static int hi8435_probe(struct spi_device *spi) priv->spi = spi; reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW); - if (IS_ERR(reset_gpio)) { - /* chip s/w reset if h/w reset failed */ + if (!IS_ERR(reset_gpio)) { + /* need >=100ns low pulse to reset chip */ + gpiod_set_raw_value_cansleep(reset_gpio, 0); + udelay(1); + gpiod_set_raw_value_cansleep(reset_gpio, 1); + } else { + /* s/w reset chip if h/w reset is not available */ hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST); hi8435_writeb(priv, HI8435_CTRL_REG, 0); - } else { - udelay(5); - gpiod_set_value(reset_gpio, 1); } spi_set_drvdata(spi, idev); -- GitLab From 691b03605d23f49888e1743467362b6bb730942a Mon Sep 17 00:00:00 2001 From: Mikko Koivunen Date: Thu, 18 May 2017 15:12:50 +0300 Subject: [PATCH 1072/1834] iio: light: rpr0521 poweroff for probe fails [ Upstream commit 12d74949133e2450533894ea01ce0c56646ce006 ] Set sensor measurement off after probe fail in pm_runtime_set_active() or iio_device_register(). Without this change sensor measurement stays on even though probe fails on these calls. This is maybe rare case, but causes constant power drain without any benefits when it happens. Power drain is 20-500uA, typically 180uA. Signed-off-by: Mikko Koivunen Acked-by: Daniel Baluta Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iio/light/rpr0521.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/iio/light/rpr0521.c b/drivers/iio/light/rpr0521.c index 7de0f397194b..d23cf7759ee7 100644 --- a/drivers/iio/light/rpr0521.c +++ b/drivers/iio/light/rpr0521.c @@ -510,13 +510,26 @@ static int rpr0521_probe(struct i2c_client *client, ret = pm_runtime_set_active(&client->dev); if (ret < 0) - return ret; + goto err_poweroff; pm_runtime_enable(&client->dev); pm_runtime_set_autosuspend_delay(&client->dev, RPR0521_SLEEP_DELAY_MS); pm_runtime_use_autosuspend(&client->dev); - return iio_device_register(indio_dev); + ret = iio_device_register(indio_dev); + if (ret) + goto err_pm_disable; + + return 0; + +err_pm_disable: + pm_runtime_disable(&client->dev); + pm_runtime_set_suspended(&client->dev); + pm_runtime_put_noidle(&client->dev); +err_poweroff: + rpr0521_poweroff(data); + + return ret; } static int rpr0521_remove(struct i2c_client *client) -- GitLab From a90e0450d203c8f13f966e62638f146b46b977f8 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Sun, 21 May 2017 22:35:23 -0400 Subject: [PATCH 1073/1834] ext4: handle the rest of ext4_mb_load_buddy() ENOMEM errors [ Upstream commit 9651e6b2e20648d04d5e1fe6479a3056047e8781 ] I've got another report about breaking ext4 by ENOMEM error returned from ext4_mb_load_buddy() caused by memory shortage in memory cgroup. This time inside ext4_discard_preallocations(). This patch replaces ext4_error() with ext4_warning() where errors returned from ext4_mb_load_buddy() are not fatal and handled by caller: * ext4_mb_discard_group_preallocations() - called before generating ENOSPC, we'll try to discard other group or return ENOSPC into user-space. * ext4_trim_all_free() - just stop trimming and return ENOMEM from ioctl. Some callers cannot handle errors, thus __GFP_NOFAIL is used for them: * ext4_discard_preallocations() * ext4_mb_discard_lg_preallocations() Fixes: adb7ef600cc9 ("ext4: use __GFP_NOFAIL in ext4_free_blocks()") Signed-off-by: Konstantin Khlebnikov Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ext4/mballoc.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 64056c6eb857..14bd37041e1a 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -3877,7 +3877,8 @@ ext4_mb_discard_group_preallocations(struct super_block *sb, err = ext4_mb_load_buddy(sb, group, &e4b); if (err) { - ext4_error(sb, "Error loading buddy information for %u", group); + ext4_warning(sb, "Error %d loading buddy information for %u", + err, group); put_bh(bitmap_bh); return 0; } @@ -4034,10 +4035,11 @@ void ext4_discard_preallocations(struct inode *inode) BUG_ON(pa->pa_type != MB_INODE_PA); group = ext4_get_group_number(sb, pa->pa_pstart); - err = ext4_mb_load_buddy(sb, group, &e4b); + err = ext4_mb_load_buddy_gfp(sb, group, &e4b, + GFP_NOFS|__GFP_NOFAIL); if (err) { - ext4_error(sb, "Error loading buddy information for %u", - group); + ext4_error(sb, "Error %d loading buddy information for %u", + err, group); continue; } @@ -4293,11 +4295,14 @@ ext4_mb_discard_lg_preallocations(struct super_block *sb, spin_unlock(&lg->lg_prealloc_lock); list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) { + int err; group = ext4_get_group_number(sb, pa->pa_pstart); - if (ext4_mb_load_buddy(sb, group, &e4b)) { - ext4_error(sb, "Error loading buddy information for %u", - group); + err = ext4_mb_load_buddy_gfp(sb, group, &e4b, + GFP_NOFS|__GFP_NOFAIL); + if (err) { + ext4_error(sb, "Error %d loading buddy information for %u", + err, group); continue; } ext4_lock_group(sb, group); @@ -5117,8 +5122,8 @@ ext4_trim_all_free(struct super_block *sb, ext4_group_t group, ret = ext4_mb_load_buddy(sb, group, &e4b); if (ret) { - ext4_error(sb, "Error in loading buddy " - "information for %u", group); + ext4_warning(sb, "Error %d loading buddy information for %u", + ret, group); return ret; } bitmap = e4b.bd_bitmap; -- GitLab From 03858f5f7ad86a1b8332e4a3329b7757c34da30c Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Tue, 16 May 2017 14:01:25 +0800 Subject: [PATCH 1074/1834] md-cluster: fix potential lock issue in add_new_disk [ Upstream commit 2dffdc0724004f38f5e39907747b53e4b0d80e59 ] The add_new_disk returns with communication locked if __sendmsg returns failure, fix it with call unlock_comm before return. Reported-by: Dan Carpenter CC: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: Shaohua Li Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/md-cluster.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index ba7edcdd09ce..fcc2b5746a9f 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -1122,8 +1122,10 @@ static int add_new_disk(struct mddev *mddev, struct md_rdev *rdev) cmsg.raid_slot = cpu_to_le32(rdev->desc_nr); lock_comm(cinfo); ret = __sendmsg(cinfo, &cmsg); - if (ret) + if (ret) { + unlock_comm(cinfo); return ret; + } cinfo->no_new_dev_lockres->flags |= DLM_LKF_NOQUEUE; ret = dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_EX); cinfo->no_new_dev_lockres->flags &= ~DLM_LKF_NOQUEUE; -- GitLab From caead37e3aebbe1b3b9c11664fc9f102e35f42f7 Mon Sep 17 00:00:00 2001 From: Suman Anna Date: Tue, 16 May 2017 17:13:45 -0500 Subject: [PATCH 1075/1834] ARM: davinci: da8xx: Create DSP device only when assigned memory [ Upstream commit f97f03578b997a8ec2b9bc4928f958a865137268 ] The DSP device on Davinci platforms does not have an MMU and requires specific DDR memory to boot. This memory is reserved using the rproc_mem kernel boot parameter and is assigned to the device on non-DT boots. The remoteproc core uses the DMA API and so will fall back to assigning random memory if this memory is not assigned to the device, but the DSP remote processor boot will not be successful in such cases. So, check that memory has been reserved and assigned to the device specifically before even creating the DSP device. Signed-off-by: Suman Anna Signed-off-by: Sekhar Nori Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-davinci/devices-da8xx.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c index add3771d38f6..9a22d40602aa 100644 --- a/arch/arm/mach-davinci/devices-da8xx.c +++ b/arch/arm/mach-davinci/devices-da8xx.c @@ -821,6 +821,8 @@ static struct platform_device da8xx_dsp = { .resource = da8xx_rproc_resources, }; +static bool rproc_mem_inited __initdata; + #if IS_ENABLED(CONFIG_DA8XX_REMOTEPROC) static phys_addr_t rproc_base __initdata; @@ -859,6 +861,8 @@ void __init da8xx_rproc_reserve_cma(void) ret = dma_declare_contiguous(&da8xx_dsp.dev, rproc_size, rproc_base, 0); if (ret) pr_err("%s: dma_declare_contiguous failed %d\n", __func__, ret); + else + rproc_mem_inited = true; } #else @@ -873,6 +877,12 @@ int __init da8xx_register_rproc(void) { int ret; + if (!rproc_mem_inited) { + pr_warn("%s: memory not reserved for DSP, not registering DSP device\n", + __func__); + return -ENOMEM; + } + ret = platform_device_register(&da8xx_dsp); if (ret) pr_err("%s: can't register DSP device: %d\n", __func__, ret); -- GitLab From 87aa297871ee0d05d45648ba647cb0ea0485884c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 5 May 2017 15:38:41 -0700 Subject: [PATCH 1076/1834] ray_cs: Avoid reading past end of buffer [ Upstream commit e48d661eb13f2f83861428f001c567fdb3f317e8 ] Using memcpy() from a buffer that is shorter than the length copied means the destination buffer is being filled with arbitrary data from the kernel rodata segment. In this case, the source was made longer, since it did not match the destination structure size. Additionally removes a needless cast. This was found with the future CONFIG_FORTIFY_SOURCE feature. Cc: Daniel Micay Signed-off-by: Kees Cook Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ray_cs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 0881ba8535f4..c78abfc7bd96 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -247,7 +247,10 @@ static const UCHAR b4_default_startup_parms[] = { 0x04, 0x08, /* Noise gain, limit offset */ 0x28, 0x28, /* det rssi, med busy offsets */ 7, /* det sync thresh */ - 0, 2, 2 /* test mode, min, max */ + 0, 2, 2, /* test mode, min, max */ + 0, /* rx/tx delay */ + 0, 0, 0, 0, 0, 0, /* current BSS id */ + 0 /* hop set */ }; /*===========================================================================*/ @@ -598,7 +601,7 @@ static void init_startup_params(ray_dev_t *local) * a_beacon_period = hops a_beacon_period = KuS *//* 64ms = 010000 */ if (local->fw_ver == 0x55) { - memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms, + memcpy(&local->sparm.b4, b4_default_startup_parms, sizeof(struct b4_startup_params)); /* Translate sane kus input values to old build 4/5 format */ /* i = hop time in uS truncated to 3 bytes */ -- GitLab From 69f4dd14771cad36c38640ff3f5c537bc6b97762 Mon Sep 17 00:00:00 2001 From: Holger Brunck Date: Mon, 22 May 2017 09:31:15 +0200 Subject: [PATCH 1077/1834] net/wan/fsl_ucc_hdlc: fix muram allocation error [ Upstream commit 85deed56032b6c98b541895bfda9bdd74f6ed987 ] sizeof(priv->ucc_pram) is 4 as it is the size of a pointer, but we want to reserve space for the struct ucc_hdlc_param. Signed-off-by: Holger Brunck Cc: Zhao Qiang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wan/fsl_ucc_hdlc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wan/fsl_ucc_hdlc.c b/drivers/net/wan/fsl_ucc_hdlc.c index dcd5ff43a946..a8bd68f252e9 100644 --- a/drivers/net/wan/fsl_ucc_hdlc.c +++ b/drivers/net/wan/fsl_ucc_hdlc.c @@ -158,7 +158,7 @@ static int uhdlc_init(struct ucc_hdlc_private *priv) } /* Alloc parameter ram for ucc hdlc */ - priv->ucc_pram_offset = qe_muram_alloc(sizeof(priv->ucc_pram), + priv->ucc_pram_offset = qe_muram_alloc(sizeof(struct ucc_hdlc_param), ALIGNMENT_OF_UCC_HDLC_PRAM); if (priv->ucc_pram_offset < 0) { -- GitLab From 1a53869c4c3406d841093c8e5e0649e5f6de80ac Mon Sep 17 00:00:00 2001 From: Tin Huynh Date: Mon, 22 May 2017 16:19:20 +0700 Subject: [PATCH 1078/1834] leds: pca955x: Correct I2C Functionality [ Upstream commit aace34c0bb8ea3c8bdcec865b6a4be4db0a68e33 ] The driver checks an incorrect flag of functionality of adapter. When a driver requires i2c_smbus_read_byte_data and i2c_smbus_write_byte_data, it should check I2C_FUNC_SMBUS_BYTE_DATA instead I2C_FUNC_I2C. This patch fixes the problem. Signed-off-by: Tin Huynh Signed-off-by: Jacek Anaszewski Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/leds/leds-pca955x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c index 840401ae9a4e..f6726484a8a1 100644 --- a/drivers/leds/leds-pca955x.c +++ b/drivers/leds/leds-pca955x.c @@ -266,7 +266,7 @@ static int pca955x_probe(struct i2c_client *client, "slave address 0x%02x\n", id->name, chip->bits, client->addr); - if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; if (pdata) { -- GitLab From f02bfec06f148d1aa2c08b8ecdc3afbc31ec0b6f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 May 2017 12:04:18 +0300 Subject: [PATCH 1079/1834] perf/core: Fix error handling in perf_event_alloc() [ Upstream commit 36cc2b9222b5106de34085c4dd8635ac67ef5cba ] We don't set an error code here which means that perf_event_alloc() returns ERR_PTR(0) (in other words NULL). The callers are not expecting that and would Oops. Signed-off-by: Dan Carpenter Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: 375637bc5249 ("perf/core: Introduce address range filtering") Link: http://lkml.kernel.org/r/20170522090418.hvs6icgpdo53wkn5@mwanda Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/events/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 13b9784427b0..d7914fa6bc09 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9289,8 +9289,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, event->addr_filters_offs = kcalloc(pmu->nr_addr_filters, sizeof(unsigned long), GFP_KERNEL); - if (!event->addr_filters_offs) + if (!event->addr_filters_offs) { + err = -ENOMEM; goto err_per_task; + } /* force hw sync on the address filters */ event->addr_filters_gen = 1; -- GitLab From a1e7a9e2e3c992574a19493566aff6580a2d5ad5 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Mon, 15 May 2017 15:13:16 +0200 Subject: [PATCH 1080/1834] sched/numa: Use down_read_trylock() for the mmap_sem [ Upstream commit 8655d5497735b288f8a9b458bd22e7d1bf95bb61 ] A customer has reported a soft-lockup when running an intensive memory stress test, where the trace on multiple CPU's looks like this: RIP: 0010:[] [] native_queued_spin_lock_slowpath+0x10e/0x190 ... Call Trace: [] queued_spin_lock_slowpath+0x7/0xa [] change_protection_range+0x3b1/0x930 [] change_prot_numa+0x18/0x30 [] task_numa_work+0x1fe/0x310 [] task_work_run+0x72/0x90 Further investigation showed that the lock contention here is pmd_lock(). The task_numa_work() function makes sure that only one thread is let to perform the work in a single scan period (via cmpxchg), but if there's a thread with mmap_sem locked for writing for several periods, multiple threads in task_numa_work() can build up a convoy waiting for mmap_sem for read and then all get unblocked at once. This patch changes the down_read() to the trylock version, which prevents the build up. For a workload experiencing mmap_sem contention, it's probably better to postpone the NUMA balancing work anyway. This seems to have fixed the soft lockups involving pmd_lock(), which is in line with the convoy theory. Signed-off-by: Vlastimil Babka Signed-off-by: Peter Zijlstra (Intel) Acked-by: Rik van Riel Acked-by: Mel Gorman Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/20170515131316.21909-1-vbabka@suse.cz Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/sched/fair.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 3d862f5b0331..f6e8727f7fa3 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -2429,7 +2429,8 @@ void task_numa_work(struct callback_head *work) return; - down_read(&mm->mmap_sem); + if (!down_read_trylock(&mm->mmap_sem)) + return; vma = find_vma(mm, start); if (!vma) { reset_ptenuma_scan(p); -- GitLab From 72185b9770fc588bc277e4e5336e9cdf7c42ad45 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 13 May 2017 14:39:53 +0200 Subject: [PATCH 1081/1834] gpio: crystalcove: Do not write regular gpio registers for virtual GPIOs [ Upstream commit 9a752b4c9ab924033bfdb8784c680d50b2bd5684 ] The Crystal Cove PMIC has 16 real GPIOs but the ACPI code for devices with this PMIC may address up to 95 GPIOs, these extra GPIOs are called virtual GPIOs and are used by the ACPI code as a method of accessing various non GPIO bits of PMIC. Commit dcdc3018d635 ("gpio: crystalcove: support virtual GPIO") added dummy support for these to avoid a bunch of ACPI errors, but instead of ignoring writes / reads to them by doing: if (gpio >= CRYSTALCOVE_GPIO_NUM) return 0; It accidentally introduced the following wrong check: if (gpio > CRYSTALCOVE_VGPIO_NUM) return 0; Which means that attempts by the ACPI code to access these gpios causes some arbitrary gpio to get touched through for example GPIO1P0CTLO + gpionr % 8. Since we do support input/output (but not interrupts) on the 0x5e virtual GPIO, this commit makes to_reg return -ENOTSUPP for unsupported virtual GPIOs so as to not have to check for (gpio >= CRYSTALCOVE_GPIO_NUM && gpio != 0x5e) everywhere and to make it easier to add support for more virtual GPIOs in the future. It then adds a check for to_reg returning an error to all callers where this may happen fixing the ACPI code accessing virtual GPIOs accidentally causing changes to real GPIOs. Fixes: dcdc3018d635 ("gpio: crystalcove: support virtual GPIO") Cc: Aaron Lu Signed-off-by: Hans de Goede Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpio-crystalcove.c | 54 ++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c index 7c446d118cd6..1d87b0718d3a 100644 --- a/drivers/gpio/gpio-crystalcove.c +++ b/drivers/gpio/gpio-crystalcove.c @@ -90,8 +90,18 @@ static inline int to_reg(int gpio, enum ctrl_register reg_type) { int reg; - if (gpio == 94) - return GPIOPANELCTL; + if (gpio >= CRYSTALCOVE_GPIO_NUM) { + /* + * Virtual GPIO called from ACPI, for now we only support + * the panel ctl. + */ + switch (gpio) { + case 0x5e: + return GPIOPANELCTL; + default: + return -EOPNOTSUPP; + } + } if (reg_type == CTRL_IN) { if (gpio < 8) @@ -130,36 +140,36 @@ static void crystalcove_update_irq_ctrl(struct crystalcove_gpio *cg, int gpio) static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), - CTLO_INPUT_SET); + return regmap_write(cg->regmap, reg, CTLO_INPUT_SET); } static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, int value) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - return regmap_write(cg->regmap, to_reg(gpio, CTRL_OUT), - CTLO_OUTPUT_SET | value); + return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value); } static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); - int ret; unsigned int val; + int ret, reg = to_reg(gpio, CTRL_IN); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return 0; - ret = regmap_read(cg->regmap, to_reg(gpio, CTRL_IN), &val); + ret = regmap_read(cg->regmap, reg, &val); if (ret) return ret; @@ -170,14 +180,15 @@ static void crystalcove_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) { struct crystalcove_gpio *cg = gpiochip_get_data(chip); + int reg = to_reg(gpio, CTRL_OUT); - if (gpio > CRYSTALCOVE_VGPIO_NUM) + if (reg < 0) return; if (value) - regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 1); + regmap_update_bits(cg->regmap, reg, 1, 1); else - regmap_update_bits(cg->regmap, to_reg(gpio, CTRL_OUT), 1, 0); + regmap_update_bits(cg->regmap, reg, 1, 0); } static int crystalcove_irq_type(struct irq_data *data, unsigned type) @@ -185,6 +196,9 @@ static int crystalcove_irq_type(struct irq_data *data, unsigned type) struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); + if (data->hwirq >= CRYSTALCOVE_GPIO_NUM) + return 0; + switch (type) { case IRQ_TYPE_NONE: cg->intcnt_value = CTLI_INTCNT_DIS; @@ -235,8 +249,10 @@ static void crystalcove_irq_unmask(struct irq_data *data) struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); - cg->set_irq_mask = false; - cg->update |= UPDATE_IRQ_MASK; + if (data->hwirq < CRYSTALCOVE_GPIO_NUM) { + cg->set_irq_mask = false; + cg->update |= UPDATE_IRQ_MASK; + } } static void crystalcove_irq_mask(struct irq_data *data) @@ -244,8 +260,10 @@ static void crystalcove_irq_mask(struct irq_data *data) struct crystalcove_gpio *cg = gpiochip_get_data(irq_data_get_irq_chip_data(data)); - cg->set_irq_mask = true; - cg->update |= UPDATE_IRQ_MASK; + if (data->hwirq < CRYSTALCOVE_GPIO_NUM) { + cg->set_irq_mask = true; + cg->update |= UPDATE_IRQ_MASK; + } } static struct irq_chip crystalcove_irqchip = { -- GitLab From 2c582b6bac13e495d6c14fdd1f866b93ff90cddc Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 18 May 2017 13:34:43 +0300 Subject: [PATCH 1082/1834] net/mlx5: Tolerate irq_set_affinity_hint() failures [ Upstream commit b665d98edc9ab295169be2fc5bb4e89a46de0a1a ] Add tolerance to failures of irq_set_affinity_hint(). Its role is to give hints that optimizes performance, and should not block the driver load. In non-SMP systems, functionality is not available as there is a single core, and all these calls definitely fail. Hence, do not call the function and avoid the warning prints. Fixes: db058a186f98 ("net/mlx5_core: Set irq affinity hints") Signed-off-by: Tariq Toukan Cc: kernel-team@fb.com Signed-off-by: Saeed Mahameed Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 981cd1d84a5b..935e62635f12 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -548,7 +548,6 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) struct mlx5_priv *priv = &mdev->priv; struct msix_entry *msix = priv->msix_arr; int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector; - int err; if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) { mlx5_core_warn(mdev, "zalloc_cpumask_var failed"); @@ -558,18 +557,12 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node), priv->irq_info[i].mask); - err = irq_set_affinity_hint(irq, priv->irq_info[i].mask); - if (err) { - mlx5_core_warn(mdev, "irq_set_affinity_hint failed,irq 0x%.4x", - irq); - goto err_clear_mask; - } +#ifdef CONFIG_SMP + if (irq_set_affinity_hint(irq, priv->irq_info[i].mask)) + mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq); +#endif return 0; - -err_clear_mask: - free_cpumask_var(priv->irq_info[i].mask); - return err; } static void mlx5_irq_clear_affinity_hint(struct mlx5_core_dev *mdev, int i) -- GitLab From b983b2a5969c9ee4e2ec73ff3444ec6814441cb8 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Fri, 12 May 2017 12:41:24 -0400 Subject: [PATCH 1083/1834] selinux: do not check open permission on sockets [ Upstream commit ccb544781d34afdb73a9a73ae53035d824d193bf ] open permission is currently only defined for files in the kernel (COMMON_FILE_PERMS rather than COMMON_FILE_SOCK_PERMS). Construction of an artificial test case that tries to open a socket via /proc/pid/fd will generate a recvfrom avc denial because recvfrom and open happen to map to the same permission bit in socket vs file classes. open of a socket via /proc/pid/fd is not supported by the kernel regardless and will ultimately return ENXIO. But we hit the permission check first and can thus produce these odd/misleading denials. Omit the open check when operating on a socket. Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- security/selinux/hooks.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 17627d8d5a26..8ded80867b92 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -2033,8 +2033,9 @@ static inline u32 file_to_av(struct file *file) static inline u32 open_file_to_av(struct file *file) { u32 av = file_to_av(file); + struct inode *inode = file_inode(file); - if (selinux_policycap_openperm) + if (selinux_policycap_openperm && inode->i_sb->s_magic != SOCKFS_MAGIC) av |= FILE__OPEN; return av; @@ -3031,6 +3032,7 @@ static int selinux_inode_permission(struct inode *inode, int mask) static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) { const struct cred *cred = current_cred(); + struct inode *inode = d_backing_inode(dentry); unsigned int ia_valid = iattr->ia_valid; __u32 av = FILE__WRITE; @@ -3046,8 +3048,10 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) return dentry_has_perm(cred, dentry, FILE__SETATTR); - if (selinux_policycap_openperm && (ia_valid & ATTR_SIZE) - && !(ia_valid & ATTR_FILE)) + if (selinux_policycap_openperm && + inode->i_sb->s_magic != SOCKFS_MAGIC && + (ia_valid & ATTR_SIZE) && + !(ia_valid & ATTR_FILE)) av |= FILE__OPEN; return dentry_has_perm(cred, dentry, av); -- GitLab From e66876452456a209daa7e1bc63539d9be50d9ad6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 23 May 2017 17:28:36 +0300 Subject: [PATCH 1084/1834] block: fix an error code in add_partition() [ Upstream commit 7bd897cfce1eb373892d35d7f73201b0f9b221c4 ] We don't set an error code on this path. It means that we return NULL instead of an error pointer and the caller does a NULL dereference. Fixes: 6d1d8050b4bc ("block, partition: add partition_meta_info to hd_struct") Signed-off-by: Dan Carpenter Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/partition-generic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/block/partition-generic.c b/block/partition-generic.c index a2437c006640..298c05f8b5e3 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -321,8 +321,10 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, if (info) { struct partition_meta_info *pinfo = alloc_part_info(disk); - if (!pinfo) + if (!pinfo) { + err = -ENOMEM; goto out_free_stats; + } memcpy(pinfo, info, sizeof(*info)); p->info = pinfo; } -- GitLab From 8adab3b9ea235e156130789bbc1c97c796ab9598 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Mon, 22 May 2017 20:13:07 +0200 Subject: [PATCH 1085/1834] mlx5: fix bug reading rss_hash_type from CQE [ Upstream commit 12e8b570e732eaa5eae3a2895ba3fbcf91bde2b4 ] Masks for extracting part of the Completion Queue Entry (CQE) field rss_hash_type was swapped, namely CQE_RSS_HTYPE_IP and CQE_RSS_HTYPE_L4. The bug resulted in setting skb->l4_hash, even-though the rss_hash_type indicated that hash was NOT computed over the L4 (UDP or TCP) part of the packet. Added comments from the datasheet, to make it more clear what these masks are selecting. Signed-off-by: Jesper Dangaard Brouer Acked-by: Saeed Mahameed Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/mlx5/device.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 58276144ba81..5f3e62253e2f 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -750,8 +750,14 @@ enum { }; enum { - CQE_RSS_HTYPE_IP = 0x3 << 6, - CQE_RSS_HTYPE_L4 = 0x3 << 2, + CQE_RSS_HTYPE_IP = 0x3 << 2, + /* cqe->rss_hash_type[3:2] - IP destination selected for hash + * (00 = none, 01 = IPv4, 10 = IPv6, 11 = Reserved) + */ + CQE_RSS_HTYPE_L4 = 0x3 << 6, + /* cqe->rss_hash_type[7:6] - L4 destination selected for hash + * (00 = none, 01 = TCP. 10 = UDP, 11 = IPSEC.SPI + */ }; enum { -- GitLab From 9fc2a46aded05d2ed0e9e05f5156fc7c91b49a4b Mon Sep 17 00:00:00 2001 From: Lin Zhang Date: Tue, 23 May 2017 13:29:39 +0800 Subject: [PATCH 1086/1834] net: ieee802154: fix net_device reference release too early [ Upstream commit a611c58b3d42a92e6b23423e166dd17c0c7fffce ] This patch fixes the kernel oops when release net_device reference in advance. In function raw_sendmsg(i think the dgram_sendmsg has the same problem), there is a race condition between dev_put and dev_queue_xmit when the device is gong that maybe lead to dev_queue_ximt to see an illegal net_device pointer. My test kernel is 3.13.0-32 and because i am not have a real 802154 device, so i change lowpan_newlink function to this: /* find and hold real wpan device */ real_dev = dev_get_by_index(src_net, nla_get_u32(tb[IFLA_LINK])); if (!real_dev) return -ENODEV; // if (real_dev->type != ARPHRD_IEEE802154) { // dev_put(real_dev); // return -EINVAL; // } lowpan_dev_info(dev)->real_dev = real_dev; lowpan_dev_info(dev)->fragment_tag = 0; mutex_init(&lowpan_dev_info(dev)->dev_list_mtx); Also, in order to simulate preempt, i change the raw_sendmsg function to this: skb->dev = dev; skb->sk = sk; skb->protocol = htons(ETH_P_IEEE802154); dev_put(dev); //simulate preempt schedule_timeout_uninterruptible(30 * HZ); err = dev_queue_xmit(skb); if (err > 0) err = net_xmit_errno(err); and this is my userspace test code named test_send_data: int main(int argc, char **argv) { char buf[127]; int sockfd; sockfd = socket(AF_IEEE802154, SOCK_RAW, 0); if (sockfd < 0) { printf("create sockfd error: %s\n", strerror(errno)); return -1; } send(sockfd, buf, sizeof(buf), 0); return 0; } This is my test case: root@zhanglin-x-computer:~/develop/802154# uname -a Linux zhanglin-x-computer 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux root@zhanglin-x-computer:~/develop/802154# ip link add link eth0 name lowpan0 type lowpan root@zhanglin-x-computer:~/develop/802154# //keep the lowpan0 device down root@zhanglin-x-computer:~/develop/802154# ./test_send_data & //wait a while root@zhanglin-x-computer:~/develop/802154# ip link del link dev lowpan0 //the device is gone //oops [381.303307] general protection fault: 0000 [#1]SMP [381.303407] Modules linked in: af_802154 6lowpan bnep rfcomm bluetooth nls_iso8859_1 snd_hda_codec_hdmi snd_hda_codec_realtek rts5139(C) snd_hda_intel snd_had_codec snd_hwdep snd_pcm snd_page_alloc snd_seq_midi snd_seq_midi_event snd_rawmidi snd_req intel_rapl snd_seq_device coretemp i915 kvm_intel kvm snd_timer snd crct10dif_pclmul crc32_pclmul ghash_clmulni_intel cypted drm_kms_helper drm i2c_algo_bit soundcore video mac_hid parport_pc ppdev ip parport hid_generic usbhid hid ahci r8169 mii libahdi [381.304286] CPU:1 PID: 2524 Commm: 1 Tainted: G C 0 3.13.0-32-generic [381.304409] Hardware name: Haier Haier DT Computer/Haier DT Codputer, BIOS FIBT19H02_X64 06/09/2014 [381.304546] tasks: ffff000096965fc0 ti: ffffB0013779c000 task.ti: ffffB8013779c000 [381.304659] RIP: 0010:[] [] __dev_queue_ximt+0x61/0x500 [381.304798] RSP: 0018:ffffB8013779dca0 EFLAGS: 00010202 [381.304880] RAX: 272b031d57565351 RBX: 0000000000000000 RCX: ffff8800968f1a00 [381.304987] RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8800968f1a00 [381.305095] RBP: ffff8e013773dce0 R08: 0000000000000266 R09: 0000000000000004 [381.305202] R10: 0000000000000004 R11: 0000000000000005 R12: ffff88013902e000 [381.305310] R13: 000000000000007f R14: 000000000000007f R15: ffff8800968f1a00 [381.305418] FS: 00007fc57f50f740(0000) GS: ffff88013fc80000(0000) knlGS: 0000000000000000 [381.305540] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [381.305627] CR2: 00007fad0841c000 CR3: 00000001368dd000 CR4: 00000000001007e0 [361.905734] Stack: [381.305768] 00000000002052d0 000000003facb30a ffff88013779dcc0 ffff880137764000 [381.305898] ffff88013779de70 000000000000007f 000000000000007f ffff88013902e000 [381.306026] ffff88013779dcf0 ffffffff81622490 ffff88013779dd39 ffffffffa03af9f1 [381.306155] Call Trace: [381.306202] [] dev_queue_xmit+0x10/0x20 [381.306294] [] raw_sendmsg+0x1b1/0x270 [af_802154] [381.306396] [] ieee802154_sock_sendmsg+0x14/0x20 [af_802154] [381.306512] [] sock_sendmsg+0x8b/0xc0 [381.306600] [] ? __d_alloc+0x25/0x180 [381.306687] [] ? kmem_cache_alloc_trace+0x1c6/0x1f0 [381.306791] [] SYSC_sendto+0x121/0x1c0 [381.306878] [] ? vtime_account_user+x54/0x60 [381.306975] [] ? syscall_trace_enter+0x145/0x250 [381.307073] [] SyS_sendto+0xe/0x10 [381.307156] [] tracesys+0xe1/0xe6 [381.307233] Code: c6 a1 a4 ff 41 8b 57 78 49 8b 47 20 85 d2 48 8b 80 78 07 00 00 75 21 49 8b 57 18 48 85 d2 74 18 48 85 c0 74 13 8b 92 ac 01 00 00 <3b> 50 10 73 08 8b 44 90 14 41 89 47 78 41 f6 84 24 d5 00 00 00 [381.307801] RIP [] _dev_queue_xmit+0x61/0x500 [381.307901] RSP [381.347512] Kernel panic - not syncing: Fatal exception in interrupt [381.347747] drm_kms_helper: panic occurred, switching back to text console In my opinion, there is always exist a chance that the device is gong before call dev_queue_xmit. I think the latest kernel is have the same problem and that dev_put should be behind of the dev_queue_xmit. Signed-off-by: Lin Zhang Acked-by: Stefan Schmidt Signed-off-by: Marcel Holtmann Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ieee802154/socket.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ieee802154/socket.c b/net/ieee802154/socket.c index e0bd013a1e5e..bf5d26d83af0 100644 --- a/net/ieee802154/socket.c +++ b/net/ieee802154/socket.c @@ -304,12 +304,12 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) skb->sk = sk; skb->protocol = htons(ETH_P_IEEE802154); - dev_put(dev); - err = dev_queue_xmit(skb); if (err > 0) err = net_xmit_errno(err); + dev_put(dev); + return err ?: size; out_skb: @@ -693,12 +693,12 @@ static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) skb->sk = sk; skb->protocol = htons(ETH_P_IEEE802154); - dev_put(dev); - err = dev_queue_xmit(skb); if (err > 0) err = net_xmit_errno(err); + dev_put(dev); + return err ?: size; out_skb: -- GitLab From 0bd1a03e003716cd0b12600c3eeafbc2e202c320 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 23 May 2017 17:25:10 +0300 Subject: [PATCH 1087/1834] libceph: NULL deref on crush_decode() error path [ Upstream commit 293dffaad8d500e1a5336eeb90d544cf40d4fbd8 ] If there is not enough space then ceph_decode_32_safe() does a goto bad. We need to return an error code in that situation. The current code returns ERR_PTR(0) which is NULL. The callers are not expecting that and it results in a NULL dereference. Fixes: f24e9980eb86 ("ceph: OSD client") Signed-off-by: Dan Carpenter Reviewed-by: Ilya Dryomov Signed-off-by: Ilya Dryomov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ceph/osdmap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index d3f6c26425b3..255c0a075e49 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -295,6 +295,7 @@ static struct crush_map *crush_decode(void *pbyval, void *end) u32 yes; struct crush_rule *r; + err = -EINVAL; ceph_decode_32_safe(p, end, yes, bad); if (!yes) { dout("crush_decode NO rule %d off %x %p to %p\n", -- GitLab From 695d3a35e49cedfc1aec195acabb165fdccac0fe Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Wed, 24 May 2017 15:21:25 +0900 Subject: [PATCH 1088/1834] perf report: Fix off-by-one for non-activation frames [ Upstream commit 1982ad48fc82c284a5cc55697a012d3357e84d01 ] As the documentation for dwfl_frame_pc says, frames that are no activation frames need to have their program counter decremented by one to properly find the function of the caller. This fixes many cases where perf report currently attributes the cost to the next line. I.e. I have code like this: ~~~~~~~~~~~~~~~ #include #include using namespace std; int main() { this_thread::sleep_for(chrono::milliseconds(1000)); this_thread::sleep_for(chrono::milliseconds(100)); this_thread::sleep_for(chrono::milliseconds(10)); return 0; } ~~~~~~~~~~~~~~~ Now compile and record it: ~~~~~~~~~~~~~~~ g++ -std=c++11 -g -O2 test.cpp echo 1 | sudo tee /proc/sys/kernel/sched_schedstats perf record \ --event sched:sched_stat_sleep \ --event sched:sched_process_exit \ --event sched:sched_switch --call-graph=dwarf \ --output perf.data.raw \ ./a.out echo 0 | sudo tee /proc/sys/kernel/sched_schedstats perf inject --sched-stat --input perf.data.raw --output perf.data ~~~~~~~~~~~~~~~ Before this patch, the report clearly shows the off-by-one issue. Most notably, the last sleep invocation is incorrectly attributed to the "return 0;" line: ~~~~~~~~~~~~~~~ Overhead Source:Line ........ ........... 100.00% core.c:0 | ---__schedule core.c:0 schedule do_nanosleep hrtimer.c:0 hrtimer_nanosleep sys_nanosleep entry_SYSCALL_64_fastpath .tmp_entry_64.o:0 __nanosleep_nocancel .:0 std::this_thread::sleep_for > thread:323 | |--90.08%--main test.cpp:9 | __libc_start_main | _start | |--9.01%--main test.cpp:10 | __libc_start_main | _start | --0.91%--main test.cpp:13 __libc_start_main _start ~~~~~~~~~~~~~~~ With this patch here applied, the issue is fixed. The report becomes much more usable: ~~~~~~~~~~~~~~~ Overhead Source:Line ........ ........... 100.00% core.c:0 | ---__schedule core.c:0 schedule do_nanosleep hrtimer.c:0 hrtimer_nanosleep sys_nanosleep entry_SYSCALL_64_fastpath .tmp_entry_64.o:0 __nanosleep_nocancel .:0 std::this_thread::sleep_for > thread:323 | |--90.08%--main test.cpp:8 | __libc_start_main | _start | |--9.01%--main test.cpp:9 | __libc_start_main | _start | --0.91%--main test.cpp:10 __libc_start_main _start ~~~~~~~~~~~~~~~ Similarly it works for signal frames: ~~~~~~~~~~~~~~~ __noinline void bar(void) { volatile long cnt = 0; for (cnt = 0; cnt < 100000000; cnt++); } __noinline void foo(void) { bar(); } void sig_handler(int sig) { foo(); } int main(void) { signal(SIGUSR1, sig_handler); raise(SIGUSR1); foo(); return 0; } ~~~~~~~~~~~~~~~~ Before, the report wrongly points to `signal.c:29` after raise(): ~~~~~~~~~~~~~~~~ $ perf report --stdio --no-children -g srcline -s srcline ... 100.00% signal.c:11 | ---bar signal.c:11 | |--50.49%--main signal.c:29 | __libc_start_main | _start | --49.51%--0x33a8f raise .:0 main signal.c:29 __libc_start_main _start ~~~~~~~~~~~~~~~~ With this patch in, the issue is fixed and we instead get: ~~~~~~~~~~~~~~~~ 100.00% signal signal [.] bar | ---bar signal.c:11 | |--50.49%--main signal.c:29 | __libc_start_main | _start | --49.51%--0x33a8f raise .:0 main signal.c:27 __libc_start_main _start ~~~~~~~~~~~~~~~~ Note how this patch fixes this issue for both unwinding methods, i.e. both dwfl and libunwind. The former case is straight-forward thanks to dwfl_frame_pc(). For libunwind, we replace the functionality via unw_is_signal_frame() for any but the very first frame. Signed-off-by: Milian Wolff Signed-off-by: Namhyung Kim Cc: Arnaldo Carvalho de Melo Cc: Arnaldo Carvalho de Melo Cc: David Ahern Cc: Jiri Olsa Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: Yao Jin Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170524062129.32529-4-namhyung@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/unwind-libdw.c | 6 +++++- tools/perf/util/unwind-libunwind-local.c | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 783a53fb7a4e..7c4defce0115 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -167,12 +167,16 @@ frame_callback(Dwfl_Frame *state, void *arg) { struct unwind_info *ui = arg; Dwarf_Addr pc; + bool isactivation; - if (!dwfl_frame_pc(state, &pc, NULL)) { + if (!dwfl_frame_pc(state, &pc, &isactivation)) { pr_err("%s", dwfl_errmsg(-1)); return DWARF_CB_ABORT; } + if (!isactivation) + --pc; + return entry(pc, ui) || !(--ui->max_stack) ? DWARF_CB_ABORT : DWARF_CB_OK; } diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unwind-libunwind-local.c index 20c2e5743903..120383494ff2 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -646,6 +646,17 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, while (!ret && (unw_step(&c) > 0) && i < max_stack) { unw_get_reg(&c, UNW_REG_IP, &ips[i]); + + /* + * Decrement the IP for any non-activation frames. + * this is required to properly find the srcline + * for caller frames. + * See also the documentation for dwfl_frame_pc(), + * which this code tries to replicate. + */ + if (unw_is_signal_frame(&c) <= 0) + --ips[i]; + ++i; } -- GitLab From 2171500ab056060df54cc015f35560784447ab35 Mon Sep 17 00:00:00 2001 From: Liping Zhang Date: Sun, 21 May 2017 07:22:49 +0800 Subject: [PATCH 1089/1834] netfilter: ctnetlink: fix incorrect nf_ct_put during hash resize [ Upstream commit fefa92679dbe0c613e62b6c27235dcfbe9640ad1 ] If nf_conntrack_htable_size was adjusted by the user during the ct dump operation, we may invoke nf_ct_put twice for the same ct, i.e. the "last" ct. This will cause the ct will be freed but still linked in hash buckets. It's very easy to reproduce the problem by the following commands: # while : ; do echo $RANDOM > /proc/sys/net/netfilter/nf_conntrack_buckets done # while : ; do conntrack -L done # iperf -s 127.0.0.1 & # iperf -c 127.0.0.1 -P 60 -t 36000 After a while, the system will hang like this: NMI watchdog: BUG: soft lockup - CPU#1 stuck for 22s! [bash:20184] NMI watchdog: BUG: soft lockup - CPU#0 stuck for 22s! [iperf:20382] ... So at last if we find cb->args[1] is equal to "last", this means hash resize happened, then we can set cb->args[1] to 0 to fix the above issue. Fixes: d205dc40798d ("[NETFILTER]: ctnetlink: fix deadlock in table dumping") Signed-off-by: Liping Zhang Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_netlink.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index d49a4639465f..9e30fd0ab227 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -890,8 +890,13 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) } out: local_bh_enable(); - if (last) + if (last) { + /* nf ct hash resize happened, now clear the leftover. */ + if ((struct nf_conn *)cb->args[1] == last) + cb->args[1] = 0; + nf_ct_put(last); + } while (i) { i--; -- GitLab From 07b2a3287210618676773e5f0945a46739e7d4ae Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 20 May 2017 00:31:12 +0300 Subject: [PATCH 1090/1834] pNFS/flexfiles: missing error code in ff_layout_alloc_lseg() [ Upstream commit 662f9a105b4322b8559d448f86110e6ec24b8738 ] If xdr_inline_decode() fails then we end up returning ERR_PTR(0). The caller treats NULL returns as -ENOMEM so it doesn't really hurt runtime, but obviously we intended to set an error code here. Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver") Signed-off-by: Dan Carpenter Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/nfs/flexfilelayout/flexfilelayout.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 13abd608af0f..4539008502ce 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -475,6 +475,7 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, goto out_err_free; /* fh */ + rc = -EIO; p = xdr_inline_decode(&stream, 4); if (!p) goto out_err_free; -- GitLab From b3311f62ea227886f95f2f5176b25624f2c1e733 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 24 May 2017 01:17:10 +0000 Subject: [PATCH 1091/1834] ASoC: rsnd: SSI PIO adjust to 24bit mode [ Upstream commit 7819a942de7b993771bd9377babc80485fe7606b ] commit 90431eb49bff ("ASoC: rsnd: don't use PDTA bit for 24bit on SSI") fixups 24bit mode data alignment, but PIO was not cared. This patch fixes PIO mode 24bit data alignment Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/sh/rcar/ssi.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index fefa6ad5de8b..17e305b71fd9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -552,6 +552,13 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 *buf = (u32 *)(runtime->dma_area + rsnd_dai_pointer_offset(io, 0)); + int shift = 0; + + switch (runtime->sample_bits) { + case 32: + shift = 8; + break; + } /* * 8/16/32 data can be assesse to TDR/RDR register @@ -559,9 +566,9 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, * see rsnd_ssi_init() */ if (rsnd_io_is_play(io)) - rsnd_mod_write(mod, SSITDR, *buf); + rsnd_mod_write(mod, SSITDR, (*buf) << shift); else - *buf = rsnd_mod_read(mod, SSIRDR); + *buf = (rsnd_mod_read(mod, SSIRDR) >> shift); elapsed = rsnd_dai_pointer_update(io, sizeof(*buf)); } -- GitLab From 5cddd2f34166ecf24710728458539c024c905fdd Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Wed, 24 May 2017 14:09:44 +0200 Subject: [PATCH 1092/1834] scsi: bnx2fc: fix race condition in bnx2fc_get_host_stats() [ Upstream commit c2dd893a3b0772d1c680e109b9d5715d7f73022b ] If multiple tasks attempt to read the stats, it may happen that the start_req_done completion is re-initialized while still being used by another task, causing a list corruption. This patch fixes the bug by adding a mutex to serialize the calls to bnx2fc_get_host_stats(). WARNING: at lib/list_debug.c:48 list_del+0x6e/0xa0() (Not tainted) Hardware name: PowerEdge R820 list_del corruption. prev->next should be ffff882035627d90, but was ffff884069541588 Pid: 40267, comm: perl Not tainted 2.6.32-642.3.1.el6.x86_64 #1 Call Trace: [] ? warn_slowpath_common+0x91/0xe0 [] ? warn_slowpath_fmt+0x46/0x60 [] ? list_del+0x6e/0xa0 [] ? wait_for_common+0x14d/0x180 [] ? default_wake_function+0x0/0x20 [] ? wait_for_completion_timeout+0x13/0x20 [] ? bnx2fc_get_host_stats+0xa1/0x280 [bnx2fc] [] ? fc_stat_show+0x90/0xc0 [scsi_transport_fc] [] ? show_fcstat_tx_frames+0x16/0x20 [scsi_transport_fc] [] ? dev_attr_show+0x27/0x50 [] ? __get_free_pages+0xe/0x50 [] ? sysfs_read_file+0x111/0x200 [] ? vfs_read+0xb5/0x1a0 [] ? fget_light_pos+0x16/0x50 [] ? sys_read+0x51/0xb0 [] ? __audit_syscall_exit+0x25e/0x290 [] ? system_call_fastpath+0x16/0x1b Signed-off-by: Maurizio Lombardi Acked-by: Chad Dupuis Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/bnx2fc/bnx2fc.h | 1 + drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h index fdd4eb4e41b2..e58786f797d9 100644 --- a/drivers/scsi/bnx2fc/bnx2fc.h +++ b/drivers/scsi/bnx2fc/bnx2fc.h @@ -191,6 +191,7 @@ struct bnx2fc_hba { struct bnx2fc_cmd_mgr *cmd_mgr; spinlock_t hba_lock; struct mutex hba_mutex; + struct mutex hba_stats_mutex; unsigned long adapter_state; #define ADAPTER_STATE_UP 0 #define ADAPTER_STATE_GOING_DOWN 1 diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index f9ddb6156f14..bee7d37367ca 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -670,15 +670,17 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost) if (!fw_stats) return NULL; + mutex_lock(&hba->hba_stats_mutex); + bnx2fc_stats = fc_get_host_stats(shost); init_completion(&hba->stat_req_done); if (bnx2fc_send_stat_req(hba)) - return bnx2fc_stats; + goto unlock_stats_mutex; rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ)); if (!rc) { BNX2FC_HBA_DBG(lport, "FW stat req timed out\n"); - return bnx2fc_stats; + goto unlock_stats_mutex; } BNX2FC_STATS(hba, rx_stat2, fc_crc_cnt); bnx2fc_stats->invalid_crc_count += hba->bfw_stats.fc_crc_cnt; @@ -700,6 +702,9 @@ static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost) memcpy(&hba->prev_stats, hba->stats_buffer, sizeof(struct fcoe_statistics_params)); + +unlock_stats_mutex: + mutex_unlock(&hba->hba_stats_mutex); return bnx2fc_stats; } @@ -1348,6 +1353,7 @@ static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) } spin_lock_init(&hba->hba_lock); mutex_init(&hba->hba_mutex); + mutex_init(&hba->hba_stats_mutex); hba->cnic = cnic; -- GitLab From a1df375ca4962c8b1bbcc0dc38de53a0da782cdd Mon Sep 17 00:00:00 2001 From: Michael Schmitz Date: Sun, 30 Apr 2017 19:49:21 +1200 Subject: [PATCH 1093/1834] fix race in drivers/char/random.c:get_reg() [ Upstream commit 9dfa7bba35ac08a63565d58c454dccb7e1bb0a08 ] get_reg() can be reentered on architectures with prioritized interrupts (m68k in this case), causing f->reg_index to be incremented after the range check. Out of bounds memory access past the pt_regs struct results. This will go mostly undetected unless access is beyond end of memory. Prevent the race by disabling interrupts in get_reg(). Tested on m68k (Atari Falcon, and ARAnyM emulator). Kudos to Geert Uytterhoeven for helping to trace this race. Signed-off-by: Michael Schmitz Signed-off-by: Theodore Ts'o Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 08d1dd58c0d2..23f3fb45ff07 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1115,12 +1115,16 @@ static void add_interrupt_bench(cycles_t start) static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs) { __u32 *ptr = (__u32 *) regs; + unsigned long flags; if (regs == NULL) return 0; + local_irq_save(flags); if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32)) f->reg_idx = 0; - return *(ptr + f->reg_idx++); + ptr += f->reg_idx++; + local_irq_restore(flags); + return *ptr; } void add_interrupt_randomness(int irq, int irq_flags) -- GitLab From 78b336afffe6dcafb242179dd6a68d8fbe355944 Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Wed, 24 May 2017 18:02:20 -0400 Subject: [PATCH 1094/1834] ext4: fix off-by-one on max nr_pages in ext4_find_unwritten_pgoff() [ Upstream commit 624327f8794704c5066b11a52f9da6a09dce7f9a ] ext4_find_unwritten_pgoff() is used to search for offset of hole or data in page range [index, end] (both inclusive), and the max number of pages to search should be at least one, if end == index. Otherwise the only page is missed and no hole or data is found, which is not correct. When block size is smaller than page size, this can be demonstrated by preallocating a file with size smaller than page size and writing data to the last block. E.g. run this xfs_io command on a 1k block size ext4 on x86_64 host. # xfs_io -fc "falloc 0 3k" -c "pwrite 2k 1k" \ -c "seek -d 0" /mnt/ext4/testfile wrote 1024/1024 bytes at offset 2048 1 KiB, 1 ops; 0.0000 sec (42.459 MiB/sec and 43478.2609 ops/sec) Whence Result DATA EOF Data at offset 2k was missed, and lseek(2) returned ENXIO. This is unconvered by generic/285 subtest 07 and 08 on ppc64 host, where pagesize is 64k. Because a recent change to generic/285 reduced the preallocated file size to smaller than 64k. Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Reviewed-by: Jan Kara Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/ext4/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 510e66422f04..08fca4add1e2 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -429,7 +429,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode, int i, num; unsigned long nr_pages; - num = min_t(pgoff_t, end - index, PAGEVEC_SIZE); + num = min_t(pgoff_t, end - index, PAGEVEC_SIZE - 1) + 1; nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, (pgoff_t)num); if (nr_pages == 0) -- GitLab From bca3e27b9262c4966cbffac94f3063aa75f4b2e7 Mon Sep 17 00:00:00 2001 From: Timmy Li Date: Mon, 22 May 2017 16:48:28 +0100 Subject: [PATCH 1095/1834] ARM64: PCI: Fix struct acpi_pci_root_ops allocation failure path [ Upstream commit 717902cc93118119a6fce7765da6cf2786987418 ] Commit 093d24a20442 ("arm64: PCI: Manage controller-specific data on per-controller basis") added code to allocate ACPI PCI root_ops dynamically on a per host bridge basis but failed to update the corresponding memory allocation failure path in pci_acpi_scan_root() leading to a potential memory leakage. Fix it by adding the required kfree call. Fixes: 093d24a20442 ("arm64: PCI: Manage controller-specific data on per-controller basis") Reviewed-by: Tomasz Nowicki Signed-off-by: Timmy Li [lorenzo.pieralisi@arm.com: refactored code, rewrote commit log] Signed-off-by: Lorenzo Pieralisi CC: Will Deacon CC: Bjorn Helgaas Signed-off-by: Catalin Marinas Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 409abc45bdb6..1b3eb67edefb 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -175,8 +175,10 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) return NULL; root_ops = kzalloc_node(sizeof(*root_ops), GFP_KERNEL, node); - if (!root_ops) + if (!root_ops) { + kfree(ri); return NULL; + } ri->cfg = pci_acpi_setup_ecam_mapping(root); if (!ri->cfg) { -- GitLab From 71c0b3344e72959b3718c637f978185918be4688 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 23 May 2017 15:24:46 -0700 Subject: [PATCH 1096/1834] tcp: better validation of received ack sequences [ Upstream commit d0e1a1b5a833b625c93d3d49847609350ebd79db ] Paul Fiterau Brostean reported : Linux TCP stack we analyze exhibits behavior that seems odd to me. The scenario is as follows (all packets have empty payloads, no window scaling, rcv/snd window size should not be a factor): TEST HARNESS (CLIENT) LINUX SERVER 1. - LISTEN (server listen, then accepts) 2. - --> --> SYN-RECEIVED 3. - <-- <-- SYN-RECEIVED 4. - --> --> ESTABLISHED 5. - <-- <-- FIN WAIT-1 (server opts to close the data connection calling "close" on the connection socket) 6. - --> --> CLOSING (client sends FIN,ACK with not yet sent acknowledgement number) 7. - <-- <-- CLOSING (ACK is 102 instead of 101, why?) ... (silence from CLIENT) 8. - <-- <-- CLOSING (retransmission, again ACK is 102) Now, note that packet 6 while having the expected sequence number, acknowledges something that wasn't sent by the server. So I would expect the packet to maybe prompt an ACK response from the server, and then be ignored. Yet it is not ignored and actually leads to an increase of the acknowledgement number in the server's retransmission of the FIN,ACK packet. The explanation I found is that the FIN in packet 6 was processed, despite the acknowledgement number being unacceptable. Further experiments indeed show that the server processes this FIN, transitioning to CLOSING, then on receiving an ACK for the FIN it had send in packet 5, the server (or better said connection) transitions from CLOSING to TIME_WAIT (as signaled by netstat). Indeed, tcp_rcv_state_process() calls tcp_ack() but does not exploit the @acceptable status but for TCP_SYN_RECV state. What we want here is to send a challenge ACK, if not in TCP_SYN_RECV state. TCP_FIN_WAIT1 state is not the only state we should fix. Add a FLAG_NO_CHALLENGE_ACK so that tcp_rcv_state_process() can choose to send a challenge ACK and discard the packet instead of wrongly change socket state. With help from Neal Cardwell. Signed-off-by: Eric Dumazet Reported-by: Paul Fiterau Brostean Cc: Neal Cardwell Cc: Yuchung Cheng Cc: Soheil Hassas Yeganeh Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv4/tcp_input.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index b5f264ae3bff..eb05ad940e37 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -115,6 +115,7 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2; #define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ #define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ #define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ +#define FLAG_NO_CHALLENGE_ACK 0x8000 /* do not call tcp_send_challenge_ack() */ #define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) #define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) @@ -3618,7 +3619,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) if (before(ack, prior_snd_una)) { /* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */ if (before(ack, prior_snd_una - tp->max_window)) { - tcp_send_challenge_ack(sk, skb); + if (!(flag & FLAG_NO_CHALLENGE_ACK)) + tcp_send_challenge_ack(sk, skb); return -1; } goto old_ack; @@ -5969,13 +5971,17 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) /* step 5: check the ACK field */ acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH | - FLAG_UPDATE_TS_RECENT) > 0; + FLAG_UPDATE_TS_RECENT | + FLAG_NO_CHALLENGE_ACK) > 0; + if (!acceptable) { + if (sk->sk_state == TCP_SYN_RECV) + return 1; /* send one RST */ + tcp_send_challenge_ack(sk, skb); + goto discard; + } switch (sk->sk_state) { case TCP_SYN_RECV: - if (!acceptable) - return 1; - if (!tp->srtt_us) tcp_synack_rtt_meas(sk, req); @@ -6045,14 +6051,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) * our SYNACK so stop the SYNACK timer. */ if (req) { - /* Return RST if ack_seq is invalid. - * Note that RFC793 only says to generate a - * DUPACK for it but for TCP Fast Open it seems - * better to treat this case like TCP_SYN_RECV - * above. - */ - if (!acceptable) - return 1; /* We no longer need the request sock. */ reqsk_fastopen_remove(sk, req, false); tcp_rearm_rto(sk); -- GitLab From 419490af01a63e6d57d8009a813b5030457b29d0 Mon Sep 17 00:00:00 2001 From: Roman Kapl Date: Wed, 24 May 2017 10:22:22 +0200 Subject: [PATCH 1097/1834] net: move somaxconn init from sysctl code [ Upstream commit 7c3f1875c66fbc19762760097cabc91849ea0bbb ] The default value for somaxconn is set in sysctl_core_net_init(), but this function is not called when kernel is configured without CONFIG_SYSCTL. This results in the kernel not being able to accept TCP connections, because the backlog has zero size. Usually, the user ends up with: "TCP: request_sock_TCP: Possible SYN flooding on port 7. Dropping request. Check SNMP counters." If SYN cookies are not enabled the connection is rejected. Before ef547f2ac16 (tcp: remove max_qlen_log), the effects were less severe, because the backlog was always at least eight slots long. Signed-off-by: Roman Kapl Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/core/net_namespace.c | 19 +++++++++++++++++++ net/core/sysctl_net_core.c | 2 -- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index b7efe2f19f83..04fd04ccaa04 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -312,6 +312,25 @@ static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) goto out; } +static int __net_init net_defaults_init_net(struct net *net) +{ + net->core.sysctl_somaxconn = SOMAXCONN; + return 0; +} + +static struct pernet_operations net_defaults_ops = { + .init = net_defaults_init_net, +}; + +static __init int net_defaults_init(void) +{ + if (register_pernet_subsys(&net_defaults_ops)) + panic("Cannot initialize net default settings"); + + return 0; +} + +core_initcall(net_defaults_init); #ifdef CONFIG_NET_NS static struct ucounts *inc_net_namespaces(struct user_namespace *ns) diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 1b4619008c4e..546ba76b35a5 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -438,8 +438,6 @@ static __net_init int sysctl_core_net_init(struct net *net) { struct ctl_table *tbl; - net->core.sysctl_somaxconn = SOMAXCONN; - tbl = netns_core_table; if (!net_eq(net, &init_net)) { tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL); -- GitLab From 969eeef39863b6435ed80da16a2325ceb4137ae6 Mon Sep 17 00:00:00 2001 From: KT Liao Date: Thu, 25 May 2017 10:06:21 -0700 Subject: [PATCH 1098/1834] Input: elan_i2c - clear INT before resetting controller [ Upstream commit 4b3c7dbbfff0673e8a89575414b864d8b001d3bb ] Some old touchpad FWs need to have interrupt cleared before issuing reset command after updating firmware. We clear interrupt by attempting to read full report from the controller, and discarding any data read. Signed-off-by: KT Liao Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/mouse/elan_i2c_i2c.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c index a679e56c44cd..765879dcaf85 100644 --- a/drivers/input/mouse/elan_i2c_i2c.c +++ b/drivers/input/mouse/elan_i2c_i2c.c @@ -557,7 +557,14 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client, long ret; int error; int len; - u8 buffer[ETP_I2C_INF_LENGTH]; + u8 buffer[ETP_I2C_REPORT_LEN]; + + len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN); + if (len != ETP_I2C_REPORT_LEN) { + error = len < 0 ? len : -EIO; + dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n", + error, len); + } reinit_completion(completion); enable_irq(client->irq); -- GitLab From 1a6906e7f50d84272849549a26e985c4d6e581bd Mon Sep 17 00:00:00 2001 From: Nithin Sujir Date: Wed, 24 May 2017 19:45:17 -0700 Subject: [PATCH 1099/1834] bonding: Don't update slave->link until ready to commit [ Upstream commit 797a93647a48d6cb8a20641a86a71713a947f786 ] In the loadbalance arp monitoring scheme, when a slave link change is detected, the slave->link is immediately updated and slave_state_changed is set. Later down the function, the rtnl_lock is acquired and the changes are committed, updating the bond link state. However, the acquisition of the rtnl_lock can fail. The next time the monitor runs, since slave->link is already updated, it determines that link is unchanged. This results in the bond link state permanently out of sync with the slave link. This patch modifies bond_loadbalance_arp_mon() to handle link changes identical to bond_ab_arp_{inspect/commit}(). The new link state is maintained in slave->new_link until we're ready to commit at which point it's copied into slave->link. NOTE: miimon_{inspect/commit}() has a more complex state machine requiring the use of the bond_{propose,commit}_link_state() functions which maintains the intermediate state in slave->link_new_state. The arp monitors don't require that. Testing: This bug is very easy to reproduce with the following steps. 1. In a loop, toggle a slave link of a bond slave interface. 2. In a separate loop, do ifconfig up/down of an unrelated interface to create contention for rtnl_lock. Within a few iterations, the bond link goes out of sync with the slave link. Signed-off-by: Nithin Nayak Sujir Cc: Mahesh Bandewar Cc: Jay Vosburgh Acked-by: Mahesh Bandewar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4907c9b57565..fb1141f7f6b5 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2605,11 +2605,13 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) bond_for_each_slave_rcu(bond, slave, iter) { unsigned long trans_start = dev_trans_start(slave->dev); + slave->new_link = BOND_LINK_NOCHANGE; + if (slave->link != BOND_LINK_UP) { if (bond_time_in_interval(bond, trans_start, 1) && bond_time_in_interval(bond, slave->last_rx, 1)) { - slave->link = BOND_LINK_UP; + slave->new_link = BOND_LINK_UP; slave_state_changed = 1; /* primary_slave has no meaning in round-robin @@ -2636,7 +2638,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) if (!bond_time_in_interval(bond, trans_start, 2) || !bond_time_in_interval(bond, slave->last_rx, 2)) { - slave->link = BOND_LINK_DOWN; + slave->new_link = BOND_LINK_DOWN; slave_state_changed = 1; if (slave->link_failure_count < UINT_MAX) @@ -2667,6 +2669,11 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) if (!rtnl_trylock()) goto re_arm; + bond_for_each_slave(bond, slave, iter) { + if (slave->new_link != BOND_LINK_NOCHANGE) + slave->link = slave->new_link; + } + if (slave_state_changed) { bond_slave_state_change(bond); if (BOND_MODE(bond) == BOND_MODE_XOR) -- GitLab From c198e227316337301f682c97c5880014b3aeb3aa Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 24 May 2017 10:15:43 +0200 Subject: [PATCH 1100/1834] cpuhotplug: Link lock stacks for hotplug callbacks [ Upstream commit 49dfe2a6779717d9c18395684ee31bdc98b22e53 ] The CPU hotplug callbacks are not covered by lockdep versus the cpu hotplug rwsem. CPU0 CPU1 cpuhp_setup_state(STATE, startup, teardown); cpus_read_lock(); invoke_callback_on_ap(); kick_hotplug_thread(ap); wait_for_completion(); hotplug_thread_fn() lock(m); do_stuff(); unlock(m); Lockdep does not know about this dependency and will not trigger on the following code sequence: lock(m); cpus_read_lock(); Add a lockdep map and connect the initiators lock chain with the hotplug thread lock chain, so potential deadlocks can be detected. Signed-off-by: Thomas Gleixner Tested-by: Paul E. McKenney Acked-by: Ingo Molnar Cc: Peter Zijlstra Cc: Sebastian Siewior Cc: Steven Rostedt Link: http://lkml.kernel.org/r/20170524081549.709375845@linutronix.de Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/cpu.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/kernel/cpu.c b/kernel/cpu.c index 802eb3361a0a..967163fb90a8 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c @@ -63,6 +63,12 @@ struct cpuhp_cpu_state { static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state); +#if defined(CONFIG_LOCKDEP) && defined(CONFIG_SMP) +static struct lock_class_key cpuhp_state_key; +static struct lockdep_map cpuhp_state_lock_map = + STATIC_LOCKDEP_MAP_INIT("cpuhp_state", &cpuhp_state_key); +#endif + /** * cpuhp_step - Hotplug state machine step * @name: Name of the step @@ -563,6 +569,7 @@ static void cpuhp_thread_fun(unsigned int cpu) st->should_run = false; + lock_map_acquire(&cpuhp_state_lock_map); /* Single callback invocation for [un]install ? */ if (st->single) { if (st->cb_state < CPUHP_AP_ONLINE) { @@ -594,6 +601,7 @@ static void cpuhp_thread_fun(unsigned int cpu) else if (st->state > st->target) ret = cpuhp_ap_offline(cpu, st); } + lock_map_release(&cpuhp_state_lock_map); st->result = ret; complete(&st->done); } @@ -608,6 +616,9 @@ cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup, if (!cpu_online(cpu)) return 0; + lock_map_acquire(&cpuhp_state_lock_map); + lock_map_release(&cpuhp_state_lock_map); + /* * If we are up and running, use the hotplug thread. For early calls * we invoke the thread function directly. @@ -651,6 +662,8 @@ static int cpuhp_kick_ap_work(unsigned int cpu) enum cpuhp_state state = st->state; trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work); + lock_map_acquire(&cpuhp_state_lock_map); + lock_map_release(&cpuhp_state_lock_map); __cpuhp_kick_ap_work(st); wait_for_completion(&st->done); trace_cpuhp_exit(cpu, st->state, state, st->result); -- GitLab From 6391346223496fdf4ac510ad4fae161daba23f80 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sat, 20 May 2017 18:59:54 +0200 Subject: [PATCH 1101/1834] PCI/msi: fix the pci_alloc_irq_vectors_affinity stub [ Upstream commit 83b4605b0c16cde5b00c8cf192408d51eab75402 ] We need to return an error for any call that asks for MSI / MSI-X vectors only, so that non-trivial fallback logic can work properly. Also valid dev->irq and use the "correct" errno value based on feedback from Linus. Signed-off-by: Christoph Hellwig Reported-by: Steven Rostedt Fixes: aff17164 ("PCI: Provide sensible IRQ vector alloc/free routines") Signed-off-by: Linus Torvalds Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/pci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/linux/pci.h b/include/linux/pci.h index 1b711796d989..36522905685b 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1348,9 +1348,9 @@ static inline int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, unsigned int max_vecs, unsigned int flags) { - if (min_vecs > 1) - return -EINVAL; - return 1; + if ((flags & PCI_IRQ_LEGACY) && min_vecs == 1 && dev->irq) + return 1; + return -ENOSPC; } static inline void pci_free_irq_vectors(struct pci_dev *dev) { -- GitLab From 5ea0519a77de6d34204012b7223ba72d0ef607dd Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Sat, 20 May 2017 20:32:32 -0700 Subject: [PATCH 1102/1834] KVM: X86: Fix preempt the preemption timer cancel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 5acc1ca4fb15f00bfa3d4046e35ca381bc25d580 ] Preemption can occur during cancel preemption timer, and there will be inconsistent status in lapic, vmx and vmcs field. CPU0 CPU1 preemption timer vmexit handle_preemption_timer(vCPU0) kvm_lapic_expired_hv_timer vmx_cancel_hv_timer vmx->hv_deadline_tsc = -1 vmcs_clear_bits /* hv_timer_in_use still true */ sched_out sched_in kvm_arch_vcpu_load vmx_set_hv_timer write vmx->hv_deadline_tsc vmcs_set_bits /* back in kvm_lapic_expired_hv_timer */ hv_timer_in_use = false ... vmx_vcpu_run vmx_arm_hv_run write preemption timer deadline spurious preemption timer vmexit handle_preemption_timer(vCPU0) kvm_lapic_expired_hv_timer WARN_ON(!apic->lapic_timer.hv_timer_in_use); This can be reproduced sporadically during boot of L2 on a preemptible L1, causing a splat on L1. WARNING: CPU: 3 PID: 1952 at arch/x86/kvm/lapic.c:1529 kvm_lapic_expired_hv_timer+0xb5/0xd0 [kvm] CPU: 3 PID: 1952 Comm: qemu-system-x86 Not tainted 4.12.0-rc1+ #24 RIP: 0010:kvm_lapic_expired_hv_timer+0xb5/0xd0 [kvm] Call Trace: handle_preemption_timer+0xe/0x20 [kvm_intel] vmx_handle_exit+0xc9/0x15f0 [kvm_intel] ? lock_acquire+0xdb/0x250 ? lock_acquire+0xdb/0x250 ? kvm_arch_vcpu_ioctl_run+0xdf3/0x1ce0 [kvm] kvm_arch_vcpu_ioctl_run+0xe55/0x1ce0 [kvm] kvm_vcpu_ioctl+0x384/0x7b0 [kvm] ? kvm_vcpu_ioctl+0x384/0x7b0 [kvm] ? __fget+0xf3/0x210 do_vfs_ioctl+0xa4/0x700 ? __fget+0x114/0x210 SyS_ioctl+0x79/0x90 do_syscall_64+0x8f/0x750 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL64_slow_path+0x25/0x25 This patch fixes it by disabling preemption while cancelling preemption timer. This way cancel_hv_timer is atomic with respect to kvm_arch_vcpu_load. Cc: Paolo Bonzini Cc: Radim Krčmář Signed-off-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/lapic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index b24b3c6d686e..5c3d416fff17 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -1363,8 +1363,10 @@ EXPORT_SYMBOL_GPL(kvm_lapic_hv_timer_in_use); static void cancel_hv_tscdeadline(struct kvm_lapic *apic) { + preempt_disable(); kvm_x86_ops->cancel_hv_timer(apic->vcpu); apic->lapic_timer.hv_timer_in_use = false; + preempt_enable(); } void kvm_lapic_expired_hv_timer(struct kvm_vcpu *vcpu) -- GitLab From a74bec409e337ea020306908aed16febab3fd356 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20H=2E=20Sch=C3=B6nherr?= Date: Sat, 20 May 2017 13:22:56 +0200 Subject: [PATCH 1103/1834] KVM: nVMX: Fix handling of lmsw instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit e1d39b17e044e8ae819827810d87d809ba5f58c0 ] The decision whether or not to exit from L2 to L1 on an lmsw instruction is based on bogus values: instead of using the information encoded within the exit qualification, it uses the data also used for the mov-to-cr instruction, which boils down to using whatever is in %eax at that point. Use the correct values instead. Without this fix, an L1 may not get notified when a 32-bit Linux L2 switches its secondary CPUs to protected mode; the L1 is only notified on the next modification of CR0. This short time window poses a problem, when there is some other reason to exit to L1 in between. Then, L2 will be resumed in real mode and chaos ensues. Signed-off-by: Jan H. Schönherr Reviewed-by: Wanpeng Li Signed-off-by: Paolo Bonzini Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/vmx.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 7ed422e2641b..41218ef8c895 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -7924,11 +7924,13 @@ static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu, { unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION); int cr = exit_qualification & 15; - int reg = (exit_qualification >> 8) & 15; - unsigned long val = kvm_register_readl(vcpu, reg); + int reg; + unsigned long val; switch ((exit_qualification >> 4) & 3) { case 0: /* mov to cr */ + reg = (exit_qualification >> 8) & 15; + val = kvm_register_readl(vcpu, reg); switch (cr) { case 0: if (vmcs12->cr0_guest_host_mask & @@ -7983,6 +7985,7 @@ static bool nested_vmx_exit_handled_cr(struct kvm_vcpu *vcpu, * lmsw can change bits 1..3 of cr0, and only set bit 0 of * cr0. Other attempted changes are ignored, with no exit. */ + val = (exit_qualification >> LMSW_SOURCE_DATA_SHIFT) & 0x0f; if (vmcs12->cr0_guest_host_mask & 0xe & (val ^ vmcs12->cr0_read_shadow)) return true; -- GitLab From 04a87dfaf6ae215ee1b9eb3c796556dd914a65a2 Mon Sep 17 00:00:00 2001 From: linzhang Date: Thu, 25 May 2017 14:07:18 +0800 Subject: [PATCH 1104/1834] net: llc: add lock_sock in llc_ui_bind to avoid a race condition [ Upstream commit 0908cf4dfef35fc6ac12329007052ebe93ff1081 ] There is a race condition in llc_ui_bind if two or more processes/threads try to bind a same socket. If more processes/threads bind a same socket success that will lead to two problems, one is this action is not what we expected, another is will lead to kernel in unstable status or oops(in my simple test case, cause llc2.ko can't unload). The current code is test SOCK_ZAPPED bit to avoid a process to bind a same socket twice but that is can't avoid more processes/threads try to bind a same socket at the same time. So, add lock_sock in llc_ui_bind like others, such as llc_ui_connect. Signed-off-by: Lin Zhang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/llc/af_llc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index db916cf51ffe..f7caf0f5d9c8 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -309,6 +309,8 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) int rc = -EINVAL; dprintk("%s: binding %02X\n", __func__, addr->sllc_sap); + + lock_sock(sk); if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr))) goto out; rc = -EAFNOSUPPORT; @@ -380,6 +382,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) out_put: llc_sap_put(sap); out: + release_sock(sk); return rc; } -- GitLab From a435a0ceadae59f839e0d4a47b771d68418e682b Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Mon, 8 May 2017 14:34:57 -0600 Subject: [PATCH 1105/1834] drm/msm: Take the mutex before calling msm_gem_new_impl [ Upstream commit 90dd57de4a043f642179b1323a31ca3ced826611 ] Amongst its other duties, msm_gem_new_impl adds the newly created GEM object to the shared inactive list which may also be actively modifiying the list during submission. All the paths to modify the list are protected by the mutex except for the one through msm_gem_import which can end up causing list corruption. Signed-off-by: Jordan Crouse [add extra WARN_ON(!mutex_is_locked(&dev->struct_mutex))] Signed-off-by: Rob Clark Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/msm/msm_gem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index 797d1f8340b9..7145127513c4 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -770,6 +770,8 @@ static int msm_gem_new_impl(struct drm_device *dev, unsigned sz; bool use_vram = false; + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + switch (flags & MSM_BO_CACHE_MASK) { case MSM_BO_UNCACHED: case MSM_BO_CACHED: @@ -863,7 +865,11 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, size = PAGE_ALIGN(dmabuf->size); + /* Take mutex so we can modify the inactive list in msm_gem_new_impl */ + mutex_lock(&dev->struct_mutex); ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj); + mutex_unlock(&dev->struct_mutex); + if (ret) goto fail; -- GitLab From ff2620e356e393ba475b0550c85477b2658b4515 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Fri, 22 Dec 2017 09:46:59 -0600 Subject: [PATCH 1106/1834] i40iw: Fix sequence number for the first partial FPDU [ Upstream commit df8b13a1b23356d01dfc4647a5629cdb0f4ce566 ] Partial FPDU processing is broken as the sequence number for the first partial FPDU is wrong due to incorrect Q2 buffer offset. The offset should be 64 rather than 16. Fixes: 786c6adb3a94 ("i40iw: add puda code") Signed-off-by: Shiraz Saleem Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/i40iw/i40iw_d.h | 1 + drivers/infiniband/hw/i40iw/i40iw_puda.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h index d1328a697750..8ce599e1639c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_d.h +++ b/drivers/infiniband/hw/i40iw/i40iw_d.h @@ -86,6 +86,7 @@ #define RDMA_OPCODE_MASK 0x0f #define RDMA_READ_REQ_OPCODE 1 #define Q2_BAD_FRAME_OFFSET 72 +#define Q2_FPSN_OFFSET 64 #define CQE_MAJOR_DRV 0x8000 #define I40IW_TERM_SENT 0x01 diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c index c62d354f7810..3ed49146d73c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.c +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c @@ -1320,7 +1320,7 @@ static void i40iw_ieq_handle_exception(struct i40iw_puda_rsrc *ieq, u32 *hw_host_ctx = (u32 *)qp->hw_host_ctx; u32 rcv_wnd = hw_host_ctx[23]; /* first partial seq # in q2 */ - u32 fps = qp->q2_buf[16]; + u32 fps = *(u32 *)(qp->q2_buf + Q2_FPSN_OFFSET); struct list_head *rxlist = &pfpdu->rxlist; struct list_head *plist; -- GitLab From 11c7a4b5ac947bd2dc01b9874948e1359fc1e065 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Fri, 22 Dec 2017 09:46:56 -0600 Subject: [PATCH 1107/1834] i40iw: Correct Q1/XF object count equation [ Upstream commit fe99afd1febd74e0ef1fed7e3283f09effe1f4f0 ] Lower Inbound RDMA Read Queue (Q1) object count by a factor of 2 as it is incorrectly doubled. Also, round up Q1 and Transmit FIFO (XF) object count to power of 2 to satisfy hardware requirement. Fixes: 86dbcd0f12e9 ("i40iw: add file to handle cqp calls") Signed-off-by: Shiraz Saleem Signed-off-by: Jason Gunthorpe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 2c4b4d072d6a..3b973cba8975 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -3644,8 +3644,10 @@ enum i40iw_status_code i40iw_config_fpm_values(struct i40iw_sc_dev *dev, u32 qp_ hmc_info->hmc_obj[I40IW_HMC_IW_APBVT_ENTRY].cnt = 1; hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt = mrwanted; - hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt = I40IW_MAX_WQ_ENTRIES * qpwanted; - hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt = 4 * I40IW_MAX_IRD_SIZE * qpwanted; + hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt = + roundup_pow_of_two(I40IW_MAX_WQ_ENTRIES * qpwanted); + hmc_info->hmc_obj[I40IW_HMC_IW_Q1].cnt = + roundup_pow_of_two(2 * I40IW_MAX_IRD_SIZE * qpwanted); hmc_info->hmc_obj[I40IW_HMC_IW_XFFL].cnt = hmc_info->hmc_obj[I40IW_HMC_IW_XF].cnt / hmc_fpm_misc->xf_block_size; hmc_info->hmc_obj[I40IW_HMC_IW_Q1FL].cnt = -- GitLab From 9487ce395616df454a394e64191a7d8f11c6612e Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 16 Nov 2017 13:15:26 +0100 Subject: [PATCH 1108/1834] ARM: dts: ls1021a: add "fsl,ls1021a-esdhc" compatible string to esdhc node [ Upstream commit d5c7b4d5ac2237a6da7ced3adfe6b8bf769f8cc6 ] Commit a22950c888e3 (mmc: sdhci-of-esdhc: add quirk SDHCI_QUIRK_BROKEN_TIMEOUT_VAL for ls1021a) added logic to the driver to enable the broken timeout val quirk for ls1021a, but did not add the corresponding compatible string to the device tree, so it didn't really have any effect. Fix that. Signed-off-by: Rasmus Villemoes Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/ls1021a.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi index 368e21934285..825f6eae3d1c 100644 --- a/arch/arm/boot/dts/ls1021a.dtsi +++ b/arch/arm/boot/dts/ls1021a.dtsi @@ -146,7 +146,7 @@ }; esdhc: esdhc@1560000 { - compatible = "fsl,esdhc"; + compatible = "fsl,ls1021a-esdhc", "fsl,esdhc"; reg = <0x0 0x1560000 0x0 0x10000>; interrupts = ; clock-frequency = <0>; -- GitLab From 8e50e9d66e872c7bb5a31d71afe44a089e81143c Mon Sep 17 00:00:00 2001 From: Yi Zeng Date: Tue, 26 Dec 2017 19:22:26 +0800 Subject: [PATCH 1109/1834] thermal: power_allocator: fix one race condition issue for thermal_instances list [ Upstream commit a5de11d67dcd268b8d0beb73dc374de5e97f0caf ] When invoking allow_maximum_power and traverse tz->thermal_instances, we should grab thermal_zone_device->lock to avoid race condition. For example, during the system reboot, if the mali GPU device implements device shutdown callback and unregister GPU devfreq cooling device, the deleted list head may be accessed to cause panic, as the following log shows: [ 33.551070] c3 25 (kworker/3:0) Unable to handle kernel paging request at virtual address dead000000000070 [ 33.566708] c3 25 (kworker/3:0) pgd = ffffffc0ed290000 [ 33.572071] c3 25 (kworker/3:0) [dead000000000070] *pgd=00000001ed292003, *pud=00000001ed292003, *pmd=0000000000000000 [ 33.581515] c3 25 (kworker/3:0) Internal error: Oops: 96000004 [#1] PREEMPT SMP [ 33.599761] c3 25 (kworker/3:0) CPU: 3 PID: 25 Comm: kworker/3:0 Not tainted 4.4.35+ #912 [ 33.614137] c3 25 (kworker/3:0) Workqueue: events_freezable thermal_zone_device_check [ 33.620245] c3 25 (kworker/3:0) task: ffffffc0f32e4200 ti: ffffffc0f32f0000 task.ti: ffffffc0f32f0000 [ 33.629466] c3 25 (kworker/3:0) PC is at power_allocator_throttle+0x7c8/0x8a4 [ 33.636609] c3 25 (kworker/3:0) LR is at power_allocator_throttle+0x808/0x8a4 [ 33.643742] c3 25 (kworker/3:0) pc : [] lr : [] pstate: 20000145 [ 33.652874] c3 25 (kworker/3:0) sp : ffffffc0f32f3bb0 [ 34.468519] c3 25 (kworker/3:0) Process kworker/3:0 (pid: 25, stack limit = 0xffffffc0f32f0020) [ 34.477220] c3 25 (kworker/3:0) Stack: (0xffffffc0f32f3bb0 to 0xffffffc0f32f4000) [ 34.819822] c3 25 (kworker/3:0) Call trace: [ 34.824021] c3 25 (kworker/3:0) Exception stack(0xffffffc0f32f39c0 to 0xffffffc0f32f3af0) [ 34.924993] c3 25 (kworker/3:0) [] power_allocator_throttle+0x7c8/0x8a4 [ 34.933184] c3 25 (kworker/3:0) [] handle_thermal_trip.part.25+0x70/0x224 [ 34.941545] c3 25 (kworker/3:0) [] thermal_zone_device_update+0xc0/0x20c [ 34.949818] c3 25 (kworker/3:0) [] thermal_zone_device_check+0x20/0x2c [ 34.957924] c3 25 (kworker/3:0) [] process_one_work+0x168/0x458 [ 34.965414] c3 25 (kworker/3:0) [] worker_thread+0x13c/0x4b4 [ 34.972650] c3 25 (kworker/3:0) [] kthread+0xe8/0xfc [ 34.979187] c3 25 (kworker/3:0) [] ret_from_fork+0x10/0x40 [ 34.986244] c3 25 (kworker/3:0) Code: f9405e73 eb1302bf d102e273 54ffc460 (b9402a61) [ 34.994339] c3 25 (kworker/3:0) ---[ end trace 32057901e3b7e1db ]--- Signed-off-by: Yi Zeng Signed-off-by: Zhang Rui Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/power_allocator.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c index b4d3116cfdaf..3055f9a12a17 100644 --- a/drivers/thermal/power_allocator.c +++ b/drivers/thermal/power_allocator.c @@ -523,6 +523,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz) struct thermal_instance *instance; struct power_allocator_params *params = tz->governor_data; + mutex_lock(&tz->lock); list_for_each_entry(instance, &tz->thermal_instances, tz_node) { if ((instance->trip != params->trip_max_desired_temperature) || (!cdev_is_power_actor(instance->cdev))) @@ -534,6 +535,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz) mutex_unlock(&instance->cdev->lock); thermal_cdev_update(instance->cdev); } + mutex_unlock(&tz->lock); } /** -- GitLab From 24cce930dc4985fcf7ed27043b311d67e1b15208 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 9 Dec 2017 01:26:46 +0900 Subject: [PATCH 1110/1834] perf probe: Add warning message if there is unexpected event name [ Upstream commit 9f5c6d8777a2d962b0eeacb2a16f37da6bea545b ] This improve the error message so that user can know event-name error before writing new events to kprobe-events interface. E.g. ====== #./perf probe -x /lib64/libc-2.25.so malloc_get_state* Internal error: "malloc_get_state@GLIBC_2" is an invalid event name. Error: Failed to add events. ====== Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Masami Hiramatsu Acked-by: Ravi Bangoria Reviewed-by: Thomas Richter Tested-by: Arnaldo Carvalho de Melo Cc: Paul Clarke Cc: bhargavb Cc: linux-rt-users@vger.kernel.org Link: http://lkml.kernel.org/r/151275040665.24652.5188568529237584489.stgit@devbox Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/probe-event.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 4d2e22f8bd94..c93daccec755 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -2609,6 +2609,14 @@ static int get_new_event_name(char *buf, size_t len, const char *base, out: free(nbase); + + /* Final validation */ + if (ret >= 0 && !is_c_func_name(buf)) { + pr_warning("Internal error: \"%s\" is an invalid event name.\n", + buf); + ret = -EINVAL; + } + return ret; } -- GitLab From ca1853c03eae86fe8504f72fb80bb0b63b9834e4 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 22 Dec 2017 15:10:17 +0100 Subject: [PATCH 1111/1834] l2tp: fix missing print session offset info [ Upstream commit 820da5357572715c6235ba3b3daa2d5b43a1198f ] Report offset parameter in L2TP_CMD_SESSION_GET command if it has been configured by userspace Fixes: 309795f4bec ("l2tp: Add netlink control API for L2TP") Reported-by: Jianlin Shi Signed-off-by: Hangbin Liu Signed-off-by: Lorenzo Bianconi Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/l2tp/l2tp_netlink.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/l2tp/l2tp_netlink.c b/net/l2tp/l2tp_netlink.c index ee03bc866d1b..ce1238492c0f 100644 --- a/net/l2tp/l2tp_netlink.c +++ b/net/l2tp/l2tp_netlink.c @@ -750,6 +750,8 @@ static int l2tp_nl_session_send(struct sk_buff *skb, u32 portid, u32 seq, int fl if ((session->ifname[0] && nla_put_string(skb, L2TP_ATTR_IFNAME, session->ifname)) || + (session->offset && + nla_put_u16(skb, L2TP_ATTR_OFFSET, session->offset)) || (session->cookie_len && nla_put(skb, L2TP_ATTR_COOKIE, session->cookie_len, &session->cookie[0])) || -- GitLab From 59bf03657ac6cd5595951440514ef59639d56648 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Fri, 22 Dec 2017 09:38:59 -0800 Subject: [PATCH 1112/1834] rds; Reset rs->rs_bound_addr in rds_add_bound() failure path [ Upstream commit 7ae0c649c47f1c5d2db8cee6dd75855970af1669 ] If the rds_sock is not added to the bind_hash_table, we must reset rs_bound_addr so that rds_remove_bound will not trip on this rds_sock. rds_add_bound() does a rds_sock_put() in this failure path, so failing to reset rs_bound_addr will result in a socket refcount bug, and will trigger a WARN_ON with the stack shown below when the application subsequently tries to close the PF_RDS socket. WARNING: CPU: 20 PID: 19499 at net/rds/af_rds.c:496 \ rds_sock_destruct+0x15/0x30 [rds] : __sk_destruct+0x21/0x190 rds_remove_bound.part.13+0xb6/0x140 [rds] rds_release+0x71/0x120 [rds] sock_release+0x1a/0x70 sock_close+0xe/0x20 __fput+0xd5/0x210 task_work_run+0x82/0xa0 do_exit+0x2ce/0xb30 ? syscall_trace_enter+0x1cc/0x2b0 do_group_exit+0x39/0xa0 SyS_exit_group+0x10/0x10 do_syscall_64+0x61/0x1a0 Signed-off-by: Sowmini Varadhan Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/rds/bind.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/rds/bind.c b/net/rds/bind.c index 095f6ce583fe..adb53ae97a02 100644 --- a/net/rds/bind.c +++ b/net/rds/bind.c @@ -114,6 +114,7 @@ static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port) rs, &addr, (int)ntohs(*port)); break; } else { + rs->rs_bound_addr = 0; rds_sock_put(rs); ret = -ENOMEM; break; -- GitLab From 2fb63a4c948be910a0f2696d6fecdb481ae1887c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 23 Dec 2017 19:41:47 +0100 Subject: [PATCH 1113/1834] ACPI / video: Default lcd_only to true on Win8-ready and newer machines [ Upstream commit 5928c281524fe451114e04f1dfa11246a37e859f ] We're seeing a lot of bogus backlight interfaces on newer machines without a LCD such as desktops, servers and HDMI sticks. This causes userspace to show a non-functional brightness slider in e.g. the GNOME3 system menu, which is undesirable. And, in general, we should simply just not register a non functional backlight interface. Checking the LCD flag causes the bogus acpi_video backlight interfaces to go away (on the machines this was tested on). This change sets the lcd_only option by default on any machines which are Win8-ready, to fix this. This is not entirely without a risk of regressions, but video_detect.c already prefers native-backlight interfaces over the acpi_video one on Win8-ready machines, calling acpi_video_unregister_backlight() as soon as a native interface shows up. This is done because the ACPI backlight interface often is broken on Win8-ready machines, because win8 does not seem to actually use it. So in practice we already end up not registering the ACPI backlight interface on (most) Win8-ready machines with a LCD panel, thus this change does not change anything for (most) machines with a LCD panel and on machines without a LCD panel we actually don't want to register any backlight interfaces. This has been tested on the following machines and fixes a bogus backlight interface showing up there: - Desktop with an Asrock B150M Pro4S/D3 m.b. using i5-6500 builtin gfx - Intel Compute Stick STK1AW32SC - Meegopad T08 HDMI stick Bogus backlight interfaces have also been reported on: - Desktop with Asus H87I-Plus m.b. - Desktop with ASRock B75M-ITX m.b. - Desktop with Gigabyte Z87-D3HP m.b. - Dell PowerEdge T20 desktop Link: https://bugzilla.redhat.com/show_bug.cgi?id=1097436 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1133327 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1133329 Link: https://bugzilla.redhat.com/show_bug.cgi?id=1133646 Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpi_video.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index c5557d070954..94e04c9de12b 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -87,8 +87,8 @@ MODULE_PARM_DESC(report_key_events, static bool device_id_scheme = false; module_param(device_id_scheme, bool, 0444); -static bool only_lcd = false; -module_param(only_lcd, bool, 0444); +static int only_lcd = -1; +module_param(only_lcd, int, 0444); static int register_count; static DEFINE_MUTEX(register_count_mutex); @@ -2082,6 +2082,16 @@ int acpi_video_register(void) goto leave; } + /* + * We're seeing a lot of bogus backlight interfaces on newer machines + * without a LCD such as desktops, servers and HDMI sticks. Checking + * the lcd flag fixes this, so enable this on any machines which are + * win8 ready (where we also prefer the native backlight driver, so + * normally the acpi_video code should not register there anyways). + */ + if (only_lcd == -1) + only_lcd = acpi_osi_is_win8(); + dmi_check_system(video_dmi_table); ret = acpi_bus_register_driver(&acpi_video_bus); -- GitLab From 9e156f310a88848b7692c41c3cfcdbfeb1c05e7a Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Thu, 28 Dec 2017 16:26:11 +0200 Subject: [PATCH 1114/1834] net/mlx4_en: Change default QoS settings [ Upstream commit a42b63c1ac1986f17f71bc91a6b0aaa14d4dae71 ] Change the default mapping between TC and TCG as follows: Prio | TC/TCG | from to | (set by FW) (set by SW) ---------+----------------------------------- 0 | 0/0 0/7 1 | 1/0 0/6 2 | 2/0 0/5 3 | 3/0 0/4 4 | 4/0 0/3 5 | 5/0 0/2 6 | 6/0 0/1 7 | 7/0 0/0 These new settings cause that a pause frame for any prio stops traffic for all prios. Fixes: 564c274c3df0 ("net/mlx4_en: DCB QoS support") Signed-off-by: Moni Shoua Signed-off-by: Maor Gottlieb Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c | 5 +++++ drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 7 +++++++ drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index b04760a5034b..d98827adec9b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -310,6 +310,7 @@ static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets) } switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_VENDOR: case IEEE_8021QAZ_TSA_STRICT: break; case IEEE_8021QAZ_TSA_ETS: @@ -347,6 +348,10 @@ static int mlx4_en_config_port_scheduler(struct mlx4_en_priv *priv, /* higher TC means higher priority => lower pg */ for (i = IEEE_8021QAZ_MAX_TCS - 1; i >= 0; i--) { switch (ets->tc_tsa[i]) { + case IEEE_8021QAZ_TSA_VENDOR: + pg[i] = MLX4_EN_TC_VENDOR; + tc_tx_bw[i] = MLX4_EN_BW_MAX; + break; case IEEE_8021QAZ_TSA_STRICT: pg[i] = num_strict++; tc_tx_bw[i] = MLX4_EN_BW_MAX; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index d223e7cb68ba..0160c93de6d3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -3125,6 +3125,13 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, priv->msg_enable = MLX4_EN_MSG_LEVEL; #ifdef CONFIG_MLX4_EN_DCB if (!mlx4_is_slave(priv->mdev->dev)) { + u8 prio; + + for (prio = 0; prio < IEEE_8021QAZ_MAX_TCS; ++prio) { + priv->ets.prio_tc[prio] = prio; + priv->ets.tc_tsa[prio] = IEEE_8021QAZ_TSA_VENDOR; + } + priv->dcbx_cap = DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_HOST | DCB_CAP_DCBX_VER_IEEE; priv->flags |= MLX4_EN_DCB_ENABLED; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index df0f39611c5e..18f221d8a04d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -472,6 +472,7 @@ struct mlx4_en_frag_info { #define MLX4_EN_BW_MIN 1 #define MLX4_EN_BW_MAX 100 /* Utilize 100% of the line */ +#define MLX4_EN_TC_VENDOR 0 #define MLX4_EN_TC_ETS 7 enum dcb_pfc_type { -- GitLab From 3aa66ba53e65ba53529fd07e1cdde5063b6a2c5a Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 10 Nov 2017 15:45:41 +1100 Subject: [PATCH 1115/1834] VFS: close race between getcwd() and d_move() [ Upstream commit 61647823aa920e395afcce4b57c32afb51456cab ] d_move() will call __d_drop() and then __d_rehash() on the dentry being moved. This creates a small window when the dentry appears to be unhashed. Many tests of d_unhashed() are made under ->d_lock and so are safe from racing with this window, but some aren't. In particular, getcwd() calls d_unlinked() (which calls d_unhashed()) without d_lock protection, so it can race. This races has been seen in practice with lustre, which uses d_move() as part of name lookup. See: https://jira.hpdd.intel.com/browse/LU-9735 It could race with a regular rename(), and result in ENOENT instead of either the 'before' or 'after' name. The race can be demonstrated with a simple program which has two threads, one renaming a directory back and forth while another calls getcwd() within that directory: it should never fail, but does. See: https://patchwork.kernel.org/patch/9455345/ We could fix this race by taking d_lock and rechecking when d_unhashed() reports true. Alternately when can remove the window, which is the approach this patch takes. ___d_drop() is introduce which does *not* clear d_hash.pprev so the dentry still appears to be hashed. __d_drop() calls ___d_drop(), then clears d_hash.pprev. __d_move() now uses ___d_drop() and only clears d_hash.pprev when not rehashing. Signed-off-by: NeilBrown Signed-off-by: Al Viro Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/dcache.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index c0c7fa8224ba..2225b9855c5f 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -461,9 +461,11 @@ static void dentry_lru_add(struct dentry *dentry) * d_drop() is used mainly for stuff that wants to invalidate a dentry for some * reason (NFS timeouts or autofs deletes). * - * __d_drop requires dentry->d_lock. + * __d_drop requires dentry->d_lock + * ___d_drop doesn't mark dentry as "unhashed" + * (dentry->d_hash.pprev will be LIST_POISON2, not NULL). */ -void __d_drop(struct dentry *dentry) +static void ___d_drop(struct dentry *dentry) { if (!d_unhashed(dentry)) { struct hlist_bl_head *b; @@ -479,12 +481,17 @@ void __d_drop(struct dentry *dentry) hlist_bl_lock(b); __hlist_bl_del(&dentry->d_hash); - dentry->d_hash.pprev = NULL; hlist_bl_unlock(b); /* After this call, in-progress rcu-walk path lookup will fail. */ write_seqcount_invalidate(&dentry->d_seq); } } + +void __d_drop(struct dentry *dentry) +{ + ___d_drop(dentry); + dentry->d_hash.pprev = NULL; +} EXPORT_SYMBOL(__d_drop); void d_drop(struct dentry *dentry) @@ -2378,7 +2385,7 @@ EXPORT_SYMBOL(d_delete); static void __d_rehash(struct dentry *entry) { struct hlist_bl_head *b = d_hash(entry->d_name.hash); - BUG_ON(!d_unhashed(entry)); + hlist_bl_lock(b); hlist_bl_add_head_rcu(&entry->d_hash, b); hlist_bl_unlock(b); @@ -2815,9 +2822,9 @@ static void __d_move(struct dentry *dentry, struct dentry *target, write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED); /* unhash both */ - /* __d_drop does write_seqcount_barrier, but they're OK to nest. */ - __d_drop(dentry); - __d_drop(target); + /* ___d_drop does write_seqcount_barrier, but they're OK to nest. */ + ___d_drop(dentry); + ___d_drop(target); /* Switch the names.. */ if (exchange) @@ -2829,6 +2836,8 @@ static void __d_move(struct dentry *dentry, struct dentry *target, __d_rehash(dentry); if (exchange) __d_rehash(target); + else + target->d_hash.pprev = NULL; /* ... and switch them in the tree */ if (IS_ROOT(dentry)) { -- GitLab From 715f7e3efef0227865162b00d13321431be7962f Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Wed, 6 Dec 2017 14:20:15 -0600 Subject: [PATCH 1116/1834] PM / devfreq: Fix potential NULL pointer dereference in governor_store [ Upstream commit 63f1e05f7fe9ca509c60154d6a833abf96eecdc9 ] df->governor is being dereferenced before it is null checked, hence there is a potential null pointer dereference. Notice that df->governor is being null checked at line 1004: if (df->governor) {, which implies it might be null. Fix this by null checking df->governor before dereferencing it. Addresses-Coverity-ID: 1401988 ("Dereference before null check") Fixes: bcf23c79c4e4 ("PM / devfreq: Fix available_governor sysfs") Signed-off-by: Gustavo A. R. Silva Reviewed-by: Chanwoo Choi Signed-off-by: MyungJoo Ham Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/devfreq/devfreq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 9e5674c5a07b..db70cee71caa 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -943,7 +943,8 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, if (df->governor == governor) { ret = 0; goto out; - } else if (df->governor->immutable || governor->immutable) { + } else if ((df->governor && df->governor->immutable) || + governor->immutable) { ret = -EINVAL; goto out; } -- GitLab From 8d008c0ce55c89c47d70646ae244c006abecd288 Mon Sep 17 00:00:00 2001 From: Maciej Purski Date: Wed, 22 Nov 2017 16:32:15 +0100 Subject: [PATCH 1117/1834] hwmon: (ina2xx) Make calibration register value fixed [ Upstream commit 5d389b125186cf254ad5b8015763ac07c151aea4 ] Calibration register is used for calculating current register in hardware according to datasheet: current = shunt_volt * calib_register / 2048 (ina 226) current = shunt_volt * calib_register / 4096 (ina 219) Fix calib_register value to 2048 for ina226 and 4096 for ina 219 in order to avoid truncation error and provide best precision allowed by shunt_voltage measurement. Make current scale value follow changes of shunt_resistor from sysfs as calib_register value is now fixed. Power_lsb value should also follow shunt_resistor changes as stated in datasheet: power_lsb = 25 * current_lsb (ina 226) power_lsb = 20 * current_lsb (ina 219) Signed-off-by: Maciej Purski Signed-off-by: Guenter Roeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/ina2xx.c | 87 ++++++++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index b24f1d3045f0..a629f7c130f0 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -94,18 +94,20 @@ enum ina2xx_ids { ina219, ina226 }; struct ina2xx_config { u16 config_default; - int calibration_factor; + int calibration_value; int registers; int shunt_div; int bus_voltage_shift; int bus_voltage_lsb; /* uV */ - int power_lsb; /* uW */ + int power_lsb_factor; }; struct ina2xx_data { const struct ina2xx_config *config; long rshunt; + long current_lsb_uA; + long power_lsb_uW; struct mutex config_lock; struct regmap *regmap; @@ -115,21 +117,21 @@ struct ina2xx_data { static const struct ina2xx_config ina2xx_config[] = { [ina219] = { .config_default = INA219_CONFIG_DEFAULT, - .calibration_factor = 40960000, + .calibration_value = 4096, .registers = INA219_REGISTERS, .shunt_div = 100, .bus_voltage_shift = 3, .bus_voltage_lsb = 4000, - .power_lsb = 20000, + .power_lsb_factor = 20, }, [ina226] = { .config_default = INA226_CONFIG_DEFAULT, - .calibration_factor = 5120000, + .calibration_value = 2048, .registers = INA226_REGISTERS, .shunt_div = 400, .bus_voltage_shift = 0, .bus_voltage_lsb = 1250, - .power_lsb = 25000, + .power_lsb_factor = 25, }, }; @@ -168,12 +170,16 @@ static u16 ina226_interval_to_reg(int interval) return INA226_SHIFT_AVG(avg_bits); } +/* + * Calibration register is set to the best value, which eliminates + * truncation errors on calculating current register in hardware. + * According to datasheet (eq. 3) the best values are 2048 for + * ina226 and 4096 for ina219. They are hardcoded as calibration_value. + */ static int ina2xx_calibrate(struct ina2xx_data *data) { - u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor, - data->rshunt); - - return regmap_write(data->regmap, INA2XX_CALIBRATION, val); + return regmap_write(data->regmap, INA2XX_CALIBRATION, + data->config->calibration_value); } /* @@ -186,10 +192,6 @@ static int ina2xx_init(struct ina2xx_data *data) if (ret < 0) return ret; - /* - * Set current LSB to 1mA, shunt is in uOhms - * (equation 13 in datasheet). - */ return ina2xx_calibrate(data); } @@ -267,15 +269,15 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg, val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_POWER: - val = regval * data->config->power_lsb; + val = regval * data->power_lsb_uW; break; case INA2XX_CURRENT: - /* signed register, LSB=1mA (selected), in mA */ - val = (s16)regval; + /* signed register, result in mA */ + val = regval * data->current_lsb_uA; + val = DIV_ROUND_CLOSEST(val, 1000); break; case INA2XX_CALIBRATION: - val = DIV_ROUND_CLOSEST(data->config->calibration_factor, - regval); + val = regval; break; default: /* programmer goofed */ @@ -303,9 +305,32 @@ static ssize_t ina2xx_show_value(struct device *dev, ina2xx_get_value(data, attr->index, regval)); } -static ssize_t ina2xx_set_shunt(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +/* + * In order to keep calibration register value fixed, the product + * of current_lsb and shunt_resistor should also be fixed and equal + * to shunt_voltage_lsb = 1 / shunt_div multiplied by 10^9 in order + * to keep the scale. + */ +static int ina2xx_set_shunt(struct ina2xx_data *data, long val) +{ + unsigned int dividend = DIV_ROUND_CLOSEST(1000000000, + data->config->shunt_div); + if (val <= 0 || val > dividend) + return -EINVAL; + + mutex_lock(&data->config_lock); + data->rshunt = val; + data->current_lsb_uA = DIV_ROUND_CLOSEST(dividend, val); + data->power_lsb_uW = data->config->power_lsb_factor * + data->current_lsb_uA; + mutex_unlock(&data->config_lock); + + return 0; +} + +static ssize_t ina2xx_store_shunt(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) { unsigned long val; int status; @@ -315,18 +340,9 @@ static ssize_t ina2xx_set_shunt(struct device *dev, if (status < 0) return status; - if (val == 0 || - /* Values greater than the calibration factor make no sense. */ - val > data->config->calibration_factor) - return -EINVAL; - - mutex_lock(&data->config_lock); - data->rshunt = val; - status = ina2xx_calibrate(data); - mutex_unlock(&data->config_lock); + status = ina2xx_set_shunt(data, val); if (status < 0) return status; - return count; } @@ -386,7 +402,7 @@ static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL, /* shunt resistance */ static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR, - ina2xx_show_value, ina2xx_set_shunt, + ina2xx_show_value, ina2xx_store_shunt, INA2XX_CALIBRATION); /* update interval (ina226 only) */ @@ -441,10 +457,7 @@ static int ina2xx_probe(struct i2c_client *client, val = INA2XX_RSHUNT_DEFAULT; } - if (val <= 0 || val > data->config->calibration_factor) - return -ENODEV; - - data->rshunt = val; + ina2xx_set_shunt(data, val); ina2xx_regmap_config.max_register = data->config->registers; -- GitLab From 1be3eb15225dc01451a4989ac13faf50116fabaf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 28 Dec 2017 09:16:47 -0500 Subject: [PATCH 1118/1834] media: videobuf2-core: don't go out of the buffer range [ Upstream commit df93dc61b0d8b19a5c9db545cf3fcc24f88dfde4 ] Currently, there's no check if an invalid buffer range is passed. However, while testing DVB memory mapped apps, I got this: videobuf2_core: VB: num_buffers -2143943680, buffer 33, index -2143943647 unable to handle kernel paging request at ffff888b773c0890 IP: __vb2_queue_alloc+0x134/0x4e0 [videobuf2_core] PGD 4142c7067 P4D 4142c7067 PUD 0 Oops: 0002 [#1] SMP Modules linked in: xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack tun bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables bluetooth rfkill ecdh_generic binfmt_misc rc_dvbsky sp2 ts2020 intel_rapl x86_pkg_temp_thermal dvb_usb_dvbsky intel_powerclamp dvb_usb_v2 coretemp m88ds3103 kvm_intel i2c_mux dvb_core snd_hda_codec_hdmi crct10dif_pclmul crc32_pclmul videobuf2_vmalloc videobuf2_memops snd_hda_intel ghash_clmulni_intel videobuf2_core snd_hda_codec rc_core mei_me intel_cstate snd_hwdep snd_hda_core videodev intel_uncore snd_pcm mei media tpm_tis tpm_tis_core intel_rapl_perf tpm snd_timer lpc_ich snd soundcore kvm irqbypass libcrc32c i915 i2c_algo_bit drm_kms_helper e1000e ptp drm crc32c_intel video pps_core CPU: 3 PID: 1776 Comm: dvbv5-zap Not tainted 4.14.0+ #78 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 task: ffff88877c73bc80 task.stack: ffffb7c402418000 RIP: 0010:__vb2_queue_alloc+0x134/0x4e0 [videobuf2_core] RSP: 0018:ffffb7c40241bc60 EFLAGS: 00010246 RAX: 0000000080360421 RBX: 0000000000000021 RCX: 000000000000000a RDX: ffffb7c40241bcf4 RSI: ffff888780362c60 RDI: ffff888796d8e130 RBP: ffffb7c40241bcc8 R08: 0000000000000316 R09: 0000000000000004 R10: ffff888780362c00 R11: 0000000000000001 R12: 000000000002f000 R13: ffff8887758be700 R14: 0000000000021000 R15: 0000000000000001 FS: 00007f2849024740(0000) GS:ffff888796d80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: ffff888b773c0890 CR3: 000000043beb2005 CR4: 00000000003606e0 Call Trace: vb2_core_reqbufs+0x226/0x420 [videobuf2_core] dvb_vb2_reqbufs+0x2d/0xc0 [dvb_core] dvb_dvr_do_ioctl+0x98/0x1d0 [dvb_core] dvb_usercopy+0x53/0x1b0 [dvb_core] ? dvb_demux_ioctl+0x20/0x20 [dvb_core] ? tty_ldisc_deref+0x16/0x20 ? tty_write+0x1f9/0x310 ? process_echoes+0x70/0x70 dvb_dvr_ioctl+0x15/0x20 [dvb_core] do_vfs_ioctl+0xa5/0x600 SyS_ioctl+0x79/0x90 entry_SYSCALL_64_fastpath+0x1a/0xa5 RIP: 0033:0x7f28486f7ea7 RSP: 002b:00007ffc13b2db18 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 000055b10fc06130 RCX: 00007f28486f7ea7 RDX: 00007ffc13b2db48 RSI: 00000000c0086f3c RDI: 0000000000000007 RBP: 0000000000000203 R08: 000055b10df1e02c R09: 000000000000002e R10: 0036b42415108357 R11: 0000000000000246 R12: 0000000000000000 R13: 00007f2849062f60 R14: 00000000000001f1 R15: 00007ffc13b2da54 Code: 74 0a 60 8b 0a 48 83 c0 30 48 83 c2 04 89 48 d0 89 48 d4 48 39 f0 75 eb 41 8b 42 08 83 7d d4 01 41 c7 82 ec 01 00 00 ff ff ff ff <4d> 89 94 c5 88 00 00 00 74 14 83 c3 01 41 39 dc 0f 85 f1 fe ff RIP: __vb2_queue_alloc+0x134/0x4e0 [videobuf2_core] RSP: ffffb7c40241bc60 CR2: ffff888b773c0890 So, add a sanity check in order to prevent going past array. Signed-off-by: Mauro Carvalho Chehab Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/videobuf2-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 9ccf7f5e0e2e..4299ce06c25b 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -334,6 +334,10 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, struct vb2_buffer *vb; int ret; + /* Ensure that q->num_buffers+num_buffers is below VB2_MAX_FRAME */ + num_buffers = min_t(unsigned int, num_buffers, + VB2_MAX_FRAME - q->num_buffers); + for (buffer = 0; buffer < num_buffers; ++buffer) { /* Allocate videobuf buffer structures */ vb = kzalloc(q->buf_struct_size, GFP_KERNEL); -- GitLab From 423535006ae6e1bce58922597b250fd89de98835 Mon Sep 17 00:00:00 2001 From: Pardha Saradhi K Date: Tue, 2 Jan 2018 14:59:57 +0530 Subject: [PATCH 1119/1834] ASoC: Intel: Skylake: Disable clock gating during firmware and library download [ Upstream commit d5cc0a1fcbb5ddbef9fdd4c4a978da3254ddbf37 ] During firmware and library download, sometimes it is observed that firmware and library download is timed-out resulting into probe failure. This patch disables dynamic clock gating while firmware and library download. Signed-off-by: Pardha Saradhi K Signed-off-by: Sanyog Kale Signed-off-by: Guneshwor Singh Acked-By: Vinod Koul Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/skylake/skl-messages.c | 4 ++++ sound/soc/intel/skylake/skl-pcm.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 805b7f2173f3..78472c908ae9 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -331,7 +331,11 @@ int skl_resume_dsp(struct skl *skl) if (skl->skl_sst->is_first_boot == true) return 0; + /* disable dynamic clock gating during fw and lib download */ + ctx->enable_miscbdcge(ctx->dev, false); + ret = skl_dsp_wake(ctx->dsp); + ctx->enable_miscbdcge(ctx->dev, true); if (ret < 0) return ret; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 58c728662600..2fd213cd9a40 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1191,7 +1191,11 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) return -EIO; } + /* disable dynamic clock gating during fw and lib download */ + skl->skl_sst->enable_miscbdcge(platform->dev, false); + ret = ops->init_fw(platform->dev, skl->skl_sst); + skl->skl_sst->enable_miscbdcge(platform->dev, true); if (ret < 0) { dev_err(platform->dev, "Failed to boot first fw: %d\n", ret); return ret; -- GitLab From c5ae3c610dd0447f60c2b03fc00a14d39e2dfb0f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 2 Jan 2018 19:53:14 +0100 Subject: [PATCH 1120/1834] ASoC: Intel: cht_bsw_rt5645: Analog Mic support [ Upstream commit b70b309950418437bbd2a30afd169c4f09dee3e5 ] Various Cherry Trail boards with a rt5645 codec have an analog mic connected to IN2P + IN2N. The mic on this boards also needs micbias to be enabled, on some boards micbias1 is used and on others micbias2, so we enable both. This commit adds a new "Int Analog Mic" DAPM widget for this, so that we do not end up enabling micbias on boards with a digital mic which uses the already present "Int Mic" widget. Some existing UCM files already refer to "Int Mic" for their "Internal Analog Microphones" SectionDevice, but these don't work anyways since they enable the RECMIX BST1 Switch instead of the BST2 switch. Signed-off-by: Hans de Goede Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/boards/cht_bsw_rt5645.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 90525614c20a..b1eb696f33b6 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -111,6 +111,7 @@ static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_MIC("Int Analog Mic", NULL), SND_SOC_DAPM_SPK("Ext Spk", NULL), SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -121,6 +122,8 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { {"IN1N", NULL, "Headset Mic"}, {"DMIC L1", NULL, "Int Mic"}, {"DMIC R1", NULL, "Int Mic"}, + {"IN2P", NULL, "Int Analog Mic"}, + {"IN2N", NULL, "Int Analog Mic"}, {"Headphone", NULL, "HPOL"}, {"Headphone", NULL, "HPOR"}, {"Ext Spk", NULL, "SPOL"}, @@ -134,6 +137,9 @@ static const struct snd_soc_dapm_route cht_rt5645_audio_map[] = { {"Headphone", NULL, "Platform Clock"}, {"Headset Mic", NULL, "Platform Clock"}, {"Int Mic", NULL, "Platform Clock"}, + {"Int Analog Mic", NULL, "Platform Clock"}, + {"Int Analog Mic", NULL, "micbias1"}, + {"Int Analog Mic", NULL, "micbias2"}, {"Ext Spk", NULL, "Platform Clock"}, }; @@ -162,6 +168,7 @@ static const struct snd_kcontrol_new cht_mc_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Int Analog Mic"), SOC_DAPM_PIN_SWITCH("Ext Spk"), }; -- GitLab From a8cfc6d0e7ace50a81a3f4ce1b7874dacbd3e4e4 Mon Sep 17 00:00:00 2001 From: Rafael David Tinoco Date: Thu, 7 Dec 2017 19:59:13 -0200 Subject: [PATCH 1121/1834] scsi: libiscsi: Allow sd_shutdown on bad transport [ Upstream commit d754941225a7dbc61f6dd2173fa9498049f9a7ee ] If, for any reason, userland shuts down iscsi transport interfaces before proper logouts - like when logging in to LUNs manually, without logging out on server shutdown, or when automated scripts can't umount/logout from logged LUNs - kernel will hang forever on its sd_sync_cache() logic, after issuing the SYNCHRONIZE_CACHE cmd to all still existent paths. PID: 1 TASK: ffff8801a69b8000 CPU: 1 COMMAND: "systemd-shutdow" #0 [ffff8801a69c3a30] __schedule at ffffffff8183e9ee #1 [ffff8801a69c3a80] schedule at ffffffff8183f0d5 #2 [ffff8801a69c3a98] schedule_timeout at ffffffff81842199 #3 [ffff8801a69c3b40] io_schedule_timeout at ffffffff8183e604 #4 [ffff8801a69c3b70] wait_for_completion_io_timeout at ffffffff8183fc6c #5 [ffff8801a69c3bd0] blk_execute_rq at ffffffff813cfe10 #6 [ffff8801a69c3c88] scsi_execute at ffffffff815c3fc7 #7 [ffff8801a69c3cc8] scsi_execute_req_flags at ffffffff815c60fe #8 [ffff8801a69c3d30] sd_sync_cache at ffffffff815d37d7 #9 [ffff8801a69c3da8] sd_shutdown at ffffffff815d3c3c This happens because iscsi_eh_cmd_timed_out(), the transport layer timeout helper, would tell the queue timeout function (scsi_times_out) to reset the request timer over and over, until the session state is back to logged in state. Unfortunately, during server shutdown, this might never happen again. Other option would be "not to handle" the issue in the transport layer. That would trigger the error handler logic, which would also need the session state to be logged in again. Best option, for such case, is to tell upper layers that the command was handled during the transport layer error handler helper, marking it as DID_NO_CONNECT, which will allow completion and inform about the problem. After the session was marked as ISCSI_STATE_FAILED, due to the first timeout during the server shutdown phase, all subsequent cmds will fail to be queued, allowing upper logic to fail faster. Signed-off-by: Rafael David Tinoco Reviewed-by: Lee Duncan Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libiscsi.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 4abd3fce5ab6..c2b682916337 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -1695,6 +1695,15 @@ int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) */ switch (session->state) { case ISCSI_STATE_FAILED: + /* + * cmds should fail during shutdown, if the session + * state is bad, allowing completion to happen + */ + if (unlikely(system_state != SYSTEM_RUNNING)) { + reason = FAILURE_SESSION_FAILED; + sc->result = DID_NO_CONNECT << 16; + break; + } case ISCSI_STATE_IN_RECOVERY: reason = FAILURE_SESSION_IN_RECOVERY; sc->result = DID_IMM_RETRY << 16; @@ -1979,6 +1988,19 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) } if (session->state != ISCSI_STATE_LOGGED_IN) { + /* + * During shutdown, if session is prematurely disconnected, + * recovery won't happen and there will be hung cmds. Not + * handling cmds would trigger EH, also bad in this case. + * Instead, handle cmd, allow completion to happen and let + * upper layer to deal with the result. + */ + if (unlikely(system_state != SYSTEM_RUNNING)) { + sc->result = DID_NO_CONNECT << 16; + ISCSI_DBG_EH(session, "sc on shutdown, handled\n"); + rc = BLK_EH_HANDLED; + goto done; + } /* * We are probably in the middle of iscsi recovery so let * that complete and handle the error. @@ -2083,7 +2105,7 @@ static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) task->last_timeout = jiffies; spin_unlock(&session->frwd_lock); ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? - "timer reset" : "nh"); + "timer reset" : "shutdown or nh"); return rc; } -- GitLab From 388f0c8cfca271b4505fadde31d2eaecd2516cfa Mon Sep 17 00:00:00 2001 From: Chaitra P B Date: Wed, 27 Dec 2017 23:09:11 -0800 Subject: [PATCH 1122/1834] scsi: mpt3sas: Proper handling of set/clear of "ATA command pending" flag. [ Upstream commit f49d4aed1315a7b766d855f1367142e682b0cc87 ] 1. In IO path, setting of "ATA command pending" flag early before device removal, invalid device handle etc., checks causes any new commands to be always returned with SAM_STAT_BUSY and when the driver removes the drive the SML issues SYNC Cache command and that command is always returned with SAM_STAT_BUSY and thus making SYNC Cache command to requeued. 2. If the driver gets an ATA PT command for a SATA drive then the driver set "ATA command pending" flag in device specific data structure not to allow any further commands until the ATA PT command is completed. However, after setting the flag if the driver decides to return the command back to upper layers without actually issuing to the firmware (i.e., returns from qcmd failure return paths) then the corresponding flag is not cleared and this prevents the driver from sending any new commands to the drive. This patch fixes above two issues by setting of "ATA command pending" flag after checking for whether device deleted, invalid device handle, device busy with task management. And by setting "ATA command pending" flag to false in all of the qcmd failure return paths after setting the flag. Signed-off-by: Chaitra P B Signed-off-by: Suganath Prabu S Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 468acab04d3d..b8589068d175 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4065,19 +4065,6 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) return 0; } - /* - * Bug work around for firmware SATL handling. The loop - * is based on atomic operations and ensures consistency - * since we're lockless at this point - */ - do { - if (test_bit(0, &sas_device_priv_data->ata_command_pending)) { - scmd->result = SAM_STAT_BUSY; - scmd->scsi_done(scmd); - return 0; - } - } while (_scsih_set_satl_pending(scmd, true)); - sas_target_priv_data = sas_device_priv_data->sas_target; /* invalid device handle */ @@ -4103,6 +4090,19 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) sas_device_priv_data->block) return SCSI_MLQUEUE_DEVICE_BUSY; + /* + * Bug work around for firmware SATL handling. The loop + * is based on atomic operations and ensures consistency + * since we're lockless at this point + */ + do { + if (test_bit(0, &sas_device_priv_data->ata_command_pending)) { + scmd->result = SAM_STAT_BUSY; + scmd->scsi_done(scmd); + return 0; + } + } while (_scsih_set_satl_pending(scmd, true)); + if (scmd->sc_data_direction == DMA_FROM_DEVICE) mpi_control = MPI2_SCSIIO_CONTROL_READ; else if (scmd->sc_data_direction == DMA_TO_DEVICE) @@ -4124,6 +4124,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) if (!smid) { pr_err(MPT3SAS_FMT "%s: failed obtaining a smid\n", ioc->name, __func__); + _scsih_set_satl_pending(scmd, false); goto out; } mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); @@ -4154,6 +4155,7 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) if (mpi_request->DataLength) { if (ioc->build_sg_scmd(ioc, scmd, smid)) { mpt3sas_base_free_smid(ioc, smid); + _scsih_set_satl_pending(scmd, false); goto out; } } else -- GitLab From c979024a1bb359988dc6b50a26dd3bb0789fd54f Mon Sep 17 00:00:00 2001 From: Shanker Donthineni Date: Tue, 5 Dec 2017 13:16:21 -0600 Subject: [PATCH 1123/1834] irqchip/gic-v3: Fix the driver probe() fail due to disabled GICC entry [ Upstream commit ebe2f8718007d5a1238bb3cb8141b5bb2b4d5773 ] The ACPI specification says OS shouldn't attempt to use GICC configuration parameters if the flag ACPI_MADT_ENABLED is cleared. The ARM64-SMP code skips the disabled GICC entries but not causing any issue. However the current GICv3 driver probe bails out causing kernel panic() instead of skipping the disabled GICC interfaces. This issue happens on systems where redistributor regions are not in the always-on power domain and one of GICC interface marked with ACPI_MADT_ENABLED=0. This patch does the two things to fix the panic. - Don't return an error in gic_acpi_match_gicc() for disabled GICC entry. - No need to keep GICR region information for disabled GICC entry. Observed kernel crash on QDF2400 platform GICC entry is disabled. Kernel crash traces: Kernel panic - not syncing: No interrupt controller found. CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.13.5 #26 [] dump_backtrace+0x0/0x218 [] show_stack+0x14/0x20 [] dump_stack+0x98/0xb8 [] panic+0x118/0x26c [] init_IRQ+0x24/0x2c [] start_kernel+0x230/0x394 [] __primary_switched+0x64/0x6c ---[ end Kernel panic - not syncing: No interrupt controller found. Disabled GICC subtable example: Subtable Type : 0B [Generic Interrupt Controller] Length : 50 Reserved : 0000 CPU Interface Number : 0000003D Processor UID : 0000003D Flags (decoded below) : 00000000 Processor Enabled : 0 Performance Interrupt Trig Mode : 0 Virtual GIC Interrupt Trig Mode : 0 Parking Protocol Version : 00000000 Performance Interrupt : 00000017 Parked Address : 0000000000000000 Base Address : 0000000000000000 Virtual GIC Base Address : 0000000000000000 Hypervisor GIC Base Address : 0000000000000000 Virtual GIC Interrupt : 00000019 Redistributor Base Address : 0000FFFF88F40000 ARM MPIDR : 000000000000000D Efficiency Class : 00 Reserved : 000000 Signed-off-by: Shanker Donthineni Signed-off-by: Marc Zyngier Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-v3.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index fd4a78296b48..100c80e48190 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -1250,6 +1250,10 @@ gic_acpi_parse_madt_gicc(struct acpi_subtable_header *header, u32 size = reg == GIC_PIDR2_ARCH_GICv4 ? SZ_64K * 4 : SZ_64K * 2; void __iomem *redist_base; + /* GICC entry which has !ACPI_MADT_ENABLED is not unusable so skip */ + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return 0; + redist_base = ioremap(gicc->gicr_base_address, size); if (!redist_base) return -ENOMEM; @@ -1299,6 +1303,13 @@ static int __init gic_acpi_match_gicc(struct acpi_subtable_header *header, if ((gicc->flags & ACPI_MADT_ENABLED) && gicc->gicr_base_address) return 0; + /* + * It's perfectly valid firmware can pass disabled GICC entry, driver + * should not treat as errors, skip the entry instead of probe fail. + */ + if (!(gicc->flags & ACPI_MADT_ENABLED)) + return 0; + return -ENODEV; } -- GitLab From b7fe48228d816c1ad7e1e90e2bff7d09d17e6642 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 2 Jan 2018 16:26:31 +0100 Subject: [PATCH 1124/1834] ACPI: EC: Fix debugfs_create_*() usage [ Upstream commit 3522f867c13b63cf62acdf1b8ca5664c549a716a ] acpi_ec.gpe is "unsigned long", hence treating it as "u32" would expose the wrong half on big-endian 64-bit systems. Fix this by changing its type to "u32" and removing the cast, as all other code already uses u32 or sometimes even only u8. Fixes: 1195a098168fcacf (ACPI: Provide /sys/kernel/debug/ec/...) Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/ec.c | 2 +- drivers/acpi/ec_sys.c | 2 +- drivers/acpi/internal.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index c3bcb7f5986e..307b3e28f34c 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1518,7 +1518,7 @@ static int acpi_ec_setup(struct acpi_ec *ec, bool handle_events) } acpi_handle_info(ec->handle, - "GPE=0x%lx, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", + "GPE=0x%x, EC_CMD/EC_SC=0x%lx, EC_DATA=0x%lx\n", ec->gpe, ec->command_addr, ec->data_addr); return ret; } diff --git a/drivers/acpi/ec_sys.c b/drivers/acpi/ec_sys.c index 6c7dd7af789e..dd70d6c2bca0 100644 --- a/drivers/acpi/ec_sys.c +++ b/drivers/acpi/ec_sys.c @@ -128,7 +128,7 @@ static int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) return -ENOMEM; } - if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe)) + if (!debugfs_create_x32("gpe", 0444, dev_dir, &first_ec->gpe)) goto error; if (!debugfs_create_bool("use_global_lock", 0444, dev_dir, &first_ec->global_lock)) diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 08b3ca0ead69..b012e94b7d9f 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -158,7 +158,7 @@ static inline void acpi_early_processor_osc(void) {} -------------------------------------------------------------------------- */ struct acpi_ec { acpi_handle handle; - unsigned long gpe; + u32 gpe; unsigned long command_addr; unsigned long data_addr; bool global_lock; -- GitLab From c6f782877d36d7d2b2f07f22b6e81049f692dfc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Peter=20Gro=C3=9Fe?= Date: Wed, 13 Dec 2017 18:29:46 +0100 Subject: [PATCH 1125/1834] mac80211: Fix setting TX power on monitor interfaces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 3a3713ec360138f806c6fc368d1de570f692b347 ] Instead of calling ieee80211_recalc_txpower on monitor interfaces directly, call it using the virtual monitor interface, if one exists. In case of a single monitor interface given, reject setting TX power, if no virtual monitor interface exists. That being checked, don't warn in ieee80211_bss_info_change_notify, after setting TX power on a monitor interface. Fixes warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 2193 at net/mac80211/driver-ops.h:167 ieee80211_bss_info_change_notify+0x111/0x190 Modules linked in: uvcvideo videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_core rndis_host cdc_ether usbnet mii tp_smapi(O) thinkpad_ec(O) ohci_hcd vboxpci(O) vboxnetadp(O) vboxnetflt(O) v boxdrv(O) x86_pkg_temp_thermal kvm_intel kvm irqbypass iwldvm iwlwifi ehci_pci ehci_hcd tpm_tis tpm_tis_core tpm CPU: 0 PID: 2193 Comm: iw Tainted: G O 4.12.12-gentoo #2 task: ffff880186fd5cc0 task.stack: ffffc90001b54000 RIP: 0010:ieee80211_bss_info_change_notify+0x111/0x190 RSP: 0018:ffffc90001b57a10 EFLAGS: 00010246 RAX: 0000000000000006 RBX: ffff8801052ce840 RCX: 0000000000000064 RDX: 00000000fffffffc RSI: 0000000000040000 RDI: ffff8801052ce840 RBP: ffffc90001b57a38 R08: 0000000000000062 R09: 0000000000000000 R10: ffff8802144b5000 R11: ffff880049dc4614 R12: 0000000000040000 R13: 0000000000000064 R14: ffff8802105f0760 R15: ffffc90001b57b48 FS: 00007f92644b4580(0000) GS:ffff88021e200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f9263c109f0 CR3: 00000001df850000 CR4: 00000000000406f0 Call Trace: ieee80211_recalc_txpower+0x33/0x40 ieee80211_set_tx_power+0x40/0x180 nl80211_set_wiphy+0x32e/0x950 Reported-by: Peter Große Signed-off-by: Peter Große Signed-off-by: Johannes Berg Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/mac80211/cfg.c | 28 +++++++++++++++++++++++++++- net/mac80211/driver-ops.h | 3 ++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index efa2a2fcae72..d7801f6877af 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2341,10 +2341,17 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, struct ieee80211_sub_if_data *sdata; enum nl80211_tx_power_setting txp_type = type; bool update_txp_type = false; + bool has_monitor = false; if (wdev) { sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { + sdata = rtnl_dereference(local->monitor_sdata); + if (!sdata) + return -EOPNOTSUPP; + } + switch (type) { case NL80211_TX_POWER_AUTOMATIC: sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL; @@ -2383,15 +2390,34 @@ static int ieee80211_set_tx_power(struct wiphy *wiphy, mutex_lock(&local->iflist_mtx); list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) { + has_monitor = true; + continue; + } sdata->user_power_level = local->user_power_level; if (txp_type != sdata->vif.bss_conf.txpower_type) update_txp_type = true; sdata->vif.bss_conf.txpower_type = txp_type; } - list_for_each_entry(sdata, &local->interfaces, list) + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR) + continue; ieee80211_recalc_txpower(sdata, update_txp_type); + } mutex_unlock(&local->iflist_mtx); + if (has_monitor) { + sdata = rtnl_dereference(local->monitor_sdata); + if (sdata) { + sdata->user_power_level = local->user_power_level; + if (txp_type != sdata->vif.bss_conf.txpower_type) + update_txp_type = true; + sdata->vif.bss_conf.txpower_type = txp_type; + + ieee80211_recalc_txpower(sdata, update_txp_type); + } + } + return 0; } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 09f77e4a8a79..49c8a9c9b91f 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -164,7 +164,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local, if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || sdata->vif.type == NL80211_IFTYPE_NAN || (sdata->vif.type == NL80211_IFTYPE_MONITOR && - !sdata->vif.mu_mimo_owner))) + !sdata->vif.mu_mimo_owner && + !(changed & BSS_CHANGED_TXPOWER)))) return; if (!check_sdata_in_driver(sdata)) -- GitLab From 2707d9b2f90136cfaea307198d83959ca8da815e Mon Sep 17 00:00:00 2001 From: "Pieter \\\"PoroCYon\\\" Sluys" Date: Thu, 4 Jan 2018 16:53:50 +0100 Subject: [PATCH 1126/1834] vfb: fix video mode and line_length being set when loaded [ Upstream commit 7b9faf5df0ac495a1a3d7cdb64921c179f9008ac ] Currently, when loading the vfb module, the newly created fbdev has a line_length of 0, and its video mode would be PSEUDOCOLOR regardless of color depth. (The former could be worked around by calling the FBIOPUT_VSCREENINFO ioctl with having the FBACTIVIATE_FORCE flag set.) This patch automatically sets the line_length correctly, and the video mode is derived from the bit depth now as well. Thanks to Geert Uytterhoeven for confirming the bug and helping me with the patch. Output of `fbset -i' before the patch: mode "1366x768-60" # D: 72.432 MHz, H: 47.403 kHz, V: 60.004 Hz geometry 1366 768 1366 768 32 timings 13806 120 10 14 3 32 5 rgba 8/0,8/8,8/16,8/24 endmode Frame buffer device information: Name : Virtual FB Address : 0xffffaa1405d85000 Size : 4196352 Type : PACKED PIXELS Visual : PSEUDOCOLOR XPanStep : 1 YPanStep : 1 YWrapStep : 1 LineLength : 0 <-- note this Accelerator : No After: mode "1366x768-60" # D: 72.432 MHz, H: 47.403 kHz, V: 60.004 Hz geometry 1366 768 1366 768 32 timings 13806 120 10 14 3 32 5 rgba 8/0,8/8,8/16,8/24 endmode Frame buffer device information: Name : Virtual FB Address : 0xffffaa1405d85000 Size : 4196352 Type : PACKED PIXELS Visual : TRUECOLOR XPanStep : 1 YPanStep : 1 YWrapStep : 1 LineLength : 5464 Accelerator : No Signed-off-by: "Pieter \"PoroCYon\" Sluys" Reviewed-by: Geert Uytterhoeven [b.zolnierkie: minor fixups] Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/fbdev/vfb.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c index da653a080394..54127905bfe7 100644 --- a/drivers/video/fbdev/vfb.c +++ b/drivers/video/fbdev/vfb.c @@ -239,8 +239,23 @@ static int vfb_check_var(struct fb_var_screeninfo *var, */ static int vfb_set_par(struct fb_info *info) { + switch (info->var.bits_per_pixel) { + case 1: + info->fix.visual = FB_VISUAL_MONO01; + break; + case 8: + info->fix.visual = FB_VISUAL_PSEUDOCOLOR; + break; + case 16: + case 24: + case 32: + info->fix.visual = FB_VISUAL_TRUECOLOR; + break; + } + info->fix.line_length = get_line_length(info->var.xres_virtual, info->var.bits_per_pixel); + return 0; } @@ -450,6 +465,8 @@ static int vfb_probe(struct platform_device *dev) goto err2; platform_set_drvdata(dev, info); + vfb_set_par(info); + fb_info(info, "Virtual frame buffer device, using %ldK of video memory\n", videomemorysize >> 10); return 0; -- GitLab From c5aa51c82e6ed7c203b2b8415645dfea249cc369 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 4 Jan 2018 22:31:11 +0100 Subject: [PATCH 1127/1834] gpio: label descriptors using the device name [ Upstream commit 24e78079bf2250874e33da2e7cfbb6db72d3caf4 ] Some GPIO lines appear named "?" in the lsgpio dump due to their requesting drivers not passing a reasonable label. Most typically this happens if a device tree node just defines gpios = <...> and not foo-gpios = <...>, the former gets named "foo" and the latter gets named "?". However the struct device passed in is always valid so let's just label the GPIO with dev_name() on the device if no proper label was passed. Cc: Reported-by: Jason Kridner Reported-by: Jason Kridner Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f3c3680963b9..4f54ff45e09e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -3231,7 +3231,8 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev, return desc; } - status = gpiod_request(desc, con_id); + /* If a connection label was passed use that, else use the device name as label */ + status = gpiod_request(desc, con_id ? con_id : dev_name(dev)); if (status < 0) return ERR_PTR(status); -- GitLab From 5736369b54e3a4dc00592df922fbd8d739fb5be2 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 18 Dec 2017 19:57:06 -0800 Subject: [PATCH 1128/1834] IB/rdmavt: Allocate CQ memory on the correct node [ Upstream commit db9a2c6f9b6196b889b98e961cb9a37617b11ccf ] CQ allocation does not ensure that completion queue entries and the completion queue structure are allocated on the correct numa node. Fix by allocating the rvt_cq and kernel CQ entries on the device node, leaving the user CQ entries on the default local node. Also ensure CQ resizes use the correct allocator when extending a CQ. Reviewed-by: Sebastian Sanchez Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/sw/rdmavt/cq.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c index 6d9904a4a0ab..29dc5278d7be 100644 --- a/drivers/infiniband/sw/rdmavt/cq.c +++ b/drivers/infiniband/sw/rdmavt/cq.c @@ -197,7 +197,7 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev, return ERR_PTR(-EINVAL); /* Allocate the completion queue structure. */ - cq = kzalloc(sizeof(*cq), GFP_KERNEL); + cq = kzalloc_node(sizeof(*cq), GFP_KERNEL, rdi->dparms.node); if (!cq) return ERR_PTR(-ENOMEM); @@ -213,7 +213,9 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev, sz += sizeof(struct ib_uverbs_wc) * (entries + 1); else sz += sizeof(struct ib_wc) * (entries + 1); - wc = vmalloc_user(sz); + wc = udata ? + vmalloc_user(sz) : + vzalloc_node(sz, rdi->dparms.node); if (!wc) { ret = ERR_PTR(-ENOMEM); goto bail_cq; @@ -368,7 +370,9 @@ int rvt_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) sz += sizeof(struct ib_uverbs_wc) * (cqe + 1); else sz += sizeof(struct ib_wc) * (cqe + 1); - wc = vmalloc_user(sz); + wc = udata ? + vmalloc_user(sz) : + vzalloc_node(sz, rdi->dparms.node); if (!wc) return -ENOMEM; -- GitLab From 3bab65f29e6bf4615519b1e6dba5684cc8b53a72 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Sat, 6 Jan 2018 16:27:40 +0800 Subject: [PATCH 1129/1834] blk-mq: fix race between updating nr_hw_queues and switching io sched [ Upstream commit fb350e0ad99359768e1e80b4784692031ec340e4 ] In both elevator_switch_mq() and blk_mq_update_nr_hw_queues(), sched tags can be allocated, and q->nr_hw_queue is used, and race is inevitable, for example: blk_mq_init_sched() may trigger use-after-free on hctx, which is freed in blk_mq_realloc_hw_ctxs() when nr_hw_queues is decreased. This patch fixes the race be holding q->sysfs_lock. Reviewed-by: Christoph Hellwig Reported-by: Yi Zhang Tested-by: Yi Zhang Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/block/blk-mq.c b/block/blk-mq.c index 84c1efc70d3b..fe24429c6278 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1907,6 +1907,9 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, struct blk_mq_hw_ctx **hctxs = q->queue_hw_ctx; blk_mq_sysfs_unregister(q); + + /* protect against switching io scheduler */ + mutex_lock(&q->sysfs_lock); for (i = 0; i < set->nr_hw_queues; i++) { int node; @@ -1956,6 +1959,7 @@ static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, } } q->nr_hw_queues = i; + mutex_unlock(&q->sysfs_lock); blk_mq_sysfs_register(q); } -- GitLab From 8612220ec404743178d0d02eb29357d4739e802f Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Thu, 28 Dec 2017 09:27:41 +0100 Subject: [PATCH 1130/1834] backlight: tdo24m: Fix the SPI CS between transfers [ Upstream commit 2023b0524a6310e9ea80daf085f51c71bff9289f ] Currently the LCD display (TD035S) on the cm-x300 platform is broken and remains blank. The TD0245S specification requires that the chipselect is toggled between commands sent to the panel. This was also the purpose of the former patch of commit f64dcac0b124 ("backlight: tdo24m: ensure chip select changes between transfers"). Unfortunately, the "cs_change" field of a SPI transfer is misleading. Its true meaning is that for a SPI message holding multiple transfers, the chip select is toggled between each transfer, but for the last transfer it remains asserted. In this driver, all the SPI messages contain exactly one transfer, which means that each transfer is the last of its message, and as a consequence the chip select is never toggled. Actually, there was a second bug hidding the first one, hence the problem was not seen until v4.6. This problem was fixed by commit a52db659c79c ("spi: pxa2xx: Fix cs_change management") for PXA based boards. This fix makes the TD035S work again on a cm-x300 board. The same applies to other PXA boards, ie. corgi and tosa. Fixes: a52db659c79c ("spi: pxa2xx: Fix cs_change management") Reported-by: Andrea Adami Signed-off-by: Robert Jarzmik Acked-by: Daniel Thompson Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/corgi_lcd.c | 2 +- drivers/video/backlight/tdo24m.c | 2 +- drivers/video/backlight/tosa_lcd.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c index d7c239ea3d09..f5574060f9c8 100644 --- a/drivers/video/backlight/corgi_lcd.c +++ b/drivers/video/backlight/corgi_lcd.c @@ -177,7 +177,7 @@ static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int adrs, uint8_t data) struct spi_message msg; struct spi_transfer xfer = { .len = 1, - .cs_change = 1, + .cs_change = 0, .tx_buf = lcd->buf, }; diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index eab1f842f9c0..e4bd63e9db6b 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -369,7 +369,7 @@ static int tdo24m_probe(struct spi_device *spi) spi_message_init(m); - x->cs_change = 1; + x->cs_change = 0; x->tx_buf = &lcd->buf[0]; spi_message_add_tail(x, m); diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 6a41ea92737a..4dc5ee8debeb 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -49,7 +49,7 @@ static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data) struct spi_message msg; struct spi_transfer xfer = { .len = 1, - .cs_change = 1, + .cs_change = 0, .tx_buf = buf, }; -- GitLab From 2bc30f850f9f20ce3cfce4c9db524519b8bdcc21 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 1 Jan 2018 13:23:57 +0100 Subject: [PATCH 1131/1834] pinctrl: baytrail: Enable glitch filter for GPIOs used as interrupts [ Upstream commit 9291c65b01d1c67ebd56644cb19317ad665c44b3 ] On some systems, some PCB traces attached to GpioInts are routed in such a way that they pick up enough interference to constantly (many times per second) trigger. Enabling glitch-filtering fixes this. Signed-off-by: Hans de Goede Acked-by: Mika Westerberg Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/intel/pinctrl-baytrail.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 0a965026b134..fc5b18d3db20 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -46,6 +46,9 @@ #define BYT_TRIG_POS BIT(25) #define BYT_TRIG_LVL BIT(24) #define BYT_DEBOUNCE_EN BIT(20) +#define BYT_GLITCH_FILTER_EN BIT(19) +#define BYT_GLITCH_F_SLOW_CLK BIT(17) +#define BYT_GLITCH_F_FAST_CLK BIT(16) #define BYT_PULL_STR_SHIFT 9 #define BYT_PULL_STR_MASK (3 << BYT_PULL_STR_SHIFT) #define BYT_PULL_STR_2K (0 << BYT_PULL_STR_SHIFT) @@ -1579,6 +1582,9 @@ static int byt_irq_type(struct irq_data *d, unsigned int type) */ value &= ~(BYT_DIRECT_IRQ_EN | BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); + /* Enable glitch filtering */ + value |= BYT_GLITCH_FILTER_EN | BYT_GLITCH_F_SLOW_CLK | + BYT_GLITCH_F_FAST_CLK; writel(value, reg); -- GitLab From 29a63b0372f0fd6d8edc68829e02fe63ffd2735b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sat, 6 Jan 2018 21:18:24 +0100 Subject: [PATCH 1132/1834] ASoC: Intel: sst: Fix the return value of 'sst_send_byte_stream_mrfld()' [ Upstream commit eaadb1caa966a91128297b754e90b7c92b350a00 ] In some error handling paths, an error code is assiegned to 'ret'. However, the function always return 0. Fix it and return the error code if such an error paths is taken. Fixes: 3d9ff34622ba ("ASoC: Intel: sst: add stream operations") Signed-off-by: Christophe JAILLET Signed-off-by: Mark Brown Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- sound/soc/intel/atom/sst/sst_stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 4ccc80e5e8cc..c798f8d4ae43 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -221,7 +221,7 @@ int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, sst_free_block(sst_drv_ctx, block); out: test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); - return 0; + return ret; } /* -- GitLab From c8fed0d73cad36fd01cbd4fc8c18c4307b7bf95c Mon Sep 17 00:00:00 2001 From: Stanislaw Gruszka Date: Tue, 19 Dec 2017 12:33:56 +0100 Subject: [PATCH 1133/1834] rt2x00: do not pause queue unconditionally on error path [ Upstream commit 6dd80efd75ce7c2dbd9f117cf585ee2b33a42ee1 ] Pausing queue without checking threshold is racy with txdone path. Moreover we do not need pause queue on any error, but only if queue is full - in case when we send RTS frame ( other cases of almost full queue are already handled in rt2x00queue_write_tx_frame() ). Patch fixes of theoretically possible problem of pausing empty queue. Signed-off-by: Stanislaw Gruszka Tested-by: Enrico Mioso Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/wireless/ralink/rt2x00/rt2x00mac.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 13da95a24cf7..987c7c4f43cd 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -142,15 +142,25 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, if (!rt2x00dev->ops->hw->set_rts_threshold && (tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | IEEE80211_TX_RC_USE_CTS_PROTECT))) { - if (rt2x00queue_available(queue) <= 1) - goto exit_fail; + if (rt2x00queue_available(queue) <= 1) { + /* + * Recheck for full queue under lock to avoid race + * conditions with rt2x00lib_txdone(). + */ + spin_lock(&queue->tx_lock); + if (rt2x00queue_threshold(queue)) + rt2x00queue_pause_queue(queue); + spin_unlock(&queue->tx_lock); + + goto exit_free_skb; + } if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) - goto exit_fail; + goto exit_free_skb; } if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false))) - goto exit_fail; + goto exit_free_skb; /* * Pausing queue has to be serialized with rt2x00lib_txdone(). Note @@ -164,10 +174,6 @@ void rt2x00mac_tx(struct ieee80211_hw *hw, return; - exit_fail: - spin_lock(&queue->tx_lock); - rt2x00queue_pause_queue(queue); - spin_unlock(&queue->tx_lock); exit_free_skb: ieee80211_free_txskb(hw, skb); } -- GitLab From 0d9870ca5012400374c9789d91dcccb86508b63e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 26 Dec 2017 17:33:18 +0000 Subject: [PATCH 1134/1834] wl1251: check return from call to wl1251_acx_arp_ip_filter [ Upstream commit ac1181c60822292176ab96912208ec9f9819faf8 ] Currently the less than zero error check on ret is incorrect as it is checking a far earlier ret assignment rather than the return from the call to wl1251_acx_arp_ip_filter. Fix this by adding in the missing assginment. Detected by CoverityScan, CID#1164835 ("Logically dead code") Fixes: 204cc5c44fb6 ("wl1251: implement hardware ARP filtering") Signed-off-by: Colin Ian King Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ti/wl1251/main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index 1c539c83e8cf..5e41bf04ef61 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -1200,8 +1200,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc; - wl1251_acx_arp_ip_filter(wl, enable, addr); - + ret = wl1251_acx_arp_ip_filter(wl, enable, addr); if (ret < 0) goto out_sleep; } -- GitLab From 9f47b01992e19560fcbc536d0010581dd9f17a9b Mon Sep 17 00:00:00 2001 From: Firo Yang Date: Fri, 26 May 2017 22:37:38 +0800 Subject: [PATCH 1135/1834] hdlcdrv: Fix divide by zero in hdlcdrv_ioctl [ Upstream commit fb3ce90b7d7761b6f7f28f0ff5c456ef6b5229a1 ] syszkaller fuzzer triggered a divide by zero, when set calibration through ioctl(). To fix it, test 'bitrate' if it is negative or 0, just return -EINVAL. Reported-by: Andrey Konovalov Signed-off-by: Firo Yang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/hamradio/hdlcdrv.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 4bad0b894e9c..27160d1870e1 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -576,6 +576,8 @@ static int hdlcdrv_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case HDLCDRVCTL_CALIBRATE: if(!capable(CAP_SYS_RAWIO)) return -EPERM; + if (s->par.bitrate <= 0) + return -EINVAL; if (bi.data.calibrate > INT_MAX / s->par.bitrate) return -EINVAL; s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16; -- GitLab From ed9f34736a6b91ca7f0c0eaaa62343b2eb3bf306 Mon Sep 17 00:00:00 2001 From: Sai Praneeth Date: Fri, 26 May 2017 12:36:49 +0100 Subject: [PATCH 1136/1834] x86/efi: Disable runtime services on kexec kernel if booted with efi=old_map [ Upstream commit 4e52797d2efefac3271abdc54439a3435abd77b9 ] Booting kexec kernel with "efi=old_map" in kernel command line hits kernel panic as shown below. BUG: unable to handle kernel paging request at ffff88007fe78070 IP: virt_efi_set_variable.part.7+0x63/0x1b0 PGD 7ea28067 PUD 7ea2b067 PMD 7ea2d067 PTE 0 [...] Call Trace: virt_efi_set_variable() efi_delete_dummy_variable() efi_enter_virtual_mode() start_kernel() x86_64_start_reservations() x86_64_start_kernel() start_cpu() [ efi=old_map was never intended to work with kexec. The problem with using efi=old_map is that the virtual addresses are assigned from the memory region used by other kernel mappings; vmalloc() space. Potentially there could be collisions when booting kexec if something else is mapped at the virtual address we allocated for runtime service regions in the initial boot - Matt Fleming ] Since kexec was never intended to work with efi=old_map, disable runtime services in kexec if booted with efi=old_map, so that we don't panic. Tested-by: Lee Chun-Yi Signed-off-by: Sai Praneeth Prakhya Signed-off-by: Matt Fleming Acked-by: Dave Young Cc: Ard Biesheuvel Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Ravi Shankar Cc: Ricardo Neri Cc: Thomas Gleixner Cc: linux-efi@vger.kernel.org Link: http://lkml.kernel.org/r/20170526113652.21339-4-matt@codeblueprint.co.uk Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/platform/efi/efi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 274dfc481849..a0e85f2aff7d 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -832,9 +832,11 @@ static void __init kexec_enter_virtual_mode(void) /* * We don't do virtual mode, since we don't do runtime services, on - * non-native EFI + * non-native EFI. With efi=old_map, we don't do runtime services in + * kexec kernel because in the initial boot something else might + * have been mapped at these virtual addresses. */ - if (!efi_is_native()) { + if (!efi_is_native() || efi_enabled(EFI_OLD_MEMMAP)) { efi_memmap_unmap(); clear_bit(EFI_RUNTIME_SERVICES, &efi.flags); return; -- GitLab From f51c45447a5fb3d1a4fb304931444e6f9940ddab Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 21 May 2017 12:52:56 +0200 Subject: [PATCH 1137/1834] netfilter: conntrack: don't call iter for non-confirmed conntracks [ Upstream commit b0feacaad13a0aa9657c37ed80991575981e2e3b ] nf_ct_iterate_cleanup_net currently calls iter() callback also for conntracks on the unconfirmed list, but this is unsafe. Acesses to nf_conn are fine, but some users access the extension area in the iter() callback, but that does only work reliably for confirmed conntracks (ct->ext can be reallocated at any time for unconfirmed conntrack). The seond issue is that there is a short window where a conntrack entry is neither on the list nor in the table: To confirm an entry, it is first removed from the unconfirmed list, then insert into the table. Fix this by iterating the unconfirmed list first and marking all entries as dying, then wait for rcu grace period. This makes sure all entries that were about to be confirmed either are in the main table, or will be dropped soon. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/netfilter/nf_conntrack_core.c | 39 +++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 750b8bf13e60..2039fd7daf4e 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1542,7 +1542,6 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), struct nf_conntrack_tuple_hash *h; struct nf_conn *ct; struct hlist_nulls_node *n; - int cpu; spinlock_t *lockp; for (; *bucket < nf_conntrack_htable_size; (*bucket)++) { @@ -1564,24 +1563,40 @@ get_next_corpse(struct net *net, int (*iter)(struct nf_conn *i, void *data), cond_resched(); } + return NULL; +found: + atomic_inc(&ct->ct_general.use); + spin_unlock(lockp); + local_bh_enable(); + return ct; +} + +static void +__nf_ct_unconfirmed_destroy(struct net *net) +{ + int cpu; + for_each_possible_cpu(cpu) { - struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); + struct nf_conntrack_tuple_hash *h; + struct hlist_nulls_node *n; + struct ct_pcpu *pcpu; + + pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); spin_lock_bh(&pcpu->lock); hlist_nulls_for_each_entry(h, n, &pcpu->unconfirmed, hnnode) { + struct nf_conn *ct; + ct = nf_ct_tuplehash_to_ctrack(h); - if (iter(ct, data)) - set_bit(IPS_DYING_BIT, &ct->status); + + /* we cannot call iter() on unconfirmed list, the + * owning cpu can reallocate ct->ext at any time. + */ + set_bit(IPS_DYING_BIT, &ct->status); } spin_unlock_bh(&pcpu->lock); cond_resched(); } - return NULL; -found: - atomic_inc(&ct->ct_general.use); - spin_unlock(lockp); - local_bh_enable(); - return ct; } void nf_ct_iterate_cleanup(struct net *net, @@ -1596,6 +1611,10 @@ void nf_ct_iterate_cleanup(struct net *net, if (atomic_read(&net->ct.count) == 0) return; + __nf_ct_unconfirmed_destroy(net); + + synchronize_net(); + while ((ct = get_next_corpse(net, iter, data, &bucket)) != NULL) { /* Time to push up daises... */ -- GitLab From 3291bb532df5181352acfb492fc18b7110172670 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 9 May 2017 10:04:36 +0200 Subject: [PATCH 1138/1834] HID: i2c: Call acpi_device_fix_up_power for ACPI-enumerated devices [ Upstream commit f3d3eab667de62572376abb1aa26316191c39929 ] For ACPI devices which do not have a _PSC method, the ACPI subsys cannot query their initial state at boot, so these devices are assumed to have been put in D0 by the BIOS, but for touchscreens that is not always true. This commit adds a call to acpi_device_fix_up_power to explicitly put devices without a _PSC method into D0 state (for devices with a _PSC method it is a nop). Note we only need to do this on probe, after a resume the ACPI subsys knows the device is in D3 and will properly put it in D0. This fixes the SIS0817 i2c-hid touchscreen on a Peaq C1010 2-in-1 device failing to probe with a "hid_descr_cmd failed" error. Acked-by: Benjamin Tissoires Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hid/i2c-hid/i2c-hid.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 865e7c262322..7d6da9b43dab 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -968,6 +968,15 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client, return ret < 0 && ret != -ENXIO ? ret : 0; } +static void i2c_hid_acpi_fix_up_power(struct device *dev) +{ + acpi_handle handle = ACPI_HANDLE(dev); + struct acpi_device *adev; + + if (handle && acpi_bus_get_device(handle, &adev) == 0) + acpi_device_fix_up_power(adev); +} + static const struct acpi_device_id i2c_hid_acpi_match[] = { {"ACPI0C50", 0 }, {"PNP0C50", 0 }, @@ -980,6 +989,8 @@ static inline int i2c_hid_acpi_pdata(struct i2c_client *client, { return -ENODEV; } + +static inline void i2c_hid_acpi_fix_up_power(struct device *dev) {} #endif #ifdef CONFIG_OF @@ -1082,6 +1093,8 @@ static int i2c_hid_probe(struct i2c_client *client, if (ret < 0) goto err; + i2c_hid_acpi_fix_up_power(&client->dev); + pm_runtime_get_noresume(&client->dev); pm_runtime_set_active(&client->dev); pm_runtime_enable(&client->dev); -- GitLab From b2a40eaef694b35ae39f1924b3bee95595676e25 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Mon, 29 May 2017 15:15:27 +0200 Subject: [PATCH 1139/1834] ovl: filter trusted xattr for non-admin [ Upstream commit a082c6f680da298cf075886ff032f32ccb7c5e1a ] Filesystems filter out extended attributes in the "trusted." domain for unprivlieged callers. Overlay calls underlying filesystem's method with elevated privs, so need to do the filtering in overlayfs too. Signed-off-by: Miklos Szeredi Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/inode.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 7fb53d055537..16f6db88c8e5 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -227,6 +227,16 @@ int ovl_xattr_get(struct dentry *dentry, const char *name, return res; } +static bool ovl_can_list(const char *s) +{ + /* List all non-trusted xatts */ + if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0) + return true; + + /* Never list trusted.overlay, list other trusted for superuser only */ + return !ovl_is_private_xattr(s) && capable(CAP_SYS_ADMIN); +} + ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) { struct dentry *realdentry = ovl_dentry_real(dentry); @@ -250,7 +260,7 @@ ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) return -EIO; len -= slen; - if (ovl_is_private_xattr(s)) { + if (!ovl_can_list(s)) { res -= slen; memmove(s, s + slen, len); } else { -- GitLab From 7ba7c8222b87993f549910b06e230564197b6e03 Mon Sep 17 00:00:00 2001 From: Ivan Mikhaylov Date: Fri, 19 May 2017 18:47:05 +0300 Subject: [PATCH 1140/1834] powerpc/[booke|4xx]: Don't clobber TCR[WP] when setting TCR[DIE] [ Upstream commit 6e2f03e292ef46eed2b31b0a344a91d514f9cd81 ] Prevent a kernel panic caused by unintentionally clearing TCR watchdog bits. At this point in the kernel boot, the watchdog may have already been enabled by u-boot. The original code's attempt to write to the TCR register results in an inadvertent clearing of the watchdog configuration bits, causing the 476 to reset. Signed-off-by: Ivan Mikhaylov Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/time.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index f1d7e996e673..ab7b661b6da3 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -719,12 +719,20 @@ static int __init get_freq(char *name, int cells, unsigned long *val) static void start_cpu_decrementer(void) { #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) + unsigned int tcr; + /* Clear any pending timer interrupts */ mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); - /* Enable decrementer interrupt */ - mtspr(SPRN_TCR, TCR_DIE); -#endif /* defined(CONFIG_BOOKE) || defined(CONFIG_40x) */ + tcr = mfspr(SPRN_TCR); + /* + * The watchdog may have already been enabled by u-boot. So leave + * TRC[WP] (Watchdog Period) alone. + */ + tcr &= TCR_WP_MASK; /* Clear all bits except for TCR[WP] */ + tcr |= TCR_DIE; /* Enable decrementer */ + mtspr(SPRN_TCR, tcr); +#endif } void __init generic_calibrate_decr(void) -- GitLab From 922841084a82f1356c0499a165319b780965f039 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 24 May 2017 12:09:53 +0530 Subject: [PATCH 1141/1834] dmaengine: imx-sdma: Handle return value of clk_prepare_enable [ Upstream commit fb9caf370f4d0457789d13a1a1b110a8db846e5e ] clk_prepare_enable() can fail here and we must check its return value. Signed-off-by: Arvind Yadav Signed-off-by: Vinod Koul Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/dma/imx-sdma.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 21726a270fc4..b9c29720aeb1 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -1755,19 +1755,26 @@ static int sdma_probe(struct platform_device *pdev) if (IS_ERR(sdma->clk_ahb)) return PTR_ERR(sdma->clk_ahb); - clk_prepare(sdma->clk_ipg); - clk_prepare(sdma->clk_ahb); + ret = clk_prepare(sdma->clk_ipg); + if (ret) + return ret; + + ret = clk_prepare(sdma->clk_ahb); + if (ret) + goto err_clk; ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0, "sdma", sdma); if (ret) - return ret; + goto err_irq; sdma->irq = irq; sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL); - if (!sdma->script_addrs) - return -ENOMEM; + if (!sdma->script_addrs) { + ret = -ENOMEM; + goto err_irq; + } /* initially no scripts available */ saddr_arr = (s32 *)sdma->script_addrs; @@ -1882,6 +1889,10 @@ static int sdma_probe(struct platform_device *pdev) dma_async_device_unregister(&sdma->dma_device); err_init: kfree(sdma->script_addrs); +err_irq: + clk_unprepare(sdma->clk_ahb); +err_clk: + clk_unprepare(sdma->clk_ipg); return ret; } @@ -1893,6 +1904,8 @@ static int sdma_remove(struct platform_device *pdev) devm_free_irq(&pdev->dev, sdma->irq, sdma); dma_async_device_unregister(&sdma->dma_device); kfree(sdma->script_addrs); + clk_unprepare(sdma->clk_ahb); + clk_unprepare(sdma->clk_ipg); /* Kill the tasklet */ for (i = 0; i < MAX_DMA_CHANNELS; i++) { struct sdma_channel *sdmac = &sdma->channel[i]; -- GitLab From 6625fd2adc4b40418f072ac0e9a11c8f1f9ea141 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 17 May 2017 21:55:07 +0100 Subject: [PATCH 1142/1834] backlight: Report error on failure [ Upstream commit 7e715c2d9c27c23f3187454157c58cf292ed103e ] It is possible to update the backlight power and the brightness using the sysfs and on writing it either returns the count or if the callback function does not exist then returns the error code 'ENXIO'. We have a situation where the userspace client is writing to the sysfs to update the power and since the callback function exists the client receives the return value as count and considers the operation to be successful. That is correct as the write to the sysfs was successful. But there is no way to know if the actual operation was done or not. backlight_update_status() returns the error code if it fails. Pass that to the userspace client who is trying to update the power so that the client knows that the operation failed. Signed-off-by: Sudip Mukherjee Acked-by: Daniel Thompson Signed-off-by: Lee Jones Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/video/backlight/backlight.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 288318ad21dd..8049e7656daa 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -134,7 +134,7 @@ static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr, { int rc; struct backlight_device *bd = to_backlight_device(dev); - unsigned long power; + unsigned long power, old_power; rc = kstrtoul(buf, 0, &power); if (rc) @@ -145,10 +145,16 @@ static ssize_t bl_power_store(struct device *dev, struct device_attribute *attr, if (bd->ops) { pr_debug("set power to %lu\n", power); if (bd->props.power != power) { + old_power = bd->props.power; bd->props.power = power; - backlight_update_status(bd); + rc = backlight_update_status(bd); + if (rc) + bd->props.power = old_power; + else + rc = count; + } else { + rc = count; } - rc = count; } mutex_unlock(&bd->ops_lock); @@ -176,8 +182,7 @@ int backlight_device_set_brightness(struct backlight_device *bd, else { pr_debug("set brightness to %lu\n", brightness); bd->props.brightness = brightness; - backlight_update_status(bd); - rc = 0; + rc = backlight_update_status(bd); } } mutex_unlock(&bd->ops_lock); -- GitLab From d7c5f8c815466fc00785bbff20f25b39643abe01 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 5 Apr 2017 11:14:05 +0100 Subject: [PATCH 1143/1834] arm64: futex: Fix undefined behaviour with FUTEX_OP_OPARG_SHIFT usage [ Upstream commit 5f16a046f8e144c294ef98cd29d9458b5f8273e5 ] FUTEX_OP_OPARG_SHIFT instructs the futex code to treat the 12-bit oparg field as a shift value, potentially leading to a left shift value that is negative or with an absolute value that is significantly larger then the size of the type. UBSAN chokes with: ================================================================================ UBSAN: Undefined behaviour in ./arch/arm64/include/asm/futex.h:60:13 shift exponent -1 is negative CPU: 1 PID: 1449 Comm: syz-executor0 Not tainted 4.11.0-rc4-00005-g977eb52-dirty #11 Hardware name: linux,dummy-virt (DT) Call trace: [] dump_backtrace+0x0/0x538 arch/arm64/kernel/traps.c:73 [] show_stack+0x20/0x30 arch/arm64/kernel/traps.c:228 [] __dump_stack lib/dump_stack.c:16 [inline] [] dump_stack+0x120/0x188 lib/dump_stack.c:52 [] ubsan_epilogue+0x18/0x98 lib/ubsan.c:164 [] __ubsan_handle_shift_out_of_bounds+0x250/0x294 lib/ubsan.c:421 [] futex_atomic_op_inuser arch/arm64/include/asm/futex.h:60 [inline] [] futex_wake_op kernel/futex.c:1489 [inline] [] do_futex+0x137c/0x1740 kernel/futex.c:3231 [] SYSC_futex kernel/futex.c:3281 [inline] [] SyS_futex+0x114/0x268 kernel/futex.c:3249 [] el0_svc_naked+0x24/0x28 ================================================================================ syz-executor1 uses obsolete (PF_INET,SOCK_PACKET) sock: process `syz-executor0' is using obsolete setsockopt SO_BSDCOMPAT This patch attempts to fix some of this by: * Making encoded_op an unsigned type, so we can shift it left even if the top bit is set. * Casting to signed prior to shifting right when extracting oparg and cmparg * Consider only the bottom 5 bits of oparg when using it as a left-shift value. Whilst I think this catches all of the issues, I'd much prefer to remove this stuff, as I think it's unused and the bugs are copy-pasted between a bunch of architectures. Reviewed-by: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/futex.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index f2585cdd32c2..20dcb196b240 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -51,16 +51,16 @@ : "memory") static inline int -futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) +futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) { int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; + int oparg = (int)(encoded_op << 8) >> 20; + int cmparg = (int)(encoded_op << 20) >> 20; int oldval = 0, ret, tmp; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; + oparg = 1U << (oparg & 0x1f); if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) return -EFAULT; -- GitLab From ecbd702dec3d9d096217b0125cbac66054bd1214 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 29 May 2017 15:00:17 +0200 Subject: [PATCH 1144/1834] net/mlx5: avoid build warning for uniprocessor [ Upstream commit f0d7ae95fff4ab444b8433f07afc4b077ef1a285 ] Building the driver with CONFIG_SMP disabled results in a harmless warning: ethernet/mellanox/mlx5/core/main.c: In function 'mlx5_irq_set_affinity_hint': ethernet/mellanox/mlx5/core/main.c:615:6: error: unused variable 'irq' [-Werror=unused-variable] It's better to express the conditional compilation using IS_ENABLED() here, as that lets the compiler see what the intented use for the variable is, and that it can be silently discarded. Fixes: b665d98edc9a ("net/mlx5: Tolerate irq_set_affinity_hint() failures") Signed-off-by: Arnd Bergmann Acked-by: Saeed Mahameed Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 935e62635f12..3c183b8c083a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -557,10 +557,9 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node), priv->irq_info[i].mask); -#ifdef CONFIG_SMP - if (irq_set_affinity_hint(irq, priv->irq_info[i].mask)) + if (IS_ENABLED(CONFIG_SMP) && + irq_set_affinity_hint(irq, priv->irq_info[i].mask)) mlx5_core_warn(mdev, "irq_set_affinity_hint failed, irq 0x%.4x", irq); -#endif return 0; } -- GitLab From 6cd7b51283df0615a223f527e0721be1058ae36e Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Tue, 30 May 2017 18:06:06 +0530 Subject: [PATCH 1145/1834] cxgb4: FW upgrade fixes [ Upstream commit 26747211486c5bc7dd014c3caab206576e00c0d0 ] Disable FW_OK flag while flashing Firmware. This will help to fix any potential mailbox timeouts during Firmware flash. Grab new devlog parameters after Firmware restart. When we FLASH new Firmware onto an adapter, the new Firmware may have the Firmware Device Log located at a different memory address or have a different size for it. Signed-off-by: Arjun Vynipadath Signed-off-by: Casey Leedom Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 6fd3be69ff21..24d391899730 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -6185,13 +6185,18 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, if (!t4_fw_matches_chip(adap, fw_hdr)) return -EINVAL; + /* Disable FW_OK flag so that mbox commands with FW_OK flag set + * wont be sent when we are flashing FW. + */ + adap->flags &= ~FW_OK; + ret = t4_fw_halt(adap, mbox, force); if (ret < 0 && !force) - return ret; + goto out; ret = t4_load_fw(adap, fw_data, size); if (ret < 0) - return ret; + goto out; /* * Older versions of the firmware don't understand the new @@ -6202,7 +6207,17 @@ int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, * its header flags to see if it advertises the capability. */ reset = ((be32_to_cpu(fw_hdr->flags) & FW_HDR_FLAGS_RESET_HALT) == 0); - return t4_fw_restart(adap, mbox, reset); + ret = t4_fw_restart(adap, mbox, reset); + + /* Grab potentially new Firmware Device Log parameters so we can see + * how healthy the new Firmware is. It's okay to contact the new + * Firmware for these parameters even though, as far as it's + * concerned, we've never said "HELLO" to it ... + */ + (void)t4_init_devlog_params(adap); +out: + adap->flags |= FW_OK; + return ret; } /** -- GitLab From 489b11ae30afc7b1315559613b7d0abf7249dd4f Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Tue, 30 May 2017 13:30:24 +0530 Subject: [PATCH 1146/1834] cxgb4: Fix netdev_features flag [ Upstream commit 90592b9a35836bacd34d92a3aba7958756b6a7c0 ] GRO is not supported by Chelsio HW when rx_csum is disabled. Update the netdev features flag when rx_csum is modified. Signed-off-by: Arjun Vynipadath Signed-off-by: Steve Wise Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 0c2a32a305bc..3ec32d7c5866 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -2742,6 +2742,16 @@ static int cxgb_setup_tc(struct net_device *dev, u32 handle, __be16 proto, return -EOPNOTSUPP; } +static netdev_features_t cxgb_fix_features(struct net_device *dev, + netdev_features_t features) +{ + /* Disable GRO, if RX_CSUM is disabled */ + if (!(features & NETIF_F_RXCSUM)) + features &= ~NETIF_F_GRO; + + return features; +} + static const struct net_device_ops cxgb4_netdev_ops = { .ndo_open = cxgb_open, .ndo_stop = cxgb_close, @@ -2766,6 +2776,7 @@ static const struct net_device_ops cxgb4_netdev_ops = { #endif .ndo_set_tx_maxrate = cxgb_set_tx_maxrate, .ndo_setup_tc = cxgb_setup_tc, + .ndo_fix_features = cxgb_fix_features, }; #ifdef CONFIG_PCI_IOV -- GitLab From 2c90ca5c196b68b2b453d1b37cebda35d068ae89 Mon Sep 17 00:00:00 2001 From: Gary Bisson Date: Tue, 25 Apr 2017 16:45:15 +0200 Subject: [PATCH 1147/1834] rtc: m41t80: fix SQW dividers override when setting a date [ Upstream commit 0f546b058b86ea2f661cc7a6e931cee5a29959ef ] This patch is only relevant for RTC with the SQ_ALT feature which means the clock output frequency divider is stored in the weekday register. Current implementation discards the previous dividers value and clear them as soon as the time is set. Signed-off-by: Gary Bisson Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-m41t80.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 58698d21c2c3..c4ca6a385790 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -168,6 +168,7 @@ static int m41t80_get_datetime(struct i2c_client *client, /* Sets the given date and time to the real time clock. */ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct m41t80_data *clientdata = i2c_get_clientdata(client); unsigned char buf[8]; int err, flags; @@ -183,6 +184,17 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100); buf[M41T80_REG_WDAY] = tm->tm_wday; + /* If the square wave output is controlled in the weekday register */ + if (clientdata->features & M41T80_FEATURE_SQ_ALT) { + int val; + + val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY); + if (val < 0) + return val; + + buf[M41T80_REG_WDAY] |= (val & 0xf0); + } + err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC, sizeof(buf), buf); if (err < 0) { -- GitLab From 3ac7598acbb6affbfe24dfca86a29626f268baaf Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Fri, 28 Apr 2017 16:53:16 -0700 Subject: [PATCH 1148/1834] i40evf: fix merge error in older patch [ Upstream commit 155b0f690051345deefc653774b739c786067d61 ] This patch fixes a missing line that was missed while merging, which results in a driver feature in the VF not working to enable RSS as a negotiated feature. Fixes: 43a3d9ba34c9c ("i40evf: Allow PF driver to configure RSS") Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index ddf478d6322b..614f93e01500 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -154,6 +154,7 @@ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_PF | I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | I40E_VIRTCHNL_VF_OFFLOAD_VLAN | -- GitLab From e1dcd000c8f4f8f1e294049d1bde596799cae83f Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Fri, 19 May 2017 15:35:09 +0530 Subject: [PATCH 1149/1834] rtc: opal: Handle disabled TPO in opal_get_tpo_time() [ Upstream commit 6dc1cf6f932bb0ea4d8f5e913a0a401ecacd2f03 ] On PowerNV platform when Timed-Power-On(TPO) is disabled, read of stored TPO yields value with all date components set to '0' inside opal_get_tpo_time(). The function opal_to_tm() then converts it to an offset from year 1900 yielding alarm-time == "1900-00-01 00:00:00". This causes problems with __rtc_read_alarm() that expecting an offset from "1970-00-01 00:00:00" and returned alarm-time results in a -ve value for time64_t. Which ultimately results in this error reported in kernel logs with a seemingly garbage value: "rtc rtc0: invalid alarm value: -2-1--1041528741 2005511117:71582844:32" We fix this by explicitly handling the case of all alarm date-time components being '0' inside opal_get_tpo_time() and returning -ENOENT in such a case. This signals generic rtc that no alarm is set and it bails out from the alarm initialization flow without reporting the above error. Signed-off-by: Vaibhav Jain Reported-by: Steve Best Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/rtc-opal.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index e4324dcf9508..aa53fceaa5e0 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -150,6 +150,16 @@ static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) y_m_d = be32_to_cpu(__y_m_d); h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32); + + /* check if no alarm is set */ + if (y_m_d == 0 && h_m_s_ms == 0) { + pr_debug("No alarm is set\n"); + rc = -ENOENT; + goto exit; + } else { + pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms); + } + opal_to_tm(y_m_d, h_m_s_ms, &alarm->time); exit: -- GitLab From d5cbc16656aee364a80af20a476d23bd11301225 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Fri, 19 May 2017 22:18:55 +0530 Subject: [PATCH 1150/1834] rtc: interface: Validate alarm-time before handling rollover [ Upstream commit da96aea0ed177105cb13ee83b328f6c61e061d3f ] In function __rtc_read_alarm() its possible for an alarm time-stamp to be invalid even after replacing missing components with current time-stamp. The condition 'alarm->time.tm_year < 70' will trigger this case and will cause the call to 'rtc_tm_to_time64(&alarm->time)' return a negative value for variable t_alm. While handling alarm rollover this negative t_alm (assumed to seconds offset from '1970-01-01 00:00:00') is converted back to rtc_time via rtc_time64_to_tm() which results in this error log with seemingly garbage values: "rtc rtc0: invalid alarm value: -2-1--1041528741 2005511117:71582844:32" This error was generated when the rtc driver (rtc-opal in this case) returned an alarm time-stamp of '00-00-00 00:00:00' to indicate that the alarm is disabled. Though I have submitted a separate fix for the rtc-opal driver, this issue may potentially impact other existing/future rtc drivers. To fix this issue the patch validates the alarm time-stamp just after filling up the missing datetime components and if rtc_valid_tm() still reports it to be invalid then bails out of the function without handling the rollover. Reported-by: Steve Best Signed-off-by: Vaibhav Jain Signed-off-by: Alexandre Belloni Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/rtc/interface.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 6ebd42aad291..25cf3069e2e7 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -227,6 +227,13 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) missing = year; } + /* Can't proceed if alarm is still invalid after replacing + * missing fields. + */ + err = rtc_valid_tm(&alarm->time); + if (err) + goto done; + /* with luck, no rollover is needed */ t_now = rtc_tm_to_time64(&now); t_alm = rtc_tm_to_time64(&alarm->time); @@ -278,9 +285,9 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) dev_warn(&rtc->dev, "alarm rollover not handled\n"); } -done: err = rtc_valid_tm(&alarm->time); +done: if (err) { dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n", alarm->time.tm_year + 1900, alarm->time.tm_mon + 1, -- GitLab From 67eed62b4dd22d388dbc55ec9b5e0077f67305de Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 25 May 2017 17:00:32 +1000 Subject: [PATCH 1151/1834] SUNRPC: ensure correct error is reported by xs_tcp_setup_socket() [ Upstream commit 6ea44adce91526700535b3150f77f8639ae8c82d ] If you attempt a TCP mount from an host that is unreachable in a way that triggers an immediate error from kernel_connect(), that error does not propagate up, instead EAGAIN is reported. This results in call_connect_status receiving the wrong error. A case that it easy to demonstrate is to attempt to mount from an address that results in ENETUNREACH, but first deleting any default route. Without this patch, the mount.nfs process is persistently runnable and is hard to kill. With this patch it exits as it should. The problem is caused by the fact that xs_tcp_force_close() eventually calls xprt_wake_pending_tasks(xprt, -EAGAIN); which causes an error return of -EAGAIN. so when xs_tcp_setup_sock() calls xprt_wake_pending_tasks(xprt, status); the status is ignored. Fixes: 4efdd92c9211 ("SUNRPC: Remove TCP client connection reset hack") Signed-off-by: NeilBrown Signed-off-by: Trond Myklebust Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/xprtsock.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index d24d14ea8ba4..1bf9153004cd 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2384,7 +2384,12 @@ static void xs_tcp_setup_socket(struct work_struct *work) case -EHOSTUNREACH: case -EADDRINUSE: case -ENOBUFS: - /* retry with existing socket, after a delay */ + /* + * xs_tcp_force_close() wakes tasks with -EIO. + * We need to wake them first to ensure the + * correct error code. + */ + xprt_wake_pending_tasks(xprt, status); xs_tcp_force_close(xprt); goto out; } -- GitLab From 2630e187b92af7e59bbb2b9702bbc2ac42b59fec Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 30 May 2017 17:38:43 -0500 Subject: [PATCH 1152/1834] net: freescale: fix potential null pointer dereference [ Upstream commit 06d2d6431bc8d41ef5ffd8bd4b52cea9f72aed22 ] Add NULL check before dereferencing pointer _id_ in order to avoid a potential NULL pointer dereference. Addresses-Coverity-ID: 1397995 Signed-off-by: Gustavo A. R. Silva Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/fsl_pq_mdio.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 446c7b374ff5..a10de1e9c157 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -381,7 +381,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) { const struct of_device_id *id = of_match_device(fsl_pq_mdio_match, &pdev->dev); - const struct fsl_pq_mdio_data *data = id->data; + const struct fsl_pq_mdio_data *data; struct device_node *np = pdev->dev.of_node; struct resource res; struct device_node *tbi; @@ -389,6 +389,13 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev) struct mii_bus *new_bus; int err; + if (!id) { + dev_err(&pdev->dev, "Failed to match device\n"); + return -ENODEV; + } + + data = id->data; + dev_dbg(&pdev->dev, "found %s compatible node\n", id->compatible); new_bus = mdiobus_alloc_size(sizeof(*priv)); -- GitLab From 903ad1a90d3bda38028b2dc05af0e0e4814543f4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 12 May 2017 16:25:30 +0200 Subject: [PATCH 1153/1834] clk: at91: fix clk-generated parenting [ Upstream commit 8e56133e5c7b7a7a97f6a92d92f664d5ecd30745 ] clk_generated_startup is called after clk_hw_register. So the first call to get_parent will not have the correct value (i.e. 0) and because this is cached, it may never be updated. Signed-off-by: Alexandre Belloni Fixes: df70aeef6083 ("clk: at91: add generated clock driver") Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/at91/clk-generated.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 4e1cd5aa69d8..70474bd97a10 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -260,13 +260,12 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, gck->lock = lock; gck->range = *range; + clk_generated_startup(gck); hw = &gck->hw; ret = clk_hw_register(NULL, &gck->hw); if (ret) { kfree(gck); hw = ERR_PTR(ret); - } else - clk_generated_startup(gck); return hw; } -- GitLab From 8d0c9ead6fd8d9a74c8743ab14b1ddc7c8072a49 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 27 May 2017 18:09:32 +0200 Subject: [PATCH 1154/1834] drm/sun4i: Ignore the generic connectors for components [ Upstream commit 49baeb074783f5bdf770dc9fac5fbb2837190583 ] The generic connectors such as hdmi-connector doesn't have any driver in, so if they are added to the component list, we will be waiting forever for a non-existing driver to probe. Add a list of the connectors we want to ignore when building our component list. Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/sun4i/sun4i_drv.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 9e77fc034e0a..aad2f4a2a0ef 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -212,6 +212,11 @@ static const struct component_master_ops sun4i_drv_master_ops = { .unbind = sun4i_drv_unbind, }; +static bool sun4i_drv_node_is_connector(struct device_node *node) +{ + return of_device_is_compatible(node, "hdmi-connector"); +} + static bool sun4i_drv_node_is_frontend(struct device_node *node) { return of_device_is_compatible(node, "allwinner,sun5i-a13-display-frontend") || @@ -252,6 +257,13 @@ static int sun4i_drv_add_endpoints(struct device *dev, !of_device_is_available(node)) return 0; + /* + * The connectors will be the last nodes in our pipeline, we + * can just bail out. + */ + if (sun4i_drv_node_is_connector(node)) + return 0; + if (!sun4i_drv_node_is_frontend(node)) { /* Add current component */ DRM_DEBUG_DRIVER("Adding component %s\n", -- GitLab From ed82ab87e13899458dda17d52a11e5b63fc15582 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 27 May 2017 18:09:34 +0200 Subject: [PATCH 1155/1834] dt-bindings: display: sun4i: Add allwinner,tcon-channel property [ Upstream commit 22662f12768f971809b478386d9cc4947d00497a ] The Allwinner Timings Controller has two, mutually exclusive, channels. When the binding has been introduced, it was assumed that there would be only a single user per channel in the system. While this is likely for the channel 0 which only connects to LCD displays, it turns out that the channel 1 can be connected to multiple controllers in the SoC (HDMI and TV encoders for example). And while the simultaneous use of HDMI and TV outputs cannot be achieved, switching from one to the other at runtime definitely sounds plausible. Add an extra property, allwinner,tcon-channel, to specify for a given endpoint which TCON channel it is connected to, while falling back to the previous mechanism if that property is missing. Acked-by: Chen-Yu Tsai Acked-by: Rob Herring Signed-off-by: Maxime Ripard Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/display/sunxi/sun4i-drm.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt index 4f7ae7555758..bda9d6fab6b4 100644 --- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt +++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt @@ -47,10 +47,13 @@ Required properties: Documentation/devicetree/bindings/media/video-interfaces.txt. The first port should be the input endpoint, the second one the output - The output should have two endpoints. The first is the block - connected to the TCON channel 0 (usually a panel or a bridge), the - second the block connected to the TCON channel 1 (usually the TV - encoder) + The output may have multiple endpoints. The TCON has two channels, + usually with the first channel being used for the panels interfaces + (RGB, LVDS, etc.), and the second being used for the outputs that + require another controller (TV Encoder, HDMI, etc.). The endpoints + will take an extra property, allwinner,tcon-channel, to specify the + channel the endpoint is associated to. If that property is not + present, the endpoint number will be used as the channel number. On SoCs other than the A33, there is one more clock required: - 'tcon-ch1': The clock driving the TCON channel 1 -- GitLab From 8bf4782062a0a0f6b9ca68f3f6625e1a5fe455fc Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 10 Apr 2017 10:35:17 +0200 Subject: [PATCH 1156/1834] mtd: nand: gpmi: Fix gpmi_nand_init() error path [ Upstream commit 4d02423e9afe6c46142ce98bbcaf5167316dbfbf ] The GPMI driver is wrongly assuming that nand_release() can safely be called on an uninitialized/unregistered NAND device. Add a new err_nand_cleanup label in the error path and only execute if nand_scan_tail() succeeded. Note that we now call nand_cleanup() instead of nand_release() (nand_release() is actually grouping the mtd_device_unregister() and nand_cleanup() in one call) because there's no point in trying to unregister a device that has never been registered. Signed-off-by: Boris Brezillon Reviewed-by: Marek Vasut Acked-by: Han Xu Reviewed-by: Marek Vasut Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 427039b77668..d9dab4275859 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -2047,18 +2047,20 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) ret = nand_boot_init(this); if (ret) - goto err_out; + goto err_nand_cleanup; ret = chip->scan_bbt(mtd); if (ret) - goto err_out; + goto err_nand_cleanup; ret = mtd_device_register(mtd, NULL, 0); if (ret) - goto err_out; + goto err_nand_cleanup; return 0; +err_nand_cleanup: + nand_cleanup(chip); err_out: - gpmi_nand_exit(this); + gpmi_free_dma_buffer(this); return ret; } -- GitLab From 2d0eb3f188e1de0fadaca05b413ea44c217fa7dd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 25 May 2017 13:50:20 +0900 Subject: [PATCH 1157/1834] mtd: nand: check ecc->total sanity in nand_scan_tail [ Upstream commit 79e0348c4e24fd1affdcf055e0269755580e0fcc ] Drivers are supposed to set correct ecc->{size,strength,bytes} before calling nand_scan_tail(), but it does not complain about ecc->total bigger than oobsize. In this case, chip->scan_bbt() crashes due to memory corruption, but it is hard to debug. It would be kind to fail it earlier with a clear message. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/nand/nand_base.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a3e86e52640a..5fb45161789c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -4785,6 +4785,11 @@ int nand_scan_tail(struct mtd_info *mtd) goto err_free; } ecc->total = ecc->steps * ecc->bytes; + if (ecc->total > mtd->oobsize) { + WARN(1, "Total number of ECC bytes exceeded oobsize\n"); + ret = -EINVAL; + goto err_free; + } /* * The number of bytes available for a client to place data into -- GitLab From 0a4546e716b200e47767f39ec44765884a6c6d63 Mon Sep 17 00:00:00 2001 From: Roman Pen Date: Thu, 1 Jun 2017 10:55:03 +0200 Subject: [PATCH 1158/1834] KVM: SVM: do not zero out segment attributes if segment is unusable or not present MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d9c1b5431d5f0e07575db785a022bce91051ac1d ] This is a fix for the problem [1], where VMCB.CPL was set to 0 and interrupt was taken on userspace stack. The root cause lies in the specific AMD CPU behaviour which manifests itself as unusable segment attributes on SYSRET. The corresponding work around for the kernel is the following: 61f01dd941ba ("x86_64, asm: Work around AMD SYSRET SS descriptor attribute issue") In other turn virtualization side treated unusable segment incorrectly and restored CPL from SS attributes, which were zeroed out few lines above. In current patch it is assured only that P bit is cleared in VMCB.save state and segment attributes are not zeroed out if segment is not presented or is unusable, therefore CPL can be safely restored from DPL field. This is only one part of the fix, since QEMU side should be fixed accordingly not to zero out attributes on its side. Corresponding patch will follow. [1] Message id: CAJrWOzD6Xq==b-zYCDdFLgSRMPM-NkNuTSDFEtX=7MreT45i7Q@mail.gmail.com Signed-off-by: Roman Pen Signed-off-by: Mikhail Sennikovskii Cc: Paolo Bonzini Cc: Radim KrÄmář Cc: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Paolo Bonzini Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/svm.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 8c99f2fbae80..aaa93b4b0380 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1879,6 +1879,7 @@ static void svm_get_segment(struct kvm_vcpu *vcpu, */ if (var->unusable) var->db = 0; + /* This is symmetric with svm_set_segment() */ var->dpl = to_svm(vcpu)->vmcb->save.cpl; break; } @@ -2024,18 +2025,14 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, s->base = var->base; s->limit = var->limit; s->selector = var->selector; - if (var->unusable) - s->attrib = 0; - else { - s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); - s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; - s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; - s->attrib |= (var->present & 1) << SVM_SELECTOR_P_SHIFT; - s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; - s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; - s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; - s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; - } + s->attrib = (var->type & SVM_SELECTOR_TYPE_MASK); + s->attrib |= (var->s & 1) << SVM_SELECTOR_S_SHIFT; + s->attrib |= (var->dpl & 3) << SVM_SELECTOR_DPL_SHIFT; + s->attrib |= ((var->present & 1) && !var->unusable) << SVM_SELECTOR_P_SHIFT; + s->attrib |= (var->avl & 1) << SVM_SELECTOR_AVL_SHIFT; + s->attrib |= (var->l & 1) << SVM_SELECTOR_L_SHIFT; + s->attrib |= (var->db & 1) << SVM_SELECTOR_DB_SHIFT; + s->attrib |= (var->g & 1) << SVM_SELECTOR_G_SHIFT; /* * This is always accurate, except if SYSRET returned to a segment @@ -2044,7 +2041,8 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, * would entail passing the CPL to userspace and back. */ if (seg == VCPU_SREG_SS) - svm->vmcb->save.cpl = (s->attrib >> SVM_SELECTOR_DPL_SHIFT) & 3; + /* This is symmetric with svm_get_segment() */ + svm->vmcb->save.cpl = (var->dpl & 3); mark_dirty(svm->vmcb, VMCB_SEG); } -- GitLab From 82a19094f113b8177e920a48a4bb4cd1054c3142 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 18 May 2017 17:19:28 +0100 Subject: [PATCH 1159/1834] clk: scpi: fix return type of __scpi_dvfs_round_rate [ Upstream commit 7374aec95636ca39409545eba4ef5ff3125c2346 ] The frequencies above the maximum value of signed integer(i.e. 2^31 -1) will overflow with the current code. This patch fixes the return type of __scpi_dvfs_round_rate from 'int' to 'unsigned long'. Fixes: cd52c2a4b5c4 ("clk: add support for clocks provided by SCP(System Control Processor)") Cc: Michael Turquette Cc: Stephen Boyd Signed-off-by: Sudeep Holla Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk-scpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c index 96d37175d0ad..8ad458b5ad6e 100644 --- a/drivers/clk/clk-scpi.c +++ b/drivers/clk/clk-scpi.c @@ -71,15 +71,15 @@ static const struct clk_ops scpi_clk_ops = { }; /* find closest match to given frequency in OPP table */ -static int __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate) +static long __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate) { int idx; - u32 fmin = 0, fmax = ~0, ftmp; + unsigned long fmin = 0, fmax = ~0, ftmp; const struct scpi_opp *opp = clk->info->opps; for (idx = 0; idx < clk->info->count; idx++, opp++) { ftmp = opp->freq; - if (ftmp >= (u32)rate) { + if (ftmp >= rate) { if (ftmp <= fmax) fmax = ftmp; break; -- GitLab From df170185b8d393a047f95f1d2871192c3b414bf1 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Mon, 15 May 2017 11:58:59 +0100 Subject: [PATCH 1160/1834] clk: Fix __set_clk_rates error print-string [ Upstream commit ee177c5d6369f8e5d3e4793dce501cf4431313a1 ] When failing to set a clock the printout emitted is incorrect. "u32 rate" is formatted as %d and should be %u whereas "unsigned long clk_set_rate()" is formatted as %ld and should be %lu as per Documentation/printk-formats.txt. Fixes: 2885c3b2a3da ("clk: Show correct information when fail to set clock rate") Signed-off-by: Bryan O'Donoghue Signed-off-by: Stephen Boyd Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/clk/clk-conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 674785d968a3..f02900922bbe 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -106,7 +106,7 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) rc = clk_set_rate(clk, rate); if (rc < 0) - pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n", + pr_err("clk: couldn't set %s clk rate to %u (%d), current rate: %lu\n", __clk_get_name(clk), rate, rc, clk_get_rate(clk)); clk_put(clk); -- GitLab From bc12167cc73ab05e97a9fda355e79d216b630661 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 29 May 2017 20:26:07 +1000 Subject: [PATCH 1161/1834] powerpc/spufs: Fix coredump of SPU contexts [ Upstream commit 99acc9bede06bbb2662aafff51f5b9e529fa845e ] If a process dumps core while it has SPU contexts active then we have code to also dump information about the SPU contexts. Unfortunately it's been broken for 3 1/2 years, and we didn't notice. In commit 7b1f4020d0d1 ("spufs: get rid of dump_emit() wrappers") the nread variable was removed and rc used instead. That means when the loop exits successfully, rc has the number of bytes read, but it's then used as the return value for the function, which should return 0 on success. So fix it by setting rc = 0 before returning in the success case. Fixes: 7b1f4020d0d1 ("spufs: get rid of dump_emit() wrappers") Signed-off-by: Michael Ellerman Acked-by: Jeremy Kerr Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/cell/spufs/coredump.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 85c85eb3e245..b4abf9d5d9e1 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -175,6 +175,8 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i, skip = roundup(cprm->pos - total + sz, 4) - cprm->pos; if (!dump_skip(cprm, skip)) goto Eio; + + rc = 0; out: free_page((unsigned long)buf); return rc; -- GitLab From 00ceff917d1b5b945756579ba34482179f56ecf2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 14 Jun 2017 13:58:53 +0300 Subject: [PATCH 1162/1834] drm/amdkfd: NULL dereference involving create_process() [ Upstream commit b312b2b25b6ac9e2eb03f4ca651b33108752de3a ] We accidentally return ERR_PTR(0) which is NULL. The caller is not expecting that and it leads to an Oops. Fixes: dd59239a9862 ("amdkfd: init aperture once per process") Signed-off-by: Dan Carpenter Reviewed-by: Felix Kuehling Signed-off-by: Oded Gabbay Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdkfd/kfd_process.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c index ef7c8de7060e..171480bb95d0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c @@ -317,7 +317,8 @@ static struct kfd_process *create_process(const struct task_struct *thread) /* init process apertures*/ process->is_32bit_user_mode = in_compat_syscall(); - if (kfd_init_apertures(process) != 0) + err = kfd_init_apertures(process); + if (err != 0) goto err_init_apretures; return process; -- GitLab From a57608696560d40cfbc5d3aa486a4405e891b044 Mon Sep 17 00:00:00 2001 From: Anilkumar Kolli Date: Wed, 31 May 2017 14:21:27 +0300 Subject: [PATCH 1163/1834] ath10k: add BMI parameters to fix calibration from DT/pre-cal [ Upstream commit a9f5f287fa1d47d61dfa8b60f94831174b2ea4d0 ] QCA99X0, QCA9888, QCA9984 supports calibration data in either OTP or DT/pre-cal file. Current ath10k supports Calibration data from OTP only. If caldata is loaded from DT/pre-cal file, fetching board id and applying calibration parameters like tx power gets failed. error log: [ 15.733663] ath10k_pci 0000:01:00.0: failed to fetch board file: -2 [ 15.741474] ath10k_pci 0000:01:00.0: could not probe fw (-2) This patch adds calibration data support from DT/pre-cal file. Below parameters are used to get board id and applying calibration parameters from cal data. EEPROM[OTP] FLASH[DT/pre-cal file] Cal param 0x700 0x10000 Board id 0x10 0x8000 Tested on QCA9888 with pre-cal file. Signed-off-by: Anilkumar Kolli Signed-off-by: Kalle Valo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath10k/bmi.h | 2 ++ drivers/net/wireless/ath/ath10k/core.c | 16 +++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 7d3231acfb24..82bdec744055 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -83,6 +83,8 @@ enum bmi_cmd_id { #define BMI_NVRAM_SEG_NAME_SZ 16 #define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10 +#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000 +#define BMI_PARAM_FLASH_SECTION_ALL 0x10000 #define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00 #define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10 diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7b3017f55e3d..65ad7a130ca1 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -652,7 +652,7 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) { u32 result, address; u8 board_id, chip_id; - int ret; + int ret, bmi_board_id_param; address = ar->hw_params.patch_load_addr; @@ -676,8 +676,13 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) return ret; } - ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EEPROM_BOARD_ID, - &result); + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID; + else + bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID; + + ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result); if (ret) { ath10k_err(ar, "could not execute otp for board id check: %d\n", ret); @@ -739,6 +744,11 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) return ret; } + /* As of now pre-cal is valid for 10_4 variants */ + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); if (ret) { ath10k_err(ar, "could not execute otp (%d)\n", ret); -- GitLab From 2761edad2fba4a3b4b02238b212f639b64b8e85a Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 31 May 2017 13:35:57 +0200 Subject: [PATCH 1164/1834] perf trace: Add mmap alias for s390 [ Upstream commit 54265664c15a68905d8d67d19205e9a767636434 ] The s390 architecture maps sys_mmap (nr 90) into sys_old_mmap. For this reason perf trace can't find the proper syscall event to get args format from and displays it wrongly as 'continued'. To fix that fill the "alias" field with "old_mmap" for trace's mmap record to get the correct translation. Before: 0.042 ( 0.011 ms): vest/43052 fstat(statbuf: 0x3ffff89fd90 ) = 0 0.042 ( 0.028 ms): vest/43052 ... [continued]: mmap()) = 0x3fffd6e2000 0.072 ( 0.025 ms): vest/43052 read(buf: 0x3fffd6e2000, count: 4096 ) = 6 After: 0.045 ( 0.011 ms): fstat(statbuf: 0x3ffff8a0930 ) = 0 0.057 ( 0.018 ms): mmap(arg: 0x3ffff8a0858 ) = 0x3fffd14a000 0.076 ( 0.025 ms): read(buf: 0x3fffd14a000, count: 4096 ) = 6 Signed-off-by: Jiri Olsa Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20170531113557.19175-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/builtin-trace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 4c596ba310cb..0fd8bfb77f65 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -679,6 +679,10 @@ static struct syscall_fmt { { .name = "mlockall", .errmsg = true, .arg_scnprintf = { [0] = SCA_HEX, /* addr */ }, }, { .name = "mmap", .hexret = true, +/* The standard mmap maps to old_mmap on s390x */ +#if defined(__s390x__) + .alias = "old_mmap", +#endif .arg_scnprintf = { [0] = SCA_HEX, /* addr */ [2] = SCA_MMAP_PROT, /* prot */ [3] = SCA_MMAP_FLAGS, /* flags */ }, }, -- GitLab From d78b198c02c4276ad93af106f7f38904bd45d6cb Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Thu, 1 Jun 2017 16:18:10 +0800 Subject: [PATCH 1165/1834] qlcnic: Fix a sleep-in-atomic bug in qlcnic_82xx_hw_write_wx_2M and qlcnic_82xx_hw_read_wx_2M [ Upstream commit 5ea6d691aac6c93b790f0905e3460d44cc4c449b ] The driver may sleep under a write spin lock, and the function call path is: qlcnic_82xx_hw_write_wx_2M (acquire the lock by write_lock_irqsave) crb_win_lock qlcnic_pcie_sem_lock usleep_range qlcnic_82xx_hw_read_wx_2M (acquire the lock by write_lock_irqsave) crb_win_lock qlcnic_pcie_sem_lock usleep_range To fix it, the usleep_range is replaced with udelay. Signed-off-by: Jia-Ju Bai Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 509b596cf1e8..bd1ec70fb736 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -341,7 +341,7 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) } return -EIO; } - usleep_range(1000, 1500); + udelay(1200); } if (id_reg) -- GitLab From 50f48039a7bd246aeafdb6733d406ab7c1a6a96a Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 19 May 2017 16:42:00 +0100 Subject: [PATCH 1166/1834] arm64: kernel: restrict /dev/mem read() calls to linear region [ Upstream commit 1151f838cb626005f4d69bf675dacaaa5ea909d6 ] When running lscpu on an AArch64 system that has SMBIOS version 2.0 tables, it will segfault in the following way: Unable to handle kernel paging request at virtual address ffff8000bfff0000 pgd = ffff8000f9615000 [ffff8000bfff0000] *pgd=0000000000000000 Internal error: Oops: 96000007 [#1] PREEMPT SMP Modules linked in: CPU: 0 PID: 1284 Comm: lscpu Not tainted 4.11.0-rc3+ #103 Hardware name: QEMU QEMU Virtual Machine, BIOS 0.0.0 02/06/2015 task: ffff8000fa78e800 task.stack: ffff8000f9780000 PC is at __arch_copy_to_user+0x90/0x220 LR is at read_mem+0xcc/0x140 This is caused by the fact that lspci issues a read() on /dev/mem at the offset where it expects to find the SMBIOS structure array. However, this region is classified as EFI_RUNTIME_SERVICE_DATA (as per the UEFI spec), and so it is omitted from the linear mapping. So let's restrict /dev/mem read/write access to those areas that are covered by the linear region. Reported-by: Alexander Graf Fixes: 4dffbfc48d65 ("arm64/efi: mark UEFI reserved regions as MEMBLOCK_NOMAP") Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/mmap.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/arch/arm64/mm/mmap.c b/arch/arm64/mm/mmap.c index 01c171723bb3..caf75abf6ae7 100644 --- a/arch/arm64/mm/mmap.c +++ b/arch/arm64/mm/mmap.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -102,12 +103,18 @@ void arch_pick_mmap_layout(struct mm_struct *mm) */ int valid_phys_addr_range(phys_addr_t addr, size_t size) { - if (addr < PHYS_OFFSET) - return 0; - if (addr + size > __pa(high_memory - 1) + 1) - return 0; - - return 1; + /* + * Check whether addr is covered by a memory region without the + * MEMBLOCK_NOMAP attribute, and whether that region covers the + * entire range. In theory, this could lead to false negatives + * if the range is covered by distinct but adjacent memory regions + * that only differ in other attributes. However, few of such + * attributes have been defined, and it is debatable whether it + * follows that /dev/mem read() calls should be able traverse + * such boundaries. + */ + return memblock_is_region_memory(addr, size) && + memblock_is_map_memory(addr); } /* -- GitLab From 96770d43016bbb1f0491c2611f0a5e07092101f2 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Wed, 31 May 2017 15:08:25 +0800 Subject: [PATCH 1167/1834] mISDN: Fix a sleep-in-atomic bug [ Upstream commit 93818da5eed63fbc17b64080406ea53b86b23309 ] The driver may sleep under a read spin lock, and the function call path is: send_socklist (acquire the lock by read_lock) skb_copy(GFP_KERNEL) --> may sleep To fix it, the "GFP_KERNEL" is replaced with "GFP_ATOMIC". Signed-off-by: Jia-Ju Bai Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/isdn/mISDN/stack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 9cb4b621fbc3..b92a19a594a1 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -72,7 +72,7 @@ send_socklist(struct mISDN_sock_list *sl, struct sk_buff *skb) if (sk->sk_state != MISDN_BOUND) continue; if (!cskb) - cskb = skb_copy(skb, GFP_KERNEL); + cskb = skb_copy(skb, GFP_ATOMIC); if (!cskb) { printk(KERN_WARNING "%s no skb\n", __func__); break; -- GitLab From d7ba3c00047dfd88fe0360a2d27169b54c88c4f1 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Wed, 31 May 2017 13:29:30 +0300 Subject: [PATCH 1168/1834] net: phy: micrel: Restore led_mode and clk_sel on resume [ Upstream commit 79e498a9c7da0737829ff864aae44df434105676 ] These bits seem to be lost after a suspend/resume cycle so just set them again. Do this by splitting the handling of these bits into a function that is also called on resume. This patch fixes ethernet suspend/resume on imx6ul-14x14-evk boards. Signed-off-by: Leonard Crestez Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/micrel.c | 42 ++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 2032a6de026b..4da73e2c37cf 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -268,23 +268,12 @@ static int kszphy_nand_tree_disable(struct phy_device *phydev) return ret; } -static int kszphy_config_init(struct phy_device *phydev) +/* Some config bits need to be set again on resume, handle them here. */ +static int kszphy_config_reset(struct phy_device *phydev) { struct kszphy_priv *priv = phydev->priv; - const struct kszphy_type *type; int ret; - if (!priv) - return 0; - - type = priv->type; - - if (type->has_broadcast_disable) - kszphy_broadcast_disable(phydev); - - if (type->has_nand_tree_disable) - kszphy_nand_tree_disable(phydev); - if (priv->rmii_ref_clk_sel) { ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val); if (ret) { @@ -295,7 +284,7 @@ static int kszphy_config_init(struct phy_device *phydev) } if (priv->led_mode >= 0) - kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode); + kszphy_setup_led(phydev, priv->type->led_mode_reg, priv->led_mode); if (phy_interrupt_is_valid(phydev)) { int ctl = phy_read(phydev, MII_BMCR); @@ -311,6 +300,25 @@ static int kszphy_config_init(struct phy_device *phydev) return 0; } +static int kszphy_config_init(struct phy_device *phydev) +{ + struct kszphy_priv *priv = phydev->priv; + const struct kszphy_type *type; + + if (!priv) + return 0; + + type = priv->type; + + if (type->has_broadcast_disable) + kszphy_broadcast_disable(phydev); + + if (type->has_nand_tree_disable) + kszphy_nand_tree_disable(phydev); + + return kszphy_config_reset(phydev); +} + static int ksz8041_config_init(struct phy_device *phydev) { struct device_node *of_node = phydev->mdio.dev.of_node; @@ -715,8 +723,14 @@ static int kszphy_suspend(struct phy_device *phydev) static int kszphy_resume(struct phy_device *phydev) { + int ret; + genphy_resume(phydev); + ret = kszphy_config_reset(phydev); + if (ret) + return ret; + /* Enable PHY Interrupts */ if (phy_interrupt_is_valid(phydev)) { phydev->interrupts = PHY_INTERRUPT_ENABLED; -- GitLab From 9d4aa135e44ecee5c295891aea97f86eb234ff77 Mon Sep 17 00:00:00 2001 From: Raju Rangoju Date: Mon, 15 May 2017 06:40:39 +0000 Subject: [PATCH 1169/1834] RDMA/iw_cxgb4: Avoid touch after free error in ARP failure handlers [ Upstream commit 1dad0ebeea1cd890b8892523f736916e245b0aef ] The patch 761e19a504af (RDMA/iw_cxgb4: Handle return value of c4iw_ofld_send() in abort_arp_failure()) from May 6, 2016 leads to the following static checker warning: drivers/infiniband/hw/cxgb4/cm.c:575 abort_arp_failure() warn: passing freed memory 'skb' Also fixes skb leak when l2t resolution fails Fixes: 761e19a504afa55 (RDMA/iw_cxgb4: Handle return value of c4iw_ofld_send() in abort_arp_failure()) Reported-by: Dan Carpenter Cc: Dan Carpenter Signed-off-by: Raju Rangoju Reviewed-by: Steve Wise Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/cxgb4/cm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 6512a555f7f8..dd18b74cd01d 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -488,6 +488,7 @@ static int _put_ep_safe(struct c4iw_dev *dev, struct sk_buff *skb) ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *))); release_ep_resources(ep); + kfree_skb(skb); return 0; } @@ -498,6 +499,7 @@ static int _put_pass_ep_safe(struct c4iw_dev *dev, struct sk_buff *skb) ep = *((struct c4iw_ep **)(skb->cb + 2 * sizeof(void *))); c4iw_put_ep(&ep->parent_ep->com); release_ep_resources(ep); + kfree_skb(skb); return 0; } @@ -569,11 +571,13 @@ static void abort_arp_failure(void *handle, struct sk_buff *skb) PDBG("%s rdev %p\n", __func__, rdev); req->cmd = CPL_ABORT_NO_RST; + skb_get(skb); ret = c4iw_ofld_send(rdev, skb); if (ret) { __state_set(&ep->com, DEAD); queue_arp_failure_cpl(ep, skb, FAKE_CPL_PUT_EP_SAFE); - } + } else + kfree_skb(skb); } static int send_flowc(struct c4iw_ep *ep) -- GitLab From 4581de2bfa6f8aeb03cd7bd28a2a4d6246b67c51 Mon Sep 17 00:00:00 2001 From: "Steven L. Roberts" Date: Wed, 10 May 2017 10:54:12 -0500 Subject: [PATCH 1170/1834] RDMA/hfi1: fix array termination by appending NULL to attr array [ Upstream commit c4dd4b69f55abcc8dd079f8de55d9d8c2ddbefce ] This fixes a kernel panic when loading the hfi driver as a dynamic module. Signed-off-by: Steven L Roberts Reviewed-by: Leon Romanovsky Acked-by: Dennis Dalessandro Signed-off-by: Doug Ledford Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/hw/hfi1/sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/hfi1/sysfs.c b/drivers/infiniband/hw/hfi1/sysfs.c index 919a5474e651..621b60ab74ee 100644 --- a/drivers/infiniband/hw/hfi1/sysfs.c +++ b/drivers/infiniband/hw/hfi1/sysfs.c @@ -196,7 +196,8 @@ static const struct sysfs_ops port_cc_sysfs_ops = { }; static struct attribute *port_cc_default_attributes[] = { - &cc_prescan_attr.attr + &cc_prescan_attr.attr, + NULL }; static struct kobj_type port_cc_ktype = { -- GitLab From 80c9698bd6a8f0385167c20eccd8d9dda25577a0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 18 May 2017 11:51:51 +0300 Subject: [PATCH 1171/1834] drm/omap: fix tiled buffer stride calculations [ Upstream commit cc8dd7661ccc2d8dc88921da8e6cc7c2fcdb0341 ] omap_gem uses page alignment for buffer stride. The related calculations are a bit off, though, as byte stride of 4096 gets aligned to 8192, instead of 4096. This patch changes the code to use DIV_ROUND_UP(), which fixes those calculations and makes them more readable. Signed-off-by: Tomi Valkeinen Reviewed-by: Laurent Pinchart Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/omapdrm/omap_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 505dee0db973..ca91651be3d4 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -195,7 +195,7 @@ static void evict_entry(struct drm_gem_object *obj, size_t size = PAGE_SIZE * n; loff_t off = mmap_offset(obj) + (entry->obj_pgoff << PAGE_SHIFT); - const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE); if (m > 1) { int i; @@ -442,7 +442,7 @@ static int fault_2d(struct drm_gem_object *obj, * into account in some of the math, so figure out virtual stride * in pages */ - const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + const int m = DIV_ROUND_UP(omap_obj->width << fmt, PAGE_SIZE); /* We don't use vmf->pgoff since that has the fake offset: */ pgoff = ((unsigned long)vmf->virtual_address - -- GitLab From 31462de6ba1d0a60299665ef40caeaf517bfd632 Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Fri, 10 Mar 2017 11:37:01 +0100 Subject: [PATCH 1172/1834] powerpc/8xx: fix mpc8xx_get_irq() return on no irq [ Upstream commit 3c29b6038828c1f4c9ecbfec14d4fc5e25f1c947 ] IRQ 0 is a valid HW interrupt. So get_irq() shall return 0 when there is no irq, instead of returning irq_linear_revmap(... ,0) Fixes: f2a0bd3753dad ("[POWERPC] 8xx: powerpc port of core CPM PIC") Signed-off-by: Christophe Leroy Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/sysdev/mpc8xx_pic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 3e828b20c21e..2842f9d63d21 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c @@ -79,7 +79,7 @@ unsigned int mpc8xx_get_irq(void) irq = in_be32(&siu_reg->sc_sivec) >> 26; if (irq == PIC_VEC_SPURRIOUS) - irq = 0; + return 0; return irq_linear_revmap(mpc8xx_pic_host, irq); -- GitLab From 6b3c6821f0ebb3153f05fe78f165ea000847270b Mon Sep 17 00:00:00 2001 From: Ganesh Goudar Date: Wed, 31 May 2017 19:10:21 +0530 Subject: [PATCH 1173/1834] cxgb4: fix incorrect cim_la output for T6 [ Upstream commit a97051f4553551d13e586ab3cb6ae13093a44a81 ] take care of UpDbgLaRdPtr[0-3] restriction for T6. Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 24d391899730..ebeeb3581b9c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -8088,7 +8088,16 @@ int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr) ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]); if (ret) break; - idx = (idx + 1) & UPDBGLARDPTR_M; + + /* Bits 0-3 of UpDbgLaRdPtr can be between 0000 to 1001 to + * identify the 32-bit portion of the full 312-bit data + */ + if (is_t6(adap->params.chip) && (idx & 0xf) >= 9) + idx = (idx & 0xff0) + 0x10; + else + idx++; + /* address can't exceed 0xfff */ + idx &= UPDBGLARDPTR_M; } restart: if (cfg & UPDBGLAEN_F) { -- GitLab From e8b356ae7876d4661aee3d307fc2dedd46aa1f42 Mon Sep 17 00:00:00 2001 From: Thomas Bogendoerfer Date: Wed, 31 May 2017 22:21:03 +0200 Subject: [PATCH 1174/1834] Fix serial console on SNI RM400 machines [ Upstream commit e279e6d98e0cf2c2fe008b3c29042b92f0e17b1d ] sccnxp driver doesn't get the correct uart clock rate, if CONFIG_HAVE_CLOCK is disabled. Correct usage of clk API to make it work with/without it. Fixes: 90efa75f7ab0 (serial: sccnxp: Using CLK API for getting UART clock) Suggested-by: Russell King - ARM Linux Signed-off-by: Thomas Bogendoerfer Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sccnxp.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index fcf803ffad19..cdd2f942317c 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -884,14 +884,19 @@ static int sccnxp_probe(struct platform_device *pdev) clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { - if (PTR_ERR(clk) == -EPROBE_DEFER) { - ret = -EPROBE_DEFER; + ret = PTR_ERR(clk); + if (ret == -EPROBE_DEFER) goto err_out; - } + uartclk = 0; + } else { + clk_prepare_enable(clk); + uartclk = clk_get_rate(clk); + } + + if (!uartclk) { dev_notice(&pdev->dev, "Using default clock frequency\n"); uartclk = s->chip->freq_std; - } else - uartclk = clk_get_rate(clk); + } /* Check input frequency */ if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) { -- GitLab From 7f851311e4d1e7bd60a5a9a2e761aba178f8bdae Mon Sep 17 00:00:00 2001 From: Dmitry Monakhov Date: Wed, 10 May 2017 19:20:44 +0400 Subject: [PATCH 1175/1834] bio-integrity: Do not allocate integrity context for bio w/o data [ Upstream commit 3116a23bb30272d74ea81baf5d0ee23f602dd15b ] If bio has no data, such as ones from blkdev_issue_flush(), then we have nothing to protect. This patch prevent bugon like follows: kfree_debugcheck: out of range ptr ac1fa1d106742a5ah kernel BUG at mm/slab.c:2773! invalid opcode: 0000 [#1] SMP Modules linked in: bcache CPU: 0 PID: 4428 Comm: xfs_io Tainted: G W 4.11.0-rc4-ext4-00041-g2ef0043-dirty #43 Hardware name: Virtuozzo KVM, BIOS seabios-1.7.5-11.vz7.4 04/01/2014 task: ffff880137786440 task.stack: ffffc90000ba8000 RIP: 0010:kfree_debugcheck+0x25/0x2a RSP: 0018:ffffc90000babde0 EFLAGS: 00010082 RAX: 0000000000000034 RBX: ac1fa1d106742a5a RCX: 0000000000000007 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff88013f3ccb40 RBP: ffffc90000babde8 R08: 0000000000000000 R09: 0000000000000000 R10: 00000000fcb76420 R11: 00000000725172ed R12: 0000000000000282 R13: ffffffff8150e766 R14: ffff88013a145e00 R15: 0000000000000001 FS: 00007fb09384bf40(0000) GS:ffff88013f200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007fd0172f9e40 CR3: 0000000137fa9000 CR4: 00000000000006f0 Call Trace: kfree+0xc8/0x1b3 bio_integrity_free+0xc3/0x16b bio_free+0x25/0x66 bio_put+0x14/0x26 blkdev_issue_flush+0x7a/0x85 blkdev_fsync+0x35/0x42 vfs_fsync_range+0x8e/0x9f vfs_fsync+0x1c/0x1e do_fsync+0x31/0x4a SyS_fsync+0x10/0x14 entry_SYSCALL_64_fastpath+0x1f/0xc2 Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Dmitry Monakhov Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/bio-integrity.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 63f72f00c72e..80dedde0de73 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -175,6 +175,9 @@ bool bio_integrity_enabled(struct bio *bio) if (!bio_is_rw(bio)) return false; + if (!bio_sectors(bio)) + return false; + /* Already protected? */ if (bio_integrity(bio)) return false; -- GitLab From fdd62a4286fbbf811ff650b90b2ef6e4abfe6f77 Mon Sep 17 00:00:00 2001 From: Liam McBirnie Date: Thu, 1 Jun 2017 15:36:01 +1000 Subject: [PATCH 1176/1834] ip6_tunnel: fix traffic class routing for tunnels [ Upstream commit 5f733ee68f9a4df94775299ac6a7ab260704f6ed ] ip6_route_output() requires that the flowlabel contains the traffic class for policy routing. Commit 0e9a709560db ("ip6_tunnel, ip6_gre: fix setting of DSCP on encapsulated packets") removed the code which previously added the traffic class to the flowlabel. The traffic class is added here because only route lookup needs the flowlabel to contain the traffic class. Fixes: 0e9a709560db ("ip6_tunnel, ip6_gre: fix setting of DSCP on encapsulated packets") Signed-off-by: Liam McBirnie Acked-by: Peter Dawson Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_tunnel.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index a2fcf7bdb597..f185126b0327 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1097,6 +1097,9 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, if (!dst) { route_lookup: + /* add dsfield to flowlabel for route lookup */ + fl6->flowlabel = ip6_make_flowinfo(dsfield, fl6->flowlabel); + dst = ip6_route_output(net, NULL, fl6); if (dst->error) -- GitLab From 2cd3aa5a3a7b4b24a2492087d054fdcc818ff53e Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Jun 2017 04:16:22 +0200 Subject: [PATCH 1177/1834] skbuff: return -EMSGSIZE in skb_to_sgvec to prevent overflow [ Upstream commit 48a1df65334b74bd7531f932cca5928932abf769 ] This is a defense-in-depth measure in response to bugs like 4d6fa57b4dab ("macsec: avoid heap overflow in skb_to_sgvec"). There's not only a potential overflow of sglist items, but also a stack overflow potential, so we fix this by limiting the amount of recursion this function is allowed to do. Not actually providing a bounded base case is a future disaster that we can easily avoid here. As a small matter of house keeping, we take this opportunity to move the documentation comment over the actual function the documentation is for. While this could be implemented by using an explicit stack of skbuffs, when implementing this, the function complexity increased considerably, and I don't think such complexity and bloat is actually worth it. So, instead I built this and tested it on x86, x86_64, ARM, ARM64, and MIPS, and measured the stack usage there. I also reverted the recent MIPS changes that give it a separate IRQ stack, so that I could experience some worst-case situations. I found that limiting it to 24 layers deep yielded a good stack usage with room for safety, as well as being much deeper than any driver actually ever creates. Signed-off-by: Jason A. Donenfeld Cc: Steffen Klassert Cc: Herbert Xu Cc: "David S. Miller" Cc: David Howells Cc: Sabrina Dubroca Cc: "Michael S. Tsirkin" Cc: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/skbuff.h | 8 +++--- net/core/skbuff.c | 65 +++++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 601dfa849d30..1b3a2f95503d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -984,10 +984,10 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom); struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom, int newtailroom, gfp_t priority); -int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, - int offset, int len); -int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, - int len); +int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, + int offset, int len); +int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, + int offset, int len); int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer); int skb_pad(struct sk_buff *skb, int pad); #define dev_kfree_skb(a) consume_skb(a) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c5ac9f48f058..c1c74abddd62 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -3475,24 +3475,18 @@ void __init skb_init(void) NULL); } -/** - * skb_to_sgvec - Fill a scatter-gather list from a socket buffer - * @skb: Socket buffer containing the buffers to be mapped - * @sg: The scatter-gather list to map into - * @offset: The offset into the buffer's contents to start mapping - * @len: Length of buffer space to be mapped - * - * Fill the specified scatter-gather list with mappings/pointers into a - * region of the buffer space attached to a socket buffer. - */ static int -__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) +__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len, + unsigned int recursion_level) { int start = skb_headlen(skb); int i, copy = start - offset; struct sk_buff *frag_iter; int elt = 0; + if (unlikely(recursion_level >= 24)) + return -EMSGSIZE; + if (copy > 0) { if (copy > len) copy = len; @@ -3511,6 +3505,8 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]); if ((copy = end - offset) > 0) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + if (unlikely(elt && sg_is_last(&sg[elt - 1]))) + return -EMSGSIZE; if (copy > len) copy = len; @@ -3525,16 +3521,22 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) } skb_walk_frags(skb, frag_iter) { - int end; + int end, ret; WARN_ON(start > offset + len); end = start + frag_iter->len; if ((copy = end - offset) > 0) { + if (unlikely(elt && sg_is_last(&sg[elt - 1]))) + return -EMSGSIZE; + if (copy > len) copy = len; - elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start, - copy); + ret = __skb_to_sgvec(frag_iter, sg+elt, offset - start, + copy, recursion_level + 1); + if (unlikely(ret < 0)) + return ret; + elt += ret; if ((len -= copy) == 0) return elt; offset += copy; @@ -3545,6 +3547,31 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) return elt; } +/** + * skb_to_sgvec - Fill a scatter-gather list from a socket buffer + * @skb: Socket buffer containing the buffers to be mapped + * @sg: The scatter-gather list to map into + * @offset: The offset into the buffer's contents to start mapping + * @len: Length of buffer space to be mapped + * + * Fill the specified scatter-gather list with mappings/pointers into a + * region of the buffer space attached to a socket buffer. Returns either + * the number of scatterlist items used, or -EMSGSIZE if the contents + * could not fit. + */ +int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) +{ + int nsg = __skb_to_sgvec(skb, sg, offset, len, 0); + + if (nsg <= 0) + return nsg; + + sg_mark_end(&sg[nsg - 1]); + + return nsg; +} +EXPORT_SYMBOL_GPL(skb_to_sgvec); + /* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given * sglist without mark the sg which contain last skb data as the end. * So the caller can mannipulate sg list as will when padding new data after @@ -3567,19 +3594,11 @@ __skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) { - return __skb_to_sgvec(skb, sg, offset, len); + return __skb_to_sgvec(skb, sg, offset, len, 0); } EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark); -int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) -{ - int nsg = __skb_to_sgvec(skb, sg, offset, len); - sg_mark_end(&sg[nsg - 1]); - - return nsg; -} -EXPORT_SYMBOL_GPL(skb_to_sgvec); /** * skb_cow_data - Check that a socket buffer's data buffers are writable -- GitLab From 6083f1625b75a9c711ab14e95f581fc2bb8e3710 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Jun 2017 04:16:25 +0200 Subject: [PATCH 1178/1834] macsec: check return value of skb_to_sgvec always [ Upstream commit cda7ea6903502af34015000e16be290a79f07638 ] Signed-off-by: Jason A. Donenfeld Cc: Sabrina Dubroca Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/macsec.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c index 2caac0c37059..365a48cfcbbf 100644 --- a/drivers/net/macsec.c +++ b/drivers/net/macsec.c @@ -742,7 +742,12 @@ static struct sk_buff *macsec_encrypt(struct sk_buff *skb, macsec_fill_iv(iv, secy->sci, pn); sg_init_table(sg, ret); - skb_to_sgvec(skb, sg, 0, skb->len); + ret = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(ret < 0)) { + macsec_txsa_put(tx_sa); + kfree_skb(skb); + return ERR_PTR(ret); + } if (tx_sc->encrypt) { int len = skb->len - macsec_hdr_len(sci_present) - @@ -949,7 +954,11 @@ static struct sk_buff *macsec_decrypt(struct sk_buff *skb, macsec_fill_iv(iv, sci, ntohl(hdr->packet_number)); sg_init_table(sg, ret); - skb_to_sgvec(skb, sg, 0, skb->len); + ret = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(ret < 0)) { + kfree_skb(skb); + return ERR_PTR(ret); + } if (hdr->tci_an & MACSEC_TCI_E) { /* confidentiality: ethernet + macsec header -- GitLab From 92b86857ed7e8be6843d216fefe2178b172dbf63 Mon Sep 17 00:00:00 2001 From: Haishuang Yan Date: Sun, 4 Jun 2017 14:43:43 +0800 Subject: [PATCH 1179/1834] sit: reload iphdr in ipip6_rcv [ Upstream commit b699d0035836f6712917a41e7ae58d84359b8ff9 ] Since iptunnel_pull_header() can call pskb_may_pull(), we must reload any pointer that was related to skb->head. Fixes: a09a4c8dd1ec ("tunnels: Remove encapsulation offloads on decap") Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/ipv6/sit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d4d84da28672..181fd958c82b 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -657,6 +657,7 @@ static int ipip6_rcv(struct sk_buff *skb) if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6), !net_eq(tunnel->net, dev_net(tunnel->dev)))) goto out; + iph = ip_hdr(skb); err = IP_ECN_decapsulate(iph, skb); if (unlikely(err)) { -- GitLab From eec6e0a4b168b26f99b91c58dc17f948deaa9d9f Mon Sep 17 00:00:00 2001 From: Talat Batheesh Date: Sun, 4 Jun 2017 14:30:07 +0300 Subject: [PATCH 1180/1834] net/mlx4: Fix the check in attaching steering rules [ Upstream commit 6dc06c08bef1c746ff8da33dab677cfbacdcad32 ] Our previous patch (cited below) introduced a regression for RAW Eth QPs. Fix it by checking if the QP number provided by user-space exists, hence allowing steering rules to be added for valid QPs only. Fixes: 89c557687a32 ("net/mlx4_en: Avoid adding steering rules with invalid ring") Reported-by: Or Gerlitz Signed-off-by: Talat Batheesh Signed-off-by: Tariq Toukan Acked-by: Or Gerlitz Reviewed-by: Leon Romanovsky Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/en_ethtool.c | 5 ----- drivers/net/ethernet/mellanox/mlx4/mcg.c | 15 +++++++++++---- drivers/net/ethernet/mellanox/mlx4/qp.c | 13 +++++++++++++ include/linux/mlx4/qp.h | 1 + 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 674246b189c2..bdda17d2ea0f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1520,11 +1520,6 @@ static int mlx4_en_flow_replace(struct net_device *dev, qpn = priv->drop_qp.qpn; else if (cmd->fs.ring_cookie & EN_ETHTOOL_QP_ATTACH) { qpn = cmd->fs.ring_cookie & (EN_ETHTOOL_QP_ATTACH - 1); - if (qpn < priv->rss_map.base_qpn || - qpn >= priv->rss_map.base_qpn + priv->rx_ring_num) { - en_warn(priv, "rxnfc: QP (0x%x) doesn't exist\n", qpn); - return -EINVAL; - } } else { if (cmd->fs.ring_cookie >= priv->rx_ring_num) { en_warn(priv, "rxnfc: RX ring (%llu) doesn't exist\n", diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c index 1a670b681555..0710b3677464 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mcg.c +++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c @@ -35,6 +35,7 @@ #include #include +#include #include #include "mlx4.h" @@ -985,16 +986,21 @@ int mlx4_flow_attach(struct mlx4_dev *dev, if (IS_ERR(mailbox)) return PTR_ERR(mailbox); + if (!mlx4_qp_lookup(dev, rule->qpn)) { + mlx4_err_rule(dev, "QP doesn't exist\n", rule); + ret = -EINVAL; + goto out; + } + trans_rule_ctrl_to_hw(rule, mailbox->buf); size += sizeof(struct mlx4_net_trans_rule_hw_ctrl); list_for_each_entry(cur, &rule->list, list) { ret = parse_trans_rule(dev, cur, mailbox->buf + size); - if (ret < 0) { - mlx4_free_cmd_mailbox(dev, mailbox); - return ret; - } + if (ret < 0) + goto out; + size += ret; } @@ -1021,6 +1027,7 @@ int mlx4_flow_attach(struct mlx4_dev *dev, } } +out: mlx4_free_cmd_mailbox(dev, mailbox); return ret; diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 6143113a7fef..99c8fc970f88 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -387,6 +387,19 @@ static void mlx4_qp_free_icm(struct mlx4_dev *dev, int qpn) __mlx4_qp_free_icm(dev, qpn); } +struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn) +{ + struct mlx4_qp_table *qp_table = &mlx4_priv(dev)->qp_table; + struct mlx4_qp *qp; + + spin_lock(&qp_table->lock); + + qp = __mlx4_qp_lookup(dev, qpn); + + spin_unlock(&qp_table->lock); + return qp; +} + int mlx4_qp_alloc(struct mlx4_dev *dev, int qpn, struct mlx4_qp *qp, gfp_t gfp) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index b4ee8f62ce8d..8e2828d48d7f 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -470,6 +470,7 @@ struct mlx4_update_qp_params { u16 rate_val; }; +struct mlx4_qp *mlx4_qp_lookup(struct mlx4_dev *dev, u32 qpn); int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn, enum mlx4_update_qp_attr attr, struct mlx4_update_qp_params *params); -- GitLab From 5366c5ff9e13d6362408e25ced761f3228de7b60 Mon Sep 17 00:00:00 2001 From: Ido Shamay Date: Mon, 5 Jun 2017 10:44:56 +0300 Subject: [PATCH 1181/1834] net/mlx4: Check if Granular QoS per VF has been enabled before updating QP qos_vport [ Upstream commit 269f9883fe254d109afdfc657875c456d6fabb08 ] The Granular QoS per VF feature must be enabled in FW before it can be used. Thus, the driver cannot modify a QP's qos_vport value (via the UPDATE_QP FW command) if the feature has not been enabled -- the FW returns an error if this is attempted. Fixes: 08068cd5683f ("net/mlx4: Added qos_vport QP configuration in VST mode") Signed-off-by: Ido Shamay Signed-off-by: Jack Morgenstein Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/qp.c | 6 ++++++ .../ethernet/mellanox/mlx4/resource_tracker.c | 16 +++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c index 99c8fc970f88..474ff36b9755 100644 --- a/drivers/net/ethernet/mellanox/mlx4/qp.c +++ b/drivers/net/ethernet/mellanox/mlx4/qp.c @@ -487,6 +487,12 @@ int mlx4_update_qp(struct mlx4_dev *dev, u32 qpn, } if (attr & MLX4_UPDATE_QP_QOS_VPORT) { + if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QOS_VPP)) { + mlx4_warn(dev, "Granular QoS per VF is not enabled\n"); + err = -EOPNOTSUPP; + goto out; + } + qp_mask |= 1ULL << MLX4_UPD_QP_MASK_QOS_VPP; cmd->qp_context.qos_vport = params->qos_vport; } diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 1822382212ee..8fd1b1ab7d81 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -5214,6 +5214,13 @@ void mlx4_delete_all_resources_for_slave(struct mlx4_dev *dev, int slave) mutex_unlock(&priv->mfunc.master.res_tracker.slave_list[slave].mutex); } +static void update_qos_vpp(struct mlx4_update_qp_context *ctx, + struct mlx4_vf_immed_vlan_work *work) +{ + ctx->qp_mask |= cpu_to_be64(1ULL << MLX4_UPD_QP_MASK_QOS_VPP); + ctx->qp_context.qos_vport = work->qos_vport; +} + void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) { struct mlx4_vf_immed_vlan_work *work = @@ -5328,11 +5335,10 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work) qp->sched_queue & 0xC7; upd_context->qp_context.pri_path.sched_queue |= ((work->qos & 0x7) << 3); - upd_context->qp_mask |= - cpu_to_be64(1ULL << - MLX4_UPD_QP_MASK_QOS_VPP); - upd_context->qp_context.qos_vport = - work->qos_vport; + + if (dev->caps.flags2 & + MLX4_DEV_CAP_FLAG2_QOS_VPP) + update_qos_vpp(upd_context, work); } err = mlx4_cmd(dev, mailbox->dma, -- GitLab From 81da672aec5eb159835fafaac8b9ebefcba27452 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 31 May 2017 21:01:03 +0900 Subject: [PATCH 1182/1834] perf header: Set proper module name when build-id event found [ Upstream commit 1deec1bd96ccd8beb04d2112a6d12fe20505c3a6 ] When perf processes build-id event, it creates DSOs with the build-id. But it didn't set the module short name (like '[module-name]') so when processing a kernel mmap event of the module, it cannot found the DSO as it only checks the short names. That leads for perf to create a same DSO without the build-id info and it'll lookup the system path even if the DSO is already in the build-id cache. After kernel was updated, perf cannot find the DSO and cannot show symbols in it anymore. You can see this if you have an old data file (w/ old kernel version): $ perf report -i perf.data.old -v |& grep scsi_mod build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz : cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1 Failed to open /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz, continuing without symbols ... The second message didn't show the build-id. With this patch: $ perf report -i perf.data.old -v |& grep scsi_mod build id event received for /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz: cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1 /lib/modules/3.19.2-1-ARCH/kernel/drivers/scsi/scsi_mod.ko.gz with build id cafe1ce6ca13a98a5d9ed3425cde249e57a27fc1 not found, continuing without symbols ... Now it shows the build-id but still cannot load the symbol table. This is a different problem which will be fixed in the next patch. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Andi Kleen Cc: David Ahern Cc: Peter Zijlstra Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170531120105.21731-1-namhyung@kernel.org [ Fix the build on older compilers (debian <= 8, fedora <= 21, etc) wrt kmod_path var init ] Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/header.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 28bdb48357f0..ab36aa5585b4 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1454,8 +1454,16 @@ static int __event_process_build_id(struct build_id_event *bev, dso__set_build_id(dso, &bev->build_id); - if (!is_kernel_module(filename, cpumode)) - dso->kernel = dso_type; + if (dso_type != DSO_TYPE_USER) { + struct kmod_path m = { .name = NULL, }; + + if (!kmod_path__parse_name(&m, filename) && m.kmod) + dso__set_short_name(dso, strdup(m.name), true); + else + dso->kernel = dso_type; + + free(m.name); + } build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); -- GitLab From aee0f56512ca2395544e5b1ab4defcc2b9dc6bc6 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Fri, 2 Jun 2017 16:37:52 +0200 Subject: [PATCH 1183/1834] perf report: Ensure the perf DSO mapping matches what libdw sees [ Upstream commit 2538b9e2450ae255337c04356e9e0f8cb9ec48d9 ] In some situations the libdw unwinder stopped working properly. I.e. with libunwind we see: ~~~~~ heaptrack_gui 2228 135073.400112: 641314 cycles: e8ed _dl_fixup (/usr/lib/ld-2.25.so) 15f06 _dl_runtime_resolve_sse_vex (/usr/lib/ld-2.25.so) ed94c KDynamicJobTracker::KDynamicJobTracker (/home/milian/projects/compiled/kf5/lib64/libKF5KIOWidgets.so.5.35.0) 608f3 _GLOBAL__sub_I_kdynamicjobtracker.cpp (/home/milian/projects/compiled/kf5/lib64/libKF5KIOWidgets.so.5.35.0) f199 call_init.part.0 (/usr/lib/ld-2.25.so) f2a5 _dl_init (/usr/lib/ld-2.25.so) db9 _dl_start_user (/usr/lib/ld-2.25.so) ~~~~~ But with libdw and without this patch this sample is not properly unwound: ~~~~~ heaptrack_gui 2228 135073.400112: 641314 cycles: e8ed _dl_fixup (/usr/lib/ld-2.25.so) 15f06 _dl_runtime_resolve_sse_vex (/usr/lib/ld-2.25.so) ed94c KDynamicJobTracker::KDynamicJobTracker (/home/milian/projects/compiled/kf5/lib64/libKF5KIOWidgets.so.5.35.0) ~~~~~ Debug output showed me that libdw found a module for the last frame address, but it thinks it belongs to /usr/lib/ld-2.25.so. This patch double-checks what libdw sees and what perf knows. If the mappings mismatch, we now report the elf known to perf. This fixes the situation above, and the libdw unwinder produces the same stack as libunwind. Signed-off-by: Milian Wolff Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20170602143753.16907-1-milian.wolff@kdab.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/unwind-libdw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c index 7c4defce0115..b46e1cf347e5 100644 --- a/tools/perf/util/unwind-libdw.c +++ b/tools/perf/util/unwind-libdw.c @@ -38,6 +38,14 @@ static int __report_module(struct addr_location *al, u64 ip, return 0; mod = dwfl_addrmodule(ui->dwfl, ip); + if (mod) { + Dwarf_Addr s; + + dwfl_module_info(mod, NULL, &s, NULL, NULL, NULL, NULL, NULL); + if (s != al->map->start) + mod = 0; + } + if (!mod) mod = dwfl_report_elf(ui->dwfl, dso->short_name, dso->long_name, -1, al->map->start, -- GitLab From fe587505e7d566982717493ddc95b935de81047c Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 29 Mar 2017 10:21:09 +0300 Subject: [PATCH 1184/1834] iwlwifi: mvm: fix firmware debug restart recording [ Upstream commit addce854f164a68da9cb158e2e7e447705068549 ] When we want to stop the recording of the firmware debug and restart it later without reloading the firmware we don't need to resend the configuration that comes with host commands. Sending those commands confused the hardware and led to an NMI 0x66. Change the flow as following: * read the relevant registers (DBGC_IN_SAMPLE, DBGC_OUT_CTRL) * clear those registers * wait for the hardware to complete its write to the buffer * get the data * restore the value of those registers (to restart the recording) For early start (where the configuration is already compiled in the firmware), we don't need to set those registers after the firmware has been loaded, but only when we want to restart the recording without having restarted the firmware. Signed-off-by: Emmanuel Grumbach Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/iwl-prph.h | 1 + .../net/wireless/intel/iwlwifi/mvm/fw-dbg.c | 12 +------ drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 32 ++++++++++++++----- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 406ef301b8ab..da8234b762bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -369,6 +369,7 @@ #define MON_DMARB_RD_DATA_ADDR (0xa03c5c) #define DBGC_IN_SAMPLE (0xa03c00) +#define DBGC_OUT_CTRL (0xa03c0c) /* enable the ID buf for read */ #define WFPM_PS_CTL_CLR 0xA0300C diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c index 700d244df34b..2642d8e477b8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c @@ -914,14 +914,6 @@ int iwl_mvm_fw_dbg_collect_trig(struct iwl_mvm *mvm, return 0; } -static inline void iwl_mvm_restart_early_start(struct iwl_mvm *mvm) -{ - if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) - iwl_clear_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); - else - iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 1); -} - int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id) { u8 *ptr; @@ -935,10 +927,8 @@ int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, u8 conf_id) /* EARLY START - firmware's configuration is hard coded */ if ((!mvm->fw->dbg_conf_tlv[conf_id] || !mvm->fw->dbg_conf_tlv[conf_id]->num_of_hcmds) && - conf_id == FW_DBG_START_FROM_ALIVE) { - iwl_mvm_restart_early_start(mvm); + conf_id == FW_DBG_START_FROM_ALIVE) return 0; - } if (!mvm->fw->dbg_conf_tlv[conf_id]) return -EINVAL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index c60703e0c246..ed9bf8c759b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1687,6 +1687,7 @@ void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { mvm->ucode_loaded = false; + mvm->fw_dbg_conf = FW_DBG_INVALID; iwl_trans_stop_device(mvm->trans); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 4d35deb628bc..6d38eec3f9d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -1118,21 +1118,37 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work) mutex_lock(&mvm->mutex); - /* stop recording */ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) { + /* stop recording */ iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100); + + iwl_mvm_fw_error_dump(mvm); + + /* start recording again if the firmware is not crashed */ + if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && + mvm->fw->dbg_dest_tlv) + iwl_clear_bits_prph(mvm->trans, + MON_BUFF_SAMPLE_CTL, 0x100); } else { + u32 in_sample = iwl_read_prph(mvm->trans, DBGC_IN_SAMPLE); + u32 out_ctrl = iwl_read_prph(mvm->trans, DBGC_OUT_CTRL); + + /* stop recording */ iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0); - /* wait before we collect the data till the DBGC stop */ udelay(100); - } + iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0); + /* wait before we collect the data till the DBGC stop */ + udelay(500); - iwl_mvm_fw_error_dump(mvm); + iwl_mvm_fw_error_dump(mvm); - /* start recording again if the firmware is not crashed */ - WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) && - mvm->fw->dbg_dest_tlv && - iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf)); + /* start recording again if the firmware is not crashed */ + if (!test_bit(STATUS_FW_ERROR, &mvm->trans->status) && + mvm->fw->dbg_dest_tlv) { + iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, in_sample); + iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, out_ctrl); + } + } mutex_unlock(&mvm->mutex); -- GitLab From c3a1c5ab6ccef80768c445bc583d0b94248cda78 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 17 Apr 2017 22:37:05 +0200 Subject: [PATCH 1185/1834] watchdog: f71808e_wdt: Add F71868 support [ Upstream commit 166fbcf88fdafa02f784ec25ac64745c716b2de0 ] This adds support for watchdog part of Fintek F71868 Super I/O chip to f71808e_wdt driver. The F71868 chip is, in general, very similar to a F71869, however it has slightly different set of available reset pulse widths. Tested on MSI A55M-P33 motherboard. Signed-off-by: Maciej S. Szmigiero Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/Kconfig | 7 ++++--- drivers/watchdog/f71808e_wdt.c | 27 ++++++++++++++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 3eb58cb51e56..8f8909a668d7 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -799,11 +799,12 @@ config EBC_C384_WDT the timeout module parameter. config F71808E_WDT - tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog" + tristate "Fintek F718xx, F818xx Super I/O Watchdog" depends on X86 help - This is the driver for the hardware watchdog on the Fintek - F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers. + This is the driver for the hardware watchdog on the Fintek F71808E, + F71862FG, F71868, F71869, F71882FG, F71889FG, F81865 and F81866 + Super I/O controllers. You can compile this driver directly into the kernel, or use it as a module. The module will be called f71808e_wdt. diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 1b7e9169072f..8658dba21768 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -57,6 +57,7 @@ #define SIO_F71808_ID 0x0901 /* Chipset ID */ #define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */ +#define SIO_F71868_ID 0x1106 /* Chipset ID */ #define SIO_F71869_ID 0x0814 /* Chipset ID */ #define SIO_F71869A_ID 0x1007 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */ @@ -101,7 +102,7 @@ MODULE_PARM_DESC(timeout, static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH; module_param(pulse_width, uint, 0); MODULE_PARM_DESC(pulse_width, - "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms" + "Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms" " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")"); static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN; @@ -119,13 +120,14 @@ module_param(start_withtimeout, uint, 0); MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" " given initial timeout. Zero (default) disables this feature."); -enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg, f81865, - f81866}; +enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg, + f81865, f81866}; static const char *f71808e_names[] = { "f71808fg", "f71858fg", "f71862fg", + "f71868", "f71869", "f71882fg", "f71889fg", @@ -252,16 +254,23 @@ static int watchdog_set_timeout(int timeout) static int watchdog_set_pulse_width(unsigned int pw) { int err = 0; + unsigned int t1 = 25, t2 = 125, t3 = 5000; + + if (watchdog.type == f71868) { + t1 = 30; + t2 = 150; + t3 = 6000; + } mutex_lock(&watchdog.lock); - if (pw <= 1) { + if (pw <= 1) { watchdog.pulse_val = 0; - } else if (pw <= 25) { + } else if (pw <= t1) { watchdog.pulse_val = 1; - } else if (pw <= 125) { + } else if (pw <= t2) { watchdog.pulse_val = 2; - } else if (pw <= 5000) { + } else if (pw <= t3) { watchdog.pulse_val = 3; } else { pr_err("pulse width out of range\n"); @@ -354,6 +363,7 @@ static int watchdog_start(void) goto exit_superio; break; + case f71868: case f71869: /* GPIO14 --> WDTRST# */ superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4); @@ -792,6 +802,9 @@ static int __init f71808e_find(int sioaddr) watchdog.type = f71862fg; err = f71862fg_pin_configure(0); /* validate module parameter */ break; + case SIO_F71868_ID: + watchdog.type = f71868; + break; case SIO_F71869_ID: case SIO_F71869A_ID: watchdog.type = f71869; -- GitLab From 6dc9a4b33b355c4bddb994b0abf1982a798ea1f4 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Thu, 16 Mar 2017 17:26:03 +0200 Subject: [PATCH 1186/1834] iwlwifi: mvm: Fix command queue number on d0i3 flow [ Upstream commit c72c37b7f392ad7edc10b6092fa48c632ba6f4ed ] During d0i3 flow we flush all the queue except from the command queue. Currently, in this flow the command queue is hard coded to 9. In DQA the command queue number has changed from 9 to 0. Fix that. This fixes a problem in runtime PM resume flow. Fixes: 097129c9e625 ("iwlwifi: mvm: move cmd queue to be #0 in dqa mode") Signed-off-by: Haim Dreyfuss Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index ed9bf8c759b4..2b1c691bb4b2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -1666,8 +1666,11 @@ int iwl_mvm_find_free_queue(struct iwl_mvm *mvm, u8 sta_id, u8 minq, u8 maxq); */ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm) { + u32 cmd_queue = iwl_mvm_is_dqa_supported(mvm) ? IWL_MVM_DQA_CMD_QUEUE : + IWL_MVM_CMD_QUEUE; + return ((BIT(mvm->cfg->base_params->num_of_queues) - 1) & - ~BIT(IWL_MVM_CMD_QUEUE)); + ~BIT(cmd_queue)); } static inline -- GitLab From 87a9c569fea9d88a5a47064a9fb6720707010114 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 22 Mar 2017 22:00:10 +0100 Subject: [PATCH 1187/1834] iwlwifi: tt: move ucode_loaded check under mutex [ Upstream commit d9954405758a0cbbe258d9b4d4dc12a06fa48a28 ] The ucode_loaded check should be under the mutex, since it can otherwise change state after we looked at it and before we got the mutex. Fix that. Fixes: 5c89e7bc557e ("iwlwifi: mvm: add registration to cooling device") Signed-off-by: Johannes Berg Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index bec7d9c46087..c5203568a47a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -790,11 +790,13 @@ static int iwl_mvm_tcool_set_cur_state(struct thermal_cooling_device *cdev, struct iwl_mvm *mvm = (struct iwl_mvm *)(cdev->devdata); int ret; - if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) - return -EIO; - mutex_lock(&mvm->mutex); + if (!mvm->ucode_loaded || !(mvm->cur_ucode == IWL_UCODE_REGULAR)) { + ret = -EIO; + goto unlock; + } + if (new_state >= ARRAY_SIZE(iwl_mvm_cdev_budgets)) { ret = -EINVAL; goto unlock; -- GitLab From 9345b98879420bde44fa448ad8d9d04e47d18835 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Fri, 24 Mar 2017 11:01:45 +0200 Subject: [PATCH 1188/1834] iwlwifi: pcie: only use d0i3 in suspend/resume if system_pm is set to d0i3 [ Upstream commit e4c49c4937951de1cdbe35572ade40c948dec1e1 ] We only need to handle d0i3 entry and exit during suspend resume if system_pm is set to IWL_PLAT_PM_MODE_D0I3, otherwise d0i3 entry failures will cause suspend to fail. This fixes https://bugzilla.kernel.org/show_bug.cgi?id=194791 Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 10ef44e8ecd5..fe32de252e6b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2824,7 +2824,8 @@ static struct iwl_trans_dump_data #ifdef CONFIG_PM_SLEEP static int iwl_trans_pcie_suspend(struct iwl_trans *trans) { - if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3) + if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3 && + (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3)) return iwl_pci_fw_enter_d0i3(trans); return 0; @@ -2832,7 +2833,8 @@ static int iwl_trans_pcie_suspend(struct iwl_trans *trans) static void iwl_trans_pcie_resume(struct iwl_trans *trans) { - if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3) + if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3 && + (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3)) iwl_pci_fw_exit_d0i3(trans); } #endif /* CONFIG_PM_SLEEP */ -- GitLab From 9d85c2a32c413be3e37b39337a927a8872ebb4a5 Mon Sep 17 00:00:00 2001 From: Luca Coelho Date: Tue, 25 Apr 2017 10:18:10 +0300 Subject: [PATCH 1189/1834] iwlwifi: fix min API version for 7265D, 3168, 8000 and 8265 [ Upstream commit 15098803d38778070b8edfa5a3d5fc4fef10d0a1 ] In a previous commit, we removed support for API versions earlier than 22 for these NICs. By mistake, the *_UCODE_API_MIN definitions were set to 17. Fix that. Fixes: 4b87e5af638b ("iwlwifi: remove support for fw older than -17 and -22") Signed-off-by: Luca Coelho Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/intel/iwlwifi/iwl-7000.c | 4 ++-- drivers/net/wireless/intel/iwlwifi/iwl-8000.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c index d4b73dedf89b..b35adbca7a5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-7000.c @@ -79,8 +79,8 @@ /* Lowest firmware API version supported */ #define IWL7260_UCODE_API_MIN 17 #define IWL7265_UCODE_API_MIN 17 -#define IWL7265D_UCODE_API_MIN 17 -#define IWL3168_UCODE_API_MIN 20 +#define IWL7265D_UCODE_API_MIN 22 +#define IWL3168_UCODE_API_MIN 22 /* NVM versions */ #define IWL7260_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index 8d3e53fac1da..20d08ddb4388 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -74,8 +74,8 @@ #define IWL8265_UCODE_API_MAX 26 /* Lowest firmware API version supported */ -#define IWL8000_UCODE_API_MIN 17 -#define IWL8265_UCODE_API_MIN 20 +#define IWL8000_UCODE_API_MIN 22 +#define IWL8265_UCODE_API_MIN 22 /* NVM versions */ #define IWL8000_NVM_VERSION 0x0a1d -- GitLab From 8339488663f23b7d59413f756a6507879d83b4bf Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 5 Jun 2017 13:59:15 +0200 Subject: [PATCH 1190/1834] tags: honor COMPILED_SOURCE with apart output directory [ Upstream commit cbf52a3e6a8a92beec6e0c70abf4111cd8f8faf7 ] When the kernel is compiled with an "O=" argument, the object files are not in the source tree, but in the build tree. This patch fixes O= build by looking for object files in the build tree. Fixes: 923e02ecf3f8 ("scripts/tags.sh: Support compiled source") Signed-off-by: Robert Jarzmik Signed-off-by: Masahiro Yamada Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- scripts/tags.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/tags.sh b/scripts/tags.sh index a2ff3388e5ea..2a61db329adf 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -106,6 +106,7 @@ all_compiled_sources() case "$i" in *.[cS]) j=${i/\.[cS]/\.o} + j="${j#$tree}" if [ -e $j ]; then echo $i fi -- GitLab From 017c118c7534f36b5a6db3079266024a4a667135 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Tue, 2 May 2017 21:19:24 +0200 Subject: [PATCH 1191/1834] ARM: dts: qcom: ipq4019: fix i2c_0 node [ Upstream commit 650df439cfb96c303328935559b2d06127a5a0b0 ] This patch fixes two typos in the i2c_0 node for the ipq4019. The reg property length is just 0x600. The core clock is GCC_BLSP1_QUP1_I2C_APPS_CLK. GCC_BLSP1_QUP2_I2C_APPS_CLK is used by the second i2c. Fixes: e76b4284b520ba3 ("qcom: ipq4019: add i2c node to ipq4019 SoC and DK01 device tree") Signed-off-by: Christian Lamparter Signed-off-by: Andy Gross Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/qcom-ipq4019.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom-ipq4019.dtsi b/arch/arm/boot/dts/qcom-ipq4019.dtsi index b7a24af8f47b..4b7d97275c62 100644 --- a/arch/arm/boot/dts/qcom-ipq4019.dtsi +++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi @@ -154,10 +154,10 @@ i2c_0: i2c@78b7000 { compatible = "qcom,i2c-qup-v2.2.1"; - reg = <0x78b7000 0x6000>; + reg = <0x78b7000 0x600>; interrupts = ; clocks = <&gcc GCC_BLSP1_AHB_CLK>, - <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>; + <&gcc GCC_BLSP1_QUP1_I2C_APPS_CLK>; clock-names = "iface", "core"; #address-cells = <1>; #size-cells = <0>; -- GitLab From 5b81fa9664ca252010ddfcffb7d61bde3642c966 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:50 -0700 Subject: [PATCH 1192/1834] e1000e: fix race condition around skb_tstamp_tx() [ Upstream commit 5012863b7347866764c4a4e58b62fb05346b0d06 ] The e1000e driver and related hardware has a limitation on Tx PTP packets which requires we limit to timestamping a single packet at once. We do this by verifying that we never request a new Tx timestamp while we still have a tx_hwtstamp_skb pointer. Unfortunately the driver suffers from a race condition around this. The tx_hwtstamp_skb pointer is not set to NULL until after skb_tstamp_tx() is called. This function notifies the stack and applications of a new timestamp. Even a well behaved application that only sends a new request when the first one is finished might be woken up and possibly send a packet before we can free the timestamp in the driver again. The result is that we needlessly ignore some Tx timestamp requests in this corner case. Fix this by assigning the tx_hwtstamp_skb pointer prior to calling skb_tstamp_tx() and use a temporary pointer to hold the timestamped skb until that function finishes. This ensures that the application is not woken up until the driver is ready to begin timestamping a new packet. This ensures that well behaved applications do not accidentally race with condition to skip Tx timestamps. Obviously an application which sends multiple Tx timestamp requests at once will still only timestamp one packet at a time. Unfortunately there is nothing we can do about this. Reported-by: David Mirabito Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/netdev.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 528a926dd979..64a0c61435c7 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1182,6 +1182,7 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) struct e1000_hw *hw = &adapter->hw; if (er32(TSYNCTXCTL) & E1000_TSYNCTXCTL_VALID) { + struct sk_buff *skb = adapter->tx_hwtstamp_skb; struct skb_shared_hwtstamps shhwtstamps; u64 txstmp; @@ -1190,9 +1191,14 @@ static void e1000e_tx_hwtstamp_work(struct work_struct *work) e1000e_systim_to_hwtstamp(adapter, &shhwtstamps, txstmp); - skb_tstamp_tx(adapter->tx_hwtstamp_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->tx_hwtstamp_skb); + /* Clear the global tx_hwtstamp_skb pointer and force writes + * prior to notifying the stack of a Tx timestamp. + */ adapter->tx_hwtstamp_skb = NULL; + wmb(); /* force write prior to skb_tstamp_tx */ + + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } else if (time_after(jiffies, adapter->tx_hwtstamp_start + adapter->tx_timeout_factor * HZ)) { dev_kfree_skb_any(adapter->tx_hwtstamp_skb); -- GitLab From f07ce2798efa11713d032513096f1912f2b1916f Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 3 May 2017 10:28:52 -0700 Subject: [PATCH 1193/1834] igb: fix race condition with PTP_TX_IN_PROGRESS bits [ Upstream commit 4ccdc013b0ae04755a8f7905e0525955d52a77d0 ] Hardware related to the igb driver has a limitation of only handling one Tx timestamp at a time. Thus, the driver uses a state bit lock to enforce that only one timestamp request is honored at a time. Unfortunately this suffers from a simple race condition. The bit lock is not cleared until after skb_tstamp_tx() is called notifying the stack of a new Tx timestamp. Even a well behaved application which sends only one timestamp request at once and waits for a response might wake up and send a new packet before the bit lock is cleared. This results in needlessly dropping some Tx timestamp requests. We can fix this by unlocking the state bit as soon as we read the Timestamp register, as this is the first point at which it is safe to unlock. To avoid issues with the skb pointer, we'll use a copy of the pointer and set the global variable in the driver structure to NULL first. This ensures that the next timestamp request does not modify our local copy of the skb pointer. This ensures that well behaved applications do not accidentally race with the unlock bit. Obviously an application which sends multiple Tx timestamp requests at once will still only timestamp one packet at a time. Unfortunately there is nothing we can do about this. Reported-by: David Mirabito Signed-off-by: Jacob Keller Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/igb/igb_ptp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index a7895c4cbcc3..9eb9b68f8935 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -721,6 +721,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) **/ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) { + struct sk_buff *skb = adapter->ptp_tx_skb; struct e1000_hw *hw = &adapter->hw; struct skb_shared_hwtstamps shhwtstamps; u64 regval; @@ -748,10 +749,17 @@ static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) shhwtstamps.hwtstamp = ktime_add_ns(shhwtstamps.hwtstamp, adjust); - skb_tstamp_tx(adapter->ptp_tx_skb, &shhwtstamps); - dev_kfree_skb_any(adapter->ptp_tx_skb); + /* Clear the lock early before calling skb_tstamp_tx so that + * applications are not woken up before the lock bit is clear. We use + * a copy of the skb pointer to ensure other threads can't change it + * while we're notifying the stack. + */ adapter->ptp_tx_skb = NULL; clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); + + /* Notify the stack and free the skb after we've unlocked */ + skb_tstamp_tx(skb, &shhwtstamps); + dev_kfree_skb_any(skb); } /** -- GitLab From 20c29d92ce653c216e1adb892bcb04846871d537 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 5 May 2017 08:34:58 +0300 Subject: [PATCH 1194/1834] cxl: Unlock on error in probe [ Upstream commit 58d876fa7181f2f393190c1d32c056b5a9d34aa2 ] We should unlock if get_cxl_adapter() fails. Fixes: 594ff7d067ca ("cxl: Support to flash a new image on the adapter from a guest") Signed-off-by: Dan Carpenter Acked-by: Frederic Barrat Signed-off-by: Michael Ellerman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/misc/cxl/flash.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c index c63d61e17d56..381a9a166f93 100644 --- a/drivers/misc/cxl/flash.c +++ b/drivers/misc/cxl/flash.c @@ -401,8 +401,10 @@ static int device_open(struct inode *inode, struct file *file) if (down_interruptible(&sem) != 0) return -EPERM; - if (!(adapter = get_cxl_adapter(adapter_num))) - return -ENODEV; + if (!(adapter = get_cxl_adapter(adapter_num))) { + rc = -ENODEV; + goto err_unlock; + } file->private_data = adapter; continue_token = 0; @@ -446,6 +448,8 @@ static int device_open(struct inode *inode, struct file *file) free_page((unsigned long) le); err: put_device(&adapter->dev); +err_unlock: + up(&sem); return rc; } -- GitLab From 7c484e3bcf10c9a83e78fe77fc3d4d0b8074b12c Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 23 Apr 2017 10:06:36 -0300 Subject: [PATCH 1195/1834] cx25840: fix unchecked return values [ Upstream commit 35378ce143071c2a6bad4b59a000e9b9f8f6ea67 ] In functions cx25840_initialize(), cx231xx_initialize(), and cx23885_initialize(), the return value of create_singlethread_workqueue() is used without validation. This may result in NULL dereference and cause kernel crash. This patch fixes it. Signed-off-by: Pan Bian Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/i2c/cx25840/cx25840-core.c | 36 ++++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 142ae28803bb..d558ed3e59c6 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -420,11 +420,13 @@ static void cx25840_initialize(struct i2c_client *client) INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); + if (q) { + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + } /* 6. */ cx25840_write(client, 0x115, 0x8c); @@ -634,11 +636,13 @@ static void cx23885_initialize(struct i2c_client *client) INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); + if (q) { + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + } /* Call the cx23888 specific std setup func, we no longer rely on * the generic cx24840 func. @@ -752,11 +756,13 @@ static void cx231xx_initialize(struct i2c_client *client) INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); - prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); - queue_work(q, &state->fw_work); - schedule(); - finish_wait(&state->fw_wait, &wait); - destroy_workqueue(q); + if (q) { + prepare_to_wait(&state->fw_wait, &wait, TASK_UNINTERRUPTIBLE); + queue_work(q, &state->fw_work); + schedule(); + finish_wait(&state->fw_wait, &wait); + destroy_workqueue(q); + } cx25840_std_setup(client); -- GitLab From 085da766de30ca002dc226fb9d90f58b58e73312 Mon Sep 17 00:00:00 2001 From: A Sun Date: Sun, 26 Mar 2017 15:33:07 -0300 Subject: [PATCH 1196/1834] mceusb: sporadic RX truncation corruption fix [ Upstream commit 8e175b22e8640bf3a58e071af54190b909e4a944 ] Intermittent RX truncation and loss of IR received data. This resulted in receive stream synchronization errors where driver attempted to incorrectly parse IR data (eg 0x90 below) as command response. [ 3969.139898] mceusb 1-1.2:1.0: processed IR data [ 3969.151315] mceusb 1-1.2:1.0: rx data: 00 90 (length=2) [ 3969.151321] mceusb 1-1.2:1.0: Unknown command 0x00 0x90 [ 3969.151336] mceusb 1-1.2:1.0: rx data: 98 0a 8d 0a 8e 0a 8e 0a 8e 0a 8e 0a 9a 0a 8e 0a 0b 3a 8e 00 80 41 59 00 00 (length=25) [ 3969.151341] mceusb 1-1.2:1.0: Raw IR data, 24 pulse/space samples [ 3969.151348] mceusb 1-1.2:1.0: Storing space with duration 500000 Bug trigger appears to be normal, but heavy, IR receiver use. Signed-off-by: A Sun Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/media/rc/mceusb.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index db525cdfac88..d9f88a4a96bd 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1381,8 +1381,13 @@ static int mceusb_dev_probe(struct usb_interface *intf, goto rc_dev_fail; /* wire up inbound data handler */ - usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, - mceusb_dev_recv, ir, ep_in->bInterval); + if (usb_endpoint_xfer_int(ep_in)) + usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, + mceusb_dev_recv, ir, ep_in->bInterval); + else + usb_fill_bulk_urb(ir->urb_in, dev, pipe, ir->buf_in, maxp, + mceusb_dev_recv, ir); + ir->urb_in->transfer_dma = ir->dma_in; ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -- GitLab From e9399672360e6ecdcb6a9ebfe88e156922d1694c Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 5 Jun 2017 12:22:55 +0100 Subject: [PATCH 1197/1834] net: phy: avoid genphy_aneg_done() for PHYs without clause 22 support [ Upstream commit 41408ad519f7a2a1c5229e61f2a97f4df1b61adc ] Avoid calling genphy_aneg_done() for PHYs that do not implement the Clause 22 register set. Clause 45 PHYs may implement the Clause 22 register set along with the Clause 22 extension MMD. Hence, we can't simply block access to the Clause 22 functions based on the PHY being a Clause 45 PHY. Signed-off-by: Russell King Reviewed-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/phy.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index e2d9ca60e467..4d217649c8b1 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -148,6 +148,12 @@ static inline int phy_aneg_done(struct phy_device *phydev) if (phydev->drv->aneg_done) return phydev->drv->aneg_done(phydev); + /* Avoid genphy_aneg_done() if the Clause 45 PHY does not + * implement Clause 22 registers + */ + if (phydev->is_c45 && !(phydev->c45_ids.devices_in_package & BIT(0))) + return -EINVAL; + return genphy_aneg_done(phydev); } -- GitLab From 72da86afee86904a7bb5963e52d11e53d2e29641 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Tue, 6 Jun 2017 20:50:42 +0300 Subject: [PATCH 1198/1834] ARM: imx: Add MXC_CPU_IMX6ULL and cpu_is_imx6ull [ Upstream commit b3ea575770c7eeb259c77b6861cd14d00eb309df ] Support for imx6ull is already present but it's based on of_machine_is_compatible("fsl,imx6ull") checks. Add it to the MXC_CPU_* enumeration as well. This also fixes /sys/devices/soc0/soc_id reading "Unknown". Signed-off-by: Leonard Crestez Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/mach-imx/cpu.c | 3 +++ arch/arm/mach-imx/mxc.h | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/arch/arm/mach-imx/cpu.c b/arch/arm/mach-imx/cpu.c index b3347d32349f..94906ed49392 100644 --- a/arch/arm/mach-imx/cpu.c +++ b/arch/arm/mach-imx/cpu.c @@ -131,6 +131,9 @@ struct device * __init imx_soc_device_init(void) case MXC_CPU_IMX6UL: soc_id = "i.MX6UL"; break; + case MXC_CPU_IMX6ULL: + soc_id = "i.MX6ULL"; + break; case MXC_CPU_IMX7D: soc_id = "i.MX7D"; break; diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h index 34f2ff62583c..e00d6260c3df 100644 --- a/arch/arm/mach-imx/mxc.h +++ b/arch/arm/mach-imx/mxc.h @@ -39,6 +39,7 @@ #define MXC_CPU_IMX6SX 0x62 #define MXC_CPU_IMX6Q 0x63 #define MXC_CPU_IMX6UL 0x64 +#define MXC_CPU_IMX6ULL 0x65 #define MXC_CPU_IMX7D 0x72 #define IMX_DDR_TYPE_LPDDR2 1 @@ -73,6 +74,11 @@ static inline bool cpu_is_imx6ul(void) return __mxc_cpu_type == MXC_CPU_IMX6UL; } +static inline bool cpu_is_imx6ull(void) +{ + return __mxc_cpu_type == MXC_CPU_IMX6ULL; +} + static inline bool cpu_is_imx6q(void) { return __mxc_cpu_type == MXC_CPU_IMX6Q; -- GitLab From 383f15ee34fb21137a6486162132f79fc049cb3e Mon Sep 17 00:00:00 2001 From: Rakesh Pandit Date: Mon, 5 Jun 2017 14:43:11 +0300 Subject: [PATCH 1199/1834] nvme-pci: fix multiple ctrl removal scheduling [ Upstream commit 82b057caefaff2a891f821a617d939f46e03e844 ] Commit c5f6ce97c1210 tries to address multiple resets but fails as work_busy doesn't involve any synchronization and can fail. This is reproducible easily as can be seen by WARNING below which is triggered with line: WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING) Allowing multiple resets can result in multiple controller removal as well if different conditions inside nvme_reset_work fail and which might deadlock on device_release_driver. [ 480.327007] WARNING: CPU: 3 PID: 150 at drivers/nvme/host/pci.c:1900 nvme_reset_work+0x36c/0xec0 [ 480.327008] Modules linked in: rfcomm fuse nf_conntrack_netbios_ns nf_conntrack_broadcast... [ 480.327044] btusb videobuf2_core ghash_clmulni_intel snd_hwdep cfg80211 acer_wmi hci_uart.. [ 480.327065] CPU: 3 PID: 150 Comm: kworker/u16:2 Not tainted 4.12.0-rc1+ #13 [ 480.327065] Hardware name: Acer Predator G9-591/Mustang_SLS, BIOS V1.10 03/03/2016 [ 480.327066] Workqueue: nvme nvme_reset_work [ 480.327067] task: ffff880498ad8000 task.stack: ffffc90002218000 [ 480.327068] RIP: 0010:nvme_reset_work+0x36c/0xec0 [ 480.327069] RSP: 0018:ffffc9000221bdb8 EFLAGS: 00010246 [ 480.327070] RAX: 0000000000460000 RBX: ffff880498a98128 RCX: dead000000000200 [ 480.327070] RDX: 0000000000000001 RSI: ffff8804b1028020 RDI: ffff880498a98128 [ 480.327071] RBP: ffffc9000221be50 R08: 0000000000000000 R09: 0000000000000000 [ 480.327071] R10: ffffc90001963ce8 R11: 000000000000020d R12: ffff880498a98000 [ 480.327072] R13: ffff880498a53500 R14: ffff880498a98130 R15: ffff880498a98128 [ 480.327072] FS: 0000000000000000(0000) GS:ffff8804c1cc0000(0000) knlGS:0000000000000000 [ 480.327073] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 480.327074] CR2: 00007ffcf3c37f78 CR3: 0000000001e09000 CR4: 00000000003406e0 [ 480.327074] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 480.327075] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 480.327075] Call Trace: [ 480.327079] ? __switch_to+0x227/0x400 [ 480.327081] process_one_work+0x18c/0x3a0 [ 480.327082] worker_thread+0x4e/0x3b0 [ 480.327084] kthread+0x109/0x140 [ 480.327085] ? process_one_work+0x3a0/0x3a0 [ 480.327087] ? kthread_park+0x60/0x60 [ 480.327102] ret_from_fork+0x2c/0x40 [ 480.327103] Code: e8 5a dc ff ff 85 c0 41 89 c1 0f..... This patch addresses the problem by using state of controller to decide whether reset should be queued or not as state change is synchronizated using controller spinlock. Also cancel_work_sync is used to make sure remove cancels the reset_work and waits for it to finish. This patch also changes return value from -ENODEV to more appropriate -EBUSY if nvme_reset fails to change state. Fixes: c5f6ce97c1210 ("nvme: don't schedule multiple resets") Signed-off-by: Rakesh Pandit Reviewed-by: Sagi Grimberg Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/pci.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index e48ecb9303ca..8cc856ecec95 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1263,7 +1263,7 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) bool nssro = dev->subsystem && (csts & NVME_CSTS_NSSRO); /* If there is a reset ongoing, we shouldn't reset again. */ - if (work_busy(&dev->reset_work)) + if (dev->ctrl.state == NVME_CTRL_RESETTING) return false; /* We shouldn't reset unless the controller is on fatal error state @@ -1755,7 +1755,7 @@ static void nvme_reset_work(struct work_struct *work) struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work); int result = -ENODEV; - if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING)) + if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING)) goto out; /* @@ -1765,9 +1765,6 @@ static void nvme_reset_work(struct work_struct *work) if (dev->ctrl.ctrl_config & NVME_CC_ENABLE) nvme_dev_disable(dev, false); - if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING)) - goto out; - result = nvme_pci_enable(dev); if (result) goto out; @@ -1841,8 +1838,8 @@ static int nvme_reset(struct nvme_dev *dev) { if (!dev->ctrl.admin_q || blk_queue_dying(dev->ctrl.admin_q)) return -ENODEV; - if (work_busy(&dev->reset_work)) - return -ENODEV; + if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING)) + return -EBUSY; if (!queue_work(nvme_workq, &dev->reset_work)) return -EBUSY; return 0; @@ -1944,6 +1941,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (result) goto release_pools; + nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_RESETTING); dev_info(dev->ctrl.device, "pci function %s\n", dev_name(&pdev->dev)); queue_work(nvme_workq, &dev->reset_work); @@ -1987,6 +1985,7 @@ static void nvme_remove(struct pci_dev *pdev) nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING); + cancel_work_sync(&dev->reset_work); pci_set_drvdata(pdev, NULL); if (!pci_device_is_present(pdev)) { -- GitLab From 4aae4388165a2611fa4206363ccb243c1622446c Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 2 Jun 2017 16:32:08 +0800 Subject: [PATCH 1200/1834] nvme: fix hang in remove path [ Upstream commit 82654b6b8ef8b93ee87a97fc562f87f081fc2f91 ] We need to start admin queues too in nvme_kill_queues() for avoiding hang in remove path[1]. This patch is very similar with 806f026f9b901eaf(nvme: use blk_mq_start_hw_queues() in nvme_kill_queues()). [1] hang stack trace [] blk_execute_rq+0x56/0x80 [] __nvme_submit_sync_cmd+0x89/0xf0 [] nvme_set_features+0x5e/0x90 [] nvme_configure_apst+0x166/0x200 [] nvme_set_latency_tolerance+0x35/0x50 [] apply_constraint+0xb1/0xc0 [] dev_pm_qos_constraints_destroy+0xf4/0x1f0 [] dpm_sysfs_remove+0x2a/0x60 [] device_del+0x101/0x320 [] device_unregister+0x1a/0x60 [] device_destroy+0x3c/0x50 [] nvme_uninit_ctrl+0x45/0xa0 [] nvme_remove+0x78/0x110 [] pci_device_remove+0x39/0xb0 [] device_release_driver_internal+0x155/0x210 [] device_release_driver+0x12/0x20 [] nvme_remove_dead_ctrl_work+0x6b/0x70 [] process_one_work+0x18c/0x3a0 [] worker_thread+0x4e/0x3b0 [] kthread+0x109/0x140 [] ret_from_fork+0x2c/0x40 [] 0xffffffffffffffff Fixes: c5552fde102fc("nvme: Enable autonomous power state transitions") Reported-by: Rakesh Pandit Tested-by: Rakesh Pandit Reviewed-by: Sagi Grimberg Signed-off-by: Ming Lei Signed-off-by: Christoph Hellwig Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/nvme/host/core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index ad9d82eb2aed..c823e9346389 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2040,6 +2040,10 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl) struct nvme_ns *ns; mutex_lock(&ctrl->namespaces_mutex); + + /* Forcibly start all queues to avoid having stuck requests */ + blk_mq_start_hw_queues(ctrl->admin_q); + list_for_each_entry(ns, &ctrl->namespaces, list) { /* * Revalidating a dead namespace sets capacity to 0. This will -- GitLab From 4933e9f2a0d98d3e53597c421e5945c9e9d1ce5b Mon Sep 17 00:00:00 2001 From: Jim Mattson Date: Thu, 1 Jun 2017 12:44:46 -0700 Subject: [PATCH 1201/1834] KVM: nVMX: Update vmcs12->guest_linear_address on nested VM-exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit d281e13b0bfe745a21061a194e386a949784393f ] The guest-linear address field is set for VM exits due to attempts to execute LMSW with a memory operand and VM exits due to attempts to execute INS or OUTS for which the relevant segment is usable, regardless of whether or not EPT is in use. Fixes: 119a9c01a5922 ("KVM: nVMX: pass valid guest linear-address to the L1") Signed-off-by: Jim Mattson Signed-off-by: Radim Krčmář Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/x86/kvm/vmx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 41218ef8c895..b978aeccda78 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -10664,8 +10664,7 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, vmcs12->guest_pdptr3 = vmcs_read64(GUEST_PDPTR3); } - if (nested_cpu_has_ept(vmcs12)) - vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS); + vmcs12->guest_linear_address = vmcs_readl(GUEST_LINEAR_ADDRESS); if (nested_cpu_has_vid(vmcs12)) vmcs12->guest_intr_status = vmcs_read16(GUEST_INTR_STATUS); -- GitLab From d54421849563260d8344a5f60190188822214cda Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 31 May 2017 18:50:43 +0300 Subject: [PATCH 1202/1834] e1000e: Undo e1000e_pm_freeze if __e1000_shutdown fails [ Upstream commit 833521ebc65b1c3092e5c0d8a97092f98eec595d ] An error during suspend (e100e_pm_suspend), [ 429.994338] ACPI : EC: event blocked [ 429.994633] e1000e: EEE TX LPI TIMER: 00000011 [ 430.955451] pci_pm_suspend(): e1000e_pm_suspend+0x0/0x30 [e1000e] returns -2 [ 430.955454] dpm_run_callback(): pci_pm_suspend+0x0/0x140 returns -2 [ 430.955458] PM: Device 0000:00:19.0 failed to suspend async: error -2 [ 430.955581] PM: Some devices failed to suspend, or early wake event detected [ 430.957709] ACPI : EC: event unblocked lead to complete failure: [ 432.585002] ------------[ cut here ]------------ [ 432.585013] WARNING: CPU: 3 PID: 8372 at kernel/irq/manage.c:1478 __free_irq+0x9f/0x280 [ 432.585015] Trying to free already-free IRQ 20 [ 432.585016] Modules linked in: cdc_ncm usbnet x86_pkg_temp_thermal intel_powerclamp coretemp mii crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec_hdmi snd_hda_codec_realtek snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hwdep lpc_ich snd_hda_core snd_pcm mei_me mei sdhci_pci sdhci i915 mmc_core e1000e ptp pps_core prime_numbers [ 432.585042] CPU: 3 PID: 8372 Comm: kworker/u16:40 Tainted: G U 4.10.0-rc8-CI-Patchwork_3870+ #1 [ 432.585044] Hardware name: LENOVO 2356GCG/2356GCG, BIOS G7ET31WW (1.13 ) 07/02/2012 [ 432.585050] Workqueue: events_unbound async_run_entry_fn [ 432.585051] Call Trace: [ 432.585058] dump_stack+0x67/0x92 [ 432.585062] __warn+0xc6/0xe0 [ 432.585065] warn_slowpath_fmt+0x4a/0x50 [ 432.585070] ? _raw_spin_lock_irqsave+0x49/0x60 [ 432.585072] __free_irq+0x9f/0x280 [ 432.585075] free_irq+0x34/0x80 [ 432.585089] e1000_free_irq+0x65/0x70 [e1000e] [ 432.585098] e1000e_pm_freeze+0x7a/0xb0 [e1000e] [ 432.585106] e1000e_pm_suspend+0x21/0x30 [e1000e] [ 432.585113] pci_pm_suspend+0x71/0x140 [ 432.585118] dpm_run_callback+0x6f/0x330 [ 432.585122] ? pci_pm_freeze+0xe0/0xe0 [ 432.585125] __device_suspend+0xea/0x330 [ 432.585128] async_suspend+0x1a/0x90 [ 432.585132] async_run_entry_fn+0x34/0x160 [ 432.585137] process_one_work+0x1f4/0x6d0 [ 432.585140] ? process_one_work+0x16e/0x6d0 [ 432.585143] worker_thread+0x49/0x4a0 [ 432.585145] kthread+0x107/0x140 [ 432.585148] ? process_one_work+0x6d0/0x6d0 [ 432.585150] ? kthread_create_on_node+0x40/0x40 [ 432.585154] ret_from_fork+0x2e/0x40 [ 432.585156] ---[ end trace 6712df7f8c4b9124 ]--- The unwind failures stems from commit 2800209994f8 ("e1000e: Refactor PM flows"), but it may be a later patch that introduced the non-recoverable behaviour. Fixes: 2800209994f8 ("e1000e: Refactor PM flows") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=99847 Signed-off-by: Chris Wilson Signed-off-by: Jani Nikula Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/intel/e1000e/netdev.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 64a0c61435c7..825ec8f710e7 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -6651,12 +6651,17 @@ static int e1000e_pm_thaw(struct device *dev) static int e1000e_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + int rc; e1000e_flush_lpic(pdev); e1000e_pm_freeze(dev); - return __e1000_shutdown(pdev, false); + rc = __e1000_shutdown(pdev, false); + if (rc) + e1000e_pm_thaw(dev); + + return rc; } static int e1000e_pm_resume(struct device *dev) -- GitLab From 50fe37e83e14a6848aaccf5ad707bf4de070d75d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 30 May 2017 11:45:12 +0200 Subject: [PATCH 1203/1834] perf/core: Correct event creation with PERF_FORMAT_GROUP [ Upstream commit ba5213ae6b88fb170c4771fef6553f759c7d8cdd ] Andi was asking about PERF_FORMAT_GROUP vs inherited events, which led to the discovery of a bug from commit: 3dab77fb1bf8 ("perf: Rework/fix the whole read vs group stuff") - PERF_SAMPLE_GROUP = 1U << 4, + PERF_SAMPLE_READ = 1U << 4, - if (attr->inherit && (attr->sample_type & PERF_SAMPLE_GROUP)) + if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) is a clear fail :/ While this changes user visible behaviour; it was previously possible to create an inherited event with PERF_SAMPLE_READ; this is deemed acceptible because its results were always incorrect. Reported-by: Andi Kleen Signed-off-by: Peter Zijlstra (Intel) Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stephane Eranian Cc: Thomas Gleixner Cc: Vince Weaver Fixes: 3dab77fb1bf8 ("perf: Rework/fix the whole read vs group stuff") Link: http://lkml.kernel.org/r/20170530094512.dy2nljns2uq7qa3j@hirez.programming.kicks-ass.net Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- kernel/events/core.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index d7914fa6bc09..c4100c38a467 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -5669,9 +5669,6 @@ static void perf_output_read_one(struct perf_output_handle *handle, __output_copy(handle, values, n * sizeof(u64)); } -/* - * XXX PERF_FORMAT_GROUP vs inherited events seems difficult. - */ static void perf_output_read_group(struct perf_output_handle *handle, struct perf_event *event, u64 enabled, u64 running) @@ -5716,6 +5713,13 @@ static void perf_output_read_group(struct perf_output_handle *handle, #define PERF_FORMAT_TOTAL_TIMES (PERF_FORMAT_TOTAL_TIME_ENABLED|\ PERF_FORMAT_TOTAL_TIME_RUNNING) +/* + * XXX PERF_SAMPLE_READ vs inherited events seems difficult. + * + * The problem is that its both hard and excessively expensive to iterate the + * child list, not to mention that its impossible to IPI the children running + * on another CPU, from interrupt/NMI context. + */ static void perf_output_read(struct perf_output_handle *handle, struct perf_event *event) { @@ -9259,9 +9263,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, local64_set(&hwc->period_left, hwc->sample_period); /* - * we currently do not support PERF_FORMAT_GROUP on inherited events + * We currently do not support PERF_SAMPLE_READ on inherited events. + * See perf_output_read(). */ - if (attr->inherit && (attr->read_format & PERF_FORMAT_GROUP)) + if (attr->inherit && (attr->sample_type & PERF_SAMPLE_READ)) goto err_ns; if (!has_branch_stack(event)) -- GitLab From 0559ea3414d146426aa7e5a95584eee50b1cf967 Mon Sep 17 00:00:00 2001 From: Daniel Bristot de Oliveira Date: Mon, 29 May 2017 16:24:03 +0200 Subject: [PATCH 1204/1834] sched/deadline: Use the revised wakeup rule for suspending constrained dl tasks [ Upstream commit 3effcb4247e74a51f5d8b775a1ee4abf87cc089a ] We have been facing some problems with self-suspending constrained deadline tasks. The main reason is that the original CBS was not designed for such sort of tasks. One problem reported by Xunlei Pang takes place when a task suspends, and then is awakened before the deadline, but so close to the deadline that its remaining runtime can cause the task to have an absolute density higher than allowed. In such situation, the original CBS assumes that the task is facing an early activation, and so it replenishes the task and set another deadline, one deadline in the future. This rule works fine for implicit deadline tasks. Moreover, it allows the system to adapt the period of a task in which the external event source suffered from a clock drift. However, this opens the window for bandwidth leakage for constrained deadline tasks. For instance, a task with the following parameters: runtime = 5 ms deadline = 7 ms [density] = 5 / 7 = 0.71 period = 1000 ms If the task runs for 1 ms, and then suspends for another 1ms, it will be awakened with the following parameters: remaining runtime = 4 laxity = 5 presenting a absolute density of 4 / 5 = 0.80. In this case, the original CBS would assume the task had an early wakeup. Then, CBS will reset the runtime, and the absolute deadline will be postponed by one relative deadline, allowing the task to run. The problem is that, if the task runs this pattern forever, it will keep receiving bandwidth, being able to run 1ms every 2ms. Following this behavior, the task would be able to run 500 ms in 1 sec. Thus running more than the 5 ms / 1 sec the admission control allowed it to run. Trying to address the self-suspending case, Luca Abeni, Giuseppe Lipari, and Juri Lelli [1] revisited the CBS in order to deal with self-suspending tasks. In the new approach, rather than replenishing/postponing the absolute deadline, the revised wakeup rule adjusts the remaining runtime, reducing it to fit into the allowed density. A revised version of the idea is: At a given time t, the maximum absolute density of a task cannot be higher than its relative density, that is: runtime / (deadline - t) <= dl_runtime / dl_deadline Knowing the laxity of a task (deadline - t), it is possible to move it to the other side of the equality, thus enabling to define max remaining runtime a task can use within the absolute deadline, without over-running the allowed density: runtime = (dl_runtime / dl_deadline) * (deadline - t) For instance, in our previous example, the task could still run: runtime = ( 5 / 7 ) * 5 runtime = 3.57 ms Without causing damage for other deadline tasks. It is note worthy that the laxity cannot be negative because that would cause a negative runtime. Thus, this patch depends on the patch: df8eac8cafce ("sched/deadline: Throttle a constrained deadline task activated after the deadline") Which throttles a constrained deadline task activated after the deadline. Finally, it is also possible to use the revised wakeup rule for all other tasks, but that would require some more discussions about pros and cons. Reported-by: Xunlei Pang Signed-off-by: Daniel Bristot de Oliveira [peterz: replaced dl_is_constrained with dl_is_implicit] Signed-off-by: Peter Zijlstra (Intel) Cc: Juri Lelli Cc: Linus Torvalds Cc: Luca Abeni Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Romulo Silva de Oliveira Cc: Steven Rostedt Cc: Thomas Gleixner Cc: Tommaso Cucinotta Link: http://lkml.kernel.org/r/5c800ab3a74a168a84ee5f3f84d12a02e11383be.1495803804.git.bristot@redhat.com Signed-off-by: Ingo Molnar Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/linux/sched.h | 1 + kernel/sched/core.c | 2 + kernel/sched/deadline.c | 98 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index a4d0afc009a7..c549c8c9245c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1412,6 +1412,7 @@ struct sched_dl_entity { u64 dl_deadline; /* relative deadline of each instance */ u64 dl_period; /* separation of two instances (period) */ u64 dl_bw; /* dl_runtime / dl_deadline */ + u64 dl_density; /* dl_runtime / dl_deadline */ /* * Actual scheduling parameters. Initialized with the values above, diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 291ea6fa7ee6..917be221438b 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2184,6 +2184,7 @@ void __dl_clear_params(struct task_struct *p) dl_se->dl_period = 0; dl_se->flags = 0; dl_se->dl_bw = 0; + dl_se->dl_density = 0; dl_se->dl_throttled = 0; dl_se->dl_yielded = 0; @@ -3912,6 +3913,7 @@ __setparam_dl(struct task_struct *p, const struct sched_attr *attr) dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline; dl_se->flags = attr->sched_flags; dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime); + dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime); /* * Changing the parameters of a task is 'tricky' and we're not doing diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 3042881169b4..3042927c8b8a 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -484,13 +484,84 @@ static bool dl_entity_overflow(struct sched_dl_entity *dl_se, } /* - * When a -deadline entity is queued back on the runqueue, its runtime and - * deadline might need updating. + * Revised wakeup rule [1]: For self-suspending tasks, rather then + * re-initializing task's runtime and deadline, the revised wakeup + * rule adjusts the task's runtime to avoid the task to overrun its + * density. * - * The policy here is that we update the deadline of the entity only if: - * - the current deadline is in the past, - * - using the remaining runtime with the current deadline would make - * the entity exceed its bandwidth. + * Reasoning: a task may overrun the density if: + * runtime / (deadline - t) > dl_runtime / dl_deadline + * + * Therefore, runtime can be adjusted to: + * runtime = (dl_runtime / dl_deadline) * (deadline - t) + * + * In such way that runtime will be equal to the maximum density + * the task can use without breaking any rule. + * + * [1] Luca Abeni, Giuseppe Lipari, and Juri Lelli. 2015. Constant + * bandwidth server revisited. SIGBED Rev. 11, 4 (January 2015), 19-24. + */ +static void +update_dl_revised_wakeup(struct sched_dl_entity *dl_se, struct rq *rq) +{ + u64 laxity = dl_se->deadline - rq_clock(rq); + + /* + * If the task has deadline < period, and the deadline is in the past, + * it should already be throttled before this check. + * + * See update_dl_entity() comments for further details. + */ + WARN_ON(dl_time_before(dl_se->deadline, rq_clock(rq))); + + dl_se->runtime = (dl_se->dl_density * laxity) >> 20; +} + +/* + * Regarding the deadline, a task with implicit deadline has a relative + * deadline == relative period. A task with constrained deadline has a + * relative deadline <= relative period. + * + * We support constrained deadline tasks. However, there are some restrictions + * applied only for tasks which do not have an implicit deadline. See + * update_dl_entity() to know more about such restrictions. + * + * The dl_is_implicit() returns true if the task has an implicit deadline. + */ +static inline bool dl_is_implicit(struct sched_dl_entity *dl_se) +{ + return dl_se->dl_deadline == dl_se->dl_period; +} + +/* + * When a deadline entity is placed in the runqueue, its runtime and deadline + * might need to be updated. This is done by a CBS wake up rule. There are two + * different rules: 1) the original CBS; and 2) the Revisited CBS. + * + * When the task is starting a new period, the Original CBS is used. In this + * case, the runtime is replenished and a new absolute deadline is set. + * + * When a task is queued before the begin of the next period, using the + * remaining runtime and deadline could make the entity to overflow, see + * dl_entity_overflow() to find more about runtime overflow. When such case + * is detected, the runtime and deadline need to be updated. + * + * If the task has an implicit deadline, i.e., deadline == period, the Original + * CBS is applied. the runtime is replenished and a new absolute deadline is + * set, as in the previous cases. + * + * However, the Original CBS does not work properly for tasks with + * deadline < period, which are said to have a constrained deadline. By + * applying the Original CBS, a constrained deadline task would be able to run + * runtime/deadline in a period. With deadline < period, the task would + * overrun the runtime/period allowed bandwidth, breaking the admission test. + * + * In order to prevent this misbehave, the Revisited CBS is used for + * constrained deadline tasks when a runtime overflow is detected. In the + * Revisited CBS, rather than replenishing & setting a new absolute deadline, + * the remaining runtime of the task is reduced to avoid runtime overflow. + * Please refer to the comments update_dl_revised_wakeup() function to find + * more about the Revised CBS rule. */ static void update_dl_entity(struct sched_dl_entity *dl_se, struct sched_dl_entity *pi_se) @@ -500,6 +571,14 @@ static void update_dl_entity(struct sched_dl_entity *dl_se, if (dl_time_before(dl_se->deadline, rq_clock(rq)) || dl_entity_overflow(dl_se, pi_se, rq_clock(rq))) { + + if (unlikely(!dl_is_implicit(dl_se) && + !dl_time_before(dl_se->deadline, rq_clock(rq)) && + !dl_se->dl_boosted)){ + update_dl_revised_wakeup(dl_se, rq); + return; + } + dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline; dl_se->runtime = pi_se->dl_runtime; } @@ -961,11 +1040,6 @@ static void dequeue_dl_entity(struct sched_dl_entity *dl_se) __dequeue_dl_entity(dl_se); } -static inline bool dl_is_constrained(struct sched_dl_entity *dl_se) -{ - return dl_se->dl_deadline < dl_se->dl_period; -} - static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) { struct task_struct *pi_task = rt_mutex_get_top_task(p); @@ -997,7 +1071,7 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) * If that is the case, the task will be throttled and * the replenishment timer will be set to the next period. */ - if (!p->dl.dl_throttled && dl_is_constrained(&p->dl)) + if (!p->dl.dl_throttled && !dl_is_implicit(&p->dl)) dl_check_constrained_dl(&p->dl); /* -- GitLab From 222c8b45a69c8be582d0a5b282dcc28387b6c72e Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Tue, 11 Apr 2017 09:00:34 +0200 Subject: [PATCH 1205/1834] MIPS: mm: fixed mappings: correct initialisation [ Upstream commit 71eb989ab5a110df8bcbb9609bacde73feacbedd ] fixrange_init operates at PMD-granularity and expects the addresses to be PMD-size aligned, but currently that might not be the case for PKMAP_BASE unless it is defined properly, so ensure a correct alignment is used before passing the address to fixrange_init. fixed mappings: only align the start address that is passed to fixrange_init rather than the value before adding the size, as we may end up with uninitialised upper part of the range. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15948/ Signed-off-by: Ralf Baechle Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/mm/pgtable-32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/mm/pgtable-32.c b/arch/mips/mm/pgtable-32.c index adc6911ba748..b19a3c506b1e 100644 --- a/arch/mips/mm/pgtable-32.c +++ b/arch/mips/mm/pgtable-32.c @@ -51,15 +51,15 @@ void __init pagetable_init(void) /* * Fixed mappings: */ - vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; - fixrange_init(vaddr, vaddr + FIXADDR_SIZE, pgd_base); + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1); + fixrange_init(vaddr & PMD_MASK, vaddr + FIXADDR_SIZE, pgd_base); #ifdef CONFIG_HIGHMEM /* * Permanent kmaps: */ vaddr = PKMAP_BASE; - fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); + fixrange_init(vaddr & PMD_MASK, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); pgd = swapper_pg_dir + __pgd_offset(vaddr); pud = pud_offset(pgd, vaddr); -- GitLab From b79e6d2da9e6ee7068049c3514a4ca9a73d8db80 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Tue, 11 Apr 2017 09:00:36 +0200 Subject: [PATCH 1206/1834] MIPS: mm: adjust PKMAP location [ Upstream commit c56e7a4c3e77f6fbd9b55c06c14eda65aae58958 ] Space reserved for PKMap should span from PKMAP_BASE to FIXADDR_START. For large page sizes this is not the case as eg. for 64k pages the range currently defined is from 0xfe000000 to 0x102000000(!!) which obviously isn't right. Remove the hardcoded location and set the BASE address as an offset from FIXADDR_START. Since all PKMAP ptes have to be placed in a contiguous memory, ensure that this is the case by placing them all in a single page. This is achieved by aligning the end address to pkmap pages count pages. Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15950/ Signed-off-by: Ralf Baechle Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/pgtable-32.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/pgtable-32.h b/arch/mips/include/asm/pgtable-32.h index d21f3da7bdb6..c0be540e83cb 100644 --- a/arch/mips/include/asm/pgtable-32.h +++ b/arch/mips/include/asm/pgtable-32.h @@ -18,6 +18,10 @@ #include +#ifdef CONFIG_HIGHMEM +#include +#endif + extern int temp_tlb_entry; /* @@ -61,7 +65,8 @@ extern int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, #define VMALLOC_START MAP_BASE -#define PKMAP_BASE (0xfe000000UL) +#define PKMAP_END ((FIXADDR_START) & ~((LAST_PKMAP << PAGE_SHIFT)-1)) +#define PKMAP_BASE (PKMAP_END - PAGE_SIZE * LAST_PKMAP) #ifdef CONFIG_HIGHMEM # define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) -- GitLab From 353a7186f1ec39881d6b20d4b150f283393e4ce6 Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Thu, 8 Jun 2017 15:20:32 +0200 Subject: [PATCH 1207/1834] MIPS: kprobes: flush_insn_slot should flush only if probe initialised [ Upstream commit 698b851073ddf5a894910d63ca04605e0473414e ] When ftrace is used with kprobes, it is possible for a kprobe to contain an invalid location (ie. only initialised to 0 and not to a specific location in the code). Trying to perform a cache flush on such location leads to a crash r4k_flush_icache_range(). Fixes: c1bf207d6ee1 ("MIPS: kprobe: Add support.") Signed-off-by: Marcin Nowakowski Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/16296/ Signed-off-by: Ralf Baechle Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/kprobes.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/asm/kprobes.h b/arch/mips/include/asm/kprobes.h index daba1f9a4f79..174aedce3167 100644 --- a/arch/mips/include/asm/kprobes.h +++ b/arch/mips/include/asm/kprobes.h @@ -40,7 +40,8 @@ typedef union mips_instruction kprobe_opcode_t; #define flush_insn_slot(p) \ do { \ - flush_icache_range((unsigned long)p->addr, \ + if (p->addr) \ + flush_icache_range((unsigned long)p->addr, \ (unsigned long)p->addr + \ (MAX_INSN_SIZE * sizeof(kprobe_opcode_t))); \ } while (0) -- GitLab From 90963c61ff0ae480090895725eabb4c60ed358bd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 1 Jun 2017 12:27:00 +0200 Subject: [PATCH 1208/1834] ARM: dts: armadillo800eva: Split LCD mux and gpio [ Upstream commit 13132b3f44d3600983aceb7e9920b8ebb55a7cf8 ] Configuration of the lcd0 pinmux group and GPIO hog for the external GPIO mux are done using a single device node, causing the "output-high" property to be applied to both. This will fail for the pinmux group, but doesn't cause any harm, as the failure is ignored silently. However, after "pinctrl: sh-pfc: propagate errors on group config", the failure will become fatal, leading to a broken display: sh-pfc e6050000.pin-controller: pin_config_group_set op failed for group 102 sh-pfc e6050000.pin-controller: Error applying setting, reverse things back sh-pfc e6050000.pin-controller: failed to select default state Move the GPIO hog to its own node to fix this. Fixes: ffd2f9a5afb730b9 ("ARM: shmobile: armadillo800eva dts: Add pinctrl and gpio-hog for lcdc0") Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Simon Horman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/r8a7740-armadillo800eva.dts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts index 7885075428bb..1788e186a512 100644 --- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts +++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts @@ -266,7 +266,9 @@ lcd0_pins: lcd0 { groups = "lcd0_data24_0", "lcd0_lclk_1", "lcd0_sync"; function = "lcd0"; + }; + lcd0_mux { /* DBGMD/LCDC0/FSIA MUX */ gpio-hog; gpios = <176 0>; -- GitLab From 7f736f0e9ba38705eaf8e36a622a4b47218c14ae Mon Sep 17 00:00:00 2001 From: James Wang Date: Thu, 8 Jun 2017 14:52:51 +0800 Subject: [PATCH 1209/1834] Fix loop device flush before configure v3 [ Upstream commit 6460495709aeb651896bc8e5c134b2e4ca7d34a8 ] While installing SLES-12 (based on v4.4), I found that the installer will stall for 60+ seconds during LVM disk scan. The root cause was determined to be the removal of a bound device check in loop_flush() by commit b5dd2f6047ca ("block: loop: improve performance via blk-mq"). Restoring this check, examining ->lo_state as set by loop_set_fd() eliminates the bad behavior. Test method: modprobe loop max_loop=64 dd if=/dev/zero of=disk bs=512 count=200K for((i=0;i<4;i++))do losetup -f disk; done mkfs.ext4 -F /dev/loop0 for((i=0;i<4;i++))do mkdir t$i; mount /dev/loop$i t$i;done for f in `ls /dev/loop[0-9]*|sort`; do \ echo $f; dd if=$f of=/dev/null bs=512 count=1; \ done Test output: stock patched /dev/loop0 18.1217e-05 8.3842e-05 /dev/loop1 6.1114e-05 0.000147979 /dev/loop10 0.414701 0.000116564 /dev/loop11 0.7474 6.7942e-05 /dev/loop12 0.747986 8.9082e-05 /dev/loop13 0.746532 7.4799e-05 /dev/loop14 0.480041 9.3926e-05 /dev/loop15 1.26453 7.2522e-05 Note that from loop10 onward, the device is not mounted, yet the stock kernel consumes several orders of magnitude more wall time than it does for a mounted device. (Thanks for Mike Galbraith , give a changelog review.) Reviewed-by: Hannes Reinecke Reviewed-by: Ming Lei Signed-off-by: James Wang Fixes: b5dd2f6047ca ("block: loop: improve performance via blk-mq") Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/block/loop.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 68bfcef24701..dc318b9100c2 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -612,6 +612,9 @@ static int loop_switch(struct loop_device *lo, struct file *file) */ static int loop_flush(struct loop_device *lo) { + /* loop not yet configured, no running thread, nothing to flush */ + if (lo->lo_state != Lo_bound) + return 0; return loop_switch(lo, NULL); } -- GitLab From b3ec3723a42fcaf998e128fd3768ce815e1ff398 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Wed, 7 Jun 2017 15:51:15 +0200 Subject: [PATCH 1210/1834] net: emac: fix reset timeout with AR8035 phy [ Upstream commit 19d90ece81da802207a9b91ce95a29fbdc40626e ] This patch fixes a problem where the AR8035 PHY can't be detected on an Cisco Meraki MR24, if the ethernet cable is not connected on boot. Russell Senior provided steps to reproduce the issue: |Disconnect ethernet cable, apply power, wait until device has booted, |plug in ethernet, check for interfaces, no eth0 is listed. | |This appears to be a problem during probing of the AR8035 Phy chip. |When ethernet has no link, the phy detection fails, and eth0 is not |created. Plugging ethernet later has no effect, because there is no |interface as far as the kernel is concerned. The relevant part of |the boot log looks like this: |this is the failing case: | |[ 0.876611] /plb/opb/emac-rgmii@ef601500: input 0 in RGMII mode |[ 0.882532] /plb/opb/ethernet@ef600c00: reset timeout |[ 0.888546] /plb/opb/ethernet@ef600c00: can't find PHY! |and the succeeding case: | |[ 0.876672] /plb/opb/emac-rgmii@ef601500: input 0 in RGMII mode |[ 0.883952] eth0: EMAC-0 /plb/opb/ethernet@ef600c00, MAC 00:01:.. |[ 0.890822] eth0: found Atheros 8035 Gigabit Ethernet PHY (0x01) Based on the comment and the commit message of commit 23fbb5a87c56 ("emac: Fix EMAC soft reset on 460EX/GT"). This is because the AR8035 PHY doesn't provide the TX Clock, if the ethernet cable is not attached. This causes the reset to timeout and the PHY detection code in emac_init_phy() is unable to detect the AR8035 PHY. As a result, the emac driver bails out early and the user left with no ethernet. In order to stay compatible with existing configurations, the driver tries the current reset approach at first. Only if the first attempt timed out, it does perform one more retry with the clock temporarily switched to the internal source for just the duration of the reset. LEDE-Bug: #687 Cc: Chris Blake Reported-by: Russell Senior Fixes: 23fbb5a87c56e98 ("emac: Fix EMAC soft reset on 460EX/GT") Signed-off-by: Christian Lamparter Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/ibm/emac/core.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 8f139197f1aa..5977b695d0fa 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -342,6 +342,7 @@ static int emac_reset(struct emac_instance *dev) { struct emac_regs __iomem *p = dev->emacp; int n = 20; + bool __maybe_unused try_internal_clock = false; DBG(dev, "reset" NL); @@ -354,6 +355,7 @@ static int emac_reset(struct emac_instance *dev) } #ifdef CONFIG_PPC_DCR_NATIVE +do_retry: /* * PPC460EX/GT Embedded Processor Advanced User's Manual * section 28.10.1 Mode Register 0 (EMACx_MR0) states: @@ -361,10 +363,19 @@ static int emac_reset(struct emac_instance *dev) * of the EMAC. If none is present, select the internal clock * (SDR0_ETH_CFG[EMACx_PHY_CLK] = 1). * After a soft reset, select the external clock. + * + * The AR8035-A PHY Meraki MR24 does not provide a TX Clk if the + * ethernet cable is not attached. This causes the reset to timeout + * and the PHY detection code in emac_init_phy() is unable to + * communicate and detect the AR8035-A PHY. As a result, the emac + * driver bails out early and the user has no ethernet. + * In order to stay compatible with existing configurations, the + * driver will temporarily switch to the internal clock, after + * the first reset fails. */ if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) { - if (dev->phy_address == 0xffffffff && - dev->phy_map == 0xffffffff) { + if (try_internal_clock || (dev->phy_address == 0xffffffff && + dev->phy_map == 0xffffffff)) { /* No PHY: select internal loop clock before reset */ dcri_clrset(SDR0, SDR0_ETH_CFG, 0, SDR0_ETH_CFG_ECS << dev->cell_index); @@ -382,8 +393,15 @@ static int emac_reset(struct emac_instance *dev) #ifdef CONFIG_PPC_DCR_NATIVE if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) { - if (dev->phy_address == 0xffffffff && - dev->phy_map == 0xffffffff) { + if (!n && !try_internal_clock) { + /* first attempt has timed out. */ + n = 20; + try_internal_clock = true; + goto do_retry; + } + + if (try_internal_clock || (dev->phy_address == 0xffffffff && + dev->phy_map == 0xffffffff)) { /* No PHY: restore external clock source after reset */ dcri_clrset(SDR0, SDR0_ETH_CFG, SDR0_ETH_CFG_ECS << dev->cell_index, 0); -- GitLab From e2d054998b151e85b6305aa72264f67097bd78e9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 8 Jun 2017 16:31:05 +0900 Subject: [PATCH 1211/1834] perf tools: Decompress kernel module when reading DSO data [ Upstream commit 1d6b3c9ba756a5134fd7ad1959acac776d17404b ] Currently perf decompresses kernel modules when loading the symbol table but it missed to do it when reading raw data. Signed-off-by: Namhyung Kim Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Peter Zijlstra Cc: Wang Nan Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170608073109.30699-6-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/dso.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d2c6cdd9d42b..4bc58822416c 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -366,7 +366,23 @@ static int __open_dso(struct dso *dso, struct machine *machine) if (!is_regular_file(name)) return -EINVAL; + if (dso__needs_decompress(dso)) { + char newpath[KMOD_DECOMP_LEN]; + size_t len = sizeof(newpath); + + if (dso__decompress_kmodule_path(dso, name, newpath, len) < 0) { + free(name); + return -dso->load_errno; + } + + strcpy(name, newpath); + } + fd = do_open(name); + + if (dso__needs_decompress(dso)) + unlink(name); + free(name); return fd; } -- GitLab From 7525a238be8f46617cdda29d1be5b85ffe3b042d Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 8 Jun 2017 16:31:07 +0900 Subject: [PATCH 1212/1834] perf tests: Decompress kernel module before objdump [ Upstream commit 94df1040b1e6aacd8dec0ba3c61d7e77cd695f26 ] If a kernel modules is compressed, it should be decompressed before running objdump to parse binary data correctly. This fixes a failure of object code reading test for me. Signed-off-by: Namhyung Kim Acked-by: Adrian Hunter Acked-by: Jiri Olsa Cc: David Ahern Cc: Peter Zijlstra Cc: Wang Nan Cc: kernel-team@lge.com Link: http://lkml.kernel.org/r/20170608073109.30699-8-namhyung@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/tests/code-reading.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index ff5bc6363a79..150334064071 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -224,6 +224,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, unsigned char buf2[BUFSZ]; size_t ret_len; u64 objdump_addr; + const char *objdump_name; + char decomp_name[KMOD_DECOMP_LEN]; int ret; pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); @@ -284,9 +286,25 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, state->done[state->done_cnt++] = al.map->start; } + objdump_name = al.map->dso->long_name; + if (dso__needs_decompress(al.map->dso)) { + if (dso__decompress_kmodule_path(al.map->dso, objdump_name, + decomp_name, + sizeof(decomp_name)) < 0) { + pr_debug("decompression failed\n"); + return -1; + } + + objdump_name = decomp_name; + } + /* Read the object code using objdump */ objdump_addr = map__rip_2objdump(al.map, al.addr); - ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len); + ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); + + if (dso__needs_decompress(al.map->dso)) + unlink(objdump_name); + if (ret > 0) { /* * The kernel maps are inaccurate - assume objdump is right in -- GitLab From fcfb53c3a8c61d9e2866edf4cdc45715c8b1dfbd Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Thu, 8 Jun 2017 11:35:03 -0400 Subject: [PATCH 1213/1834] skbuff: only inherit relevant tx_flags [ Upstream commit fff88030b3ff930ca7a3d74acfee0472f33887ea ] When inheriting tx_flags from one skbuff to another, always apply a mask to avoid overwriting unrelated other bits in the field. The two SKBTX_SHARED_FRAG cases clears all other bits. In practice, tx_flags are zero at this point now. But this is fragile. Timestamp flags are set, for instance, if in tcp_gso_segment, after this clear in skb_segment. The SKBTX_ANY_TSTAMP mask in __skb_tstamp_tx ensures that new skbs do not accidentally inherit flags such as SKBTX_SHARED_FRAG. Signed-off-by: Willem de Bruijn Acked-by: Soheil Hassas Yeganeh Acked-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/core/skbuff.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index c1c74abddd62..fb422dfec848 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -2615,7 +2615,8 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len) { int pos = skb_headlen(skb); - skb_shinfo(skb1)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG; + skb_shinfo(skb1)->tx_flags |= skb_shinfo(skb)->tx_flags & + SKBTX_SHARED_FRAG; if (len < pos) /* Split line is inside header. */ skb_split_inside_header(skb, skb1, len, pos); else /* Second chunk has no header, nothing to copy. */ @@ -3228,8 +3229,8 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, skb_copy_from_linear_data_offset(head_skb, offset, skb_put(nskb, hsize), hsize); - skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags & - SKBTX_SHARED_FRAG; + skb_shinfo(nskb)->tx_flags |= skb_shinfo(head_skb)->tx_flags & + SKBTX_SHARED_FRAG; while (pos < offset + len) { if (i >= nfrags) { @@ -3881,7 +3882,8 @@ void __skb_tstamp_tx(struct sk_buff *orig_skb, return; if (tsonly) { - skb_shinfo(skb)->tx_flags = skb_shinfo(orig_skb)->tx_flags; + skb_shinfo(skb)->tx_flags |= skb_shinfo(orig_skb)->tx_flags & + SKBTX_ANY_TSTAMP; skb_shinfo(skb)->tskey = skb_shinfo(orig_skb)->tskey; } -- GitLab From 45be9b7771600c650acfdcc8501999df8751f695 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 8 Jun 2017 10:53:10 +0200 Subject: [PATCH 1214/1834] xen: avoid type warning in xchg_xen_ulong [ Upstream commit 9cc91f212111cdcbefa02dcdb7dd443f224bf52c ] The improved type-checking version of container_of() triggers a warning for xchg_xen_ulong, pointing out that 'xen_ulong_t' is unsigned, but atomic64_t contains a signed value: drivers/xen/events/events_2l.c: In function 'evtchn_2l_handle_events': drivers/xen/events/events_2l.c:187:1020: error: call to '__compiletime_assert_187' declared with attribute error: pointer type mismatch in container_of() This adds a cast to work around the warning. Cc: Ian Abbott Fixes: 85323a991d40 ("xen: arm: mandate EABI and use generic atomic operations.") Fixes: daa2ac80834d ("kernel.h: handle pointers to arrays better in container_of()") Signed-off-by: Arnd Bergmann Signed-off-by: Stefano Stabellini Reviewed-by: Stefano Stabellini Acked-by: Ian Abbott Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/xen/events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/include/asm/xen/events.h b/arch/arm/include/asm/xen/events.h index 71e473d05fcc..620dc75362e5 100644 --- a/arch/arm/include/asm/xen/events.h +++ b/arch/arm/include/asm/xen/events.h @@ -16,7 +16,7 @@ static inline int xen_irqs_disabled(struct pt_regs *regs) return raw_irqs_disabled_flags(regs->ARM_cpsr); } -#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((ptr), \ +#define xchg_xen_ulong(ptr, val) atomic64_xchg(container_of((long long*)(ptr),\ atomic64_t, \ counter), (val)) -- GitLab From 4b8fd8db48be40261cb1eafb8a9605a2e4d37091 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 8 Jun 2017 14:47:49 +0100 Subject: [PATCH 1215/1834] X.509: Fix error code in x509_cert_parse() [ Upstream commit 4e880168e9ffb1cdbdb72b3b48ab0324b30c2d62 ] We forgot to set the error code on this path so it could result in returning NULL which leads to a NULL dereference. Fixes: db6c43bd2132 ("crypto: KEYS: convert public key and digsig asym to the akcipher api") Signed-off-by: Dan Carpenter Signed-off-by: David Howells Signed-off-by: James Morris Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- crypto/asymmetric_keys/x509_cert_parser.c | 1 + 1 file changed, 1 insertion(+) diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index 029f7051f2be..ce2df8c9c583 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c @@ -102,6 +102,7 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) } } + ret = -ENOMEM; cert->pub->key = kmemdup(ctx->key, ctx->key_size, GFP_KERNEL); if (!cert->pub->key) goto error_decode; -- GitLab From 577438f5774154305c80a5f5a4a66cd7c4a2ca39 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Wed, 7 Jun 2017 07:44:20 +0200 Subject: [PATCH 1216/1834] pinctrl: meson-gxbb: remove non-existing pin GPIOX_22 [ Upstream commit 4c8127cb523982e0a474ad80b14b665dc2f37b3b ] After commit 34e61801a3b9 "pinctrl: meson-gxbb: Add missing GPIODV_18 pin entry" I started to get the following warning: "meson-pinctrl c8834000.periphs:pinctrl@4b0: names 119 do not match number of GPIOs 120" It turned out that not the mentioned commit has a problem, it just revealed another problem which had existed before. There is no PIN GPIOX_22 on Meson GXBB. Fixes: 468c234f9ed7 ("pinctrl: amlogic: Add support for Amlogic Meson GXBB SoC") Signed-off-by: Heiner Kallweit Reviewed-by: Neil Armstrong Signed-off-by: Linus Walleij Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/pinctrl/meson/pinctrl-meson-gxbb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c index 7511723c6b05..257c1c2e5888 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c @@ -138,7 +138,6 @@ static const struct pinctrl_pin_desc meson_gxbb_periphs_pins[] = { MESON_PIN(GPIOX_19, EE_OFF), MESON_PIN(GPIOX_20, EE_OFF), MESON_PIN(GPIOX_21, EE_OFF), - MESON_PIN(GPIOX_22, EE_OFF), MESON_PIN(GPIOCLK_0, EE_OFF), MESON_PIN(GPIOCLK_1, EE_OFF), -- GitLab From 41830b8672a801adb74486d37fee4c35c9ca42b2 Mon Sep 17 00:00:00 2001 From: Suzuki K Poulose Date: Mon, 5 Jun 2017 14:15:03 -0600 Subject: [PATCH 1217/1834] coresight: Fix reference count for software sources [ Upstream commit 022aa1a81b778789ee7cf3124595854276a0330d ] For software sources (i.e STM), there could be multiple agents generating the trace data, unlike the ETMs. So we need to properly do the accounting for the active number of users to disable the device when the last user goes away. Right now, the reference counting is broken for sources as we skip the actions when we detect that the source is enabled. This patch fixes the problem by adding the refcounting for software sources, even when they are enabled. Cc: Mathieu Poirier Reported-by: Robert Walker Signed-off-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index 7bf00a0beb6f..4383324ec01c 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -498,6 +498,9 @@ int coresight_enable(struct coresight_device *csdev) { int cpu, ret = 0; struct list_head *path; + enum coresight_dev_subtype_source subtype; + + subtype = csdev->subtype.source_subtype; mutex_lock(&coresight_mutex); @@ -505,8 +508,16 @@ int coresight_enable(struct coresight_device *csdev) if (ret) goto out; - if (csdev->enable) + if (csdev->enable) { + /* + * There could be multiple applications driving the software + * source. So keep the refcount for each such user when the + * source is already enabled. + */ + if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE) + atomic_inc(csdev->refcnt); goto out; + } path = coresight_build_path(csdev); if (IS_ERR(path)) { @@ -523,7 +534,7 @@ int coresight_enable(struct coresight_device *csdev) if (ret) goto err_source; - switch (csdev->subtype.source_subtype) { + switch (subtype) { case CORESIGHT_DEV_SUBTYPE_SOURCE_PROC: /* * When working from sysFS it is important to keep track -- GitLab From 9606743ca7f8f45b0e589e5ff8dd93a3e49dcdd1 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 5 Jun 2017 14:15:09 -0600 Subject: [PATCH 1218/1834] coresight: tmc: Configure DMA mask appropriately [ Upstream commit a3959c50b02f57df4c4e4f14f632220f1c0b1f79 ] Before making any DMA API calls, the ETR driver should really be setting its masks to ensure that DMA is possible. Especially since it can address more than the 32-bit default mask set by the AMBA bus code. Signed-off-by: Robin Murphy Tested-by: Suzuki K Poulose Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-tmc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index d8517d2a968c..864488793f09 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -362,6 +362,13 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) desc.type = CORESIGHT_DEV_TYPE_SINK; desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER; desc.ops = &tmc_etr_cs_ops; + /* + * ETR configuration uses a 40-bit AXI master in place of + * the embedded SRAM of ETB/ETF. + */ + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40)); + if (ret) + goto out; } else { desc.type = CORESIGHT_DEV_TYPE_LINKSINK; desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO; -- GitLab From 3f7b3c7a792c8d74bcdf6dfca0189c9d2065508f Mon Sep 17 00:00:00 2001 From: Mario Molitor Date: Thu, 8 Jun 2017 22:41:02 +0200 Subject: [PATCH 1219/1834] stmmac: fix ptp header for GMAC3 hw timestamp [ Upstream commit fd6720aefde06eacf17404eed2cad65c6ec103e1 ] According the CYCLON V documention only the bit 16 of snaptypesel should set. (more information see Table 17-20 (cv_5v4.pdf) : Timestamp Snapshot Dependency on Register Bits) Fixes: d2042052a0aa ("stmmac: update the PTP header file") Signed-off-by: Mario Molitor Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 ++++++++++++--- drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 98bbb91336e4..c212d1dd8bfd 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -478,7 +478,10 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) /* PTP v1, UDP, any kind of event packet */ config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; /* take time stamp for all event messages */ - snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + if (priv->plat->has_gmac4) + snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1; + else + snap_type_sel = PTP_TCR_SNAPTYPSEL_1; ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; @@ -510,7 +513,10 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; ptp_v2 = PTP_TCR_TSVER2ENA; /* take time stamp for all event messages */ - snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + if (priv->plat->has_gmac4) + snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1; + else + snap_type_sel = PTP_TCR_SNAPTYPSEL_1; ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; @@ -544,7 +550,10 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; ptp_v2 = PTP_TCR_TSVER2ENA; /* take time stamp for all event messages */ - snap_type_sel = PTP_TCR_SNAPTYPSEL_1; + if (priv->plat->has_gmac4) + snap_type_sel = PTP_GMAC4_TCR_SNAPTYPSEL_1; + else + snap_type_sel = PTP_TCR_SNAPTYPSEL_1; ptp_over_ipv4_udp = PTP_TCR_TSIPV4ENA; ptp_over_ipv6_udp = PTP_TCR_TSIPV6ENA; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h index c06938c47af5..174777cd888e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h @@ -63,7 +63,8 @@ /* Enable Snapshot for Messages Relevant to Master */ #define PTP_TCR_TSMSTRENA BIT(15) /* Select PTP packets for Taking Snapshots */ -#define PTP_TCR_SNAPTYPSEL_1 GENMASK(17, 16) +#define PTP_TCR_SNAPTYPSEL_1 BIT(16) +#define PTP_GMAC4_TCR_SNAPTYPSEL_1 GENMASK(17, 16) /* Enable MAC address for PTP Frame Filtering */ #define PTP_TCR_TSENMACADDR BIT(18) -- GitLab From fb96822d6c4d5c3e252dbf687ad2f7d6d8b0ef8b Mon Sep 17 00:00:00 2001 From: Girish Moodalbail Date: Thu, 8 Jun 2017 17:07:48 -0700 Subject: [PATCH 1220/1834] geneve: add missing rx stats accounting [ Upstream commit fe741e2362f33bbea813bcc3a921de356c6653db ] There are few places on the receive path where packet drops and packet errors were not accounted for. This patch fixes that issue. Signed-off-by: Girish Moodalbail Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/geneve.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 3c1f89ab0110..92ad43e53c72 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -209,6 +209,7 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, struct genevehdr *gnvh = geneve_hdr(skb); struct metadata_dst *tun_dst = NULL; struct pcpu_sw_netstats *stats; + unsigned int len; int err = 0; void *oiph; @@ -222,8 +223,10 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, tun_dst = udp_tun_rx_dst(skb, geneve_get_sk_family(gs), flags, vni_to_tunnel_id(gnvh->vni), gnvh->opt_len * 4); - if (!tun_dst) + if (!tun_dst) { + geneve->dev->stats.rx_dropped++; goto drop; + } /* Update tunnel dst according to Geneve options. */ ip_tunnel_info_opts_set(&tun_dst->u.tun_info, gnvh->options, gnvh->opt_len * 4); @@ -231,8 +234,11 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, /* Drop packets w/ critical options, * since we don't support any... */ - if (gnvh->critical) + if (gnvh->critical) { + geneve->dev->stats.rx_frame_errors++; + geneve->dev->stats.rx_errors++; goto drop; + } } skb_reset_mac_header(skb); @@ -243,8 +249,10 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, skb_dst_set(skb, &tun_dst->dst); /* Ignore packet loops (and multicast echo) */ - if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) + if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) { + geneve->dev->stats.rx_errors++; goto drop; + } oiph = skb_network_header(skb); skb_reset_network_header(skb); @@ -276,13 +284,15 @@ static void geneve_rx(struct geneve_dev *geneve, struct geneve_sock *gs, } } - stats = this_cpu_ptr(geneve->dev->tstats); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); - - gro_cells_receive(&geneve->gro_cells, skb); + len = skb->len; + err = gro_cells_receive(&geneve->gro_cells, skb); + if (likely(err == NET_RX_SUCCESS)) { + stats = this_cpu_ptr(geneve->dev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += len; + u64_stats_update_end(&stats->syncp); + } return; drop: /* Consume bad packet */ @@ -332,7 +342,7 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) struct geneve_sock *gs; int opts_len; - /* Need Geneve and inner Ethernet header to be present */ + /* Need UDP and Geneve header to be present */ if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN))) goto drop; @@ -355,8 +365,10 @@ static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) opts_len = geneveh->opt_len * 4; if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, htons(ETH_P_TEB), - !net_eq(geneve->net, dev_net(geneve->dev)))) + !net_eq(geneve->net, dev_net(geneve->dev)))) { + geneve->dev->stats.rx_dropped++; goto drop; + } geneve_rx(geneve, gs, skb); return 0; -- GitLab From c0fe1e29a59f436c10b9ed05df52ab650a9f3727 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 24 May 2017 10:35:32 +0300 Subject: [PATCH 1221/1834] crypto: omap-sham - buffer handling fixes for hashing later [ Upstream commit 5d78d57ede8f9e7f656c610ed25be7be337e0529 ] Currently, the hash later code only handles the cases when we have either new data coming in with the request or old data in the buffer, but not the combination when we have both. Fix this by changing the ordering of the code a bit and handling both cases properly simultaneously if needed. Also, fix an issue with omap_sham_update that surfaces with this fix, so that the code checks the bufcnt instead of total data amount against buffer length to avoid any buffer overflows. Signed-off-by: Tero Kristo Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/omap-sham.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index d0b16e5e4ee5..c65b49baf0c7 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -873,14 +873,21 @@ static int omap_sham_prepare_request(struct ahash_request *req, bool update) } if (hash_later) { - if (req->nbytes) { - scatterwalk_map_and_copy(rctx->buffer, req->src, - req->nbytes - hash_later, - hash_later, 0); - } else { + int offset = 0; + + if (hash_later > req->nbytes) { memcpy(rctx->buffer, rctx->buffer + xmit_len, - hash_later); + hash_later - req->nbytes); + offset = hash_later - req->nbytes; } + + if (req->nbytes) { + scatterwalk_map_and_copy(rctx->buffer + offset, + req->src, + offset + req->nbytes - + hash_later, hash_later, 0); + } + rctx->bufcnt = hash_later; } else { rctx->bufcnt = 0; @@ -1189,11 +1196,10 @@ static int omap_sham_update(struct ahash_request *req) if (!req->nbytes) return 0; - if (ctx->total + req->nbytes < ctx->buflen) { + if (ctx->bufcnt + req->nbytes <= ctx->buflen) { scatterwalk_map_and_copy(ctx->buffer + ctx->bufcnt, req->src, 0, req->nbytes, 0); ctx->bufcnt += req->nbytes; - ctx->total += req->nbytes; return 0; } -- GitLab From 1fb08363c85da3c3c3c0acb53d7809ca2c72bede Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Wed, 24 May 2017 10:35:33 +0300 Subject: [PATCH 1222/1834] crypto: omap-sham - fix closing of hash with separate finalize call [ Upstream commit 898d86a565925f09de3d0b30cf3b47ec2e409680 ] Currently there is an interesting corner case failure with omap-sham driver, if the finalize call is done separately with no data, but all previous data has already been processed. In this case, it is not possible to close the hash with the hardware without providing any data, so we get incorrect results. Fix this by adjusting the size of data sent to the hardware crypto engine in case the non-final data size falls on the block size boundary, by reducing the amount of data sent by one full block. This makes it sure that we always have some data available for the finalize call and we can close the hash properly. Signed-off-by: Tero Kristo Reported-by: Aparna Balasubramanian Signed-off-by: Herbert Xu Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/crypto/omap-sham.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index c65b49baf0c7..d8305ddf87d0 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -750,7 +750,10 @@ static int omap_sham_align_sgs(struct scatterlist *sg, if (final) new_len = DIV_ROUND_UP(new_len, bs) * bs; else - new_len = new_len / bs * bs; + new_len = (new_len - 1) / bs * bs; + + if (nbytes != new_len) + list_ok = false; while (nbytes > 0 && sg_tmp) { n++; @@ -846,6 +849,8 @@ static int omap_sham_prepare_request(struct ahash_request *req, bool update) xmit_len = DIV_ROUND_UP(xmit_len, bs) * bs; else xmit_len = xmit_len / bs * bs; + } else if (!final) { + xmit_len -= bs; } hash_later = rctx->total - xmit_len; @@ -1137,7 +1142,7 @@ static int omap_sham_handle_queue(struct omap_sham_dev *dd, ctx = ahash_request_ctx(req); err = omap_sham_prepare_request(req, ctx->op == OP_UPDATE); - if (err) + if (err || !ctx->total) goto err1; dev_dbg(dd->dev, "handling new req, op: %lu, nbytes: %d\n", -- GitLab From 5c27f6464438761af16038180e37d1b92986f29a Mon Sep 17 00:00:00 2001 From: "Mintz, Yuval" Date: Fri, 9 Jun 2017 17:17:01 +0300 Subject: [PATCH 1223/1834] bnx2x: Allow vfs to disable txvlan offload [ Upstream commit 92f85f05caa51d844af6ea14ffbc7a786446a644 ] VF clients are configured as enforced, meaning firmware is validating the correctness of their ethertype/vid during transmission. Once txvlan is disabled, VF would start getting SKBs for transmission here vlan is on the payload - but it'll pass the packet's ethertype instead of the vid, leading to firmware declaring it as malicious. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index ca6c4718000f..31287cec6e3a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -3887,15 +3887,26 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) /* when transmitting in a vf, start bd must hold the ethertype * for fw to enforce it */ + u16 vlan_tci = 0; #ifndef BNX2X_STOP_ON_ERROR - if (IS_VF(bp)) + if (IS_VF(bp)) { #endif - tx_start_bd->vlan_or_ethertype = - cpu_to_le16(ntohs(eth->h_proto)); + /* Still need to consider inband vlan for enforced */ + if (__vlan_get_tag(skb, &vlan_tci)) { + tx_start_bd->vlan_or_ethertype = + cpu_to_le16(ntohs(eth->h_proto)); + } else { + tx_start_bd->bd_flags.as_bitfield |= + (X_ETH_INBAND_VLAN << + ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT); + tx_start_bd->vlan_or_ethertype = + cpu_to_le16(vlan_tci); + } #ifndef BNX2X_STOP_ON_ERROR - else + } else { /* used by FW for packet accounting */ tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod); + } #endif } -- GitLab From 2c7608e644c01cdf638b9f3cb7e0c596ae950964 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sat, 10 Jun 2017 14:56:56 +0800 Subject: [PATCH 1224/1834] sctp: fix recursive locking warning in sctp_do_peeloff [ Upstream commit 6dfe4b97e08ec3d1a593fdaca099f0ef0a3a19e6 ] Dmitry got the following recursive locking report while running syzkaller fuzzer, the Call Trace: __dump_stack lib/dump_stack.c:16 [inline] dump_stack+0x2ee/0x3ef lib/dump_stack.c:52 print_deadlock_bug kernel/locking/lockdep.c:1729 [inline] check_deadlock kernel/locking/lockdep.c:1773 [inline] validate_chain kernel/locking/lockdep.c:2251 [inline] __lock_acquire+0xef2/0x3430 kernel/locking/lockdep.c:3340 lock_acquire+0x2a1/0x630 kernel/locking/lockdep.c:3755 lock_sock_nested+0xcb/0x120 net/core/sock.c:2536 lock_sock include/net/sock.h:1460 [inline] sctp_close+0xcd/0x9d0 net/sctp/socket.c:1497 inet_release+0xed/0x1c0 net/ipv4/af_inet.c:425 inet6_release+0x50/0x70 net/ipv6/af_inet6.c:432 sock_release+0x8d/0x1e0 net/socket.c:597 __sock_create+0x38b/0x870 net/socket.c:1226 sock_create+0x7f/0xa0 net/socket.c:1237 sctp_do_peeloff+0x1a2/0x440 net/sctp/socket.c:4879 sctp_getsockopt_peeloff net/sctp/socket.c:4914 [inline] sctp_getsockopt+0x111a/0x67e0 net/sctp/socket.c:6628 sock_common_getsockopt+0x95/0xd0 net/core/sock.c:2690 SYSC_getsockopt net/socket.c:1817 [inline] SyS_getsockopt+0x240/0x380 net/socket.c:1799 entry_SYSCALL_64_fastpath+0x1f/0xc2 This warning is caused by the lock held by sctp_getsockopt() is on one socket, while the other lock that sctp_close() is getting later is on the newly created (which failed) socket during peeloff operation. This patch is to avoid this warning by use lock_sock with subclass SINGLE_DEPTH_NESTING as Wang Cong and Marcelo's suggestion. Reported-by: Dmitry Vyukov Suggested-by: Marcelo Ricardo Leitner Suggested-by: Cong Wang Signed-off-by: Xin Long Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/sctp/socket.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 8cdd6bbe2efa..172465b7c0f4 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1519,7 +1519,7 @@ static void sctp_close(struct sock *sk, long timeout) pr_debug("%s: sk:%p, timeout:%ld\n", __func__, sk, timeout); - lock_sock(sk); + lock_sock_nested(sk, SINGLE_DEPTH_NESTING); sk->sk_shutdown = SHUTDOWN_MASK; sk->sk_state = SCTP_SS_CLOSING; @@ -1569,7 +1569,7 @@ static void sctp_close(struct sock *sk, long timeout) * held and that should be grabbed before socket lock. */ spin_lock_bh(&net->sctp.addr_wq_lock); - bh_lock_sock(sk); + bh_lock_sock_nested(sk); /* Hold the sock, since sk_common_release() will put sock_put() * and we have just a little more cleanup. -- GitLab From aabd70361a7ff2546d00f32d83a96713b33ad4ad Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 9 Jun 2017 22:37:22 -0300 Subject: [PATCH 1225/1834] net: fec: Add a fec_enet_clear_ethtool_stats() stub for CONFIG_M5272 [ Upstream commit bf292f1b2c813f1d6ac49b04bd1a9863d8314266 ] Commit 2b30842b23b9 ("net: fec: Clear and enable MIB counters on imx51") introduced fec_enet_clear_ethtool_stats(), but missed to add a stub for the CONFIG_M5272=y case, causing build failure for the m5272c3_defconfig. Add the missing empty stub to fix the build failure. Reported-by: Paul Gortmaker Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/freescale/fec_main.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 05e5b38e4891..fe00f71bc6b4 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2371,6 +2371,10 @@ static int fec_enet_get_sset_count(struct net_device *dev, int sset) static inline void fec_enet_update_ethtool_stats(struct net_device *dev) { } + +static inline void fec_enet_clear_ethtool_stats(struct net_device *dev) +{ +} #endif /* !defined(CONFIG_M5272) */ static int fec_enet_nway_reset(struct net_device *dev) -- GitLab From 3da8b25acacfdf4ac760b721977cfc96ffdc601c Mon Sep 17 00:00:00 2001 From: Jag Raman Date: Fri, 9 Jun 2017 12:29:31 -0400 Subject: [PATCH 1226/1834] sparc64: ldc abort during vds iso boot [ Upstream commit 6c95483b768c62f8ee933ae08a1bdbcb78b5410f ] Orabug: 20902628 When an ldc control-only packet is received during data exchange in read_nonraw(), a new rx head is calculated but the rx queue head is not actually advanced (rx_set_head() is not called) and a branch is taken to 'no_data' at which point two things can happen depending on the value of the newly calculated rx head and the current rx tail: - If the rx queue is determined to be not empty, then the wrong packet is picked up. - If the rx queue is determined to be empty, then a read error (EAGAIN) is eventually returned since it is falsely assumed that more data was expected. The fix is to update the rx head and return in case of a control only packet during data exchange. Signed-off-by: Jagannathan Raman Reviewed-by: Aaron Young Reviewed-by: Alexandre Chartre Reviewed-by: Bijan Mottahedeh Reviewed-by: Liam Merwick Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- arch/sparc/kernel/ldc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 59d503866431..9cc600b2d68c 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c @@ -1733,9 +1733,14 @@ static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size) lp->rcv_nxt = p->seqid; + /* + * If this is a control-only packet, there is nothing + * else to do but advance the rx queue since the packet + * was already processed above. + */ if (!(p->type & LDC_DATA)) { new = rx_advance(lp, new); - goto no_data; + break; } if (p->stype & (LDC_ACK | LDC_NACK)) { err = data_ack_nack(lp, p); -- GitLab From c613f7c06b9ad259cf66fb14bdc8f7442dfeea85 Mon Sep 17 00:00:00 2001 From: Lorenzo Bianconi Date: Tue, 6 Jun 2017 22:51:24 +0200 Subject: [PATCH 1227/1834] iio: magnetometer: st_magn_spi: fix spi_device_id table [ Upstream commit c83761ff0aac954aa368c623bb0f0d1a3214e834 ] Remove LSM303DLHC, LSM303DLM from st_magn_id_table since LSM303DL series does not support spi interface Fixes: 872e79add756 (iio: magn: Add STMicroelectronics magn driver) Signed-off-by: Lorenzo Bianconi Signed-off-by: Jonathan Cameron Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/iio/magnetometer/st_magn_spi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/iio/magnetometer/st_magn_spi.c b/drivers/iio/magnetometer/st_magn_spi.c index 6325e7dc8e03..f3cb4dc05391 100644 --- a/drivers/iio/magnetometer/st_magn_spi.c +++ b/drivers/iio/magnetometer/st_magn_spi.c @@ -48,8 +48,6 @@ static int st_magn_spi_remove(struct spi_device *spi) } static const struct spi_device_id st_magn_id_table[] = { - { LSM303DLHC_MAGN_DEV_NAME }, - { LSM303DLM_MAGN_DEV_NAME }, { LIS3MDL_MAGN_DEV_NAME }, { LSM303AGR_MAGN_DEV_NAME }, {}, -- GitLab From 61e01f1db6dadcfd56b32fb879bcad01f691f064 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Sun, 11 Jun 2017 15:42:43 +0300 Subject: [PATCH 1228/1834] net: ena: fix rare uncompleted admin command false alarm [ Upstream commit a77c1aafcc906f657d1a0890c1d898be9ee1d5c9 ] The current flow to detect admin completion is: while (command_not_completed) { if (timeout) error check_for_completion() sleep() } So in case the sleep took more than the timeout (in case the thread/workqueue was not scheduled due to higher priority task or prolonged VMexit), the driver can detect a stall even if the completion is present. The fix changes the order of this function to first check for completion and only after that check if the timeout expired. Fixes: 1738cd3ed342 ("Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amazon/ena/ena_com.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index e2512ab41168..564b556baba9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -508,15 +508,20 @@ static int ena_com_comp_status_to_errno(u8 comp_status) static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_ctx, struct ena_com_admin_queue *admin_queue) { - unsigned long flags; - u32 start_time; + unsigned long flags, timeout; int ret; - start_time = ((u32)jiffies_to_usecs(jiffies)); + timeout = jiffies + ADMIN_CMD_TIMEOUT_US; + + while (1) { + spin_lock_irqsave(&admin_queue->q_lock, flags); + ena_com_handle_admin_completion(admin_queue); + spin_unlock_irqrestore(&admin_queue->q_lock, flags); - while (comp_ctx->status == ENA_CMD_SUBMITTED) { - if ((((u32)jiffies_to_usecs(jiffies)) - start_time) > - ADMIN_CMD_TIMEOUT_US) { + if (comp_ctx->status != ENA_CMD_SUBMITTED) + break; + + if (time_is_before_jiffies(timeout)) { pr_err("Wait for completion (polling) timeout\n"); /* ENA didn't have any completion */ spin_lock_irqsave(&admin_queue->q_lock, flags); @@ -528,10 +533,6 @@ static int ena_com_wait_and_process_admin_cq_polling(struct ena_comp_ctx *comp_c goto err; } - spin_lock_irqsave(&admin_queue->q_lock, flags); - ena_com_handle_admin_completion(admin_queue); - spin_unlock_irqrestore(&admin_queue->q_lock, flags); - msleep(100); } -- GitLab From 0dc5e02cf060233b5a7c11f3b3e0592f8fb4505f Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Sun, 11 Jun 2017 15:42:46 +0300 Subject: [PATCH 1229/1834] net: ena: fix race condition between submit and completion admin command [ Upstream commit 661d2b0ccef6a63f48b61105cf7be17403d1db01 ] Bug: "Completion context is occupied" error printout will be noticed in dmesg. This error will cause the admin command to fail, which will lead to an ena_probe() failure or a watchdog reset (depends on which admin command failed). Root cause: __ena_com_submit_admin_cmd() is the function that submits new entries to the admin queue. The function have a check that makes sure the queue is not full and the function does not override any outstanding command. It uses head and tail indexes for this check. The head is increased by ena_com_handle_admin_completion() which runs from interrupt context, and the tail index is increased by the submit function (the function is running under ->q_lock, so there is no risk of multithread increment). Each command is associated with a completion context. This context allocated before call to __ena_com_submit_admin_cmd() and freed by ena_com_wait_and_process_admin_cq_interrupts(), right after the command was completed. This can lead to a state where the head was increased, the check passed, but the completion context is still in use. Solution: Use the atomic variable ->outstanding_cmds instead of using the head and the tail indexes. This variable is safe for use since it is bumped in get_comp_ctx() in __ena_com_submit_admin_cmd() and is freed by comp_ctxt_release() Fixes: 1738cd3ed342 ("Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amazon/ena/ena_com.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index 564b556baba9..f4c107b66af4 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -232,11 +232,9 @@ static struct ena_comp_ctx *__ena_com_submit_admin_cmd(struct ena_com_admin_queu tail_masked = admin_queue->sq.tail & queue_size_mask; /* In case of queue FULL */ - cnt = admin_queue->sq.tail - admin_queue->sq.head; + cnt = atomic_read(&admin_queue->outstanding_cmds); if (cnt >= admin_queue->q_depth) { - pr_debug("admin queue is FULL (tail %d head %d depth: %d)\n", - admin_queue->sq.tail, admin_queue->sq.head, - admin_queue->q_depth); + pr_debug("admin queue is full.\n"); admin_queue->stats.out_of_space++; return ERR_PTR(-ENOSPC); } -- GitLab From d06b43ba6706b26c9c3eadd9383161e220dfe808 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Sun, 11 Jun 2017 15:42:45 +0300 Subject: [PATCH 1230/1834] net: ena: add missing return when ena_com_get_io_handlers() fails [ Upstream commit 2d2c600a917127f16f179d5a88fc44ba3ed263ed ] Fixes: 1738cd3ed342 ("Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index bfeaec5bd7b9..fe691017d5aa 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1542,6 +1542,7 @@ static int ena_create_io_tx_queue(struct ena_adapter *adapter, int qid) "Failed to get TX queue handlers. TX queue num %d rc: %d\n", qid, rc); ena_com_destroy_io_queue(ena_dev, ena_qid); + return rc; } ena_com_update_numa_node(tx_ring->ena_com_io_cq, ctx.numa_node); @@ -1606,6 +1607,7 @@ static int ena_create_io_rx_queue(struct ena_adapter *adapter, int qid) "Failed to get RX queue handlers. RX queue num %d rc: %d\n", qid, rc); ena_com_destroy_io_queue(ena_dev, ena_qid); + return rc; } ena_com_update_numa_node(rx_ring->ena_com_io_cq, ctx.numa_node); -- GitLab From ff5b272d686912f1e49f01bb779ea57176095aa3 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Sun, 11 Jun 2017 15:42:47 +0300 Subject: [PATCH 1231/1834] net: ena: add missing unmap bars on device removal [ Upstream commit 0857d92f71b6cb75281fde913554b2d5436c394b ] This patch also change the mapping functions to devm_ functions Fixes: 1738cd3ed342 ("Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amazon/ena/ena_netdev.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index fe691017d5aa..0d9ce08ee3a9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -2808,6 +2808,11 @@ static void ena_release_bars(struct ena_com_dev *ena_dev, struct pci_dev *pdev) { int release_bars; + if (ena_dev->mem_bar) + devm_iounmap(&pdev->dev, ena_dev->mem_bar); + + devm_iounmap(&pdev->dev, ena_dev->reg_bar); + release_bars = pci_select_bars(pdev, IORESOURCE_MEM) & ENA_BAR_MASK; pci_release_selected_regions(pdev, release_bars); } @@ -2895,8 +2900,9 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free_ena_dev; } - ena_dev->reg_bar = ioremap(pci_resource_start(pdev, ENA_REG_BAR), - pci_resource_len(pdev, ENA_REG_BAR)); + ena_dev->reg_bar = devm_ioremap(&pdev->dev, + pci_resource_start(pdev, ENA_REG_BAR), + pci_resource_len(pdev, ENA_REG_BAR)); if (!ena_dev->reg_bar) { dev_err(&pdev->dev, "failed to remap regs bar\n"); rc = -EFAULT; @@ -2916,8 +2922,9 @@ static int ena_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ena_set_push_mode(pdev, ena_dev, &get_feat_ctx); if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { - ena_dev->mem_bar = ioremap_wc(pci_resource_start(pdev, ENA_MEM_BAR), - pci_resource_len(pdev, ENA_MEM_BAR)); + ena_dev->mem_bar = devm_ioremap_wc(&pdev->dev, + pci_resource_start(pdev, ENA_MEM_BAR), + pci_resource_len(pdev, ENA_MEM_BAR)); if (!ena_dev->mem_bar) { rc = -EFAULT; goto err_device_destroy; -- GitLab From 70accaaca83b13210a8c866fa60421ff88b63d60 Mon Sep 17 00:00:00 2001 From: Netanel Belgazal Date: Sun, 11 Jun 2017 15:42:49 +0300 Subject: [PATCH 1232/1834] net: ena: disable admin msix while working in polling mode [ Upstream commit a2cc5198dac102775b21787752a2e0afe44ad311 ] Fixes: 1738cd3ed342 ("Add a driver for Amazon Elastic Network Adapters (ENA)") Signed-off-by: Netanel Belgazal Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/amazon/ena/ena_com.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/amazon/ena/ena_com.c b/drivers/net/ethernet/amazon/ena/ena_com.c index f4c107b66af4..e13c9cd45dc0 100644 --- a/drivers/net/ethernet/amazon/ena/ena_com.c +++ b/drivers/net/ethernet/amazon/ena/ena_com.c @@ -61,6 +61,8 @@ #define ENA_MMIO_READ_TIMEOUT 0xFFFFFFFF +#define ENA_REGS_ADMIN_INTR_MASK 1 + /*****************************************************************************/ /*****************************************************************************/ /*****************************************************************************/ @@ -1448,6 +1450,12 @@ void ena_com_admin_destroy(struct ena_com_dev *ena_dev) void ena_com_set_admin_polling_mode(struct ena_com_dev *ena_dev, bool polling) { + u32 mask_value = 0; + + if (polling) + mask_value = ENA_REGS_ADMIN_INTR_MASK; + + writel(mask_value, ena_dev->reg_bar + ENA_REGS_INTR_MASK_OFF); ena_dev->admin_queue.polling = polling; } -- GitLab From a81437a759337a9fa6a89704d22e9adf1874a20d Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sun, 4 Jun 2017 20:33:39 +0200 Subject: [PATCH 1233/1834] clk: meson: meson8b: add compatibles for Meson8 and Meson8m2 [ Upstream commit 855f06a1009faabb0c6a3e9b49d115496d325856 ] The clock controller on Meson8, Meson8b and Meson8m2 is very similar based on the code from the Amlogic GPL kernel sources. Add separate compatibles for each SoC to make sure that we can easily implement all the small differences for each SoC later on. In general the Meson8 and Meson8m2 seem to be almost identical as they even share the same mach-meson8 directory in Amlogic's GPL kernel sources. The main clocks on Meson8, Meson8b and Meson8m2 are very similar, because they are all using the same PLL values, 90% of the clock gates are the same (the actual diffstat of the mach-meson8/clock.c and mach-meson8b/clock.c files is around 30 to 40 lines, when excluding all commented out code). The difference between the Meson8 and Meson8b clock gates seem to be: - Meson8 has AIU_PCLK, HDMI_RX, VCLK2_ENCT, VCLK2_ENCL, UART3, CSI_DIG_CLKIN gates which don't seem to be available on Meson8b - the gate on Meson8 for bit 7 seems to be named "_1200XXX" instead of "PERIPHS_TOP" (on Meson8b) - Meson8b has a SANA gate which doesn't seem to exist on Meson8 (or on Meson8 the same bit is used by the UART3 gate in Amlogic's GPL kernel sources) None of these gates is added for now, since it's unclear whether these definitions are actually correct (the VCLK2_ENCT gate for example is defined, but only used in some commented block). The main difference between all three SoCs seem to be the video (VPU) clocks. Apart from different supported clock rates (according to vpu.c in mach-meson8 and mach-meson8b from Amlogic's GPL kernel sources) the most notable difference is that Meson8m2 has a GP_PLL clock and a mux (probably the same as on the Meson GX SoCs) to support glitch-free (clock rate) switching. None of these VPU clocks are not supported by our mainline meson8b clock driver yet though. Signed-off-by: Martin Blumenstingl Acked-by: Rob Herring Acked-by: Kevin Hilman Signed-off-by: Jerome Brunet Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- .../bindings/clock/amlogic,meson8b-clkc.txt | 11 +++++++---- drivers/clk/meson/Kconfig | 6 +++--- drivers/clk/meson/meson8b.c | 5 ++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt index 2b7b3fa588d7..606da38c0959 100644 --- a/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt +++ b/Documentation/devicetree/bindings/clock/amlogic,meson8b-clkc.txt @@ -1,11 +1,14 @@ -* Amlogic Meson8b Clock and Reset Unit +* Amlogic Meson8, Meson8b and Meson8m2 Clock and Reset Unit -The Amlogic Meson8b clock controller generates and supplies clock to various -controllers within the SoC. +The Amlogic Meson8 / Meson8b / Meson8m2 clock controller generates and +supplies clock to various controllers within the SoC. Required Properties: -- compatible: should be "amlogic,meson8b-clkc" +- compatible: must be one of: + - "amlogic,meson8-clkc" for Meson8 (S802) SoCs + - "amlogic,meson8b-clkc" for Meson8 (S805) SoCs + - "amlogic,meson8m2-clkc" for Meson8m2 (S812) SoCs - reg: it must be composed by two tuples: 0) physical base address of the xtal register and length of memory mapped region. diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 2f29ee1a4d00..5588f75a8414 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -7,9 +7,9 @@ config COMMON_CLK_MESON8B bool depends on COMMON_CLK_AMLOGIC help - Support for the clock controller on AmLogic S805 devices, aka - meson8b. Say Y if you want peripherals and CPU frequency scaling to - work. + Support for the clock controller on AmLogic S802 (Meson8), + S805 (Meson8b) and S812 (Meson8m2) devices. Say Y if you + want peripherals and CPU frequency scaling to work. config COMMON_CLK_GXBB bool diff --git a/drivers/clk/meson/meson8b.c b/drivers/clk/meson/meson8b.c index 3f1be46cbb33..70567958b86a 100644 --- a/drivers/clk/meson/meson8b.c +++ b/drivers/clk/meson/meson8b.c @@ -1,5 +1,6 @@ /* - * AmLogic S805 / Meson8b Clock Controller Driver + * AmLogic S802 (Meson8) / S805 (Meson8b) / S812 (Meson8m2) Clock Controller + * Driver * * Copyright (c) 2015 Endless Mobile, Inc. * Author: Carlo Caione @@ -661,7 +662,9 @@ static int meson8b_clkc_probe(struct platform_device *pdev) } static const struct of_device_id meson8b_clkc_match_table[] = { + { .compatible = "amlogic,meson8-clkc" }, { .compatible = "amlogic,meson8b-clkc" }, + { .compatible = "amlogic,meson8m2-clkc" }, { } }; -- GitLab From f5d899cbec6f4733cbc5366cb03f442a31785acd Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 9 Jun 2017 18:43:56 +0200 Subject: [PATCH 1234/1834] Bluetooth: Send HCI Set Event Mask Page 2 command only when needed [ Upstream commit 313f6888c8fbb1bc8b36c9012ce4e1de848df696 ] The Broadcom BCM20702 Bluetooth controller in ThinkPad-T530 devices report support for the Set Event Mask Page 2 command, but actually do return an error when trying to use it. < HCI Command: Read Local Supported Commands (0x04|0x0002) plen 0 > HCI Event: Command Complete (0x0e) plen 68 Read Local Supported Commands (0x04|0x0002) ncmd 1 Status: Success (0x00) Commands: 162 entries ... Set Event Mask Page 2 (Octet 22 - Bit 2) ... < HCI Command: Set Event Mask Page 2 (0x03|0x0063) plen 8 Mask: 0x0000000000000000 > HCI Event: Command Complete (0x0e) plen 4 Set Event Mask Page 2 (0x03|0x0063) ncmd 1 Status: Unknown HCI Command (0x01) Since these controllers do not support any feature that would require the event mask page 2 to be modified, it is safe to not send this command at all. The default value is all bits set to zero. T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=03 Dev#= 9 Spd=12 MxCh= 0 D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=0a5c ProdID=21e6 Rev= 1.12 S: Manufacturer=Broadcom Corp S: Product=BCM20702A0 S: SerialNumber=F82FA8E8CFC0 C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=btusb E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none) Signed-off-by: Marcel Holtmann Reported-by: Sedat Dilek Tested-by: Sedat Dilek Signed-off-by: Szymon Janc Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/bluetooth/hci_core.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3ac89e9ace71..4bd72d2fe415 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -548,6 +548,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) { struct hci_dev *hdev = req->hdev; u8 events[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + bool changed = false; /* If Connectionless Slave Broadcast master role is supported * enable all necessary events for it. @@ -557,6 +558,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req) events[1] |= 0x80; /* Synchronization Train Complete */ events[2] |= 0x10; /* Slave Page Response Timeout */ events[2] |= 0x20; /* CSB Channel Map Change */ + changed = true; } /* If Connectionless Slave Broadcast slave role is supported @@ -567,13 +569,24 @@ static void hci_set_event_mask_page_2(struct hci_request *req) events[2] |= 0x02; /* CSB Receive */ events[2] |= 0x04; /* CSB Timeout */ events[2] |= 0x08; /* Truncated Page Complete */ + changed = true; } /* Enable Authenticated Payload Timeout Expired event if supported */ - if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) + if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) { events[2] |= 0x80; + changed = true; + } - hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events); + /* Some Broadcom based controllers indicate support for Set Event + * Mask Page 2 command, but then actually do not support it. Since + * the default value is all bits set to zero, the command is only + * required if the event mask has to be changed. In case no change + * to the event mask is needed, skip this command. + */ + if (changed) + hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, + sizeof(events), events); } static int hci_init3_req(struct hci_request *req, unsigned long opt) -- GitLab From b22081fbfbaac0016fec3c087216ec11adba64d3 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Sun, 11 Jun 2017 14:28:54 +0200 Subject: [PATCH 1235/1834] cpuidle: dt: Add missing 'of_node_put()' [ Upstream commit b2cdd8e1b54849477a32d820acc2e87828a38f3d ] 'of_node_put()' should be called on pointer returned by 'of_parse_phandle()' when done. In this function this is done in all path except this 'continue', so add it. Fixes: 97735da074fd (drivers: cpuidle: Add status property to ARM idle states) Signed-off-by: Christophe Jaillet Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/cpuidle/dt_idle_states.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c index a5c111b67f37..ea11a33e7fff 100644 --- a/drivers/cpuidle/dt_idle_states.c +++ b/drivers/cpuidle/dt_idle_states.c @@ -174,8 +174,10 @@ int dt_init_idle_driver(struct cpuidle_driver *drv, if (!state_node) break; - if (!of_device_is_available(state_node)) + if (!of_device_is_available(state_node)) { + of_node_put(state_node); continue; + } if (!idle_state_valid(state_node, i, cpumask)) { pr_warn("%s idle state not valid, bailing out\n", -- GitLab From ac748c54d3617b7a4c5f42e695d5f90e099deee4 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 5 Jun 2017 16:39:56 +0800 Subject: [PATCH 1236/1834] ACPICA: OSL: Add support to exclude stdarg.h [ Upstream commit 84676b87b27d8aefafb9f712a5b444938f284513 ] ACPICA commit e2df7455a9a4301b03668e4c9c02c7a564cc841c Some hosts may choose not to include stdarg.h, implementing a configurability in acgcc.h, allowing OSen like Solaris to exclude stdarg.h. This patch also fixes acintel.h accordingly without providing builtin support as Intel compiler is similar as GCC. Reported by Dana Myers, fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/e2df7455 Reported-by: Dana Myers Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- include/acpi/platform/acgcc.h | 10 ++++++++++ include/acpi/platform/acintel.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h index 8f66aaabadf7..9e3f7618593f 100644 --- a/include/acpi/platform/acgcc.h +++ b/include/acpi/platform/acgcc.h @@ -48,7 +48,17 @@ * Use compiler specific is a good practice for even when * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined. */ +#ifndef va_arg +#ifdef ACPI_USE_BUILTIN_STDARG +typedef __builtin_va_list va_list; +#define va_start(v, l) __builtin_va_start(v, l) +#define va_end(v) __builtin_va_end(v) +#define va_arg(v, l) __builtin_va_arg(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) +#else #include +#endif +#endif #define ACPI_INLINE __inline__ diff --git a/include/acpi/platform/acintel.h b/include/acpi/platform/acintel.h index 17bd3b7b4e5a..bdb6858e2458 100644 --- a/include/acpi/platform/acintel.h +++ b/include/acpi/platform/acintel.h @@ -48,7 +48,9 @@ * Use compiler specific is a good practice for even when * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined. */ +#ifndef va_arg #include +#endif /* Configuration specific to Intel 64-bit C compiler */ -- GitLab From 9711cf143de362d05ae149bd5c54be23aa4d4882 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Mon, 5 Jun 2017 16:40:02 +0800 Subject: [PATCH 1237/1834] ACPICA: Events: Add runtime stub support for event APIs [ Upstream commit 861ba6351c520328e94a78c923b415faa9116287 ] ACPICA commit 99bc3beca92c6574ea1d69de42e54f872e6373ce It is reported that on Linux, RTC driver complains wrong errors on hardware reduced platform: [ 4.085420] ACPI Warning: Could not enable fixed event - real_time_clock (4) (20160422/evxface-654) This patch fixes this by correctly adding runtime reduced hardware check. Reported by Chandan Tagore, fixed by Lv Zheng. Link: https://github.com/acpica/acpica/commit/99bc3bec Tested-by: Chandan Tagore Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpica/evxfevnt.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 9179e9abe3db..35a2d9ea0654 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -180,6 +180,12 @@ acpi_status acpi_enable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_enable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -237,6 +243,12 @@ acpi_status acpi_disable_event(u32 event, u32 flags) ACPI_FUNCTION_TRACE(acpi_disable_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { @@ -290,6 +302,12 @@ acpi_status acpi_clear_event(u32 event) ACPI_FUNCTION_TRACE(acpi_clear_event); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Decode the Fixed Event */ if (event > ACPI_EVENT_MAX) { -- GitLab From 352b45c2ff86d59944e6bbc5381f6c1e62822a65 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Mon, 5 Jun 2017 16:40:34 +0800 Subject: [PATCH 1238/1834] ACPICA: Disassembler: Abort on an invalid/unknown AML opcode [ Upstream commit 6f0527b77d9e0129dd8e50945b0d610ed943d6b2 ] ACPICA commit ed0389cb11a61e63c568ac1f67948fc6a7bd1aeb An invalid opcode indicates something seriously wrong with the input AML file. The AML parser is immediately confused and lost, causing the resulting parse tree to be ill-formed. The actual disassembly can then cause numerous unrelated errors and faults. This change aborts the disassembly upon discovery of such an opcode during the AML parse phase. Link: https://github.com/acpica/acpica/commit/ed0389cb Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/acpica/psobject.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index db0e90342e82..ac2e8dfdf74e 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -121,6 +121,9 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) (u32)(aml_offset + sizeof(struct acpi_table_header))); + ACPI_ERROR((AE_INFO, + "Aborting disassembly, AML byte code is corrupt")); + /* Dump the context surrounding the invalid opcode */ acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. @@ -129,6 +132,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) sizeof(struct acpi_table_header) - 16)); acpi_os_printf(" */\n"); + + /* + * Just abort the disassembly, cannot continue because the + * parser is essentially lost. The disassembler can then + * randomly fail because an ill-constructed parse tree + * can result. + */ + return_ACPI_STATUS(AE_AML_BAD_OPCODE); #endif } @@ -293,6 +304,9 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, if (status == AE_CTRL_PARSE_CONTINUE) { return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE); } + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } /* Create Op structure and append to parent's argument list */ -- GitLab From d5a4ef2bce3598d5dd6ca749e2e48e56869d9965 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Thu, 18 May 2017 13:24:45 +0200 Subject: [PATCH 1239/1834] s390/dasd: fix hanging safe offline [ Upstream commit e8ac01555d9e464249e8bb122337d6d6e5589ccc ] The safe offline processing may hang forever because it waits for I/O which can not be started because of the offline flag that prevents new I/O from being started. Allow I/O to be started during safe offline processing because in this special case we take care that the queues are empty before throwing away the device. Signed-off-by: Stefan Haberland Signed-off-by: Martin Schwidefsky Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/s390/block/dasd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 5ecd40884f01..0da246505f70 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1950,8 +1950,12 @@ static int __dasd_device_is_unusable(struct dasd_device *device, { int mask = ~(DASD_STOPPED_DC_WAIT | DASD_UNRESUMED_PM); - if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { - /* dasd is being set offline. */ + if (test_bit(DASD_FLAG_OFFLINE, &device->flags) && + !test_bit(DASD_FLAG_SAFE_OFFLINE_RUNNING, &device->flags)) { + /* + * dasd is being set offline + * but it is no safe offline where we have to allow I/O + */ return 1; } if (device->stopped) { -- GitLab From deaee4d29d05bde5fa3c2dda5ad813b8bae944e2 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Sun, 11 Jun 2017 16:32:50 -0700 Subject: [PATCH 1240/1834] vxlan: dont migrate permanent fdb entries during learn [ Upstream commit e0090a9e979de5202c7d16c635dea2f005221073 ] This patch fixes vxlan_snoop to not move permanent fdb entries on learn events. This is consistent with the bridge fdb handling of permanent entries. Fixes: 26a41ae60438 ("vxlan: only migrate dynamic FDB entries") Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/vxlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 0f5dfb8a545d..28afdf22b88f 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -930,7 +930,7 @@ static bool vxlan_snoop(struct net_device *dev, return false; /* Don't migrate static entries, drop packets */ - if (f->state & NUD_NOARP) + if (f->state & (NUD_PERMANENT | NUD_NOARP)) return true; if (net_ratelimit()) -- GitLab From 329812f9e6944ae14662e2cd51975ef76c3ac61c Mon Sep 17 00:00:00 2001 From: "Karicheri, Muralidharan" Date: Mon, 12 Jun 2017 15:06:26 -0400 Subject: [PATCH 1241/1834] hsr: fix incorrect warning [ Upstream commit 675c8da049fd6556eb2d6cdd745fe812752f07a8 ] When HSR interface is setup using ip link command, an annoying warning appears with the trace as below:- [ 203.019828] hsr_get_node: Non-HSR frame [ 203.019833] Modules linked in: [ 203.019848] CPU: 0 PID: 158 Comm: sd-resolve Tainted: G W 4.12.0-rc3-00052-g9fa6bf70 #2 [ 203.019853] Hardware name: Generic DRA74X (Flattened Device Tree) [ 203.019869] [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [ 203.019880] [] (show_stack) from [] (dump_stack+0xac/0xe0) [ 203.019894] [] (dump_stack) from [] (__warn+0xd8/0x104) [ 203.019907] [] (__warn) from [] (warn_slowpath_fmt+0x34/0x44) root@am57xx-evm:~# [ 203.019921] [] (warn_slowpath_fmt) from [] (hsr_get_node+0x148/0x170) [ 203.019932] [] (hsr_get_node) from [] (hsr_forward_skb+0x110/0x7c0) [ 203.019942] [] (hsr_forward_skb) from [] (hsr_dev_xmit+0x2c/0x34) [ 203.019954] [] (hsr_dev_xmit) from [] (dev_hard_start_xmit+0xc4/0x3bc) [ 203.019963] [] (dev_hard_start_xmit) from [] (__dev_queue_xmit+0x7c4/0x98c) [ 203.019974] [] (__dev_queue_xmit) from [] (ip6_finish_output2+0x330/0xc1c) [ 203.019983] [] (ip6_finish_output2) from [] (ip6_output+0x58/0x454) [ 203.019994] [] (ip6_output) from [] (mld_sendpack+0x420/0x744) As this is an expected path to hsr_get_node() with frame coming from the master interface, add a check to ensure packet is not from the master port and then warn. Signed-off-by: Murali Karicheri Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- net/hsr/hsr_forward.c | 3 +-- net/hsr/hsr_framereg.c | 9 +++++++-- net/hsr/hsr_framereg.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/net/hsr/hsr_forward.c b/net/hsr/hsr_forward.c index 4ebe2aa3e7d3..04b5450c5a55 100644 --- a/net/hsr/hsr_forward.c +++ b/net/hsr/hsr_forward.c @@ -324,8 +324,7 @@ static int hsr_fill_frame_info(struct hsr_frame_info *frame, unsigned long irqflags; frame->is_supervision = is_supervision_frame(port->hsr, skb); - frame->node_src = hsr_get_node(&port->hsr->node_db, skb, - frame->is_supervision); + frame->node_src = hsr_get_node(port, skb, frame->is_supervision); if (frame->node_src == NULL) return -1; /* Unknown node and !is_supervision, or no mem */ diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 7ea925816f79..284a9b820df8 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c @@ -158,9 +158,10 @@ struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], /* Get the hsr_node from which 'skb' was sent. */ -struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb, +struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb, bool is_sup) { + struct list_head *node_db = &port->hsr->node_db; struct hsr_node *node; struct ethhdr *ethhdr; u16 seq_out; @@ -186,7 +187,11 @@ struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb, */ seq_out = hsr_get_skb_sequence_nr(skb) - 1; } else { - WARN_ONCE(1, "%s: Non-HSR frame\n", __func__); + /* this is called also for frames from master port and + * so warn only for non master ports + */ + if (port->type != HSR_PT_MASTER) + WARN_ONCE(1, "%s: Non-HSR frame\n", __func__); seq_out = HSR_SEQNR_START; } diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index 438b40f98f5a..4e04f0e868e9 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h @@ -18,7 +18,7 @@ struct hsr_node; struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], u16 seq_out); -struct hsr_node *hsr_get_node(struct list_head *node_db, struct sk_buff *skb, +struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb, bool is_sup); void hsr_handle_sup_frame(struct sk_buff *skb, struct hsr_node *node_curr, struct hsr_port *port); -- GitLab From db14d7564396bd3325a7a3e9e74ad4574a094ca8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Sala=C3=BCn?= Date: Sun, 11 Jun 2017 14:32:58 +0200 Subject: [PATCH 1242/1834] selftests: kselftest_harness: Fix compile warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ Upstream commit 34a048cc06802556e5f96f325dc32cc2f6a11225 ] Do not confuse the compiler with a semicolon preceding a block. Replace the semicolon with an empty block to avoid a warning: gcc -Wl,-no-as-needed -Wall -lpthread seccomp_bpf.c -o /.../linux/tools/testing/selftests/seccomp/seccomp_bpf In file included from seccomp_bpf.c:40:0: seccomp_bpf.c: In function ‘change_syscall’: ../kselftest_harness.h:558:2: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation] for (; _metadata->trigger; _metadata->trigger = __bail(_assert)) ^ ../kselftest_harness.h:574:14: note: in expansion of macro ‘OPTIONAL_HANDLER’ } while (0); OPTIONAL_HANDLER(_assert) ^~~~~~~~~~~~~~~~ ../kselftest_harness.h:440:2: note: in expansion of macro ‘__EXPECT’ __EXPECT(expected, seen, ==, 0) ^~~~~~~~ seccomp_bpf.c:1313:2: note: in expansion of macro ‘EXPECT_EQ’ EXPECT_EQ(0, ret); ^~~~~~~~~ seccomp_bpf.c:1317:2: note: ...this statement, but the latter is misleadingly indented as if it is guarded by the ‘for’ { ^ Signed-off-by: Mickaël Salaün Cc: Andy Lutomirski Cc: Kees Cook Cc: Shuah Khan Cc: Will Drewry Acked-by: Kees Cook Signed-off-by: Shuah Khan Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/seccomp/seccomp_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index cbb0564c0ec4..f68998149351 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -1318,7 +1318,7 @@ void change_syscall(struct __test_metadata *_metadata, iov.iov_len = sizeof(regs); ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov); #endif - EXPECT_EQ(0, ret); + EXPECT_EQ(0, ret) {} #if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \ defined(__s390__) || defined(__hppa__) -- GitLab From 9622668cf21a54b7df0c0d2d5e923576187ab603 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 12 May 2017 14:38:03 +0200 Subject: [PATCH 1243/1834] drm/vc4: Fix resource leak in 'vc4_get_hang_state_ioctl()' in error handling path [ Upstream commit d0b1d259a4b58b21a21ea82d7174bf7ea825e9cc ] If one 'drm_gem_handle_create()' fails, we leak somes handles and some memory. In order to fix it: - move the 'free(bo_state)' at the end of the function so that it is also called in the eror handling path. This has the side effect to also try to free it if the first 'kcalloc' fails. This is harmless. - add a new label, err_delete_handle, in order to delete already allocated handles in error handling path - remove the now useless 'err' label The way the code is now written will also delete the handles if the 'copy_to_user()' call fails. Signed-off-by: Christophe JAILLET Reviewed-by: Eric Anholt Link: http://patchwork.freedesktop.org/patch/msgid/20170512123803.1886-1-christophe.jaillet@wanadoo.fr Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/vc4/vc4_gem.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index ab3016982466..b608cd463d4e 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -110,8 +110,8 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, &handle); if (ret) { - state->bo_count = i - 1; - goto err; + state->bo_count = i; + goto err_delete_handle; } bo_state[i].handle = handle; bo_state[i].paddr = vc4_bo->base.paddr; @@ -123,13 +123,16 @@ vc4_get_hang_state_ioctl(struct drm_device *dev, void *data, state->bo_count * sizeof(*bo_state))) ret = -EFAULT; - kfree(bo_state); +err_delete_handle: + if (ret) { + for (i = 0; i < state->bo_count; i++) + drm_gem_handle_delete(file_priv, bo_state[i].handle); + } err_free: - vc4_free_hang_state(dev, kernel_state); + kfree(bo_state); -err: return ret; } -- GitLab From d046bb9ec4947cd131ff22e1989179007c41b31f Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Mon, 8 Jan 2018 12:21:19 -0800 Subject: [PATCH 1244/1834] bcache: stop writeback thread after detaching [ Upstream commit 8d29c4426b9f8afaccf28de414fde8a722b35fdf ] Currently, when a cached device detaching from cache, writeback thread is not stopped, and writeback_rate_update work is not canceled. For example, after the following command: echo 1 >/sys/block/sdb/bcache/detach you can still see the writeback thread. Then you attach the device to the cache again, bcache will create another writeback thread, for example, after below command: echo ba0fb5cd-658a-4533-9806-6ce166d883b9 > /sys/block/sdb/bcache/attach then you will see 2 writeback threads. This patch stops writeback thread and cancels writeback_rate_update work when cached device detaching from cache. Compare with patch v1, this v2 patch moves code down into the register lock for safety in case of any future changes as Coly and Mike suggested. [edit by mlyle: commit log spelling/formatting] Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/super.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index c61341c84d2d..4af7cd423c71 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -892,6 +892,12 @@ static void cached_dev_detach_finish(struct work_struct *w) mutex_lock(&bch_register_lock); + cancel_delayed_work_sync(&dc->writeback_rate_update); + if (!IS_ERR_OR_NULL(dc->writeback_thread)) { + kthread_stop(dc->writeback_thread); + dc->writeback_thread = NULL; + } + memset(&dc->sb.set_uuid, 0, 16); SET_BDEV_STATE(&dc->sb, BDEV_STATE_NONE); -- GitLab From 38f1e54e5dfa3d132b884cd4c394efb3d265b4e5 Mon Sep 17 00:00:00 2001 From: Tang Junhui Date: Mon, 8 Jan 2018 12:21:21 -0800 Subject: [PATCH 1245/1834] bcache: segregate flash only volume write streams [ Upstream commit 4eca1cb28d8b0574ca4f1f48e9331c5f852d43b9 ] In such scenario that there are some flash only volumes , and some cached devices, when many tasks request these devices in writeback mode, the write IOs may fall to the same bucket as bellow: | cached data | flash data | cached data | cached data| flash data| then after writeback of these cached devices, the bucket would be like bellow bucket: | free | flash data | free | free | flash data | So, there are many free space in this bucket, but since data of flash only volumes still exists, so this bucket cannot be reclaimable, which would cause waste of bucket space. In this patch, we segregate flash only volume write streams from cached devices, so data from flash only volumes and cached devices can store in different buckets. Compare to v1 patch, this patch do not add a additionally open bucket list, and it is try best to segregate flash only volume write streams from cached devices, sectors of flash only volumes may still be mixed with dirty sectors of cached device, but the number is very small. [mlyle: fixed commit log formatting, permissions, line endings] Signed-off-by: Tang Junhui Reviewed-by: Michael Lyle Signed-off-by: Michael Lyle Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/md/bcache/alloc.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 537903bf9add..d23337e8c4ee 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -512,15 +512,21 @@ struct open_bucket { /* * We keep multiple buckets open for writes, and try to segregate different - * write streams for better cache utilization: first we look for a bucket where - * the last write to it was sequential with the current write, and failing that - * we look for a bucket that was last used by the same task. + * write streams for better cache utilization: first we try to segregate flash + * only volume write streams from cached devices, secondly we look for a bucket + * where the last write to it was sequential with the current write, and + * failing that we look for a bucket that was last used by the same task. * * The ideas is if you've got multiple tasks pulling data into the cache at the * same time, you'll get better cache utilization if you try to segregate their * data and preserve locality. * - * For example, say you've starting Firefox at the same time you're copying a + * For example, dirty sectors of flash only volume is not reclaimable, if their + * dirty sectors mixed with dirty sectors of cached device, such buckets will + * be marked as dirty and won't be reclaimed, though the dirty data of cached + * device have been written back to backend device. + * + * And say you've starting Firefox at the same time you're copying a * bunch of files. Firefox will likely end up being fairly hot and stay in the * cache awhile, but the data you copied might not be; if you wrote all that * data to the same buckets it'd get invalidated at the same time. @@ -537,7 +543,10 @@ static struct open_bucket *pick_data_bucket(struct cache_set *c, struct open_bucket *ret, *ret_task = NULL; list_for_each_entry_reverse(ret, &c->data_buckets, list) - if (!bkey_cmp(&ret->key, search)) + if (UUID_FLASH_ONLY(&c->uuids[KEY_INODE(&ret->key)]) != + UUID_FLASH_ONLY(&c->uuids[KEY_INODE(search)])) + continue; + else if (!bkey_cmp(&ret->key, search)) goto found; else if (ret->last_write_point == write_point) ret_task = ret; -- GitLab From 0ef71347d2e8db15ab0f8c7b79cf2c38d34d1870 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Thu, 4 Jan 2018 21:04:31 +0800 Subject: [PATCH 1246/1834] scsi: libsas: fix memory leak in sas_smp_get_phy_events() [ Upstream commit 4a491b1ab11ca0556d2fda1ff1301e862a2d44c4 ] We've got a memory leak with the following producer: while true; do cat /sys/class/sas_phy/phy-1:0:12/invalid_dword_count >/dev/null; done The buffer req is allocated and not freed after we return. Fix it. Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") Signed-off-by: Jason Yan CC: John Garry CC: chenqilin CC: chenxiang Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 022bb6e10d98..76730a5637ca 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -684,6 +684,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); out: + kfree(req); kfree(resp); return res; -- GitLab From 7333f17273a15a218e778135ef730f2d4a6f9213 Mon Sep 17 00:00:00 2001 From: Jason Yan Date: Thu, 4 Jan 2018 21:04:32 +0800 Subject: [PATCH 1247/1834] scsi: libsas: fix error when getting phy events [ Upstream commit 2b23d9509fd7174b362482cf5f3b5f9a2265bc33 ] The intend purpose here was to goto out if smp_execute_task() returned error. Obviously something got screwed up. We will never get these link error statistics below: ~:/sys/class/sas_phy/phy-1:0:12 # cat invalid_dword_count 0 ~:/sys/class/sas_phy/phy-1:0:12 # cat running_disparity_error_count 0 ~:/sys/class/sas_phy/phy-1:0:12 # cat loss_of_dword_sync_count 0 ~:/sys/class/sas_phy/phy-1:0:12 # cat phy_reset_problem_count 0 Obviously we should goto error handler if smp_execute_task() returns non-zero. Fixes: 2908d778ab3e ("[SCSI] aic94xx: new driver") Signed-off-by: Jason Yan CC: John Garry CC: chenqilin CC: chenxiang Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 76730a5637ca..ccdb9d5e2f28 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -675,7 +675,7 @@ int sas_smp_get_phy_events(struct sas_phy *phy) res = smp_execute_task(dev, req, RPEL_REQ_SIZE, resp, RPEL_RESP_SIZE); - if (!res) + if (res) goto out; phy->invalid_dword_count = scsi_to_u32(&resp[12]); -- GitLab From cafd951e8bf2b2f70246a329dd0e226bf3c45d3d Mon Sep 17 00:00:00 2001 From: chenxiang Date: Thu, 4 Jan 2018 21:04:33 +0800 Subject: [PATCH 1248/1834] scsi: libsas: initialize sas_phy status according to response of DISCOVER [ Upstream commit affc67788fe5dfffad5cda3d461db5cf2b2ff2b0 ] The status of SAS PHY is in sas_phy->enabled. There is an issue that the status of a remote SAS PHY may be initialized incorrectly: if disable remote SAS PHY through sysfs interface (such as echo 0 > /sys/class/sas_phy/phy-1:0:0/enable), then reboot the system, and we will find the status of remote SAS PHY which is disabled before is 1 (cat /sys/class/sas_phy/phy-1:0:0/enable). But actually the status of remote SAS PHY is disabled and the device attached is not found. In SAS protocol, NEGOTIATED LOGICAL LINK RATE field of DISCOVER response is 0x1 when remote SAS PHY is disabled. So initialize sas_phy->enabled according to the value of NEGOTIATED LOGICAL LINK RATE field. Signed-off-by: chenxiang Reviewed-by: John Garry Signed-off-by: Jason Yan Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/scsi/libsas/sas_expander.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index ccdb9d5e2f28..12886f96b286 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -282,6 +282,7 @@ static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) phy->phy->minimum_linkrate = dr->pmin_linkrate; phy->phy->maximum_linkrate = dr->pmax_linkrate; phy->phy->negotiated_linkrate = phy->linkrate; + phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED); skip: if (new_phy) -- GitLab From 3f4e241969e87b26a17702457a364228bd675880 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 9 Jan 2018 21:28:29 +0800 Subject: [PATCH 1249/1834] blk-mq: fix kernel oops in blk_mq_tag_idle() [ Upstream commit 8ab0b7dc73e1b3e2987d42554b2bff503f692772 ] HW queues may be unmapped in some cases, such as blk_mq_update_nr_hw_queues(), then we need to check it before calling blk_mq_tag_idle(), otherwise the following kernel oops can be triggered, so fix it by checking if the hw queue is unmapped since it doesn't make sense to idle the tags any more after hw queues are unmapped. [ 440.771298] Workqueue: nvme-wq nvme_rdma_del_ctrl_work [nvme_rdma] [ 440.779104] task: ffff894bae755ee0 ti: ffff893bf9bc8000 task.ti: ffff893bf9bc8000 [ 440.788359] RIP: 0010:[] [] __blk_mq_tag_idle+0x24/0x40 [ 440.798697] RSP: 0018:ffff893bf9bcbd10 EFLAGS: 00010286 [ 440.805538] RAX: 0000000000000000 RBX: ffff895bb131dc00 RCX: 000000000000011f [ 440.814426] RDX: 00000000ffffffff RSI: 0000000000000120 RDI: ffff895bb131dc00 [ 440.823301] RBP: ffff893bf9bcbd10 R08: 000000000001b860 R09: 4a51d361c00c0000 [ 440.832193] R10: b5907f32b4cc7003 R11: ffffd6cabfb57000 R12: ffff894bafd1e008 [ 440.841091] R13: 0000000000000001 R14: ffff895baf770000 R15: 0000000000000080 [ 440.849988] FS: 0000000000000000(0000) GS:ffff894bbdcc0000(0000) knlGS:0000000000000000 [ 440.859955] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 440.867274] CR2: 0000000000000008 CR3: 000000103d098000 CR4: 00000000001407e0 [ 440.876169] Call Trace: [ 440.879818] [] blk_mq_exit_hctx+0xd8/0xe0 [ 440.887051] [] blk_mq_free_queue+0xf0/0x160 [ 440.894465] [] blk_cleanup_queue+0xd9/0x150 [ 440.901881] [] nvme_ns_remove+0x5b/0xb0 [nvme_core] [ 440.910068] [] nvme_remove_namespaces+0x3b/0x60 [nvme_core] [ 440.919026] [] __nvme_rdma_remove_ctrl+0x2b/0xb0 [nvme_rdma] [ 440.928079] [] nvme_rdma_del_ctrl_work+0x17/0x20 [nvme_rdma] [ 440.937126] [] process_one_work+0x17a/0x440 [ 440.944517] [] worker_thread+0x278/0x3c0 [ 440.951607] [] ? manage_workers.isra.24+0x2a0/0x2a0 [ 440.959760] [] kthread+0xcf/0xe0 [ 440.966055] [] ? insert_kthread_work+0x40/0x40 [ 440.973715] [] ret_from_fork+0x58/0x90 [ 440.980586] [] ? insert_kthread_work+0x40/0x40 [ 440.988229] Code: 5b 41 5c 5d c3 66 90 0f 1f 44 00 00 48 8b 87 20 01 00 00 f0 0f ba 77 40 01 19 d2 85 d2 75 08 c3 0f 1f 80 00 00 00 00 55 48 89 e5 ff 48 08 48 8d 78 10 e8 7f 0f 05 00 5d c3 0f 1f 00 66 2e 0f [ 441.011620] RIP [] __blk_mq_tag_idle+0x24/0x40 [ 441.019301] RSP [ 441.024052] CR2: 0000000000000008 Reported-by: Zhang Yi Tested-by: Zhang Yi Signed-off-by: Ming Lei Signed-off-by: Jens Axboe Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index fe24429c6278..5ca4e4cd8cba 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -1592,7 +1592,8 @@ static void blk_mq_exit_hctx(struct request_queue *q, { unsigned flush_start_tag = set->queue_depth; - blk_mq_tag_idle(hctx); + if (blk_mq_hw_queue_mapped(hctx)) + blk_mq_tag_idle(hctx); if (set->ops->exit_request) set->ops->exit_request(set->driver_data, -- GitLab From a74b51be6cf0dec61dccff34358daf7e900dd096 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 3 Jan 2018 10:18:03 -0800 Subject: [PATCH 1250/1834] tty: n_gsm: Allow ADM response in addition to UA for control dlci [ Upstream commit ea3d8465ab9b3e01be329ac5195970a84bef76c5 ] Some devices have the control dlci stay in ADM mode instead of the UA mode. This can seen at least on droid 4 when trying to open the ts 27.010 mux port. Enabling n_gsm debug mode shows the control dlci always respond with DM to SABM instead of UA: # modprobe n_gsm debug=0xff # ldattach -d GSM0710 /dev/ttyS0 & gsmld_output: 00000000: f9 03 3f 01 1c f9 --> 0) C: SABM(P) gsmld_receive: 00000000: f9 03 1f 01 36 f9 <-- 0) C: DM(P) ... $ minicom -D /dev/gsmtty1 minicom: cannot open /dev/gsmtty1: No error information $ strace minicom -D /dev/gsmtty1 ... open("/dev/gsmtty1", O_RDWR|O_NOCTTY|O_NONBLOCK|O_LARGEFILE) = -1 EL2HLT Note that this is different issue from other n_gsm -EL2HLT issues such as timeouts when the control dlci does not respond at all. The ADM mode seems to be a quite common according to "RF Wireless World" article "GSM Issue-UE sends SABM and gets a DM response instead of UA response": This issue is most commonly observed in GSM networks where in UE sends SABM and expects network to send UA response but it ends up receiving DM response from the network. SABM stands for Set asynchronous balanced mode, UA stands for Unnumbered Acknowledge and DA stands for Disconnected Mode. An RLP entity can be in one of two modes: - Asynchronous Balanced Mode (ABM) - Asynchronous Disconnected Mode (ADM) Currently Linux kernel closes the control dlci after several retries in gsm_dlci_t1() on DM. This causes n_gsm /dev/gsmtty ports to produce error code -EL2HLT when trying to open them as the closing of control dlci has already set gsm->dead. Let's fix the issue by allowing control dlci stay in ADM mode after the retries so the /dev/gsmtty ports can be opened and used. It seems that it might take several attempts to get any response from the control dlci, so it's best to allow ADM mode only after the SABM retries are done. Note that for droid 4 additional patches are needed to mux the ttyS0 pins and to toggle RTS gpio_149 to wake up the mdm6600 modem are also needed to use n_gsm. And the mdm6600 modem needs to be powered on. Cc: linux-serial@vger.kernel.org Cc: Alan Cox Cc: Jiri Prchal Cc: Jiri Slaby Cc: Marcel Partap Cc: Michael Scott Cc: Peter Hurley Cc: Russ Gorby Cc: Sascha Hauer Cc: Sebastian Reichel Signed-off-by: Tony Lindgren Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 54cab59e20ed..fe2291795d2f 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1467,6 +1467,10 @@ static void gsm_dlci_open(struct gsm_dlci *dlci) * in which case an opening port goes back to closed and a closing port * is simply put into closed state (any further frames from the other * end will get a DM response) + * + * Some control dlci can stay in ADM mode with other dlci working just + * fine. In that case we can just keep the control dlci open after the + * DLCI_OPENING retries time out. */ static void gsm_dlci_t1(unsigned long data) @@ -1480,8 +1484,15 @@ static void gsm_dlci_t1(unsigned long data) if (dlci->retries) { gsm_command(dlci->gsm, dlci->addr, SABM|PF); mod_timer(&dlci->t1, jiffies + gsm->t1 * HZ / 100); - } else + } else if (!dlci->addr && gsm->control == (DM | PF)) { + if (debug & 8) + pr_info("DLCI %d opening in ADM mode.\n", + dlci->addr); + gsm_dlci_open(dlci); + } else { gsm_dlci_close(dlci); + } + break; case DLCI_CLOSING: dlci->retries--; @@ -1499,8 +1510,8 @@ static void gsm_dlci_t1(unsigned long data) * @dlci: DLCI to open * * Commence opening a DLCI from the Linux side. We issue SABM messages - * to the modem which should then reply with a UA, at which point we - * will move into open state. Opening is done asynchronously with retry + * to the modem which should then reply with a UA or ADM, at which point + * we will move into open state. Opening is done asynchronously with retry * running off timers and the responses. */ -- GitLab From 8c2ba5fafdd9b0fc822f78fce42fc46ef5a2c3af Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 7 Jan 2018 21:54:00 +0100 Subject: [PATCH 1251/1834] EDAC, mv64x60: Fix an error handling path [ Upstream commit 68fa24f9121c04ef146b5158f538c8b32f285be5 ] We should not call edac_mc_del_mc() if a corresponding call to edac_mc_add_mc() has not been performed yet. So here, we should go to err instead of err2 to branch at the right place of the error handling path. Signed-off-by: Christophe JAILLET Cc: linux-edac Link: http://lkml.kernel.org/r/20180107205400.14068-1-christophe.jaillet@wanadoo.fr Signed-off-by: Borislav Petkov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/edac/mv64x60_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index cb9b8577acbc..61c19b81ed81 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c @@ -759,7 +759,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) /* Non-ECC RAM? */ printk(KERN_WARNING "%s: No ECC DIMMs discovered\n", __func__); res = -ENODEV; - goto err2; + goto err; } edac_dbg(3, "init mci\n"); -- GitLab From d774913ba20e86338aedda6fee84351739dc100d Mon Sep 17 00:00:00 2001 From: Arjun Vynipadath Date: Wed, 10 Jan 2018 12:02:13 +0530 Subject: [PATCH 1252/1834] cxgb4vf: Fix SGE FL buffer initialization logic for 64K pages [ Upstream commit ea0a42109aee7b92e631c4eb3f2219fadf58acdd ] We'd come in with SGE_FL_BUFFER_SIZE[0] and [1] both equal to 64KB and the extant logic would flag that as an error. This was already fixed in cxgb4 driver with "92ddcc7 cxgb4: Fix some small bugs in t4_sge_init_soft() when our Page Size is 64KB". Original Work by: Casey Leedom Signed-off-by: Arjun Vynipadath Signed-off-by: Ganesh Goudar Signed-off-by: David S. Miller Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index f3ed9ce99e5e..9d64e8e7c417 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -2616,8 +2616,8 @@ void t4vf_sge_stop(struct adapter *adapter) int t4vf_sge_init(struct adapter *adapter) { struct sge_params *sge_params = &adapter->params.sge; - u32 fl0 = sge_params->sge_fl_buffer_size[0]; - u32 fl1 = sge_params->sge_fl_buffer_size[1]; + u32 fl_small_pg = sge_params->sge_fl_buffer_size[0]; + u32 fl_large_pg = sge_params->sge_fl_buffer_size[1]; struct sge *s = &adapter->sge; /* @@ -2625,9 +2625,20 @@ int t4vf_sge_init(struct adapter *adapter) * the Physical Function Driver. Ideally we should be able to deal * with _any_ configuration. Practice is different ... */ - if (fl0 != PAGE_SIZE || (fl1 != 0 && fl1 <= fl0)) { + + /* We only bother using the Large Page logic if the Large Page Buffer + * is larger than our Page Size Buffer. + */ + if (fl_large_pg <= fl_small_pg) + fl_large_pg = 0; + + /* The Page Size Buffer must be exactly equal to our Page Size and the + * Large Page Size Buffer should be 0 (per above) or a power of 2. + */ + if (fl_small_pg != PAGE_SIZE || + (fl_large_pg & (fl_large_pg - 1)) != 0) { dev_err(adapter->pdev_dev, "bad SGE FL buffer sizes [%d, %d]\n", - fl0, fl1); + fl_small_pg, fl_large_pg); return -EINVAL; } if ((sge_params->sge_control & RXPKTCPLMODE_F) != @@ -2639,8 +2650,8 @@ int t4vf_sge_init(struct adapter *adapter) /* * Now translate the adapter parameters into our internal forms. */ - if (fl1) - s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT; + if (fl_large_pg) + s->fl_pg_order = ilog2(fl_large_pg) - PAGE_SHIFT; s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64); s->pktshift = PKTSHIFT_G(sge_params->sge_control); -- GitLab From 905348d08acd1d35d270f49090c3ac1d2c4bc374 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 11 Jan 2018 15:51:58 +0200 Subject: [PATCH 1253/1834] sdhci: Advertise 2.0v supply on SDIO host controller [ Upstream commit 2a609abe71ca59e4bd7139e161eaca2144ae6f2e ] On Intel Edison the Broadcom Wi-Fi card, which is connected to SDIO, requires 2.0v, while the host, according to Intel Merrifield TRM, supports 1.8v supply only. The card announces itself as mmc2: new ultra high speed DDR50 SDIO card at address 0001 Introduce a custom OCR mask for SDIO host controller on Intel Merrifield and add a special case to sdhci_set_power_noreg() to override 2.0v supply by enforcing 1.8v power choice. Signed-off-by: Andy Shevchenko Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci-pci-core.c | 2 ++ drivers/mmc/host/sdhci.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index b0b9ceb0ab01..cfb794766fea 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -492,6 +492,8 @@ static int intel_mrfld_mmc_probe_slot(struct sdhci_pci_slot *slot) slot->host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V; break; case INTEL_MRFLD_SDIO: + /* Advertise 2.0v for compatibility with the SDIO card's OCR */ + slot->host->ocr_mask = MMC_VDD_20_21 | MMC_VDD_165_195; slot->host->mmc->caps |= MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD; break; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7d275e72903a..44ea9d88651f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1404,6 +1404,13 @@ void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode, if (mode != MMC_POWER_OFF) { switch (1 << vdd) { case MMC_VDD_165_195: + /* + * Without a regulator, SDHCI does not support 2.0v + * so we only get here if the driver deliberately + * added the 2.0v range to ocr_avail. Map it to 1.8v + * for the purpose of turning on the power. + */ + case MMC_VDD_20_21: pwr = SDHCI_POWER_180; break; case MMC_VDD_29_30: -- GitLab From 2a584051aba85f3fbb246c01429df073db3e3f2f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 12 Jan 2018 00:36:48 -0800 Subject: [PATCH 1254/1834] Input: goodix - disable IRQs while suspended [ Upstream commit faec44b6838312484d63e82286087cf2d5ebb891 ] We should not try to do any i2c transfers before the controller is resumed (which happens before our resume method gets called). So we need to disable our IRQ while suspended to enforce this. The code paths for devices with GPIOs for the int and reset pins already disable the IRQ the through goodix_free_irq(). This commit also disables the IRQ while suspended for devices without GPIOs for the int and reset pins. This fixes the i2c bus sometimes getting stuck after a suspend/resume causing the touchscreen to sometimes not work after a suspend/resume. This has been tested on a GPD pocked device. BugLink: https://github.com/nexus511/gpd-ubuntu-packages/issues/10 BugLink: https://www.reddit.com/r/GPDPocket/comments/7niut2/fix_for_broken_touch_after_resume_all_linux/ Tested-by: Hans de Goede Signed-off-by: Hans de Goede Reviewed-by: Bastien Nocera Signed-off-by: Dmitry Torokhov Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/input/touchscreen/goodix.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 240b16f3ee97..5907fddcc966 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -778,8 +778,10 @@ static int __maybe_unused goodix_suspend(struct device *dev) int error; /* We need gpio pins to suspend/resume */ - if (!ts->gpiod_int || !ts->gpiod_rst) + if (!ts->gpiod_int || !ts->gpiod_rst) { + disable_irq(client->irq); return 0; + } wait_for_completion(&ts->firmware_loading_complete); @@ -819,8 +821,10 @@ static int __maybe_unused goodix_resume(struct device *dev) struct goodix_ts_data *ts = i2c_get_clientdata(client); int error; - if (!ts->gpiod_int || !ts->gpiod_rst) + if (!ts->gpiod_int || !ts->gpiod_rst) { + enable_irq(client->irq); return 0; + } /* * Exit sleep mode by outputting HIGH level to INT pin -- GitLab From f6df92f22be342118d2eedbbcc5ca1953aab1a13 Mon Sep 17 00:00:00 2001 From: Miquel Raynal Date: Thu, 11 Jan 2018 21:39:20 +0100 Subject: [PATCH 1255/1834] mtd: mtd_oobtest: Handle bitflips during reads [ Upstream commit 12663b442e5ac5aa3d6097cd3f287c71ba46d26e ] Reads from NAND devices usually trigger bitflips, this is an expected behavior. While bitflips are under a given threshold, the MTD core returns 0. However, when the number of corrected bitflips is above this same threshold, -EUCLEAN is returned to inform the upper layer that this block is slightly dying and soon the ECC engine will be overtaken so actions should be taken to move the data out of it. This particular condition should not be treated like an error and the test should continue. Signed-off-by: Miquel Raynal Signed-off-by: Boris Brezillon Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/tests/oobtest.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 1cb3f7758fb6..766b2c385682 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -193,6 +193,9 @@ static int verify_eraseblock(int ebnum) ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err || ops.oobretlen != use_len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); @@ -227,6 +230,9 @@ static int verify_eraseblock(int ebnum) ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err || ops.oobretlen != mtd->oobavail) { pr_err("error: readoob failed at %#llx\n", (long long)addr); @@ -286,6 +292,9 @@ static int verify_eraseblock_in_one_go(int ebnum) /* read entire block's OOB at one go */ err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err || ops.oobretlen != len) { pr_err("error: readoob failed at %#llx\n", (long long)addr); @@ -527,6 +536,9 @@ static int __init mtd_oobtest_init(void) pr_info("attempting to start read past end of OOB\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, addr0, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) { pr_info("error occurred as expected\n"); err = 0; @@ -571,6 +583,9 @@ static int __init mtd_oobtest_init(void) pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) { pr_info("error occurred as expected\n"); err = 0; @@ -615,6 +630,9 @@ static int __init mtd_oobtest_init(void) pr_info("attempting to read past end of device\n"); pr_info("an error is expected...\n"); err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) { pr_info("error occurred as expected\n"); err = 0; @@ -684,6 +702,9 @@ static int __init mtd_oobtest_init(void) ops.datbuf = NULL; ops.oobbuf = readbuf; err = mtd_read_oob(mtd, addr, &ops); + if (mtd_is_bitflip(err)) + err = 0; + if (err) goto out; if (memcmpshow(addr, readbuf, writebuf, -- GitLab From 720f6277784d5b53bd5bd4195f7d2ff7447f981b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 9 Jan 2018 14:39:23 +0100 Subject: [PATCH 1256/1834] perf tools: Fix copyfile_offset update of output offset [ Upstream commit fa1195ccc0af2d121abe0fe266a1caee8c265eea ] We need to increase output offset in each iteration, not decrease it as we currently do. I guess we were lucky to finish in most cases in first iteration, so the bug never showed. However it shows a lot when working with big (~4GB) size data. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Fixes: 9c9f5a2f1944 ("perf tools: Introduce copyfile_offset() function") Link: http://lkml.kernel.org/r/20180109133923.25406-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index 85c56800f17a..dfb010bd29f2 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c @@ -207,7 +207,7 @@ int copyfile_offset(int ifd, loff_t off_in, int ofd, loff_t off_out, u64 size) size -= ret; off_in += ret; - off_out -= ret; + off_out += ret; } munmap(ptr, off_in + size); -- GitLab From 753b04d213ec51ad3c476510ed87b60a3612d467 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Jun 2017 04:16:23 +0200 Subject: [PATCH 1257/1834] ipsec: check return value of skb_to_sgvec always commit 3f29770723fe498a5c5f57c3a31a996ebdde03e1 upstream. Signed-off-by: Jason A. Donenfeld Cc: Steffen Klassert Cc: Herbert Xu Cc: "David S. Miller" Signed-off-by: David S. Miller [natechancellor: Adjusted context due to lack of fca11ebde3f0] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ah4.c | 8 ++++++-- net/ipv4/esp4.c | 13 ++++++++----- net/ipv6/ah6.c | 8 ++++++-- net/ipv6/esp6.c | 12 ++++++++---- 4 files changed, 28 insertions(+), 13 deletions(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 22377c8ff14b..e8f862358518 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -220,7 +220,9 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); sg_init_table(sg, nfrags + sglists); - skb_to_sgvec_nomark(skb, sg, 0, skb->len); + err = skb_to_sgvec_nomark(skb, sg, 0, skb->len); + if (unlikely(err < 0)) + goto out_free; if (x->props.flags & XFRM_STATE_ESN) { /* Attach seqhi sg right after packet payload */ @@ -393,7 +395,9 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) skb_push(skb, ihl); sg_init_table(sg, nfrags + sglists); - skb_to_sgvec_nomark(skb, sg, 0, skb->len); + err = skb_to_sgvec_nomark(skb, sg, 0, skb->len); + if (unlikely(err < 0)) + goto out_free; if (x->props.flags & XFRM_STATE_ESN) { /* Attach seqhi sg right after packet payload */ diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 20fb25e3027b..3d8021d55336 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -268,10 +268,11 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) esph->spi = x->id.spi; sg_init_table(sg, nfrags); - skb_to_sgvec(skb, sg, - (unsigned char *)esph - skb->data, - assoclen + ivlen + clen + alen); - + err = skb_to_sgvec(skb, sg, + (unsigned char *)esph - skb->data, + assoclen + ivlen + clen + alen); + if (unlikely(err < 0)) + goto error; aead_request_set_crypt(req, sg, sg, ivlen + clen, iv); aead_request_set_ad(req, assoclen); @@ -481,7 +482,9 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb) } sg_init_table(sg, nfrags); - skb_to_sgvec(skb, sg, 0, skb->len); + err = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(err < 0)) + goto out; aead_request_set_crypt(req, sg, sg, elen + ivlen, iv); aead_request_set_ad(req, assoclen); diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 0630a4d5daaa..0edc44cb254e 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -423,7 +423,9 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low); sg_init_table(sg, nfrags + sglists); - skb_to_sgvec_nomark(skb, sg, 0, skb->len); + err = skb_to_sgvec_nomark(skb, sg, 0, skb->len); + if (unlikely(err < 0)) + goto out_free; if (x->props.flags & XFRM_STATE_ESN) { /* Attach seqhi sg right after packet payload */ @@ -603,7 +605,9 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) ip6h->hop_limit = 0; sg_init_table(sg, nfrags + sglists); - skb_to_sgvec_nomark(skb, sg, 0, skb->len); + err = skb_to_sgvec_nomark(skb, sg, 0, skb->len); + if (unlikely(err < 0)) + goto out_free; if (x->props.flags & XFRM_STATE_ESN) { /* Attach seqhi sg right after packet payload */ diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 111ba55fd512..6a924be66e37 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -248,9 +248,11 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) esph->spi = x->id.spi; sg_init_table(sg, nfrags); - skb_to_sgvec(skb, sg, - (unsigned char *)esph - skb->data, - assoclen + ivlen + clen + alen); + err = skb_to_sgvec(skb, sg, + (unsigned char *)esph - skb->data, + assoclen + ivlen + clen + alen); + if (unlikely(err < 0)) + goto error; aead_request_set_crypt(req, sg, sg, ivlen + clen, iv); aead_request_set_ad(req, assoclen); @@ -423,7 +425,9 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb) } sg_init_table(sg, nfrags); - skb_to_sgvec(skb, sg, 0, skb->len); + ret = skb_to_sgvec(skb, sg, 0, skb->len); + if (unlikely(ret < 0)) + goto out; aead_request_set_crypt(req, sg, sg, elen + ivlen, iv); aead_request_set_ad(req, assoclen); -- GitLab From 9a7ba601935c7128bbd711420ccb5423e9ef83ec Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Jun 2017 04:16:24 +0200 Subject: [PATCH 1258/1834] rxrpc: check return value of skb_to_sgvec always commit 89a5ea99662505d2d61f2a3030a6896c2cb3cdb0 upstream. Signed-off-by: Jason A. Donenfeld Acked-by: David Howells Signed-off-by: David S. Miller Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- net/rxrpc/rxkad.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index 4374e7b9c7bf..90df95e18ea4 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -229,7 +229,9 @@ static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call, len &= ~(call->conn->size_align - 1); sg_init_table(sg, nsg); - skb_to_sgvec(skb, sg, 0, len); + err = skb_to_sgvec(skb, sg, 0, len); + if (unlikely(err < 0)) + goto out; skcipher_request_set_crypt(req, sg, sg, len, iv.x); crypto_skcipher_encrypt(req); @@ -325,7 +327,7 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, struct sk_buff *trailer; u32 data_size, buf; u16 check; - int nsg; + int nsg, ret; _enter(""); @@ -342,7 +344,9 @@ static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb, goto nomem; sg_init_table(sg, nsg); - skb_to_sgvec(skb, sg, offset, 8); + ret = skb_to_sgvec(skb, sg, offset, 8); + if (unlikely(ret < 0)) + return ret; /* start the decryption afresh */ memset(&iv, 0, sizeof(iv)); @@ -405,7 +409,7 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, struct sk_buff *trailer; u32 data_size, buf; u16 check; - int nsg; + int nsg, ret; _enter(",{%d}", skb->len); @@ -429,7 +433,12 @@ static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb, } sg_init_table(sg, nsg); - skb_to_sgvec(skb, sg, offset, len); + ret = skb_to_sgvec(skb, sg, offset, len); + if (unlikely(ret < 0)) { + if (sg != _sg) + kfree(sg); + return ret; + } /* decrypt from the session key */ token = call->conn->params.key->payload.data[0]; -- GitLab From 0414cff3e8de1688d694439d366be04d1dacd835 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Sun, 4 Jun 2017 04:16:26 +0200 Subject: [PATCH 1259/1834] virtio_net: check return value of skb_to_sgvec always commit e2fcad58fd230f635a74e4e983c6f4ea893642d2 upstream. Signed-off-by: Jason A. Donenfeld Reviewed-by: Sergei Shtylyov Cc: "Michael S. Tsirkin" Cc: Jason Wang Signed-off-by: David S. Miller Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/net/virtio_net.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1568aedddfc9..0a2f3ac36be2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -831,7 +831,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) struct virtio_net_hdr_mrg_rxbuf *hdr; const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; struct virtnet_info *vi = sq->vq->vdev->priv; - unsigned num_sg; + int num_sg; unsigned hdr_len = vi->hdr_len; bool can_push; @@ -858,11 +858,16 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) if (can_push) { __skb_push(skb, hdr_len); num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; /* Pull header back to avoid skew in tx bytes calculations. */ __skb_pull(skb, hdr_len); } else { sg_set_buf(sq->sg, hdr, hdr_len); - num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1; + num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); + if (unlikely(num_sg < 0)) + return num_sg; + num_sg++; } return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC); } -- GitLab From 32a1f12961b485a02ba84ecddf39c17deeb345d7 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Mon, 9 Apr 2018 18:21:50 -0700 Subject: [PATCH 1260/1834] virtio_net: check return value of skb_to_sgvec in one more location Kernels that do not have f6b10209b90d ("virtio-net: switch to use build_skb() for small buffer") will have an extra call to skb_to_sgvec that is not handled by e2fcad58fd23 ("virtio_net: check return value of skb_to_sgvec always"). Since the former does not appear to be stable material, just fix the call up directly. Cc: Jason A. Donenfeld Cc: Sergei Shtylyov Cc: "Michael S. Tsirkin" Cc: Jason Wang Cc: David S. Miller Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- drivers/net/virtio_net.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0a2f3ac36be2..472ed6df2221 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -529,7 +529,12 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, hdr = skb_vnet_hdr(skb); sg_init_table(rq->sg, 2); sg_set_buf(rq->sg, hdr, vi->hdr_len); - skb_to_sgvec(skb, rq->sg + 1, 0, skb->len); + + err = skb_to_sgvec(skb, rq->sg + 1, 0, skb->len); + if (unlikely(err < 0)) { + dev_kfree_skb(skb); + return err; + } err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp); if (err < 0) -- GitLab From b4d93c6f89688a1e18fc1e4d8c089e163c1ce54f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 7 Jun 2017 19:01:32 -0400 Subject: [PATCH 1261/1834] random: use lockless method of accessing and updating f->reg_idx commit 92e75428ffc90e2a0321062379f883f3671cfebe upstream. Linus pointed out that there is a much more efficient way of avoiding the problem that we were trying to address in commit 9dfa7bba35ac0: "fix race in drivers/char/random.c:get_reg()". Signed-off-by: Theodore Ts'o Cc: Michael Schmitz Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 23f3fb45ff07..0c23ced255cb 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1115,15 +1115,15 @@ static void add_interrupt_bench(cycles_t start) static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs) { __u32 *ptr = (__u32 *) regs; - unsigned long flags; + unsigned int idx; if (regs == NULL) return 0; - local_irq_save(flags); - if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32)) - f->reg_idx = 0; - ptr += f->reg_idx++; - local_irq_restore(flags); + idx = READ_ONCE(f->reg_idx); + if (idx >= sizeof(struct pt_regs) / sizeof(__u32)) + idx = 0; + ptr += idx++; + WRITE_ONCE(f->reg_idx, idx); return *ptr; } -- GitLab From 2f9c90e7ad3314f5207d9fc6d069cc218303199a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 5 Jun 2017 00:02:57 +0200 Subject: [PATCH 1262/1834] clk: at91: fix clk-generated compilation commit 4a5f06a01cfd1f7a9141bdb760bf5b68cca7f224 upstream. Fix missing } Signed-off-by: Alexandre Belloni Signed-off-by: Stephen Boyd Cc: Amit Pundir Signed-off-by: Greg Kroah-Hartman --- drivers/clk/at91/clk-generated.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 70474bd97a10..07c8f701e51c 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -266,6 +266,7 @@ at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock, if (ret) { kfree(gck); hw = ERR_PTR(ret); + } return hw; } -- GitLab From 24123fdee85dfb8fea8b5796e5c481c3a1572d65 Mon Sep 17 00:00:00 2001 From: Miguel Fadon Perlines Date: Thu, 5 Apr 2018 10:25:38 +0200 Subject: [PATCH 1263/1834] arp: fix arp_filter on l3slave devices [ Upstream commit 58b35f27689b5eb514fc293c332966c226b1b6e4 ] arp_filter performs an ip_route_output search for arp source address and checks if output device is the same where the arp request was received, if it is not, the arp request is not answered. This route lookup is always done on main route table so l3slave devices never find the proper route and arp is not answered. Passing l3mdev_master_ifindex_rcu(dev) return value as oif fixes the lookup for l3slave devices while maintaining same behavior for non l3slave devices as this function returns 0 in that case. Fixes: 613d09b30f8b ("net: Use VRF device index for lookups on TX") Signed-off-by: Miguel Fadon Perlines Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/arp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 43bacf65dbab..8cae791a7ace 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -437,7 +437,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) /*unsigned long now; */ struct net *net = dev_net(dev); - rt = ip_route_output(net, sip, tip, 0, 0); + rt = ip_route_output(net, sip, tip, 0, l3mdev_master_ifindex_rcu(dev)); if (IS_ERR(rt)) return 1; if (rt->dst.dev != dev) { -- GitLab From 81eb03e07efccb1ce87e79c3453d35a3f6185e93 Mon Sep 17 00:00:00 2001 From: Paolo Abeni Date: Fri, 23 Mar 2018 14:47:30 +0100 Subject: [PATCH 1264/1834] ipv6: the entire IPv6 header chain must fit the first fragment [ Upstream commit 10b8a3de603df7b96004179b1b33b1708c76d144 ] While building ipv6 datagram we currently allow arbitrary large extheaders, even beyond pmtu size. The syzbot has found a way to exploit the above to trigger the following splat: kernel BUG at ./include/linux/skbuff.h:2073! invalid opcode: 0000 [#1] SMP KASAN Dumping ftrace buffer: (ftrace buffer empty) Modules linked in: CPU: 1 PID: 4230 Comm: syzkaller672661 Not tainted 4.16.0-rc2+ #326 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 RIP: 0010:__skb_pull include/linux/skbuff.h:2073 [inline] RIP: 0010:__ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636 RSP: 0018:ffff8801bc18f0f0 EFLAGS: 00010293 RAX: ffff8801b17400c0 RBX: 0000000000000738 RCX: ffffffff84f01828 RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8801b415ac18 RBP: ffff8801bc18f360 R08: ffff8801b4576844 R09: 0000000000000000 R10: ffff8801bc18f380 R11: ffffed00367aee4e R12: 00000000000000d6 R13: ffff8801b415a740 R14: dffffc0000000000 R15: ffff8801b45767c0 FS: 0000000001535880(0000) GS:ffff8801db300000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000000002000b000 CR3: 00000001b4123001 CR4: 00000000001606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: ip6_finish_skb include/net/ipv6.h:969 [inline] udp_v6_push_pending_frames+0x269/0x3b0 net/ipv6/udp.c:1073 udpv6_sendmsg+0x2a96/0x3400 net/ipv6/udp.c:1343 inet_sendmsg+0x11f/0x5e0 net/ipv4/af_inet.c:764 sock_sendmsg_nosec net/socket.c:630 [inline] sock_sendmsg+0xca/0x110 net/socket.c:640 ___sys_sendmsg+0x320/0x8b0 net/socket.c:2046 __sys_sendmmsg+0x1ee/0x620 net/socket.c:2136 SYSC_sendmmsg net/socket.c:2167 [inline] SyS_sendmmsg+0x35/0x60 net/socket.c:2162 do_syscall_64+0x280/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x4404c9 RSP: 002b:00007ffdce35f948 EFLAGS: 00000217 ORIG_RAX: 0000000000000133 RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 00000000004404c9 RDX: 0000000000000003 RSI: 0000000020001f00 RDI: 0000000000000003 RBP: 00000000006cb018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 0000000020000080 R11: 0000000000000217 R12: 0000000000401df0 R13: 0000000000401e80 R14: 0000000000000000 R15: 0000000000000000 Code: ff e8 1d 5e b9 fc e9 15 e9 ff ff e8 13 5e b9 fc e9 44 e8 ff ff e8 29 5e b9 fc e9 c0 e6 ff ff e8 3f f3 80 fc 0f 0b e8 38 f3 80 fc <0f> 0b 49 8d 87 80 00 00 00 4d 8d 87 84 00 00 00 48 89 85 20 fe RIP: __skb_pull include/linux/skbuff.h:2073 [inline] RSP: ffff8801bc18f0f0 RIP: __ip6_make_skb+0x1ac8/0x2190 net/ipv6/ip6_output.c:1636 RSP: ffff8801bc18f0f0 As stated by RFC 7112 section 5: When a host fragments an IPv6 datagram, it MUST include the entire IPv6 Header Chain in the First Fragment. So this patch addresses the issue dropping datagrams with excessive extheader length. It also updates the error path to report to the calling socket nonnegative pmtu values. The issue apparently predates git history. v1 -> v2: cleanup error path, as per Eric's suggestion Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: syzbot+91e6f9932ff122fa4410@syzkaller.appspotmail.com Signed-off-by: Paolo Abeni Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2e3db3619858..f0d103413a36 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1291,7 +1291,7 @@ static int __ip6_append_data(struct sock *sk, const struct sockcm_cookie *sockc) { struct sk_buff *skb, *skb_prev = NULL; - unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; + unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu, pmtu; int exthdrlen = 0; int dst_exthdrlen = 0; int hh_len; @@ -1327,6 +1327,12 @@ static int __ip6_append_data(struct sock *sk, sizeof(struct frag_hdr) : 0) + rt->rt6i_nfheader_len; + /* as per RFC 7112 section 5, the entire IPv6 Header Chain must fit + * the first fragment + */ + if (headersize + transhdrlen > mtu) + goto emsgsize; + if (cork->length + length > mtu - headersize && ipc6->dontfrag && (sk->sk_protocol == IPPROTO_UDP || sk->sk_protocol == IPPROTO_RAW)) { @@ -1342,9 +1348,8 @@ static int __ip6_append_data(struct sock *sk, if (cork->length + length > maxnonfragsize - headersize) { emsgsize: - ipv6_local_error(sk, EMSGSIZE, fl6, - mtu - headersize + - sizeof(struct ipv6hdr)); + pmtu = max_t(int, mtu - headersize + sizeof(struct ipv6hdr), 0); + ipv6_local_error(sk, EMSGSIZE, fl6, pmtu); return -EMSGSIZE; } -- GitLab From fb9fa142d45bbbb968b99bd1c0959dd40b4cc9f4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 26 Mar 2018 08:08:07 -0700 Subject: [PATCH 1265/1834] net: fix possible out-of-bound read in skb_network_protocol() [ Upstream commit 1dfe82ebd7d8fd43dba9948fdfb31f145014baa0 ] skb mac header is not necessarily set at the time skb_network_protocol() is called. Use skb->data instead. BUG: KASAN: slab-out-of-bounds in skb_network_protocol+0x46b/0x4b0 net/core/dev.c:2739 Read of size 2 at addr ffff8801b3097a0b by task syz-executor5/14242 CPU: 1 PID: 14242 Comm: syz-executor5 Not tainted 4.16.0-rc6+ #280 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x194/0x24d lib/dump_stack.c:53 print_address_description+0x73/0x250 mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report+0x23c/0x360 mm/kasan/report.c:412 __asan_report_load_n_noabort+0xf/0x20 mm/kasan/report.c:443 skb_network_protocol+0x46b/0x4b0 net/core/dev.c:2739 harmonize_features net/core/dev.c:2924 [inline] netif_skb_features+0x509/0x9b0 net/core/dev.c:3011 validate_xmit_skb+0x81/0xb00 net/core/dev.c:3084 validate_xmit_skb_list+0xbf/0x120 net/core/dev.c:3142 packet_direct_xmit+0x117/0x790 net/packet/af_packet.c:256 packet_snd net/packet/af_packet.c:2944 [inline] packet_sendmsg+0x3aed/0x60b0 net/packet/af_packet.c:2969 sock_sendmsg_nosec net/socket.c:629 [inline] sock_sendmsg+0xca/0x110 net/socket.c:639 ___sys_sendmsg+0x767/0x8b0 net/socket.c:2047 __sys_sendmsg+0xe5/0x210 net/socket.c:2081 Fixes: 19acc327258a ("gso: Handle Trans-Ether-Bridging protocol in skb_network_protocol()") Signed-off-by: Eric Dumazet Cc: Pravin B Shelar Reported-by: Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 07d2c93c9636..1259587370b8 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2667,7 +2667,7 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) return 0; - eth = (struct ethhdr *)skb_mac_header(skb); + eth = (struct ethhdr *)skb->data; type = eth->h_proto; } -- GitLab From eb3dd0f9fedef46620c75818af56213df1935e42 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 29 Mar 2018 17:44:57 -0700 Subject: [PATCH 1266/1834] net/ipv6: Fix route leaking between VRFs [ Upstream commit b6cdbc85234b072340b8923e69f49ec293f905dc ] Donald reported that IPv6 route leaking between VRFs is not working. The root cause is the strict argument in the call to rt6_lookup when validating the nexthop spec. ip6_route_check_nh validates the gateway and device (if given) of a route spec. It in turn could call rt6_lookup (e.g., lookup in a given table did not succeed so it falls back to a full lookup) and if so sets the strict argument to 1. That means if the egress device is given, the route lookup needs to return a result with the same device. This strict requirement does not work with VRFs (IPv4 or IPv6) because the oif in the flow struct is overridden with the index of the VRF device to trigger a match on the l3mdev rule and force the lookup to its table. The right long term solution is to add an l3mdev index to the flow struct such that the oif is not overridden. That solution will not backport well, so this patch aims for a simpler solution to relax the strict argument if the route spec device is an l3mdev slave. As done in other places, use the FLOWI_FLAG_SKIP_NH_OIF to know that the RT6_LOOKUP_F_IFACE flag needs to be removed. Fixes: ca254490c8df ("net: Add VRF support to IPv6 stack") Reported-by: Donald Sharp Signed-off-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/route.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a8f80bd20c55..d6a4b2c73a7c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -856,6 +856,9 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, struct fib6_node *fn; struct rt6_info *rt; + if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) + flags &= ~RT6_LOOKUP_F_IFACE; + read_lock_bh(&table->tb6_lock); fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); restart: -- GitLab From 584d541c12157989af1491b007721e18ea0503c1 Mon Sep 17 00:00:00 2001 From: Jeff Barnhill <0xeffeff@gmail.com> Date: Thu, 5 Apr 2018 21:29:47 +0000 Subject: [PATCH 1267/1834] net/ipv6: Increment OUTxxx counters after netfilter hook [ Upstream commit 71a1c915238c970cd9bdd5bf158b1279d6b6d55b ] At the end of ip6_forward(), IPSTATS_MIB_OUTFORWDATAGRAMS and IPSTATS_MIB_OUTOCTETS are incremented immediately before the NF_HOOK call for NFPROTO_IPV6 / NF_INET_FORWARD. As a result, these counters get incremented regardless of whether or not the netfilter hook allows the packet to continue being processed. This change increments the counters in ip6_forward_finish() so that it will not happen if the netfilter hook chooses to terminate the packet, which is similar to how IPv4 works. Signed-off-by: Jeff Barnhill <0xeffeff@gmail.com> Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_output.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index f0d103413a36..58a6eeeacbf7 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -356,6 +356,11 @@ static int ip6_forward_proxy_check(struct sk_buff *skb) static inline int ip6_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) { + struct dst_entry *dst = skb_dst(skb); + + __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); + __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); + return dst_output(net, sk, skb); } @@ -549,8 +554,6 @@ int ip6_forward(struct sk_buff *skb) hdr->hop_limit--; - __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); - __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, net, NULL, skb, skb->dev, dst->dev, ip6_forward_finish); -- GitLab From cf10533553686617e2b76a84d21764a81e3692da Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Fri, 23 Mar 2018 13:49:02 +0100 Subject: [PATCH 1268/1834] netlink: make sure nladdr has correct size in netlink_connect() [ Upstream commit 7880287981b60a6808f39f297bb66936e8bdf57a ] KMSAN reports use of uninitialized memory in the case when |alen| is smaller than sizeof(struct sockaddr_nl), and therefore |nladdr| isn't fully copied from the userspace. Signed-off-by: Alexander Potapenko Fixes: 1da177e4c3f41524 ("Linux-2.6.12-rc2") Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/netlink/af_netlink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index c1f59a06da6f..1e97b8d9a159 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1054,6 +1054,9 @@ static int netlink_connect(struct socket *sock, struct sockaddr *addr, if (addr->sa_family != AF_NETLINK) return -EINVAL; + if (alen < sizeof(struct sockaddr_nl)) + return -EINVAL; + if ((nladdr->nl_groups || nladdr->nl_pid) && !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) return -EPERM; -- GitLab From 44c8871e421c41572ea4a0c62694b3b6d07373f5 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 6 Apr 2018 01:19:37 +0200 Subject: [PATCH 1269/1834] net/sched: fix NULL dereference in the error path of tcf_bpf_init() [ Upstream commit 3239534a79ee6f20cffd974173a1e62e0730e8ac ] when tcf_bpf_init_from_ops() fails (e.g. because of program having invalid number of instructions), tcf_bpf_cfg_cleanup() calls bpf_prog_put(NULL) or bpf_prog_destroy(NULL). Unless CONFIG_BPF_SYSCALL is unset, this causes the following error: BUG: unable to handle kernel NULL pointer dereference at 0000000000000020 PGD 800000007345a067 P4D 800000007345a067 PUD 340e1067 PMD 0 Oops: 0000 [#1] SMP PTI Modules linked in: act_bpf(E) ip6table_filter ip6_tables iptable_filter binfmt_misc ext4 mbcache jbd2 crct10dif_pclmul crc32_pclmul ghash_clmulni_intel snd_hda_codec_generic pcbc snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_seq snd_seq_device snd_pcm aesni_intel crypto_simd glue_helper cryptd joydev snd_timer snd virtio_balloon pcspkr soundcore i2c_piix4 nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c ata_generic pata_acpi qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm virtio_blk drm virtio_net virtio_console i2c_core crc32c_intel serio_raw virtio_pci ata_piix libata virtio_ring floppy virtio dm_mirror dm_region_hash dm_log dm_mod [last unloaded: act_bpf] CPU: 3 PID: 5654 Comm: tc Tainted: G E 4.16.0.bpf_test+ #408 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:__bpf_prog_put+0xc/0xc0 RSP: 0018:ffff9594003ef728 EFLAGS: 00010202 RAX: 0000000000000000 RBX: ffff9594003ef758 RCX: 0000000000000024 RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000044 R10: 0000000000000220 R11: ffff8a7ab9f17131 R12: 0000000000000000 R13: ffff8a7ab7c3c8e0 R14: 0000000000000001 R15: ffff8a7ab88f1054 FS: 00007fcb2f17c740(0000) GS:ffff8a7abfd80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000020 CR3: 000000007c888006 CR4: 00000000001606e0 Call Trace: tcf_bpf_cfg_cleanup+0x2f/0x40 [act_bpf] tcf_bpf_cleanup+0x4c/0x70 [act_bpf] __tcf_idr_release+0x79/0x140 tcf_bpf_init+0x125/0x330 [act_bpf] tcf_action_init_1+0x2cc/0x430 ? get_page_from_freelist+0x3f0/0x11b0 tcf_action_init+0xd3/0x1b0 tc_ctl_action+0x18b/0x240 rtnetlink_rcv_msg+0x29c/0x310 ? _cond_resched+0x15/0x30 ? __kmalloc_node_track_caller+0x1b9/0x270 ? rtnl_calcit.isra.29+0x100/0x100 netlink_rcv_skb+0xd2/0x110 netlink_unicast+0x17c/0x230 netlink_sendmsg+0x2cd/0x3c0 sock_sendmsg+0x30/0x40 ___sys_sendmsg+0x27a/0x290 ? mem_cgroup_commit_charge+0x80/0x130 ? page_add_new_anon_rmap+0x73/0xc0 ? do_anonymous_page+0x2a2/0x560 ? __handle_mm_fault+0xc75/0xe20 __sys_sendmsg+0x58/0xa0 do_syscall_64+0x6e/0x1a0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7fcb2e58eba0 RSP: 002b:00007ffc93c496c8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007ffc93c497f0 RCX: 00007fcb2e58eba0 RDX: 0000000000000000 RSI: 00007ffc93c49740 RDI: 0000000000000003 RBP: 000000005ac6a646 R08: 0000000000000002 R09: 0000000000000000 R10: 00007ffc93c49120 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffc93c49804 R14: 0000000000000001 R15: 000000000066afa0 Code: 5f 00 48 8b 43 20 48 c7 c7 70 2f 7c b8 c7 40 10 00 00 00 00 5b e9 a5 8b 61 00 0f 1f 44 00 00 0f 1f 44 00 00 41 54 55 48 89 fd 53 <48> 8b 47 20 f0 ff 08 74 05 5b 5d 41 5c c3 41 89 f4 0f 1f 44 00 RIP: __bpf_prog_put+0xc/0xc0 RSP: ffff9594003ef728 CR2: 0000000000000020 Fix it in tcf_bpf_cfg_cleanup(), ensuring that bpf_prog_{put,destroy}(f) is called only when f is not NULL. Fixes: bbc09e7842a5 ("net/sched: fix idr leak on the error path of tcf_bpf_init()") Reported-by: Lucas Bates Signed-off-by: Davide Caratti Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_bpf.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 1d3960033f61..40496f34bdb3 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -245,10 +245,14 @@ static int tcf_bpf_init_from_efd(struct nlattr **tb, struct tcf_bpf_cfg *cfg) static void tcf_bpf_cfg_cleanup(const struct tcf_bpf_cfg *cfg) { - if (cfg->is_ebpf) - bpf_prog_put(cfg->filter); - else - bpf_prog_destroy(cfg->filter); + struct bpf_prog *filter = cfg->filter; + + if (filter) { + if (cfg->is_ebpf) + bpf_prog_put(filter); + else + bpf_prog_destroy(filter); + } kfree(cfg->bpf_ops); kfree(cfg->bpf_name); -- GitLab From 765884bc645b142bbac3c18a08d06237cbd05a73 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 2 Apr 2018 18:48:37 -0700 Subject: [PATCH 1270/1834] pptp: remove a buggy dst release in pptp_connect() [ Upstream commit bfacfb457b36911a10140b8cb3ce76a74883ac5a ] Once dst has been cached in socket via sk_setup_caps(), it is illegal to call ip_rt_put() (or dst_release()), since sk_setup_caps() did not change dst refcount. We can still dereference it since we hold socket lock. Caugth by syzbot : BUG: KASAN: use-after-free in atomic_dec_return include/asm-generic/atomic-instrumented.h:198 [inline] BUG: KASAN: use-after-free in dst_release+0x27/0xa0 net/core/dst.c:185 Write of size 4 at addr ffff8801c54dc040 by task syz-executor4/20088 CPU: 1 PID: 20088 Comm: syz-executor4 Not tainted 4.16.0+ #376 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1a7/0x27d lib/dump_stack.c:53 print_address_description+0x73/0x250 mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report+0x23c/0x360 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x137/0x190 mm/kasan/kasan.c:267 kasan_check_write+0x14/0x20 mm/kasan/kasan.c:278 atomic_dec_return include/asm-generic/atomic-instrumented.h:198 [inline] dst_release+0x27/0xa0 net/core/dst.c:185 sk_dst_set include/net/sock.h:1812 [inline] sk_dst_reset include/net/sock.h:1824 [inline] sock_setbindtodevice net/core/sock.c:610 [inline] sock_setsockopt+0x431/0x1b20 net/core/sock.c:707 SYSC_setsockopt net/socket.c:1845 [inline] SyS_setsockopt+0x2ff/0x360 net/socket.c:1828 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 RIP: 0033:0x4552d9 RSP: 002b:00007f4878126c68 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 RAX: ffffffffffffffda RBX: 00007f48781276d4 RCX: 00000000004552d9 RDX: 0000000000000019 RSI: 0000000000000001 RDI: 0000000000000013 RBP: 000000000072bea0 R08: 0000000000000010 R09: 0000000000000000 R10: 00000000200010c0 R11: 0000000000000246 R12: 00000000ffffffff R13: 0000000000000526 R14: 00000000006fac30 R15: 0000000000000000 Allocated by task 20088: save_stack+0x43/0xd0 mm/kasan/kasan.c:447 set_track mm/kasan/kasan.c:459 [inline] kasan_kmalloc+0xad/0xe0 mm/kasan/kasan.c:552 kasan_slab_alloc+0x12/0x20 mm/kasan/kasan.c:489 kmem_cache_alloc+0x12e/0x760 mm/slab.c:3542 dst_alloc+0x11f/0x1a0 net/core/dst.c:104 rt_dst_alloc+0xe9/0x540 net/ipv4/route.c:1520 __mkroute_output net/ipv4/route.c:2265 [inline] ip_route_output_key_hash_rcu+0xa49/0x2c60 net/ipv4/route.c:2493 ip_route_output_key_hash+0x20b/0x370 net/ipv4/route.c:2322 __ip_route_output_key include/net/route.h:126 [inline] ip_route_output_flow+0x26/0xa0 net/ipv4/route.c:2577 ip_route_output_ports include/net/route.h:163 [inline] pptp_connect+0xa84/0x1170 drivers/net/ppp/pptp.c:453 SYSC_connect+0x213/0x4a0 net/socket.c:1639 SyS_connect+0x24/0x30 net/socket.c:1620 do_syscall_64+0x281/0x940 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Freed by task 20082: save_stack+0x43/0xd0 mm/kasan/kasan.c:447 set_track mm/kasan/kasan.c:459 [inline] __kasan_slab_free+0x11a/0x170 mm/kasan/kasan.c:520 kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:527 __cache_free mm/slab.c:3486 [inline] kmem_cache_free+0x83/0x2a0 mm/slab.c:3744 dst_destroy+0x266/0x380 net/core/dst.c:140 dst_destroy_rcu+0x16/0x20 net/core/dst.c:153 __rcu_reclaim kernel/rcu/rcu.h:178 [inline] rcu_do_batch kernel/rcu/tree.c:2675 [inline] invoke_rcu_callbacks kernel/rcu/tree.c:2930 [inline] __rcu_process_callbacks kernel/rcu/tree.c:2897 [inline] rcu_process_callbacks+0xd6c/0x17b0 kernel/rcu/tree.c:2914 __do_softirq+0x2d7/0xb85 kernel/softirq.c:285 The buggy address belongs to the object at ffff8801c54dc000 which belongs to the cache ip_dst_cache of size 168 The buggy address is located 64 bytes inside of 168-byte region [ffff8801c54dc000, ffff8801c54dc0a8) The buggy address belongs to the page: page:ffffea0007153700 count:1 mapcount:0 mapping:ffff8801c54dc000 index:0x0 flags: 0x2fffc0000000100(slab) raw: 02fffc0000000100 ffff8801c54dc000 0000000000000000 0000000100000010 raw: ffffea0006b34b20 ffffea0006b6c1e0 ffff8801d674a1c0 0000000000000000 page dumped because: kasan: bad access detected Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ppp/pptp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 1951b1085cb8..3045c9662ed6 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -465,7 +465,6 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr, po->chan.mtu = dst_mtu(&rt->dst); if (!po->chan.mtu) po->chan.mtu = PPP_MRU; - ip_rt_put(rt); po->chan.mtu -= PPTP_HEADER_OVERHEAD; po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header); -- GitLab From 360e1e58f3fa7fe4eb266ebc0ae1690e0d1e372b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Mon, 26 Mar 2018 19:19:30 +0200 Subject: [PATCH 1271/1834] r8169: fix setting driver_data after register_netdev [ Upstream commit 19c9ea363a244f85f90a424f9936e6d56449e33c ] pci_set_drvdata() is called only after registering the net_device, therefore we could run into a NPE if one of the functions using driver_data is called before it's set. Fix this by calling pci_set_drvdata() before registering the net_device. This fix is a candidate for stable. As far as I can see the bug has been there in kernel version 3.2 already, therefore I can't provide a reference which commit is fixed by it. The fix may need small adjustments per kernel version because due to other changes the label which is jumped to if register_netdev() fails has changed over time. Reported-by: David Miller Signed-off-by: Heiner Kallweit Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/realtek/r8169.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 18e68c91e651..dbb63640bc6e 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -8446,12 +8446,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_msi_5; } + pci_set_drvdata(pdev, dev); + rc = register_netdev(dev); if (rc < 0) goto err_out_cnt_6; - pci_set_drvdata(pdev, dev); - netif_info(tp, probe, dev, "%s at 0x%p, %pM, XID %08x IRQ %d\n", rtl_chip_infos[chipset].name, ioaddr, dev->dev_addr, (u32)(RTL_R32(TxConfig) & 0x9cf0f8ff), pdev->irq); -- GitLab From 2cd9afc8b75abd60939890b5af50372c07d92ee4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sat, 7 Apr 2018 17:15:22 -0700 Subject: [PATCH 1272/1834] sctp: do not leak kernel memory to user space [ Upstream commit 6780db244d6b1537d139dea0ec8aad10cf9e4adb ] syzbot produced a nice report [1] Issue here is that a recvmmsg() managed to leak 8 bytes of kernel memory to user space, because sin_zero (padding field) was not properly cleared. [1] BUG: KMSAN: uninit-value in copy_to_user include/linux/uaccess.h:184 [inline] BUG: KMSAN: uninit-value in move_addr_to_user+0x32e/0x530 net/socket.c:227 CPU: 1 PID: 3586 Comm: syzkaller481044 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 kmsan_internal_check_memory+0x164/0x1d0 mm/kmsan/kmsan.c:1176 kmsan_copy_to_user+0x69/0x160 mm/kmsan/kmsan.c:1199 copy_to_user include/linux/uaccess.h:184 [inline] move_addr_to_user+0x32e/0x530 net/socket.c:227 ___sys_recvmsg+0x4e2/0x810 net/socket.c:2211 __sys_recvmmsg+0x54e/0xdb0 net/socket.c:2313 SYSC_recvmmsg+0x29b/0x3e0 net/socket.c:2394 SyS_recvmmsg+0x76/0xa0 net/socket.c:2378 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x4401c9 RSP: 002b:00007ffc56f73098 EFLAGS: 00000217 ORIG_RAX: 000000000000012b RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 00000000004401c9 RDX: 0000000000000001 RSI: 0000000020003ac0 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 0000000020003bc0 R09: 0000000000000010 R10: 0000000000000000 R11: 0000000000000217 R12: 0000000000401af0 R13: 0000000000401b80 R14: 0000000000000000 R15: 0000000000000000 Local variable description: ----addr@___sys_recvmsg Variable was created at: ___sys_recvmsg+0xd5/0x810 net/socket.c:2172 __sys_recvmmsg+0x54e/0xdb0 net/socket.c:2313 Bytes 8-15 of 16 are uninitialized ================================================================== Kernel panic - not syncing: panic_on_warn set ... CPU: 1 PID: 3586 Comm: syzkaller481044 Tainted: G B 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 panic+0x39d/0x940 kernel/panic.c:183 kmsan_report+0x238/0x240 mm/kmsan/kmsan.c:1083 kmsan_internal_check_memory+0x164/0x1d0 mm/kmsan/kmsan.c:1176 kmsan_copy_to_user+0x69/0x160 mm/kmsan/kmsan.c:1199 copy_to_user include/linux/uaccess.h:184 [inline] move_addr_to_user+0x32e/0x530 net/socket.c:227 ___sys_recvmsg+0x4e2/0x810 net/socket.c:2211 __sys_recvmmsg+0x54e/0xdb0 net/socket.c:2313 SYSC_recvmmsg+0x29b/0x3e0 net/socket.c:2394 SyS_recvmmsg+0x76/0xa0 net/socket.c:2378 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Cc: Vlad Yasevich Cc: Neil Horman Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/ipv6.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 11f69d4c5619..355d95a7cd81 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -727,8 +727,10 @@ static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) sctp_v6_map_v4(addr); } - if (addr->sa.sa_family == AF_INET) + if (addr->sa.sa_family == AF_INET) { + memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero)); return sizeof(struct sockaddr_in); + } return sizeof(struct sockaddr_in6); } -- GitLab From 16002a42da497ad78c14a880da1cab49bd80024f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 8 Apr 2018 07:52:08 -0700 Subject: [PATCH 1273/1834] sctp: sctp_sockaddr_af must check minimal addr length for AF_INET6 [ Upstream commit 81e98370293afcb58340ce8bd71af7b97f925c26 ] Check must happen before call to ipv6_addr_v4mapped() syzbot report was : BUG: KMSAN: uninit-value in sctp_sockaddr_af net/sctp/socket.c:359 [inline] BUG: KMSAN: uninit-value in sctp_do_bind+0x60f/0xdc0 net/sctp/socket.c:384 CPU: 0 PID: 3576 Comm: syzkaller968804 Not tainted 4.16.0+ #82 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x185/0x1d0 lib/dump_stack.c:53 kmsan_report+0x142/0x240 mm/kmsan/kmsan.c:1067 __msan_warning_32+0x6c/0xb0 mm/kmsan/kmsan_instr.c:676 sctp_sockaddr_af net/sctp/socket.c:359 [inline] sctp_do_bind+0x60f/0xdc0 net/sctp/socket.c:384 sctp_bind+0x149/0x190 net/sctp/socket.c:332 inet6_bind+0x1fd/0x1820 net/ipv6/af_inet6.c:293 SYSC_bind+0x3f2/0x4b0 net/socket.c:1474 SyS_bind+0x54/0x80 net/socket.c:1460 do_syscall_64+0x309/0x430 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x43fd49 RSP: 002b:00007ffe99df3d28 EFLAGS: 00000213 ORIG_RAX: 0000000000000031 RAX: ffffffffffffffda RBX: 00000000004002c8 RCX: 000000000043fd49 RDX: 0000000000000010 RSI: 0000000020000000 RDI: 0000000000000003 RBP: 00000000006ca018 R08: 00000000004002c8 R09: 00000000004002c8 R10: 00000000004002c8 R11: 0000000000000213 R12: 0000000000401670 R13: 0000000000401700 R14: 0000000000000000 R15: 0000000000000000 Local variable description: ----address@SYSC_bind Variable was created at: SYSC_bind+0x6f/0x4b0 net/socket.c:1461 SyS_bind+0x54/0x80 net/socket.c:1460 Signed-off-by: Eric Dumazet Cc: Vlad Yasevich Cc: Neil Horman Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sctp/socket.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 172465b7c0f4..78f38056fca6 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -335,11 +335,14 @@ static struct sctp_af *sctp_sockaddr_af(struct sctp_sock *opt, if (!opt->pf->af_supported(addr->sa.sa_family, opt)) return NULL; - /* V4 mapped address are really of AF_INET family */ - if (addr->sa.sa_family == AF_INET6 && - ipv6_addr_v4mapped(&addr->v6.sin6_addr) && - !opt->pf->af_supported(AF_INET, opt)) - return NULL; + if (addr->sa.sa_family == AF_INET6) { + if (len < SIN6_LEN_RFC2133) + return NULL; + /* V4 mapped address are really of AF_INET family */ + if (ipv6_addr_v4mapped(&addr->v6.sin6_addr) && + !opt->pf->af_supported(AF_INET, opt)) + return NULL; + } /* If we get this far, af is valid. */ af = sctp_get_af_specific(addr->sa.sa_family); -- GitLab From 10200c71c411a451eec56d32dbcc29cdd940786e Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Sat, 31 Mar 2018 23:42:03 +0800 Subject: [PATCH 1274/1834] sky2: Increase D3 delay to sky2 stops working after suspend [ Upstream commit afb133637071be6deeb8b3d0e55593ffbf63c527 ] The sky2 ethernet stops working after system resume from suspend: [ 582.852065] sky2 0000:04:00.0: Refused to change power state, currently in D3 The current 150ms delay is not enough, change it to 200ms can solve the issue. BugLink: https://bugs.launchpad.net/bugs/1758507 Cc: Stable Signed-off-by: Kai-Heng Feng Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/marvell/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 941c8e2c944e..93ab0b3ad393 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -5079,7 +5079,7 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) INIT_WORK(&hw->restart_work, sky2_restart); pci_set_drvdata(pdev, hw); - pdev->d3_delay = 150; + pdev->d3_delay = 200; return 0; -- GitLab From 827148d08d43bce95fda03b462e213fc0094c8b1 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 27 Mar 2018 20:50:52 +0800 Subject: [PATCH 1275/1834] vhost: correctly remove wait queue during poll failure [ Upstream commit dc6455a71c7fc5117977e197f67f71b49f27baba ] We tried to remove vq poll from wait queue, but do not check whether or not it was in a list before. This will lead double free. Fixing this by switching to use vhost_poll_stop() which zeros poll->wqh after removing poll from waitqueue to make sure it won't be freed twice. Cc: Darren Kenny Reported-by: syzbot+c0272972b01b872e604a@syzkaller.appspotmail.com Fixes: 2b8b328b61c79 ("vhost_net: handle polling errors when setting backend") Signed-off-by: Jason Wang Reviewed-by: Darren Kenny Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index cd38f5add254..126730384d7d 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -211,8 +211,7 @@ int vhost_poll_start(struct vhost_poll *poll, struct file *file) if (mask) vhost_poll_wakeup(&poll->wait, 0, 0, (void *)mask); if (mask & POLLERR) { - if (poll->wqh) - remove_wait_queue(poll->wqh, &poll->wait); + vhost_poll_stop(poll); ret = -EINVAL; } -- GitLab From 2463af64c2b445e10e0c3f5a2f4c4db49dabc114 Mon Sep 17 00:00:00 2001 From: Hangbin Liu Date: Fri, 30 Mar 2018 09:44:00 +0800 Subject: [PATCH 1276/1834] vlan: also check phy_driver ts_info for vlan's real device [ Upstream commit ec1d8ccb07deaf30fd0508af6755364ac47dc08d ] Just like function ethtool_get_ts_info(), we should also consider the phy_driver ts_info call back. For example, driver dp83640. Fixes: 37dd9255b2f6 ("vlan: Pass ethtool get_ts_info queries to real device.") Acked-by: Richard Cochran Signed-off-by: Hangbin Liu Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/8021q/vlan_dev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 767144128b95..fb3e2a50d76e 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -658,8 +659,11 @@ static int vlan_ethtool_get_ts_info(struct net_device *dev, { const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); const struct ethtool_ops *ops = vlan->real_dev->ethtool_ops; + struct phy_device *phydev = vlan->real_dev->phydev; - if (ops->get_ts_info) { + if (phydev && phydev->drv && phydev->drv->ts_info) { + return phydev->drv->ts_info(phydev, info); + } else if (ops->get_ts_info) { return ops->get_ts_info(vlan->real_dev, info); } else { info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE | -- GitLab From f611a5e1433f71989d3d9846964e91cfb0c1ba01 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:16:45 +0800 Subject: [PATCH 1277/1834] bonding: fix the err path for dev hwaddr sync in bond_enslave [ Upstream commit 5c78f6bfae2b10ff70e21d343e64584ea6280c26 ] vlan_vids_add_by_dev is called right after dev hwaddr sync, so on the err path it should unsync dev hwaddr. Otherwise, the slave dev's hwaddr will never be unsync when this err happens. Fixes: 1ff412ad7714 ("bonding: change the bond's vlan syncing functions with the standard ones") Signed-off-by: Xin Long Reviewed-by: Nikolay Aleksandrov Acked-by: Andy Gospodarek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index fb1141f7f6b5..64f2a3f3279f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1561,7 +1561,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (res) { netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", slave_dev->name); - goto err_close; + goto err_hwaddr_unsync; } prev_slave = bond_last_slave(bond); @@ -1749,9 +1749,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) netdev_rx_handler_unregister(slave_dev); err_detach: - if (!bond_uses_primary(bond)) - bond_hw_addr_flush(bond_dev, slave_dev); - vlan_vids_del_by_dev(slave_dev, bond_dev); if (rcu_access_pointer(bond->primary_slave) == new_slave) RCU_INIT_POINTER(bond->primary_slave, NULL); @@ -1765,6 +1762,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) synchronize_rcu(); slave_disable_netpoll(new_slave); +err_hwaddr_unsync: + if (!bond_uses_primary(bond)) + bond_hw_addr_flush(bond_dev, slave_dev); + err_close: slave_dev->priv_flags &= ~IFF_BONDING; dev_close(slave_dev); -- GitLab From d6d65b4c8fd700be97bd24980bc0bde9b0c55109 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:16:46 +0800 Subject: [PATCH 1278/1834] bonding: move dev_mc_sync after master_upper_dev_link in bond_enslave [ Upstream commit ae42cc62a9f07f1f6979054ed92606b9c30f4a2e ] Beniamino found a crash when adding vlan as slave of bond which is also the parent link: ip link add bond1 type bond ip link set bond1 up ip link add link bond1 vlan1 type vlan id 80 ip link set vlan1 master bond1 The call trace is as below: [] queued_spin_lock_slowpath+0xb/0xf [] _raw_spin_lock+0x20/0x30 [] dev_mc_sync+0x37/0x80 [] vlan_dev_set_rx_mode+0x1c/0x30 [8021q] [] __dev_set_rx_mode+0x5a/0xa0 [] dev_mc_sync_multiple+0x78/0x80 [] bond_enslave+0x67c/0x1190 [bonding] [] do_setlink+0x9c9/0xe50 [] rtnl_newlink+0x522/0x880 [] rtnetlink_rcv_msg+0xa7/0x260 [] netlink_rcv_skb+0xab/0xc0 [] rtnetlink_rcv+0x28/0x30 [] netlink_unicast+0x170/0x210 [] netlink_sendmsg+0x308/0x420 [] sock_sendmsg+0xb6/0xf0 This is actually a dead lock caused by sync slave hwaddr from master when the master is the slave's 'slave'. This dead loop check is actually done by netdev_master_upper_dev_link. However, Commit 1f718f0f4f97 ("bonding: populate neighbour's private on enslave") moved it after dev_mc_sync. This patch is to fix it by moving dev_mc_sync after master_upper_dev_link, so that this loop check would be earlier than dev_mc_sync. It also moves if (mode == BOND_MODE_8023AD) into if (!bond_uses_primary) clause as an improvement. Note team driver also has this issue, I will fix it in another patch. Fixes: 1f718f0f4f97 ("bonding: populate neighbour's private on enslave") Reported-by: Beniamino Galvani Signed-off-by: Xin Long Acked-by: Andy Gospodarek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 73 ++++++++++++++++----------------- 1 file changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 64f2a3f3279f..68b90391cfe2 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1524,44 +1524,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_close; } - /* If the mode uses primary, then the following is handled by - * bond_change_active_slave(). - */ - if (!bond_uses_primary(bond)) { - /* set promiscuity level to new slave */ - if (bond_dev->flags & IFF_PROMISC) { - res = dev_set_promiscuity(slave_dev, 1); - if (res) - goto err_close; - } - - /* set allmulti level to new slave */ - if (bond_dev->flags & IFF_ALLMULTI) { - res = dev_set_allmulti(slave_dev, 1); - if (res) - goto err_close; - } - - netif_addr_lock_bh(bond_dev); - - dev_mc_sync_multiple(slave_dev, bond_dev); - dev_uc_sync_multiple(slave_dev, bond_dev); - - netif_addr_unlock_bh(bond_dev); - } - - if (BOND_MODE(bond) == BOND_MODE_8023AD) { - /* add lacpdu mc addr to mc list */ - u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; - - dev_mc_add(slave_dev, lacpdu_multicast); - } - res = vlan_vids_add_by_dev(slave_dev, bond_dev); if (res) { netdev_err(bond_dev, "Couldn't add bond vlan ids to %s\n", slave_dev->name); - goto err_hwaddr_unsync; + goto err_close; } prev_slave = bond_last_slave(bond); @@ -1719,6 +1686,37 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_upper_unlink; } + /* If the mode uses primary, then the following is handled by + * bond_change_active_slave(). + */ + if (!bond_uses_primary(bond)) { + /* set promiscuity level to new slave */ + if (bond_dev->flags & IFF_PROMISC) { + res = dev_set_promiscuity(slave_dev, 1); + if (res) + goto err_sysfs_del; + } + + /* set allmulti level to new slave */ + if (bond_dev->flags & IFF_ALLMULTI) { + res = dev_set_allmulti(slave_dev, 1); + if (res) + goto err_sysfs_del; + } + + netif_addr_lock_bh(bond_dev); + dev_mc_sync_multiple(slave_dev, bond_dev); + dev_uc_sync_multiple(slave_dev, bond_dev); + netif_addr_unlock_bh(bond_dev); + + if (BOND_MODE(bond) == BOND_MODE_8023AD) { + /* add lacpdu mc addr to mc list */ + u8 lacpdu_multicast[ETH_ALEN] = MULTICAST_LACPDU_ADDR; + + dev_mc_add(slave_dev, lacpdu_multicast); + } + } + bond->slave_cnt++; bond_compute_features(bond); bond_set_carrier(bond); @@ -1742,6 +1740,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) return 0; /* Undo stages on error */ +err_sysfs_del: + bond_sysfs_slave_del(new_slave); + err_upper_unlink: bond_upper_dev_unlink(bond, new_slave); @@ -1762,10 +1763,6 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) synchronize_rcu(); slave_disable_netpoll(new_slave); -err_hwaddr_unsync: - if (!bond_uses_primary(bond)) - bond_hw_addr_flush(bond_dev, slave_dev); - err_close: slave_dev->priv_flags &= ~IFF_BONDING; dev_close(slave_dev); -- GitLab From 359d6e35786b3aafc4dea0d5cf59ff62c1eb126c Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:16:47 +0800 Subject: [PATCH 1279/1834] bonding: process the err returned by dev_set_allmulti properly in bond_enslave [ Upstream commit 9f5a90c107741b864398f4ac0014711a8c1d8474 ] When dev_set_promiscuity(1) succeeds but dev_set_allmulti(1) fails, dev_set_promiscuity(-1) should be done before going to the err path. Otherwise, dev->promiscuity will leak. Fixes: 7e1a1ac1fbaa ("bonding: Check return of dev_set_promiscuity/allmulti") Signed-off-by: Xin Long Acked-by: Andy Gospodarek Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/bonding/bond_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 68b90391cfe2..513457a2a7bf 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1700,8 +1700,11 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* set allmulti level to new slave */ if (bond_dev->flags & IFF_ALLMULTI) { res = dev_set_allmulti(slave_dev, 1); - if (res) + if (res) { + if (bond_dev->flags & IFF_PROMISC) + dev_set_promiscuity(slave_dev, -1); goto err_sysfs_del; + } } netif_addr_lock_bh(bond_dev); -- GitLab From 0d1c057dd6f373d8bfb168ee33f5ef8ee9e92e1b Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:26 -0700 Subject: [PATCH 1280/1834] net: fool proof dev_valid_name() [ Upstream commit a9d48205d0aedda021fc3728972a9e9934c2b9de ] We want to use dev_valid_name() to validate tunnel names, so better use strnlen(name, IFNAMSIZ) than strlen(name) to make sure to not upset KASAN. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index 1259587370b8..3d9190c2940d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -993,7 +993,7 @@ bool dev_valid_name(const char *name) { if (*name == '\0') return false; - if (strlen(name) >= IFNAMSIZ) + if (strnlen(name, IFNAMSIZ) == IFNAMSIZ) return false; if (!strcmp(name, ".") || !strcmp(name, "..")) return false; -- GitLab From 6cc0290b932d9d02831a826e54e2cce70f109c4c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:27 -0700 Subject: [PATCH 1281/1834] ip_tunnel: better validate user provided tunnel names [ Upstream commit 9cb726a212a82c88c98aa9f0037fd04777cd8fe5 ] Use dev_valid_name() to make sure user does not provide illegal device name. syzbot caught the following bug : BUG: KASAN: stack-out-of-bounds in strlcpy include/linux/string.h:300 [inline] BUG: KASAN: stack-out-of-bounds in __ip_tunnel_create+0xca/0x6b0 net/ipv4/ip_tunnel.c:257 Write of size 20 at addr ffff8801ac79f810 by task syzkaller268107/4482 CPU: 0 PID: 4482 Comm: syzkaller268107 Not tainted 4.16.0+ #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1b9/0x29f lib/dump_stack.c:53 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0xac/0x2f5 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 strlcpy include/linux/string.h:300 [inline] __ip_tunnel_create+0xca/0x6b0 net/ipv4/ip_tunnel.c:257 ip_tunnel_create net/ipv4/ip_tunnel.c:352 [inline] ip_tunnel_ioctl+0x818/0xd40 net/ipv4/ip_tunnel.c:861 ipip_tunnel_ioctl+0x1c5/0x420 net/ipv4/ipip.c:350 dev_ifsioc+0x43e/0xb90 net/core/dev_ioctl.c:334 dev_ioctl+0x69a/0xcc0 net/core/dev_ioctl.c:525 sock_ioctl+0x47e/0x680 net/socket.c:1015 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:500 [inline] do_vfs_ioctl+0x1cf/0x1650 fs/ioctl.c:684 ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701 SYSC_ioctl fs/ioctl.c:708 [inline] SyS_ioctl+0x24/0x30 fs/ioctl.c:706 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: c54419321455 ("GRE: Refactor GRE tunneling code.") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/ip_tunnel.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index 96536a0d6e2d..e1271e75e107 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -253,13 +253,14 @@ static struct net_device *__ip_tunnel_create(struct net *net, struct net_device *dev; char name[IFNAMSIZ]; - if (parms->name[0]) + err = -E2BIG; + if (parms->name[0]) { + if (!dev_valid_name(parms->name)) + goto failed; strlcpy(name, parms->name, IFNAMSIZ); - else { - if (strlen(ops->kind) > (IFNAMSIZ - 3)) { - err = -E2BIG; + } else { + if (strlen(ops->kind) > (IFNAMSIZ - 3)) goto failed; - } strlcpy(name, ops->kind, IFNAMSIZ); strncat(name, "%d", 2); } -- GitLab From f1f1f94f7d70703baf7d4f966b69601a9042a306 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:28 -0700 Subject: [PATCH 1282/1834] ipv6: sit: better validate user provided tunnel names [ Upstream commit b95211e066fc3494b7c115060b2297b4ba21f025 ] Use dev_valid_name() to make sure user does not provide illegal device name. syzbot caught the following bug : BUG: KASAN: stack-out-of-bounds in strlcpy include/linux/string.h:300 [inline] BUG: KASAN: stack-out-of-bounds in ipip6_tunnel_locate+0x63b/0xaa0 net/ipv6/sit.c:254 Write of size 33 at addr ffff8801b64076d8 by task syzkaller932654/4453 CPU: 0 PID: 4453 Comm: syzkaller932654 Not tainted 4.16.0+ #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1b9/0x29f lib/dump_stack.c:53 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0xac/0x2f5 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 strlcpy include/linux/string.h:300 [inline] ipip6_tunnel_locate+0x63b/0xaa0 net/ipv6/sit.c:254 ipip6_tunnel_ioctl+0xe71/0x241b net/ipv6/sit.c:1221 dev_ifsioc+0x43e/0xb90 net/core/dev_ioctl.c:334 dev_ioctl+0x69a/0xcc0 net/core/dev_ioctl.c:525 sock_ioctl+0x47e/0x680 net/socket.c:1015 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:500 [inline] do_vfs_ioctl+0x1cf/0x1650 fs/ioctl.c:684 ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701 SYSC_ioctl fs/ioctl.c:708 [inline] SyS_ioctl+0x24/0x30 fs/ioctl.c:706 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/sit.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 181fd958c82b..dcb292134c21 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -244,11 +244,13 @@ static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, if (!create) goto failed; - if (parms->name[0]) + if (parms->name[0]) { + if (!dev_valid_name(parms->name)) + goto failed; strlcpy(name, parms->name, IFNAMSIZ); - else + } else { strcpy(name, "sit%d"); - + } dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ipip6_tunnel_setup); if (!dev) -- GitLab From 5dcf6eb5a275ddb00eea4d6a8127ffaf5428a475 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:29 -0700 Subject: [PATCH 1283/1834] ip6_gre: better validate user provided tunnel names [ Upstream commit 5f42df013b8bc1b6511af7a04bf93b014884ae2a ] Use dev_valid_name() to make sure user does not provide illegal device name. syzbot caught the following bug : BUG: KASAN: stack-out-of-bounds in strlcpy include/linux/string.h:300 [inline] BUG: KASAN: stack-out-of-bounds in ip6gre_tunnel_locate+0x334/0x860 net/ipv6/ip6_gre.c:339 Write of size 20 at addr ffff8801afb9f7b8 by task syzkaller851048/4466 CPU: 1 PID: 4466 Comm: syzkaller851048 Not tainted 4.16.0+ #1 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:17 [inline] dump_stack+0x1b9/0x29f lib/dump_stack.c:53 print_address_description+0x6c/0x20b mm/kasan/report.c:256 kasan_report_error mm/kasan/report.c:354 [inline] kasan_report.cold.7+0xac/0x2f5 mm/kasan/report.c:412 check_memory_region_inline mm/kasan/kasan.c:260 [inline] check_memory_region+0x13e/0x1b0 mm/kasan/kasan.c:267 memcpy+0x37/0x50 mm/kasan/kasan.c:303 strlcpy include/linux/string.h:300 [inline] ip6gre_tunnel_locate+0x334/0x860 net/ipv6/ip6_gre.c:339 ip6gre_tunnel_ioctl+0x69d/0x12e0 net/ipv6/ip6_gre.c:1195 dev_ifsioc+0x43e/0xb90 net/core/dev_ioctl.c:334 dev_ioctl+0x69a/0xcc0 net/core/dev_ioctl.c:525 sock_ioctl+0x47e/0x680 net/socket.c:1015 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:500 [inline] do_vfs_ioctl+0x1cf/0x1650 fs/ioctl.c:684 ksys_ioctl+0xa9/0xd0 fs/ioctl.c:701 SYSC_ioctl fs/ioctl.c:708 [inline] SyS_ioctl+0x24/0x30 fs/ioctl.c:706 do_syscall_64+0x29e/0x9d0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 Fixes: c12b395a4664 ("gre: Support GRE over IPv6") Signed-off-by: Eric Dumazet Reported-by: syzbot Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_gre.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index db2613b4a049..caee5530ae2c 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c @@ -319,11 +319,13 @@ static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, if (t || !create) return t; - if (parms->name[0]) + if (parms->name[0]) { + if (!dev_valid_name(parms->name)) + return NULL; strlcpy(name, parms->name, IFNAMSIZ); - else + } else { strcpy(name, "ip6gre%d"); - + } dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ip6gre_tunnel_setup); if (!dev) -- GitLab From 92b2828c7c361ce44f8b01c2268265478841c586 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:30 -0700 Subject: [PATCH 1284/1834] ip6_tunnel: better validate user provided tunnel names [ Upstream commit db7a65e3ab78e5b1c4b17c0870ebee35a4ee3257 ] Use valid_name() to make sure user does not provide illegal device name. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_tunnel.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index f185126b0327..417af5ea2509 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -298,13 +298,16 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) struct net_device *dev; struct ip6_tnl *t; char name[IFNAMSIZ]; - int err = -ENOMEM; + int err = -E2BIG; - if (p->name[0]) + if (p->name[0]) { + if (!dev_valid_name(p->name)) + goto failed; strlcpy(name, p->name, IFNAMSIZ); - else + } else { sprintf(name, "ip6tnl%%d"); - + } + err = -ENOMEM; dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, ip6_tnl_dev_setup); if (!dev) -- GitLab From dbb6ed68192765066bf16067d76ec699c87d42f0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Apr 2018 06:39:31 -0700 Subject: [PATCH 1285/1834] vti6: better validate user provided tunnel names [ Upstream commit 537b361fbcbcc3cd6fe2bb47069fd292b9256d16 ] Use valid_name() to make sure user does not provide illegal device name. Fixes: ed1efb2aefbb ("ipv6: Add support for IPsec virtual tunnel interfaces") Signed-off-by: Eric Dumazet Cc: Steffen Klassert Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv6/ip6_vti.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 912333586de6..beae93fd66d5 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c @@ -212,10 +212,13 @@ static struct ip6_tnl *vti6_tnl_create(struct net *net, struct __ip6_tnl_parm *p char name[IFNAMSIZ]; int err; - if (p->name[0]) + if (p->name[0]) { + if (!dev_valid_name(p->name)) + goto failed; strlcpy(name, p->name, IFNAMSIZ); - else + } else { sprintf(name, "ip6_vti%%d"); + } dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, vti6_dev_setup); if (!dev) -- GitLab From eb9b11a1abce0122d7851bb1f6ad1790a98f5eb9 Mon Sep 17 00:00:00 2001 From: Shahar Klein Date: Tue, 20 Mar 2018 14:44:40 +0200 Subject: [PATCH 1286/1834] net/mlx5e: Sync netdev vxlan ports at open [ Upstream commit a117f73dc2430443f23e18367fa545981129c1a6 ] When mlx5_core is loaded it is expected to sync ports with all vxlan devices so it can support vxlan encap/decap. This is done via udp_tunnel_get_rx_info(). Currently this call is set in mlx5e_nic_enable() and if the netdev is not in NETREG_REGISTERED state it will not be called. Normally on load the netdev state is not NETREG_REGISTERED so udp_tunnel_get_rx_info() will not be called. Moving udp_tunnel_get_rx_info() to mlx5e_open() so it will be called on netdev UP event and allow encap/decap. Fixes: 610e89e05c3f ("net/mlx5e: Don't sync netdev state when not registered") Signed-off-by: Shahar Klein Reviewed-by: Roi Dayan Signed-off-by: Saeed Mahameed Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 38981db43bc3..2d235e8433be 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -2741,6 +2741,9 @@ static int set_feature_lro(struct net_device *netdev, bool enable) mutex_unlock(&priv->state_lock); + if (mlx5e_vxlan_allowed(priv->mdev)) + udp_tunnel_get_rx_info(netdev); + return err; } @@ -3785,13 +3788,6 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv) if (netdev->reg_state != NETREG_REGISTERED) return; - /* Device already registered: sync netdev system state */ - if (mlx5e_vxlan_allowed(mdev)) { - rtnl_lock(); - udp_tunnel_get_rx_info(netdev); - rtnl_unlock(); - } - queue_work(priv->wq, &priv->set_rx_mode_work); } -- GitLab From 9d1ff266f8a08b02f5eeee5293cd43032438dbc6 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 16 Mar 2018 00:00:55 +0100 Subject: [PATCH 1287/1834] net/sched: fix NULL dereference in the error path of tunnel_key_init() [ Upstream commit abdadd3cfd3e7ea3da61ac774f84777d1f702058 ] when the following command # tc action add action tunnel_key unset index 100 is run for the first time, and tunnel_key_init() fails to allocate struct tcf_tunnel_key_params, tunnel_key_release() dereferences NULL pointers. This causes the following error: BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 IP: tunnel_key_release+0xd/0x40 [act_tunnel_key] PGD 8000000033787067 P4D 8000000033787067 PUD 74646067 PMD 0 Oops: 0000 [#1] SMP PTI Modules linked in: act_tunnel_key(E) act_csum ip6table_filter ip6_tables iptable_filter binfmt_misc ext4 mbcache jbd2 crct10dif_pclmul crc32_pclmul snd_hda_codec_generic ghash_clmulni_intel snd_hda_intel pcbc snd_hda_codec snd_hda_core snd_hwdep snd_seq aesni_intel snd_seq_device crypto_simd glue_helper snd_pcm cryptd joydev snd_timer pcspkr virtio_balloon snd i2c_piix4 soundcore nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c ata_generic pata_acpi qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm virtio_net virtio_blk drm virtio_console crc32c_intel ata_piix serio_raw i2c_core virtio_pci libata virtio_ring virtio floppy dm_mirror dm_region_hash dm_log dm_mod CPU: 2 PID: 3101 Comm: tc Tainted: G E 4.16.0-rc4.act_vlan.orig+ #403 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:tunnel_key_release+0xd/0x40 [act_tunnel_key] RSP: 0018:ffffba46803b7768 EFLAGS: 00010286 RAX: ffffffffc09010a0 RBX: 0000000000000000 RCX: 0000000000000024 RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff99ee336d7480 RBP: 0000000000000000 R08: 0000000000000001 R09: 0000000000000044 R10: 0000000000000220 R11: ffff99ee79d73131 R12: 0000000000000000 R13: ffff99ee32d67610 R14: ffff99ee7671dc38 R15: 00000000fffffff4 FS: 00007febcb2cd740(0000) GS:ffff99ee7fd00000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000010 CR3: 000000007c8e4005 CR4: 00000000001606e0 Call Trace: __tcf_idr_release+0x79/0xf0 tunnel_key_init+0xd9/0x460 [act_tunnel_key] tcf_action_init_1+0x2cc/0x430 tcf_action_init+0xd3/0x1b0 tc_ctl_action+0x18b/0x240 rtnetlink_rcv_msg+0x29c/0x310 ? _cond_resched+0x15/0x30 ? __kmalloc_node_track_caller+0x1b9/0x270 ? rtnl_calcit.isra.28+0x100/0x100 netlink_rcv_skb+0xd2/0x110 netlink_unicast+0x17c/0x230 netlink_sendmsg+0x2cd/0x3c0 sock_sendmsg+0x30/0x40 ___sys_sendmsg+0x27a/0x290 __sys_sendmsg+0x51/0x90 do_syscall_64+0x6e/0x1a0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7febca6deba0 RSP: 002b:00007ffe7b0dd128 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007ffe7b0dd250 RCX: 00007febca6deba0 RDX: 0000000000000000 RSI: 00007ffe7b0dd1a0 RDI: 0000000000000003 RBP: 000000005aaa90cb R08: 0000000000000002 R09: 0000000000000000 R10: 00007ffe7b0dcba0 R11: 0000000000000246 R12: 0000000000000000 R13: 00007ffe7b0dd264 R14: 0000000000000001 R15: 0000000000669f60 Code: 44 00 00 8b 0d b5 23 00 00 48 8b 87 48 10 00 00 48 8b 3c c8 e9 a5 e5 d8 c3 0f 1f 44 00 00 0f 1f 44 00 00 53 48 8b 9f b0 00 00 00 <83> 7b 10 01 74 0b 48 89 df 31 f6 5b e9 f2 fa 7f c3 48 8b 7b 18 RIP: tunnel_key_release+0xd/0x40 [act_tunnel_key] RSP: ffffba46803b7768 CR2: 0000000000000010 Fix this in tunnel_key_release(), ensuring 'param' is not NULL before dereferencing it. Fixes: d0f6dd8a914f ("net/sched: Introduce act_tunnel_key") Signed-off-by: Davide Caratti Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_tunnel_key.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/sched/act_tunnel_key.c b/net/sched/act_tunnel_key.c index b6e3abe505ac..901fb8bb9dce 100644 --- a/net/sched/act_tunnel_key.c +++ b/net/sched/act_tunnel_key.c @@ -196,11 +196,12 @@ static void tunnel_key_release(struct tc_action *a, int bind) struct tcf_tunnel_key_params *params; params = rcu_dereference_protected(t->params, 1); + if (params) { + if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) + dst_release(¶ms->tcft_enc_metadata->dst); - if (params->tcft_action == TCA_TUNNEL_KEY_ACT_SET) - dst_release(¶ms->tcft_enc_metadata->dst); - - kfree_rcu(params, rcu); + kfree_rcu(params, rcu); + } } static int tunnel_key_dump_addresses(struct sk_buff *skb, -- GitLab From 0e8d6e87d2965999219d140d6a078aef128e1703 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 16 Mar 2018 00:00:57 +0100 Subject: [PATCH 1288/1834] net/sched: fix NULL dereference on the error path of tcf_skbmod_init() [ Upstream commit 2d433610176d6569e8b3a28f67bc72235bf69efc ] when the following command # tc action replace action skbmod swap mac index 100 is run for the first time, and tcf_skbmod_init() fails to allocate struct tcf_skbmod_params, tcf_skbmod_cleanup() calls kfree_rcu(NULL), thus causing the following error: BUG: unable to handle kernel NULL pointer dereference at 0000000000000008 IP: __call_rcu+0x23/0x2b0 PGD 8000000034057067 P4D 8000000034057067 PUD 74937067 PMD 0 Oops: 0002 [#1] SMP PTI Modules linked in: act_skbmod(E) psample ip6table_filter ip6_tables iptable_filter binfmt_misc ext4 snd_hda_codec_generic snd_hda_intel snd_hda_codec crct10dif_pclmul mbcache jbd2 crc32_pclmul snd_hda_core ghash_clmulni_intel snd_hwdep pcbc snd_seq snd_seq_device snd_pcm aesni_intel snd_timer crypto_simd glue_helper snd cryptd virtio_balloon joydev soundcore pcspkr i2c_piix4 nfsd auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c ata_generic pata_acpi qxl drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm drm virtio_console virtio_net virtio_blk ata_piix libata crc32c_intel virtio_pci serio_raw virtio_ring virtio i2c_core floppy dm_mirror dm_region_hash dm_log dm_mod [last unloaded: act_skbmod] CPU: 3 PID: 3144 Comm: tc Tainted: G E 4.16.0-rc4.act_vlan.orig+ #403 Hardware name: Red Hat KVM, BIOS 0.5.1 01/01/2011 RIP: 0010:__call_rcu+0x23/0x2b0 RSP: 0018:ffffbd2e403e7798 EFLAGS: 00010246 RAX: ffffffffc0872080 RBX: ffff981d34bff780 RCX: 00000000ffffffff RDX: ffffffff922a5f00 RSI: 0000000000000000 RDI: 0000000000000000 RBP: 0000000000000000 R08: 0000000000000001 R09: 000000000000021f R10: 000000003d003000 R11: 0000000000aaaaaa R12: 0000000000000000 R13: ffffffff922a5f00 R14: 0000000000000001 R15: ffff981d3b698c2c FS: 00007f3678292740(0000) GS:ffff981d3fd80000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 0000000000000008 CR3: 000000007c57a006 CR4: 00000000001606e0 Call Trace: __tcf_idr_release+0x79/0xf0 tcf_skbmod_init+0x1d1/0x210 [act_skbmod] tcf_action_init_1+0x2cc/0x430 tcf_action_init+0xd3/0x1b0 tc_ctl_action+0x18b/0x240 rtnetlink_rcv_msg+0x29c/0x310 ? _cond_resched+0x15/0x30 ? __kmalloc_node_track_caller+0x1b9/0x270 ? rtnl_calcit.isra.28+0x100/0x100 netlink_rcv_skb+0xd2/0x110 netlink_unicast+0x17c/0x230 netlink_sendmsg+0x2cd/0x3c0 sock_sendmsg+0x30/0x40 ___sys_sendmsg+0x27a/0x290 ? filemap_map_pages+0x34a/0x3a0 ? __handle_mm_fault+0xbfd/0xe20 __sys_sendmsg+0x51/0x90 do_syscall_64+0x6e/0x1a0 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7f36776a3ba0 RSP: 002b:00007fff4703b618 EFLAGS: 00000246 ORIG_RAX: 000000000000002e RAX: ffffffffffffffda RBX: 00007fff4703b740 RCX: 00007f36776a3ba0 RDX: 0000000000000000 RSI: 00007fff4703b690 RDI: 0000000000000003 RBP: 000000005aaaba36 R08: 0000000000000002 R09: 0000000000000000 R10: 00007fff4703b0a0 R11: 0000000000000246 R12: 0000000000000000 R13: 00007fff4703b754 R14: 0000000000000001 R15: 0000000000669f60 Code: 5d e9 42 da ff ff 66 90 0f 1f 44 00 00 41 57 41 56 41 55 49 89 d5 41 54 55 48 89 fd 53 48 83 ec 08 40 f6 c7 07 0f 85 19 02 00 00 <48> 89 75 08 48 c7 45 00 00 00 00 00 9c 58 0f 1f 44 00 00 49 89 RIP: __call_rcu+0x23/0x2b0 RSP: ffffbd2e403e7798 CR2: 0000000000000008 Fix it in tcf_skbmod_cleanup(), ensuring that kfree_rcu(p, ...) is called only when p is not NULL. Fixes: 86da71b57383 ("net_sched: Introduce skbmod action") Signed-off-by: Davide Caratti Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_skbmod.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/sched/act_skbmod.c b/net/sched/act_skbmod.c index f85313d60a4d..bd8e86cb8743 100644 --- a/net/sched/act_skbmod.c +++ b/net/sched/act_skbmod.c @@ -192,7 +192,8 @@ static void tcf_skbmod_cleanup(struct tc_action *a, int bind) struct tcf_skbmod_params *p; p = rcu_dereference_protected(d->skbmod_p, 1); - kfree_rcu(p, rcu); + if (p) + kfree_rcu(p, rcu); } static int tcf_skbmod_dump(struct sk_buff *skb, struct tc_action *a, -- GitLab From b3e1c92e59911cd61672f8f735bc78f36ca7fef0 Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Tue, 27 Mar 2018 14:41:18 +0300 Subject: [PATCH 1289/1834] net/mlx4_en: Fix mixed PFC and Global pause user control requests [ Upstream commit 6e8814ceb7e8f468659ef9253bd212c07ae19584 ] Global pause and PFC configuration should be mutually exclusive (i.e. only one of them at most can be set). However, once PFC was turned off, driver automatically turned Global pause on. This is a bug. Fix the driver behaviour to turn off PFC/Global once the user turned the other on. This also fixed a weird behaviour that at a current time, the profile had both PFC and global pause configuration turned on, which is Hardware-wise impossible and caused returning false positive indication to query tools. In addition, fix error code when setting global pause or PFC to change metadata only upon successful change. Also, removed useless debug print. Fixes: af7d51852631 ("net/mlx4_en: Add DCB PFC support through CEE netlink commands") Fixes: c27a02cd94d6 ("mlx4_en: Add driver for Mellanox ConnectX 10GbE NIC") Signed-off-by: Eran Ben Elisha Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- .../net/ethernet/mellanox/mlx4/en_dcb_nl.c | 72 +++++++++++-------- .../net/ethernet/mellanox/mlx4/en_ethtool.c | 33 +++++---- drivers/net/ethernet/mellanox/mlx4/en_main.c | 4 +- 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index d98827adec9b..af2e6ea36eac 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -156,57 +156,63 @@ static int mlx4_en_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) static u8 mlx4_en_dcbnl_set_all(struct net_device *netdev) { struct mlx4_en_priv *priv = netdev_priv(netdev); + struct mlx4_en_port_profile *prof = priv->prof; struct mlx4_en_dev *mdev = priv->mdev; + u8 tx_pause, tx_ppp, rx_pause, rx_ppp; if (!(priv->dcbx_cap & DCB_CAP_DCBX_VER_CEE)) return 1; if (priv->cee_config.pfc_state) { int tc; + rx_ppp = prof->rx_ppp; + tx_ppp = prof->tx_ppp; - priv->prof->rx_pause = 0; - priv->prof->tx_pause = 0; for (tc = 0; tc < CEE_DCBX_MAX_PRIO; tc++) { u8 tc_mask = 1 << tc; switch (priv->cee_config.dcb_pfc[tc]) { case pfc_disabled: - priv->prof->tx_ppp &= ~tc_mask; - priv->prof->rx_ppp &= ~tc_mask; + tx_ppp &= ~tc_mask; + rx_ppp &= ~tc_mask; break; case pfc_enabled_full: - priv->prof->tx_ppp |= tc_mask; - priv->prof->rx_ppp |= tc_mask; + tx_ppp |= tc_mask; + rx_ppp |= tc_mask; break; case pfc_enabled_tx: - priv->prof->tx_ppp |= tc_mask; - priv->prof->rx_ppp &= ~tc_mask; + tx_ppp |= tc_mask; + rx_ppp &= ~tc_mask; break; case pfc_enabled_rx: - priv->prof->tx_ppp &= ~tc_mask; - priv->prof->rx_ppp |= tc_mask; + tx_ppp &= ~tc_mask; + rx_ppp |= tc_mask; break; default: break; } } - en_dbg(DRV, priv, "Set pfc on\n"); + rx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->rx_pause; + tx_pause = !!(rx_ppp || tx_ppp) ? 0 : prof->tx_pause; } else { - priv->prof->rx_pause = 1; - priv->prof->tx_pause = 1; - en_dbg(DRV, priv, "Set pfc off\n"); + rx_ppp = 0; + tx_ppp = 0; + rx_pause = prof->rx_pause; + tx_pause = prof->tx_pause; } if (mlx4_SET_PORT_general(mdev->dev, priv->port, priv->rx_skb_size + ETH_FCS_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp)) { + tx_pause, tx_ppp, rx_pause, rx_ppp)) { en_err(priv, "Failed setting pause params\n"); return 1; } + prof->tx_ppp = tx_ppp; + prof->rx_ppp = rx_ppp; + prof->tx_pause = tx_pause; + prof->rx_pause = rx_pause; + return 0; } @@ -408,6 +414,7 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev, struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_port_profile *prof = priv->prof; struct mlx4_en_dev *mdev = priv->mdev; + u32 tx_pause, tx_ppp, rx_pause, rx_ppp; int err; en_dbg(DRV, priv, "cap: 0x%x en: 0x%x mbc: 0x%x delay: %d\n", @@ -416,23 +423,26 @@ static int mlx4_en_dcbnl_ieee_setpfc(struct net_device *dev, pfc->mbc, pfc->delay); - prof->rx_pause = !pfc->pfc_en; - prof->tx_pause = !pfc->pfc_en; - prof->rx_ppp = pfc->pfc_en; - prof->tx_ppp = pfc->pfc_en; + rx_pause = prof->rx_pause && !pfc->pfc_en; + tx_pause = prof->tx_pause && !pfc->pfc_en; + rx_ppp = pfc->pfc_en; + tx_ppp = pfc->pfc_en; err = mlx4_SET_PORT_general(mdev->dev, priv->port, priv->rx_skb_size + ETH_FCS_LEN, - prof->tx_pause, - prof->tx_ppp, - prof->rx_pause, - prof->rx_ppp); - if (err) + tx_pause, tx_ppp, rx_pause, rx_ppp); + if (err) { en_err(priv, "Failed setting pause params\n"); - else - mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, - prof->rx_ppp, prof->rx_pause, - prof->tx_ppp, prof->tx_pause); + return err; + } + + mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, + rx_ppp, rx_pause, tx_ppp, tx_pause); + + prof->tx_ppp = tx_ppp; + prof->rx_ppp = rx_ppp; + prof->rx_pause = rx_pause; + prof->tx_pause = tx_pause; return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index bdda17d2ea0f..24977cc881d2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1003,27 +1003,32 @@ static int mlx4_en_set_pauseparam(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; + u8 tx_pause, tx_ppp, rx_pause, rx_ppp; int err; if (pause->autoneg) return -EINVAL; - priv->prof->tx_pause = pause->tx_pause != 0; - priv->prof->rx_pause = pause->rx_pause != 0; + tx_pause = !!(pause->tx_pause); + rx_pause = !!(pause->rx_pause); + rx_ppp = priv->prof->rx_ppp && !(tx_pause || rx_pause); + tx_ppp = priv->prof->tx_ppp && !(tx_pause || rx_pause); + err = mlx4_SET_PORT_general(mdev->dev, priv->port, priv->rx_skb_size + ETH_FCS_LEN, - priv->prof->tx_pause, - priv->prof->tx_ppp, - priv->prof->rx_pause, - priv->prof->rx_ppp); - if (err) - en_err(priv, "Failed setting pause params\n"); - else - mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, - priv->prof->rx_ppp, - priv->prof->rx_pause, - priv->prof->tx_ppp, - priv->prof->tx_pause); + tx_pause, tx_ppp, rx_pause, rx_ppp); + if (err) { + en_err(priv, "Failed setting pause params, err = %d\n", err); + return err; + } + + mlx4_en_update_pfc_stats_bitmap(mdev->dev, &priv->stats_bitmap, + rx_ppp, rx_pause, tx_ppp, tx_pause); + + priv->prof->tx_pause = tx_pause; + priv->prof->rx_pause = rx_pause; + priv->prof->tx_ppp = tx_ppp; + priv->prof->rx_ppp = rx_ppp; return err; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index bf7628db098a..22c3fdd5482a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -163,9 +163,9 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->udp_rss = 0; } for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = 1; + params->prof[i].rx_pause = !(pfcrx || pfctx); params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = 1; + params->prof[i].tx_pause = !(pfcrx || pfctx); params->prof[i].tx_ppp = pfctx; params->prof[i].tx_ring_size = MLX4_EN_DEF_TX_RING_SIZE; params->prof[i].rx_ring_size = MLX4_EN_DEF_RX_RING_SIZE; -- GitLab From 992dbb1d5a653c49a7f2159f75d9cda0d8248f1f Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 29 Mar 2018 16:00:04 +0800 Subject: [PATCH 1290/1834] vhost: validate log when IOTLB is enabled [ Upstream commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ] Vq log_base is the userspace address of bitmap which has nothing to do with IOTLB. So it needs to be validated unconditionally otherwise we may try use 0 as log_base which may lead to pin pages that will lead unexpected result (e.g trigger BUG_ON() in set_bit_to_user()). Fixes: 6b1e6cc7855b0 ("vhost: new device IOTLB API") Reported-by: syzbot+6304bf97ef436580fede@syzkaller.appspotmail.com Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 126730384d7d..e2c37aeed45a 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1175,14 +1175,12 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, /* Caller should have vq mutex and device mutex */ int vhost_vq_access_ok(struct vhost_virtqueue *vq) { - if (vq->iotlb) { - /* When device IOTLB was used, the access validation - * will be validated during prefetching. - */ - return 1; - } - return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used) && - vq_log_access_ok(vq, vq->log_base); + int ret = vq_log_access_ok(vq, vq->log_base); + + if (ret || vq->iotlb) + return ret; + + return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); } EXPORT_SYMBOL_GPL(vhost_vq_access_ok); -- GitLab From 8cba34a7a66444f11f1d5c315e947222e21cfe4d Mon Sep 17 00:00:00 2001 From: Xin Long Date: Sun, 1 Apr 2018 22:40:35 +0800 Subject: [PATCH 1291/1834] route: check sysctl_fib_multipath_use_neigh earlier than hash [ Upstream commit 6174a30df1b902e1fedbd728f5343937e83e64e6 ] Prior to this patch, when one packet is hashed into path [1] (hash <= nh_upper_bound) and it's neigh is dead, it will try path [2]. However, if path [2]'s neigh is alive but it's hash > nh_upper_bound, it will not return this alive path. This packet will never be sent even if path [2] is alive. 3.3.3.1/24: nexthop via 1.1.1.254 dev eth1 weight 1 <--[1] (dead neigh) nexthop via 2.2.2.254 dev eth2 weight 1 <--[2] With sysctl_fib_multipath_use_neigh set is supposed to find an available path respecting to the l3/l4 hash. But if there is no available route with this hash, it should at least return an alive route even with other hash. This patch is to fix it by processing fib_multipath_use_neigh earlier than the hash check, so that it will at least return an alive route if there is when fib_multipath_use_neigh is enabled. It's also compatible with before when there are alive routes with the l3/l4 hash. Fixes: a6db4494d218 ("net: ipv4: Consider failed nexthops in multipath routes") Reported-by: Jianlin Shi Signed-off-by: Xin Long Acked-by: David Ahern Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/ipv4/fib_semantics.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 7e7b7a3efa99..e1be24416c0e 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -1611,18 +1611,20 @@ void fib_select_multipath(struct fib_result *res, int hash) bool first = false; for_nexthops(fi) { + if (net->ipv4.sysctl_fib_multipath_use_neigh) { + if (!fib_good_nh(nh)) + continue; + if (!first) { + res->nh_sel = nhsel; + first = true; + } + } + if (hash > atomic_read(&nh->nh_upper_bound)) continue; - if (!net->ipv4.sysctl_fib_multipath_use_neigh || - fib_good_nh(nh)) { - res->nh_sel = nhsel; - return; - } - if (!first) { - res->nh_sel = nhsel; - first = true; - } + res->nh_sel = nhsel; + return; } endfor_nexthops(fi); } #endif -- GitLab From e0cfa0d3e53b6e4f2fd4280b2f9474e6fb8e13f4 Mon Sep 17 00:00:00 2001 From: Xin Long Date: Mon, 26 Mar 2018 01:25:06 +0800 Subject: [PATCH 1292/1834] team: move dev_mc_sync after master_upper_dev_link in team_port_add [ Upstream commit 982cf3b3999d39a2eaca0a65542df33c19b5d814 ] The same fix as in 'bonding: move dev_mc_sync after master_upper_dev_link in bond_enslave' is needed for team driver. The panic can be reproduced easily: ip link add team1 type team ip link set team1 up ip link add link team1 vlan1 type vlan id 80 ip link set vlan1 master team1 Fixes: cb41c997d444 ("team: team should sync the port's uc/mc addrs when add a port") Signed-off-by: Xin Long Acked-by: Jiri Pirko Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/team/team.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index a0a9c9d39f01..8673ef3c9cdc 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1203,11 +1203,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_dev_open; } - netif_addr_lock_bh(dev); - dev_uc_sync_multiple(port_dev, dev); - dev_mc_sync_multiple(port_dev, dev); - netif_addr_unlock_bh(dev); - err = vlan_vids_add_by_dev(port_dev, dev); if (err) { netdev_err(dev, "Failed to add vlan ids to device %s\n", @@ -1247,6 +1242,11 @@ static int team_port_add(struct team *team, struct net_device *port_dev) goto err_option_port_add; } + netif_addr_lock_bh(dev); + dev_uc_sync_multiple(port_dev, dev); + dev_mc_sync_multiple(port_dev, dev); + netif_addr_unlock_bh(dev); + port->index = -1; list_add_tail_rcu(&port->list, &team->port_list); team_port_enable(team, port); @@ -1271,8 +1271,6 @@ static int team_port_add(struct team *team, struct net_device *port_dev) vlan_vids_del_by_dev(port_dev, dev); err_vids_add: - dev_uc_unsync(port_dev, dev); - dev_mc_unsync(port_dev, dev); dev_close(port_dev); err_dev_open: -- GitLab From 1cb81756b7c3813f7d65d3c6bb1133cb53b69775 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 26 Mar 2018 16:10:23 +0800 Subject: [PATCH 1293/1834] vhost_net: add missing lock nesting notation [ Upstream commit aaa3149bbee9ba9b4e6f0bd6e3e7d191edeae942 ] We try to hold TX virtqueue mutex in vhost_net_rx_peek_head_len() after RX virtqueue mutex is held in handle_rx(). This requires an appropriate lock nesting notation to calm down deadlock detector. Fixes: 0308813724606 ("vhost_net: basic polling support") Reported-by: syzbot+7f073540b1384a614e09@syzkaller.appspotmail.com Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index e5b7652234fc..487586e2d8b9 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -524,7 +524,7 @@ static int vhost_net_rx_peek_head_len(struct vhost_net *net, struct sock *sk) if (!len && vq->busyloop_timeout) { /* Both tx vq and rx socket were polled here */ - mutex_lock(&vq->mutex); + mutex_lock_nested(&vq->mutex, 1); vhost_disable_notify(&net->dev, vq); preempt_disable(); @@ -657,7 +657,7 @@ static void handle_rx(struct vhost_net *net) struct iov_iter fixup; __virtio16 num_buffers; - mutex_lock(&vq->mutex); + mutex_lock_nested(&vq->mutex, 0); sock = vq->private_data; if (!sock) goto out; -- GitLab From 3d392d2e3ed5b59b995da08a8deb3abb3e48b99b Mon Sep 17 00:00:00 2001 From: Moshe Shemesh Date: Tue, 27 Mar 2018 14:41:19 +0300 Subject: [PATCH 1294/1834] net/mlx4_core: Fix memory leak while delete slave's resources [ Upstream commit 461d5f1b59490ce0096dfda45e10038c122a7892 ] mlx4_delete_all_resources_for_slave in resource tracker should free all memory allocated for a slave. While releasing memory of fs_rule, it misses releasing memory of fs_rule->mirr_mbox. Fixes: 78efed275117 ('net/mlx4_core: Support mirroring VF DMFS rules on both ports') Signed-off-by: Moshe Shemesh Signed-off-by: Tariq Toukan Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 8fd1b1ab7d81..d6b06bef1b69 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -5048,6 +5048,7 @@ static void rem_slave_fs_rule(struct mlx4_dev *dev, int slave) &tracker->res_tree[RES_FS_RULE]); list_del(&fs_rule->com.list); spin_unlock_irq(mlx4_tlock(dev)); + kfree(fs_rule->mirr_mbox); kfree(fs_rule); state = 0; break; -- GitLab From 32a2fd96bf77b27e55f6524d16501f55887b3b7b Mon Sep 17 00:00:00 2001 From: Dave Watson Date: Mon, 26 Mar 2018 12:31:21 -0700 Subject: [PATCH 1295/1834] strparser: Fix sign of err codes [ Upstream commit cd00edc179863848abab5cc5683de5b7b5f70954 ] strp_parser_err is called with a negative code everywhere, which then calls abort_parser with a negative code. strp_msg_timeout calls abort_parser directly with a positive code. Negate ETIMEDOUT to match signed-ness of other calls. The default abort_parser callback, strp_abort_strp, sets sk->sk_err to err. Also negate the error here so sk_err always holds a positive value, as the rest of the net code expects. Currently a negative sk_err can result in endless loops, or user code that thinks it actually sent/received err bytes. Found while testing net/tls_sw recv path. Fixes: 43a0c6751a322847 ("strparser: Stream parser for messages") Signed-off-by: Dave Watson Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/strparser/strparser.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c index b5c279b22680..6cbc935ddd96 100644 --- a/net/strparser/strparser.c +++ b/net/strparser/strparser.c @@ -59,7 +59,7 @@ static void strp_abort_rx_strp(struct strparser *strp, int err) strp->rx_stopped = 1; /* Report an error on the lower socket */ - csk->sk_err = err; + csk->sk_err = -err; csk->sk_error_report(csk); } @@ -422,7 +422,7 @@ static void strp_rx_msg_timeout(unsigned long arg) /* Message assembly timed out */ STRP_STATS_INCR(strp->stats.rx_msg_timeouts); lock_sock(strp->sk); - strp->cb.abort_parser(strp, ETIMEDOUT); + strp->cb.abort_parser(strp, -ETIMEDOUT); release_sock(strp->sk); } -- GitLab From 4363b972ada0968732ef7393eabffddf0b9f4341 Mon Sep 17 00:00:00 2001 From: Craig Dillabaugh Date: Mon, 26 Mar 2018 14:58:32 -0400 Subject: [PATCH 1296/1834] net sched actions: fix dumping which requires several messages to user space [ Upstream commit 734549eb550c0c720bc89e50501f1b1e98cdd841 ] Fixes a bug in the tcf_dump_walker function that can cause some actions to not be reported when dumping a large number of actions. This issue became more aggrevated when cookies feature was added. In particular this issue is manifest when large cookie values are assigned to the actions and when enough actions are created that the resulting table must be dumped in multiple batches. The number of actions returned in each batch is limited by the total number of actions and the memory buffer size. With small cookies the numeric limit is reached before the buffer size limit, which avoids the code path triggering this bug. When large cookies are used buffer fills before the numeric limit, and the erroneous code path is hit. For example after creating 32 csum actions with the cookie aaaabbbbccccdddd $ tc actions ls action csum total acts 26 action order 0: csum (tcp) action continue index 1 ref 1 bind 0 cookie aaaabbbbccccdddd ..... action order 25: csum (tcp) action continue index 26 ref 1 bind 0 cookie aaaabbbbccccdddd total acts 6 action order 0: csum (tcp) action continue index 28 ref 1 bind 0 cookie aaaabbbbccccdddd ...... action order 5: csum (tcp) action continue index 32 ref 1 bind 0 cookie aaaabbbbccccdddd Note that the action with index 27 is omitted from the report. Fixes: 4b3550ef530c ("[NET_SCHED]: Use nla_nest_start/nla_nest_end")" Signed-off-by: Craig Dillabaugh Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/sched/act_api.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sched/act_api.c b/net/sched/act_api.c index f3117324146a..67adb4ecded2 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -95,8 +95,10 @@ static int tcf_dump_walker(struct tcf_hashinfo *hinfo, struct sk_buff *skb, continue; nest = nla_nest_start(skb, n_i); - if (nest == NULL) + if (nest == NULL) { + index--; goto nla_put_failure; + } err = tcf_action_dump_1(skb, p, 0, 0); if (err < 0) { index--; -- GitLab From 89cd658056d24f8fbde817a263674a5253d4f427 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 29 Mar 2018 12:49:52 -0700 Subject: [PATCH 1297/1834] vrf: Fix use after free and double free in vrf_finish_output commit 82dd0d2a9a76fc8fa2b18d80b987d455728bf83a upstream. Miguel reported an skb use after free / double free in vrf_finish_output when neigh_output returns an error. The vrf driver should return after the call to neigh_output as it takes over the skb on error path as well. Patch is a simplified version of Miguel's patch which was written for 4.9, and updated to top of tree. Fixes: 8f58336d3f78a ("net: Add ethernet header for pass through VRF device") Signed-off-by: Miguel Fadon Perlines Signed-off-by: David Ahern Signed-off-by: David S. Miller [ backport to 4.4 and 4.9 dropped the sock_confirm_neigh and changed neigh_output to dst_neigh_output ] Signed-off-by: Greg Kroah-Hartman --- drivers/net/vrf.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 346e48698555..42c9480acdc7 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -585,13 +585,15 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s neigh = __ipv4_neigh_lookup_noref(dev, nexthop); if (unlikely(!neigh)) neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); - if (!IS_ERR(neigh)) + if (!IS_ERR(neigh)) { ret = dst_neigh_output(dst, neigh, skb); + rcu_read_unlock_bh(); + return ret; + } rcu_read_unlock_bh(); err: - if (unlikely(ret < 0)) - vrf_tx_error(skb->dev, skb); + vrf_tx_error(skb->dev, skb); return ret; } -- GitLab From 0efce82a41ce9b9cd1371622011a85827c099d0f Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Thu, 12 Apr 2018 17:29:51 -0700 Subject: [PATCH 1298/1834] Revert "xhci: plat: Register shutdown for xhci_plat" Pixel 2 field testers reported that when they tried to reboot their phones with some USB devices plugged in, the reboot would get wedged and eventually trigger watchdog reset. Once the Pixel kernel team found a reliable repro case, they narrowed it down to this commit's 4.4.y backport. Reverting the change made the issue go away. This reverts commit b07c12517f2aed0add8ce18146bb426b14099392. Signed-off-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/xhci-plat.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index dec100811946..ca8b0b1ae37d 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -335,7 +335,6 @@ MODULE_DEVICE_TABLE(acpi, usb_xhci_acpi_match); static struct platform_driver usb_xhci_driver = { .probe = xhci_plat_probe, .remove = xhci_plat_remove, - .shutdown = usb_hcd_platform_shutdown, .driver = { .name = "xhci-hcd", .pm = DEV_PM_OPS, -- GitLab From cc0eb4dd504b8a0adab865a9488297aca63013ba Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 13 Apr 2018 19:48:37 +0200 Subject: [PATCH 1299/1834] Linux 4.9.94 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f5cf4159fc20..02188cf8e9af 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 93 +SUBLEVEL = 94 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From f4cf34644cd919c5d054fb4c931e5d2bcfd161a2 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Thu, 12 Apr 2018 16:02:30 -0700 Subject: [PATCH 1300/1834] msm: camera: sensor: Add slave address info Print sensor slave address during sensor acquire, release, stream on and stream off. Change-Id: I3a3a53a9495ede14a79217eaabc2ed475de58421 Signed-off-by: Vishalsingh Hajeri --- .../cam_sensor/cam_sensor_core.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index d5bee96bfb63..d58834c3d719 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -730,8 +730,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; CAM_INFO(CAM_SENSOR, - "CAM_ACQUIRE_DEV Success, sensor_id:0x%x", - s_ctrl->sensordata->slave_info.sensor_id); + "CAM_ACQUIRE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); } break; case CAM_RELEASE_DEV: { @@ -770,8 +771,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, s_ctrl->sensor_state = CAM_SENSOR_INIT; CAM_INFO(CAM_SENSOR, - "CAM_RELEASE_DEV Success, sensor_id:0x%x", - s_ctrl->sensordata->slave_info.sensor_id); + "CAM_RELEASE_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); s_ctrl->streamon_count = 0; s_ctrl->streamoff_count = 0; } @@ -810,8 +812,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } s_ctrl->sensor_state = CAM_SENSOR_START; CAM_INFO(CAM_SENSOR, - "CAM_START_DEV Success, sensor_id:0x%x", - s_ctrl->sensordata->slave_info.sensor_id); + "CAM_START_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); } break; case CAM_STOP_DEV: { @@ -836,8 +839,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, cam_sensor_release_resource(s_ctrl); s_ctrl->sensor_state = CAM_SENSOR_ACQUIRE; CAM_INFO(CAM_SENSOR, - "CAM_STOP_DEV Success, sensor_id:0x%x", - s_ctrl->sensordata->slave_info.sensor_id); + "CAM_STOP_DEV Success, sensor_id:0x%x,sensor_slave_addr:0x%x", + s_ctrl->sensordata->slave_info.sensor_id, + s_ctrl->sensordata->slave_info.sensor_slave_addr); } break; case CAM_CONFIG_DEV: { -- GitLab From 4405a1f744d8f1fc970d20a0fb94586b258a1ec3 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 7 Nov 2017 13:18:43 -0800 Subject: [PATCH 1301/1834] Revert "ANDROID: fixup! proc: make oom adjustment files user read-only" CTS no longer expects oom_{adj,score_adj} to be read-only. See https://android-review.googlesource.com/530687/ for additional context. This reverts commit f049c419aee1ad45a55f30c94e6f3b5677419a75. Bug: 63142211 Change-Id: I83c42123921e8dd0395420125e69246c4d85cda6 Signed-off-by: Greg Hackmann --- fs/proc/base.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/proc/base.c b/fs/proc/base.c index 5e697d9bc6ac..f7b394ab4458 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2913,6 +2913,7 @@ static const struct pid_entry tgid_base_stuff[] = { ONE("cgroup", S_IRUGO, proc_cgroup_show), #endif ONE("oom_score", S_IRUGO, proc_oom_score), + INF("oom_score", S_IRUGO, proc_oom_score), REG("oom_adj", S_IRUSR, proc_oom_adj_operations), REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations), #ifdef CONFIG_AUDITSYSCALL -- GitLab From 3a6594d7d13cc1369162357179ba002e12c7cffd Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Tue, 7 Nov 2017 13:21:20 -0800 Subject: [PATCH 1302/1834] Revert "ANDROID: proc: make oom adjustment files user read-only" CTS no longer expects oom_{adj,score_adj} to be read-only. See https://android-review.googlesource.com/530687/ for additional context. This reverts commit 2956c9be7e5a8a2a89e790e20d2953b490571a4c. Bug: 63142211 Change-Id: I9ff2728531eb2b09b5ddb19da51eacf6e4316dd6 Signed-off-by: Greg Hackmann --- fs/proc/base.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index f7b394ab4458..3a60e671f24d 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2913,9 +2913,8 @@ static const struct pid_entry tgid_base_stuff[] = { ONE("cgroup", S_IRUGO, proc_cgroup_show), #endif ONE("oom_score", S_IRUGO, proc_oom_score), - INF("oom_score", S_IRUGO, proc_oom_score), - REG("oom_adj", S_IRUSR, proc_oom_adj_operations), - REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations), + REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), + REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), #ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), @@ -3308,8 +3307,8 @@ static const struct pid_entry tid_base_stuff[] = { ONE("cgroup", S_IRUGO, proc_cgroup_show), #endif ONE("oom_score", S_IRUGO, proc_oom_score), - REG("oom_adj", S_IRUSR, proc_oom_adj_operations), - REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations), + REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), + REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), #ifdef CONFIG_AUDITSYSCALL REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), REG("sessionid", S_IRUGO, proc_sessionid_operations), -- GitLab From 0055e0d13e5ee3e938d54dcd0eae79610de47aaa Mon Sep 17 00:00:00 2001 From: Greg Hartman Date: Thu, 5 Apr 2018 17:59:11 -0700 Subject: [PATCH 1303/1834] FROMLIST: staging: Android: Add 'vsoc' driver for cuttlefish. The cuttlefish system is a virtual SoC architecture based on QEMU. It uses the QEMU ivshmem feature to share memory regions between guest and host with a custom protocol. Signed-off-by: Greg Hartman [sent upstream via staging https://patchwork.kernel.org/patch/10339507/] Change-Id: Iaf5d7536898329a66d00764d8892d1395164519e Signed-off-by: Alistair Strachan --- drivers/staging/android/Kconfig | 9 + drivers/staging/android/Makefile | 1 + drivers/staging/android/TODO | 10 + drivers/staging/android/uapi/vsoc_shm.h | 303 ++++++ drivers/staging/android/vsoc.c | 1169 +++++++++++++++++++++++ 5 files changed, 1492 insertions(+) create mode 100644 drivers/staging/android/uapi/vsoc_shm.h create mode 100644 drivers/staging/android/vsoc.c diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 7bd27a42b9e8..a17c483f906e 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -33,6 +33,15 @@ config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES /sys/module/lowmemorykiller/parameters/adj and convert them to oom_score_adj values. +config ANDROID_VSOC + tristate "Android Virtual SoC support" + default n + depends on PCI_MSI + ---help--- + This option adds support for the Virtual SoC driver needed to boot + a 'cuttlefish' Android image inside QEmu. The driver interacts with + a QEmu ivshmem device. If built as a module, it will be called vsoc. + source "drivers/staging/android/ion/Kconfig" source "drivers/staging/android/fiq_debugger/Kconfig" diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 21b0ff4a158a..93c5f5a7390a 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o +obj-$(CONFIG_ANDROID_VSOC) += vsoc.o diff --git a/drivers/staging/android/TODO b/drivers/staging/android/TODO index 64d8c8720960..dd64148f1587 100644 --- a/drivers/staging/android/TODO +++ b/drivers/staging/android/TODO @@ -33,5 +33,15 @@ sync framework: - clean up and ABI check for security issues - move it to drivers/base/dma-buf +vsoc.c, uapi/vsoc_shm.h + - The current driver uses the same wait queue for all of the futexes in a + region. This will cause false wakeups in regions with a large number of + waiting threads. We should eventually use multiple queues and select the + queue based on the region. + - Add debugfs support for examining the permissions of regions. + - Use ioremap_wc instead of ioremap_nocache. + - Remove VSOC_WAIT_FOR_INCOMING_INTERRUPT ioctl. This functionality has been + superseded by the futex and is there for legacy reasons. + Please send patches to Greg Kroah-Hartman and Cc: Arve Hjønnevåg and Riley Andrews diff --git a/drivers/staging/android/uapi/vsoc_shm.h b/drivers/staging/android/uapi/vsoc_shm.h new file mode 100644 index 000000000000..741b1387c25b --- /dev/null +++ b/drivers/staging/android/uapi/vsoc_shm.h @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2017 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _UAPI_LINUX_VSOC_SHM_H +#define _UAPI_LINUX_VSOC_SHM_H + +#include + +/** + * A permission is a token that permits a receiver to read and/or write an area + * of memory within a Vsoc region. + * + * An fd_scoped permission grants both read and write access, and can be + * attached to a file description (see open(2)). + * Ownership of the area can then be shared by passing a file descriptor + * among processes. + * + * begin_offset and end_offset define the area of memory that is controlled by + * the permission. owner_offset points to a word, also in shared memory, that + * controls ownership of the area. + * + * ownership of the region expires when the associated file description is + * released. + * + * At most one permission can be attached to each file description. + * + * This is useful when implementing HALs like gralloc that scope and pass + * ownership of shared resources via file descriptors. + * + * The caller is responsibe for doing any fencing. + * + * The calling process will normally identify a currently free area of + * memory. It will construct a proposed fd_scoped_permission_arg structure: + * + * begin_offset and end_offset describe the area being claimed + * + * owner_offset points to the location in shared memory that indicates the + * owner of the area. + * + * owned_value is the value that will be stored in owner_offset iff the + * permission can be granted. It must be different than VSOC_REGION_FREE. + * + * Two fd_scoped_permission structures are compatible if they vary only by + * their owned_value fields. + * + * The driver ensures that, for any group of simultaneous callers proposing + * compatible fd_scoped_permissions, it will accept exactly one of the + * propopsals. The other callers will get a failure with errno of EAGAIN. + * + * A process receiving a file descriptor can identify the region being + * granted using the VSOC_GET_FD_SCOPED_PERMISSION ioctl. + */ +struct fd_scoped_permission { + __u32 begin_offset; + __u32 end_offset; + __u32 owner_offset; + __u32 owned_value; +}; + +/* + * This value represents a free area of memory. The driver expects to see this + * value at owner_offset when creating a permission otherwise it will not do it, + * and will write this value back once the permission is no longer needed. + */ +#define VSOC_REGION_FREE ((__u32)0) + +/** + * ioctl argument for VSOC_CREATE_FD_SCOPE_PERMISSION + */ +struct fd_scoped_permission_arg { + struct fd_scoped_permission perm; + __s32 managed_region_fd; +}; + +#define VSOC_NODE_FREE ((__u32)0) + +/* + * Describes a signal table in shared memory. Each non-zero entry in the + * table indicates that the receiver should signal the futex at the given + * offset. Offsets are relative to the region, not the shared memory window. + * + * interrupt_signalled_offset is used to reliably signal interrupts across the + * vmm boundary. There are two roles: transmitter and receiver. For example, + * in the host_to_guest_signal_table the host is the transmitter and the + * guest is the receiver. The protocol is as follows: + * + * 1. The transmitter should convert the offset of the futex to an offset + * in the signal table [0, (1 << num_nodes_lg2)) + * The transmitter can choose any appropriate hashing algorithm, including + * hash = futex_offset & ((1 << num_nodes_lg2) - 1) + * + * 3. The transmitter should atomically compare and swap futex_offset with 0 + * at hash. There are 3 possible outcomes + * a. The swap fails because the futex_offset is already in the table. + * The transmitter should stop. + * b. Some other offset is in the table. This is a hash collision. The + * transmitter should move to another table slot and try again. One + * possible algorithm: + * hash = (hash + 1) & ((1 << num_nodes_lg2) - 1) + * c. The swap worked. Continue below. + * + * 3. The transmitter atomically swaps 1 with the value at the + * interrupt_signalled_offset. There are two outcomes: + * a. The prior value was 1. In this case an interrupt has already been + * posted. The transmitter is done. + * b. The prior value was 0, indicating that the receiver may be sleeping. + * The transmitter will issue an interrupt. + * + * 4. On waking the receiver immediately exchanges a 0 with the + * interrupt_signalled_offset. If it receives a 0 then this a spurious + * interrupt. That may occasionally happen in the current protocol, but + * should be rare. + * + * 5. The receiver scans the signal table by atomicaly exchanging 0 at each + * location. If a non-zero offset is returned from the exchange the + * receiver wakes all sleepers at the given offset: + * futex((int*)(region_base + old_value), FUTEX_WAKE, MAX_INT); + * + * 6. The receiver thread then does a conditional wait, waking immediately + * if the value at interrupt_signalled_offset is non-zero. This catches cases + * here additional signals were posted while the table was being scanned. + * On the guest the wait is handled via the VSOC_WAIT_FOR_INCOMING_INTERRUPT + * ioctl. + */ +struct vsoc_signal_table_layout { + /* log_2(Number of signal table entries) */ + __u32 num_nodes_lg2; + /* + * Offset to the first signal table entry relative to the start of the + * region + */ + __u32 futex_uaddr_table_offset; + /* + * Offset to an atomic_t / atomic uint32_t. A non-zero value indicates + * that one or more offsets are currently posted in the table. + * semi-unique access to an entry in the table + */ + __u32 interrupt_signalled_offset; +}; + +#define VSOC_REGION_WHOLE ((__s32)0) +#define VSOC_DEVICE_NAME_SZ 16 + +/** + * Each HAL would (usually) talk to a single device region + * Mulitple entities care about these regions: + * - The ivshmem_server will populate the regions in shared memory + * - The guest kernel will read the region, create minor device nodes, and + * allow interested parties to register for FUTEX_WAKE events in the region + * - HALs will access via the minor device nodes published by the guest kernel + * - Host side processes will access the region via the ivshmem_server: + * 1. Pass name to ivshmem_server at a UNIX socket + * 2. ivshmemserver will reply with 2 fds: + * - host->guest doorbell fd + * - guest->host doorbell fd + * - fd for the shared memory region + * - region offset + * 3. Start a futex receiver thread on the doorbell fd pointed at the + * signal_nodes + */ +struct vsoc_device_region { + __u16 current_version; + __u16 min_compatible_version; + __u32 region_begin_offset; + __u32 region_end_offset; + __u32 offset_of_region_data; + struct vsoc_signal_table_layout guest_to_host_signal_table; + struct vsoc_signal_table_layout host_to_guest_signal_table; + /* Name of the device. Must always be terminated with a '\0', so + * the longest supported device name is 15 characters. + */ + char device_name[VSOC_DEVICE_NAME_SZ]; + /* There are two ways that permissions to access regions are handled: + * - When subdivided_by is VSOC_REGION_WHOLE, any process that can + * open the device node for the region gains complete access to it. + * - When subdivided is set processes that open the region cannot + * access it. Access to a sub-region must be established by invoking + * the VSOC_CREATE_FD_SCOPE_PERMISSION ioctl on the region + * referenced in subdivided_by, providing a fileinstance + * (represented by a fd) opened on this region. + */ + __u32 managed_by; +}; + +/* + * The vsoc layout descriptor. + * The first 4K should be reserved for the shm header and region descriptors. + * The regions should be page aligned. + */ + +struct vsoc_shm_layout_descriptor { + __u16 major_version; + __u16 minor_version; + + /* size of the shm. This may be redundant but nice to have */ + __u32 size; + + /* number of shared memory regions */ + __u32 region_count; + + /* The offset to the start of region descriptors */ + __u32 vsoc_region_desc_offset; +}; + +/* + * This specifies the current version that should be stored in + * vsoc_shm_layout_descriptor.major_version and + * vsoc_shm_layout_descriptor.minor_version. + * It should be updated only if the vsoc_device_region and + * vsoc_shm_layout_descriptor structures have changed. + * Versioning within each region is transferred + * via the min_compatible_version and current_version fields in + * vsoc_device_region. The driver does not consult these fields: they are left + * for the HALs and host processes and will change independently of the layout + * version. + */ +#define CURRENT_VSOC_LAYOUT_MAJOR_VERSION 2 +#define CURRENT_VSOC_LAYOUT_MINOR_VERSION 0 + +#define VSOC_CREATE_FD_SCOPED_PERMISSION \ + _IOW(0xF5, 0, struct fd_scoped_permission) +#define VSOC_GET_FD_SCOPED_PERMISSION _IOR(0xF5, 1, struct fd_scoped_permission) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt if one is not already + * in flight. + */ +#define VSOC_MAYBE_SEND_INTERRUPT_TO_HOST _IO(0xF5, 2) + +/* + * When this returns the guest will scan host_to_guest_signal_table to + * check for new futexes to wake. + */ +/* TODO(ghartman): Consider moving this to the bottom half */ +#define VSOC_WAIT_FOR_INCOMING_INTERRUPT _IO(0xF5, 3) + +/* + * Guest HALs will use this to retrieve the region description after + * opening their device node. + */ +#define VSOC_DESCRIBE_REGION _IOR(0xF5, 4, struct vsoc_device_region) + +/* + * Wake any threads that may be waiting for a host interrupt on this region. + * This is mostly used during shutdown. + */ +#define VSOC_SELF_INTERRUPT _IO(0xF5, 5) + +/* + * This is used to signal the host to scan the guest_to_host_signal_table + * for new futexes to wake. This sends an interrupt unconditionally. + */ +#define VSOC_SEND_INTERRUPT_TO_HOST _IO(0xF5, 6) + +enum wait_types { + VSOC_WAIT_UNDEFINED = 0, + VSOC_WAIT_IF_EQUAL = 1, + VSOC_WAIT_IF_EQUAL_TIMEOUT = 2 +}; + +/* + * Wait for a condition to be true + * + * Note, this is sized and aligned so the 32 bit and 64 bit layouts are + * identical. + */ +struct vsoc_cond_wait { + /* Input: Offset of the 32 bit word to check */ + __u32 offset; + /* Input: Value that will be compared with the offset */ + __u32 value; + /* Monotonic time to wake at in seconds */ + __u64 wake_time_sec; + /* Input: Monotonic time to wait in nanoseconds */ + __u32 wake_time_nsec; + /* Input: Type of wait */ + __u32 wait_type; + /* Output: Number of times the thread woke before returning. */ + __u32 wakes; + /* Ensure that we're 8-byte aligned and 8 byte length for 32/64 bit + * compatibility. + */ + __u32 reserved_1; +}; + +#define VSOC_COND_WAIT _IOWR(0xF5, 7, struct vsoc_cond_wait) + +/* Wake any local threads waiting at the offset given in arg */ +#define VSOC_COND_WAKE _IO(0xF5, 8) + +#endif /* _UAPI_LINUX_VSOC_SHM_H */ diff --git a/drivers/staging/android/vsoc.c b/drivers/staging/android/vsoc.c new file mode 100644 index 000000000000..587c66d709b9 --- /dev/null +++ b/drivers/staging/android/vsoc.c @@ -0,0 +1,1169 @@ +/* + * drivers/android/staging/vsoc.c + * + * Android Virtual System on a Chip (VSoC) driver + * + * Copyright (C) 2017 Google, Inc. + * + * Author: ghartman@google.com + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Based on drivers/char/kvm_ivshmem.c - driver for KVM Inter-VM shared memory + * Copyright 2009 Cam Macdonell + * + * Based on cirrusfb.c and 8139cp.c: + * Copyright 1999-2001 Jeff Garzik + * Copyright 2001-2004 Jeff Garzik + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uapi/vsoc_shm.h" + +#define VSOC_DEV_NAME "vsoc" + +/* + * Description of the ivshmem-doorbell PCI device used by QEmu. These + * constants follow docs/specs/ivshmem-spec.txt, which can be found in + * the QEmu repository. This was last reconciled with the version that + * came out with 2.8 + */ + +/* + * These constants are determined KVM Inter-VM shared memory device + * register offsets + */ +enum { + INTR_MASK = 0x00, /* Interrupt Mask */ + INTR_STATUS = 0x04, /* Interrupt Status */ + IV_POSITION = 0x08, /* VM ID */ + DOORBELL = 0x0c, /* Doorbell */ +}; + +static const int REGISTER_BAR; /* Equal to 0 */ +static const int MAX_REGISTER_BAR_LEN = 0x100; +/* + * The MSI-x BAR is not used directly. + * + * static const int MSI_X_BAR = 1; + */ +static const int SHARED_MEMORY_BAR = 2; + +struct vsoc_region_data { + char name[VSOC_DEVICE_NAME_SZ + 1]; + wait_queue_head_t interrupt_wait_queue; + /* TODO(b/73664181): Use multiple futex wait queues */ + wait_queue_head_t futex_wait_queue; + /* Flag indicating that an interrupt has been signalled by the host. */ + atomic_t *incoming_signalled; + /* Flag indicating the guest has signalled the host. */ + atomic_t *outgoing_signalled; + int irq_requested; + int device_created; +}; + +struct vsoc_device { + /* Kernel virtual address of REGISTER_BAR. */ + void __iomem *regs; + /* Physical address of SHARED_MEMORY_BAR. */ + phys_addr_t shm_phys_start; + /* Kernel virtual address of SHARED_MEMORY_BAR. */ + void *kernel_mapped_shm; + /* Size of the entire shared memory window in bytes. */ + size_t shm_size; + /* + * Pointer to the virtual address of the shared memory layout structure. + * This is probably identical to kernel_mapped_shm, but saving this + * here saves a lot of annoying casts. + */ + struct vsoc_shm_layout_descriptor *layout; + /* + * Points to a table of region descriptors in the kernel's virtual + * address space. Calculated from + * vsoc_shm_layout_descriptor.vsoc_region_desc_offset + */ + struct vsoc_device_region *regions; + /* Head of a list of permissions that have been granted. */ + struct list_head permissions; + struct pci_dev *dev; + /* Per-region (and therefore per-interrupt) information. */ + struct vsoc_region_data *regions_data; + /* + * Table of msi-x entries. This has to be separated from struct + * vsoc_region_data because the kernel deals with them as an array. + */ + struct msix_entry *msix_entries; + /* + * Flags that indicate what we've initialzied. These are used to do an + * orderly cleanup of the device. + */ + char enabled_device; + char requested_regions; + char cdev_added; + char class_added; + char msix_enabled; + /* Mutex that protectes the permission list */ + struct mutex mtx; + /* Major number assigned by the kernel */ + int major; + + struct cdev cdev; + struct class *class; +}; + +static struct vsoc_device vsoc_dev; + +/* + * TODO(ghartman): Add a /sys filesystem entry that summarizes the permissions. + */ + +struct fd_scoped_permission_node { + struct fd_scoped_permission permission; + struct list_head list; +}; + +struct vsoc_private_data { + struct fd_scoped_permission_node *fd_scoped_permission_node; +}; + +static long vsoc_ioctl(struct file *, unsigned int, unsigned long); +static int vsoc_mmap(struct file *, struct vm_area_struct *); +static int vsoc_open(struct inode *, struct file *); +static int vsoc_release(struct inode *, struct file *); +static ssize_t vsoc_read(struct file *, char *, size_t, loff_t *); +static ssize_t vsoc_write(struct file *, const char *, size_t, loff_t *); +static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin); +static int do_create_fd_scoped_permission( + struct vsoc_device_region *region_p, + struct fd_scoped_permission_node *np, + struct fd_scoped_permission_arg *__user arg); +static void do_destroy_fd_scoped_permission( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission *perm); +static long do_vsoc_describe_region(struct file *, + struct vsoc_device_region __user *); +static ssize_t vsoc_get_area(struct file *filp, __u32 *perm_off); + +/** + * Validate arguments on entry points to the driver. + */ +inline int vsoc_validate_inode(struct inode *inode) +{ + if (iminor(inode) >= vsoc_dev.layout->region_count) { + dev_err(&vsoc_dev.dev->dev, + "describe_region: invalid region %d\n", iminor(inode)); + return -ENODEV; + } + return 0; +} + +inline int vsoc_validate_filep(struct file *filp) +{ + int ret = vsoc_validate_inode(file_inode(filp)); + + if (ret) + return ret; + if (!filp->private_data) { + dev_err(&vsoc_dev.dev->dev, + "No private data on fd, region %d\n", + iminor(file_inode(filp))); + return -EBADFD; + } + return 0; +} + +/* Converts from shared memory offset to virtual address */ +static inline void *shm_off_to_virtual_addr(__u32 offset) +{ + return vsoc_dev.kernel_mapped_shm + offset; +} + +/* Converts from shared memory offset to physical address */ +static inline phys_addr_t shm_off_to_phys_addr(__u32 offset) +{ + return vsoc_dev.shm_phys_start + offset; +} + +/** + * Convenience functions to obtain the region from the inode or file. + * Dangerous to call before validating the inode/file. + */ +static inline struct vsoc_device_region *vsoc_region_from_inode( + struct inode *inode) +{ + return &vsoc_dev.regions[iminor(inode)]; +} + +static inline struct vsoc_device_region *vsoc_region_from_filep( + struct file *inode) +{ + return vsoc_region_from_inode(file_inode(inode)); +} + +static inline uint32_t vsoc_device_region_size(struct vsoc_device_region *r) +{ + return r->region_end_offset - r->region_begin_offset; +} + +static const struct file_operations vsoc_ops = { + .owner = THIS_MODULE, + .open = vsoc_open, + .mmap = vsoc_mmap, + .read = vsoc_read, + .unlocked_ioctl = vsoc_ioctl, + .compat_ioctl = vsoc_ioctl, + .write = vsoc_write, + .llseek = vsoc_lseek, + .release = vsoc_release, +}; + +static struct pci_device_id vsoc_id_table[] = { + {0x1af4, 0x1110, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0}, +}; + +MODULE_DEVICE_TABLE(pci, vsoc_id_table); + +static void vsoc_remove_device(struct pci_dev *pdev); +static int vsoc_probe_device(struct pci_dev *pdev, + const struct pci_device_id *ent); + +static struct pci_driver vsoc_pci_driver = { + .name = "vsoc", + .id_table = vsoc_id_table, + .probe = vsoc_probe_device, + .remove = vsoc_remove_device, +}; + +static int do_create_fd_scoped_permission( + struct vsoc_device_region *region_p, + struct fd_scoped_permission_node *np, + struct fd_scoped_permission_arg *__user arg) +{ + struct file *managed_filp; + s32 managed_fd; + atomic_t *owner_ptr = NULL; + struct vsoc_device_region *managed_region_p; + + if (copy_from_user(&np->permission, &arg->perm, sizeof(*np)) || + copy_from_user(&managed_fd, + &arg->managed_region_fd, sizeof(managed_fd))) { + return -EFAULT; + } + managed_filp = fdget(managed_fd).file; + /* Check that it's a valid fd, */ + if (!managed_filp || vsoc_validate_filep(managed_filp)) + return -EPERM; + /* EEXIST if the given fd already has a permission. */ + if (((struct vsoc_private_data *)managed_filp->private_data)-> + fd_scoped_permission_node) + return -EEXIST; + managed_region_p = vsoc_region_from_filep(managed_filp); + /* Check that the provided region is managed by this one */ + if (&vsoc_dev.regions[managed_region_p->managed_by] != region_p) + return -EPERM; + /* The area must be well formed and have non-zero size */ + if (np->permission.begin_offset >= np->permission.end_offset) + return -EINVAL; + /* The area must fit in the memory window */ + if (np->permission.end_offset > + vsoc_device_region_size(managed_region_p)) + return -ERANGE; + /* The area must be in the region data section */ + if (np->permission.begin_offset < + managed_region_p->offset_of_region_data) + return -ERANGE; + /* The area must be page aligned */ + if (!PAGE_ALIGNED(np->permission.begin_offset) || + !PAGE_ALIGNED(np->permission.end_offset)) + return -EINVAL; + /* Owner offset must be naturally aligned in the window */ + if (np->permission.owner_offset & + (sizeof(np->permission.owner_offset) - 1)) + return -EINVAL; + /* The owner flag must reside in the owner memory */ + if (np->permission.owner_offset + sizeof(np->permission.owner_offset) > + vsoc_device_region_size(region_p)) + return -ERANGE; + /* The owner flag must reside in the data section */ + if (np->permission.owner_offset < region_p->offset_of_region_data) + return -EINVAL; + /* The owner value must change to claim the memory */ + if (np->permission.owned_value == VSOC_REGION_FREE) + return -EINVAL; + owner_ptr = + (atomic_t *)shm_off_to_virtual_addr(region_p->region_begin_offset + + np->permission.owner_offset); + /* We've already verified that this is in the shared memory window, so + * it should be safe to write to this address. + */ + if (atomic_cmpxchg(owner_ptr, + VSOC_REGION_FREE, + np->permission.owned_value) != VSOC_REGION_FREE) { + return -EBUSY; + } + ((struct vsoc_private_data *)managed_filp->private_data)-> + fd_scoped_permission_node = np; + /* The file offset needs to be adjusted if the calling + * process did any read/write operations on the fd + * before creating the permission. + */ + if (managed_filp->f_pos) { + if (managed_filp->f_pos > np->permission.end_offset) { + /* If the offset is beyond the permission end, set it + * to the end. + */ + managed_filp->f_pos = np->permission.end_offset; + } else { + /* If the offset is within the permission interval + * keep it there otherwise reset it to zero. + */ + if (managed_filp->f_pos < np->permission.begin_offset) { + managed_filp->f_pos = 0; + } else { + managed_filp->f_pos -= + np->permission.begin_offset; + } + } + } + return 0; +} + +static void do_destroy_fd_scoped_permission_node( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission_node *node) +{ + if (node) { + do_destroy_fd_scoped_permission(owner_region_p, + &node->permission); + mutex_lock(&vsoc_dev.mtx); + list_del(&node->list); + mutex_unlock(&vsoc_dev.mtx); + kfree(node); + } +} + +static void do_destroy_fd_scoped_permission( + struct vsoc_device_region *owner_region_p, + struct fd_scoped_permission *perm) +{ + atomic_t *owner_ptr = NULL; + int prev = 0; + + if (!perm) + return; + owner_ptr = (atomic_t *)shm_off_to_virtual_addr( + owner_region_p->region_begin_offset + perm->owner_offset); + prev = atomic_xchg(owner_ptr, VSOC_REGION_FREE); + if (prev != perm->owned_value) + dev_err(&vsoc_dev.dev->dev, + "%x-%x: owner (%s) %x: expected to be %x was %x", + perm->begin_offset, perm->end_offset, + owner_region_p->device_name, perm->owner_offset, + perm->owned_value, prev); +} + +static long do_vsoc_describe_region(struct file *filp, + struct vsoc_device_region __user *dest) +{ + struct vsoc_device_region *region_p; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + region_p = vsoc_region_from_filep(filp); + if (copy_to_user(dest, region_p, sizeof(*region_p))) + return -EFAULT; + return 0; +} + +/** + * Implements the inner logic of cond_wait. Copies to and from userspace are + * done in the helper function below. + */ +static int handle_vsoc_cond_wait(struct file *filp, struct vsoc_cond_wait *arg) +{ + DEFINE_WAIT(wait); + u32 region_number = iminor(file_inode(filp)); + struct vsoc_region_data *data = vsoc_dev.regions_data + region_number; + struct hrtimer_sleeper timeout, *to = NULL; + int ret = 0; + struct vsoc_device_region *region_p = vsoc_region_from_filep(filp); + atomic_t *address = NULL; + struct timespec ts; + + /* Ensure that the offset is aligned */ + if (arg->offset & (sizeof(uint32_t) - 1)) + return -EADDRNOTAVAIL; + /* Ensure that the offset is within shared memory */ + if (((uint64_t)arg->offset) + region_p->region_begin_offset + + sizeof(uint32_t) > region_p->region_end_offset) + return -E2BIG; + address = shm_off_to_virtual_addr(region_p->region_begin_offset + + arg->offset); + + /* Ensure that the type of wait is valid */ + switch (arg->wait_type) { + case VSOC_WAIT_IF_EQUAL: + break; + case VSOC_WAIT_IF_EQUAL_TIMEOUT: + to = &timeout; + break; + default: + return -EINVAL; + } + + if (to) { + /* Copy the user-supplied timesec into the kernel structure. + * We do things this way to flatten differences between 32 bit + * and 64 bit timespecs. + */ + ts.tv_sec = arg->wake_time_sec; + ts.tv_nsec = arg->wake_time_nsec; + + if (!timespec_valid(&ts)) + return -EINVAL; + hrtimer_init_on_stack(&to->timer, CLOCK_MONOTONIC, + HRTIMER_MODE_ABS); + hrtimer_set_expires_range_ns(&to->timer, timespec_to_ktime(ts), + current->timer_slack_ns); + + hrtimer_init_sleeper(to, current); + } + + while (1) { + prepare_to_wait(&data->futex_wait_queue, &wait, + TASK_INTERRUPTIBLE); + /* + * Check the sentinel value after prepare_to_wait. If the value + * changes after this check the writer will call signal, + * changing the task state from INTERRUPTIBLE to RUNNING. That + * will ensure that schedule() will eventually schedule this + * task. + */ + if (atomic_read(address) != arg->value) { + ret = 0; + break; + } + if (to) { + hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS); + if (likely(to->task)) + freezable_schedule(); + hrtimer_cancel(&to->timer); + if (!to->task) { + ret = -ETIMEDOUT; + break; + } + } else { + freezable_schedule(); + } + /* Count the number of times that we woke up. This is useful + * for unit testing. + */ + ++arg->wakes; + if (signal_pending(current)) { + ret = -EINTR; + break; + } + } + finish_wait(&data->futex_wait_queue, &wait); + if (to) + destroy_hrtimer_on_stack(&to->timer); + return ret; +} + +/** + * Handles the details of copying from/to userspace to ensure that the copies + * happen on all of the return paths of cond_wait. + */ +static int do_vsoc_cond_wait(struct file *filp, + struct vsoc_cond_wait __user *untrusted_in) +{ + struct vsoc_cond_wait arg; + int rval = 0; + + if (copy_from_user(&arg, untrusted_in, sizeof(arg))) + return -EFAULT; + /* wakes is an out parameter. Initialize it to something sensible. */ + arg.wakes = 0; + rval = handle_vsoc_cond_wait(filp, &arg); + if (copy_to_user(untrusted_in, &arg, sizeof(arg))) + return -EFAULT; + return rval; +} + +static int do_vsoc_cond_wake(struct file *filp, uint32_t offset) +{ + struct vsoc_device_region *region_p = vsoc_region_from_filep(filp); + u32 region_number = iminor(file_inode(filp)); + struct vsoc_region_data *data = vsoc_dev.regions_data + region_number; + /* Ensure that the offset is aligned */ + if (offset & (sizeof(uint32_t) - 1)) + return -EADDRNOTAVAIL; + /* Ensure that the offset is within shared memory */ + if (((uint64_t)offset) + region_p->region_begin_offset + + sizeof(uint32_t) > region_p->region_end_offset) + return -E2BIG; + /* + * TODO(b/73664181): Use multiple futex wait queues. + * We need to wake every sleeper when the condition changes. Typically + * only a single thread will be waiting on the condition, but there + * are exceptions. The worst case is about 10 threads. + */ + wake_up_interruptible_all(&data->futex_wait_queue); + return 0; +} + +static long vsoc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int rv = 0; + struct vsoc_device_region *region_p; + u32 reg_num; + struct vsoc_region_data *reg_data; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + region_p = vsoc_region_from_filep(filp); + reg_num = iminor(file_inode(filp)); + reg_data = vsoc_dev.regions_data + reg_num; + switch (cmd) { + case VSOC_CREATE_FD_SCOPED_PERMISSION: + { + struct fd_scoped_permission_node *node = NULL; + + node = kzalloc(sizeof(*node), GFP_KERNEL); + /* We can't allocate memory for the permission */ + if (!node) + return -ENOMEM; + INIT_LIST_HEAD(&node->list); + rv = do_create_fd_scoped_permission( + region_p, + node, + (struct fd_scoped_permission_arg __user *)arg); + if (!rv) { + mutex_lock(&vsoc_dev.mtx); + list_add(&node->list, &vsoc_dev.permissions); + mutex_unlock(&vsoc_dev.mtx); + } else { + kfree(node); + return rv; + } + } + break; + + case VSOC_GET_FD_SCOPED_PERMISSION: + { + struct fd_scoped_permission_node *node = + ((struct vsoc_private_data *)filp->private_data)-> + fd_scoped_permission_node; + if (!node) + return -ENOENT; + if (copy_to_user + ((struct fd_scoped_permission __user *)arg, + &node->permission, sizeof(node->permission))) + return -EFAULT; + } + break; + + case VSOC_MAYBE_SEND_INTERRUPT_TO_HOST: + if (!atomic_xchg( + reg_data->outgoing_signalled, + 1)) { + writel(reg_num, vsoc_dev.regs + DOORBELL); + return 0; + } else { + return -EBUSY; + } + break; + + case VSOC_SEND_INTERRUPT_TO_HOST: + writel(reg_num, vsoc_dev.regs + DOORBELL); + return 0; + + case VSOC_WAIT_FOR_INCOMING_INTERRUPT: + wait_event_interruptible( + reg_data->interrupt_wait_queue, + (atomic_read(reg_data->incoming_signalled) != 0)); + break; + + case VSOC_DESCRIBE_REGION: + return do_vsoc_describe_region( + filp, + (struct vsoc_device_region __user *)arg); + + case VSOC_SELF_INTERRUPT: + atomic_set(reg_data->incoming_signalled, 1); + wake_up_interruptible(®_data->interrupt_wait_queue); + break; + + case VSOC_COND_WAIT: + return do_vsoc_cond_wait(filp, + (struct vsoc_cond_wait __user *)arg); + case VSOC_COND_WAKE: + return do_vsoc_cond_wake(filp, arg); + + default: + return -EINVAL; + } + return 0; +} + +static ssize_t vsoc_read(struct file *filp, char *buffer, size_t len, + loff_t *poffset) +{ + __u32 area_off; + void *area_p; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + area_p = shm_off_to_virtual_addr(area_off); + area_p += *poffset; + area_len -= *poffset; + if (area_len <= 0) + return 0; + if (area_len < len) + len = area_len; + if (copy_to_user(buffer, area_p, len)) + return -EFAULT; + *poffset += len; + return len; +} + +static loff_t vsoc_lseek(struct file *filp, loff_t offset, int origin) +{ + ssize_t area_len = 0; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, NULL); + switch (origin) { + case SEEK_SET: + break; + + case SEEK_CUR: + if (offset > 0 && offset + filp->f_pos < 0) + return -EOVERFLOW; + offset += filp->f_pos; + break; + + case SEEK_END: + if (offset > 0 && offset + area_len < 0) + return -EOVERFLOW; + offset += area_len; + break; + + case SEEK_DATA: + if (offset >= area_len) + return -EINVAL; + if (offset < 0) + offset = 0; + break; + + case SEEK_HOLE: + /* Next hole is always the end of the region, unless offset is + * beyond that + */ + if (offset < area_len) + offset = area_len; + break; + + default: + return -EINVAL; + } + + if (offset < 0 || offset > area_len) + return -EINVAL; + filp->f_pos = offset; + + return offset; +} + +static ssize_t vsoc_write(struct file *filp, const char *buffer, + size_t len, loff_t *poffset) +{ + __u32 area_off; + void *area_p; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + area_p = shm_off_to_virtual_addr(area_off); + area_p += *poffset; + area_len -= *poffset; + if (area_len <= 0) + return 0; + if (area_len < len) + len = area_len; + if (copy_from_user(area_p, buffer, len)) + return -EFAULT; + *poffset += len; + return len; +} + +static irqreturn_t vsoc_interrupt(int irq, void *region_data_v) +{ + struct vsoc_region_data *region_data = + (struct vsoc_region_data *)region_data_v; + int reg_num = region_data - vsoc_dev.regions_data; + + if (unlikely(!region_data)) + return IRQ_NONE; + + if (unlikely(reg_num < 0 || + reg_num >= vsoc_dev.layout->region_count)) { + dev_err(&vsoc_dev.dev->dev, + "invalid irq @%p reg_num=0x%04x\n", + region_data, reg_num); + return IRQ_NONE; + } + if (unlikely(vsoc_dev.regions_data + reg_num != region_data)) { + dev_err(&vsoc_dev.dev->dev, + "irq not aligned @%p reg_num=0x%04x\n", + region_data, reg_num); + return IRQ_NONE; + } + wake_up_interruptible(®ion_data->interrupt_wait_queue); + return IRQ_HANDLED; +} + +static int vsoc_probe_device(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int result; + int i; + resource_size_t reg_size; + dev_t devt; + + vsoc_dev.dev = pdev; + result = pci_enable_device(pdev); + if (result) { + dev_err(&pdev->dev, + "pci_enable_device failed %s: error %d\n", + pci_name(pdev), result); + return result; + } + vsoc_dev.enabled_device = 1; + result = pci_request_regions(pdev, "vsoc"); + if (result < 0) { + dev_err(&pdev->dev, "pci_request_regions failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.requested_regions = 1; + /* Set up the control registers in BAR 0 */ + reg_size = pci_resource_len(pdev, REGISTER_BAR); + if (reg_size > MAX_REGISTER_BAR_LEN) + vsoc_dev.regs = + pci_iomap(pdev, REGISTER_BAR, MAX_REGISTER_BAR_LEN); + else + vsoc_dev.regs = pci_iomap(pdev, REGISTER_BAR, reg_size); + + if (!vsoc_dev.regs) { + dev_err(&pdev->dev, + "cannot ioremap registers of size %zu\n", + (size_t)reg_size); + vsoc_remove_device(pdev); + return -EBUSY; + } + + /* Map the shared memory in BAR 2 */ + vsoc_dev.shm_phys_start = pci_resource_start(pdev, SHARED_MEMORY_BAR); + vsoc_dev.shm_size = pci_resource_len(pdev, SHARED_MEMORY_BAR); + + dev_info(&pdev->dev, "shared memory @ DMA %p size=0x%zx\n", + (void *)vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + /* TODO(ghartman): ioremap_wc should work here */ + vsoc_dev.kernel_mapped_shm = ioremap_nocache( + vsoc_dev.shm_phys_start, vsoc_dev.shm_size); + if (!vsoc_dev.kernel_mapped_shm) { + dev_err(&vsoc_dev.dev->dev, "cannot iomap region\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + + vsoc_dev.layout = + (struct vsoc_shm_layout_descriptor *)vsoc_dev.kernel_mapped_shm; + dev_info(&pdev->dev, "major_version: %d\n", + vsoc_dev.layout->major_version); + dev_info(&pdev->dev, "minor_version: %d\n", + vsoc_dev.layout->minor_version); + dev_info(&pdev->dev, "size: 0x%x\n", vsoc_dev.layout->size); + dev_info(&pdev->dev, "regions: %d\n", vsoc_dev.layout->region_count); + if (vsoc_dev.layout->major_version != + CURRENT_VSOC_LAYOUT_MAJOR_VERSION) { + dev_err(&vsoc_dev.dev->dev, + "driver supports only major_version %d\n", + CURRENT_VSOC_LAYOUT_MAJOR_VERSION); + vsoc_remove_device(pdev); + return -EBUSY; + } + result = alloc_chrdev_region(&devt, 0, vsoc_dev.layout->region_count, + VSOC_DEV_NAME); + if (result) { + dev_err(&vsoc_dev.dev->dev, "alloc_chrdev_region failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.major = MAJOR(devt); + cdev_init(&vsoc_dev.cdev, &vsoc_ops); + vsoc_dev.cdev.owner = THIS_MODULE; + result = cdev_add(&vsoc_dev.cdev, devt, vsoc_dev.layout->region_count); + if (result) { + dev_err(&vsoc_dev.dev->dev, "cdev_add error\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.cdev_added = 1; + vsoc_dev.class = class_create(THIS_MODULE, VSOC_DEV_NAME); + if (IS_ERR(vsoc_dev.class)) { + dev_err(&vsoc_dev.dev->dev, "class_create failed\n"); + vsoc_remove_device(pdev); + return PTR_ERR(vsoc_dev.class); + } + vsoc_dev.class_added = 1; + vsoc_dev.regions = (struct vsoc_device_region *) + (vsoc_dev.kernel_mapped_shm + + vsoc_dev.layout->vsoc_region_desc_offset); + vsoc_dev.msix_entries = kcalloc( + vsoc_dev.layout->region_count, + sizeof(vsoc_dev.msix_entries[0]), GFP_KERNEL); + if (!vsoc_dev.msix_entries) { + dev_err(&vsoc_dev.dev->dev, + "unable to allocate msix_entries\n"); + vsoc_remove_device(pdev); + return -ENOSPC; + } + vsoc_dev.regions_data = kcalloc( + vsoc_dev.layout->region_count, + sizeof(vsoc_dev.regions_data[0]), GFP_KERNEL); + if (!vsoc_dev.regions_data) { + dev_err(&vsoc_dev.dev->dev, + "unable to allocate regions' data\n"); + vsoc_remove_device(pdev); + return -ENOSPC; + } + for (i = 0; i < vsoc_dev.layout->region_count; ++i) + vsoc_dev.msix_entries[i].entry = i; + + result = pci_enable_msix_exact(vsoc_dev.dev, vsoc_dev.msix_entries, + vsoc_dev.layout->region_count); + if (result) { + dev_info(&pdev->dev, "pci_enable_msix failed: %d\n", result); + vsoc_remove_device(pdev); + return -ENOSPC; + } + /* Check that all regions are well formed */ + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + const struct vsoc_device_region *region = vsoc_dev.regions + i; + + if (!PAGE_ALIGNED(region->region_begin_offset) || + !PAGE_ALIGNED(region->region_end_offset)) { + dev_err(&vsoc_dev.dev->dev, + "region %d not aligned (%x:%x)", i, + region->region_begin_offset, + region->region_end_offset); + vsoc_remove_device(pdev); + return -EFAULT; + } + if (region->region_begin_offset >= region->region_end_offset || + region->region_end_offset > vsoc_dev.shm_size) { + dev_err(&vsoc_dev.dev->dev, + "region %d offsets are wrong: %x %x %zx", + i, region->region_begin_offset, + region->region_end_offset, vsoc_dev.shm_size); + vsoc_remove_device(pdev); + return -EFAULT; + } + if (region->managed_by >= vsoc_dev.layout->region_count) { + dev_err(&vsoc_dev.dev->dev, + "region %d has invalid owner: %u", + i, region->managed_by); + vsoc_remove_device(pdev); + return -EFAULT; + } + } + vsoc_dev.msix_enabled = 1; + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + const struct vsoc_device_region *region = vsoc_dev.regions + i; + size_t name_sz = sizeof(vsoc_dev.regions_data[i].name) - 1; + const struct vsoc_signal_table_layout *h_to_g_signal_table = + ®ion->host_to_guest_signal_table; + const struct vsoc_signal_table_layout *g_to_h_signal_table = + ®ion->guest_to_host_signal_table; + + vsoc_dev.regions_data[i].name[name_sz] = '\0'; + memcpy(vsoc_dev.regions_data[i].name, region->device_name, + name_sz); + dev_info(&pdev->dev, "region %d name=%s\n", + i, vsoc_dev.regions_data[i].name); + init_waitqueue_head( + &vsoc_dev.regions_data[i].interrupt_wait_queue); + init_waitqueue_head(&vsoc_dev.regions_data[i].futex_wait_queue); + vsoc_dev.regions_data[i].incoming_signalled = + vsoc_dev.kernel_mapped_shm + + region->region_begin_offset + + h_to_g_signal_table->interrupt_signalled_offset; + vsoc_dev.regions_data[i].outgoing_signalled = + vsoc_dev.kernel_mapped_shm + + region->region_begin_offset + + g_to_h_signal_table->interrupt_signalled_offset; + + result = request_irq( + vsoc_dev.msix_entries[i].vector, + vsoc_interrupt, 0, + vsoc_dev.regions_data[i].name, + vsoc_dev.regions_data + i); + if (result) { + dev_info(&pdev->dev, + "request_irq failed irq=%d vector=%d\n", + i, vsoc_dev.msix_entries[i].vector); + vsoc_remove_device(pdev); + return -ENOSPC; + } + vsoc_dev.regions_data[i].irq_requested = 1; + if (!device_create(vsoc_dev.class, NULL, + MKDEV(vsoc_dev.major, i), + NULL, vsoc_dev.regions_data[i].name)) { + dev_err(&vsoc_dev.dev->dev, "device_create failed\n"); + vsoc_remove_device(pdev); + return -EBUSY; + } + vsoc_dev.regions_data[i].device_created = 1; + } + return 0; +} + +/* + * This should undo all of the allocations in the probe function in reverse + * order. + * + * Notes: + * + * The device may have been partially initialized, so double check + * that the allocations happened. + * + * This function may be called multiple times, so mark resources as freed + * as they are deallocated. + */ +static void vsoc_remove_device(struct pci_dev *pdev) +{ + int i; + /* + * pdev is the first thing to be set on probe and the last thing + * to be cleared here. If it's NULL then there is no cleanup. + */ + if (!pdev || !vsoc_dev.dev) + return; + dev_info(&pdev->dev, "remove_device\n"); + if (vsoc_dev.regions_data) { + for (i = 0; i < vsoc_dev.layout->region_count; ++i) { + if (vsoc_dev.regions_data[i].device_created) { + device_destroy(vsoc_dev.class, + MKDEV(vsoc_dev.major, i)); + vsoc_dev.regions_data[i].device_created = 0; + } + if (vsoc_dev.regions_data[i].irq_requested) + free_irq(vsoc_dev.msix_entries[i].vector, NULL); + vsoc_dev.regions_data[i].irq_requested = 0; + } + kfree(vsoc_dev.regions_data); + vsoc_dev.regions_data = 0; + } + if (vsoc_dev.msix_enabled) { + pci_disable_msix(pdev); + vsoc_dev.msix_enabled = 0; + } + kfree(vsoc_dev.msix_entries); + vsoc_dev.msix_entries = 0; + vsoc_dev.regions = 0; + if (vsoc_dev.class_added) { + class_destroy(vsoc_dev.class); + vsoc_dev.class_added = 0; + } + if (vsoc_dev.cdev_added) { + cdev_del(&vsoc_dev.cdev); + vsoc_dev.cdev_added = 0; + } + if (vsoc_dev.major && vsoc_dev.layout) { + unregister_chrdev_region(MKDEV(vsoc_dev.major, 0), + vsoc_dev.layout->region_count); + vsoc_dev.major = 0; + } + vsoc_dev.layout = 0; + if (vsoc_dev.kernel_mapped_shm) { + pci_iounmap(pdev, vsoc_dev.kernel_mapped_shm); + vsoc_dev.kernel_mapped_shm = 0; + } + if (vsoc_dev.regs) { + pci_iounmap(pdev, vsoc_dev.regs); + vsoc_dev.regs = 0; + } + if (vsoc_dev.requested_regions) { + pci_release_regions(pdev); + vsoc_dev.requested_regions = 0; + } + if (vsoc_dev.enabled_device) { + pci_disable_device(pdev); + vsoc_dev.enabled_device = 0; + } + /* Do this last: it indicates that the device is not initialized. */ + vsoc_dev.dev = NULL; +} + +static void __exit vsoc_cleanup_module(void) +{ + vsoc_remove_device(vsoc_dev.dev); + pci_unregister_driver(&vsoc_pci_driver); +} + +static int __init vsoc_init_module(void) +{ + int err = -ENOMEM; + + INIT_LIST_HEAD(&vsoc_dev.permissions); + mutex_init(&vsoc_dev.mtx); + + err = pci_register_driver(&vsoc_pci_driver); + if (err < 0) + return err; + return 0; +} + +static int vsoc_open(struct inode *inode, struct file *filp) +{ + /* Can't use vsoc_validate_filep because filp is still incomplete */ + int ret = vsoc_validate_inode(inode); + + if (ret) + return ret; + filp->private_data = + kzalloc(sizeof(struct vsoc_private_data), GFP_KERNEL); + if (!filp->private_data) + return -ENOMEM; + return 0; +} + +static int vsoc_release(struct inode *inode, struct file *filp) +{ + struct vsoc_private_data *private_data = NULL; + struct fd_scoped_permission_node *node = NULL; + struct vsoc_device_region *owner_region_p = NULL; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + private_data = (struct vsoc_private_data *)filp->private_data; + if (!private_data) + return 0; + + node = private_data->fd_scoped_permission_node; + if (node) { + owner_region_p = vsoc_region_from_inode(inode); + if (owner_region_p->managed_by != VSOC_REGION_WHOLE) { + owner_region_p = + &vsoc_dev.regions[owner_region_p->managed_by]; + } + do_destroy_fd_scoped_permission_node(owner_region_p, node); + private_data->fd_scoped_permission_node = NULL; + } + kfree(private_data); + filp->private_data = NULL; + + return 0; +} + +/* + * Returns the device relative offset and length of the area specified by the + * fd scoped permission. If there is no fd scoped permission set, a default + * permission covering the entire region is assumed, unless the region is owned + * by another one, in which case the default is a permission with zero size. + */ +static ssize_t vsoc_get_area(struct file *filp, __u32 *area_offset) +{ + __u32 off = 0; + ssize_t length = 0; + struct vsoc_device_region *region_p; + struct fd_scoped_permission *perm; + + region_p = vsoc_region_from_filep(filp); + off = region_p->region_begin_offset; + perm = &((struct vsoc_private_data *)filp->private_data)-> + fd_scoped_permission_node->permission; + if (perm) { + off += perm->begin_offset; + length = perm->end_offset - perm->begin_offset; + } else if (region_p->managed_by == VSOC_REGION_WHOLE) { + /* No permission set and the regions is not owned by another, + * default to full region access. + */ + length = vsoc_device_region_size(region_p); + } else { + /* return zero length, access is denied. */ + length = 0; + } + if (area_offset) + *area_offset = off; + return length; +} + +static int vsoc_mmap(struct file *filp, struct vm_area_struct *vma) +{ + unsigned long len = vma->vm_end - vma->vm_start; + __u32 area_off; + phys_addr_t mem_off; + ssize_t area_len; + int retval = vsoc_validate_filep(filp); + + if (retval) + return retval; + area_len = vsoc_get_area(filp, &area_off); + /* Add the requested offset */ + area_off += (vma->vm_pgoff << PAGE_SHIFT); + area_len -= (vma->vm_pgoff << PAGE_SHIFT); + if (area_len < len) + return -EINVAL; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + mem_off = shm_off_to_phys_addr(area_off); + if (io_remap_pfn_range(vma, vma->vm_start, mem_off >> PAGE_SHIFT, + len, vma->vm_page_prot)) + return -EAGAIN; + return 0; +} + +module_init(vsoc_init_module); +module_exit(vsoc_cleanup_module); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Hartman "); +MODULE_DESCRIPTION("VSoC interpretation of QEmu's ivshmem device"); +MODULE_VERSION("1.0"); -- GitLab From 657081db6e1c80677ce179741ed50ba4786732d3 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Thu, 5 Apr 2018 18:01:04 -0700 Subject: [PATCH 1304/1834] ANDROID: Add defconfig for cuttlefish. This file is based on x86_64_defconfig, merged with the base and recommended configs from configs.git, with the virtio drivers enabled and some spurious kernel features turned off. Change-Id: I61bde941e8cfef2dd83cb4ff040f7380922cc44e Signed-off-by: Alistair Strachan --- arch/x86/configs/x86_64_cuttlefish_defconfig | 454 +++++++++++++++++++ 1 file changed, 454 insertions(+) create mode 100644 arch/x86/configs/x86_64_cuttlefish_defconfig diff --git a/arch/x86/configs/x86_64_cuttlefish_defconfig b/arch/x86/configs/x86_64_cuttlefish_defconfig new file mode 100644 index 000000000000..43c95758a914 --- /dev/null +++ b/arch/x86/configs/x86_64_cuttlefish_defconfig @@ -0,0 +1,454 @@ +CONFIG_POSIX_MQUEUE=y +# CONFIG_FHANDLE is not set +# CONFIG_USELIB is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_CGROUPS=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_CGROUP_SCHED=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_JUMP_LABEL=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_SMP=y +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PARAVIRT=y +CONFIG_PARAVIRT_SPINLOCKS=y +CONFIG_MCORE2=y +CONFIG_PROCESSOR_SELECT=y +# CONFIG_CPU_SUP_CENTAUR is not set +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +# CONFIG_MICROCODE is not set +CONFIG_X86_MSR=y +CONFIG_X86_CPUID=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_TRANSPARENT_HUGEPAGE=y +# CONFIG_MTRR is not set +CONFIG_HZ_100=y +CONFIG_KEXEC=y +CONFIG_CRASH_DUMP=y +CONFIG_PHYSICAL_START=0x200000 +CONFIG_RANDOMIZE_BASE=y +CONFIG_PHYSICAL_ALIGN=0x1000000 +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttyS0 reboot=p" +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_PM_DEBUG=y +CONFIG_ACPI_PROCFS_POWER=y +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_THERMAL is not set +# CONFIG_X86_PM_TIMER is not set +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_GOV_ONDEMAND=y +CONFIG_X86_ACPI_CPUFREQ=y +# CONFIG_X86_ACPI_CPUFREQ_CPB is not set +CONFIG_PCI_MMCONFIG=y +CONFIG_PCI_MSI=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_BINFMT_MISC=y +CONFIG_IA32_EMULATION=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_MROUTE=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_ESP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +# CONFIG_TCP_CONG_BIC is not set +# CONFIG_TCP_CONG_WESTWOOD is not set +# CONFIG_TCP_CONG_HTCP is not set +CONFIG_TCP_MD5SIG=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETLABEL=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_IPV6HEADER=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_CLS_U32=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_CLS_ACT=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_RFKILL=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEBUG_DEVRES=y +CONFIG_OF=y +CONFIG_OF_UNITTEST=y +# CONFIG_PNP_DEBUG_MESSAGES is not set +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_VIRTIO_BLK=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_VIRTIO=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_MIRROR=y +CONFIG_DM_ZERO=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_NETCONSOLE=y +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=y +CONFIG_VIRTIO_NET=y +# CONFIG_ETHERNET is not set +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_MPPE=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_USB_USBNET=y +# CONFIG_USB_NET_AX8817X is not set +# CONFIG_USB_NET_AX88179_178A is not set +# CONFIG_USB_NET_CDCETHER is not set +# CONFIG_USB_NET_CDC_NCM is not set +# CONFIG_USB_NET_NET1080 is not set +# CONFIG_USB_NET_CDC_SUBSET is not set +# CONFIG_USB_NET_ZAURUS is not set +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set +CONFIG_MAC80211_HWSIM=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_KEYRESET=y +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_JOYSTICK=y +CONFIG_JOYSTICK_XPAD=y +CONFIG_JOYSTICK_XPAD_FF=y +CONFIG_JOYSTICK_XPAD_LEDS=y +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_USB_ACECAD=y +CONFIG_TABLET_USB_AIPTEK=y +CONFIG_TABLET_USB_GTCO=y +CONFIG_TABLET_USB_HANWANG=y +CONFIG_TABLET_USB_KBTAB=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_KEYCHORD=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_GPIO=y +# CONFIG_SERIO_I8042 is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=48 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_MANY_PORTS=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_VIRTIO_CONSOLE=y +CONFIG_HW_RANDOM=y +# CONFIG_HW_RANDOM_INTEL is not set +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HW_RANDOM_VIRTIO=y +CONFIG_HPET=y +# CONFIG_HPET_MMAP_DEFAULT is not set +# CONFIG_DEVPORT is not set +# CONFIG_ACPI_I2C_OPREGION is not set +# CONFIG_I2C_COMPAT is not set +# CONFIG_I2C_HELPER_AUTO is not set +CONFIG_PTP_1588_CLOCK=y +# CONFIG_HWMON is not set +# CONFIG_X86_PKG_TEMP_THERMAL is not set +CONFIG_WATCHDOG=y +CONFIG_SOFT_WATCHDOG=y +CONFIG_MEDIA_SUPPORT=y +# CONFIG_DVB_TUNER_DIB0070 is not set +# CONFIG_DVB_TUNER_DIB0090 is not set +# CONFIG_VGA_ARB is not set +CONFIG_DRM=y +# CONFIG_DRM_FBDEV_EMULATION is not set +CONFIG_DRM_VIRTIO_GPU=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_HIDRAW=y +CONFIG_UHID=y +# CONFIG_HID_GENERIC is not set +CONFIG_HID_A4TECH=y +CONFIG_HID_ACRUX=y +CONFIG_HID_ACRUX_FF=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_PRODIKEYS=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_DRAGONRISE=y +CONFIG_DRAGONRISE_FF=y +CONFIG_HID_EMS_FF=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_HOLTEK=y +CONFIG_HID_KEYTOUCH=y +CONFIG_HID_KYE=y +CONFIG_HID_UCLOGIC=y +CONFIG_HID_WALTOP=y +CONFIG_HID_GYRATION=y +CONFIG_HID_TWINHAN=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LCPOWER=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_LOGITECH_DJ=y +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_NTRIG=y +CONFIG_HID_ORTEK=y +CONFIG_HID_PANTHERLORD=y +CONFIG_PANTHERLORD_FF=y +CONFIG_HID_PETALYNX=y +CONFIG_HID_PICOLCD=y +CONFIG_HID_PRIMAX=y +CONFIG_HID_ROCCAT=y +CONFIG_HID_SAITEK=y +CONFIG_HID_SAMSUNG=y +CONFIG_HID_SONY=y +CONFIG_HID_SPEEDLINK=y +CONFIG_HID_SUNPLUS=y +CONFIG_HID_GREENASIA=y +CONFIG_GREENASIA_FF=y +CONFIG_HID_SMARTJOYPLUS=y +CONFIG_SMARTJOYPLUS_FF=y +CONFIG_HID_TIVO=y +CONFIG_HID_TOPSEED=y +CONFIG_HID_THRUSTMASTER=y +CONFIG_HID_WACOM=y +CONFIG_HID_WIIMOTE=y +CONFIG_HID_ZEROPLUS=y +CONFIG_HID_ZYDACRON=y +CONFIG_USB_HIDDEV=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_GADGET=y +CONFIG_USB_DUMMY_HCD=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_RTC_CLASS=y +# CONFIG_RTC_HCTOSYS is not set +CONFIG_SW_SYNC=y +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_BALLOON=y +CONFIG_VIRTIO_MMIO=y +CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_VSOC=y +CONFIG_ION=y +# CONFIG_X86_PLATFORM_DEVICES is not set +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +# CONFIG_FIRMWARE_MEMMAP is not set +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_POSIX_ACL=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +# CONFIG_PRINT_QUOTA_WARNING is not set +CONFIG_QFMT_V2=y +CONFIG_AUTOFS4_FS=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_SDCARD_FS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_RAM=y +CONFIG_NLS_DEFAULT="utf8" +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set +# CONFIG_ENABLE_MUST_CHECK is not set +CONFIG_FRAME_WARN=1024 +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_LOCKUP_DETECTOR=y +CONFIG_PANIC_TIMEOUT=5 +# CONFIG_SCHED_DEBUG is not set +CONFIG_SCHEDSTATS=y +CONFIG_TIMER_STATS=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_ENABLE_DEFAULT_TRACERS=y +CONFIG_IO_DELAY_NONE=y +CONFIG_DEBUG_BOOT_PARAMS=y +CONFIG_OPTIMIZE_INLINING=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_PATH=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE=1 +# CONFIG_CRYPTO_MANAGER_DISABLE_TESTS is not set -- GitLab From 2ba4887f2937a15bf32e0c482d68bd77fcf04aa8 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Fri, 13 Apr 2018 15:36:37 -0700 Subject: [PATCH 1305/1834] ANDROID: Add build server config for cuttlefish. The build server config can be used with gcc or clang. Specify CC=clang to build with clang. Change-Id: Id346ab1489ecaaef8e9e66b084cc416dd0581f69 Signed-off-by: Alistair Strachan --- build.config.cuttlefish.x86_64 | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 build.config.cuttlefish.x86_64 diff --git a/build.config.cuttlefish.x86_64 b/build.config.cuttlefish.x86_64 new file mode 100644 index 000000000000..5a9656359f0b --- /dev/null +++ b/build.config.cuttlefish.x86_64 @@ -0,0 +1,15 @@ +ARCH=x86_64 +BRANCH=android-4.9 +CLANG_TRIPLE=x86_64-linux-gnu- +CROSS_COMPILE=x86_64-linux-androidkernel- +DEFCONFIG=x86_64_cuttlefish_defconfig +EXTRA_CMDS='' +KERNEL_DIR=common +POST_DEFCONFIG_CMDS="check_defconfig" +CLANG_PREBUILT_BIN=prebuilts/clang/host/linux-x86/clang-4630689/bin +LINUX_GCC_CROSS_COMPILE_PREBUILTS_BIN=prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/bin +FILES=" +arch/x86/boot/bzImage +vmlinux +System.map +" -- GitLab From 32dab11c4742d5b0c23c78a977f6592158b1b0d1 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 12 Apr 2018 15:13:12 +0530 Subject: [PATCH 1306/1834] ARM: dts: msm: Add 30k and 400k bat_therm channels for PMI632 Add channels to read bat_therm for 30k and 400k pullups on PMI632. Change-Id: I4bdcb3252e9b451a0f196ea145266d8b1905041b Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/pmi632.dtsi | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index bdd69e29714a..95675791f086 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -152,6 +152,30 @@ qcom,cal-val = <0>; }; + chan@2a { + label = "bat_therm_PU30"; + reg = <0x2a>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <24>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + + chan@6a { + label = "bat_therm_PU400"; + reg = <0x6a>; + qcom,decimation = <2>; + qcom,pre-div-channel-scaling = <0>; + qcom,calibration-type = "ratiometric"; + qcom,scale-function = <25>; + qcom,hw-settle-time = <0>; + qcom,fast-avg-setup = <0>; + qcom,cal-val = <0>; + }; + chan@4b { label = "bat_id"; reg = <0x4b>; -- GitLab From 64c9d3ff4d1ae32d2aa166d434d7bab6e50d2db7 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 12 Apr 2018 17:01:32 +0530 Subject: [PATCH 1307/1834] hwmon: qpnp-adc: Add support to read bat_therm for PMI632 Add voltage to temperature lookup table and scaling function for reading bat_therm on 30k and 400k pullups for PMI632. Change-Id: Ia046807617952cc68ea4b13e1310ad1bd6ca5fe8 Signed-off-by: Jishnu Prakash --- drivers/hwmon/qpnp-adc-common.c | 204 +++++++++++++++++++++++++++++++ drivers/hwmon/qpnp-adc-voltage.c | 2 + include/linux/qpnp/qpnp-adc.h | 56 ++++++++- 3 files changed, 261 insertions(+), 1 deletion(-) diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c index 62ad4f4639f7..f396c7695e44 100644 --- a/drivers/hwmon/qpnp-adc-common.c +++ b/drivers/hwmon/qpnp-adc-common.c @@ -751,6 +751,154 @@ static const struct qpnp_vadc_map_pt adcmap_batt_therm_qrd[] = { {107, 980} }; +/* Voltage to temperature */ +static const struct qpnp_vadc_map_pt adcmap_batt_therm_pu30[] = { + {1842, -400}, + {1838, -380}, + {1833, -360}, + {1828, -340}, + {1822, -320}, + {1816, -300}, + {1809, -280}, + {1801, -260}, + {1793, -240}, + {1784, -220}, + {1774, -200}, + {1763, -180}, + {1752, -160}, + {1739, -140}, + {1726, -120}, + {1712, -100}, + {1697, -80}, + {1680, -60}, + {1663, -40}, + {1645, -20}, + {1625, 0}, + {1605, 20}, + {1583, 40}, + {1561, 60}, + {1537, 80}, + {1513, 100}, + {1487, 120}, + {1461, 140}, + {1433, 160}, + {1405, 180}, + {1376, 200}, + {1347, 220}, + {1316, 240}, + {1286, 260}, + {1254, 280}, + {1223, 300}, + {1191, 320}, + {1159, 340}, + {1126, 360}, + {1094, 380}, + {1062, 400}, + {1029, 420}, + {997, 440}, + {966, 460}, + {934, 480}, + {903, 500}, + {873, 520}, + {843, 540}, + {813, 560}, + {784, 580}, + {756, 600}, + {728, 620}, + {702, 640}, + {675, 660}, + {650, 680}, + {625, 700}, + {601, 720}, + {578, 740}, + {556, 760}, + {534, 780}, + {513, 800}, + {493, 820}, + {474, 840}, + {455, 860}, + {437, 880}, + {420, 900}, + {403, 920}, + {387, 940}, + {372, 960}, + {357, 980} +}; + +/* Voltage to temp0erature */ +static const struct qpnp_vadc_map_pt adcmap_batt_therm_pu400[] = { + {1516, -400}, + {1478, -380}, + {1438, -360}, + {1396, -340}, + {1353, -320}, + {1307, -300}, + {1261, -280}, + {1213, -260}, + {1164, -240}, + {1115, -220}, + {1066, -200}, + {1017, -180}, + {968, -160}, + {920, -140}, + {872, -120}, + {826, -100}, + {781, -80}, + {737, -60}, + {694, -40}, + {654, -20}, + {615, 0}, + {578, 20}, + {542, 40}, + {509, 60}, + {477, 80}, + {447, 100}, + {419, 120}, + {392, 140}, + {367, 160}, + {343, 180}, + {321, 200}, + {301, 220}, + {282, 240}, + {264, 260}, + {247, 280}, + {231, 300}, + {216, 320}, + {203, 340}, + {190, 360}, + {178, 380}, + {167, 400}, + {157, 420}, + {147, 440}, + {138, 460}, + {130, 480}, + {122, 500}, + {115, 520}, + {108, 540}, + {102, 560}, + {96, 580}, + {90, 600}, + {85, 620}, + {80, 640}, + {76, 660}, + {72, 680}, + {68, 700}, + {64, 720}, + {61, 740}, + {57, 760}, + {54, 780}, + {52, 800}, + {49, 820}, + {46, 840}, + {44, 860}, + {42, 880}, + {40, 900}, + {38, 920}, + {36, 940}, + {34, 960}, + {32, 980} +}; + /* * Voltage to temperature table for 100k pull up for NTCG104EF104 with * 1.875V reference. @@ -1120,6 +1268,62 @@ int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *chip, } EXPORT_SYMBOL(qpnp_adc_batt_therm_qrd); +int32_t qpnp_adc_batt_therm_pu30(struct qpnp_vadc_chip *chip, + int32_t adc_code, + const struct qpnp_adc_properties *adc_properties, + const struct qpnp_vadc_chan_properties *chan_properties, + struct qpnp_vadc_result *adc_chan_result) +{ + int64_t batt_thm_voltage = 0; + + if (!chan_properties || !chan_properties->offset_gain_numerator || + !chan_properties->offset_gain_denominator || !adc_properties + || !adc_chan_result) + return -EINVAL; + + /* (code * vref_vadc (1.875V) * 1000) / (scale_code * 1000) */ + if (adc_code > QPNP_VADC_HC_MAX_CODE) + adc_code = 0; + batt_thm_voltage = (int64_t) adc_code; + batt_thm_voltage *= (adc_properties->adc_vdd_reference + * 1000); + batt_thm_voltage = div64_s64(batt_thm_voltage, + adc_properties->full_scale_code * 1000); + qpnp_adc_map_voltage_temp(adcmap_batt_therm_pu30, + ARRAY_SIZE(adcmap_batt_therm_pu30), + batt_thm_voltage, &adc_chan_result->physical); + return 0; +} +EXPORT_SYMBOL(qpnp_adc_batt_therm_pu30); + +int32_t qpnp_adc_batt_therm_pu400(struct qpnp_vadc_chip *chip, + int32_t adc_code, + const struct qpnp_adc_properties *adc_properties, + const struct qpnp_vadc_chan_properties *chan_properties, + struct qpnp_vadc_result *adc_chan_result) +{ + int64_t batt_thm_voltage = 0; + + if (!chan_properties || !chan_properties->offset_gain_numerator || + !chan_properties->offset_gain_denominator || !adc_properties + || !adc_chan_result) + return -EINVAL; + + /* (code * vref_vadc (1.875V) * 1000) / (scale_code * 1000) */ + if (adc_code > QPNP_VADC_HC_MAX_CODE) + adc_code = 0; + batt_thm_voltage = (int64_t) adc_code; + batt_thm_voltage *= (adc_properties->adc_vdd_reference + * 1000); + batt_thm_voltage = div64_s64(batt_thm_voltage, + adc_properties->full_scale_code * 1000); + qpnp_adc_map_voltage_temp(adcmap_batt_therm_pu400, + ARRAY_SIZE(adcmap_batt_therm_pu400), + batt_thm_voltage, &adc_chan_result->physical); + return 0; +} +EXPORT_SYMBOL(qpnp_adc_batt_therm_pu400); + int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *chip, int32_t adc_code, const struct qpnp_adc_properties *adc_properties, diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c index 1f38574dc4de..ed5222eb8f3d 100644 --- a/drivers/hwmon/qpnp-adc-voltage.c +++ b/drivers/hwmon/qpnp-adc-voltage.c @@ -228,6 +228,8 @@ static struct qpnp_vadc_scale_fn vadc_scale_fn[] = { [SCALE_USBIN_I] = {qpnp_adc_scale_usbin_curr}, [SCALE_BATT_THERM_TEMP_QRD] = {qpnp_adc_batt_therm_qrd}, [SCALE_SMB1390_DIE_TEMP] = {qpnp_adc_scale_die_temp_1390}, + [SCALE_BATT_THERM_TEMP_PU30] = {qpnp_adc_batt_therm_pu30}, + [SCALE_BATT_THERM_TEMP_PU400] = {qpnp_adc_batt_therm_pu400}, }; static struct qpnp_vadc_rscale_fn adc_vadc_rscale_fn[] = { diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h index a083370465b3..031573dd8be3 100644 --- a/include/linux/qpnp/qpnp-adc.h +++ b/include/linux/qpnp/qpnp-adc.h @@ -401,6 +401,10 @@ enum qpnp_adc_channel_scaling_param { * %SCALE_USBIN_I: Conversion for USB input current. * %SCALE_BATT_THERM_TEMP_QRD: Conversion to temperature(decidegC) based on btm * parameters for QRD. + * %SCALE_BATT_THERM_TEMP_PU30: Conversion to temperature(decidegC) for 30k + * pullup. + * %SCALE_BATT_THERM_TEMP_PU400: Conversion to temperature(decidegC) for 400k + * pullup. * %SCALE_SMB1390_DIE_TEMP: Conversion for SMB1390 die temp * %SCALE_NONE: Do not use this scaling type. */ @@ -426,6 +430,8 @@ enum qpnp_adc_scale_fn_type { SCALE_USBIN_I, SCALE_BATT_THERM_TEMP_QRD, SCALE_SMB1390_DIE_TEMP, + SCALE_BATT_THERM_TEMP_PU30, + SCALE_BATT_THERM_TEMP_PU400, SCALE_NONE, }; @@ -1465,9 +1471,10 @@ int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *dev, const struct qpnp_vadc_chan_properties *chan_prop, struct qpnp_vadc_result *chan_rslt); /** - * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output + * qpnp_adc_batt_therm_pu30() - Scales the pre-calibrated digital output * of an ADC to the ADC reference and compensates for the * gain and offset. Returns the temperature in decidegC. + * It uses a mapping table computed for a 30K pull-up. * @dev: Structure device for qpnp vadc * @adc_code: pre-calibrated digital output of the ADC. * @adc_prop: adc properties of the pm8xxx adc such as bit resolution, @@ -1476,6 +1483,41 @@ int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *dev, * slope and offset. * @chan_rslt: physical result to be stored. */ +int32_t qpnp_adc_batt_therm_pu30(struct qpnp_vadc_chip *dev, + int32_t adc_code, + const struct qpnp_adc_properties *adc_prop, + const struct qpnp_vadc_chan_properties *chan_prop, + struct qpnp_vadc_result *chan_rslt); +/** + * qpnp_adc_batt_therm_pu400() - Scales the pre-calibrated digital output + * of an ADC to the ADC reference and compensates for the + * gain and offset. Returns the temperature in decidegC. + * It uses a mapping table computed for a 400K pull-up. + * @dev: Structure device for qpnp vadc + * @adc_code: pre-calibrated digital output of the ADC. + * @adc_prop: adc properties of the adc such as bit resolution, + * reference voltage. + * @chan_prop: individual channel properties to compensate the i/p scaling, + * slope and offset. + * @chan_rslt: physical result to be stored. + */ +int32_t qpnp_adc_batt_therm_pu400(struct qpnp_vadc_chip *dev, + int32_t adc_code, + const struct qpnp_adc_properties *adc_prop, + const struct qpnp_vadc_chan_properties *chan_prop, + struct qpnp_vadc_result *chan_rslt); +/** + * qpnp_adc_scale_batt_therm() - Scales the pre-calibrated digital output + * of an ADC to the ADC reference and compensates for the + * gain and offset. Returns the temperature in decidegC. + * @dev: Structure device for qpnp vadc + * @adc_code: pre-calibrated digital output of the ADC. + * @adc_prop: adc properties of the adc such as bit resolution, + * reference voltage. + * @chan_prop: individual channel properties to compensate the i/p scaling, + * slope and offset. + * @chan_rslt: physical result to be stored. + */ int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *dev, int32_t adc_code, const struct qpnp_adc_properties *adc_prop, @@ -2091,6 +2133,18 @@ static inline int32_t qpnp_adc_batt_therm_qrd(struct qpnp_vadc_chip *vadc, const struct qpnp_vadc_chan_properties *chan_prop, struct qpnp_vadc_result *chan_rslt) { return -ENXIO; } +static inline int32_t qpnp_adc_batt_therm_pu30(struct qpnp_vadc_chip *vadc, + int32_t adc_code, + const struct qpnp_adc_properties *adc_prop, + const struct qpnp_vadc_chan_properties *chan_prop, + struct qpnp_vadc_result *chan_rslt) +{ return -ENXIO; } +static inline int32_t qpnp_adc_batt_therm_pu400(struct qpnp_vadc_chip *vadc, + int32_t adc_code, + const struct qpnp_adc_properties *adc_prop, + const struct qpnp_vadc_chan_properties *chan_prop, + struct qpnp_vadc_result *chan_rslt) +{ return -ENXIO; } static inline int32_t qpnp_adc_scale_batt_therm(struct qpnp_vadc_chip *vadc, int32_t adc_code, const struct qpnp_adc_properties *adc_prop, -- GitLab From 08174038ff791d811446a3455a57cb4961549e1d Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Mon, 16 Apr 2018 10:50:15 +0800 Subject: [PATCH 1308/1834] ARM: dts: msm: remove lpaif mode muxsel on sdm845 lpaif_mode_muxsel to select AUXPCM or I2S in LPASSis not needed on SDM845. LPASS would select AUXPCM or I2S according to afe port. Remove the register value and register name in device tree setting. Change-Id: I23eed45f0c30bb2c1adfed2cff12247c2ac09007 Signed-off-by: Meng Wang --- arch/arm64/boot/dts/qcom/sdm845-audio.dtsi | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi index a5c6d84ccdbe..944c1ddc15c9 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-audio.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,15 +37,6 @@ qcom,auxpcm-audio-intf; qcom,msm-mi2s-master = <1>, <1>, <1>, <1>; - reg = <0x1711a000 0x4>, - <0x1711b000 0x4>, - <0x1711c000 0x4>, - <0x1711d000 0x4>; - reg-names = "lpaif_pri_mode_muxsel", - "lpaif_sec_mode_muxsel", - "lpaif_tert_mode_muxsel", - "lpaif_quat_mode_muxsel"; - asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, -- GitLab From f4fdde5b07f865efecc5dea97e3a728be2db2e16 Mon Sep 17 00:00:00 2001 From: Ravikishore Pampana Date: Mon, 16 Apr 2018 16:59:47 +0530 Subject: [PATCH 1309/1834] msm: camera: isp: Poll for CSID hardware reset status Currently after csid hardware reset, software wait for interrupt to come. CSID irq handler gives the complete signal once CSID reset irq raised. Instead of waiting for reset irq comes, software can poll reset status register and check status. This avoids the race conditions in the csid irq complete signals. Change-Id: Ibe0ea7bbb5efe89ea38e095371b60bfcbc34c0e3 Signed-off-by: Ravikishore Pampana --- .../isp_hw/ife_csid_hw/cam_ife_csid_core.c | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 053eb00afe4c..d20450c38511 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -989,10 +989,6 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); - /* Enable the top IRQ interrupt */ - cam_io_w_mb(1, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_mask_addr); - val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_hw_version_addr); CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", @@ -2171,25 +2167,38 @@ static int cam_ife_csid_reset_retain_sw_reg( struct cam_ife_csid_hw *csid_hw) { int rc = 0; + uint32_t status; struct cam_ife_csid_reg_offset *csid_reg = csid_hw->csid_info->csid_reg; + struct cam_hw_soc_info *soc_info; + + soc_info = &csid_hw->hw_info->soc_info; + /* clear the top interrupt first */ + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); - init_completion(&csid_hw->csid_top_complete); cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, - csid_hw->hw_info->soc_info.reg_map[0].mem_base + + soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); - - CAM_DBG(CAM_ISP, " Waiting for SW reset complete from irq handler"); - rc = wait_for_completion_timeout(&csid_hw->csid_top_complete, - msecs_to_jiffies(IFE_CSID_TIMEOUT)); - if (rc <= 0) { - CAM_ERR(CAM_ISP, "CSID:%d reset completion in fail rc = %d", - csid_hw->hw_intf->hw_idx, rc); - if (rc == 0) - rc = -ETIMEDOUT; + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_status_addr, + status, (status & 0x1) == 0x1, + CAM_IFE_CSID_TIMEOUT_SLEEP_US, CAM_IFE_CSID_TIMEOUT_ALL_US); + if (rc < 0) { + CAM_ERR(CAM_ISP, "CSID:%d csid_reset fail rc = %d", + csid_hw->hw_intf->hw_idx, rc); + rc = -ETIMEDOUT; } else { + CAM_DBG(CAM_ISP, "CSID:%d hw reset completed %d", + csid_hw->hw_intf->hw_idx, rc); rc = 0; } + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_top_irq_clear_addr); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + + csid_reg->cmn_reg->csid_irq_cmd_addr); return rc; } @@ -2529,8 +2538,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); /* clear */ - cam_io_w_mb(irq_status_top, soc_info->reg_map[0].mem_base + - csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(irq_status_rx, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_clear_addr); if (csid_reg->cmn_reg->no_pix) @@ -2551,13 +2558,6 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) CAM_DBG(CAM_ISP, "irq_status_rdi1= 0x%x", irq_status_rdi[1]); CAM_DBG(CAM_ISP, "irq_status_rdi2= 0x%x", irq_status_rdi[2]); - if (irq_status_top) { - CAM_DBG(CAM_ISP, "CSID global reset complete......Exit"); - complete(&csid_hw->csid_top_complete); - return IRQ_HANDLED; - } - - if (irq_status_rx & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); complete(&csid_hw->csid_csi2_complete); -- GitLab From f8eb9d29eea3237c0a813433b85ebdbbff63d366 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 16 Apr 2018 14:00:12 -0700 Subject: [PATCH 1310/1834] leds: qpnp-flash-v2: Modify current code calculation Currently, the code calculated for a desired target current and IRES is rounded up since DIV_ROUND_UP is used in the calculation. With a higher IRES (12.5 mA), code can be configured to a higher value. Fix this by using DIV_ROUND_CLOSEST so that the optimal code can be obtained. Change-Id: I51c1b15fff3ff2a23cb256f2ae1d341f5271adf2 Signed-off-by: Subbaraman Narayanamurthy --- drivers/leds/leds-qpnp-flash-v2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/leds/leds-qpnp-flash-v2.c b/drivers/leds/leds-qpnp-flash-v2.c index d4b64ba800e6..759d8531114c 100644 --- a/drivers/leds/leds-qpnp-flash-v2.c +++ b/drivers/leds/leds-qpnp-flash-v2.c @@ -353,7 +353,7 @@ static inline int get_current_reg_code(int target_curr_ma, int ires_ua) if (!ires_ua || !target_curr_ma || (target_curr_ma < (ires_ua / 1000))) return 0; - return DIV_ROUND_UP(target_curr_ma * 1000, ires_ua) - 1; + return DIV_ROUND_CLOSEST(target_curr_ma * 1000, ires_ua) - 1; } static int qpnp_flash_led_read(struct qpnp_flash_led *led, u16 addr, u8 *data) -- GitLab From 72633f804586f131f5cc79c011c1151ca4cdd14b Mon Sep 17 00:00:00 2001 From: Matt Wagantall Date: Fri, 20 Mar 2015 12:54:57 -0700 Subject: [PATCH 1311/1834] exit: Add PANIC_ON_RECURSIVE_FAULT Kconfig option If a recursive fault is detected during do_exit(), tasks are left to sit and wait in an un-interruptible sleep until the system reboots (typically manually). Add Kconfig option to change this behaviour and force a panic. This is particularly important if a critical system task encounters a recursive fault (ex. a kworker). Otherwise, the system may be unusable, but since the scheduler is still running system watchdogs may continue to be pet. Change-Id: Ifc26fc79d6066f05a3b2c4d27f78bf4f8d2bd640 Signed-off-by: Matt Wagantall --- kernel/exit.c | 4 ++++ lib/Kconfig.debug | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/kernel/exit.c b/kernel/exit.c index 35ff28345459..2c2cc1a185bd 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -765,7 +765,11 @@ void __noreturn do_exit(long code) * leave this task alone and wait for reboot. */ if (unlikely(tsk->flags & PF_EXITING)) { +#ifdef CONFIG_PANIC_ON_RECURSIVE_FAULT + panic("Recursive fault!\n"); +#else pr_alert("Fixing recursive fault but reboot is needed!\n"); +#endif /* * We can do this unlocked here. The futex code uses * this flag just to verify whether the pi state diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 558be538a443..079d91ad4e2f 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -834,6 +834,17 @@ config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC default 1 if BOOTPARAM_SOFTLOCKUP_PANIC +config PANIC_ON_RECURSIVE_FAULT + bool "Panic on recursive faults during task exit" + help + Panic upon the detection of a recursive fault during task exit, + rather than putting the task into an uninterruptible sleep. + This is particularly useful for debugging system hangs in + scenarios where the task experiencing the fault is critical + for system operation, rendering the system inoperable. + + Say N if unsure. + config DETECT_HUNG_TASK bool "Detect Hung Tasks" depends on DEBUG_KERNEL -- GitLab From cd845496a0740e0cd66c4ce42361fb13abf64e13 Mon Sep 17 00:00:00 2001 From: Jeevan Shriram Date: Mon, 16 Apr 2018 17:54:41 -0700 Subject: [PATCH 1312/1834] defconfig: Enable PANIC_ON_RECURSIVE_FAULT on sdxpoorwills target Enable panic on recursive fault during do_exit() to collect the important debug information leading to the fault. Change-Id: I8c28a759019ec4b4887b3b4871ab17015709e7ce Signed-off-by: Jeevan Shriram --- arch/arm/configs/sdxpoorwills-perf_defconfig | 1 + arch/arm/configs/sdxpoorwills_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index e3c1c1aa817b..09d428977f5e 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -392,6 +392,7 @@ CONFIG_NLS_ISO8859_1=y CONFIG_PRINTK_TIME=y CONFIG_DEBUG_INFO=y CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y CONFIG_PANIC_TIMEOUT=5 # CONFIG_SCHED_DEBUG is not set CONFIG_SCHEDSTATS=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index fd3d7846ac2b..e64a5079235c 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -405,6 +405,7 @@ CONFIG_DEBUG_KMEMLEAK=y CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y CONFIG_DEBUG_STACK_USAGE=y CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_PANIC_ON_RECURSIVE_FAULT=y CONFIG_PANIC_TIMEOUT=5 CONFIG_SCHEDSTATS=y CONFIG_DEBUG_SPINLOCK=y -- GitLab From 74dfa76eea7057e50534ed8c1fd1bb91ae8948a1 Mon Sep 17 00:00:00 2001 From: Surajit Podder Date: Tue, 27 Feb 2018 18:26:25 +0530 Subject: [PATCH 1313/1834] msm: vidc: Halt AXI on sys error Halt AXI on sys error to ensure that there are no further NOC transactions when video subsystem is deinitialized. Change-Id: I357a55538eaeb8fd75deb9fb7cb8ccf20d2e9909 Signed-off-by: Surajit Podder --- drivers/media/platform/msm/vidc/venus_hfi.c | 45 ++++++++++++++++++- drivers/media/platform/msm/vidc/vidc_hfi_io.h | 8 +++- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/vidc/venus_hfi.c b/drivers/media/platform/msm/vidc/venus_hfi.c index 7e7ed4713485..ade04e32c320 100644 --- a/drivers/media/platform/msm/vidc/venus_hfi.c +++ b/drivers/media/platform/msm/vidc/venus_hfi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -60,6 +60,9 @@ struct tzbsp_resp { /* Poll interval in uS */ #define POLL_INTERVAL_US 50 +#define VENUS_AXI_HALT_ACK_TIMEOUT_US 500000 + + enum tzbsp_video_state { TZBSP_VIDEO_STATE_SUSPEND = 0, TZBSP_VIDEO_STATE_RESUME = 1, @@ -2850,12 +2853,52 @@ static void venus_hfi_pm_handler(struct work_struct *work) mutex_unlock(&device->lock); } +static int __halt_axi(struct venus_hfi_device *device) +{ + u32 reg; + int rc = 0; + + if (!device) { + dprintk(VIDC_ERR, "Invalid input\n"); + return -EINVAL; + } + + /* + * Driver needs to make sure that clocks are enabled to read Venus AXI + * registers. If not skip AXI HALT. + */ + if (!device->power_enabled) { + dprintk(VIDC_WARN, + "Clocks are OFF, skipping AXI HALT\n"); + return -EINVAL; + } + + /* Halt AXI and AXI IMEM VBIF Access */ + reg = __read_register(device, VENUS_WRAPPER_AXI_HALT); + reg |= BRIC_AXI_HALT; + __write_register(device, VENUS_WRAPPER_AXI_HALT, reg); + + /* Request for AXI bus port halt */ + rc = readl_poll_timeout(device->hal_data->register_base + + VENUS_WRAPPER_AXI_HALT_STATUS, + reg, reg & BRIC_AXI_HALT_ACK, + POLL_INTERVAL_US, + VENUS_AXI_HALT_ACK_TIMEOUT_US); + if (rc) + dprintk(VIDC_WARN, "AXI bus port halt timeout\n"); + + return rc; +} + static void __process_sys_error(struct venus_hfi_device *device) { struct hfi_sfr_struct *vsfr = NULL; __set_state(device, VENUS_STATE_DEINIT); + if (__halt_axi(device)) + dprintk(VIDC_WARN, "Failed to halt AXI after SYS_ERROR\n"); + vsfr = (struct hfi_sfr_struct *)device->sfr.align_virtual_addr; if (vsfr) { void *p = memchr(vsfr->rg_data, '\0', vsfr->bufSize); diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/vidc_hfi_io.h index 343348395c54..3ddd6336acd0 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_io.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_io.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -148,6 +148,12 @@ #define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0) #define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000 +#define VENUS_WRAPPER_AXI_HALT 0x000E2008 +#define VENUS_WRAPPER_AXI_HALT_STATUS 0x000E200C + +#define BRIC_AXI_HALT BIT(16) +#define BRIC_AXI_HALT_ACK BIT(16) + #define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \ (VIDC_WRAPPER_BASE_OFFS + 0x20) #define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \ -- GitLab From 9bb83c558b5f299e97c11dc0dcea9ab866bb12e9 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Mon, 26 Mar 2018 20:41:09 +0530 Subject: [PATCH 1314/1834] msm: vidc: Remove init_completion before wait On 4.9 kernel list is currupted while killing video session. This could be because of session abort, as session is rejected due to overload. So, Removing init_completion before wait as this is done during session init. Change-Id: I4d75a119ddff0d1743ecddb1048e6289f2fbb027 Signed-off-by: Mansur Alisha Shaik --- .../platform/msm/vidc_3x/msm_vidc_common.c | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c index 4dcb3b133a00..bd5811750082 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc_3x/msm_vidc_common.c @@ -2474,7 +2474,6 @@ static int msm_comm_session_abort(struct msm_vidc_inst *inst) } hdev = inst->core->device; abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE); - init_completion(&inst->completions[abort_completion]); rc = call_hfi_op(hdev, session_abort, (void *)inst->session); if (rc) { @@ -2632,8 +2631,6 @@ static int msm_comm_init_core(struct msm_vidc_inst *inst) __func__); } - init_completion(&core->completions - [SYS_MSG_INDEX(HAL_SYS_INIT_DONE)]); rc = call_hfi_op(hdev, core_init, hdev->hfi_device_data); if (rc) { dprintk(VIDC_ERR, "Failed to init core, id = %d\n", @@ -2737,8 +2734,6 @@ static int msm_comm_session_init(int flipped_state, dprintk(VIDC_ERR, "Invalid session\n"); return -EINVAL; } - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_INIT_DONE)]); rc = call_hfi_op(hdev, session_init, hdev->hfi_device_data, inst, get_hal_domain(inst->session_type), @@ -2877,8 +2872,6 @@ static int msm_vidc_start(int flipped_state, struct msm_vidc_inst *inst) inst, inst->state); goto exit; } - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_START_DONE)]); rc = call_hfi_op(hdev, session_start, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, @@ -2908,8 +2901,6 @@ static int msm_vidc_stop(int flipped_state, struct msm_vidc_inst *inst) goto exit; } dprintk(VIDC_DBG, "Send Stop to hal\n"); - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_STOP_DONE)]); rc = call_hfi_op(hdev, session_stop, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, "Failed to send stop\n"); @@ -2939,8 +2930,6 @@ static int msm_vidc_release_res(int flipped_state, struct msm_vidc_inst *inst) } dprintk(VIDC_DBG, "Send release res to hal\n"); - init_completion(&inst->completions[ - SESSION_MSG_INDEX(HAL_SESSION_RELEASE_RESOURCE_DONE)]); rc = call_hfi_op(hdev, session_release_res, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, @@ -2971,8 +2960,6 @@ static int msm_comm_session_close(int flipped_state, } dprintk(VIDC_DBG, "Send session close to hal\n"); - init_completion( - &inst->completions[SESSION_MSG_INDEX(HAL_SESSION_END_DONE)]); rc = call_hfi_op(hdev, session_end, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, @@ -4021,8 +4008,6 @@ int msm_comm_try_get_prop(struct msm_vidc_inst *inst, enum hal_property ptype, } mutex_unlock(&inst->sync_lock); - init_completion(&inst->completions[ - SESSION_MSG_INDEX(HAL_SESSION_PROPERTY_INFO)]); switch (ptype) { case HAL_PARAM_PROFILE_LEVEL_CURRENT: case HAL_CONFIG_VDEC_ENTROPY: @@ -4248,8 +4233,6 @@ int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst, if (inst->state != MSM_VIDC_CORE_INVALID && core->state != VIDC_CORE_INVALID) { buffer_info.response_required = true; - init_completion(&inst->completions[SESSION_MSG_INDEX - (HAL_SESSION_RELEASE_BUFFER_DONE)]); rc = call_hfi_op(hdev, session_release_buffers, (void *)inst->session, &buffer_info); if (rc) { @@ -4321,9 +4304,6 @@ int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst) if (inst->state != MSM_VIDC_CORE_INVALID && core->state != VIDC_CORE_INVALID) { buffer_info.response_required = true; - init_completion( - &inst->completions[SESSION_MSG_INDEX - (HAL_SESSION_RELEASE_BUFFER_DONE)]); rc = call_hfi_op(hdev, session_release_buffers, (void *)inst->session, &buffer_info); if (rc) { -- GitLab From 97254550fda53ab908f3b28a5f6b9aec6fd38d91 Mon Sep 17 00:00:00 2001 From: Mansur Alisha Shaik Date: Thu, 15 Mar 2018 17:19:31 +0530 Subject: [PATCH 1315/1834] msm: vidc: V4l2 to HAL intra refresh mode mapping Because of incorrect intra refresh mode mapping core is going into bad state, setting control is failed. So added correct mapping for V4l2 to HAL for intra refresh mode. Change-Id: I910b8c3dc894adaf0e10a6bb82d47b193b5efeae Signed-off-by: Mansur Alisha Shaik --- drivers/media/platform/msm/vidc_3x/msm_venc.c | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc_3x/msm_venc.c b/drivers/media/platform/msm/vidc_3x/msm_venc.c index a728b691515d..fd19069bab44 100644 --- a/drivers/media/platform/msm/vidc_3x/msm_venc.c +++ b/drivers/media/platform/msm/vidc_3x/msm_venc.c @@ -2278,6 +2278,21 @@ static inline int venc_v4l2_to_hal(int id, int value) default: goto unknown_value; } + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: + switch (value) { + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE: + return HAL_INTRA_REFRESH_NONE; + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC: + return HAL_INTRA_REFRESH_CYCLIC; + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM: + return HAL_INTRA_REFRESH_RANDOM; + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE: + return HAL_INTRA_REFRESH_ADAPTIVE; + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE: + return HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE; + default: + goto unknown_value; + } } unknown_value: @@ -3123,8 +3138,10 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) } property_id = HAL_PARAM_VENC_INTRA_REFRESH; + intra_refresh.mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE, + ctrl->val); - intra_refresh.mode = ctrl->val; intra_refresh.air_mbs = air_mbs->val; intra_refresh.air_ref = air_ref->val; intra_refresh.cir_mbs = cir_mbs->val; @@ -3143,7 +3160,9 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) property_id = HAL_PARAM_VENC_INTRA_REFRESH; intra_refresh.air_mbs = ctrl->val; - intra_refresh.mode = ir_mode->val; + intra_refresh.mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE, + ir_mode->val); intra_refresh.air_ref = air_ref->val; intra_refresh.cir_mbs = cir_mbs->val; @@ -3162,7 +3181,9 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) intra_refresh.air_ref = ctrl->val; intra_refresh.air_mbs = air_mbs->val; - intra_refresh.mode = ir_mode->val; + intra_refresh.mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE, + ir_mode->val); intra_refresh.cir_mbs = cir_mbs->val; pdata = &intra_refresh; @@ -3181,7 +3202,9 @@ static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) intra_refresh.cir_mbs = ctrl->val; intra_refresh.air_mbs = air_mbs->val; intra_refresh.air_ref = air_ref->val; - intra_refresh.mode = ir_mode->val; + intra_refresh.mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE, + ir_mode->val); pdata = &intra_refresh; break; -- GitLab From dffffa01cd7648c5a634ac58e2c6c75adb03b290 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Wed, 11 Apr 2018 14:16:56 +0530 Subject: [PATCH 1316/1834] soc: qcom: service-locator: Use interruptible wait for locator Using uninterruptible wait for locator service can lead to the task disk-sleeping indefinitely in cases where pd-mapper service is not going to be available. Use interruptible wait with timeout to skip the wait gracefully in those cases. Change-Id: Id5cd3ad716a164ecb86f816111cba90e3b105c3e Signed-off-by: Jitendra Sharma --- drivers/soc/qcom/service-locator.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/service-locator.c b/drivers/soc/qcom/service-locator.c index 9dfe281812fe..5abc093003d6 100644 --- a/drivers/soc/qcom/service-locator.c +++ b/drivers/soc/qcom/service-locator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -34,6 +34,7 @@ #define QMI_SERVREG_LOC_SERVER_INITIAL_TIMEOUT 2000 #define QMI_SERVREG_LOC_SERVER_TIMEOUT 2000 #define INITIAL_TIMEOUT 100000 +#define LOCATOR_SERVICE_TIMEOUT 300000 #define LOCATOR_NOT_PRESENT 0 #define LOCATOR_PRESENT 1 @@ -302,13 +303,20 @@ static int service_locator_send_msg(struct pd_qmi_client_data *pd) static int init_service_locator(void) { int rc = 0; + static bool service_timedout; - mutex_lock(&service_init_mutex); + rc = mutex_lock_interruptible(&service_init_mutex); + if (rc) + return rc; if (locator_status == LOCATOR_NOT_PRESENT) { pr_err("Service Locator not enabled\n"); rc = -ENODEV; goto inited; } + if (service_timedout) { + rc = -ETIME; + goto inited; + } if (service_inited) goto inited; @@ -336,7 +344,20 @@ static int init_service_locator(void) goto inited; } - wait_for_completion(&service_locator.service_available); + rc = wait_for_completion_interruptible_timeout( + &service_locator.service_available, + msecs_to_jiffies(LOCATOR_SERVICE_TIMEOUT)); + if (rc < 0) { + pr_err("Wait for locator service interrupted by signal\n"); + goto inited; + } + if (!rc) { + pr_err("%s: wait for locator service timed out\n", __func__); + service_timedout = true; + rc = -ETIME; + goto inited; + } + service_inited = true; mutex_unlock(&service_init_mutex); pr_info("Service locator initialized\n"); -- GitLab From acd2ce068a6623ceb5db2b0e569c6ce24905964e Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Wed, 11 Apr 2018 10:48:59 -0400 Subject: [PATCH 1317/1834] drm/msm/sde: clear dim-layer settings when setting default value Clear all dim-layers when the default value of 0 (NULL) is set for the dim layer property. This setting needs to be cleared when resetting the crtc custom properties during lastclose. Change-Id: Ib451f918d7448e4952d086827852516445f137c1 Signed-off-by: Steve Cohen --- drivers/gpu/drm/msm/sde/sde_crtc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index ce2997d64860..67f8a844de62 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -2439,6 +2439,23 @@ static void _sde_crtc_set_input_fence_timeout(struct sde_crtc_state *cstate) cstate->input_fence_timeout_ns *= NSEC_PER_MSEC; } +/** + * _sde_crtc_clear_dim_layers_v1 - clear all dim layer settings + * @cstate: Pointer to sde crtc state + */ +static void _sde_crtc_clear_dim_layers_v1(struct sde_crtc_state *cstate) +{ + u32 i; + + if (!cstate) + return; + + for (i = 0; i < cstate->num_dim_layers; i++) + memset(&cstate->dim_layer[i], 0, sizeof(cstate->dim_layer[i])); + + cstate->num_dim_layers = 0; +} + /** * _sde_crtc_set_dim_layer_v1 - copy dim layer settings from userspace * @cstate: Pointer to sde crtc state @@ -2459,6 +2476,8 @@ static void _sde_crtc_set_dim_layer_v1(struct sde_crtc_state *cstate, dim_layer = cstate->dim_layer; if (!usr_ptr) { + /* usr_ptr is null when setting the default property value */ + _sde_crtc_clear_dim_layers_v1(cstate); SDE_DEBUG("dim_layer data removed\n"); return; } -- GitLab From 00d2580f20f0f3aafe8ad129cb8061ab905555dd Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Mon, 16 Apr 2018 14:17:18 -0700 Subject: [PATCH 1318/1834] msm: camera: core: Add debug messages for cam context leak Add debug messages in acquire and release to print leaking cam contexts. Change-Id: I9b7fc531c9fef66c9caa45821b323daae6c7634b Signed-off-by: Vishalsingh Hajeri --- .../platform/msm/camera/cam_core/cam_node.c | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_core/cam_node.c b/drivers/media/platform/msm/camera/cam_core/cam_node.c index a943680215e2..0a9fabcf8d5e 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_node.c +++ b/drivers/media/platform/msm/camera/cam_core/cam_node.c @@ -18,6 +18,34 @@ #include "cam_trace.h" #include "cam_debug_util.h" +static void cam_node_print_ctx_state( + struct cam_node *node) +{ + int i; + struct cam_context *ctx; + + CAM_INFO(CAM_CORE, "[%s] state=%d, ctx_size %d", + node->name, node->state, node->ctx_size); + + mutex_lock(&node->list_mutex); + for (i = 0; i < node->ctx_size; i++) { + ctx = &node->ctx_list[i]; + + spin_lock(&ctx->lock); + CAM_INFO(CAM_CORE, + "[%s][%d] : state=%d, refcount=%d, active_req_list=%d, pending_req_list=%d, wait_req_list=%d, free_req_list=%d", + ctx->dev_name ? ctx->dev_name : "null", + i, ctx->state, + atomic_read(&(ctx->refcount.refcount)), + list_empty(&ctx->active_req_list), + list_empty(&ctx->pending_req_list), + list_empty(&ctx->wait_req_list), + list_empty(&ctx->free_req_list)); + spin_unlock(&ctx->lock); + } + mutex_unlock(&node->list_mutex); +} + static struct cam_context *cam_node_get_ctxt_from_free_list( struct cam_node *node) { @@ -75,6 +103,10 @@ static int __cam_node_handle_acquire_dev(struct cam_node *node, ctx = cam_node_get_ctxt_from_free_list(node); if (!ctx) { + CAM_ERR(CAM_CORE, "No free ctx in free list node %s", + node->name); + cam_node_print_ctx_state(node); + rc = -ENOMEM; goto err; } @@ -86,6 +118,9 @@ static int __cam_node_handle_acquire_dev(struct cam_node *node, goto free_ctx; } + CAM_DBG(CAM_CORE, "[%s] Acquire ctx_id %d", + node->name, ctx->ctx_id); + return 0; free_ctx: cam_context_putref(ctx); @@ -260,6 +295,10 @@ static int __cam_node_handle_release_dev(struct cam_node *node, CAM_ERR(CAM_CORE, "destroy device handle is failed node %s", node->name); + CAM_DBG(CAM_CORE, "[%s] Release ctx_id=%d, refcount=%d", + node->name, ctx->ctx_id, + atomic_read(&(ctx->refcount.refcount))); + cam_context_putref(ctx); return rc; } -- GitLab From 4d505a51a1a0c920a4e3c951241aacad936f0859 Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Tue, 10 Apr 2018 14:43:33 -0700 Subject: [PATCH 1319/1834] msm: camera: isp: only wait for cdm callback for start Add check to make IFE only wait for its CDM callback when it starts. Change-Id: Idfbebd575d34681d08de0363fb56fca5b7c51130 Signed-off-by: Junzhe Zou --- drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h | 1 + drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c | 2 ++ .../platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h index 4168ce62ce91..f7990b6d5d4a 100644 --- a/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h +++ b/drivers/media/platform/msm/camera/cam_core/cam_hw_mgr_intf.h @@ -183,6 +183,7 @@ struct cam_hw_config_args { uint32_t num_out_map_entries; void *priv; uint64_t request_id; + bool init_packet; }; /** diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index 97e977d0c83a..f9985eb882bc 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -1244,6 +1244,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state( cfg.hw_update_entries = req_isp->cfg; cfg.num_hw_update_entries = req_isp->num_cfg; cfg.priv = &req_isp->hw_update_data; + cfg.init_packet = 0; rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); if (rc) { @@ -2374,6 +2375,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx, arg.hw_update_entries = req_isp->cfg; arg.num_hw_update_entries = req_isp->num_cfg; arg.priv = &req_isp->hw_update_data; + arg.init_packet = 1; ctx_isp->frame_id = 0; ctx_isp->active_req_cnt = 0; diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 0a127eff35a7..38a449796a18 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -1611,7 +1611,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, cdm_cmd->cmd[i].len = cmd->len; } - if (cfg->request_id == 1) + if (cfg->init_packet) init_completion(&ctx->config_done_complete); CAM_DBG(CAM_ISP, "Submit to CDM"); @@ -1621,7 +1621,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv, return rc; } - if (cfg->request_id == 1) { + if (cfg->init_packet) { rc = wait_for_completion_timeout( &ctx->config_done_complete, msecs_to_jiffies(30)); -- GitLab From 77dd58703e4f83c4e9a66b3496c29ef56e394889 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Mon, 2 Apr 2018 12:48:17 +0530 Subject: [PATCH 1320/1834] msm: ADSPRPC: handle static PDR during daemon start and kill Set the signal only if the msg.pid variable is not NULL. Change-Id: Iac70d2db43782985282d7fe00efb607fc7cd81b9 Acked-by: Krishnaiah Tadakamalla Signed-off-by: Tharun Kumar Merugu --- drivers/char/adsprpc.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 96314f429711..6b6189fd0622 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1220,6 +1220,25 @@ static void fastrpc_notify_users(struct fastrpc_file *me) } + +static void fastrpc_notify_users_staticpd_pdr(struct fastrpc_file *me) +{ + struct smq_invoke_ctx *ictx; + struct hlist_node *n; + + spin_lock(&me->hlock); + hlist_for_each_entry_safe(ictx, n, &me->clst.pending, hn) { + if (ictx->msg.pid) + complete(&ictx->work); + } + hlist_for_each_entry_safe(ictx, n, &me->clst.interrupted, hn) { + if (ictx->msg.pid) + complete(&ictx->work); + } + spin_unlock(&me->hlock); +} + + static void fastrpc_notify_drivers(struct fastrpc_apps *me, int cid) { struct fastrpc_file *fl; @@ -1242,7 +1261,7 @@ static void fastrpc_notify_pdr_drivers(struct fastrpc_apps *me, char *spdname) spin_lock(&me->hlock); hlist_for_each_entry_safe(fl, n, &me->drivers, hn) { if (fl->spdname && !strcmp(spdname, fl->spdname)) - fastrpc_notify_users(fl); + fastrpc_notify_users_staticpd_pdr(fl); } spin_unlock(&me->hlock); -- GitLab From 259c4b0cd97e348f77aba524b6abc9e27657ff04 Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Wed, 16 Nov 2016 09:24:32 -0800 Subject: [PATCH 1321/1834] msm: mdss: dsi: add support to set state for mode switch commands Some panels need to send the dcs commands for mode switch in HS mode instead the default LP mode due time constraints. Add entries so the panels can be configured to HS mode if required for the mode switch. Change-Id: Ie41ad1965384b131db343c54f888ade82fc45e31 Signed-off-by: Ingrid Gallardo --- Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt | 6 ++++++ drivers/video/fbdev/msm/mdss_dsi_panel.c | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index b8cb9036262f..60fe0c9d661e 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -452,6 +452,11 @@ Optional properties: - qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent to panel in order to switch from command mode to video mode dynamically. Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,mode-switch-commands-state: String that specifies the ctrl state for sending commands to switch + the panel mode, it applies for both switches, from command to video and + from video to command. + "dsi_lp_mode" = DSI low power mode (default) + "dsi_hs_mode" = DSI high speed mode - qcom,send-pps-before-switch: Boolean propety to indicate when PPS commands should be sent, either before or after switch commands during dynamic resolution switch in DSC panels. If the property is not present, the default @@ -687,6 +692,7 @@ Example: qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B 15 01 00 00 00 00 02 C2 08]; qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03]; + qcom,mode-switch-commands-state = "dsi_hs_mode"; qcom,send-pps-before-switch; qcom,panel-ack-disabled; qcom,mdss-dsi-horizontal-line-idle = <0 40 256>, diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 2ef1695b15f1..53152a257984 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -1823,10 +1823,12 @@ static void mdss_dsi_parse_dms_config(struct device_node *np, pr_debug("%s: default dms suspend/resume\n", __func__); mdss_dsi_parse_dcs_cmds(np, &ctrl->video2cmd, - "qcom,video-to-cmd-mode-switch-commands", NULL); + "qcom,video-to-cmd-mode-switch-commands", + "qcom,mode-switch-commands-state"); mdss_dsi_parse_dcs_cmds(np, &ctrl->cmd2video, - "qcom,cmd-to-video-mode-switch-commands", NULL); + "qcom,cmd-to-video-mode-switch-commands", + "qcom,mode-switch-commands-state"); mdss_dsi_parse_dcs_cmds(np, &ctrl->post_dms_on_cmds, "qcom,mdss-dsi-post-mode-switch-on-command", -- GitLab From 30e239e20a22c1c68b1ea95d5f4c7fbf6403c839 Mon Sep 17 00:00:00 2001 From: Vishalsingh Hajeri Date: Wed, 18 Apr 2018 16:07:28 -0700 Subject: [PATCH 1322/1834] msm: camera: isp: Add debug logs Print out information related to buffer io configuration. Change-Id: I56c884c9e613f3726cc9c79dfd31f17eb568d20e Signed-off-by: Vishalsingh Hajeri --- .../isp_hw_mgr/hw_utils/cam_isp_packet_parser.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c index 1d38f3bb1cb6..e869e2bdc918 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_isp_packet_parser.c @@ -579,8 +579,15 @@ int cam_isp_add_io_buffers( io_addr[plane_id] += io_cfg[i].offsets[plane_id]; CAM_DBG(CAM_ISP, - "get io_addr for plane %d: 0x%llx", - plane_id, io_addr[plane_id]); + "get io_addr for plane %d: 0x%llx, mem_hdl=0x%x", + plane_id, io_addr[plane_id], + io_cfg[i].mem_handle[plane_id]); + + CAM_DBG(CAM_ISP, + "mmu_hdl=0x%x, size=%d, end=0x%x", + mmu_hdl, (int)size, + io_addr[plane_id]+size); + } if (!plane_id) { CAM_ERR(CAM_ISP, "No valid planes for res%d", -- GitLab From 143b89baf4c73f8c38da895830d286243d748a98 Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Thu, 22 Dec 2016 16:19:10 -0500 Subject: [PATCH 1323/1834] msm: mdss: Avoid incorrect status while parsing dsi topology When parsing topology dtsi struct the return value gets set while checking for qcom,split-mode. When this node and DSC construct are not present, the rc value gets set as INVALID incorrectly. This change prevents that scenario. Change-Id: Id358e0d46ca5eacc75c5e7ff0064ff67f1b7e356 Signed-off-by: Naseer Ahmed Signed-off-by: Rashi Bindra --- drivers/video/fbdev/msm/mdss_dsi_panel.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 2ef1695b15f1..2dcf405b970c 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -1570,8 +1570,9 @@ static int mdss_dsi_parse_topology_config(struct device_node *np, goto end; } } - rc = of_property_read_string(cfg_np, "qcom,split-mode", &data); - if (!rc && !strcmp(data, "pingpong-split")) + + if (!of_property_read_string(cfg_np, "qcom,split-mode", + &data) && !strcmp(data, "pingpong-split")) pinfo->use_pingpong_split = true; if (((timing->lm_widths[0]) || (timing->lm_widths[1])) && -- GitLab From 53795e70aaabe1201d3804ba8fdea14bc0ebb94e Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Wed, 12 Oct 2016 18:38:48 -0700 Subject: [PATCH 1324/1834] msm: mdss: fix null pointer if wrong params passed on esd config If wrong parameters are set on the dtsi to configure the esd, a null pointer access can happen. Fix this to make sure we check for valid pointers and otherwise just throw an error, but not access an invalid pointer. Change-Id: I3df0889c1225dcb613910cb90f050a2994f5834d Signed-off-by: Ingrid Gallardo --- drivers/video/fbdev/msm/mdss_dsi_host.c | 5 +++++ drivers/video/fbdev/msm/mdss_dsi_panel.c | 13 ++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index d76be70b5704..7d737b539817 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -1134,6 +1134,11 @@ static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl) rc = 1; lenp = ctrl->status_valid_params ?: ctrl->status_cmds_rlen; + if (!lenp || !ctrl->status_cmds_rlen) { + pr_err("invalid dsi read params!\n"); + return 0; + } + for (i = 0; i < ctrl->status_cmds.cmd_cnt; ++i) { memset(&cmdreq, 0, sizeof(cmdreq)); cmdreq.cmds = ctrl->status_cmds.cmds + i; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 2ef1695b15f1..65d6153022ef 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -27,6 +27,8 @@ #ifdef TARGET_HW_MDSS_HDMI #include "mdss_dba_utils.h" #endif +#include "mdss_debug.h" + #define DT_CMD_HDR 6 #define MIN_REFRESH_RATE 48 #define DEFAULT_MDP_TRANSFER_TIME 14000 @@ -1683,7 +1685,7 @@ static int mdss_dsi_parse_reset_seq(struct device_node *np, static bool mdss_dsi_cmp_panel_reg_v2(struct mdss_dsi_ctrl_pdata *ctrl) { - int i, j; + int i, j = 0; int len = 0, *lenp; int group = 0; @@ -1692,6 +1694,15 @@ static bool mdss_dsi_cmp_panel_reg_v2(struct mdss_dsi_ctrl_pdata *ctrl) for (i = 0; i < ctrl->status_cmds.cmd_cnt; i++) len += lenp[i]; + for (i = 0; i < len; i++) { + pr_debug("[%i] return:0x%x status:0x%x\n", + i, (unsigned int)ctrl->return_buf[i], + (unsigned int)ctrl->status_value[j + i]); + MDSS_XLOG(ctrl->ndx, ctrl->return_buf[i], + ctrl->status_value[j + i]); + j += len; + } + for (j = 0; j < ctrl->groups; ++j) { for (i = 0; i < len; ++i) { if (ctrl->return_buf[i] != -- GitLab From efd2e783d8f387f52e9364cdc17c0036d9539572 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Wed, 24 Aug 2016 16:43:13 -0700 Subject: [PATCH 1325/1834] msm: mdss: dsi: fix panel minimum refresh rate configuration In the current implementation, if a DSI panel does not explicitly specify the minimum supported refresh rate, then it is set to 48 by default. This is incorrect since many panels may not support that low of a refresh rate. Fix this by setting the default value to the panel's actual refresh rate. CRs-Fixed: 1056610 Change-Id: I8d4267528068e36a648c328fbe6d6a35943f3810 Signed-off-by: Aravind Venkateswaran --- drivers/video/fbdev/msm/mdss_dsi_panel.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 2ef1695b15f1..7260493f3151 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -28,7 +28,6 @@ #include "mdss_dba_utils.h" #endif #define DT_CMD_HDR 6 -#define MIN_REFRESH_RATE 48 #define DEFAULT_MDP_TRANSFER_TIME 14000 #define VSYNC_DELAY msecs_to_jiffies(17) @@ -2146,10 +2145,10 @@ static int mdss_dsi_set_refresh_rate_range(struct device_node *pan_node, __func__, __LINE__); /* - * Since min refresh rate is not specified when dynamic - * fps is enabled, using minimum as 30 + * If min refresh rate is not specified, set it to the + * default panel refresh rate. */ - pinfo->min_fps = MIN_REFRESH_RATE; + pinfo->min_fps = pinfo->mipi.frame_rate; rc = 0; } -- GitLab From 12a6d3793d5f1964baa942e0f402dc9cd51c5f02 Mon Sep 17 00:00:00 2001 From: Yahui Wang Date: Mon, 12 Dec 2016 22:43:20 +0800 Subject: [PATCH 1326/1834] msm: mdss: add backlight gpio invert support for display Some platforms may use external gpio to enable and disable backlight, and we may need to invert this gpio according to HW design, so add support for that. CRs-Fixed: 1109294 Change-Id: Ib5e895eebcc38d185e8b703c3d895781b43c58c7 Signed-off-by: Yahui Wang --- .../devicetree/bindings/fb/mdss-dsi.txt | 5 +++++ drivers/video/fbdev/msm/dsi_v2.c | 4 ++++ drivers/video/fbdev/msm/mdss_dsi.c | 4 ++++ drivers/video/fbdev/msm/mdss_dsi.h | 2 ++ drivers/video/fbdev/msm/mdss_dsi_panel.c | 17 ++++++++++++++--- 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt index 8b593a97ef0d..1934bc5c9f34 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt @@ -110,6 +110,9 @@ Optional properties: both modes. - qcom,platform-intf-mux-gpio: Select dsi/external(hdmi) interface through gpio when it supports either dsi or external interface. +- qcom,platform-bklight-en-gpio-invert: Invert the gpio used to enable display back-light +- qcom,panel-mode-gpio: Specifies the GPIO to select video/command/single-port/dual-port + mode of panel through gpio when it supports these modes. - pinctrl-names: List of names to assign mdss pin states defined in pinctrl device node Refer to pinctrl-bindings.txt - pinctrl-<0..n>: Lists phandles each pointing to the pin configuration node within a pin @@ -253,6 +256,8 @@ Example: qcom,platform-bklight-en-gpio = <&msmgpio 86 0>; qcom,platform-mode-gpio = <&msmgpio 7 0>; qcom,platform-intf-mux-gpio = <&tlmm 115 0>; + qcom,platform-bklight-en-gpio-invert; + qcom,panel-mode-gpio = <&msmgpio 107 0>; qcom,dsi-irq-line; qcom,lane-map = "lane_map_3012"; qcom,display-id = "primary"; diff --git a/drivers/video/fbdev/msm/dsi_v2.c b/drivers/video/fbdev/msm/dsi_v2.c index 74c072602b10..11c7144c605b 100644 --- a/drivers/video/fbdev/msm/dsi_v2.c +++ b/drivers/video/fbdev/msm/dsi_v2.c @@ -233,6 +233,10 @@ static int dsi_parse_gpio(struct platform_device *pdev, pr_err("%s:%d, bklt_en gpio not specified\n", __func__, __LINE__); + ctrl_pdata->bklt_en_gpio_invert = + of_property_read_bool(ctrl_pdev->dev.of_node, + "qcom,platform-bklight-en-gpio-invert"); + return 0; } diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index cad1387a8d73..d8e74dab4251 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -4084,6 +4084,10 @@ static int mdss_dsi_parse_gpio_params(struct platform_device *ctrl_pdev, if (!gpio_is_valid(ctrl_pdata->bklt_en_gpio)) pr_info("%s: bklt_en gpio not specified\n", __func__); + ctrl_pdata->bklt_en_gpio_invert = + of_property_read_bool(ctrl_pdev->dev.of_node, + "qcom,platform-bklight-en-gpio-invert"); + ctrl_pdata->rst_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, "qcom,platform-reset-gpio", 0); if (!gpio_is_valid(ctrl_pdata->rst_gpio)) diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 058c27a61130..c13d22a974ff 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -435,6 +435,8 @@ struct mdss_dsi_ctrl_pdata { int bklt_en_gpio; int mode_gpio; int intf_mux_gpio; + bool bklt_en_gpio_invert; + int lcd_mode_sel_gpio; int bklt_ctrl; /* backlight ctrl */ bool pwm_pmi; int pwm_period; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 2ef1695b15f1..986be2c30e19 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -442,8 +442,14 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) } if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) { - rc = gpio_direction_output( - ctrl_pdata->bklt_en_gpio, 1); + + if (ctrl_pdata->bklt_en_gpio_invert) + rc = gpio_direction_output( + ctrl_pdata->bklt_en_gpio, 0); + else + rc = gpio_direction_output( + ctrl_pdata->bklt_en_gpio, 1); + if (rc) { pr_err("%s: unable to set dir for bklt gpio\n", __func__); @@ -475,7 +481,12 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) } } else { if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) { - gpio_set_value((ctrl_pdata->bklt_en_gpio), 0); + + if (ctrl_pdata->bklt_en_gpio_invert) + gpio_set_value((ctrl_pdata->bklt_en_gpio), 1); + else + gpio_set_value((ctrl_pdata->bklt_en_gpio), 0); + gpio_free(ctrl_pdata->bklt_en_gpio); } if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { -- GitLab From 394a9a7b7387e5cc8661b45e9bd111c850437c8e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 28 Mar 2018 13:59:22 -0400 Subject: [PATCH 1327/1834] media: v4l2-compat-ioctl32: don't oops on overlay commit 85ea29f19eab56ec16ec6b92bc67305998706afa upstream. At put_v4l2_window32(), it tries to access kp->clips. However, kp points to an userspace pointer. So, it should be obtained via get_user(), otherwise it can OOPS: vivid-000: ================== END STATUS ================== BUG: unable to handle kernel paging request at 00000000fffb18e0 IP: [] __put_v4l2_format32+0x169/0x220 [videodev] PGD 3f5776067 PUD 3f576f067 PMD 3f5769067 PTE 800000042548f067 Oops: 0001 [#1] SMP Modules linked in: vivid videobuf2_vmalloc videobuf2_memops v4l2_dv_timings videobuf2_core v4l2_common videodev media xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack tun bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables bluetooth rfkill binfmt_misc snd_hda_codec_hdmi i915 snd_hda_intel snd_hda_controller snd_hda_codec intel_rapl x86_pkg_temp_thermal snd_hwdep intel_powerclamp snd_pcm coretemp snd_seq_midi kvm_intel kvm snd_seq_midi_event snd_rawmidi i2c_algo_bit drm_kms_helper snd_seq drm crct10dif_pclmul e1000e snd_seq_device crc32_pclmul snd_timer ghash_clmulni_intel snd mei_me mei ptp pps_core soundcore lpc_ich video crc32c_intel [last unloaded: media] CPU: 2 PID: 28332 Comm: v4l2-compliance Not tainted 3.18.102+ #107 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 task: ffff8804293f8000 ti: ffff8803f5640000 task.ti: ffff8803f5640000 RIP: 0010:[] [] __put_v4l2_format32+0x169/0x220 [videodev] RSP: 0018:ffff8803f5643e28 EFLAGS: 00010246 RAX: 0000000000000000 RBX: 0000000000000000 RCX: 00000000fffb1ab4 RDX: 00000000fffb1a68 RSI: 00000000fffb18d8 RDI: 00000000fffb1aa8 RBP: ffff8803f5643e48 R08: 0000000000000001 R09: ffff8803f54b0378 R10: 0000000000000000 R11: 0000000000000168 R12: 00000000fffb18c0 R13: 00000000fffb1a94 R14: 00000000fffb18c8 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff880456d00000(0063) knlGS:00000000f7100980 CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 CR2: 00000000fffb18e0 CR3: 00000003f552b000 CR4: 00000000003407e0 Stack: 00000000fffb1a94 00000000c0cc5640 0000000000000056 ffff8804274f3600 ffff8803f5643ed0 ffffffffc0547e16 0000000000000003 ffff8803f5643eb0 ffffffff81301460 ffff88009db44b01 ffff880441942520 ffff8800c0d05640 Call Trace: [] v4l2_compat_ioctl32+0x12d6/0x1b1d [videodev] [] ? file_has_perm+0x70/0xc0 [] compat_SyS_ioctl+0xec/0x1200 [] sysenter_dispatch+0x7/0x21 Code: 00 00 48 8b 80 48 c0 ff ff 48 83 e8 38 49 39 c6 0f 87 2b ff ff ff 49 8d 45 1c e8 a3 ce e3 c0 85 c0 0f 85 1a ff ff ff 41 8d 40 ff <4d> 8b 64 24 20 41 89 d5 48 8d 44 40 03 4d 8d 34 c4 eb 15 0f 1f RIP [] __put_v4l2_format32+0x169/0x220 [videodev] RSP CR2: 00000000fffb18e0 Tested with vivid driver on Kernel v3.18.102. Same bug happens upstream too: BUG: KASAN: user-memory-access in __put_v4l2_format32+0x98/0x4d0 [videodev] Read of size 8 at addr 00000000ffe48400 by task v4l2-compliance/8713 CPU: 0 PID: 8713 Comm: v4l2-compliance Not tainted 4.16.0-rc4+ #108 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 Call Trace: dump_stack+0x5c/0x7c kasan_report+0x164/0x380 ? __put_v4l2_format32+0x98/0x4d0 [videodev] __put_v4l2_format32+0x98/0x4d0 [videodev] v4l2_compat_ioctl32+0x1aec/0x27a0 [videodev] ? __fsnotify_inode_delete+0x20/0x20 ? __put_v4l2_format32+0x4d0/0x4d0 [videodev] compat_SyS_ioctl+0x646/0x14d0 ? do_ioctl+0x30/0x30 do_fast_syscall_32+0x191/0x3f4 entry_SYSENTER_compat+0x6b/0x7a ================================================================== Disabling lock debugging due to kernel taint BUG: unable to handle kernel paging request at 00000000ffe48400 IP: __put_v4l2_format32+0x98/0x4d0 [videodev] PGD 3a22fb067 P4D 3a22fb067 PUD 39b6f0067 PMD 39b6f1067 PTE 80000003256af067 Oops: 0001 [#1] SMP KASAN Modules linked in: vivid videobuf2_vmalloc videobuf2_dma_contig videobuf2_memops v4l2_tpg v4l2_dv_timings videobuf2_v4l2 videobuf2_common v4l2_common videodev xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack libcrc32c tun bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables bluetooth rfkill ecdh_generic binfmt_misc snd_hda_codec_hdmi intel_rapl x86_pkg_temp_thermal intel_powerclamp i915 coretemp snd_hda_intel snd_hda_codec kvm_intel snd_hwdep snd_hda_core kvm snd_pcm irqbypass crct10dif_pclmul crc32_pclmul snd_seq_midi ghash_clmulni_intel snd_seq_midi_event i2c_algo_bit intel_cstate snd_rawmidi intel_uncore snd_seq drm_kms_helper e1000e snd_seq_device snd_timer intel_rapl_perf drm ptp snd mei_me mei lpc_ich pps_core soundcore video crc32c_intel CPU: 0 PID: 8713 Comm: v4l2-compliance Tainted: G B 4.16.0-rc4+ #108 Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0364.2017.0511.0949 05/11/2017 RIP: 0010:__put_v4l2_format32+0x98/0x4d0 [videodev] RSP: 0018:ffff8803b9be7d30 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff8803ac983e80 RCX: ffffffff8cd929f2 RDX: 1ffffffff1d0a149 RSI: 0000000000000297 RDI: 0000000000000297 RBP: 00000000ffe485c0 R08: fffffbfff1cf5123 R09: ffffffff8e7a8948 R10: 0000000000000001 R11: fffffbfff1cf5122 R12: 00000000ffe483e0 R13: 00000000ffe485c4 R14: ffff8803ac985918 R15: 00000000ffe483e8 FS: 0000000000000000(0000) GS:ffff880407400000(0063) knlGS:00000000f7a46980 CS: 0010 DS: 002b ES: 002b CR0: 0000000080050033 CR2: 00000000ffe48400 CR3: 00000003a83f2003 CR4: 00000000003606f0 Call Trace: v4l2_compat_ioctl32+0x1aec/0x27a0 [videodev] ? __fsnotify_inode_delete+0x20/0x20 ? __put_v4l2_format32+0x4d0/0x4d0 [videodev] compat_SyS_ioctl+0x646/0x14d0 ? do_ioctl+0x30/0x30 do_fast_syscall_32+0x191/0x3f4 entry_SYSENTER_compat+0x6b/0x7a Code: 4c 89 f7 4d 8d 7c 24 08 e8 e6 a4 69 cb 48 8b 83 98 1a 00 00 48 83 e8 10 49 39 c7 0f 87 9d 01 00 00 49 8d 7c 24 20 e8 c8 a4 69 cb <4d> 8b 74 24 20 4c 89 ef 4c 89 fe ba 10 00 00 00 e8 23 d9 08 cc RIP: __put_v4l2_format32+0x98/0x4d0 [videodev] RSP: ffff8803b9be7d30 CR2: 00000000ffe48400 cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Sakari Ailus Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Greg Kroah-Hartman --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 48a39222fdf9..a9fc64557c53 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -101,7 +101,7 @@ static int get_v4l2_window32(struct v4l2_window __user *kp, static int put_v4l2_window32(struct v4l2_window __user *kp, struct v4l2_window32 __user *up) { - struct v4l2_clip __user *kclips = kp->clips; + struct v4l2_clip __user *kclips; struct v4l2_clip32 __user *uclips; compat_caddr_t p; u32 clipcount; @@ -116,6 +116,8 @@ static int put_v4l2_window32(struct v4l2_window __user *kp, if (!clipcount) return 0; + if (get_user(kclips, &kp->clips)) + return -EFAULT; if (get_user(p, &up->clips)) return -EFAULT; uclips = compat_ptr(p); -- GitLab From 68401e8b681329976f2a988fbfe0480e1abd6440 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 25 Mar 2018 23:53:22 +0200 Subject: [PATCH 1328/1834] parisc: Fix out of array access in match_pci_device() commit 615b2665fd20c327b631ff1e79426775de748094 upstream. As found by the ubsan checker, the value of the 'index' variable can be out of range for the bc[] array: UBSAN: Undefined behaviour in arch/parisc/kernel/drivers.c:655:21 index 6 is out of range for type 'char [6]' Backtrace: [<104fa850>] __ubsan_handle_out_of_bounds+0x68/0x80 [<1019d83c>] check_parent+0xc0/0x170 [<1019d91c>] descend_children+0x30/0x6c [<1059e164>] device_for_each_child+0x60/0x98 [<1019cd54>] parse_tree_node+0x40/0x54 [<1019d86c>] check_parent+0xf0/0x170 [<1019d91c>] descend_children+0x30/0x6c [<1059e164>] device_for_each_child+0x60/0x98 [<1019d938>] descend_children+0x4c/0x6c [<1059e164>] device_for_each_child+0x60/0x98 [<1019cd54>] parse_tree_node+0x40/0x54 [<1019cffc>] hwpath_to_device+0xa4/0xc4 Signed-off-by: Helge Deller Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- arch/parisc/kernel/drivers.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c index 700e2d2da096..2e68ca1fe0db 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -648,6 +648,10 @@ static int match_pci_device(struct device *dev, int index, (modpath->mod == PCI_FUNC(devfn))); } + /* index might be out of bounds for bc[] */ + if (index >= 6) + return 0; + id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5); return (modpath->bc[index] == id); } -- GitLab From 6408066f849ee17f0db76e8f091b759242ea2f52 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Tue, 27 Mar 2018 15:01:02 -0700 Subject: [PATCH 1329/1834] Drivers: hv: vmbus: do not mark HV_PCIE as perf_device commit 238064f13d057390a8c5e1a6a80f4f0a0ec46499 upstream. The pci-hyperv driver's channel callback hv_pci_onchannelcallback() is not really a hot path, so we don't need to mark it as a perf_device, meaning with this patch all HV_PCIE channels' target_cpu will be CPU0. Signed-off-by: Dexuan Cui Cc: stable@vger.kernel.org Cc: Stephen Hemminger Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index d8bc4b910192..9360cdce740e 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -70,7 +70,7 @@ static const struct vmbus_device vmbus_devs[] = { /* PCIE */ { .dev_type = HV_PCIE, HV_PCIE_GUID, - .perf_device = true, + .perf_device = false, }, /* Synthetic Frame Buffer */ -- GitLab From aad2ad6e3cd0c59786b15acd6a220fe5068d3a10 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:21 +0200 Subject: [PATCH 1330/1834] perf intel-pt: Fix overlap detection to identify consecutive buffers correctly commit 117db4b27bf08dba412faf3924ba55fe970c57b8 upstream. Overlap detection was not not updating the buffer's 'consecutive' flag. Marking buffers consecutive has the advantage that decoding begins from the start of the buffer instead of the first PSB. Fix overlap detection to identify consecutive buffers correctly. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- .../util/intel-pt-decoder/intel-pt-decoder.c | 62 +++++++++---------- .../util/intel-pt-decoder/intel-pt-decoder.h | 2 +- tools/perf/util/intel-pt.c | 5 +- 3 files changed, 34 insertions(+), 35 deletions(-) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 7e27207d0f45..c202e114a2bb 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -2182,14 +2182,6 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder) return &decoder->state; } -static bool intel_pt_at_psb(unsigned char *buf, size_t len) -{ - if (len < INTEL_PT_PSB_LEN) - return false; - return memmem(buf, INTEL_PT_PSB_LEN, INTEL_PT_PSB_STR, - INTEL_PT_PSB_LEN); -} - /** * intel_pt_next_psb - move buffer pointer to the start of the next PSB packet. * @buf: pointer to buffer pointer @@ -2278,6 +2270,7 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len) * @buf: buffer * @len: size of buffer * @tsc: TSC value returned + * @rem: returns remaining size when TSC is found * * Find a TSC packet in @buf and return the TSC value. This function assumes * that @buf starts at a PSB and that PSB+ will contain TSC and so stops if a @@ -2285,7 +2278,8 @@ static unsigned char *intel_pt_last_psb(unsigned char *buf, size_t len) * * Return: %true if TSC is found, false otherwise. */ -static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc) +static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc, + size_t *rem) { struct intel_pt_pkt packet; int ret; @@ -2296,6 +2290,7 @@ static bool intel_pt_next_tsc(unsigned char *buf, size_t len, uint64_t *tsc) return false; if (packet.type == INTEL_PT_TSC) { *tsc = packet.payload; + *rem = len; return true; } if (packet.type == INTEL_PT_PSBEND) @@ -2346,6 +2341,8 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2) * @len_a: size of first buffer * @buf_b: second buffer * @len_b: size of second buffer + * @consecutive: returns true if there is data in buf_b that is consecutive + * to buf_a * * If the trace contains TSC we can look at the last TSC of @buf_a and the * first TSC of @buf_b in order to determine if the buffers overlap, and then @@ -2358,33 +2355,41 @@ static int intel_pt_tsc_cmp(uint64_t tsc1, uint64_t tsc2) static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, size_t len_a, unsigned char *buf_b, - size_t len_b) + size_t len_b, bool *consecutive) { uint64_t tsc_a, tsc_b; unsigned char *p; - size_t len; + size_t len, rem_a, rem_b; p = intel_pt_last_psb(buf_a, len_a); if (!p) return buf_b; /* No PSB in buf_a => no overlap */ len = len_a - (p - buf_a); - if (!intel_pt_next_tsc(p, len, &tsc_a)) { + if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) { /* The last PSB+ in buf_a is incomplete, so go back one more */ len_a -= len; p = intel_pt_last_psb(buf_a, len_a); if (!p) return buf_b; /* No full PSB+ => assume no overlap */ len = len_a - (p - buf_a); - if (!intel_pt_next_tsc(p, len, &tsc_a)) + if (!intel_pt_next_tsc(p, len, &tsc_a, &rem_a)) return buf_b; /* No TSC in buf_a => assume no overlap */ } while (1) { /* Ignore PSB+ with no TSC */ - if (intel_pt_next_tsc(buf_b, len_b, &tsc_b) && - intel_pt_tsc_cmp(tsc_a, tsc_b) < 0) - return buf_b; /* tsc_a < tsc_b => no overlap */ + if (intel_pt_next_tsc(buf_b, len_b, &tsc_b, &rem_b)) { + int cmp = intel_pt_tsc_cmp(tsc_a, tsc_b); + + /* Same TSC, so buffers are consecutive */ + if (!cmp && rem_b >= rem_a) { + *consecutive = true; + return buf_b + len_b - (rem_b - rem_a); + } + if (cmp < 0) + return buf_b; /* tsc_a < tsc_b => no overlap */ + } if (!intel_pt_step_psb(&buf_b, &len_b)) return buf_b + len_b; /* No PSB in buf_b => no data */ @@ -2398,6 +2403,8 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, * @buf_b: second buffer * @len_b: size of second buffer * @have_tsc: can use TSC packets to detect overlap + * @consecutive: returns true if there is data in buf_b that is consecutive + * to buf_a * * When trace samples or snapshots are recorded there is the possibility that * the data overlaps. Note that, for the purposes of decoding, data is only @@ -2408,7 +2415,7 @@ static unsigned char *intel_pt_find_overlap_tsc(unsigned char *buf_a, */ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, unsigned char *buf_b, size_t len_b, - bool have_tsc) + bool have_tsc, bool *consecutive) { unsigned char *found; @@ -2420,7 +2427,8 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, return buf_b; /* No overlap */ if (have_tsc) { - found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b); + found = intel_pt_find_overlap_tsc(buf_a, len_a, buf_b, len_b, + consecutive); if (found) return found; } @@ -2435,28 +2443,16 @@ unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, } /* Now len_b >= len_a */ - if (len_b > len_a) { - /* The leftover buffer 'b' must start at a PSB */ - while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) { - if (!intel_pt_step_psb(&buf_a, &len_a)) - return buf_b; /* No overlap */ - } - } - while (1) { /* Potential overlap so check the bytes */ found = memmem(buf_a, len_a, buf_b, len_a); - if (found) + if (found) { + *consecutive = true; return buf_b + len_a; + } /* Try again at next PSB in buffer 'a' */ if (!intel_pt_step_psb(&buf_a, &len_a)) return buf_b; /* No overlap */ - - /* The leftover buffer 'b' must start at a PSB */ - while (!intel_pt_at_psb(buf_b + len_a, len_b - len_a)) { - if (!intel_pt_step_psb(&buf_a, &len_a)) - return buf_b; /* No overlap */ - } } } diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index 89399985fa4d..9ae4df1dcedc 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -103,7 +103,7 @@ const struct intel_pt_state *intel_pt_decode(struct intel_pt_decoder *decoder); unsigned char *intel_pt_find_overlap(unsigned char *buf_a, size_t len_a, unsigned char *buf_b, size_t len_b, - bool have_tsc); + bool have_tsc, bool *consecutive); int intel_pt__strerror(int code, char *buf, size_t buflen); diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index dc041d4368c8..f832657871b8 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -194,14 +194,17 @@ static void intel_pt_dump_event(struct intel_pt *pt, unsigned char *buf, static int intel_pt_do_fix_overlap(struct intel_pt *pt, struct auxtrace_buffer *a, struct auxtrace_buffer *b) { + bool consecutive = false; void *start; start = intel_pt_find_overlap(a->data, a->size, b->data, b->size, - pt->have_tsc); + pt->have_tsc, &consecutive); if (!start) return -EINVAL; b->use_size = b->data + b->size - start; b->use_data = start; + if (b->use_size && consecutive) + b->consecutive = true; return 0; } -- GitLab From 6a33036b130a2ad01f16a205ef36b21d1b89f10a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:22 +0200 Subject: [PATCH 1331/1834] perf intel-pt: Fix sync_switch commit 63d8e38f6ae6c36dd5b5ba0e8c112e8861532ea2 upstream. sync_switch is a facility to synchronize decoding more closely with the point in the kernel when the context actually switched. The flag when sync_switch is enabled was global to the decoding, whereas it is really specific to the CPU. The trace data for different CPUs is put on different queues, so add sync_switch to the intel_pt_queue structure and use that in preference to the global setting in the intel_pt structure. That fixes problems decoding one CPU's trace because sync_switch was disabled on a different CPU's queue. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index f832657871b8..b1161d725ce9 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -131,6 +131,7 @@ struct intel_pt_queue { bool stop; bool step_through_buffers; bool use_buffer_pid_tid; + bool sync_switch; pid_t pid, tid; int cpu; int switch_state; @@ -931,10 +932,12 @@ static int intel_pt_setup_queue(struct intel_pt *pt, if (pt->timeless_decoding || !pt->have_sched_switch) ptq->use_buffer_pid_tid = true; } + + ptq->sync_switch = pt->sync_switch; } if (!ptq->on_heap && - (!pt->sync_switch || + (!ptq->sync_switch || ptq->switch_state != INTEL_PT_SS_EXPECTING_SWITCH_EVENT)) { const struct intel_pt_state *state; int ret; @@ -1336,7 +1339,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) if (pt->synth_opts.last_branch) intel_pt_update_last_branch_rb(ptq); - if (!pt->sync_switch) + if (!ptq->sync_switch) return 0; if (intel_pt_is_switch_ip(ptq, state->to_ip)) { @@ -1417,6 +1420,21 @@ static u64 intel_pt_switch_ip(struct intel_pt *pt, u64 *ptss_ip) return switch_ip; } +static void intel_pt_enable_sync_switch(struct intel_pt *pt) +{ + unsigned int i; + + pt->sync_switch = true; + + for (i = 0; i < pt->queues.nr_queues; i++) { + struct auxtrace_queue *queue = &pt->queues.queue_array[i]; + struct intel_pt_queue *ptq = queue->priv; + + if (ptq) + ptq->sync_switch = true; + } +} + static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) { const struct intel_pt_state *state = ptq->state; @@ -1433,7 +1451,7 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) if (pt->switch_ip) { intel_pt_log("switch_ip: %"PRIx64" ptss_ip: %"PRIx64"\n", pt->switch_ip, pt->ptss_ip); - pt->sync_switch = true; + intel_pt_enable_sync_switch(pt); } } } @@ -1449,9 +1467,9 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) if (state->err) { if (state->err == INTEL_PT_ERR_NODATA) return 1; - if (pt->sync_switch && + if (ptq->sync_switch && state->from_ip >= pt->kernel_start) { - pt->sync_switch = false; + ptq->sync_switch = false; intel_pt_next_tid(pt, ptq); } if (pt->synth_opts.errors) { @@ -1477,7 +1495,7 @@ static int intel_pt_run_decoder(struct intel_pt_queue *ptq, u64 *timestamp) state->timestamp, state->est_timestamp); ptq->timestamp = state->est_timestamp; /* Use estimated TSC in unknown switch state */ - } else if (pt->sync_switch && + } else if (ptq->sync_switch && ptq->switch_state == INTEL_PT_SS_UNKNOWN && intel_pt_is_switch_ip(ptq, state->to_ip) && ptq->next_tid == -1) { @@ -1624,7 +1642,7 @@ static int intel_pt_sync_switch(struct intel_pt *pt, int cpu, pid_t tid, return 1; ptq = intel_pt_cpu_to_ptq(pt, cpu); - if (!ptq) + if (!ptq || !ptq->sync_switch) return 1; switch (ptq->switch_state) { -- GitLab From 2c1f44bdf8e088c693189edf4233ad8eb09faa65 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:23 +0200 Subject: [PATCH 1332/1834] perf intel-pt: Fix error recovery from missing TIP packet commit 1c196a6c771c47a2faa63d38d913e03284f73a16 upstream. When a TIP packet is expected but there is a different packet, it is an error. However the unexpected packet might be something important like a TSC packet, so after the error, it is necessary to continue from there, rather than the next packet. That is achieved by setting pkt_step to zero. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index c202e114a2bb..1d0ea0c78d0c 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1522,6 +1522,7 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) case INTEL_PT_PSBEND: intel_pt_log("ERROR: Missing TIP after FUP\n"); decoder->pkt_state = INTEL_PT_STATE_ERR3; + decoder->pkt_step = 0; return -ENOENT; case INTEL_PT_OVF: -- GitLab From 57ce7d4b43db2ec16807a50a12b4724f60c6a641 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Mar 2018 16:02:24 +0200 Subject: [PATCH 1333/1834] perf intel-pt: Fix timestamp following overflow commit 91d29b288aed3406caf7c454bf2b898c96cfd177 upstream. timestamp_insn_cnt is used to estimate the timestamp based on the number of instructions since the last known timestamp. If the estimate is not accurate enough decoding might not be correctly synchronized with side-band events causing more trace errors. However there are always timestamps following an overflow, so the estimate is not needed and can indeed result in more errors. Suppress the estimate by setting timestamp_insn_cnt to zero. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1520431349-30689-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Greg Kroah-Hartman --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 1d0ea0c78d0c..cac39532c057 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1300,6 +1300,7 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder) intel_pt_clear_tx_flags(decoder); decoder->have_tma = false; decoder->cbr = 0; + decoder->timestamp_insn_cnt = 0; decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; decoder->overflow = true; return -EOVERFLOW; -- GitLab From b951ffb160f765db6b06b9ee065f79faed5fa9e1 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Mon, 9 Apr 2018 19:03:46 +0900 Subject: [PATCH 1334/1834] perf/core: Fix use-after-free in uprobe_perf_close() commit 621b6d2ea297d0fb6030452c5bcd221f12165fcf upstream. A use-after-free bug was caught by KASAN while running usdt related code (BCC project. bcc/tests/python/test_usdt2.py): ================================================================== BUG: KASAN: use-after-free in uprobe_perf_close+0x222/0x3b0 Read of size 4 at addr ffff880384f9b4a4 by task test_usdt2.py/870 CPU: 4 PID: 870 Comm: test_usdt2.py Tainted: G W 4.16.0-next-20180409 #215 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Ubuntu-1.8.2-1ubuntu1 04/01/2014 Call Trace: dump_stack+0xc7/0x15b ? show_regs_print_info+0x5/0x5 ? printk+0x9c/0xc3 ? kmsg_dump_rewind_nolock+0x6e/0x6e ? uprobe_perf_close+0x222/0x3b0 print_address_description+0x83/0x3a0 ? uprobe_perf_close+0x222/0x3b0 kasan_report+0x1dd/0x460 ? uprobe_perf_close+0x222/0x3b0 uprobe_perf_close+0x222/0x3b0 ? probes_open+0x180/0x180 ? free_filters_list+0x290/0x290 trace_uprobe_register+0x1bb/0x500 ? perf_event_attach_bpf_prog+0x310/0x310 ? probe_event_disable+0x4e0/0x4e0 perf_uprobe_destroy+0x63/0xd0 _free_event+0x2bc/0xbd0 ? lockdep_rcu_suspicious+0x100/0x100 ? ring_buffer_attach+0x550/0x550 ? kvm_sched_clock_read+0x1a/0x30 ? perf_event_release_kernel+0x3e4/0xc00 ? __mutex_unlock_slowpath+0x12e/0x540 ? wait_for_completion+0x430/0x430 ? lock_downgrade+0x3c0/0x3c0 ? lock_release+0x980/0x980 ? do_raw_spin_trylock+0x118/0x150 ? do_raw_spin_unlock+0x121/0x210 ? do_raw_spin_trylock+0x150/0x150 perf_event_release_kernel+0x5d4/0xc00 ? put_event+0x30/0x30 ? fsnotify+0xd2d/0xea0 ? sched_clock_cpu+0x18/0x1a0 ? __fsnotify_update_child_dentry_flags.part.0+0x1b0/0x1b0 ? pvclock_clocksource_read+0x152/0x2b0 ? pvclock_read_flags+0x80/0x80 ? kvm_sched_clock_read+0x1a/0x30 ? sched_clock_cpu+0x18/0x1a0 ? pvclock_clocksource_read+0x152/0x2b0 ? locks_remove_file+0xec/0x470 ? pvclock_read_flags+0x80/0x80 ? fcntl_setlk+0x880/0x880 ? ima_file_free+0x8d/0x390 ? lockdep_rcu_suspicious+0x100/0x100 ? ima_file_check+0x110/0x110 ? fsnotify+0xea0/0xea0 ? kvm_sched_clock_read+0x1a/0x30 ? rcu_note_context_switch+0x600/0x600 perf_release+0x21/0x40 __fput+0x264/0x620 ? fput+0xf0/0xf0 ? do_raw_spin_unlock+0x121/0x210 ? do_raw_spin_trylock+0x150/0x150 ? SyS_fchdir+0x100/0x100 ? fsnotify+0xea0/0xea0 task_work_run+0x14b/0x1e0 ? task_work_cancel+0x1c0/0x1c0 ? copy_fd_bitmaps+0x150/0x150 ? vfs_read+0xe5/0x260 exit_to_usermode_loop+0x17b/0x1b0 ? trace_event_raw_event_sys_exit+0x1a0/0x1a0 do_syscall_64+0x3f6/0x490 ? syscall_return_slowpath+0x2c0/0x2c0 ? lockdep_sys_exit+0x1f/0xaa ? syscall_return_slowpath+0x1a3/0x2c0 ? lockdep_sys_exit+0x1f/0xaa ? prepare_exit_to_usermode+0x11c/0x1e0 ? enter_from_user_mode+0x30/0x30 random: crng init done ? __put_user_4+0x1c/0x30 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 RIP: 0033:0x7f41d95f9340 RSP: 002b:00007fffe71e4268 EFLAGS: 00000246 ORIG_RAX: 0000000000000003 RAX: 0000000000000000 RBX: 000000000000000d RCX: 00007f41d95f9340 RDX: 0000000000000000 RSI: 0000000000002401 RDI: 000000000000000d RBP: 0000000000000000 R08: 00007f41ca8ff700 R09: 00007f41d996dd1f R10: 00007fffe71e41e0 R11: 0000000000000246 R12: 00007fffe71e4330 R13: 0000000000000000 R14: fffffffffffffffc R15: 00007fffe71e4290 Allocated by task 870: kasan_kmalloc+0xa0/0xd0 kmem_cache_alloc_node+0x11a/0x430 copy_process.part.19+0x11a0/0x41c0 _do_fork+0x1be/0xa20 do_syscall_64+0x198/0x490 entry_SYSCALL_64_after_hwframe+0x3d/0xa2 Freed by task 0: __kasan_slab_free+0x12e/0x180 kmem_cache_free+0x102/0x4d0 free_task+0xfe/0x160 __put_task_struct+0x189/0x290 delayed_put_task_struct+0x119/0x250 rcu_process_callbacks+0xa6c/0x1b60 __do_softirq+0x238/0x7ae The buggy address belongs to the object at ffff880384f9b480 which belongs to the cache task_struct of size 12928 It occurs because task_struct is freed before perf_event which refers to the task and task flags are checked while teardown of the event. perf_event_alloc() assigns task_struct to hw.target of perf_event, but there is no reference counting for it. As a fix we get_task_struct() in perf_event_alloc() at above mentioned assignment and put_task_struct() in _free_event(). Signed-off-by: Prashant Bhole Reviewed-by: Oleg Nesterov Acked-by: Peter Zijlstra (Intel) Cc: Cc: Alexander Shishkin Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Linus Torvalds Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Gleixner Fixes: 63b6da39bb38e8f1a1ef3180d32a39d6 ("perf: Fix perf_event_exit_task() race") Link: http://lkml.kernel.org/r/20180409100346.6416-1-bhole_prashant_q7@lab.ntt.co.jp Signed-off-by: Ingo Molnar Signed-off-by: Greg Kroah-Hartman --- kernel/events/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/kernel/events/core.c b/kernel/events/core.c index c4100c38a467..74710fad35d5 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4091,6 +4091,9 @@ static void _free_event(struct perf_event *event) if (event->ctx) put_ctx(event->ctx); + if (event->hw.target) + put_task_struct(event->hw.target); + exclusive_event_destroy(event); module_put(event->pmu->module); @@ -9214,6 +9217,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, * and we cannot use the ctx information because we need the * pmu before we get a ctx. */ + get_task_struct(task); event->hw.target = task; } @@ -9331,6 +9335,8 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, perf_detach_cgroup(event); if (event->ns) put_pid_ns(event->ns); + if (event->hw.target) + put_task_struct(event->hw.target); kfree(event); return ERR_PTR(err); -- GitLab From cacf021760ee51ef163b1094c9163a863be6b104 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2018 16:26:57 +0100 Subject: [PATCH 1335/1834] radeon: hide pointless #warning when compile testing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit c02216acf4177c4411d33735c81cad687790fa59 upstream. In randconfig testing, we sometimes get this warning: drivers/gpu/drm/radeon/radeon_object.c: In function 'radeon_bo_create': drivers/gpu/drm/radeon/radeon_object.c:242:2: error: #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance thanks to write-combining [-Werror=cpp] #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ This is rather annoying since almost all other code produces no build-time output unless we have found a real bug. We already fixed this in the amdgpu driver in commit 31bb90f1cd08 ("drm/amdgpu: shut up #warning for compile testing") by adding a CONFIG_COMPILE_TEST check last year and agreed to do the same here, but both Michel and I then forgot about it until I came across the issue again now. For stable kernels, as this is one of very few remaining randconfig warnings in 4.14. Cc: stable@vger.kernel.org Link: https://patchwork.kernel.org/patch/9550009/ Signed-off-by: Arnd Bergmann Signed-off-by: Michel Dänzer Signed-off-by: Alex Deucher Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/radeon_object.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 41b72ce6613f..83e1345db9e2 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -238,9 +238,10 @@ int radeon_bo_create(struct radeon_device *rdev, * may be slow * See https://bugs.freedesktop.org/show_bug.cgi?id=88758 */ - +#ifndef CONFIG_COMPILE_TEST #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ thanks to write-combining +#endif if (bo->flags & RADEON_GEM_GTT_WC) DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " -- GitLab From afc09540dab21e717ae116f646455eb812cbf11c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:10:57 +0100 Subject: [PATCH 1336/1834] arm64: barrier: Add CSDB macros to control data-value prediction From: Will Deacon commit 669474e772b952b14f4de4845a1558fd4c0414a4 upstream. For CPUs capable of data value prediction, CSDB waits for any outstanding predictions to architecturally resolve before allowing speculative execution to continue. Provide macros to expose it to the arch code. Reviewed-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/assembler.h | 7 +++++++ arch/arm64/include/asm/barrier.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 7193bf97b8da..b223b1b4d5cd 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -86,6 +86,13 @@ dmb \opt .endm +/* + * Value prediction barrier + */ + .macro csdb + hint #20 + .endm + /* * NOP sequence */ diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 0fe7e43b7fbc..c68fdc5707ed 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -31,6 +31,8 @@ #define dmb(opt) asm volatile("dmb " #opt : : : "memory") #define dsb(opt) asm volatile("dsb " #opt : : : "memory") +#define csdb() asm volatile("hint #20" : : : "memory") + #define mb() dsb(sy) #define rmb() dsb(ld) #define wmb() dsb(st) -- GitLab From d89be0087b372c3a527bcd05ebed0d354d2b7fe1 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:10:58 +0100 Subject: [PATCH 1337/1834] arm64: Implement array_index_mask_nospec() From: Robin Murphy commit 022620eed3d0bc4bf2027326f599f5ad71c2ea3f upstream. Provide an optimised, assembly implementation of array_index_mask_nospec() for arm64 so that the compiler is not in a position to transform the code in ways which affect its ability to inhibit speculation (e.g. by introducing conditional branches). This is similar to the sequence used by x86, modulo architectural differences in the carry/borrow flags. Reviewed-by: Mark Rutland Signed-off-by: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/barrier.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index c68fdc5707ed..0b0755c961ac 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -40,6 +40,27 @@ #define dma_rmb() dmb(oshld) #define dma_wmb() dmb(oshst) +/* + * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz + * and 0 otherwise. + */ +#define array_index_mask_nospec array_index_mask_nospec +static inline unsigned long array_index_mask_nospec(unsigned long idx, + unsigned long sz) +{ + unsigned long mask; + + asm volatile( + " cmp %1, %2\n" + " sbc %0, xzr, xzr\n" + : "=r" (mask) + : "r" (idx), "Ir" (sz) + : "cc"); + + csdb(); + return mask; +} + #define __smp_mb() dmb(ish) #define __smp_rmb() dmb(ishld) #define __smp_wmb() dmb(ishst) -- GitLab From 27eeceda11e50477b11a35573776c4622aff5c29 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:10:59 +0100 Subject: [PATCH 1338/1834] arm64: move TASK_* definitions to From: Yury Norov commit eef94a3d09aab437c8c254de942d8b1aa76455e2 upstream. ILP32 series [1] introduces the dependency on for TASK_SIZE macro. Which in turn requires , and include , giving a circular dependency, because TASK_SIZE is currently located in . In other architectures, TASK_SIZE is defined in , and moving TASK_SIZE there fixes the problem. Discussion: https://patchwork.kernel.org/patch/9929107/ [1] https://github.com/norov/linux/tree/ilp32-next CC: Will Deacon CC: Laura Abbott Cc: Ard Biesheuvel Cc: Catalin Marinas Cc: James Morse Suggested-by: Mark Rutland Signed-off-by: Yury Norov Signed-off-by: Will Deacon [v4.9: necessary for making USER_DS an inclusive limit] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/memory.h | 15 --------------- arch/arm64/include/asm/processor.h | 21 +++++++++++++++++++++ arch/arm64/kernel/entry.S | 1 + 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index 5e3faba689e0..ba917be5565a 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -60,8 +60,6 @@ * KIMAGE_VADDR - the virtual address of the start of the kernel image * VA_BITS - the maximum number of bits for virtual addresses. * VA_START - the first kernel virtual address. - * TASK_SIZE - the maximum size of a user space task. - * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. */ #define VA_BITS (CONFIG_ARM64_VA_BITS) #define VA_START (UL(0xffffffffffffffff) - \ @@ -76,19 +74,6 @@ #define PCI_IO_END (VMEMMAP_START - SZ_2M) #define PCI_IO_START (PCI_IO_END - PCI_IO_SIZE) #define FIXADDR_TOP (PCI_IO_START - SZ_2M) -#define TASK_SIZE_64 (UL(1) << VA_BITS) - -#ifdef CONFIG_COMPAT -#define TASK_SIZE_32 UL(0x100000000) -#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ - TASK_SIZE_32 : TASK_SIZE_64) -#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \ - TASK_SIZE_32 : TASK_SIZE_64) -#else -#define TASK_SIZE TASK_SIZE_64 -#endif /* CONFIG_COMPAT */ - -#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4)) #define KERNEL_START _text #define KERNEL_END _end diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 60e34824e18c..4258f4d594b5 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -19,6 +19,10 @@ #ifndef __ASM_PROCESSOR_H #define __ASM_PROCESSOR_H +#define TASK_SIZE_64 (UL(1) << VA_BITS) + +#ifndef __ASSEMBLY__ + /* * Default implementation of macro that returns current * instruction pointer ("program counter"). @@ -37,6 +41,22 @@ #include #include +/* + * TASK_SIZE - the maximum size of a user space task. + * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. + */ +#ifdef CONFIG_COMPAT +#define TASK_SIZE_32 UL(0x100000000) +#define TASK_SIZE (test_thread_flag(TIF_32BIT) ? \ + TASK_SIZE_32 : TASK_SIZE_64) +#define TASK_SIZE_OF(tsk) (test_tsk_thread_flag(tsk, TIF_32BIT) ? \ + TASK_SIZE_32 : TASK_SIZE_64) +#else +#define TASK_SIZE TASK_SIZE_64 +#endif /* CONFIG_COMPAT */ + +#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 4)) + #define STACK_TOP_MAX TASK_SIZE_64 #ifdef CONFIG_COMPAT #define AARCH32_VECTORS_BASE 0xffff0000 @@ -192,4 +212,5 @@ int cpu_enable_pan(void *__unused); int cpu_enable_uao(void *__unused); int cpu_enable_cache_maint_trap(void *__unused); +#endif /* __ASSEMBLY__ */ #endif /* __ASM_PROCESSOR_H */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 8d1600b18562..e10e9f2e48ad 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include -- GitLab From c910086de5c484cc435c35017b3d222be652872c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:00 +0100 Subject: [PATCH 1339/1834] arm64: Make USER_DS an inclusive limit From: Robin Murphy commit 51369e398d0d33e8f524314e672b07e8cf870e79 upstream. Currently, USER_DS represents an exclusive limit while KERNEL_DS is inclusive. In order to do some clever trickery for speculation-safe masking, we need them both to behave equivalently - there aren't enough bits to make KERNEL_DS exclusive, so we have precisely one option. This also happens to correct a longstanding false negative for a range ending on the very top byte of kernel memory. Mark Rutland points out that we've actually got the semantics of addresses vs. segments muddled up in most of the places we need to amend, so shuffle the {USER,KERNEL}_DS definitions around such that we can correct those properly instead of just pasting "-1"s everywhere. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas [v4.9: avoid dependence on TTBR0 SW PAN and THREAD_INFO_IN_TASK_STRUCT] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/processor.h | 3 ++ arch/arm64/include/asm/uaccess.h | 46 ++++++++++++++++++------------ arch/arm64/kernel/entry.S | 4 +-- arch/arm64/mm/fault.c | 2 +- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 4258f4d594b5..5917147af0c4 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -21,6 +21,9 @@ #define TASK_SIZE_64 (UL(1) << VA_BITS) +#define KERNEL_DS UL(-1) +#define USER_DS (TASK_SIZE_64 - 1) + #ifndef __ASSEMBLY__ /* diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 811cf16a65f9..0f05ba51531c 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -59,10 +60,7 @@ struct exception_table_entry extern int fixup_exception(struct pt_regs *regs); -#define KERNEL_DS (-1UL) #define get_ds() (KERNEL_DS) - -#define USER_DS TASK_SIZE_64 #define get_fs() (current_thread_info()->addr_limit) static inline void set_fs(mm_segment_t fs) @@ -87,22 +85,32 @@ static inline void set_fs(mm_segment_t fs) * Returns 1 if the range is valid, 0 otherwise. * * This is equivalent to the following test: - * (u65)addr + (u65)size <= current->addr_limit - * - * This needs 65-bit arithmetic. + * (u65)addr + (u65)size <= (u65)current->addr_limit + 1 */ -#define __range_ok(addr, size) \ -({ \ - unsigned long __addr = (unsigned long __force)(addr); \ - unsigned long flag, roksum; \ - __chk_user_ptr(addr); \ - asm("adds %1, %1, %3; ccmp %1, %4, #2, cc; cset %0, ls" \ - : "=&r" (flag), "=&r" (roksum) \ - : "1" (__addr), "Ir" (size), \ - "r" (current_thread_info()->addr_limit) \ - : "cc"); \ - flag; \ -}) +static inline unsigned long __range_ok(unsigned long addr, unsigned long size) +{ + unsigned long limit = current_thread_info()->addr_limit; + + __chk_user_ptr(addr); + asm volatile( + // A + B <= C + 1 for all A,B,C, in four easy steps: + // 1: X = A + B; X' = X % 2^64 + " adds %0, %0, %2\n" + // 2: Set C = 0 if X > 2^64, to guarantee X' > C in step 4 + " csel %1, xzr, %1, hi\n" + // 3: Set X' = ~0 if X >= 2^64. For X == 2^64, this decrements X' + // to compensate for the carry flag being set in step 4. For + // X > 2^64, X' merely has to remain nonzero, which it does. + " csinv %0, %0, xzr, cc\n" + // 4: For X < 2^64, this gives us X' - C - 1 <= 0, where the -1 + // comes from the carry in being clear. Otherwise, we are + // testing X' - C == 0, subject to the previous adjustments. + " sbcs xzr, %0, %1\n" + " cset %0, ls\n" + : "+r" (addr), "+r" (limit) : "Ir" (size) : "cc"); + + return addr; +} /* * When dealing with data aborts, watchpoints, or instruction traps we may end @@ -111,7 +119,7 @@ static inline void set_fs(mm_segment_t fs) */ #define untagged_addr(addr) sign_extend64(addr, 55) -#define access_ok(type, addr, size) __range_ok(addr, size) +#define access_ok(type, addr, size) __range_ok((unsigned long)(addr), size) #define user_addr_max get_fs #define _ASM_EXTABLE(from, to) \ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index e10e9f2e48ad..3f1cd7a795bb 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -126,10 +126,10 @@ alternative_else_nop_endif .else add x21, sp, #S_FRAME_SIZE get_thread_info tsk - /* Save the task's original addr_limit and set USER_DS (TASK_SIZE_64) */ + /* Save the task's original addr_limit and set USER_DS */ ldr x20, [tsk, #TI_ADDR_LIMIT] str x20, [sp, #S_ORIG_ADDR_LIMIT] - mov x20, #TASK_SIZE_64 + mov x20, #USER_DS str x20, [tsk, #TI_ADDR_LIMIT] /* No need to reset PSTATE.UAO, hardware's already set it to 0 for us */ .endif /* \el == 0 */ diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 403fe9e57135..4df70c9fd762 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -332,7 +332,7 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, mm_flags |= FAULT_FLAG_WRITE; } - if (is_permission_fault(esr) && (addr < USER_DS)) { + if (is_permission_fault(esr) && (addr < TASK_SIZE)) { /* regs->orig_addr_limit may be 0 if we entered from EL0 */ if (regs->orig_addr_limit == KERNEL_DS) die("Accessing user space memory with fs=KERNEL_DS", regs, esr); -- GitLab From 891bea9528a6e48312ac16111a134442ee963726 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:01 +0100 Subject: [PATCH 1340/1834] arm64: Use pointer masking to limit uaccess speculation From: Robin Murphy commit 4d8efc2d5ee4c9ccfeb29ee8afd47a8660d0c0ce upstream. Similarly to x86, mitigate speculation past an access_ok() check by masking the pointer against the address limit before use. Even if we don't expect speculative writes per se, it is plausible that a CPU may still speculate at least as far as fetching a cache line for writing, hence we also harden put_user() and clear_user() for peace of mind. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/uaccess.h | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 0f05ba51531c..a9db051b967f 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -128,6 +128,26 @@ static inline unsigned long __range_ok(unsigned long addr, unsigned long size) " .long (" #from " - .), (" #to " - .)\n" \ " .popsection\n" +/* + * Sanitise a uaccess pointer such that it becomes NULL if above the + * current addr_limit. + */ +#define uaccess_mask_ptr(ptr) (__typeof__(ptr))__uaccess_mask_ptr(ptr) +static inline void __user *__uaccess_mask_ptr(const void __user *ptr) +{ + void __user *safe_ptr; + + asm volatile( + " bics xzr, %1, %2\n" + " csel %0, %1, xzr, eq\n" + : "=&r" (safe_ptr) + : "r" (ptr), "r" (current_thread_info()->addr_limit) + : "cc"); + + csdb(); + return safe_ptr; +} + /* * The "__xxx" versions of the user access functions do not verify the address * space - it must have been done previously with a separate "access_ok()" @@ -202,7 +222,7 @@ do { \ __typeof__(*(ptr)) __user *__p = (ptr); \ might_fault(); \ access_ok(VERIFY_READ, __p, sizeof(*__p)) ? \ - __get_user((x), __p) : \ + __p = uaccess_mask_ptr(__p), __get_user((x), __p) : \ ((x) = 0, -EFAULT); \ }) @@ -270,7 +290,7 @@ do { \ __typeof__(*(ptr)) __user *__p = (ptr); \ might_fault(); \ access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ? \ - __put_user((x), __p) : \ + __p = uaccess_mask_ptr(__p), __put_user((x), __p) : \ -EFAULT; \ }) @@ -331,7 +351,7 @@ static inline unsigned long __must_check copy_in_user(void __user *to, const voi static inline unsigned long __must_check clear_user(void __user *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) - n = __clear_user(to, n); + n = __clear_user(__uaccess_mask_ptr(to), n); return n; } -- GitLab From f3ed64a6273ebdc1ddf22262c4e5f724688b7393 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:02 +0100 Subject: [PATCH 1341/1834] arm64: entry: Ensure branch through syscall table is bounded under speculation From: Will Deacon commit 6314d90e64936c584f300a52ef173603fb2461b5 upstream. In a similar manner to array_index_mask_nospec, this patch introduces an assembly macro (mask_nospec64) which can be used to bound a value under speculation. This macro is then used to ensure that the indirect branch through the syscall table is bounded under speculation, with out-of-range addresses speculating as calls to sys_io_setup (0). Reviewed-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas [v4.9: use existing scno & sc_nr definitions] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/assembler.h | 11 +++++++++++ arch/arm64/kernel/entry.S | 1 + 2 files changed, 12 insertions(+) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index b223b1b4d5cd..540c24f74837 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -93,6 +93,17 @@ hint #20 .endm +/* + * Sanitise a 64-bit bounded index wrt speculation, returning zero if out + * of bounds. + */ + .macro mask_nospec64, idx, limit, tmp + sub \tmp, \idx, \limit + bic \tmp, \tmp, \idx + and \idx, \idx, \tmp, asr #63 + csdb + .endm + /* * NOP sequence */ diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 3f1cd7a795bb..c154b1608405 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -795,6 +795,7 @@ el0_svc_naked: // compat entry point b.ne __sys_trace cmp scno, sc_nr // check upper syscall limit b.hs ni_sys + mask_nospec64 scno, sc_nr, x19 // enforce bounds for syscall number ldr x16, [stbl, scno, lsl #3] // address in the syscall table blr x16 // call sys_* routine b ret_fast_syscall -- GitLab From 346edd61ce1ce5f2a2a3e81518d86b2b239ed4d4 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:03 +0100 Subject: [PATCH 1342/1834] arm64: uaccess: Prevent speculative use of the current addr_limit From: Will Deacon commit c2f0ad4fc089cff81cef6a13d04b399980ecbfcc upstream. A mispredicted conditional call to set_fs could result in the wrong addr_limit being forwarded under speculation to a subsequent access_ok check, potentially forming part of a spectre-v1 attack using uaccess routines. This patch prevents this forwarding from taking place, but putting heavy barriers in set_fs after writing the addr_limit. Reviewed-by: Mark Rutland Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/uaccess.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index a9db051b967f..900397e73fa6 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -67,6 +67,13 @@ static inline void set_fs(mm_segment_t fs) { current_thread_info()->addr_limit = fs; + /* + * Prevent a mispredicted conditional call to set_fs from forwarding + * the wrong address limit to access_ok under speculation. + */ + dsb(nsh); + isb(); + /* * Enable/disable UAO so that copy_to_user() etc can access * kernel memory with the unprivileged instructions. -- GitLab From 4c03928fd68a710ec55b7a07a4e65d2f438a1256 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:04 +0100 Subject: [PATCH 1343/1834] arm64: uaccess: Don't bother eliding access_ok checks in __{get, put}_user From: Will Deacon commit 84624087dd7e3b482b7b11c170ebc1f329b3a218 upstream. access_ok isn't an expensive operation once the addr_limit for the current thread has been loaded into the cache. Given that the initial access_ok check preceding a sequence of __{get,put}_user operations will take the brunt of the miss, we can make the __* variants identical to the full-fat versions, which brings with it the benefits of address masking. The likely cost in these sequences will be from toggling PAN/UAO, which we can address later by implementing the *_unsafe versions. Reviewed-by: Robin Murphy Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/uaccess.h | 62 ++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 900397e73fa6..0d4330c7d58d 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -209,30 +209,35 @@ do { \ CONFIG_ARM64_PAN)); \ } while (0) -#define __get_user(x, ptr) \ +#define __get_user_check(x, ptr, err) \ ({ \ - int __gu_err = 0; \ - __get_user_err((x), (ptr), __gu_err); \ - __gu_err; \ + __typeof__(*(ptr)) __user *__p = (ptr); \ + might_fault(); \ + if (access_ok(VERIFY_READ, __p, sizeof(*__p))) { \ + __p = uaccess_mask_ptr(__p); \ + __get_user_err((x), __p, (err)); \ + } else { \ + (x) = 0; (err) = -EFAULT; \ + } \ }) #define __get_user_error(x, ptr, err) \ ({ \ - __get_user_err((x), (ptr), (err)); \ + __get_user_check((x), (ptr), (err)); \ (void)0; \ }) -#define __get_user_unaligned __get_user - -#define get_user(x, ptr) \ +#define __get_user(x, ptr) \ ({ \ - __typeof__(*(ptr)) __user *__p = (ptr); \ - might_fault(); \ - access_ok(VERIFY_READ, __p, sizeof(*__p)) ? \ - __p = uaccess_mask_ptr(__p), __get_user((x), __p) : \ - ((x) = 0, -EFAULT); \ + int __gu_err = 0; \ + __get_user_check((x), (ptr), __gu_err); \ + __gu_err; \ }) +#define __get_user_unaligned __get_user + +#define get_user __get_user + #define __put_user_asm(instr, alt_instr, reg, x, addr, err, feature) \ asm volatile( \ "1:"ALTERNATIVE(instr " " reg "1, [%2]\n", \ @@ -277,30 +282,35 @@ do { \ CONFIG_ARM64_PAN)); \ } while (0) -#define __put_user(x, ptr) \ +#define __put_user_check(x, ptr, err) \ ({ \ - int __pu_err = 0; \ - __put_user_err((x), (ptr), __pu_err); \ - __pu_err; \ + __typeof__(*(ptr)) __user *__p = (ptr); \ + might_fault(); \ + if (access_ok(VERIFY_WRITE, __p, sizeof(*__p))) { \ + __p = uaccess_mask_ptr(__p); \ + __put_user_err((x), __p, (err)); \ + } else { \ + (err) = -EFAULT; \ + } \ }) #define __put_user_error(x, ptr, err) \ ({ \ - __put_user_err((x), (ptr), (err)); \ + __put_user_check((x), (ptr), (err)); \ (void)0; \ }) -#define __put_user_unaligned __put_user - -#define put_user(x, ptr) \ +#define __put_user(x, ptr) \ ({ \ - __typeof__(*(ptr)) __user *__p = (ptr); \ - might_fault(); \ - access_ok(VERIFY_WRITE, __p, sizeof(*__p)) ? \ - __p = uaccess_mask_ptr(__p), __put_user((x), __p) : \ - -EFAULT; \ + int __pu_err = 0; \ + __put_user_check((x), (ptr), __pu_err); \ + __pu_err; \ }) +#define __put_user_unaligned __put_user + +#define put_user __put_user + extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n); extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n); extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n); -- GitLab From 4504c5ccef54070bdc09f26a7fcb41a3f053ded0 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:05 +0100 Subject: [PATCH 1344/1834] arm64: uaccess: Mask __user pointers for __arch_{clear, copy_*}_user From: Will Deacon commit f71c2ffcb20dd8626880747557014bb9a61eb90e upstream. Like we've done for get_user and put_user, ensure that user pointers are masked before invoking the underlying __arch_{clear,copy_*}_user operations. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas [v4.9: fixup for v4.9-style uaccess primitives] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/uaccess.h | 18 ++++++++++-------- arch/arm64/kernel/arm64ksyms.c | 4 ++-- arch/arm64/lib/clear_user.S | 6 +++--- arch/arm64/lib/copy_in_user.S | 4 ++-- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 0d4330c7d58d..1d047d6c421b 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -313,21 +313,20 @@ do { \ extern unsigned long __must_check __arch_copy_from_user(void *to, const void __user *from, unsigned long n); extern unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n); -extern unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n); -extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); +extern unsigned long __must_check __arch_copy_in_user(void __user *to, const void __user *from, unsigned long n); static inline unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n) { kasan_check_write(to, n); check_object_size(to, n, false); - return __arch_copy_from_user(to, from, n); + return __arch_copy_from_user(to, __uaccess_mask_ptr(from), n); } static inline unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n) { kasan_check_read(from, n); check_object_size(from, n, true); - return __arch_copy_to_user(to, from, n); + return __arch_copy_to_user(__uaccess_mask_ptr(to), from, n); } static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) @@ -355,22 +354,25 @@ static inline unsigned long __must_check copy_to_user(void __user *to, const voi return n; } -static inline unsigned long __must_check copy_in_user(void __user *to, const void __user *from, unsigned long n) +static inline unsigned long __must_check __copy_in_user(void __user *to, const void __user *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n) && access_ok(VERIFY_WRITE, to, n)) - n = __copy_in_user(to, from, n); + n = __arch_copy_in_user(__uaccess_mask_ptr(to), __uaccess_mask_ptr(from), n); return n; } +#define copy_in_user __copy_in_user #define __copy_to_user_inatomic __copy_to_user #define __copy_from_user_inatomic __copy_from_user -static inline unsigned long __must_check clear_user(void __user *to, unsigned long n) +extern unsigned long __must_check __arch_clear_user(void __user *to, unsigned long n); +static inline unsigned long __must_check __clear_user(void __user *to, unsigned long n) { if (access_ok(VERIFY_WRITE, to, n)) - n = __clear_user(__uaccess_mask_ptr(to), n); + n = __arch_clear_user(__uaccess_mask_ptr(to), n); return n; } +#define clear_user __clear_user extern long strncpy_from_user(char *dest, const char __user *src, long count); diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c index e9c4dc9e0ada..66be504edb6c 100644 --- a/arch/arm64/kernel/arm64ksyms.c +++ b/arch/arm64/kernel/arm64ksyms.c @@ -37,8 +37,8 @@ EXPORT_SYMBOL(clear_page); /* user mem (segment) */ EXPORT_SYMBOL(__arch_copy_from_user); EXPORT_SYMBOL(__arch_copy_to_user); -EXPORT_SYMBOL(__clear_user); -EXPORT_SYMBOL(__copy_in_user); +EXPORT_SYMBOL(__arch_clear_user); +EXPORT_SYMBOL(__arch_copy_in_user); /* physical memory */ EXPORT_SYMBOL(memstart_addr); diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index 5d1cad3ce6d6..efbf610eaf4e 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -24,7 +24,7 @@ .text -/* Prototype: int __clear_user(void *addr, size_t sz) +/* Prototype: int __arch_clear_user(void *addr, size_t sz) * Purpose : clear some user memory * Params : addr - user memory address to clear * : sz - number of bytes to clear @@ -32,7 +32,7 @@ * * Alignment fixed up by hardware. */ -ENTRY(__clear_user) +ENTRY(__arch_clear_user) ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \ CONFIG_ARM64_PAN) mov x2, x1 // save the size for fixup return @@ -57,7 +57,7 @@ uao_user_alternative 9f, strb, sttrb, wzr, x0, 0 ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \ CONFIG_ARM64_PAN) ret -ENDPROC(__clear_user) +ENDPROC(__arch_clear_user) .section .fixup,"ax" .align 2 diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index f7292dd08c84..841bf8f7fab7 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -67,7 +67,7 @@ .endm end .req x5 -ENTRY(__copy_in_user) +ENTRY(__arch_copy_in_user) ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_ALT_PAN_NOT_UAO, \ CONFIG_ARM64_PAN) add end, x0, x2 @@ -76,7 +76,7 @@ ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_ALT_PAN_NOT_UAO, \ CONFIG_ARM64_PAN) mov x0, #0 ret -ENDPROC(__copy_in_user) +ENDPROC(__arch_copy_in_user) .section .fixup,"ax" .align 2 -- GitLab From 93f339ef4175afdb101b5972b09e7a166bd3265b Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:07 +0100 Subject: [PATCH 1345/1834] arm64: cpufeature: __this_cpu_has_cap() shouldn't stop early From: James Morse commit edf298cfce47ab7279d03b5203ae2ef3a58e49db upstream. this_cpu_has_cap() tests caps->desc not caps->matches, so it stops walking the list when it finds a 'silent' feature, instead of walking to the end of the list. Prior to v4.6's 644c2ae198412 ("arm64: cpufeature: Test 'matches' pointer to find the end of the list") we always tested desc to find the end of a capability list. This was changed for dubious things like PAN_NOT_UAO. v4.7's e3661b128e53e ("arm64: Allow a capability to be checked on single CPU") added this_cpu_has_cap() using the old desc style test. CC: Suzuki K Poulose Reviewed-by: Suzuki K Poulose Acked-by: Marc Zyngier Signed-off-by: James Morse Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 5056fc597ae9..cf000fd694fa 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1024,9 +1024,8 @@ static bool __this_cpu_has_cap(const struct arm64_cpu_capabilities *cap_array, if (WARN_ON(preemptible())) return false; - for (caps = cap_array; caps->desc; caps++) + for (caps = cap_array; caps->matches; caps++) if (caps->capability == cap && - caps->matches && caps->matches(caps, SCOPE_LOCAL_CPU)) return true; return false; -- GitLab From 3c31fa5a06b41ba6a30a4a52b93f49a7e9f2cc00 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:08 +0100 Subject: [PATCH 1346/1834] arm64: Run enable method for errata work arounds on late CPUs From: Suzuki K Poulose commit 55b35d070c2534dfb714b883f3c3ae05d02032da upstream. When a CPU is brought up after we have finalised the system wide capabilities (i.e, features and errata), we make sure the new CPU doesn't need a new errata work around which has not been detected already. However we don't run enable() method on the new CPU for the errata work arounds already detected. This could cause the new CPU running without potential work arounds. It is upto the "enable()" method to decide if this CPU should do something about the errata. Fixes: commit 6a6efbb45b7d95c84 ("arm64: Verify CPU errata work arounds on hotplugged CPU") Cc: Will Deacon Cc: Mark Rutland Cc: Andre Przywara Cc: Dave Martin Signed-off-by: Suzuki K Poulose Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpu_errata.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index b75e917aac46..b866df79bb83 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -143,15 +143,18 @@ void verify_local_cpu_errata_workarounds(void) { const struct arm64_cpu_capabilities *caps = arm64_errata; - for (; caps->matches; caps++) - if (!cpus_have_cap(caps->capability) && - caps->matches(caps, SCOPE_LOCAL_CPU)) { + for (; caps->matches; caps++) { + if (cpus_have_cap(caps->capability)) { + if (caps->enable) + caps->enable((void *)caps); + } else if (caps->matches(caps, SCOPE_LOCAL_CPU)) { pr_crit("CPU%d: Requires work around for %s, not detected" " at boot time\n", smp_processor_id(), caps->desc ? : "an erratum"); cpu_die_early(); } + } } void update_cpu_errata_workarounds(void) -- GitLab From 92e7a8317d9cbad7eb7952b2de47c10d9a8da81d Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:09 +0100 Subject: [PATCH 1347/1834] arm64: cpufeature: Pass capability structure to ->enable callback From: Will Deacon commit 0a0d111d40fd1dc588cc590fab6b55d86ddc71d3 upstream. In order to invoke the CPU capability ->matches callback from the ->enable callback for applying local-CPU workarounds, we need a handle on the capability structure. This patch passes a pointer to the capability structure to the ->enable callback. Reviewed-by: Suzuki K Poulose Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpufeature.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index cf000fd694fa..692f107bb46e 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1058,7 +1058,7 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) * uses an IPI, giving us a PSTATE that disappears when * we return. */ - stop_machine(caps->enable, NULL, cpu_online_mask); + stop_machine(caps->enable, (void *)caps, cpu_online_mask); } /* @@ -1115,7 +1115,7 @@ verify_local_cpu_features(const struct arm64_cpu_capabilities *caps_list) cpu_die_early(); } if (caps->enable) - caps->enable(NULL); + caps->enable((void *)caps); } } -- GitLab From 6289541c4804c7ed81d7f8a97de7be9a88297752 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:10 +0100 Subject: [PATCH 1348/1834] drivers/firmware: Expose psci_get_version through psci_ops structure From: Will Deacon commit d68e3ba5303f7e1099f51fdcd155f5263da8569b upstream. Entry into recent versions of ARM Trusted Firmware will invalidate the CPU branch predictor state in order to protect against aliasing attacks. This patch exposes the PSCI "VERSION" function via psci_ops, so that it can be invoked outside of the PSCI driver where necessary. Acked-by: Lorenzo Pieralisi Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/psci.c | 2 ++ include/linux/psci.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 8263429e21b8..9a3ce76304b6 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -496,6 +496,8 @@ static void __init psci_init_migrate(void) static void __init psci_0_2_set_functions(void) { pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_ops.get_version = psci_get_version; + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_FN_NATIVE(0_2, CPU_SUSPEND); psci_ops.cpu_suspend = psci_cpu_suspend; diff --git a/include/linux/psci.h b/include/linux/psci.h index bdea1cb5e1db..6306ab10af18 100644 --- a/include/linux/psci.h +++ b/include/linux/psci.h @@ -26,6 +26,7 @@ int psci_cpu_init_idle(unsigned int cpu); int psci_cpu_suspend_enter(unsigned long index); struct psci_operations { + u32 (*get_version)(void); int (*cpu_suspend)(u32 state, unsigned long entry_point); int (*cpu_off)(u32 state); int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); -- GitLab From 965924ee9a73ee7509f0f3a261978931e33ef375 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:11 +0100 Subject: [PATCH 1349/1834] arm64: Factor out TTBR0_EL1 post-update workaround into a specific asm macro From: Catalin Marinas commit f33bcf03e6079668da6bf4eec4a7dcf9289131d0 upstream. This patch takes the errata workaround code out of cpu_do_switch_mm into a dedicated post_ttbr0_update_workaround macro which will be reused in a subsequent patch. Cc: Will Deacon Cc: James Morse Cc: Kees Cook Reviewed-by: Mark Rutland Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/assembler.h | 14 ++++++++++++++ arch/arm64/mm/proc.S | 6 +----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 540c24f74837..c9bd4ad4db82 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -434,4 +434,18 @@ alternative_endif .macro pte_to_phys, phys, pte and \phys, \pte, #(((1 << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT) .endm + +/* + * Errata workaround post TTBR0_EL1 update. + */ + .macro post_ttbr0_update_workaround +#ifdef CONFIG_CAVIUM_ERRATUM_27456 +alternative_if ARM64_WORKAROUND_CAVIUM_27456 + ic iallu + dsb nsh + isb +alternative_else_nop_endif +#endif + .endm + #endif /* __ASM_ASSEMBLER_H */ diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index c07d9cc057e6..135a698ce946 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -139,11 +139,7 @@ ENTRY(cpu_do_switch_mm) isb msr ttbr0_el1, x0 // now update TTBR0 isb -alternative_if ARM64_WORKAROUND_CAVIUM_27456 - ic iallu - dsb nsh - isb -alternative_else_nop_endif + post_ttbr0_update_workaround ret ENDPROC(cpu_do_switch_mm) -- GitLab From 20bcfe09d404df14c2a3b0e3fa3ce56326bd8ced Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:12 +0100 Subject: [PATCH 1350/1834] arm64: Move post_ttbr_update_workaround to C code From: Marc Zyngier commit 95e3de3590e3f2358bb13f013911bc1bfa5d3f53 upstream. We will soon need to invoke a CPU-specific function pointer after changing page tables, so move post_ttbr_update_workaround out into C code to make this possible. Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/assembler.h | 13 ------------- arch/arm64/mm/context.c | 9 +++++++++ arch/arm64/mm/proc.S | 3 +-- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index c9bd4ad4db82..e60375ce0dd2 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -435,17 +435,4 @@ alternative_endif and \phys, \pte, #(((1 << (48 - PAGE_SHIFT)) - 1) << PAGE_SHIFT) .endm -/* - * Errata workaround post TTBR0_EL1 update. - */ - .macro post_ttbr0_update_workaround -#ifdef CONFIG_CAVIUM_ERRATUM_27456 -alternative_if ARM64_WORKAROUND_CAVIUM_27456 - ic iallu - dsb nsh - isb -alternative_else_nop_endif -#endif - .endm - #endif /* __ASM_ASSEMBLER_H */ diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index f00f5eeb556f..b9b087564bac 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -233,6 +233,15 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) cpu_switch_mm(mm->pgd, mm); } +/* Errata workaround post TTBRx_EL1 update. */ +asmlinkage void post_ttbr_update_workaround(void) +{ + asm(ALTERNATIVE("nop; nop; nop", + "ic iallu; dsb nsh; isb", + ARM64_WORKAROUND_CAVIUM_27456, + CONFIG_CAVIUM_ERRATUM_27456)); +} + static int asids_init(void) { asid_bits = get_cpu_asid_bits(); diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 135a698ce946..619da1cbd32b 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -139,8 +139,7 @@ ENTRY(cpu_do_switch_mm) isb msr ttbr0_el1, x0 // now update TTBR0 isb - post_ttbr0_update_workaround - ret + b post_ttbr_update_workaround // Back to C code... ENDPROC(cpu_do_switch_mm) .pushsection ".idmap.text", "awx" -- GitLab From 4732001f7721d89d3dc921d5f4c8208405cb88c1 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:13 +0100 Subject: [PATCH 1351/1834] arm64: Add skeleton to harden the branch predictor against aliasing attacks From: Will Deacon commit 0f15adbb2861ce6f75ccfc5a92b19eae0ef327d0 upstream. Aliasing attacks against CPU branch predictors can allow an attacker to redirect speculative control flow on some CPUs and potentially divulge information from one context to another. This patch adds initial skeleton code behind a new Kconfig option to enable implementation-specific mitigations against these attacks for CPUs that are affected. Co-developed-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas [v4.9: copy bp hardening cb via text mapping] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/Kconfig | 17 ++++++++ arch/arm64/include/asm/cpucaps.h | 3 +- arch/arm64/include/asm/mmu.h | 39 +++++++++++++++++ arch/arm64/include/asm/sysreg.h | 2 + arch/arm64/kernel/Makefile | 4 ++ arch/arm64/kernel/bpi.S | 55 ++++++++++++++++++++++++ arch/arm64/kernel/cpu_errata.c | 74 ++++++++++++++++++++++++++++++++ arch/arm64/kernel/cpufeature.c | 3 +- arch/arm64/kernel/entry.S | 8 ++-- arch/arm64/mm/context.c | 2 + arch/arm64/mm/fault.c | 17 ++++++++ 11 files changed, 219 insertions(+), 5 deletions(-) create mode 100644 arch/arm64/kernel/bpi.S diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index c8471cf46cbb..90e58bbbd858 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -745,6 +745,23 @@ config UNMAP_KERNEL_AT_EL0 If unsure, say Y. +config HARDEN_BRANCH_PREDICTOR + bool "Harden the branch predictor against aliasing attacks" if EXPERT + default y + help + Speculation attacks against some high-performance processors rely on + being able to manipulate the branch predictor for a victim context by + executing aliasing branches in the attacker context. Such attacks + can be partially mitigated against by clearing internal branch + predictor state and limiting the prediction logic in some situations. + + This config option will take CPU-specific actions to harden the + branch predictor against aliasing attacks and may rely on specific + instruction sequences or control bits being set by the system + firmware. + + If unsure, say Y. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index 7ddf233f05bd..ce67bf6a0886 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -35,7 +35,8 @@ #define ARM64_HYP_OFFSET_LOW 14 #define ARM64_MISMATCHED_CACHE_LINE_SIZE 15 #define ARM64_UNMAP_KERNEL_AT_EL0 16 +#define ARM64_HARDEN_BRANCH_PREDICTOR 17 -#define ARM64_NCAPS 17 +#define ARM64_NCAPS 18 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index a813edf28737..d51158a61892 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -20,6 +20,8 @@ #ifndef __ASSEMBLY__ +#include + typedef struct { atomic64_t id; void *vdso; @@ -38,6 +40,43 @@ static inline bool arm64_kernel_unmapped_at_el0(void) cpus_have_cap(ARM64_UNMAP_KERNEL_AT_EL0); } +typedef void (*bp_hardening_cb_t)(void); + +struct bp_hardening_data { + int hyp_vectors_slot; + bp_hardening_cb_t fn; +}; + +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +extern char __bp_harden_hyp_vecs_start[], __bp_harden_hyp_vecs_end[]; + +DECLARE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); + +static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) +{ + return this_cpu_ptr(&bp_hardening_data); +} + +static inline void arm64_apply_bp_hardening(void) +{ + struct bp_hardening_data *d; + + if (!cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR)) + return; + + d = arm64_get_bp_hardening_data(); + if (d->fn) + d->fn(); +} +#else +static inline struct bp_hardening_data *arm64_get_bp_hardening_data(void) +{ + return NULL; +} + +static inline void arm64_apply_bp_hardening(void) { } +#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ + extern void paging_init(void); extern void bootmem_init(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 7cb7f7cdcfbc..88bbe364b6ae 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -118,6 +118,8 @@ /* id_aa64pfr0 */ #define ID_AA64PFR0_CSV3_SHIFT 60 +#define ID_AA64PFR0_CSV2_SHIFT 56 +#define ID_AA64PFR0_SVE_SHIFT 32 #define ID_AA64PFR0_GIC_SHIFT 24 #define ID_AA64PFR0_ASIMD_SHIFT 20 #define ID_AA64PFR0_FP_SHIFT 16 diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 7d66bbaafc0c..74b8fd860714 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -51,6 +51,10 @@ arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \ cpu-reset.o +ifeq ($(CONFIG_KVM),y) +arm64-obj-$(CONFIG_HARDEN_BRANCH_PREDICTOR) += bpi.o +endif + obj-y += $(arm64-obj-y) vdso/ probes/ obj-m += $(arm64-obj-m) head-y := head.o diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S new file mode 100644 index 000000000000..06a931eb2673 --- /dev/null +++ b/arch/arm64/kernel/bpi.S @@ -0,0 +1,55 @@ +/* + * Contains CPU specific branch predictor invalidation sequences + * + * Copyright (C) 2018 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +.macro ventry target + .rept 31 + nop + .endr + b \target +.endm + +.macro vectors target + ventry \target + 0x000 + ventry \target + 0x080 + ventry \target + 0x100 + ventry \target + 0x180 + + ventry \target + 0x200 + ventry \target + 0x280 + ventry \target + 0x300 + ventry \target + 0x380 + + ventry \target + 0x400 + ventry \target + 0x480 + ventry \target + 0x500 + ventry \target + 0x580 + + ventry \target + 0x600 + ventry \target + 0x680 + ventry \target + 0x700 + ventry \target + 0x780 +.endm + + .align 11 +ENTRY(__bp_harden_hyp_vecs_start) + .rept 4 + vectors __kvm_hyp_vector + .endr +ENTRY(__bp_harden_hyp_vecs_end) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index b866df79bb83..3884c4398597 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -46,6 +46,80 @@ static int cpu_enable_trap_ctr_access(void *__unused) return 0; } +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +#include +#include + +DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); + +#ifdef CONFIG_KVM +static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + void *dst = __bp_harden_hyp_vecs_start + slot * SZ_2K; + int i; + + for (i = 0; i < SZ_2K; i += 0x80) + memcpy(dst + i, hyp_vecs_start, hyp_vecs_end - hyp_vecs_start); + + flush_icache_range((uintptr_t)dst, (uintptr_t)dst + SZ_2K); +} + +static void __install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + static int last_slot = -1; + static DEFINE_SPINLOCK(bp_lock); + int cpu, slot = -1; + + spin_lock(&bp_lock); + for_each_possible_cpu(cpu) { + if (per_cpu(bp_hardening_data.fn, cpu) == fn) { + slot = per_cpu(bp_hardening_data.hyp_vectors_slot, cpu); + break; + } + } + + if (slot == -1) { + last_slot++; + BUG_ON(((__bp_harden_hyp_vecs_end - __bp_harden_hyp_vecs_start) + / SZ_2K) <= last_slot); + slot = last_slot; + __copy_hyp_vect_bpi(slot, hyp_vecs_start, hyp_vecs_end); + } + + __this_cpu_write(bp_hardening_data.hyp_vectors_slot, slot); + __this_cpu_write(bp_hardening_data.fn, fn); + spin_unlock(&bp_lock); +} +#else +static void __install_bp_hardening_cb(bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + __this_cpu_write(bp_hardening_data.fn, fn); +} +#endif /* CONFIG_KVM */ + +static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, + bp_hardening_cb_t fn, + const char *hyp_vecs_start, + const char *hyp_vecs_end) +{ + u64 pfr0; + + if (!entry->matches(entry, SCOPE_LOCAL_CPU)) + return; + + pfr0 = read_cpuid(ID_AA64PFR0_EL1); + if (cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_CSV2_SHIFT)) + return; + + __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); +} +#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ + #define MIDR_RANGE(model, min, max) \ .def_scope = SCOPE_LOCAL_CPU, \ .matches = is_affected_midr_range, \ diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 692f107bb46e..a0ee01202503 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -94,7 +94,8 @@ static const struct arm64_ftr_bits ftr_id_aa64isar0[] = { static const struct arm64_ftr_bits ftr_id_aa64pfr0[] = { ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV3_SHIFT, 4, 0), - ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 28, 0), + ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64PFR0_CSV2_SHIFT, 4, 0), + ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 24, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 4, 0), ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64PFR0_GIC_SHIFT, 4, 0), S_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64PFR0_ASIMD_SHIFT, 4, ID_AA64PFR0_ASIMD_NI), diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index c154b1608405..fd6879d98bd7 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -589,13 +589,15 @@ el0_ia: * Instruction abort handling */ mrs x26, far_el1 - // enable interrupts before calling the main handler - enable_dbg_and_irq + msr daifclr, #(8 | 4 | 1) +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif ct_user_exit mov x0, x26 mov x1, x25 mov x2, sp - bl do_mem_abort + bl do_el0_ia_bp_hardening b ret_to_user el0_fpsimd_acc: /* diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index b9b087564bac..accf7ead3945 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -240,6 +240,8 @@ asmlinkage void post_ttbr_update_workaround(void) "ic iallu; dsb nsh; isb", ARM64_WORKAROUND_CAVIUM_27456, CONFIG_CAVIUM_ERRATUM_27456)); + + arm64_apply_bp_hardening(); } static int asids_init(void) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 4df70c9fd762..c95b194d1c6e 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -590,6 +590,23 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, arm64_notify_die("", regs, &info, esr); } +asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr, + unsigned int esr, + struct pt_regs *regs) +{ + /* + * We've taken an instruction abort from userspace and not yet + * re-enabled IRQs. If the address is a kernel address, apply + * BP hardening prior to enabling IRQs and pre-emption. + */ + if (addr > TASK_SIZE) + arm64_apply_bp_hardening(); + + local_irq_enable(); + do_mem_abort(addr, esr, regs); +} + + /* * Handle stack alignment exceptions. */ -- GitLab From bfacceccc8fd9fd30f70563569d7bd1d1453a841 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:14 +0100 Subject: [PATCH 1352/1834] arm64: Move BP hardening to check_and_switch_context From: Marc Zyngier commit a8e4c0a919ae310944ed2c9ace11cf3ccd8a609b upstream. We call arm64_apply_bp_hardening() from post_ttbr_update_workaround, which has the unexpected consequence of being triggered on every exception return to userspace when ARM64_SW_TTBR0_PAN is selected, even if no context switch actually occured. This is a bit suboptimal, and it would be more logical to only invalidate the branch predictor when we actually switch to a different mm. In order to solve this, move the call to arm64_apply_bp_hardening() into check_and_switch_context(), where we're guaranteed to pick a different mm context. Acked-by: Will Deacon Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/mm/context.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index accf7ead3945..62d976e843fc 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -230,6 +230,9 @@ void check_and_switch_context(struct mm_struct *mm, unsigned int cpu) raw_spin_unlock_irqrestore(&cpu_asid_lock, flags); switch_mm_fastpath: + + arm64_apply_bp_hardening(); + cpu_switch_mm(mm->pgd, mm); } @@ -240,8 +243,6 @@ asmlinkage void post_ttbr_update_workaround(void) "ic iallu; dsb nsh; isb", ARM64_WORKAROUND_CAVIUM_27456, CONFIG_CAVIUM_ERRATUM_27456)); - - arm64_apply_bp_hardening(); } static int asids_init(void) -- GitLab From 09ea80a05c6a08d0419fa3875a2612f4c462d9d5 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:15 +0100 Subject: [PATCH 1353/1834] mm: Introduce lm_alias From: Laura Abbott commit 568c5fe5a54f2654f5a4c599c45b8a62ed9a2013 upstream. Certain architectures may have the kernel image mapped separately to alias the linear map. Introduce a macro lm_alias to translate a kernel image symbol into its linear alias. This is used in part with work to add CONFIG_DEBUG_VIRTUAL support for arm64. Reviewed-by: Mark Rutland Tested-by: Mark Rutland Signed-off-by: Laura Abbott Signed-off-by: Will Deacon Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- include/linux/mm.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index 8e506783631b..4a07ff4f38e1 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -76,6 +76,10 @@ extern int mmap_rnd_compat_bits __read_mostly; #define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x))) #endif +#ifndef lm_alias +#define lm_alias(x) __va(__pa_symbol(x)) +#endif + /* * To prevent common memory management code establishing * a zero page mapping on a read fault. -- GitLab From 9327f0696367b7373c4af5fe4d1fed8b194f68b0 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:16 +0100 Subject: [PATCH 1354/1834] arm64: KVM: Use per-CPU vector when BP hardening is enabled From: Marc Zyngier commit 6840bdd73d07216ab4bc46f5a8768c37ea519038 upstream. Now that we have per-CPU vectors, let's plug then in the KVM/arm64 code. Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream, use cpus_have_cap()] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kvm_mmu.h | 10 +++++++++ arch/arm/kvm/arm.c | 9 +++++++- arch/arm64/include/asm/kvm_mmu.h | 38 ++++++++++++++++++++++++++++++++ arch/arm64/kvm/hyp/switch.c | 2 +- 4 files changed, 57 insertions(+), 2 deletions(-) diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h index a58bbaa3ec60..d10e36235438 100644 --- a/arch/arm/include/asm/kvm_mmu.h +++ b/arch/arm/include/asm/kvm_mmu.h @@ -223,6 +223,16 @@ static inline unsigned int kvm_get_vmid_bits(void) return 8; } +static inline void *kvm_get_hyp_vector(void) +{ + return kvm_ksym_ref(__kvm_hyp_vector); +} + +static inline int kvm_map_vectors(void) +{ + return 0; +} + #endif /* !__ASSEMBLY__ */ #endif /* __ARM_KVM_MMU_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index c38bfbeec306..5e666b624dc1 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -1088,7 +1088,7 @@ static void cpu_init_hyp_mode(void *dummy) pgd_ptr = kvm_mmu_get_httbr(); stack_page = __this_cpu_read(kvm_arm_hyp_stack_page); hyp_stack_ptr = stack_page + PAGE_SIZE; - vector_ptr = (unsigned long)kvm_ksym_ref(__kvm_hyp_vector); + vector_ptr = (unsigned long)kvm_get_hyp_vector(); __cpu_init_hyp_mode(pgd_ptr, hyp_stack_ptr, vector_ptr); __cpu_init_stage2(); @@ -1345,6 +1345,13 @@ static int init_hyp_mode(void) goto out_err; } + + err = kvm_map_vectors(); + if (err) { + kvm_err("Cannot map vectors\n"); + goto out_err; + } + /* * Map the Hyp stack pages */ diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h index 6d22017ebbad..80bf33715ecb 100644 --- a/arch/arm64/include/asm/kvm_mmu.h +++ b/arch/arm64/include/asm/kvm_mmu.h @@ -313,5 +313,43 @@ static inline unsigned int kvm_get_vmid_bits(void) return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8; } +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR +#include + +static inline void *kvm_get_hyp_vector(void) +{ + struct bp_hardening_data *data = arm64_get_bp_hardening_data(); + void *vect = kvm_ksym_ref(__kvm_hyp_vector); + + if (data->fn) { + vect = __bp_harden_hyp_vecs_start + + data->hyp_vectors_slot * SZ_2K; + + if (!cpus_have_cap(ARM64_HAS_VIRT_HOST_EXTN)) + vect = lm_alias(vect); + } + + return vect; +} + +static inline int kvm_map_vectors(void) +{ + return create_hyp_mappings(kvm_ksym_ref(__bp_harden_hyp_vecs_start), + kvm_ksym_ref(__bp_harden_hyp_vecs_end), + PAGE_HYP_EXEC); +} + +#else +static inline void *kvm_get_hyp_vector(void) +{ + return kvm_ksym_ref(__kvm_hyp_vector); +} + +static inline int kvm_map_vectors(void) +{ + return 0; +} +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ARM64_KVM_MMU_H__ */ diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 9174ba917d65..5640f1d1780f 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -50,7 +50,7 @@ static void __hyp_text __activate_traps_vhe(void) val &= ~CPACR_EL1_FPEN; write_sysreg(val, cpacr_el1); - write_sysreg(__kvm_hyp_vector, vbar_el1); + write_sysreg(kvm_get_hyp_vector(), vbar_el1); } static void __hyp_text __activate_traps_nvhe(void) -- GitLab From e7c3b246edb26b12f420532766e6a39a6410315e Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:17 +0100 Subject: [PATCH 1355/1834] arm64: entry: Apply BP hardening for high-priority synchronous exceptions From: Will Deacon commit 5dfc6ed27710c42cbc15db5c0d4475699991da0a upstream. Software-step and PC alignment fault exceptions have higher priority than instruction abort exceptions, so apply the BP hardening hooks there too if the user PC appears to reside in kernel space. Reported-by: Dan Hettena Reviewed-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 6 ++++-- arch/arm64/mm/fault.c | 9 +++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index fd6879d98bd7..30f4331d477a 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -624,8 +624,10 @@ el0_sp_pc: * Stack or PC alignment exception handling */ mrs x26, far_el1 - // enable interrupts before calling the main handler - enable_dbg_and_irq + enable_dbg +#ifdef CONFIG_TRACE_IRQFLAGS + bl trace_hardirqs_off +#endif ct_user_exit mov x0, x26 mov x1, x25 diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index c95b194d1c6e..6120a1486054 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -617,6 +617,12 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr, struct siginfo info; struct task_struct *tsk = current; + if (user_mode(regs)) { + if (instruction_pointer(regs) > TASK_SIZE) + arm64_apply_bp_hardening(); + local_irq_enable(); + } + if (show_unhandled_signals && unhandled_signal(tsk, SIGBUS)) pr_info_ratelimited("%s[%d]: %s exception: pc=%p sp=%p\n", tsk->comm, task_pid_nr(tsk), @@ -676,6 +682,9 @@ asmlinkage int __exception do_debug_exception(unsigned long addr, if (interrupts_enabled(regs)) trace_hardirqs_off(); + if (user_mode(regs) && instruction_pointer(regs) > TASK_SIZE) + arm64_apply_bp_hardening(); + if (!inf->fn(addr, esr, regs)) { rv = 1; } else { -- GitLab From 34dc20b03d0e9361c86865adcb9ae7516339cfdb Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:18 +0100 Subject: [PATCH 1356/1834] arm64: entry: Apply BP hardening for suspicious interrupts from EL0 From: Will Deacon commit 30d88c0e3ace625a92eead9ca0ad94093a8f59fe upstream. It is possible to take an IRQ from EL0 following a branch to a kernel address in such a way that the IRQ is prioritised over the instruction abort. Whilst an attacker would need to get the stars to align here, it might be sufficient with enough calibration so perform BP hardening in the rare case that we see a kernel address in the ELR when handling an IRQ from EL0. Reported-by: Dan Hettena Reviewed-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/entry.S | 5 +++++ arch/arm64/mm/fault.c | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 30f4331d477a..b79e302d2a3e 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -686,6 +686,11 @@ el0_irq_naked: #endif ct_user_exit +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR + tbz x22, #55, 1f + bl do_el0_irq_bp_hardening +1: +#endif irq_handler #ifdef CONFIG_TRACE_IRQFLAGS diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 6120a1486054..ad49ae8f3967 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -590,6 +590,12 @@ asmlinkage void __exception do_mem_abort(unsigned long addr, unsigned int esr, arm64_notify_die("", regs, &info, esr); } +asmlinkage void __exception do_el0_irq_bp_hardening(void) +{ + /* PC has already been checked in entry.S */ + arm64_apply_bp_hardening(); +} + asmlinkage void __exception do_el0_ia_bp_hardening(unsigned long addr, unsigned int esr, struct pt_regs *regs) -- GitLab From 04b4cc6dabc28c2fe778e5668763be898035a5ba Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:19 +0100 Subject: [PATCH 1357/1834] arm64: cputype: Add missing MIDR values for Cortex-A72 and Cortex-A75 From: Will Deacon commit a65d219fe5dc7887fd5ca04c2ac3e9a34feb8dfc upstream. Hook up MIDR values for the Cortex-A72 and Cortex-A75 CPUs, since they will soon need MIDR matches for hardening the branch predictor. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/cputype.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index 1d47930c30dc..9ee3038a6b98 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -75,7 +75,10 @@ #define ARM_CPU_PART_AEM_V8 0xD0F #define ARM_CPU_PART_FOUNDATION 0xD00 #define ARM_CPU_PART_CORTEX_A57 0xD07 +#define ARM_CPU_PART_CORTEX_A72 0xD08 #define ARM_CPU_PART_CORTEX_A53 0xD03 +#define ARM_CPU_PART_CORTEX_A73 0xD09 +#define ARM_CPU_PART_CORTEX_A75 0xD0A #define APM_CPU_PART_POTENZA 0x000 @@ -87,6 +90,9 @@ #define MIDR_CORTEX_A53 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53) #define MIDR_CORTEX_A57 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57) +#define MIDR_CORTEX_A72 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A72) +#define MIDR_CORTEX_A73 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A73) +#define MIDR_CORTEX_A75 MIDR_CPU_MODEL(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A75) #define MIDR_THUNDERX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX) #define MIDR_THUNDERX_81XX MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX_81XX) #define MIDR_CAVIUM_THUNDERX2 MIDR_CPU_MODEL(ARM_CPU_IMP_CAVIUM, CAVIUM_CPU_PART_THUNDERX2) -- GitLab From 4bcf61fa86cd8bb150fe89be782ded66e5ff11c3 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:20 +0100 Subject: [PATCH 1358/1834] arm64: cpu_errata: Allow an erratum to be match for all revisions of a core From: Marc Zyngier commit 06f1494f837da8997d670a1ba87add7963b08922 upstream. Some minor erratum may not be fixed in further revisions of a core, leading to a situation where the workaround needs to be updated each time an updated core is released. Introduce a MIDR_ALL_VERSIONS match helper that will work for all versions of that MIDR, once and for all. Acked-by: Thomas Gleixner Acked-by: Mark Rutland Acked-by: Daniel Lezcano Reviewed-by: Suzuki K Poulose Signed-off-by: Marc Zyngier Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpu_errata.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 3884c4398597..b9fcbd155df2 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -127,6 +127,13 @@ static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, .midr_range_min = min, \ .midr_range_max = max +#define MIDR_ALL_VERSIONS(model) \ + .def_scope = SCOPE_LOCAL_CPU, \ + .matches = is_affected_midr_range, \ + .midr_model = model, \ + .midr_range_min = 0, \ + .midr_range_max = (MIDR_VARIANT_MASK | MIDR_REVISION_MASK) + const struct arm64_cpu_capabilities arm64_errata[] = { #if defined(CONFIG_ARM64_ERRATUM_826319) || \ defined(CONFIG_ARM64_ERRATUM_827319) || \ -- GitLab From bad52d7979532b20bce7545c18fe7e443b7472f6 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:21 +0100 Subject: [PATCH 1359/1834] arm64: Implement branch predictor hardening for affected Cortex-A CPUs From: Will Deacon commit aa6acde65e03186b5add8151e1ffe36c3c62639b upstream. Cortex-A57, A72, A73 and A75 are susceptible to branch predictor aliasing and can theoretically be attacked by malicious code. This patch implements a PSCI-based mitigation for these CPUs when available. The call into firmware will invalidate the branch predictor state, preventing any malicious entries from affecting other victim contexts. Co-developed-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/bpi.S | 24 +++++++++++++++++++ arch/arm64/kernel/cpu_errata.c | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S index 06a931eb2673..dec95bd82e31 100644 --- a/arch/arm64/kernel/bpi.S +++ b/arch/arm64/kernel/bpi.S @@ -53,3 +53,27 @@ ENTRY(__bp_harden_hyp_vecs_start) vectors __kvm_hyp_vector .endr ENTRY(__bp_harden_hyp_vecs_end) +ENTRY(__psci_hyp_bp_inval_start) + sub sp, sp, #(8 * 18) + stp x16, x17, [sp, #(16 * 0)] + stp x14, x15, [sp, #(16 * 1)] + stp x12, x13, [sp, #(16 * 2)] + stp x10, x11, [sp, #(16 * 3)] + stp x8, x9, [sp, #(16 * 4)] + stp x6, x7, [sp, #(16 * 5)] + stp x4, x5, [sp, #(16 * 6)] + stp x2, x3, [sp, #(16 * 7)] + stp x0, x1, [sp, #(16 * 8)] + mov x0, #0x84000000 + smc #0 + ldp x16, x17, [sp, #(16 * 0)] + ldp x14, x15, [sp, #(16 * 1)] + ldp x12, x13, [sp, #(16 * 2)] + ldp x10, x11, [sp, #(16 * 3)] + ldp x8, x9, [sp, #(16 * 4)] + ldp x6, x7, [sp, #(16 * 5)] + ldp x4, x5, [sp, #(16 * 6)] + ldp x2, x3, [sp, #(16 * 7)] + ldp x0, x1, [sp, #(16 * 8)] + add sp, sp, #(8 * 18) +ENTRY(__psci_hyp_bp_inval_end) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index b9fcbd155df2..5550d18b8180 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -53,6 +53,8 @@ static int cpu_enable_trap_ctr_access(void *__unused) DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); #ifdef CONFIG_KVM +extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; + static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, const char *hyp_vecs_end) { @@ -94,6 +96,9 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, spin_unlock(&bp_lock); } #else +#define __psci_hyp_bp_inval_start NULL +#define __psci_hyp_bp_inval_end NULL + static void __install_bp_hardening_cb(bp_hardening_cb_t fn, const char *hyp_vecs_start, const char *hyp_vecs_end) @@ -118,6 +123,21 @@ static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); } + +#include + +static int enable_psci_bp_hardening(void *data) +{ + const struct arm64_cpu_capabilities *entry = data; + + if (psci_ops.get_version) + install_bp_hardening_cb(entry, + (bp_hardening_cb_t)psci_ops.get_version, + __psci_hyp_bp_inval_start, + __psci_hyp_bp_inval_end); + + return 0; +} #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ #define MIDR_RANGE(model, min, max) \ @@ -211,6 +231,28 @@ const struct arm64_cpu_capabilities arm64_errata[] = { .def_scope = SCOPE_LOCAL_CPU, .enable = cpu_enable_trap_ctr_access, }, +#ifdef CONFIG_HARDEN_BRANCH_PREDICTOR + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), + .enable = enable_psci_bp_hardening, + }, +#endif { } }; -- GitLab From 6df8d16adc44ca8791d11449887db87e67bf0688 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:22 +0100 Subject: [PATCH 1360/1834] arm64: Branch predictor hardening for Cavium ThunderX2 From: Jayachandran C commit f3d795d9b360523beca6d13ba64c2c532f601149 upstream. Use PSCI based mitigation for speculative execution attacks targeting the branch predictor. We use the same mechanism as the one used for Cortex-A CPUs, we expect the PSCI version call to have a side effect of clearing the BTBs. Acked-by: Will Deacon Signed-off-by: Jayachandran C Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/cpu_errata.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 5550d18b8180..67cdfc6a458e 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -252,6 +252,16 @@ const struct arm64_cpu_capabilities arm64_errata[] = { MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), .enable = enable_psci_bp_hardening, }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN), + .enable = enable_psci_bp_hardening, + }, + { + .capability = ARM64_HARDEN_BRANCH_PREDICTOR, + MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2), + .enable = enable_psci_bp_hardening, + }, #endif { } -- GitLab From e06ea9af0fb58e46771569fded5b3bd75fdd2dc9 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:23 +0100 Subject: [PATCH 1361/1834] arm64: KVM: Increment PC after handling an SMC trap From: Marc Zyngier commit f5115e8869e1dfafac0e414b4f1664f3a84a4683 upstream. When handling an SMC trap, the "preferred return address" is set to that of the SMC, and not the next PC (which is a departure from the behaviour of an SMC that isn't trapped). Increment PC in the handler, as the guest is otherwise forever stuck... Cc: stable@vger.kernel.org Fixes: acfb3b883f6d ("arm64: KVM: Fix SMCCC handling of unimplemented SMC/HVC calls") Reviewed-by: Christoffer Dall Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kvm/handle_exit.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 2e6e9e99977b..5b56b09d317b 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -53,7 +53,16 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) static int handle_smc(struct kvm_vcpu *vcpu, struct kvm_run *run) { + /* + * "If an SMC instruction executed at Non-secure EL1 is + * trapped to EL2 because HCR_EL2.TSC is 1, the exception is a + * Trap exception, not a Secure Monitor Call exception [...]" + * + * We need to advance the PC after the trap, as it would + * otherwise return to the same address... + */ vcpu_set_reg(vcpu, 0, ~0UL); + kvm_skip_instr(vcpu, kvm_vcpu_trap_il_is32bit(vcpu)); return 1; } -- GitLab From 8b106affdfb63b6fd71c49b230c942fa525d8a0c Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:24 +0100 Subject: [PATCH 1362/1834] arm/arm64: KVM: Consolidate the PSCI include files From: Marc Zyngier commit 1a2fb94e6a771ff94f4afa22497a4695187b820c upstream. As we're about to update the PSCI support, and because I'm lazy, let's move the PSCI include file to include/kvm so that both ARM architectures can find it. Acked-by: Christoffer Dall Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kvm_psci.h | 27 ------------------- arch/arm/kvm/arm.c | 2 +- arch/arm/kvm/handle_exit.c | 2 +- arch/arm/kvm/psci.c | 3 ++- arch/arm64/kvm/handle_exit.c | 5 +++- .../asm/kvm_psci.h => include/kvm/arm_psci.h | 6 ++--- 6 files changed, 11 insertions(+), 34 deletions(-) delete mode 100644 arch/arm/include/asm/kvm_psci.h rename arch/arm64/include/asm/kvm_psci.h => include/kvm/arm_psci.h (89%) diff --git a/arch/arm/include/asm/kvm_psci.h b/arch/arm/include/asm/kvm_psci.h deleted file mode 100644 index 6bda945d31fa..000000000000 --- a/arch/arm/include/asm/kvm_psci.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2012 - ARM Ltd - * Author: Marc Zyngier - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __ARM_KVM_PSCI_H__ -#define __ARM_KVM_PSCI_H__ - -#define KVM_ARM_PSCI_0_1 1 -#define KVM_ARM_PSCI_0_2 2 - -int kvm_psci_version(struct kvm_vcpu *vcpu); -int kvm_psci_call(struct kvm_vcpu *vcpu); - -#endif /* __ARM_KVM_PSCI_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 5e666b624dc1..ef6595c7d697 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -29,6 +29,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -44,7 +45,6 @@ #include #include #include -#include #include #ifdef REQUIRES_VIRT diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index 4e57ebca6e69..0a2b75882ca8 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include "trace.h" diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index a08d7a93aebb..f44ecf677414 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -21,9 +21,10 @@ #include #include -#include #include +#include + #include /* diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 5b56b09d317b..ff7c18b89e5e 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -22,12 +22,15 @@ #include #include +#include + #include #include #include #include #include -#include +#include +#include #define CREATE_TRACE_POINTS #include "trace.h" diff --git a/arch/arm64/include/asm/kvm_psci.h b/include/kvm/arm_psci.h similarity index 89% rename from arch/arm64/include/asm/kvm_psci.h rename to include/kvm/arm_psci.h index bc39e557c56c..2042bb909474 100644 --- a/arch/arm64/include/asm/kvm_psci.h +++ b/include/kvm/arm_psci.h @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -#ifndef __ARM64_KVM_PSCI_H__ -#define __ARM64_KVM_PSCI_H__ +#ifndef __KVM_ARM_PSCI_H__ +#define __KVM_ARM_PSCI_H__ #define KVM_ARM_PSCI_0_1 1 #define KVM_ARM_PSCI_0_2 2 @@ -24,4 +24,4 @@ int kvm_psci_version(struct kvm_vcpu *vcpu); int kvm_psci_call(struct kvm_vcpu *vcpu); -#endif /* __ARM64_KVM_PSCI_H__ */ +#endif /* __KVM_ARM_PSCI_H__ */ -- GitLab From 33e6484755bc6fbd16f455a4e23e68335db3cb21 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:25 +0100 Subject: [PATCH 1363/1834] arm/arm64: KVM: Add PSCI_VERSION helper From: Marc Zyngier commit d0a144f12a7ca8368933eae6583c096c363ec506 upstream. As we're about to trigger a PSCI version explosion, it doesn't hurt to introduce a PSCI_VERSION helper that is going to be used everywhere. Reviewed-by: Christoffer Dall Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/psci.c | 4 +--- include/kvm/arm_psci.h | 6 ++++-- include/uapi/linux/psci.h | 3 +++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index f44ecf677414..5d8ad0e6661c 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -25,8 +25,6 @@ #include -#include - /* * This is an implementation of the Power State Coordination Interface * as described in ARM document number ARM DEN 0022A. @@ -220,7 +218,7 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) * Bits[31:16] = Major Version = 0 * Bits[15:0] = Minor Version = 2 */ - val = 2; + val = KVM_ARM_PSCI_0_2; break; case PSCI_0_2_FN_CPU_SUSPEND: case PSCI_0_2_FN64_CPU_SUSPEND: diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h index 2042bb909474..5659343580a3 100644 --- a/include/kvm/arm_psci.h +++ b/include/kvm/arm_psci.h @@ -18,8 +18,10 @@ #ifndef __KVM_ARM_PSCI_H__ #define __KVM_ARM_PSCI_H__ -#define KVM_ARM_PSCI_0_1 1 -#define KVM_ARM_PSCI_0_2 2 +#include + +#define KVM_ARM_PSCI_0_1 PSCI_VERSION(0, 1) +#define KVM_ARM_PSCI_0_2 PSCI_VERSION(0, 2) int kvm_psci_version(struct kvm_vcpu *vcpu); int kvm_psci_call(struct kvm_vcpu *vcpu); diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h index 3d7a0fc021a7..39930ca998cd 100644 --- a/include/uapi/linux/psci.h +++ b/include/uapi/linux/psci.h @@ -87,6 +87,9 @@ (((ver) & PSCI_VERSION_MAJOR_MASK) >> PSCI_VERSION_MAJOR_SHIFT) #define PSCI_VERSION_MINOR(ver) \ ((ver) & PSCI_VERSION_MINOR_MASK) +#define PSCI_VERSION(maj, min) \ + ((((maj) << PSCI_VERSION_MAJOR_SHIFT) & PSCI_VERSION_MAJOR_MASK) | \ + ((min) & PSCI_VERSION_MINOR_MASK)) /* PSCI features decoding (>=1.0) */ #define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1 -- GitLab From 54faafb2b7b1900eeb08fc9db55c0a9e122dd20d Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:26 +0100 Subject: [PATCH 1364/1834] arm/arm64: KVM: Add smccc accessors to PSCI code From: Marc Zyngier commit 84684fecd7ea381824a96634a027b7719587fb77 upstream. Instead of open coding the accesses to the various registers, let's add explicit SMCCC accessors. Reviewed-by: Christoffer Dall Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/psci.c | 52 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 5d8ad0e6661c..f579ed9d279b 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -32,6 +32,38 @@ #define AFFINITY_MASK(level) ~((0x1UL << ((level) * MPIDR_LEVEL_BITS)) - 1) +static u32 smccc_get_function(struct kvm_vcpu *vcpu) +{ + return vcpu_get_reg(vcpu, 0); +} + +static unsigned long smccc_get_arg1(struct kvm_vcpu *vcpu) +{ + return vcpu_get_reg(vcpu, 1); +} + +static unsigned long smccc_get_arg2(struct kvm_vcpu *vcpu) +{ + return vcpu_get_reg(vcpu, 2); +} + +static unsigned long smccc_get_arg3(struct kvm_vcpu *vcpu) +{ + return vcpu_get_reg(vcpu, 3); +} + +static void smccc_set_retval(struct kvm_vcpu *vcpu, + unsigned long a0, + unsigned long a1, + unsigned long a2, + unsigned long a3) +{ + vcpu_set_reg(vcpu, 0, a0); + vcpu_set_reg(vcpu, 1, a1); + vcpu_set_reg(vcpu, 2, a2); + vcpu_set_reg(vcpu, 3, a3); +} + static unsigned long psci_affinity_mask(unsigned long affinity_level) { if (affinity_level <= 3) @@ -74,7 +106,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) unsigned long context_id; phys_addr_t target_pc; - cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK; + cpu_id = smccc_get_arg1(source_vcpu) & MPIDR_HWID_BITMASK; if (vcpu_mode_is_32bit(source_vcpu)) cpu_id &= ~((u32) 0); @@ -93,8 +125,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) return PSCI_RET_INVALID_PARAMS; } - target_pc = vcpu_get_reg(source_vcpu, 2); - context_id = vcpu_get_reg(source_vcpu, 3); + target_pc = smccc_get_arg2(source_vcpu); + context_id = smccc_get_arg3(source_vcpu); kvm_reset_vcpu(vcpu); @@ -113,7 +145,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) * NOTE: We always update r0 (or x0) because for PSCI v0.1 * the general puspose registers are undefined upon CPU_ON. */ - vcpu_set_reg(vcpu, 0, context_id); + smccc_set_retval(vcpu, context_id, 0, 0, 0); vcpu->arch.power_off = false; smp_mb(); /* Make sure the above is visible */ @@ -133,8 +165,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu) struct kvm *kvm = vcpu->kvm; struct kvm_vcpu *tmp; - target_affinity = vcpu_get_reg(vcpu, 1); - lowest_affinity_level = vcpu_get_reg(vcpu, 2); + target_affinity = smccc_get_arg1(vcpu); + lowest_affinity_level = smccc_get_arg2(vcpu); /* Determine target affinity mask */ target_affinity_mask = psci_affinity_mask(lowest_affinity_level); @@ -208,7 +240,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu) static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) { struct kvm *kvm = vcpu->kvm; - unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); + unsigned long psci_fn = smccc_get_function(vcpu); unsigned long val; int ret = 1; @@ -275,14 +307,14 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) break; } - vcpu_set_reg(vcpu, 0, val); + smccc_set_retval(vcpu, val, 0, 0, 0); return ret; } static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) { struct kvm *kvm = vcpu->kvm; - unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0); + unsigned long psci_fn = smccc_get_function(vcpu); unsigned long val; switch (psci_fn) { @@ -300,7 +332,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) break; } - vcpu_set_reg(vcpu, 0, val); + smccc_set_retval(vcpu, val, 0, 0, 0); return 1; } -- GitLab From 4b1713f50d68de8f5cb4c98b6956d29d653e2c1b Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:27 +0100 Subject: [PATCH 1365/1834] arm/arm64: KVM: Implement PSCI 1.0 support From: Marc Zyngier commit 58e0b2239a4d997094ba63986ef4de29ddc91d87 upstream. PSCI 1.0 can be trivially implemented by providing the FEATURES call on top of PSCI 0.2 and returning 1.0 as the PSCI version. We happily ignore everything else, as they are either optional or are clarifications that do not require any additional change. PSCI 1.0 is now the default until we decide to add a userspace selection API. Reviewed-by: Christoffer Dall Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/psci.c | 45 +++++++++++++++++++++++++++++++++++++++++- include/kvm/arm_psci.h | 3 +++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index f579ed9d279b..220eaa04b1c4 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -232,7 +232,7 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu) int kvm_psci_version(struct kvm_vcpu *vcpu) { if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) - return KVM_ARM_PSCI_0_2; + return KVM_ARM_PSCI_LATEST; return KVM_ARM_PSCI_0_1; } @@ -311,6 +311,47 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) return ret; } +static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu) +{ + u32 psci_fn = smccc_get_function(vcpu); + u32 feature; + unsigned long val; + int ret = 1; + + switch(psci_fn) { + case PSCI_0_2_FN_PSCI_VERSION: + val = KVM_ARM_PSCI_1_0; + break; + case PSCI_1_0_FN_PSCI_FEATURES: + feature = smccc_get_arg1(vcpu); + switch(feature) { + case PSCI_0_2_FN_PSCI_VERSION: + case PSCI_0_2_FN_CPU_SUSPEND: + case PSCI_0_2_FN64_CPU_SUSPEND: + case PSCI_0_2_FN_CPU_OFF: + case PSCI_0_2_FN_CPU_ON: + case PSCI_0_2_FN64_CPU_ON: + case PSCI_0_2_FN_AFFINITY_INFO: + case PSCI_0_2_FN64_AFFINITY_INFO: + case PSCI_0_2_FN_MIGRATE_INFO_TYPE: + case PSCI_0_2_FN_SYSTEM_OFF: + case PSCI_0_2_FN_SYSTEM_RESET: + case PSCI_1_0_FN_PSCI_FEATURES: + val = 0; + break; + default: + val = PSCI_RET_NOT_SUPPORTED; + break; + } + break; + default: + return kvm_psci_0_2_call(vcpu); + } + + smccc_set_retval(vcpu, val, 0, 0, 0); + return ret; +} + static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) { struct kvm *kvm = vcpu->kvm; @@ -353,6 +394,8 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) int kvm_psci_call(struct kvm_vcpu *vcpu) { switch (kvm_psci_version(vcpu)) { + case KVM_ARM_PSCI_1_0: + return kvm_psci_1_0_call(vcpu); case KVM_ARM_PSCI_0_2: return kvm_psci_0_2_call(vcpu); case KVM_ARM_PSCI_0_1: diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h index 5659343580a3..32360432cff5 100644 --- a/include/kvm/arm_psci.h +++ b/include/kvm/arm_psci.h @@ -22,6 +22,9 @@ #define KVM_ARM_PSCI_0_1 PSCI_VERSION(0, 1) #define KVM_ARM_PSCI_0_2 PSCI_VERSION(0, 2) +#define KVM_ARM_PSCI_1_0 PSCI_VERSION(1, 0) + +#define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_0 int kvm_psci_version(struct kvm_vcpu *vcpu); int kvm_psci_call(struct kvm_vcpu *vcpu); -- GitLab From 6681f3c44016f6997daf55e0389393b6fee89843 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:28 +0100 Subject: [PATCH 1366/1834] arm/arm64: KVM: Advertise SMCCC v1.1 From: Marc Zyngier commit 09e6be12effdb33bf7210c8867bbd213b66a499e upstream. The new SMC Calling Convention (v1.1) allows for a reduced overhead when calling into the firmware, and provides a new feature discovery mechanism. Make it visible to KVM guests. Tested-by: Ard Biesheuvel Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/handle_exit.c | 2 +- arch/arm/kvm/psci.c | 24 +++++++++++++++++++++++- arch/arm64/kvm/handle_exit.c | 2 +- include/kvm/arm_psci.h | 2 +- include/linux/arm-smccc.h | 13 +++++++++++++ 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c index 0a2b75882ca8..de1aedce2a8b 100644 --- a/arch/arm/kvm/handle_exit.c +++ b/arch/arm/kvm/handle_exit.c @@ -36,7 +36,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) kvm_vcpu_hvc_get_imm(vcpu)); vcpu->stat.hvc_exit_stat++; - ret = kvm_psci_call(vcpu); + ret = kvm_hvc_call_handler(vcpu); if (ret < 0) { vcpu_set_reg(vcpu, 0, ~0UL); return 1; diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 220eaa04b1c4..02efb0d4ed4d 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -337,6 +338,7 @@ static int kvm_psci_1_0_call(struct kvm_vcpu *vcpu) case PSCI_0_2_FN_SYSTEM_OFF: case PSCI_0_2_FN_SYSTEM_RESET: case PSCI_1_0_FN_PSCI_FEATURES: + case ARM_SMCCC_VERSION_FUNC_ID: val = 0; break; default: @@ -391,7 +393,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) * Errors: * -EINVAL: Unrecognized PSCI function */ -int kvm_psci_call(struct kvm_vcpu *vcpu) +static int kvm_psci_call(struct kvm_vcpu *vcpu) { switch (kvm_psci_version(vcpu)) { case KVM_ARM_PSCI_1_0: @@ -404,3 +406,23 @@ int kvm_psci_call(struct kvm_vcpu *vcpu) return -EINVAL; }; } + +int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) +{ + u32 func_id = smccc_get_function(vcpu); + u32 val = PSCI_RET_NOT_SUPPORTED; + + switch (func_id) { + case ARM_SMCCC_VERSION_FUNC_ID: + val = ARM_SMCCC_VERSION_1_1; + break; + case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: + /* Nothing supported yet */ + break; + default: + return kvm_psci_call(vcpu); + } + + smccc_set_retval(vcpu, val, 0, 0, 0); + return 1; +} diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index ff7c18b89e5e..efe43c5f2dc1 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -45,7 +45,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run) kvm_vcpu_hvc_get_imm(vcpu)); vcpu->stat.hvc_exit_stat++; - ret = kvm_psci_call(vcpu); + ret = kvm_hvc_call_handler(vcpu); if (ret < 0) { vcpu_set_reg(vcpu, 0, ~0UL); return 1; diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h index 32360432cff5..ed1dd8088f1c 100644 --- a/include/kvm/arm_psci.h +++ b/include/kvm/arm_psci.h @@ -27,6 +27,6 @@ #define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_0 int kvm_psci_version(struct kvm_vcpu *vcpu); -int kvm_psci_call(struct kvm_vcpu *vcpu); +int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); #endif /* __KVM_ARM_PSCI_H__ */ diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index 4c5bca38c653..dc68aa5a7261 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -60,6 +60,19 @@ #define ARM_SMCCC_QUIRK_NONE 0 #define ARM_SMCCC_QUIRK_QCOM_A6 1 /* Save/restore register a6 */ +#define ARM_SMCCC_VERSION_1_0 0x10000 +#define ARM_SMCCC_VERSION_1_1 0x10001 + +#define ARM_SMCCC_VERSION_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 0) + +#define ARM_SMCCC_ARCH_FEATURES_FUNC_ID \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 1) + #ifndef __ASSEMBLY__ #include -- GitLab From c482a245b9692d86d038262795caa998d852983f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:29 +0100 Subject: [PATCH 1367/1834] arm64: KVM: Make PSCI_VERSION a fast path From: Marc Zyngier commit 90348689d500410ca7a55624c667f956771dce7f upstream. For those CPUs that require PSCI to perform a BP invalidation, going all the way to the PSCI code for not much is a waste of precious cycles. Let's terminate that call as early as possible. Signed-off-by: Marc Zyngier Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kvm/hyp/switch.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 5640f1d1780f..b63a52854c8c 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -308,6 +309,18 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu)) goto again; + if (exit_code == ARM_EXCEPTION_TRAP && + (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 || + kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) && + vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) { + u64 val = PSCI_RET_NOT_SUPPORTED; + if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) + val = 2; + + vcpu_set_reg(vcpu, 0, val); + goto again; + } + if (static_branch_unlikely(&vgic_v2_cpuif_trap) && exit_code == ARM_EXCEPTION_TRAP) { bool valid; -- GitLab From 142cfd60faba9cfa34adc1a3cf7e184a8066c12f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:30 +0100 Subject: [PATCH 1368/1834] arm/arm64: KVM: Turn kvm_psci_version into a static inline From: Marc Zyngier commit a4097b351118e821841941a79ec77d3ce3f1c5d9 upstream. We're about to need kvm_psci_version in HYP too. So let's turn it into a static inline, and pass the kvm structure as a second parameter (so that HYP can do a kern_hyp_va on it). Tested-by: Ard Biesheuvel Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/kvm/psci.c | 12 ++---------- arch/arm64/kvm/hyp/switch.c | 20 ++++++++++++-------- include/kvm/arm_psci.h | 21 ++++++++++++++++++++- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 02efb0d4ed4d..1120ad0bd3d2 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -120,7 +120,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu) if (!vcpu) return PSCI_RET_INVALID_PARAMS; if (!vcpu->arch.power_off) { - if (kvm_psci_version(source_vcpu) != KVM_ARM_PSCI_0_1) + if (kvm_psci_version(source_vcpu, kvm) != KVM_ARM_PSCI_0_1) return PSCI_RET_ALREADY_ON; else return PSCI_RET_INVALID_PARAMS; @@ -230,14 +230,6 @@ static void kvm_psci_system_reset(struct kvm_vcpu *vcpu) kvm_prepare_system_event(vcpu, KVM_SYSTEM_EVENT_RESET); } -int kvm_psci_version(struct kvm_vcpu *vcpu) -{ - if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) - return KVM_ARM_PSCI_LATEST; - - return KVM_ARM_PSCI_0_1; -} - static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu) { struct kvm *kvm = vcpu->kvm; @@ -395,7 +387,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu) */ static int kvm_psci_call(struct kvm_vcpu *vcpu) { - switch (kvm_psci_version(vcpu)) { + switch (kvm_psci_version(vcpu, vcpu->kvm)) { case KVM_ARM_PSCI_1_0: return kvm_psci_1_0_call(vcpu); case KVM_ARM_PSCI_0_2: diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index b63a52854c8c..849ee8a17525 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -19,6 +19,8 @@ #include #include +#include + #include #include #include @@ -311,14 +313,16 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) if (exit_code == ARM_EXCEPTION_TRAP && (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 || - kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32) && - vcpu_get_reg(vcpu, 0) == PSCI_0_2_FN_PSCI_VERSION) { - u64 val = PSCI_RET_NOT_SUPPORTED; - if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) - val = 2; - - vcpu_set_reg(vcpu, 0, val); - goto again; + kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32)) { + u32 val = vcpu_get_reg(vcpu, 0); + + if (val == PSCI_0_2_FN_PSCI_VERSION) { + val = kvm_psci_version(vcpu, kern_hyp_va(vcpu->kvm)); + if (unlikely(val == KVM_ARM_PSCI_0_1)) + val = PSCI_RET_NOT_SUPPORTED; + vcpu_set_reg(vcpu, 0, val); + goto again; + } } if (static_branch_unlikely(&vgic_v2_cpuif_trap) && diff --git a/include/kvm/arm_psci.h b/include/kvm/arm_psci.h index ed1dd8088f1c..e518e4e3dfb5 100644 --- a/include/kvm/arm_psci.h +++ b/include/kvm/arm_psci.h @@ -18,6 +18,7 @@ #ifndef __KVM_ARM_PSCI_H__ #define __KVM_ARM_PSCI_H__ +#include #include #define KVM_ARM_PSCI_0_1 PSCI_VERSION(0, 1) @@ -26,7 +27,25 @@ #define KVM_ARM_PSCI_LATEST KVM_ARM_PSCI_1_0 -int kvm_psci_version(struct kvm_vcpu *vcpu); +/* + * We need the KVM pointer independently from the vcpu as we can call + * this from HYP, and need to apply kern_hyp_va on it... + */ +static inline int kvm_psci_version(struct kvm_vcpu *vcpu, struct kvm *kvm) +{ + /* + * Our PSCI implementation stays the same across versions from + * v0.2 onward, only adding the few mandatory functions (such + * as FEATURES with 1.0) that are required by newer + * revisions. It is thus safe to return the latest. + */ + if (test_bit(KVM_ARM_VCPU_PSCI_0_2, vcpu->arch.features)) + return KVM_ARM_PSCI_LATEST; + + return KVM_ARM_PSCI_0_1; +} + + int kvm_hvc_call_handler(struct kvm_vcpu *vcpu); #endif /* __KVM_ARM_PSCI_H__ */ -- GitLab From c9ae3d5717bf14c05299f184c4bfee79e9a22efe Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:31 +0100 Subject: [PATCH 1369/1834] arm64: KVM: Report SMCCC_ARCH_WORKAROUND_1 BP hardening support From: Marc Zyngier commit 6167ec5c9145cdf493722dfd80a5d48bafc4a18a upstream. A new feature of SMCCC 1.1 is that it offers firmware-based CPU workarounds. In particular, SMCCC_ARCH_WORKAROUND_1 provides BP hardening for CVE-2017-5715. If the host has some mitigation for this issue, report that we deal with it using SMCCC_ARCH_WORKAROUND_1, as we apply the host workaround on every guest exit. Tested-by: Ard Biesheuvel Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas [v4.9: account for files moved to virt/ upstream] Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm/include/asm/kvm_host.h | 6 ++++++ arch/arm/kvm/psci.c | 9 ++++++++- arch/arm64/include/asm/kvm_host.h | 5 +++++ include/linux/arm-smccc.h | 5 +++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index d5423ab15ed5..9fe1043e72d2 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -318,4 +318,10 @@ static inline int kvm_arm_vcpu_arch_has_attr(struct kvm_vcpu *vcpu, return -ENXIO; } +static inline bool kvm_arm_harden_branch_predictor(void) +{ + /* No way to detect it yet, pretend it is not there. */ + return false; +} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c index 1120ad0bd3d2..3d962257c166 100644 --- a/arch/arm/kvm/psci.c +++ b/arch/arm/kvm/psci.c @@ -403,13 +403,20 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu) { u32 func_id = smccc_get_function(vcpu); u32 val = PSCI_RET_NOT_SUPPORTED; + u32 feature; switch (func_id) { case ARM_SMCCC_VERSION_FUNC_ID: val = ARM_SMCCC_VERSION_1_1; break; case ARM_SMCCC_ARCH_FEATURES_FUNC_ID: - /* Nothing supported yet */ + feature = smccc_get_arg1(vcpu); + switch(feature) { + case ARM_SMCCC_ARCH_WORKAROUND_1: + if (kvm_arm_harden_branch_predictor()) + val = 0; + break; + } break; default: return kvm_psci_call(vcpu); diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index e5050388e062..37d56e85036e 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -393,4 +393,9 @@ static inline void __cpu_init_stage2(void) "PARange is %d bits, unsupported configuration!", parange); } +static inline bool kvm_arm_harden_branch_predictor(void) +{ + return cpus_have_cap(ARM64_HARDEN_BRANCH_PREDICTOR); +} + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index dc68aa5a7261..e1ef944ef1da 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -73,6 +73,11 @@ ARM_SMCCC_SMC_32, \ 0, 1) +#define ARM_SMCCC_ARCH_WORKAROUND_1 \ + ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \ + ARM_SMCCC_SMC_32, \ + 0, 0x8000) + #ifndef __ASSEMBLY__ #include -- GitLab From 196d04197d08a9871c1e12782823caee90cc1c20 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:32 +0100 Subject: [PATCH 1370/1834] arm64: KVM: Add SMCCC_ARCH_WORKAROUND_1 fast handling From: Marc Zyngier commit f72af90c3783d924337624659b43e2d36f1b36b4 upstream. We want SMCCC_ARCH_WORKAROUND_1 to be fast. As fast as possible. So let's intercept it as early as we can by testing for the function call number as soon as we've identified a HVC call coming from the guest. Tested-by: Ard Biesheuvel Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kvm/hyp/hyp-entry.S | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S index 4e92399f7105..4e9d50c3e658 100644 --- a/arch/arm64/kvm/hyp/hyp-entry.S +++ b/arch/arm64/kvm/hyp/hyp-entry.S @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include #include #include @@ -79,10 +80,11 @@ alternative_endif lsr x0, x1, #ESR_ELx_EC_SHIFT cmp x0, #ESR_ELx_EC_HVC64 + ccmp x0, #ESR_ELx_EC_HVC32, #4, ne b.ne el1_trap - mrs x1, vttbr_el2 // If vttbr is valid, the 64bit guest - cbnz x1, el1_trap // called HVC + mrs x1, vttbr_el2 // If vttbr is valid, the guest + cbnz x1, el1_hvc_guest // called HVC /* Here, we're pretty sure the host called HVC. */ ldp x0, x1, [sp], #16 @@ -101,6 +103,20 @@ alternative_endif 2: eret +el1_hvc_guest: + /* + * Fastest possible path for ARM_SMCCC_ARCH_WORKAROUND_1. + * The workaround has already been applied on the host, + * so let's quickly get back to the guest. We don't bother + * restoring x1, as it can be clobbered anyway. + */ + ldr x1, [sp] // Guest's x0 + eor w1, w1, #ARM_SMCCC_ARCH_WORKAROUND_1 + cbnz w1, el1_trap + mov x0, x1 + add sp, sp, #16 + eret + el1_trap: /* * x0: ESR_EC -- GitLab From 56d37971abfc59d6c6eaafab9bd4d62445c1d66f Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:33 +0100 Subject: [PATCH 1371/1834] firmware/psci: Expose PSCI conduit From: Marc Zyngier commit 09a8d6d48499f93e2abde691f5800081cd858726 upstream. In order to call into the firmware to apply workarounds, it is useful to find out whether we're using HVC or SMC. Let's expose this through the psci_ops. Acked-by: Lorenzo Pieralisi Reviewed-by: Robin Murphy Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/psci.c | 28 +++++++++++++++++++++++----- include/linux/psci.h | 7 +++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 9a3ce76304b6..a49196ae0840 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -59,7 +59,9 @@ bool psci_tos_resident_on(int cpu) return cpu == resident_cpu; } -struct psci_operations psci_ops; +struct psci_operations psci_ops = { + .conduit = PSCI_CONDUIT_NONE, +}; typedef unsigned long (psci_fn)(unsigned long, unsigned long, unsigned long, unsigned long); @@ -210,6 +212,22 @@ static unsigned long psci_migrate_info_up_cpu(void) 0, 0, 0); } +static void set_conduit(enum psci_conduit conduit) +{ + switch (conduit) { + case PSCI_CONDUIT_HVC: + invoke_psci_fn = __invoke_psci_fn_hvc; + break; + case PSCI_CONDUIT_SMC: + invoke_psci_fn = __invoke_psci_fn_smc; + break; + default: + WARN(1, "Unexpected PSCI conduit %d\n", conduit); + } + + psci_ops.conduit = conduit; +} + static int get_set_conduit_method(struct device_node *np) { const char *method; @@ -222,9 +240,9 @@ static int get_set_conduit_method(struct device_node *np) } if (!strcmp("hvc", method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; + set_conduit(PSCI_CONDUIT_HVC); } else if (!strcmp("smc", method)) { - invoke_psci_fn = __invoke_psci_fn_smc; + set_conduit(PSCI_CONDUIT_SMC); } else { pr_warn("invalid \"method\" property: %s\n", method); return -EINVAL; @@ -654,9 +672,9 @@ int __init psci_acpi_init(void) pr_info("probing for conduit method from ACPI.\n"); if (acpi_psci_use_hvc()) - invoke_psci_fn = __invoke_psci_fn_hvc; + set_conduit(PSCI_CONDUIT_HVC); else - invoke_psci_fn = __invoke_psci_fn_smc; + set_conduit(PSCI_CONDUIT_SMC); return psci_probe(); } diff --git a/include/linux/psci.h b/include/linux/psci.h index 6306ab10af18..66ff54787d3e 100644 --- a/include/linux/psci.h +++ b/include/linux/psci.h @@ -25,6 +25,12 @@ bool psci_tos_resident_on(int cpu); int psci_cpu_init_idle(unsigned int cpu); int psci_cpu_suspend_enter(unsigned long index); +enum psci_conduit { + PSCI_CONDUIT_NONE, + PSCI_CONDUIT_SMC, + PSCI_CONDUIT_HVC, +}; + struct psci_operations { u32 (*get_version)(void); int (*cpu_suspend)(u32 state, unsigned long entry_point); @@ -34,6 +40,7 @@ struct psci_operations { int (*affinity_info)(unsigned long target_affinity, unsigned long lowest_affinity_level); int (*migrate_info_type)(void); + enum psci_conduit conduit; }; extern struct psci_operations psci_ops; -- GitLab From 883a91d37ff3809d3c5a144ec0a59f4f68509acc Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:34 +0100 Subject: [PATCH 1372/1834] firmware/psci: Expose SMCCC version through psci_ops From: Marc Zyngier commit e78eef554a912ef6c1e0bbf97619dafbeae3339f upstream. Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed, let's do that at boot time, and expose the version of the calling convention as part of the psci_ops structure. Acked-by: Lorenzo Pieralisi Reviewed-by: Robin Murphy Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/psci.c | 27 +++++++++++++++++++++++++++ include/linux/psci.h | 6 ++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index a49196ae0840..79a48c37fb35 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -61,6 +61,7 @@ bool psci_tos_resident_on(int cpu) struct psci_operations psci_ops = { .conduit = PSCI_CONDUIT_NONE, + .smccc_version = SMCCC_VERSION_1_0, }; typedef unsigned long (psci_fn)(unsigned long, unsigned long, @@ -511,6 +512,31 @@ static void __init psci_init_migrate(void) pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); } +static void __init psci_init_smccc(void) +{ + u32 ver = ARM_SMCCC_VERSION_1_0; + int feature; + + feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID); + + if (feature != PSCI_RET_NOT_SUPPORTED) { + u32 ret; + ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0); + if (ret == ARM_SMCCC_VERSION_1_1) { + psci_ops.smccc_version = SMCCC_VERSION_1_1; + ver = ret; + } + } + + /* + * Conveniently, the SMCCC and PSCI versions are encoded the + * same way. No, this isn't accidental. + */ + pr_info("SMC Calling Convention v%d.%d\n", + PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver)); + +} + static void __init psci_0_2_set_functions(void) { pr_info("Using standard PSCI v0.2 function IDs\n"); @@ -559,6 +585,7 @@ static int __init psci_probe(void) psci_init_migrate(); if (PSCI_VERSION_MAJOR(ver) >= 1) { + psci_init_smccc(); psci_init_cpu_suspend(); psci_init_system_suspend(); } diff --git a/include/linux/psci.h b/include/linux/psci.h index 66ff54787d3e..347077cf19c6 100644 --- a/include/linux/psci.h +++ b/include/linux/psci.h @@ -31,6 +31,11 @@ enum psci_conduit { PSCI_CONDUIT_HVC, }; +enum smccc_version { + SMCCC_VERSION_1_0, + SMCCC_VERSION_1_1, +}; + struct psci_operations { u32 (*get_version)(void); int (*cpu_suspend)(u32 state, unsigned long entry_point); @@ -41,6 +46,7 @@ struct psci_operations { unsigned long lowest_affinity_level); int (*migrate_info_type)(void); enum psci_conduit conduit; + enum smccc_version smccc_version; }; extern struct psci_operations psci_ops; -- GitLab From 5d667c15ee231d357d6f1ee3d8afb91ff9e3c877 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:35 +0100 Subject: [PATCH 1373/1834] arm/arm64: smccc: Make function identifiers an unsigned quantity From: Marc Zyngier commit ded4c39e93f3b72968fdb79baba27f3b83dad34c upstream. Function identifiers are a 32bit, unsigned quantity. But we never tell so to the compiler, resulting in the following: 4ac: b26187e0 mov x0, #0xffffffff80000001 We thus rely on the firmware narrowing it for us, which is not always a reasonable expectation. Cc: stable@vger.kernel.org Reported-by: Ard Biesheuvel Acked-by: Ard Biesheuvel Reviewed-by: Robin Murphy Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- include/linux/arm-smccc.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index e1ef944ef1da..dd44d8458c04 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -14,14 +14,16 @@ #ifndef __LINUX_ARM_SMCCC_H #define __LINUX_ARM_SMCCC_H +#include + /* * This file provides common defines for ARM SMC Calling Convention as * specified in * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html */ -#define ARM_SMCCC_STD_CALL 0 -#define ARM_SMCCC_FAST_CALL 1 +#define ARM_SMCCC_STD_CALL _AC(0,U) +#define ARM_SMCCC_FAST_CALL _AC(1,U) #define ARM_SMCCC_TYPE_SHIFT 31 #define ARM_SMCCC_SMC_32 0 -- GitLab From eb90973e64c7174a4d2b584f1675e80fb8336100 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:36 +0100 Subject: [PATCH 1374/1834] arm/arm64: smccc: Implement SMCCC v1.1 inline primitive From: Marc Zyngier commit f2d3b2e8759a5833df6f022e42df2d581e6d843c upstream. One of the major improvement of SMCCC v1.1 is that it only clobbers the first 4 registers, both on 32 and 64bit. This means that it becomes very easy to provide an inline version of the SMC call primitive, and avoid performing a function call to stash the registers that would otherwise be clobbered by SMCCC v1.0. Reviewed-by: Robin Murphy Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- include/linux/arm-smccc.h | 141 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index dd44d8458c04..a031897fca76 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -150,5 +150,146 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, #define arm_smccc_hvc_quirk(...) __arm_smccc_hvc(__VA_ARGS__) +/* SMCCC v1.1 implementation madness follows */ +#ifdef CONFIG_ARM64 + +#define SMCCC_SMC_INST "smc #0" +#define SMCCC_HVC_INST "hvc #0" + +#elif defined(CONFIG_ARM) +#include +#include + +#define SMCCC_SMC_INST __SMC(0) +#define SMCCC_HVC_INST __HVC(0) + +#endif + +#define ___count_args(_0, _1, _2, _3, _4, _5, _6, _7, _8, x, ...) x + +#define __count_args(...) \ + ___count_args(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) + +#define __constraint_write_0 \ + "+r" (r0), "=&r" (r1), "=&r" (r2), "=&r" (r3) +#define __constraint_write_1 \ + "+r" (r0), "+r" (r1), "=&r" (r2), "=&r" (r3) +#define __constraint_write_2 \ + "+r" (r0), "+r" (r1), "+r" (r2), "=&r" (r3) +#define __constraint_write_3 \ + "+r" (r0), "+r" (r1), "+r" (r2), "+r" (r3) +#define __constraint_write_4 __constraint_write_3 +#define __constraint_write_5 __constraint_write_4 +#define __constraint_write_6 __constraint_write_5 +#define __constraint_write_7 __constraint_write_6 + +#define __constraint_read_0 +#define __constraint_read_1 +#define __constraint_read_2 +#define __constraint_read_3 +#define __constraint_read_4 "r" (r4) +#define __constraint_read_5 __constraint_read_4, "r" (r5) +#define __constraint_read_6 __constraint_read_5, "r" (r6) +#define __constraint_read_7 __constraint_read_6, "r" (r7) + +#define __declare_arg_0(a0, res) \ + struct arm_smccc_res *___res = res; \ + register u32 r0 asm("r0") = a0; \ + register unsigned long r1 asm("r1"); \ + register unsigned long r2 asm("r2"); \ + register unsigned long r3 asm("r3") + +#define __declare_arg_1(a0, a1, res) \ + struct arm_smccc_res *___res = res; \ + register u32 r0 asm("r0") = a0; \ + register typeof(a1) r1 asm("r1") = a1; \ + register unsigned long r2 asm("r2"); \ + register unsigned long r3 asm("r3") + +#define __declare_arg_2(a0, a1, a2, res) \ + struct arm_smccc_res *___res = res; \ + register u32 r0 asm("r0") = a0; \ + register typeof(a1) r1 asm("r1") = a1; \ + register typeof(a2) r2 asm("r2") = a2; \ + register unsigned long r3 asm("r3") + +#define __declare_arg_3(a0, a1, a2, a3, res) \ + struct arm_smccc_res *___res = res; \ + register u32 r0 asm("r0") = a0; \ + register typeof(a1) r1 asm("r1") = a1; \ + register typeof(a2) r2 asm("r2") = a2; \ + register typeof(a3) r3 asm("r3") = a3 + +#define __declare_arg_4(a0, a1, a2, a3, a4, res) \ + __declare_arg_3(a0, a1, a2, a3, res); \ + register typeof(a4) r4 asm("r4") = a4 + +#define __declare_arg_5(a0, a1, a2, a3, a4, a5, res) \ + __declare_arg_4(a0, a1, a2, a3, a4, res); \ + register typeof(a5) r5 asm("r5") = a5 + +#define __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res) \ + __declare_arg_5(a0, a1, a2, a3, a4, a5, res); \ + register typeof(a6) r6 asm("r6") = a6 + +#define __declare_arg_7(a0, a1, a2, a3, a4, a5, a6, a7, res) \ + __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res); \ + register typeof(a7) r7 asm("r7") = a7 + +#define ___declare_args(count, ...) __declare_arg_ ## count(__VA_ARGS__) +#define __declare_args(count, ...) ___declare_args(count, __VA_ARGS__) + +#define ___constraints(count) \ + : __constraint_write_ ## count \ + : __constraint_read_ ## count \ + : "memory" +#define __constraints(count) ___constraints(count) + +/* + * We have an output list that is not necessarily used, and GCC feels + * entitled to optimise the whole sequence away. "volatile" is what + * makes it stick. + */ +#define __arm_smccc_1_1(inst, ...) \ + do { \ + __declare_args(__count_args(__VA_ARGS__), __VA_ARGS__); \ + asm volatile(inst "\n" \ + __constraints(__count_args(__VA_ARGS__))); \ + if (___res) \ + *___res = (typeof(*___res)){r0, r1, r2, r3}; \ + } while (0) + +/* + * arm_smccc_1_1_smc() - make an SMCCC v1.1 compliant SMC call + * + * This is a variadic macro taking one to eight source arguments, and + * an optional return structure. + * + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 + * + * This macro is used to make SMC calls following SMC Calling Convention v1.1. + * The content of the supplied param are copied to registers 0 to 7 prior + * to the SMC instruction. The return values are updated with the content + * from register 0 to 3 on return from the SMC instruction if not NULL. + */ +#define arm_smccc_1_1_smc(...) __arm_smccc_1_1(SMCCC_SMC_INST, __VA_ARGS__) + +/* + * arm_smccc_1_1_hvc() - make an SMCCC v1.1 compliant HVC call + * + * This is a variadic macro taking one to eight source arguments, and + * an optional return structure. + * + * @a0-a7: arguments passed in registers 0 to 7 + * @res: result values from registers 0 to 3 + * + * This macro is used to make HVC calls following SMC Calling Convention v1.1. + * The content of the supplied param are copied to registers 0 to 7 prior + * to the HVC instruction. The return values are updated with the content + * from register 0 to 3 on return from the HVC instruction if not NULL. + */ +#define arm_smccc_1_1_hvc(...) __arm_smccc_1_1(SMCCC_HVC_INST, __VA_ARGS__) + #endif /*__ASSEMBLY__*/ #endif /*__LINUX_ARM_SMCCC_H*/ -- GitLab From c24c205d2528e09379c2129cc33773221269feb0 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:37 +0100 Subject: [PATCH 1375/1834] arm64: Add ARM_SMCCC_ARCH_WORKAROUND_1 BP hardening support From: Marc Zyngier commit b092201e0020614127f495c092e0a12d26a2116e upstream. Add the detection and runtime code for ARM_SMCCC_ARCH_WORKAROUND_1. It is lovely. Really. Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/crypto/sha256-core.S | 2061 +++++++++++++++++++++++++++++++ arch/arm64/crypto/sha512-core.S | 1085 ++++++++++++++++ arch/arm64/kernel/bpi.S | 20 + arch/arm64/kernel/cpu_errata.c | 72 +- 4 files changed, 3235 insertions(+), 3 deletions(-) create mode 100644 arch/arm64/crypto/sha256-core.S create mode 100644 arch/arm64/crypto/sha512-core.S diff --git a/arch/arm64/crypto/sha256-core.S b/arch/arm64/crypto/sha256-core.S new file mode 100644 index 000000000000..3ce82cc860bc --- /dev/null +++ b/arch/arm64/crypto/sha256-core.S @@ -0,0 +1,2061 @@ +// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved. +// +// Licensed under the OpenSSL license (the "License"). You may not use +// this file except in compliance with the License. You can obtain a copy +// in the file LICENSE in the source distribution or at +// https://www.openssl.org/source/license.html + +// ==================================================================== +// Written by Andy Polyakov for the OpenSSL +// project. The module is, however, dual licensed under OpenSSL and +// CRYPTOGAMS licenses depending on where you obtain it. For further +// details see http://www.openssl.org/~appro/cryptogams/. +// +// Permission to use under GPLv2 terms is granted. +// ==================================================================== +// +// SHA256/512 for ARMv8. +// +// Performance in cycles per processed byte and improvement coefficient +// over code generated with "default" compiler: +// +// SHA256-hw SHA256(*) SHA512 +// Apple A7 1.97 10.5 (+33%) 6.73 (-1%(**)) +// Cortex-A53 2.38 15.5 (+115%) 10.0 (+150%(***)) +// Cortex-A57 2.31 11.6 (+86%) 7.51 (+260%(***)) +// Denver 2.01 10.5 (+26%) 6.70 (+8%) +// X-Gene 20.0 (+100%) 12.8 (+300%(***)) +// Mongoose 2.36 13.0 (+50%) 8.36 (+33%) +// +// (*) Software SHA256 results are of lesser relevance, presented +// mostly for informational purposes. +// (**) The result is a trade-off: it's possible to improve it by +// 10% (or by 1 cycle per round), but at the cost of 20% loss +// on Cortex-A53 (or by 4 cycles per round). +// (***) Super-impressive coefficients over gcc-generated code are +// indication of some compiler "pathology", most notably code +// generated with -mgeneral-regs-only is significanty faster +// and the gap is only 40-90%. +// +// October 2016. +// +// Originally it was reckoned that it makes no sense to implement NEON +// version of SHA256 for 64-bit processors. This is because performance +// improvement on most wide-spread Cortex-A5x processors was observed +// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was +// observed that 32-bit NEON SHA256 performs significantly better than +// 64-bit scalar version on *some* of the more recent processors. As +// result 64-bit NEON version of SHA256 was added to provide best +// all-round performance. For example it executes ~30% faster on X-Gene +// and Mongoose. [For reference, NEON version of SHA512 is bound to +// deliver much less improvement, likely *negative* on Cortex-A5x. +// Which is why NEON support is limited to SHA256.] + +#ifndef __KERNEL__ +# include "arm_arch.h" +#endif + +.text + +.extern OPENSSL_armcap_P +.globl sha256_block_data_order +.type sha256_block_data_order,%function +.align 6 +sha256_block_data_order: +#ifndef __KERNEL__ +# ifdef __ILP32__ + ldrsw x16,.LOPENSSL_armcap_P +# else + ldr x16,.LOPENSSL_armcap_P +# endif + adr x17,.LOPENSSL_armcap_P + add x16,x16,x17 + ldr w16,[x16] + tst w16,#ARMV8_SHA256 + b.ne .Lv8_entry + tst w16,#ARMV7_NEON + b.ne .Lneon_entry +#endif + stp x29,x30,[sp,#-128]! + add x29,sp,#0 + + stp x19,x20,[sp,#16] + stp x21,x22,[sp,#32] + stp x23,x24,[sp,#48] + stp x25,x26,[sp,#64] + stp x27,x28,[sp,#80] + sub sp,sp,#4*4 + + ldp w20,w21,[x0] // load context + ldp w22,w23,[x0,#2*4] + ldp w24,w25,[x0,#4*4] + add x2,x1,x2,lsl#6 // end of input + ldp w26,w27,[x0,#6*4] + adr x30,.LK256 + stp x0,x2,[x29,#96] + +.Loop: + ldp w3,w4,[x1],#2*4 + ldr w19,[x30],#4 // *K++ + eor w28,w21,w22 // magic seed + str x1,[x29,#112] +#ifndef __AARCH64EB__ + rev w3,w3 // 0 +#endif + ror w16,w24,#6 + add w27,w27,w19 // h+=K[i] + eor w6,w24,w24,ror#14 + and w17,w25,w24 + bic w19,w26,w24 + add w27,w27,w3 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w20,w21 // a^b, b^c in next round + eor w16,w16,w6,ror#11 // Sigma1(e) + ror w6,w20,#2 + add w27,w27,w17 // h+=Ch(e,f,g) + eor w17,w20,w20,ror#9 + add w27,w27,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w23,w23,w27 // d+=h + eor w28,w28,w21 // Maj(a,b,c) + eor w17,w6,w17,ror#13 // Sigma0(a) + add w27,w27,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w27,w27,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w4,w4 // 1 +#endif + ldp w5,w6,[x1],#2*4 + add w27,w27,w17 // h+=Sigma0(a) + ror w16,w23,#6 + add w26,w26,w28 // h+=K[i] + eor w7,w23,w23,ror#14 + and w17,w24,w23 + bic w28,w25,w23 + add w26,w26,w4 // h+=X[i] + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w27,w20 // a^b, b^c in next round + eor w16,w16,w7,ror#11 // Sigma1(e) + ror w7,w27,#2 + add w26,w26,w17 // h+=Ch(e,f,g) + eor w17,w27,w27,ror#9 + add w26,w26,w16 // h+=Sigma1(e) + and w19,w19,w28 // (b^c)&=(a^b) + add w22,w22,w26 // d+=h + eor w19,w19,w20 // Maj(a,b,c) + eor w17,w7,w17,ror#13 // Sigma0(a) + add w26,w26,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + //add w26,w26,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w5,w5 // 2 +#endif + add w26,w26,w17 // h+=Sigma0(a) + ror w16,w22,#6 + add w25,w25,w19 // h+=K[i] + eor w8,w22,w22,ror#14 + and w17,w23,w22 + bic w19,w24,w22 + add w25,w25,w5 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w26,w27 // a^b, b^c in next round + eor w16,w16,w8,ror#11 // Sigma1(e) + ror w8,w26,#2 + add w25,w25,w17 // h+=Ch(e,f,g) + eor w17,w26,w26,ror#9 + add w25,w25,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w21,w21,w25 // d+=h + eor w28,w28,w27 // Maj(a,b,c) + eor w17,w8,w17,ror#13 // Sigma0(a) + add w25,w25,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w25,w25,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w6,w6 // 3 +#endif + ldp w7,w8,[x1],#2*4 + add w25,w25,w17 // h+=Sigma0(a) + ror w16,w21,#6 + add w24,w24,w28 // h+=K[i] + eor w9,w21,w21,ror#14 + and w17,w22,w21 + bic w28,w23,w21 + add w24,w24,w6 // h+=X[i] + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w25,w26 // a^b, b^c in next round + eor w16,w16,w9,ror#11 // Sigma1(e) + ror w9,w25,#2 + add w24,w24,w17 // h+=Ch(e,f,g) + eor w17,w25,w25,ror#9 + add w24,w24,w16 // h+=Sigma1(e) + and w19,w19,w28 // (b^c)&=(a^b) + add w20,w20,w24 // d+=h + eor w19,w19,w26 // Maj(a,b,c) + eor w17,w9,w17,ror#13 // Sigma0(a) + add w24,w24,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + //add w24,w24,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w7,w7 // 4 +#endif + add w24,w24,w17 // h+=Sigma0(a) + ror w16,w20,#6 + add w23,w23,w19 // h+=K[i] + eor w10,w20,w20,ror#14 + and w17,w21,w20 + bic w19,w22,w20 + add w23,w23,w7 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w24,w25 // a^b, b^c in next round + eor w16,w16,w10,ror#11 // Sigma1(e) + ror w10,w24,#2 + add w23,w23,w17 // h+=Ch(e,f,g) + eor w17,w24,w24,ror#9 + add w23,w23,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w27,w27,w23 // d+=h + eor w28,w28,w25 // Maj(a,b,c) + eor w17,w10,w17,ror#13 // Sigma0(a) + add w23,w23,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w23,w23,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w8,w8 // 5 +#endif + ldp w9,w10,[x1],#2*4 + add w23,w23,w17 // h+=Sigma0(a) + ror w16,w27,#6 + add w22,w22,w28 // h+=K[i] + eor w11,w27,w27,ror#14 + and w17,w20,w27 + bic w28,w21,w27 + add w22,w22,w8 // h+=X[i] + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w23,w24 // a^b, b^c in next round + eor w16,w16,w11,ror#11 // Sigma1(e) + ror w11,w23,#2 + add w22,w22,w17 // h+=Ch(e,f,g) + eor w17,w23,w23,ror#9 + add w22,w22,w16 // h+=Sigma1(e) + and w19,w19,w28 // (b^c)&=(a^b) + add w26,w26,w22 // d+=h + eor w19,w19,w24 // Maj(a,b,c) + eor w17,w11,w17,ror#13 // Sigma0(a) + add w22,w22,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + //add w22,w22,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w9,w9 // 6 +#endif + add w22,w22,w17 // h+=Sigma0(a) + ror w16,w26,#6 + add w21,w21,w19 // h+=K[i] + eor w12,w26,w26,ror#14 + and w17,w27,w26 + bic w19,w20,w26 + add w21,w21,w9 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w22,w23 // a^b, b^c in next round + eor w16,w16,w12,ror#11 // Sigma1(e) + ror w12,w22,#2 + add w21,w21,w17 // h+=Ch(e,f,g) + eor w17,w22,w22,ror#9 + add w21,w21,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w25,w25,w21 // d+=h + eor w28,w28,w23 // Maj(a,b,c) + eor w17,w12,w17,ror#13 // Sigma0(a) + add w21,w21,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w21,w21,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w10,w10 // 7 +#endif + ldp w11,w12,[x1],#2*4 + add w21,w21,w17 // h+=Sigma0(a) + ror w16,w25,#6 + add w20,w20,w28 // h+=K[i] + eor w13,w25,w25,ror#14 + and w17,w26,w25 + bic w28,w27,w25 + add w20,w20,w10 // h+=X[i] + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w21,w22 // a^b, b^c in next round + eor w16,w16,w13,ror#11 // Sigma1(e) + ror w13,w21,#2 + add w20,w20,w17 // h+=Ch(e,f,g) + eor w17,w21,w21,ror#9 + add w20,w20,w16 // h+=Sigma1(e) + and w19,w19,w28 // (b^c)&=(a^b) + add w24,w24,w20 // d+=h + eor w19,w19,w22 // Maj(a,b,c) + eor w17,w13,w17,ror#13 // Sigma0(a) + add w20,w20,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + //add w20,w20,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w11,w11 // 8 +#endif + add w20,w20,w17 // h+=Sigma0(a) + ror w16,w24,#6 + add w27,w27,w19 // h+=K[i] + eor w14,w24,w24,ror#14 + and w17,w25,w24 + bic w19,w26,w24 + add w27,w27,w11 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w20,w21 // a^b, b^c in next round + eor w16,w16,w14,ror#11 // Sigma1(e) + ror w14,w20,#2 + add w27,w27,w17 // h+=Ch(e,f,g) + eor w17,w20,w20,ror#9 + add w27,w27,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w23,w23,w27 // d+=h + eor w28,w28,w21 // Maj(a,b,c) + eor w17,w14,w17,ror#13 // Sigma0(a) + add w27,w27,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w27,w27,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w12,w12 // 9 +#endif + ldp w13,w14,[x1],#2*4 + add w27,w27,w17 // h+=Sigma0(a) + ror w16,w23,#6 + add w26,w26,w28 // h+=K[i] + eor w15,w23,w23,ror#14 + and w17,w24,w23 + bic w28,w25,w23 + add w26,w26,w12 // h+=X[i] + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w27,w20 // a^b, b^c in next round + eor w16,w16,w15,ror#11 // Sigma1(e) + ror w15,w27,#2 + add w26,w26,w17 // h+=Ch(e,f,g) + eor w17,w27,w27,ror#9 + add w26,w26,w16 // h+=Sigma1(e) + and w19,w19,w28 // (b^c)&=(a^b) + add w22,w22,w26 // d+=h + eor w19,w19,w20 // Maj(a,b,c) + eor w17,w15,w17,ror#13 // Sigma0(a) + add w26,w26,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + //add w26,w26,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w13,w13 // 10 +#endif + add w26,w26,w17 // h+=Sigma0(a) + ror w16,w22,#6 + add w25,w25,w19 // h+=K[i] + eor w0,w22,w22,ror#14 + and w17,w23,w22 + bic w19,w24,w22 + add w25,w25,w13 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w26,w27 // a^b, b^c in next round + eor w16,w16,w0,ror#11 // Sigma1(e) + ror w0,w26,#2 + add w25,w25,w17 // h+=Ch(e,f,g) + eor w17,w26,w26,ror#9 + add w25,w25,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w21,w21,w25 // d+=h + eor w28,w28,w27 // Maj(a,b,c) + eor w17,w0,w17,ror#13 // Sigma0(a) + add w25,w25,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w25,w25,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w14,w14 // 11 +#endif + ldp w15,w0,[x1],#2*4 + add w25,w25,w17 // h+=Sigma0(a) + str w6,[sp,#12] + ror w16,w21,#6 + add w24,w24,w28 // h+=K[i] + eor w6,w21,w21,ror#14 + and w17,w22,w21 + bic w28,w23,w21 + add w24,w24,w14 // h+=X[i] + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w25,w26 // a^b, b^c in next round + eor w16,w16,w6,ror#11 // Sigma1(e) + ror w6,w25,#2 + add w24,w24,w17 // h+=Ch(e,f,g) + eor w17,w25,w25,ror#9 + add w24,w24,w16 // h+=Sigma1(e) + and w19,w19,w28 // (b^c)&=(a^b) + add w20,w20,w24 // d+=h + eor w19,w19,w26 // Maj(a,b,c) + eor w17,w6,w17,ror#13 // Sigma0(a) + add w24,w24,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + //add w24,w24,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w15,w15 // 12 +#endif + add w24,w24,w17 // h+=Sigma0(a) + str w7,[sp,#0] + ror w16,w20,#6 + add w23,w23,w19 // h+=K[i] + eor w7,w20,w20,ror#14 + and w17,w21,w20 + bic w19,w22,w20 + add w23,w23,w15 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w24,w25 // a^b, b^c in next round + eor w16,w16,w7,ror#11 // Sigma1(e) + ror w7,w24,#2 + add w23,w23,w17 // h+=Ch(e,f,g) + eor w17,w24,w24,ror#9 + add w23,w23,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w27,w27,w23 // d+=h + eor w28,w28,w25 // Maj(a,b,c) + eor w17,w7,w17,ror#13 // Sigma0(a) + add w23,w23,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w23,w23,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w0,w0 // 13 +#endif + ldp w1,w2,[x1] + add w23,w23,w17 // h+=Sigma0(a) + str w8,[sp,#4] + ror w16,w27,#6 + add w22,w22,w28 // h+=K[i] + eor w8,w27,w27,ror#14 + and w17,w20,w27 + bic w28,w21,w27 + add w22,w22,w0 // h+=X[i] + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w23,w24 // a^b, b^c in next round + eor w16,w16,w8,ror#11 // Sigma1(e) + ror w8,w23,#2 + add w22,w22,w17 // h+=Ch(e,f,g) + eor w17,w23,w23,ror#9 + add w22,w22,w16 // h+=Sigma1(e) + and w19,w19,w28 // (b^c)&=(a^b) + add w26,w26,w22 // d+=h + eor w19,w19,w24 // Maj(a,b,c) + eor w17,w8,w17,ror#13 // Sigma0(a) + add w22,w22,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + //add w22,w22,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w1,w1 // 14 +#endif + ldr w6,[sp,#12] + add w22,w22,w17 // h+=Sigma0(a) + str w9,[sp,#8] + ror w16,w26,#6 + add w21,w21,w19 // h+=K[i] + eor w9,w26,w26,ror#14 + and w17,w27,w26 + bic w19,w20,w26 + add w21,w21,w1 // h+=X[i] + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w22,w23 // a^b, b^c in next round + eor w16,w16,w9,ror#11 // Sigma1(e) + ror w9,w22,#2 + add w21,w21,w17 // h+=Ch(e,f,g) + eor w17,w22,w22,ror#9 + add w21,w21,w16 // h+=Sigma1(e) + and w28,w28,w19 // (b^c)&=(a^b) + add w25,w25,w21 // d+=h + eor w28,w28,w23 // Maj(a,b,c) + eor w17,w9,w17,ror#13 // Sigma0(a) + add w21,w21,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + //add w21,w21,w17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev w2,w2 // 15 +#endif + ldr w7,[sp,#0] + add w21,w21,w17 // h+=Sigma0(a) + str w10,[sp,#12] + ror w16,w25,#6 + add w20,w20,w28 // h+=K[i] + ror w9,w4,#7 + and w17,w26,w25 + ror w8,w1,#17 + bic w28,w27,w25 + ror w10,w21,#2 + add w20,w20,w2 // h+=X[i] + eor w16,w16,w25,ror#11 + eor w9,w9,w4,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w21,w22 // a^b, b^c in next round + eor w16,w16,w25,ror#25 // Sigma1(e) + eor w10,w10,w21,ror#13 + add w20,w20,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w8,w8,w1,ror#19 + eor w9,w9,w4,lsr#3 // sigma0(X[i+1]) + add w20,w20,w16 // h+=Sigma1(e) + eor w19,w19,w22 // Maj(a,b,c) + eor w17,w10,w21,ror#22 // Sigma0(a) + eor w8,w8,w1,lsr#10 // sigma1(X[i+14]) + add w3,w3,w12 + add w24,w24,w20 // d+=h + add w20,w20,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w3,w3,w9 + add w20,w20,w17 // h+=Sigma0(a) + add w3,w3,w8 +.Loop_16_xx: + ldr w8,[sp,#4] + str w11,[sp,#0] + ror w16,w24,#6 + add w27,w27,w19 // h+=K[i] + ror w10,w5,#7 + and w17,w25,w24 + ror w9,w2,#17 + bic w19,w26,w24 + ror w11,w20,#2 + add w27,w27,w3 // h+=X[i] + eor w16,w16,w24,ror#11 + eor w10,w10,w5,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w20,w21 // a^b, b^c in next round + eor w16,w16,w24,ror#25 // Sigma1(e) + eor w11,w11,w20,ror#13 + add w27,w27,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w9,w9,w2,ror#19 + eor w10,w10,w5,lsr#3 // sigma0(X[i+1]) + add w27,w27,w16 // h+=Sigma1(e) + eor w28,w28,w21 // Maj(a,b,c) + eor w17,w11,w20,ror#22 // Sigma0(a) + eor w9,w9,w2,lsr#10 // sigma1(X[i+14]) + add w4,w4,w13 + add w23,w23,w27 // d+=h + add w27,w27,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w4,w4,w10 + add w27,w27,w17 // h+=Sigma0(a) + add w4,w4,w9 + ldr w9,[sp,#8] + str w12,[sp,#4] + ror w16,w23,#6 + add w26,w26,w28 // h+=K[i] + ror w11,w6,#7 + and w17,w24,w23 + ror w10,w3,#17 + bic w28,w25,w23 + ror w12,w27,#2 + add w26,w26,w4 // h+=X[i] + eor w16,w16,w23,ror#11 + eor w11,w11,w6,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w27,w20 // a^b, b^c in next round + eor w16,w16,w23,ror#25 // Sigma1(e) + eor w12,w12,w27,ror#13 + add w26,w26,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w10,w10,w3,ror#19 + eor w11,w11,w6,lsr#3 // sigma0(X[i+1]) + add w26,w26,w16 // h+=Sigma1(e) + eor w19,w19,w20 // Maj(a,b,c) + eor w17,w12,w27,ror#22 // Sigma0(a) + eor w10,w10,w3,lsr#10 // sigma1(X[i+14]) + add w5,w5,w14 + add w22,w22,w26 // d+=h + add w26,w26,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w5,w5,w11 + add w26,w26,w17 // h+=Sigma0(a) + add w5,w5,w10 + ldr w10,[sp,#12] + str w13,[sp,#8] + ror w16,w22,#6 + add w25,w25,w19 // h+=K[i] + ror w12,w7,#7 + and w17,w23,w22 + ror w11,w4,#17 + bic w19,w24,w22 + ror w13,w26,#2 + add w25,w25,w5 // h+=X[i] + eor w16,w16,w22,ror#11 + eor w12,w12,w7,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w26,w27 // a^b, b^c in next round + eor w16,w16,w22,ror#25 // Sigma1(e) + eor w13,w13,w26,ror#13 + add w25,w25,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w11,w11,w4,ror#19 + eor w12,w12,w7,lsr#3 // sigma0(X[i+1]) + add w25,w25,w16 // h+=Sigma1(e) + eor w28,w28,w27 // Maj(a,b,c) + eor w17,w13,w26,ror#22 // Sigma0(a) + eor w11,w11,w4,lsr#10 // sigma1(X[i+14]) + add w6,w6,w15 + add w21,w21,w25 // d+=h + add w25,w25,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w6,w6,w12 + add w25,w25,w17 // h+=Sigma0(a) + add w6,w6,w11 + ldr w11,[sp,#0] + str w14,[sp,#12] + ror w16,w21,#6 + add w24,w24,w28 // h+=K[i] + ror w13,w8,#7 + and w17,w22,w21 + ror w12,w5,#17 + bic w28,w23,w21 + ror w14,w25,#2 + add w24,w24,w6 // h+=X[i] + eor w16,w16,w21,ror#11 + eor w13,w13,w8,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w25,w26 // a^b, b^c in next round + eor w16,w16,w21,ror#25 // Sigma1(e) + eor w14,w14,w25,ror#13 + add w24,w24,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w12,w12,w5,ror#19 + eor w13,w13,w8,lsr#3 // sigma0(X[i+1]) + add w24,w24,w16 // h+=Sigma1(e) + eor w19,w19,w26 // Maj(a,b,c) + eor w17,w14,w25,ror#22 // Sigma0(a) + eor w12,w12,w5,lsr#10 // sigma1(X[i+14]) + add w7,w7,w0 + add w20,w20,w24 // d+=h + add w24,w24,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w7,w7,w13 + add w24,w24,w17 // h+=Sigma0(a) + add w7,w7,w12 + ldr w12,[sp,#4] + str w15,[sp,#0] + ror w16,w20,#6 + add w23,w23,w19 // h+=K[i] + ror w14,w9,#7 + and w17,w21,w20 + ror w13,w6,#17 + bic w19,w22,w20 + ror w15,w24,#2 + add w23,w23,w7 // h+=X[i] + eor w16,w16,w20,ror#11 + eor w14,w14,w9,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w24,w25 // a^b, b^c in next round + eor w16,w16,w20,ror#25 // Sigma1(e) + eor w15,w15,w24,ror#13 + add w23,w23,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w13,w13,w6,ror#19 + eor w14,w14,w9,lsr#3 // sigma0(X[i+1]) + add w23,w23,w16 // h+=Sigma1(e) + eor w28,w28,w25 // Maj(a,b,c) + eor w17,w15,w24,ror#22 // Sigma0(a) + eor w13,w13,w6,lsr#10 // sigma1(X[i+14]) + add w8,w8,w1 + add w27,w27,w23 // d+=h + add w23,w23,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w8,w8,w14 + add w23,w23,w17 // h+=Sigma0(a) + add w8,w8,w13 + ldr w13,[sp,#8] + str w0,[sp,#4] + ror w16,w27,#6 + add w22,w22,w28 // h+=K[i] + ror w15,w10,#7 + and w17,w20,w27 + ror w14,w7,#17 + bic w28,w21,w27 + ror w0,w23,#2 + add w22,w22,w8 // h+=X[i] + eor w16,w16,w27,ror#11 + eor w15,w15,w10,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w23,w24 // a^b, b^c in next round + eor w16,w16,w27,ror#25 // Sigma1(e) + eor w0,w0,w23,ror#13 + add w22,w22,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w14,w14,w7,ror#19 + eor w15,w15,w10,lsr#3 // sigma0(X[i+1]) + add w22,w22,w16 // h+=Sigma1(e) + eor w19,w19,w24 // Maj(a,b,c) + eor w17,w0,w23,ror#22 // Sigma0(a) + eor w14,w14,w7,lsr#10 // sigma1(X[i+14]) + add w9,w9,w2 + add w26,w26,w22 // d+=h + add w22,w22,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w9,w9,w15 + add w22,w22,w17 // h+=Sigma0(a) + add w9,w9,w14 + ldr w14,[sp,#12] + str w1,[sp,#8] + ror w16,w26,#6 + add w21,w21,w19 // h+=K[i] + ror w0,w11,#7 + and w17,w27,w26 + ror w15,w8,#17 + bic w19,w20,w26 + ror w1,w22,#2 + add w21,w21,w9 // h+=X[i] + eor w16,w16,w26,ror#11 + eor w0,w0,w11,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w22,w23 // a^b, b^c in next round + eor w16,w16,w26,ror#25 // Sigma1(e) + eor w1,w1,w22,ror#13 + add w21,w21,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w15,w15,w8,ror#19 + eor w0,w0,w11,lsr#3 // sigma0(X[i+1]) + add w21,w21,w16 // h+=Sigma1(e) + eor w28,w28,w23 // Maj(a,b,c) + eor w17,w1,w22,ror#22 // Sigma0(a) + eor w15,w15,w8,lsr#10 // sigma1(X[i+14]) + add w10,w10,w3 + add w25,w25,w21 // d+=h + add w21,w21,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w10,w10,w0 + add w21,w21,w17 // h+=Sigma0(a) + add w10,w10,w15 + ldr w15,[sp,#0] + str w2,[sp,#12] + ror w16,w25,#6 + add w20,w20,w28 // h+=K[i] + ror w1,w12,#7 + and w17,w26,w25 + ror w0,w9,#17 + bic w28,w27,w25 + ror w2,w21,#2 + add w20,w20,w10 // h+=X[i] + eor w16,w16,w25,ror#11 + eor w1,w1,w12,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w21,w22 // a^b, b^c in next round + eor w16,w16,w25,ror#25 // Sigma1(e) + eor w2,w2,w21,ror#13 + add w20,w20,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w0,w0,w9,ror#19 + eor w1,w1,w12,lsr#3 // sigma0(X[i+1]) + add w20,w20,w16 // h+=Sigma1(e) + eor w19,w19,w22 // Maj(a,b,c) + eor w17,w2,w21,ror#22 // Sigma0(a) + eor w0,w0,w9,lsr#10 // sigma1(X[i+14]) + add w11,w11,w4 + add w24,w24,w20 // d+=h + add w20,w20,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w11,w11,w1 + add w20,w20,w17 // h+=Sigma0(a) + add w11,w11,w0 + ldr w0,[sp,#4] + str w3,[sp,#0] + ror w16,w24,#6 + add w27,w27,w19 // h+=K[i] + ror w2,w13,#7 + and w17,w25,w24 + ror w1,w10,#17 + bic w19,w26,w24 + ror w3,w20,#2 + add w27,w27,w11 // h+=X[i] + eor w16,w16,w24,ror#11 + eor w2,w2,w13,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w20,w21 // a^b, b^c in next round + eor w16,w16,w24,ror#25 // Sigma1(e) + eor w3,w3,w20,ror#13 + add w27,w27,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w1,w1,w10,ror#19 + eor w2,w2,w13,lsr#3 // sigma0(X[i+1]) + add w27,w27,w16 // h+=Sigma1(e) + eor w28,w28,w21 // Maj(a,b,c) + eor w17,w3,w20,ror#22 // Sigma0(a) + eor w1,w1,w10,lsr#10 // sigma1(X[i+14]) + add w12,w12,w5 + add w23,w23,w27 // d+=h + add w27,w27,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w12,w12,w2 + add w27,w27,w17 // h+=Sigma0(a) + add w12,w12,w1 + ldr w1,[sp,#8] + str w4,[sp,#4] + ror w16,w23,#6 + add w26,w26,w28 // h+=K[i] + ror w3,w14,#7 + and w17,w24,w23 + ror w2,w11,#17 + bic w28,w25,w23 + ror w4,w27,#2 + add w26,w26,w12 // h+=X[i] + eor w16,w16,w23,ror#11 + eor w3,w3,w14,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w27,w20 // a^b, b^c in next round + eor w16,w16,w23,ror#25 // Sigma1(e) + eor w4,w4,w27,ror#13 + add w26,w26,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w2,w2,w11,ror#19 + eor w3,w3,w14,lsr#3 // sigma0(X[i+1]) + add w26,w26,w16 // h+=Sigma1(e) + eor w19,w19,w20 // Maj(a,b,c) + eor w17,w4,w27,ror#22 // Sigma0(a) + eor w2,w2,w11,lsr#10 // sigma1(X[i+14]) + add w13,w13,w6 + add w22,w22,w26 // d+=h + add w26,w26,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w13,w13,w3 + add w26,w26,w17 // h+=Sigma0(a) + add w13,w13,w2 + ldr w2,[sp,#12] + str w5,[sp,#8] + ror w16,w22,#6 + add w25,w25,w19 // h+=K[i] + ror w4,w15,#7 + and w17,w23,w22 + ror w3,w12,#17 + bic w19,w24,w22 + ror w5,w26,#2 + add w25,w25,w13 // h+=X[i] + eor w16,w16,w22,ror#11 + eor w4,w4,w15,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w26,w27 // a^b, b^c in next round + eor w16,w16,w22,ror#25 // Sigma1(e) + eor w5,w5,w26,ror#13 + add w25,w25,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w3,w3,w12,ror#19 + eor w4,w4,w15,lsr#3 // sigma0(X[i+1]) + add w25,w25,w16 // h+=Sigma1(e) + eor w28,w28,w27 // Maj(a,b,c) + eor w17,w5,w26,ror#22 // Sigma0(a) + eor w3,w3,w12,lsr#10 // sigma1(X[i+14]) + add w14,w14,w7 + add w21,w21,w25 // d+=h + add w25,w25,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w14,w14,w4 + add w25,w25,w17 // h+=Sigma0(a) + add w14,w14,w3 + ldr w3,[sp,#0] + str w6,[sp,#12] + ror w16,w21,#6 + add w24,w24,w28 // h+=K[i] + ror w5,w0,#7 + and w17,w22,w21 + ror w4,w13,#17 + bic w28,w23,w21 + ror w6,w25,#2 + add w24,w24,w14 // h+=X[i] + eor w16,w16,w21,ror#11 + eor w5,w5,w0,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w25,w26 // a^b, b^c in next round + eor w16,w16,w21,ror#25 // Sigma1(e) + eor w6,w6,w25,ror#13 + add w24,w24,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w4,w4,w13,ror#19 + eor w5,w5,w0,lsr#3 // sigma0(X[i+1]) + add w24,w24,w16 // h+=Sigma1(e) + eor w19,w19,w26 // Maj(a,b,c) + eor w17,w6,w25,ror#22 // Sigma0(a) + eor w4,w4,w13,lsr#10 // sigma1(X[i+14]) + add w15,w15,w8 + add w20,w20,w24 // d+=h + add w24,w24,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w15,w15,w5 + add w24,w24,w17 // h+=Sigma0(a) + add w15,w15,w4 + ldr w4,[sp,#4] + str w7,[sp,#0] + ror w16,w20,#6 + add w23,w23,w19 // h+=K[i] + ror w6,w1,#7 + and w17,w21,w20 + ror w5,w14,#17 + bic w19,w22,w20 + ror w7,w24,#2 + add w23,w23,w15 // h+=X[i] + eor w16,w16,w20,ror#11 + eor w6,w6,w1,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w24,w25 // a^b, b^c in next round + eor w16,w16,w20,ror#25 // Sigma1(e) + eor w7,w7,w24,ror#13 + add w23,w23,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w5,w5,w14,ror#19 + eor w6,w6,w1,lsr#3 // sigma0(X[i+1]) + add w23,w23,w16 // h+=Sigma1(e) + eor w28,w28,w25 // Maj(a,b,c) + eor w17,w7,w24,ror#22 // Sigma0(a) + eor w5,w5,w14,lsr#10 // sigma1(X[i+14]) + add w0,w0,w9 + add w27,w27,w23 // d+=h + add w23,w23,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w0,w0,w6 + add w23,w23,w17 // h+=Sigma0(a) + add w0,w0,w5 + ldr w5,[sp,#8] + str w8,[sp,#4] + ror w16,w27,#6 + add w22,w22,w28 // h+=K[i] + ror w7,w2,#7 + and w17,w20,w27 + ror w6,w15,#17 + bic w28,w21,w27 + ror w8,w23,#2 + add w22,w22,w0 // h+=X[i] + eor w16,w16,w27,ror#11 + eor w7,w7,w2,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w23,w24 // a^b, b^c in next round + eor w16,w16,w27,ror#25 // Sigma1(e) + eor w8,w8,w23,ror#13 + add w22,w22,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w6,w6,w15,ror#19 + eor w7,w7,w2,lsr#3 // sigma0(X[i+1]) + add w22,w22,w16 // h+=Sigma1(e) + eor w19,w19,w24 // Maj(a,b,c) + eor w17,w8,w23,ror#22 // Sigma0(a) + eor w6,w6,w15,lsr#10 // sigma1(X[i+14]) + add w1,w1,w10 + add w26,w26,w22 // d+=h + add w22,w22,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w1,w1,w7 + add w22,w22,w17 // h+=Sigma0(a) + add w1,w1,w6 + ldr w6,[sp,#12] + str w9,[sp,#8] + ror w16,w26,#6 + add w21,w21,w19 // h+=K[i] + ror w8,w3,#7 + and w17,w27,w26 + ror w7,w0,#17 + bic w19,w20,w26 + ror w9,w22,#2 + add w21,w21,w1 // h+=X[i] + eor w16,w16,w26,ror#11 + eor w8,w8,w3,ror#18 + orr w17,w17,w19 // Ch(e,f,g) + eor w19,w22,w23 // a^b, b^c in next round + eor w16,w16,w26,ror#25 // Sigma1(e) + eor w9,w9,w22,ror#13 + add w21,w21,w17 // h+=Ch(e,f,g) + and w28,w28,w19 // (b^c)&=(a^b) + eor w7,w7,w0,ror#19 + eor w8,w8,w3,lsr#3 // sigma0(X[i+1]) + add w21,w21,w16 // h+=Sigma1(e) + eor w28,w28,w23 // Maj(a,b,c) + eor w17,w9,w22,ror#22 // Sigma0(a) + eor w7,w7,w0,lsr#10 // sigma1(X[i+14]) + add w2,w2,w11 + add w25,w25,w21 // d+=h + add w21,w21,w28 // h+=Maj(a,b,c) + ldr w28,[x30],#4 // *K++, w19 in next round + add w2,w2,w8 + add w21,w21,w17 // h+=Sigma0(a) + add w2,w2,w7 + ldr w7,[sp,#0] + str w10,[sp,#12] + ror w16,w25,#6 + add w20,w20,w28 // h+=K[i] + ror w9,w4,#7 + and w17,w26,w25 + ror w8,w1,#17 + bic w28,w27,w25 + ror w10,w21,#2 + add w20,w20,w2 // h+=X[i] + eor w16,w16,w25,ror#11 + eor w9,w9,w4,ror#18 + orr w17,w17,w28 // Ch(e,f,g) + eor w28,w21,w22 // a^b, b^c in next round + eor w16,w16,w25,ror#25 // Sigma1(e) + eor w10,w10,w21,ror#13 + add w20,w20,w17 // h+=Ch(e,f,g) + and w19,w19,w28 // (b^c)&=(a^b) + eor w8,w8,w1,ror#19 + eor w9,w9,w4,lsr#3 // sigma0(X[i+1]) + add w20,w20,w16 // h+=Sigma1(e) + eor w19,w19,w22 // Maj(a,b,c) + eor w17,w10,w21,ror#22 // Sigma0(a) + eor w8,w8,w1,lsr#10 // sigma1(X[i+14]) + add w3,w3,w12 + add w24,w24,w20 // d+=h + add w20,w20,w19 // h+=Maj(a,b,c) + ldr w19,[x30],#4 // *K++, w28 in next round + add w3,w3,w9 + add w20,w20,w17 // h+=Sigma0(a) + add w3,w3,w8 + cbnz w19,.Loop_16_xx + + ldp x0,x2,[x29,#96] + ldr x1,[x29,#112] + sub x30,x30,#260 // rewind + + ldp w3,w4,[x0] + ldp w5,w6,[x0,#2*4] + add x1,x1,#14*4 // advance input pointer + ldp w7,w8,[x0,#4*4] + add w20,w20,w3 + ldp w9,w10,[x0,#6*4] + add w21,w21,w4 + add w22,w22,w5 + add w23,w23,w6 + stp w20,w21,[x0] + add w24,w24,w7 + add w25,w25,w8 + stp w22,w23,[x0,#2*4] + add w26,w26,w9 + add w27,w27,w10 + cmp x1,x2 + stp w24,w25,[x0,#4*4] + stp w26,w27,[x0,#6*4] + b.ne .Loop + + ldp x19,x20,[x29,#16] + add sp,sp,#4*4 + ldp x21,x22,[x29,#32] + ldp x23,x24,[x29,#48] + ldp x25,x26,[x29,#64] + ldp x27,x28,[x29,#80] + ldp x29,x30,[sp],#128 + ret +.size sha256_block_data_order,.-sha256_block_data_order + +.align 6 +.type .LK256,%object +.LK256: + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + .long 0 //terminator +.size .LK256,.-.LK256 +#ifndef __KERNEL__ +.align 3 +.LOPENSSL_armcap_P: +# ifdef __ILP32__ + .long OPENSSL_armcap_P-. +# else + .quad OPENSSL_armcap_P-. +# endif +#endif +.asciz "SHA256 block transform for ARMv8, CRYPTOGAMS by " +.align 2 +#ifndef __KERNEL__ +.type sha256_block_armv8,%function +.align 6 +sha256_block_armv8: +.Lv8_entry: + stp x29,x30,[sp,#-16]! + add x29,sp,#0 + + ld1 {v0.4s,v1.4s},[x0] + adr x3,.LK256 + +.Loop_hw: + ld1 {v4.16b-v7.16b},[x1],#64 + sub x2,x2,#1 + ld1 {v16.4s},[x3],#16 + rev32 v4.16b,v4.16b + rev32 v5.16b,v5.16b + rev32 v6.16b,v6.16b + rev32 v7.16b,v7.16b + orr v18.16b,v0.16b,v0.16b // offload + orr v19.16b,v1.16b,v1.16b + ld1 {v17.4s},[x3],#16 + add v16.4s,v16.4s,v4.4s + .inst 0x5e2828a4 //sha256su0 v4.16b,v5.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + .inst 0x5e0760c4 //sha256su1 v4.16b,v6.16b,v7.16b + ld1 {v16.4s},[x3],#16 + add v17.4s,v17.4s,v5.4s + .inst 0x5e2828c5 //sha256su0 v5.16b,v6.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + .inst 0x5e0460e5 //sha256su1 v5.16b,v7.16b,v4.16b + ld1 {v17.4s},[x3],#16 + add v16.4s,v16.4s,v6.4s + .inst 0x5e2828e6 //sha256su0 v6.16b,v7.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + .inst 0x5e056086 //sha256su1 v6.16b,v4.16b,v5.16b + ld1 {v16.4s},[x3],#16 + add v17.4s,v17.4s,v7.4s + .inst 0x5e282887 //sha256su0 v7.16b,v4.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + .inst 0x5e0660a7 //sha256su1 v7.16b,v5.16b,v6.16b + ld1 {v17.4s},[x3],#16 + add v16.4s,v16.4s,v4.4s + .inst 0x5e2828a4 //sha256su0 v4.16b,v5.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + .inst 0x5e0760c4 //sha256su1 v4.16b,v6.16b,v7.16b + ld1 {v16.4s},[x3],#16 + add v17.4s,v17.4s,v5.4s + .inst 0x5e2828c5 //sha256su0 v5.16b,v6.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + .inst 0x5e0460e5 //sha256su1 v5.16b,v7.16b,v4.16b + ld1 {v17.4s},[x3],#16 + add v16.4s,v16.4s,v6.4s + .inst 0x5e2828e6 //sha256su0 v6.16b,v7.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + .inst 0x5e056086 //sha256su1 v6.16b,v4.16b,v5.16b + ld1 {v16.4s},[x3],#16 + add v17.4s,v17.4s,v7.4s + .inst 0x5e282887 //sha256su0 v7.16b,v4.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + .inst 0x5e0660a7 //sha256su1 v7.16b,v5.16b,v6.16b + ld1 {v17.4s},[x3],#16 + add v16.4s,v16.4s,v4.4s + .inst 0x5e2828a4 //sha256su0 v4.16b,v5.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + .inst 0x5e0760c4 //sha256su1 v4.16b,v6.16b,v7.16b + ld1 {v16.4s},[x3],#16 + add v17.4s,v17.4s,v5.4s + .inst 0x5e2828c5 //sha256su0 v5.16b,v6.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + .inst 0x5e0460e5 //sha256su1 v5.16b,v7.16b,v4.16b + ld1 {v17.4s},[x3],#16 + add v16.4s,v16.4s,v6.4s + .inst 0x5e2828e6 //sha256su0 v6.16b,v7.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + .inst 0x5e056086 //sha256su1 v6.16b,v4.16b,v5.16b + ld1 {v16.4s},[x3],#16 + add v17.4s,v17.4s,v7.4s + .inst 0x5e282887 //sha256su0 v7.16b,v4.16b + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + .inst 0x5e0660a7 //sha256su1 v7.16b,v5.16b,v6.16b + ld1 {v17.4s},[x3],#16 + add v16.4s,v16.4s,v4.4s + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + + ld1 {v16.4s},[x3],#16 + add v17.4s,v17.4s,v5.4s + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + + ld1 {v17.4s},[x3] + add v16.4s,v16.4s,v6.4s + sub x3,x3,#64*4-16 // rewind + orr v2.16b,v0.16b,v0.16b + .inst 0x5e104020 //sha256h v0.16b,v1.16b,v16.4s + .inst 0x5e105041 //sha256h2 v1.16b,v2.16b,v16.4s + + add v17.4s,v17.4s,v7.4s + orr v2.16b,v0.16b,v0.16b + .inst 0x5e114020 //sha256h v0.16b,v1.16b,v17.4s + .inst 0x5e115041 //sha256h2 v1.16b,v2.16b,v17.4s + + add v0.4s,v0.4s,v18.4s + add v1.4s,v1.4s,v19.4s + + cbnz x2,.Loop_hw + + st1 {v0.4s,v1.4s},[x0] + + ldr x29,[sp],#16 + ret +.size sha256_block_armv8,.-sha256_block_armv8 +#endif +#ifdef __KERNEL__ +.globl sha256_block_neon +#endif +.type sha256_block_neon,%function +.align 4 +sha256_block_neon: +.Lneon_entry: + stp x29, x30, [sp, #-16]! + mov x29, sp + sub sp,sp,#16*4 + + adr x16,.LK256 + add x2,x1,x2,lsl#6 // len to point at the end of inp + + ld1 {v0.16b},[x1], #16 + ld1 {v1.16b},[x1], #16 + ld1 {v2.16b},[x1], #16 + ld1 {v3.16b},[x1], #16 + ld1 {v4.4s},[x16], #16 + ld1 {v5.4s},[x16], #16 + ld1 {v6.4s},[x16], #16 + ld1 {v7.4s},[x16], #16 + rev32 v0.16b,v0.16b // yes, even on + rev32 v1.16b,v1.16b // big-endian + rev32 v2.16b,v2.16b + rev32 v3.16b,v3.16b + mov x17,sp + add v4.4s,v4.4s,v0.4s + add v5.4s,v5.4s,v1.4s + add v6.4s,v6.4s,v2.4s + st1 {v4.4s-v5.4s},[x17], #32 + add v7.4s,v7.4s,v3.4s + st1 {v6.4s-v7.4s},[x17] + sub x17,x17,#32 + + ldp w3,w4,[x0] + ldp w5,w6,[x0,#8] + ldp w7,w8,[x0,#16] + ldp w9,w10,[x0,#24] + ldr w12,[sp,#0] + mov w13,wzr + eor w14,w4,w5 + mov w15,wzr + b .L_00_48 + +.align 4 +.L_00_48: + ext v4.16b,v0.16b,v1.16b,#4 + add w10,w10,w12 + add w3,w3,w15 + and w12,w8,w7 + bic w15,w9,w7 + ext v7.16b,v2.16b,v3.16b,#4 + eor w11,w7,w7,ror#5 + add w3,w3,w13 + mov d19,v3.d[1] + orr w12,w12,w15 + eor w11,w11,w7,ror#19 + ushr v6.4s,v4.4s,#7 + eor w15,w3,w3,ror#11 + ushr v5.4s,v4.4s,#3 + add w10,w10,w12 + add v0.4s,v0.4s,v7.4s + ror w11,w11,#6 + sli v6.4s,v4.4s,#25 + eor w13,w3,w4 + eor w15,w15,w3,ror#20 + ushr v7.4s,v4.4s,#18 + add w10,w10,w11 + ldr w12,[sp,#4] + and w14,w14,w13 + eor v5.16b,v5.16b,v6.16b + ror w15,w15,#2 + add w6,w6,w10 + sli v7.4s,v4.4s,#14 + eor w14,w14,w4 + ushr v16.4s,v19.4s,#17 + add w9,w9,w12 + add w10,w10,w15 + and w12,w7,w6 + eor v5.16b,v5.16b,v7.16b + bic w15,w8,w6 + eor w11,w6,w6,ror#5 + sli v16.4s,v19.4s,#15 + add w10,w10,w14 + orr w12,w12,w15 + ushr v17.4s,v19.4s,#10 + eor w11,w11,w6,ror#19 + eor w15,w10,w10,ror#11 + ushr v7.4s,v19.4s,#19 + add w9,w9,w12 + ror w11,w11,#6 + add v0.4s,v0.4s,v5.4s + eor w14,w10,w3 + eor w15,w15,w10,ror#20 + sli v7.4s,v19.4s,#13 + add w9,w9,w11 + ldr w12,[sp,#8] + and w13,w13,w14 + eor v17.16b,v17.16b,v16.16b + ror w15,w15,#2 + add w5,w5,w9 + eor w13,w13,w3 + eor v17.16b,v17.16b,v7.16b + add w8,w8,w12 + add w9,w9,w15 + and w12,w6,w5 + add v0.4s,v0.4s,v17.4s + bic w15,w7,w5 + eor w11,w5,w5,ror#5 + add w9,w9,w13 + ushr v18.4s,v0.4s,#17 + orr w12,w12,w15 + ushr v19.4s,v0.4s,#10 + eor w11,w11,w5,ror#19 + eor w15,w9,w9,ror#11 + sli v18.4s,v0.4s,#15 + add w8,w8,w12 + ushr v17.4s,v0.4s,#19 + ror w11,w11,#6 + eor w13,w9,w10 + eor v19.16b,v19.16b,v18.16b + eor w15,w15,w9,ror#20 + add w8,w8,w11 + sli v17.4s,v0.4s,#13 + ldr w12,[sp,#12] + and w14,w14,w13 + ror w15,w15,#2 + ld1 {v4.4s},[x16], #16 + add w4,w4,w8 + eor v19.16b,v19.16b,v17.16b + eor w14,w14,w10 + eor v17.16b,v17.16b,v17.16b + add w7,w7,w12 + add w8,w8,w15 + and w12,w5,w4 + mov v17.d[1],v19.d[0] + bic w15,w6,w4 + eor w11,w4,w4,ror#5 + add w8,w8,w14 + add v0.4s,v0.4s,v17.4s + orr w12,w12,w15 + eor w11,w11,w4,ror#19 + eor w15,w8,w8,ror#11 + add v4.4s,v4.4s,v0.4s + add w7,w7,w12 + ror w11,w11,#6 + eor w14,w8,w9 + eor w15,w15,w8,ror#20 + add w7,w7,w11 + ldr w12,[sp,#16] + and w13,w13,w14 + ror w15,w15,#2 + add w3,w3,w7 + eor w13,w13,w9 + st1 {v4.4s},[x17], #16 + ext v4.16b,v1.16b,v2.16b,#4 + add w6,w6,w12 + add w7,w7,w15 + and w12,w4,w3 + bic w15,w5,w3 + ext v7.16b,v3.16b,v0.16b,#4 + eor w11,w3,w3,ror#5 + add w7,w7,w13 + mov d19,v0.d[1] + orr w12,w12,w15 + eor w11,w11,w3,ror#19 + ushr v6.4s,v4.4s,#7 + eor w15,w7,w7,ror#11 + ushr v5.4s,v4.4s,#3 + add w6,w6,w12 + add v1.4s,v1.4s,v7.4s + ror w11,w11,#6 + sli v6.4s,v4.4s,#25 + eor w13,w7,w8 + eor w15,w15,w7,ror#20 + ushr v7.4s,v4.4s,#18 + add w6,w6,w11 + ldr w12,[sp,#20] + and w14,w14,w13 + eor v5.16b,v5.16b,v6.16b + ror w15,w15,#2 + add w10,w10,w6 + sli v7.4s,v4.4s,#14 + eor w14,w14,w8 + ushr v16.4s,v19.4s,#17 + add w5,w5,w12 + add w6,w6,w15 + and w12,w3,w10 + eor v5.16b,v5.16b,v7.16b + bic w15,w4,w10 + eor w11,w10,w10,ror#5 + sli v16.4s,v19.4s,#15 + add w6,w6,w14 + orr w12,w12,w15 + ushr v17.4s,v19.4s,#10 + eor w11,w11,w10,ror#19 + eor w15,w6,w6,ror#11 + ushr v7.4s,v19.4s,#19 + add w5,w5,w12 + ror w11,w11,#6 + add v1.4s,v1.4s,v5.4s + eor w14,w6,w7 + eor w15,w15,w6,ror#20 + sli v7.4s,v19.4s,#13 + add w5,w5,w11 + ldr w12,[sp,#24] + and w13,w13,w14 + eor v17.16b,v17.16b,v16.16b + ror w15,w15,#2 + add w9,w9,w5 + eor w13,w13,w7 + eor v17.16b,v17.16b,v7.16b + add w4,w4,w12 + add w5,w5,w15 + and w12,w10,w9 + add v1.4s,v1.4s,v17.4s + bic w15,w3,w9 + eor w11,w9,w9,ror#5 + add w5,w5,w13 + ushr v18.4s,v1.4s,#17 + orr w12,w12,w15 + ushr v19.4s,v1.4s,#10 + eor w11,w11,w9,ror#19 + eor w15,w5,w5,ror#11 + sli v18.4s,v1.4s,#15 + add w4,w4,w12 + ushr v17.4s,v1.4s,#19 + ror w11,w11,#6 + eor w13,w5,w6 + eor v19.16b,v19.16b,v18.16b + eor w15,w15,w5,ror#20 + add w4,w4,w11 + sli v17.4s,v1.4s,#13 + ldr w12,[sp,#28] + and w14,w14,w13 + ror w15,w15,#2 + ld1 {v4.4s},[x16], #16 + add w8,w8,w4 + eor v19.16b,v19.16b,v17.16b + eor w14,w14,w6 + eor v17.16b,v17.16b,v17.16b + add w3,w3,w12 + add w4,w4,w15 + and w12,w9,w8 + mov v17.d[1],v19.d[0] + bic w15,w10,w8 + eor w11,w8,w8,ror#5 + add w4,w4,w14 + add v1.4s,v1.4s,v17.4s + orr w12,w12,w15 + eor w11,w11,w8,ror#19 + eor w15,w4,w4,ror#11 + add v4.4s,v4.4s,v1.4s + add w3,w3,w12 + ror w11,w11,#6 + eor w14,w4,w5 + eor w15,w15,w4,ror#20 + add w3,w3,w11 + ldr w12,[sp,#32] + and w13,w13,w14 + ror w15,w15,#2 + add w7,w7,w3 + eor w13,w13,w5 + st1 {v4.4s},[x17], #16 + ext v4.16b,v2.16b,v3.16b,#4 + add w10,w10,w12 + add w3,w3,w15 + and w12,w8,w7 + bic w15,w9,w7 + ext v7.16b,v0.16b,v1.16b,#4 + eor w11,w7,w7,ror#5 + add w3,w3,w13 + mov d19,v1.d[1] + orr w12,w12,w15 + eor w11,w11,w7,ror#19 + ushr v6.4s,v4.4s,#7 + eor w15,w3,w3,ror#11 + ushr v5.4s,v4.4s,#3 + add w10,w10,w12 + add v2.4s,v2.4s,v7.4s + ror w11,w11,#6 + sli v6.4s,v4.4s,#25 + eor w13,w3,w4 + eor w15,w15,w3,ror#20 + ushr v7.4s,v4.4s,#18 + add w10,w10,w11 + ldr w12,[sp,#36] + and w14,w14,w13 + eor v5.16b,v5.16b,v6.16b + ror w15,w15,#2 + add w6,w6,w10 + sli v7.4s,v4.4s,#14 + eor w14,w14,w4 + ushr v16.4s,v19.4s,#17 + add w9,w9,w12 + add w10,w10,w15 + and w12,w7,w6 + eor v5.16b,v5.16b,v7.16b + bic w15,w8,w6 + eor w11,w6,w6,ror#5 + sli v16.4s,v19.4s,#15 + add w10,w10,w14 + orr w12,w12,w15 + ushr v17.4s,v19.4s,#10 + eor w11,w11,w6,ror#19 + eor w15,w10,w10,ror#11 + ushr v7.4s,v19.4s,#19 + add w9,w9,w12 + ror w11,w11,#6 + add v2.4s,v2.4s,v5.4s + eor w14,w10,w3 + eor w15,w15,w10,ror#20 + sli v7.4s,v19.4s,#13 + add w9,w9,w11 + ldr w12,[sp,#40] + and w13,w13,w14 + eor v17.16b,v17.16b,v16.16b + ror w15,w15,#2 + add w5,w5,w9 + eor w13,w13,w3 + eor v17.16b,v17.16b,v7.16b + add w8,w8,w12 + add w9,w9,w15 + and w12,w6,w5 + add v2.4s,v2.4s,v17.4s + bic w15,w7,w5 + eor w11,w5,w5,ror#5 + add w9,w9,w13 + ushr v18.4s,v2.4s,#17 + orr w12,w12,w15 + ushr v19.4s,v2.4s,#10 + eor w11,w11,w5,ror#19 + eor w15,w9,w9,ror#11 + sli v18.4s,v2.4s,#15 + add w8,w8,w12 + ushr v17.4s,v2.4s,#19 + ror w11,w11,#6 + eor w13,w9,w10 + eor v19.16b,v19.16b,v18.16b + eor w15,w15,w9,ror#20 + add w8,w8,w11 + sli v17.4s,v2.4s,#13 + ldr w12,[sp,#44] + and w14,w14,w13 + ror w15,w15,#2 + ld1 {v4.4s},[x16], #16 + add w4,w4,w8 + eor v19.16b,v19.16b,v17.16b + eor w14,w14,w10 + eor v17.16b,v17.16b,v17.16b + add w7,w7,w12 + add w8,w8,w15 + and w12,w5,w4 + mov v17.d[1],v19.d[0] + bic w15,w6,w4 + eor w11,w4,w4,ror#5 + add w8,w8,w14 + add v2.4s,v2.4s,v17.4s + orr w12,w12,w15 + eor w11,w11,w4,ror#19 + eor w15,w8,w8,ror#11 + add v4.4s,v4.4s,v2.4s + add w7,w7,w12 + ror w11,w11,#6 + eor w14,w8,w9 + eor w15,w15,w8,ror#20 + add w7,w7,w11 + ldr w12,[sp,#48] + and w13,w13,w14 + ror w15,w15,#2 + add w3,w3,w7 + eor w13,w13,w9 + st1 {v4.4s},[x17], #16 + ext v4.16b,v3.16b,v0.16b,#4 + add w6,w6,w12 + add w7,w7,w15 + and w12,w4,w3 + bic w15,w5,w3 + ext v7.16b,v1.16b,v2.16b,#4 + eor w11,w3,w3,ror#5 + add w7,w7,w13 + mov d19,v2.d[1] + orr w12,w12,w15 + eor w11,w11,w3,ror#19 + ushr v6.4s,v4.4s,#7 + eor w15,w7,w7,ror#11 + ushr v5.4s,v4.4s,#3 + add w6,w6,w12 + add v3.4s,v3.4s,v7.4s + ror w11,w11,#6 + sli v6.4s,v4.4s,#25 + eor w13,w7,w8 + eor w15,w15,w7,ror#20 + ushr v7.4s,v4.4s,#18 + add w6,w6,w11 + ldr w12,[sp,#52] + and w14,w14,w13 + eor v5.16b,v5.16b,v6.16b + ror w15,w15,#2 + add w10,w10,w6 + sli v7.4s,v4.4s,#14 + eor w14,w14,w8 + ushr v16.4s,v19.4s,#17 + add w5,w5,w12 + add w6,w6,w15 + and w12,w3,w10 + eor v5.16b,v5.16b,v7.16b + bic w15,w4,w10 + eor w11,w10,w10,ror#5 + sli v16.4s,v19.4s,#15 + add w6,w6,w14 + orr w12,w12,w15 + ushr v17.4s,v19.4s,#10 + eor w11,w11,w10,ror#19 + eor w15,w6,w6,ror#11 + ushr v7.4s,v19.4s,#19 + add w5,w5,w12 + ror w11,w11,#6 + add v3.4s,v3.4s,v5.4s + eor w14,w6,w7 + eor w15,w15,w6,ror#20 + sli v7.4s,v19.4s,#13 + add w5,w5,w11 + ldr w12,[sp,#56] + and w13,w13,w14 + eor v17.16b,v17.16b,v16.16b + ror w15,w15,#2 + add w9,w9,w5 + eor w13,w13,w7 + eor v17.16b,v17.16b,v7.16b + add w4,w4,w12 + add w5,w5,w15 + and w12,w10,w9 + add v3.4s,v3.4s,v17.4s + bic w15,w3,w9 + eor w11,w9,w9,ror#5 + add w5,w5,w13 + ushr v18.4s,v3.4s,#17 + orr w12,w12,w15 + ushr v19.4s,v3.4s,#10 + eor w11,w11,w9,ror#19 + eor w15,w5,w5,ror#11 + sli v18.4s,v3.4s,#15 + add w4,w4,w12 + ushr v17.4s,v3.4s,#19 + ror w11,w11,#6 + eor w13,w5,w6 + eor v19.16b,v19.16b,v18.16b + eor w15,w15,w5,ror#20 + add w4,w4,w11 + sli v17.4s,v3.4s,#13 + ldr w12,[sp,#60] + and w14,w14,w13 + ror w15,w15,#2 + ld1 {v4.4s},[x16], #16 + add w8,w8,w4 + eor v19.16b,v19.16b,v17.16b + eor w14,w14,w6 + eor v17.16b,v17.16b,v17.16b + add w3,w3,w12 + add w4,w4,w15 + and w12,w9,w8 + mov v17.d[1],v19.d[0] + bic w15,w10,w8 + eor w11,w8,w8,ror#5 + add w4,w4,w14 + add v3.4s,v3.4s,v17.4s + orr w12,w12,w15 + eor w11,w11,w8,ror#19 + eor w15,w4,w4,ror#11 + add v4.4s,v4.4s,v3.4s + add w3,w3,w12 + ror w11,w11,#6 + eor w14,w4,w5 + eor w15,w15,w4,ror#20 + add w3,w3,w11 + ldr w12,[x16] + and w13,w13,w14 + ror w15,w15,#2 + add w7,w7,w3 + eor w13,w13,w5 + st1 {v4.4s},[x17], #16 + cmp w12,#0 // check for K256 terminator + ldr w12,[sp,#0] + sub x17,x17,#64 + bne .L_00_48 + + sub x16,x16,#256 // rewind x16 + cmp x1,x2 + mov x17, #64 + csel x17, x17, xzr, eq + sub x1,x1,x17 // avoid SEGV + mov x17,sp + add w10,w10,w12 + add w3,w3,w15 + and w12,w8,w7 + ld1 {v0.16b},[x1],#16 + bic w15,w9,w7 + eor w11,w7,w7,ror#5 + ld1 {v4.4s},[x16],#16 + add w3,w3,w13 + orr w12,w12,w15 + eor w11,w11,w7,ror#19 + eor w15,w3,w3,ror#11 + rev32 v0.16b,v0.16b + add w10,w10,w12 + ror w11,w11,#6 + eor w13,w3,w4 + eor w15,w15,w3,ror#20 + add v4.4s,v4.4s,v0.4s + add w10,w10,w11 + ldr w12,[sp,#4] + and w14,w14,w13 + ror w15,w15,#2 + add w6,w6,w10 + eor w14,w14,w4 + add w9,w9,w12 + add w10,w10,w15 + and w12,w7,w6 + bic w15,w8,w6 + eor w11,w6,w6,ror#5 + add w10,w10,w14 + orr w12,w12,w15 + eor w11,w11,w6,ror#19 + eor w15,w10,w10,ror#11 + add w9,w9,w12 + ror w11,w11,#6 + eor w14,w10,w3 + eor w15,w15,w10,ror#20 + add w9,w9,w11 + ldr w12,[sp,#8] + and w13,w13,w14 + ror w15,w15,#2 + add w5,w5,w9 + eor w13,w13,w3 + add w8,w8,w12 + add w9,w9,w15 + and w12,w6,w5 + bic w15,w7,w5 + eor w11,w5,w5,ror#5 + add w9,w9,w13 + orr w12,w12,w15 + eor w11,w11,w5,ror#19 + eor w15,w9,w9,ror#11 + add w8,w8,w12 + ror w11,w11,#6 + eor w13,w9,w10 + eor w15,w15,w9,ror#20 + add w8,w8,w11 + ldr w12,[sp,#12] + and w14,w14,w13 + ror w15,w15,#2 + add w4,w4,w8 + eor w14,w14,w10 + add w7,w7,w12 + add w8,w8,w15 + and w12,w5,w4 + bic w15,w6,w4 + eor w11,w4,w4,ror#5 + add w8,w8,w14 + orr w12,w12,w15 + eor w11,w11,w4,ror#19 + eor w15,w8,w8,ror#11 + add w7,w7,w12 + ror w11,w11,#6 + eor w14,w8,w9 + eor w15,w15,w8,ror#20 + add w7,w7,w11 + ldr w12,[sp,#16] + and w13,w13,w14 + ror w15,w15,#2 + add w3,w3,w7 + eor w13,w13,w9 + st1 {v4.4s},[x17], #16 + add w6,w6,w12 + add w7,w7,w15 + and w12,w4,w3 + ld1 {v1.16b},[x1],#16 + bic w15,w5,w3 + eor w11,w3,w3,ror#5 + ld1 {v4.4s},[x16],#16 + add w7,w7,w13 + orr w12,w12,w15 + eor w11,w11,w3,ror#19 + eor w15,w7,w7,ror#11 + rev32 v1.16b,v1.16b + add w6,w6,w12 + ror w11,w11,#6 + eor w13,w7,w8 + eor w15,w15,w7,ror#20 + add v4.4s,v4.4s,v1.4s + add w6,w6,w11 + ldr w12,[sp,#20] + and w14,w14,w13 + ror w15,w15,#2 + add w10,w10,w6 + eor w14,w14,w8 + add w5,w5,w12 + add w6,w6,w15 + and w12,w3,w10 + bic w15,w4,w10 + eor w11,w10,w10,ror#5 + add w6,w6,w14 + orr w12,w12,w15 + eor w11,w11,w10,ror#19 + eor w15,w6,w6,ror#11 + add w5,w5,w12 + ror w11,w11,#6 + eor w14,w6,w7 + eor w15,w15,w6,ror#20 + add w5,w5,w11 + ldr w12,[sp,#24] + and w13,w13,w14 + ror w15,w15,#2 + add w9,w9,w5 + eor w13,w13,w7 + add w4,w4,w12 + add w5,w5,w15 + and w12,w10,w9 + bic w15,w3,w9 + eor w11,w9,w9,ror#5 + add w5,w5,w13 + orr w12,w12,w15 + eor w11,w11,w9,ror#19 + eor w15,w5,w5,ror#11 + add w4,w4,w12 + ror w11,w11,#6 + eor w13,w5,w6 + eor w15,w15,w5,ror#20 + add w4,w4,w11 + ldr w12,[sp,#28] + and w14,w14,w13 + ror w15,w15,#2 + add w8,w8,w4 + eor w14,w14,w6 + add w3,w3,w12 + add w4,w4,w15 + and w12,w9,w8 + bic w15,w10,w8 + eor w11,w8,w8,ror#5 + add w4,w4,w14 + orr w12,w12,w15 + eor w11,w11,w8,ror#19 + eor w15,w4,w4,ror#11 + add w3,w3,w12 + ror w11,w11,#6 + eor w14,w4,w5 + eor w15,w15,w4,ror#20 + add w3,w3,w11 + ldr w12,[sp,#32] + and w13,w13,w14 + ror w15,w15,#2 + add w7,w7,w3 + eor w13,w13,w5 + st1 {v4.4s},[x17], #16 + add w10,w10,w12 + add w3,w3,w15 + and w12,w8,w7 + ld1 {v2.16b},[x1],#16 + bic w15,w9,w7 + eor w11,w7,w7,ror#5 + ld1 {v4.4s},[x16],#16 + add w3,w3,w13 + orr w12,w12,w15 + eor w11,w11,w7,ror#19 + eor w15,w3,w3,ror#11 + rev32 v2.16b,v2.16b + add w10,w10,w12 + ror w11,w11,#6 + eor w13,w3,w4 + eor w15,w15,w3,ror#20 + add v4.4s,v4.4s,v2.4s + add w10,w10,w11 + ldr w12,[sp,#36] + and w14,w14,w13 + ror w15,w15,#2 + add w6,w6,w10 + eor w14,w14,w4 + add w9,w9,w12 + add w10,w10,w15 + and w12,w7,w6 + bic w15,w8,w6 + eor w11,w6,w6,ror#5 + add w10,w10,w14 + orr w12,w12,w15 + eor w11,w11,w6,ror#19 + eor w15,w10,w10,ror#11 + add w9,w9,w12 + ror w11,w11,#6 + eor w14,w10,w3 + eor w15,w15,w10,ror#20 + add w9,w9,w11 + ldr w12,[sp,#40] + and w13,w13,w14 + ror w15,w15,#2 + add w5,w5,w9 + eor w13,w13,w3 + add w8,w8,w12 + add w9,w9,w15 + and w12,w6,w5 + bic w15,w7,w5 + eor w11,w5,w5,ror#5 + add w9,w9,w13 + orr w12,w12,w15 + eor w11,w11,w5,ror#19 + eor w15,w9,w9,ror#11 + add w8,w8,w12 + ror w11,w11,#6 + eor w13,w9,w10 + eor w15,w15,w9,ror#20 + add w8,w8,w11 + ldr w12,[sp,#44] + and w14,w14,w13 + ror w15,w15,#2 + add w4,w4,w8 + eor w14,w14,w10 + add w7,w7,w12 + add w8,w8,w15 + and w12,w5,w4 + bic w15,w6,w4 + eor w11,w4,w4,ror#5 + add w8,w8,w14 + orr w12,w12,w15 + eor w11,w11,w4,ror#19 + eor w15,w8,w8,ror#11 + add w7,w7,w12 + ror w11,w11,#6 + eor w14,w8,w9 + eor w15,w15,w8,ror#20 + add w7,w7,w11 + ldr w12,[sp,#48] + and w13,w13,w14 + ror w15,w15,#2 + add w3,w3,w7 + eor w13,w13,w9 + st1 {v4.4s},[x17], #16 + add w6,w6,w12 + add w7,w7,w15 + and w12,w4,w3 + ld1 {v3.16b},[x1],#16 + bic w15,w5,w3 + eor w11,w3,w3,ror#5 + ld1 {v4.4s},[x16],#16 + add w7,w7,w13 + orr w12,w12,w15 + eor w11,w11,w3,ror#19 + eor w15,w7,w7,ror#11 + rev32 v3.16b,v3.16b + add w6,w6,w12 + ror w11,w11,#6 + eor w13,w7,w8 + eor w15,w15,w7,ror#20 + add v4.4s,v4.4s,v3.4s + add w6,w6,w11 + ldr w12,[sp,#52] + and w14,w14,w13 + ror w15,w15,#2 + add w10,w10,w6 + eor w14,w14,w8 + add w5,w5,w12 + add w6,w6,w15 + and w12,w3,w10 + bic w15,w4,w10 + eor w11,w10,w10,ror#5 + add w6,w6,w14 + orr w12,w12,w15 + eor w11,w11,w10,ror#19 + eor w15,w6,w6,ror#11 + add w5,w5,w12 + ror w11,w11,#6 + eor w14,w6,w7 + eor w15,w15,w6,ror#20 + add w5,w5,w11 + ldr w12,[sp,#56] + and w13,w13,w14 + ror w15,w15,#2 + add w9,w9,w5 + eor w13,w13,w7 + add w4,w4,w12 + add w5,w5,w15 + and w12,w10,w9 + bic w15,w3,w9 + eor w11,w9,w9,ror#5 + add w5,w5,w13 + orr w12,w12,w15 + eor w11,w11,w9,ror#19 + eor w15,w5,w5,ror#11 + add w4,w4,w12 + ror w11,w11,#6 + eor w13,w5,w6 + eor w15,w15,w5,ror#20 + add w4,w4,w11 + ldr w12,[sp,#60] + and w14,w14,w13 + ror w15,w15,#2 + add w8,w8,w4 + eor w14,w14,w6 + add w3,w3,w12 + add w4,w4,w15 + and w12,w9,w8 + bic w15,w10,w8 + eor w11,w8,w8,ror#5 + add w4,w4,w14 + orr w12,w12,w15 + eor w11,w11,w8,ror#19 + eor w15,w4,w4,ror#11 + add w3,w3,w12 + ror w11,w11,#6 + eor w14,w4,w5 + eor w15,w15,w4,ror#20 + add w3,w3,w11 + and w13,w13,w14 + ror w15,w15,#2 + add w7,w7,w3 + eor w13,w13,w5 + st1 {v4.4s},[x17], #16 + add w3,w3,w15 // h+=Sigma0(a) from the past + ldp w11,w12,[x0,#0] + add w3,w3,w13 // h+=Maj(a,b,c) from the past + ldp w13,w14,[x0,#8] + add w3,w3,w11 // accumulate + add w4,w4,w12 + ldp w11,w12,[x0,#16] + add w5,w5,w13 + add w6,w6,w14 + ldp w13,w14,[x0,#24] + add w7,w7,w11 + add w8,w8,w12 + ldr w12,[sp,#0] + stp w3,w4,[x0,#0] + add w9,w9,w13 + mov w13,wzr + stp w5,w6,[x0,#8] + add w10,w10,w14 + stp w7,w8,[x0,#16] + eor w14,w4,w5 + stp w9,w10,[x0,#24] + mov w15,wzr + mov x17,sp + b.ne .L_00_48 + + ldr x29,[x29] + add sp,sp,#16*4+16 + ret +.size sha256_block_neon,.-sha256_block_neon +#ifndef __KERNEL__ +.comm OPENSSL_armcap_P,4,4 +#endif diff --git a/arch/arm64/crypto/sha512-core.S b/arch/arm64/crypto/sha512-core.S new file mode 100644 index 000000000000..bd0f59f06c9d --- /dev/null +++ b/arch/arm64/crypto/sha512-core.S @@ -0,0 +1,1085 @@ +// Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved. +// +// Licensed under the OpenSSL license (the "License"). You may not use +// this file except in compliance with the License. You can obtain a copy +// in the file LICENSE in the source distribution or at +// https://www.openssl.org/source/license.html + +// ==================================================================== +// Written by Andy Polyakov for the OpenSSL +// project. The module is, however, dual licensed under OpenSSL and +// CRYPTOGAMS licenses depending on where you obtain it. For further +// details see http://www.openssl.org/~appro/cryptogams/. +// +// Permission to use under GPLv2 terms is granted. +// ==================================================================== +// +// SHA256/512 for ARMv8. +// +// Performance in cycles per processed byte and improvement coefficient +// over code generated with "default" compiler: +// +// SHA256-hw SHA256(*) SHA512 +// Apple A7 1.97 10.5 (+33%) 6.73 (-1%(**)) +// Cortex-A53 2.38 15.5 (+115%) 10.0 (+150%(***)) +// Cortex-A57 2.31 11.6 (+86%) 7.51 (+260%(***)) +// Denver 2.01 10.5 (+26%) 6.70 (+8%) +// X-Gene 20.0 (+100%) 12.8 (+300%(***)) +// Mongoose 2.36 13.0 (+50%) 8.36 (+33%) +// +// (*) Software SHA256 results are of lesser relevance, presented +// mostly for informational purposes. +// (**) The result is a trade-off: it's possible to improve it by +// 10% (or by 1 cycle per round), but at the cost of 20% loss +// on Cortex-A53 (or by 4 cycles per round). +// (***) Super-impressive coefficients over gcc-generated code are +// indication of some compiler "pathology", most notably code +// generated with -mgeneral-regs-only is significanty faster +// and the gap is only 40-90%. +// +// October 2016. +// +// Originally it was reckoned that it makes no sense to implement NEON +// version of SHA256 for 64-bit processors. This is because performance +// improvement on most wide-spread Cortex-A5x processors was observed +// to be marginal, same on Cortex-A53 and ~10% on A57. But then it was +// observed that 32-bit NEON SHA256 performs significantly better than +// 64-bit scalar version on *some* of the more recent processors. As +// result 64-bit NEON version of SHA256 was added to provide best +// all-round performance. For example it executes ~30% faster on X-Gene +// and Mongoose. [For reference, NEON version of SHA512 is bound to +// deliver much less improvement, likely *negative* on Cortex-A5x. +// Which is why NEON support is limited to SHA256.] + +#ifndef __KERNEL__ +# include "arm_arch.h" +#endif + +.text + +.extern OPENSSL_armcap_P +.globl sha512_block_data_order +.type sha512_block_data_order,%function +.align 6 +sha512_block_data_order: + stp x29,x30,[sp,#-128]! + add x29,sp,#0 + + stp x19,x20,[sp,#16] + stp x21,x22,[sp,#32] + stp x23,x24,[sp,#48] + stp x25,x26,[sp,#64] + stp x27,x28,[sp,#80] + sub sp,sp,#4*8 + + ldp x20,x21,[x0] // load context + ldp x22,x23,[x0,#2*8] + ldp x24,x25,[x0,#4*8] + add x2,x1,x2,lsl#7 // end of input + ldp x26,x27,[x0,#6*8] + adr x30,.LK512 + stp x0,x2,[x29,#96] + +.Loop: + ldp x3,x4,[x1],#2*8 + ldr x19,[x30],#8 // *K++ + eor x28,x21,x22 // magic seed + str x1,[x29,#112] +#ifndef __AARCH64EB__ + rev x3,x3 // 0 +#endif + ror x16,x24,#14 + add x27,x27,x19 // h+=K[i] + eor x6,x24,x24,ror#23 + and x17,x25,x24 + bic x19,x26,x24 + add x27,x27,x3 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x20,x21 // a^b, b^c in next round + eor x16,x16,x6,ror#18 // Sigma1(e) + ror x6,x20,#28 + add x27,x27,x17 // h+=Ch(e,f,g) + eor x17,x20,x20,ror#5 + add x27,x27,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x23,x23,x27 // d+=h + eor x28,x28,x21 // Maj(a,b,c) + eor x17,x6,x17,ror#34 // Sigma0(a) + add x27,x27,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x27,x27,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x4,x4 // 1 +#endif + ldp x5,x6,[x1],#2*8 + add x27,x27,x17 // h+=Sigma0(a) + ror x16,x23,#14 + add x26,x26,x28 // h+=K[i] + eor x7,x23,x23,ror#23 + and x17,x24,x23 + bic x28,x25,x23 + add x26,x26,x4 // h+=X[i] + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x27,x20 // a^b, b^c in next round + eor x16,x16,x7,ror#18 // Sigma1(e) + ror x7,x27,#28 + add x26,x26,x17 // h+=Ch(e,f,g) + eor x17,x27,x27,ror#5 + add x26,x26,x16 // h+=Sigma1(e) + and x19,x19,x28 // (b^c)&=(a^b) + add x22,x22,x26 // d+=h + eor x19,x19,x20 // Maj(a,b,c) + eor x17,x7,x17,ror#34 // Sigma0(a) + add x26,x26,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + //add x26,x26,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x5,x5 // 2 +#endif + add x26,x26,x17 // h+=Sigma0(a) + ror x16,x22,#14 + add x25,x25,x19 // h+=K[i] + eor x8,x22,x22,ror#23 + and x17,x23,x22 + bic x19,x24,x22 + add x25,x25,x5 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x26,x27 // a^b, b^c in next round + eor x16,x16,x8,ror#18 // Sigma1(e) + ror x8,x26,#28 + add x25,x25,x17 // h+=Ch(e,f,g) + eor x17,x26,x26,ror#5 + add x25,x25,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x21,x21,x25 // d+=h + eor x28,x28,x27 // Maj(a,b,c) + eor x17,x8,x17,ror#34 // Sigma0(a) + add x25,x25,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x25,x25,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x6,x6 // 3 +#endif + ldp x7,x8,[x1],#2*8 + add x25,x25,x17 // h+=Sigma0(a) + ror x16,x21,#14 + add x24,x24,x28 // h+=K[i] + eor x9,x21,x21,ror#23 + and x17,x22,x21 + bic x28,x23,x21 + add x24,x24,x6 // h+=X[i] + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x25,x26 // a^b, b^c in next round + eor x16,x16,x9,ror#18 // Sigma1(e) + ror x9,x25,#28 + add x24,x24,x17 // h+=Ch(e,f,g) + eor x17,x25,x25,ror#5 + add x24,x24,x16 // h+=Sigma1(e) + and x19,x19,x28 // (b^c)&=(a^b) + add x20,x20,x24 // d+=h + eor x19,x19,x26 // Maj(a,b,c) + eor x17,x9,x17,ror#34 // Sigma0(a) + add x24,x24,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + //add x24,x24,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x7,x7 // 4 +#endif + add x24,x24,x17 // h+=Sigma0(a) + ror x16,x20,#14 + add x23,x23,x19 // h+=K[i] + eor x10,x20,x20,ror#23 + and x17,x21,x20 + bic x19,x22,x20 + add x23,x23,x7 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x24,x25 // a^b, b^c in next round + eor x16,x16,x10,ror#18 // Sigma1(e) + ror x10,x24,#28 + add x23,x23,x17 // h+=Ch(e,f,g) + eor x17,x24,x24,ror#5 + add x23,x23,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x27,x27,x23 // d+=h + eor x28,x28,x25 // Maj(a,b,c) + eor x17,x10,x17,ror#34 // Sigma0(a) + add x23,x23,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x23,x23,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x8,x8 // 5 +#endif + ldp x9,x10,[x1],#2*8 + add x23,x23,x17 // h+=Sigma0(a) + ror x16,x27,#14 + add x22,x22,x28 // h+=K[i] + eor x11,x27,x27,ror#23 + and x17,x20,x27 + bic x28,x21,x27 + add x22,x22,x8 // h+=X[i] + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x23,x24 // a^b, b^c in next round + eor x16,x16,x11,ror#18 // Sigma1(e) + ror x11,x23,#28 + add x22,x22,x17 // h+=Ch(e,f,g) + eor x17,x23,x23,ror#5 + add x22,x22,x16 // h+=Sigma1(e) + and x19,x19,x28 // (b^c)&=(a^b) + add x26,x26,x22 // d+=h + eor x19,x19,x24 // Maj(a,b,c) + eor x17,x11,x17,ror#34 // Sigma0(a) + add x22,x22,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + //add x22,x22,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x9,x9 // 6 +#endif + add x22,x22,x17 // h+=Sigma0(a) + ror x16,x26,#14 + add x21,x21,x19 // h+=K[i] + eor x12,x26,x26,ror#23 + and x17,x27,x26 + bic x19,x20,x26 + add x21,x21,x9 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x22,x23 // a^b, b^c in next round + eor x16,x16,x12,ror#18 // Sigma1(e) + ror x12,x22,#28 + add x21,x21,x17 // h+=Ch(e,f,g) + eor x17,x22,x22,ror#5 + add x21,x21,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x25,x25,x21 // d+=h + eor x28,x28,x23 // Maj(a,b,c) + eor x17,x12,x17,ror#34 // Sigma0(a) + add x21,x21,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x21,x21,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x10,x10 // 7 +#endif + ldp x11,x12,[x1],#2*8 + add x21,x21,x17 // h+=Sigma0(a) + ror x16,x25,#14 + add x20,x20,x28 // h+=K[i] + eor x13,x25,x25,ror#23 + and x17,x26,x25 + bic x28,x27,x25 + add x20,x20,x10 // h+=X[i] + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x21,x22 // a^b, b^c in next round + eor x16,x16,x13,ror#18 // Sigma1(e) + ror x13,x21,#28 + add x20,x20,x17 // h+=Ch(e,f,g) + eor x17,x21,x21,ror#5 + add x20,x20,x16 // h+=Sigma1(e) + and x19,x19,x28 // (b^c)&=(a^b) + add x24,x24,x20 // d+=h + eor x19,x19,x22 // Maj(a,b,c) + eor x17,x13,x17,ror#34 // Sigma0(a) + add x20,x20,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + //add x20,x20,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x11,x11 // 8 +#endif + add x20,x20,x17 // h+=Sigma0(a) + ror x16,x24,#14 + add x27,x27,x19 // h+=K[i] + eor x14,x24,x24,ror#23 + and x17,x25,x24 + bic x19,x26,x24 + add x27,x27,x11 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x20,x21 // a^b, b^c in next round + eor x16,x16,x14,ror#18 // Sigma1(e) + ror x14,x20,#28 + add x27,x27,x17 // h+=Ch(e,f,g) + eor x17,x20,x20,ror#5 + add x27,x27,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x23,x23,x27 // d+=h + eor x28,x28,x21 // Maj(a,b,c) + eor x17,x14,x17,ror#34 // Sigma0(a) + add x27,x27,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x27,x27,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x12,x12 // 9 +#endif + ldp x13,x14,[x1],#2*8 + add x27,x27,x17 // h+=Sigma0(a) + ror x16,x23,#14 + add x26,x26,x28 // h+=K[i] + eor x15,x23,x23,ror#23 + and x17,x24,x23 + bic x28,x25,x23 + add x26,x26,x12 // h+=X[i] + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x27,x20 // a^b, b^c in next round + eor x16,x16,x15,ror#18 // Sigma1(e) + ror x15,x27,#28 + add x26,x26,x17 // h+=Ch(e,f,g) + eor x17,x27,x27,ror#5 + add x26,x26,x16 // h+=Sigma1(e) + and x19,x19,x28 // (b^c)&=(a^b) + add x22,x22,x26 // d+=h + eor x19,x19,x20 // Maj(a,b,c) + eor x17,x15,x17,ror#34 // Sigma0(a) + add x26,x26,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + //add x26,x26,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x13,x13 // 10 +#endif + add x26,x26,x17 // h+=Sigma0(a) + ror x16,x22,#14 + add x25,x25,x19 // h+=K[i] + eor x0,x22,x22,ror#23 + and x17,x23,x22 + bic x19,x24,x22 + add x25,x25,x13 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x26,x27 // a^b, b^c in next round + eor x16,x16,x0,ror#18 // Sigma1(e) + ror x0,x26,#28 + add x25,x25,x17 // h+=Ch(e,f,g) + eor x17,x26,x26,ror#5 + add x25,x25,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x21,x21,x25 // d+=h + eor x28,x28,x27 // Maj(a,b,c) + eor x17,x0,x17,ror#34 // Sigma0(a) + add x25,x25,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x25,x25,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x14,x14 // 11 +#endif + ldp x15,x0,[x1],#2*8 + add x25,x25,x17 // h+=Sigma0(a) + str x6,[sp,#24] + ror x16,x21,#14 + add x24,x24,x28 // h+=K[i] + eor x6,x21,x21,ror#23 + and x17,x22,x21 + bic x28,x23,x21 + add x24,x24,x14 // h+=X[i] + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x25,x26 // a^b, b^c in next round + eor x16,x16,x6,ror#18 // Sigma1(e) + ror x6,x25,#28 + add x24,x24,x17 // h+=Ch(e,f,g) + eor x17,x25,x25,ror#5 + add x24,x24,x16 // h+=Sigma1(e) + and x19,x19,x28 // (b^c)&=(a^b) + add x20,x20,x24 // d+=h + eor x19,x19,x26 // Maj(a,b,c) + eor x17,x6,x17,ror#34 // Sigma0(a) + add x24,x24,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + //add x24,x24,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x15,x15 // 12 +#endif + add x24,x24,x17 // h+=Sigma0(a) + str x7,[sp,#0] + ror x16,x20,#14 + add x23,x23,x19 // h+=K[i] + eor x7,x20,x20,ror#23 + and x17,x21,x20 + bic x19,x22,x20 + add x23,x23,x15 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x24,x25 // a^b, b^c in next round + eor x16,x16,x7,ror#18 // Sigma1(e) + ror x7,x24,#28 + add x23,x23,x17 // h+=Ch(e,f,g) + eor x17,x24,x24,ror#5 + add x23,x23,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x27,x27,x23 // d+=h + eor x28,x28,x25 // Maj(a,b,c) + eor x17,x7,x17,ror#34 // Sigma0(a) + add x23,x23,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x23,x23,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x0,x0 // 13 +#endif + ldp x1,x2,[x1] + add x23,x23,x17 // h+=Sigma0(a) + str x8,[sp,#8] + ror x16,x27,#14 + add x22,x22,x28 // h+=K[i] + eor x8,x27,x27,ror#23 + and x17,x20,x27 + bic x28,x21,x27 + add x22,x22,x0 // h+=X[i] + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x23,x24 // a^b, b^c in next round + eor x16,x16,x8,ror#18 // Sigma1(e) + ror x8,x23,#28 + add x22,x22,x17 // h+=Ch(e,f,g) + eor x17,x23,x23,ror#5 + add x22,x22,x16 // h+=Sigma1(e) + and x19,x19,x28 // (b^c)&=(a^b) + add x26,x26,x22 // d+=h + eor x19,x19,x24 // Maj(a,b,c) + eor x17,x8,x17,ror#34 // Sigma0(a) + add x22,x22,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + //add x22,x22,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x1,x1 // 14 +#endif + ldr x6,[sp,#24] + add x22,x22,x17 // h+=Sigma0(a) + str x9,[sp,#16] + ror x16,x26,#14 + add x21,x21,x19 // h+=K[i] + eor x9,x26,x26,ror#23 + and x17,x27,x26 + bic x19,x20,x26 + add x21,x21,x1 // h+=X[i] + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x22,x23 // a^b, b^c in next round + eor x16,x16,x9,ror#18 // Sigma1(e) + ror x9,x22,#28 + add x21,x21,x17 // h+=Ch(e,f,g) + eor x17,x22,x22,ror#5 + add x21,x21,x16 // h+=Sigma1(e) + and x28,x28,x19 // (b^c)&=(a^b) + add x25,x25,x21 // d+=h + eor x28,x28,x23 // Maj(a,b,c) + eor x17,x9,x17,ror#34 // Sigma0(a) + add x21,x21,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + //add x21,x21,x17 // h+=Sigma0(a) +#ifndef __AARCH64EB__ + rev x2,x2 // 15 +#endif + ldr x7,[sp,#0] + add x21,x21,x17 // h+=Sigma0(a) + str x10,[sp,#24] + ror x16,x25,#14 + add x20,x20,x28 // h+=K[i] + ror x9,x4,#1 + and x17,x26,x25 + ror x8,x1,#19 + bic x28,x27,x25 + ror x10,x21,#28 + add x20,x20,x2 // h+=X[i] + eor x16,x16,x25,ror#18 + eor x9,x9,x4,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x21,x22 // a^b, b^c in next round + eor x16,x16,x25,ror#41 // Sigma1(e) + eor x10,x10,x21,ror#34 + add x20,x20,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x8,x8,x1,ror#61 + eor x9,x9,x4,lsr#7 // sigma0(X[i+1]) + add x20,x20,x16 // h+=Sigma1(e) + eor x19,x19,x22 // Maj(a,b,c) + eor x17,x10,x21,ror#39 // Sigma0(a) + eor x8,x8,x1,lsr#6 // sigma1(X[i+14]) + add x3,x3,x12 + add x24,x24,x20 // d+=h + add x20,x20,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x3,x3,x9 + add x20,x20,x17 // h+=Sigma0(a) + add x3,x3,x8 +.Loop_16_xx: + ldr x8,[sp,#8] + str x11,[sp,#0] + ror x16,x24,#14 + add x27,x27,x19 // h+=K[i] + ror x10,x5,#1 + and x17,x25,x24 + ror x9,x2,#19 + bic x19,x26,x24 + ror x11,x20,#28 + add x27,x27,x3 // h+=X[i] + eor x16,x16,x24,ror#18 + eor x10,x10,x5,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x20,x21 // a^b, b^c in next round + eor x16,x16,x24,ror#41 // Sigma1(e) + eor x11,x11,x20,ror#34 + add x27,x27,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x9,x9,x2,ror#61 + eor x10,x10,x5,lsr#7 // sigma0(X[i+1]) + add x27,x27,x16 // h+=Sigma1(e) + eor x28,x28,x21 // Maj(a,b,c) + eor x17,x11,x20,ror#39 // Sigma0(a) + eor x9,x9,x2,lsr#6 // sigma1(X[i+14]) + add x4,x4,x13 + add x23,x23,x27 // d+=h + add x27,x27,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x4,x4,x10 + add x27,x27,x17 // h+=Sigma0(a) + add x4,x4,x9 + ldr x9,[sp,#16] + str x12,[sp,#8] + ror x16,x23,#14 + add x26,x26,x28 // h+=K[i] + ror x11,x6,#1 + and x17,x24,x23 + ror x10,x3,#19 + bic x28,x25,x23 + ror x12,x27,#28 + add x26,x26,x4 // h+=X[i] + eor x16,x16,x23,ror#18 + eor x11,x11,x6,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x27,x20 // a^b, b^c in next round + eor x16,x16,x23,ror#41 // Sigma1(e) + eor x12,x12,x27,ror#34 + add x26,x26,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x10,x10,x3,ror#61 + eor x11,x11,x6,lsr#7 // sigma0(X[i+1]) + add x26,x26,x16 // h+=Sigma1(e) + eor x19,x19,x20 // Maj(a,b,c) + eor x17,x12,x27,ror#39 // Sigma0(a) + eor x10,x10,x3,lsr#6 // sigma1(X[i+14]) + add x5,x5,x14 + add x22,x22,x26 // d+=h + add x26,x26,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x5,x5,x11 + add x26,x26,x17 // h+=Sigma0(a) + add x5,x5,x10 + ldr x10,[sp,#24] + str x13,[sp,#16] + ror x16,x22,#14 + add x25,x25,x19 // h+=K[i] + ror x12,x7,#1 + and x17,x23,x22 + ror x11,x4,#19 + bic x19,x24,x22 + ror x13,x26,#28 + add x25,x25,x5 // h+=X[i] + eor x16,x16,x22,ror#18 + eor x12,x12,x7,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x26,x27 // a^b, b^c in next round + eor x16,x16,x22,ror#41 // Sigma1(e) + eor x13,x13,x26,ror#34 + add x25,x25,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x11,x11,x4,ror#61 + eor x12,x12,x7,lsr#7 // sigma0(X[i+1]) + add x25,x25,x16 // h+=Sigma1(e) + eor x28,x28,x27 // Maj(a,b,c) + eor x17,x13,x26,ror#39 // Sigma0(a) + eor x11,x11,x4,lsr#6 // sigma1(X[i+14]) + add x6,x6,x15 + add x21,x21,x25 // d+=h + add x25,x25,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x6,x6,x12 + add x25,x25,x17 // h+=Sigma0(a) + add x6,x6,x11 + ldr x11,[sp,#0] + str x14,[sp,#24] + ror x16,x21,#14 + add x24,x24,x28 // h+=K[i] + ror x13,x8,#1 + and x17,x22,x21 + ror x12,x5,#19 + bic x28,x23,x21 + ror x14,x25,#28 + add x24,x24,x6 // h+=X[i] + eor x16,x16,x21,ror#18 + eor x13,x13,x8,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x25,x26 // a^b, b^c in next round + eor x16,x16,x21,ror#41 // Sigma1(e) + eor x14,x14,x25,ror#34 + add x24,x24,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x12,x12,x5,ror#61 + eor x13,x13,x8,lsr#7 // sigma0(X[i+1]) + add x24,x24,x16 // h+=Sigma1(e) + eor x19,x19,x26 // Maj(a,b,c) + eor x17,x14,x25,ror#39 // Sigma0(a) + eor x12,x12,x5,lsr#6 // sigma1(X[i+14]) + add x7,x7,x0 + add x20,x20,x24 // d+=h + add x24,x24,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x7,x7,x13 + add x24,x24,x17 // h+=Sigma0(a) + add x7,x7,x12 + ldr x12,[sp,#8] + str x15,[sp,#0] + ror x16,x20,#14 + add x23,x23,x19 // h+=K[i] + ror x14,x9,#1 + and x17,x21,x20 + ror x13,x6,#19 + bic x19,x22,x20 + ror x15,x24,#28 + add x23,x23,x7 // h+=X[i] + eor x16,x16,x20,ror#18 + eor x14,x14,x9,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x24,x25 // a^b, b^c in next round + eor x16,x16,x20,ror#41 // Sigma1(e) + eor x15,x15,x24,ror#34 + add x23,x23,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x13,x13,x6,ror#61 + eor x14,x14,x9,lsr#7 // sigma0(X[i+1]) + add x23,x23,x16 // h+=Sigma1(e) + eor x28,x28,x25 // Maj(a,b,c) + eor x17,x15,x24,ror#39 // Sigma0(a) + eor x13,x13,x6,lsr#6 // sigma1(X[i+14]) + add x8,x8,x1 + add x27,x27,x23 // d+=h + add x23,x23,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x8,x8,x14 + add x23,x23,x17 // h+=Sigma0(a) + add x8,x8,x13 + ldr x13,[sp,#16] + str x0,[sp,#8] + ror x16,x27,#14 + add x22,x22,x28 // h+=K[i] + ror x15,x10,#1 + and x17,x20,x27 + ror x14,x7,#19 + bic x28,x21,x27 + ror x0,x23,#28 + add x22,x22,x8 // h+=X[i] + eor x16,x16,x27,ror#18 + eor x15,x15,x10,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x23,x24 // a^b, b^c in next round + eor x16,x16,x27,ror#41 // Sigma1(e) + eor x0,x0,x23,ror#34 + add x22,x22,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x14,x14,x7,ror#61 + eor x15,x15,x10,lsr#7 // sigma0(X[i+1]) + add x22,x22,x16 // h+=Sigma1(e) + eor x19,x19,x24 // Maj(a,b,c) + eor x17,x0,x23,ror#39 // Sigma0(a) + eor x14,x14,x7,lsr#6 // sigma1(X[i+14]) + add x9,x9,x2 + add x26,x26,x22 // d+=h + add x22,x22,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x9,x9,x15 + add x22,x22,x17 // h+=Sigma0(a) + add x9,x9,x14 + ldr x14,[sp,#24] + str x1,[sp,#16] + ror x16,x26,#14 + add x21,x21,x19 // h+=K[i] + ror x0,x11,#1 + and x17,x27,x26 + ror x15,x8,#19 + bic x19,x20,x26 + ror x1,x22,#28 + add x21,x21,x9 // h+=X[i] + eor x16,x16,x26,ror#18 + eor x0,x0,x11,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x22,x23 // a^b, b^c in next round + eor x16,x16,x26,ror#41 // Sigma1(e) + eor x1,x1,x22,ror#34 + add x21,x21,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x15,x15,x8,ror#61 + eor x0,x0,x11,lsr#7 // sigma0(X[i+1]) + add x21,x21,x16 // h+=Sigma1(e) + eor x28,x28,x23 // Maj(a,b,c) + eor x17,x1,x22,ror#39 // Sigma0(a) + eor x15,x15,x8,lsr#6 // sigma1(X[i+14]) + add x10,x10,x3 + add x25,x25,x21 // d+=h + add x21,x21,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x10,x10,x0 + add x21,x21,x17 // h+=Sigma0(a) + add x10,x10,x15 + ldr x15,[sp,#0] + str x2,[sp,#24] + ror x16,x25,#14 + add x20,x20,x28 // h+=K[i] + ror x1,x12,#1 + and x17,x26,x25 + ror x0,x9,#19 + bic x28,x27,x25 + ror x2,x21,#28 + add x20,x20,x10 // h+=X[i] + eor x16,x16,x25,ror#18 + eor x1,x1,x12,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x21,x22 // a^b, b^c in next round + eor x16,x16,x25,ror#41 // Sigma1(e) + eor x2,x2,x21,ror#34 + add x20,x20,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x0,x0,x9,ror#61 + eor x1,x1,x12,lsr#7 // sigma0(X[i+1]) + add x20,x20,x16 // h+=Sigma1(e) + eor x19,x19,x22 // Maj(a,b,c) + eor x17,x2,x21,ror#39 // Sigma0(a) + eor x0,x0,x9,lsr#6 // sigma1(X[i+14]) + add x11,x11,x4 + add x24,x24,x20 // d+=h + add x20,x20,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x11,x11,x1 + add x20,x20,x17 // h+=Sigma0(a) + add x11,x11,x0 + ldr x0,[sp,#8] + str x3,[sp,#0] + ror x16,x24,#14 + add x27,x27,x19 // h+=K[i] + ror x2,x13,#1 + and x17,x25,x24 + ror x1,x10,#19 + bic x19,x26,x24 + ror x3,x20,#28 + add x27,x27,x11 // h+=X[i] + eor x16,x16,x24,ror#18 + eor x2,x2,x13,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x20,x21 // a^b, b^c in next round + eor x16,x16,x24,ror#41 // Sigma1(e) + eor x3,x3,x20,ror#34 + add x27,x27,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x1,x1,x10,ror#61 + eor x2,x2,x13,lsr#7 // sigma0(X[i+1]) + add x27,x27,x16 // h+=Sigma1(e) + eor x28,x28,x21 // Maj(a,b,c) + eor x17,x3,x20,ror#39 // Sigma0(a) + eor x1,x1,x10,lsr#6 // sigma1(X[i+14]) + add x12,x12,x5 + add x23,x23,x27 // d+=h + add x27,x27,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x12,x12,x2 + add x27,x27,x17 // h+=Sigma0(a) + add x12,x12,x1 + ldr x1,[sp,#16] + str x4,[sp,#8] + ror x16,x23,#14 + add x26,x26,x28 // h+=K[i] + ror x3,x14,#1 + and x17,x24,x23 + ror x2,x11,#19 + bic x28,x25,x23 + ror x4,x27,#28 + add x26,x26,x12 // h+=X[i] + eor x16,x16,x23,ror#18 + eor x3,x3,x14,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x27,x20 // a^b, b^c in next round + eor x16,x16,x23,ror#41 // Sigma1(e) + eor x4,x4,x27,ror#34 + add x26,x26,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x2,x2,x11,ror#61 + eor x3,x3,x14,lsr#7 // sigma0(X[i+1]) + add x26,x26,x16 // h+=Sigma1(e) + eor x19,x19,x20 // Maj(a,b,c) + eor x17,x4,x27,ror#39 // Sigma0(a) + eor x2,x2,x11,lsr#6 // sigma1(X[i+14]) + add x13,x13,x6 + add x22,x22,x26 // d+=h + add x26,x26,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x13,x13,x3 + add x26,x26,x17 // h+=Sigma0(a) + add x13,x13,x2 + ldr x2,[sp,#24] + str x5,[sp,#16] + ror x16,x22,#14 + add x25,x25,x19 // h+=K[i] + ror x4,x15,#1 + and x17,x23,x22 + ror x3,x12,#19 + bic x19,x24,x22 + ror x5,x26,#28 + add x25,x25,x13 // h+=X[i] + eor x16,x16,x22,ror#18 + eor x4,x4,x15,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x26,x27 // a^b, b^c in next round + eor x16,x16,x22,ror#41 // Sigma1(e) + eor x5,x5,x26,ror#34 + add x25,x25,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x3,x3,x12,ror#61 + eor x4,x4,x15,lsr#7 // sigma0(X[i+1]) + add x25,x25,x16 // h+=Sigma1(e) + eor x28,x28,x27 // Maj(a,b,c) + eor x17,x5,x26,ror#39 // Sigma0(a) + eor x3,x3,x12,lsr#6 // sigma1(X[i+14]) + add x14,x14,x7 + add x21,x21,x25 // d+=h + add x25,x25,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x14,x14,x4 + add x25,x25,x17 // h+=Sigma0(a) + add x14,x14,x3 + ldr x3,[sp,#0] + str x6,[sp,#24] + ror x16,x21,#14 + add x24,x24,x28 // h+=K[i] + ror x5,x0,#1 + and x17,x22,x21 + ror x4,x13,#19 + bic x28,x23,x21 + ror x6,x25,#28 + add x24,x24,x14 // h+=X[i] + eor x16,x16,x21,ror#18 + eor x5,x5,x0,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x25,x26 // a^b, b^c in next round + eor x16,x16,x21,ror#41 // Sigma1(e) + eor x6,x6,x25,ror#34 + add x24,x24,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x4,x4,x13,ror#61 + eor x5,x5,x0,lsr#7 // sigma0(X[i+1]) + add x24,x24,x16 // h+=Sigma1(e) + eor x19,x19,x26 // Maj(a,b,c) + eor x17,x6,x25,ror#39 // Sigma0(a) + eor x4,x4,x13,lsr#6 // sigma1(X[i+14]) + add x15,x15,x8 + add x20,x20,x24 // d+=h + add x24,x24,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x15,x15,x5 + add x24,x24,x17 // h+=Sigma0(a) + add x15,x15,x4 + ldr x4,[sp,#8] + str x7,[sp,#0] + ror x16,x20,#14 + add x23,x23,x19 // h+=K[i] + ror x6,x1,#1 + and x17,x21,x20 + ror x5,x14,#19 + bic x19,x22,x20 + ror x7,x24,#28 + add x23,x23,x15 // h+=X[i] + eor x16,x16,x20,ror#18 + eor x6,x6,x1,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x24,x25 // a^b, b^c in next round + eor x16,x16,x20,ror#41 // Sigma1(e) + eor x7,x7,x24,ror#34 + add x23,x23,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x5,x5,x14,ror#61 + eor x6,x6,x1,lsr#7 // sigma0(X[i+1]) + add x23,x23,x16 // h+=Sigma1(e) + eor x28,x28,x25 // Maj(a,b,c) + eor x17,x7,x24,ror#39 // Sigma0(a) + eor x5,x5,x14,lsr#6 // sigma1(X[i+14]) + add x0,x0,x9 + add x27,x27,x23 // d+=h + add x23,x23,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x0,x0,x6 + add x23,x23,x17 // h+=Sigma0(a) + add x0,x0,x5 + ldr x5,[sp,#16] + str x8,[sp,#8] + ror x16,x27,#14 + add x22,x22,x28 // h+=K[i] + ror x7,x2,#1 + and x17,x20,x27 + ror x6,x15,#19 + bic x28,x21,x27 + ror x8,x23,#28 + add x22,x22,x0 // h+=X[i] + eor x16,x16,x27,ror#18 + eor x7,x7,x2,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x23,x24 // a^b, b^c in next round + eor x16,x16,x27,ror#41 // Sigma1(e) + eor x8,x8,x23,ror#34 + add x22,x22,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x6,x6,x15,ror#61 + eor x7,x7,x2,lsr#7 // sigma0(X[i+1]) + add x22,x22,x16 // h+=Sigma1(e) + eor x19,x19,x24 // Maj(a,b,c) + eor x17,x8,x23,ror#39 // Sigma0(a) + eor x6,x6,x15,lsr#6 // sigma1(X[i+14]) + add x1,x1,x10 + add x26,x26,x22 // d+=h + add x22,x22,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x1,x1,x7 + add x22,x22,x17 // h+=Sigma0(a) + add x1,x1,x6 + ldr x6,[sp,#24] + str x9,[sp,#16] + ror x16,x26,#14 + add x21,x21,x19 // h+=K[i] + ror x8,x3,#1 + and x17,x27,x26 + ror x7,x0,#19 + bic x19,x20,x26 + ror x9,x22,#28 + add x21,x21,x1 // h+=X[i] + eor x16,x16,x26,ror#18 + eor x8,x8,x3,ror#8 + orr x17,x17,x19 // Ch(e,f,g) + eor x19,x22,x23 // a^b, b^c in next round + eor x16,x16,x26,ror#41 // Sigma1(e) + eor x9,x9,x22,ror#34 + add x21,x21,x17 // h+=Ch(e,f,g) + and x28,x28,x19 // (b^c)&=(a^b) + eor x7,x7,x0,ror#61 + eor x8,x8,x3,lsr#7 // sigma0(X[i+1]) + add x21,x21,x16 // h+=Sigma1(e) + eor x28,x28,x23 // Maj(a,b,c) + eor x17,x9,x22,ror#39 // Sigma0(a) + eor x7,x7,x0,lsr#6 // sigma1(X[i+14]) + add x2,x2,x11 + add x25,x25,x21 // d+=h + add x21,x21,x28 // h+=Maj(a,b,c) + ldr x28,[x30],#8 // *K++, x19 in next round + add x2,x2,x8 + add x21,x21,x17 // h+=Sigma0(a) + add x2,x2,x7 + ldr x7,[sp,#0] + str x10,[sp,#24] + ror x16,x25,#14 + add x20,x20,x28 // h+=K[i] + ror x9,x4,#1 + and x17,x26,x25 + ror x8,x1,#19 + bic x28,x27,x25 + ror x10,x21,#28 + add x20,x20,x2 // h+=X[i] + eor x16,x16,x25,ror#18 + eor x9,x9,x4,ror#8 + orr x17,x17,x28 // Ch(e,f,g) + eor x28,x21,x22 // a^b, b^c in next round + eor x16,x16,x25,ror#41 // Sigma1(e) + eor x10,x10,x21,ror#34 + add x20,x20,x17 // h+=Ch(e,f,g) + and x19,x19,x28 // (b^c)&=(a^b) + eor x8,x8,x1,ror#61 + eor x9,x9,x4,lsr#7 // sigma0(X[i+1]) + add x20,x20,x16 // h+=Sigma1(e) + eor x19,x19,x22 // Maj(a,b,c) + eor x17,x10,x21,ror#39 // Sigma0(a) + eor x8,x8,x1,lsr#6 // sigma1(X[i+14]) + add x3,x3,x12 + add x24,x24,x20 // d+=h + add x20,x20,x19 // h+=Maj(a,b,c) + ldr x19,[x30],#8 // *K++, x28 in next round + add x3,x3,x9 + add x20,x20,x17 // h+=Sigma0(a) + add x3,x3,x8 + cbnz x19,.Loop_16_xx + + ldp x0,x2,[x29,#96] + ldr x1,[x29,#112] + sub x30,x30,#648 // rewind + + ldp x3,x4,[x0] + ldp x5,x6,[x0,#2*8] + add x1,x1,#14*8 // advance input pointer + ldp x7,x8,[x0,#4*8] + add x20,x20,x3 + ldp x9,x10,[x0,#6*8] + add x21,x21,x4 + add x22,x22,x5 + add x23,x23,x6 + stp x20,x21,[x0] + add x24,x24,x7 + add x25,x25,x8 + stp x22,x23,[x0,#2*8] + add x26,x26,x9 + add x27,x27,x10 + cmp x1,x2 + stp x24,x25,[x0,#4*8] + stp x26,x27,[x0,#6*8] + b.ne .Loop + + ldp x19,x20,[x29,#16] + add sp,sp,#4*8 + ldp x21,x22,[x29,#32] + ldp x23,x24,[x29,#48] + ldp x25,x26,[x29,#64] + ldp x27,x28,[x29,#80] + ldp x29,x30,[sp],#128 + ret +.size sha512_block_data_order,.-sha512_block_data_order + +.align 6 +.type .LK512,%object +.LK512: + .quad 0x428a2f98d728ae22,0x7137449123ef65cd + .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc + .quad 0x3956c25bf348b538,0x59f111f1b605d019 + .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118 + .quad 0xd807aa98a3030242,0x12835b0145706fbe + .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2 + .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1 + .quad 0x9bdc06a725c71235,0xc19bf174cf692694 + .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3 + .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65 + .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483 + .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5 + .quad 0x983e5152ee66dfab,0xa831c66d2db43210 + .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4 + .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725 + .quad 0x06ca6351e003826f,0x142929670a0e6e70 + .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926 + .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df + .quad 0x650a73548baf63de,0x766a0abb3c77b2a8 + .quad 0x81c2c92e47edaee6,0x92722c851482353b + .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001 + .quad 0xc24b8b70d0f89791,0xc76c51a30654be30 + .quad 0xd192e819d6ef5218,0xd69906245565a910 + .quad 0xf40e35855771202a,0x106aa07032bbd1b8 + .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53 + .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8 + .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb + .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3 + .quad 0x748f82ee5defb2fc,0x78a5636f43172f60 + .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec + .quad 0x90befffa23631e28,0xa4506cebde82bde9 + .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b + .quad 0xca273eceea26619c,0xd186b8c721c0c207 + .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178 + .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6 + .quad 0x113f9804bef90dae,0x1b710b35131c471b + .quad 0x28db77f523047d84,0x32caab7b40c72493 + .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c + .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a + .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817 + .quad 0 // terminator +.size .LK512,.-.LK512 +#ifndef __KERNEL__ +.align 3 +.LOPENSSL_armcap_P: +# ifdef __ILP32__ + .long OPENSSL_armcap_P-. +# else + .quad OPENSSL_armcap_P-. +# endif +#endif +.asciz "SHA512 block transform for ARMv8, CRYPTOGAMS by " +.align 2 +#ifndef __KERNEL__ +.comm OPENSSL_armcap_P,4,4 +#endif diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S index dec95bd82e31..c72f261f4b64 100644 --- a/arch/arm64/kernel/bpi.S +++ b/arch/arm64/kernel/bpi.S @@ -17,6 +17,7 @@ */ #include +#include .macro ventry target .rept 31 @@ -77,3 +78,22 @@ ENTRY(__psci_hyp_bp_inval_start) ldp x0, x1, [sp, #(16 * 8)] add sp, sp, #(8 * 18) ENTRY(__psci_hyp_bp_inval_end) + +.macro smccc_workaround_1 inst + sub sp, sp, #(8 * 4) + stp x2, x3, [sp, #(8 * 0)] + stp x0, x1, [sp, #(8 * 2)] + mov w0, #ARM_SMCCC_ARCH_WORKAROUND_1 + \inst #0 + ldp x2, x3, [sp, #(8 * 0)] + ldp x0, x1, [sp, #(8 * 2)] + add sp, sp, #(8 * 4) +.endm + +ENTRY(__smccc_workaround_1_smc_start) + smccc_workaround_1 smc +ENTRY(__smccc_workaround_1_smc_end) + +ENTRY(__smccc_workaround_1_hvc_start) + smccc_workaround_1 hvc +ENTRY(__smccc_workaround_1_hvc_end) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index 67cdfc6a458e..a91239bd8696 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -54,6 +54,10 @@ DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); #ifdef CONFIG_KVM extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; +extern char __smccc_workaround_1_smc_start[]; +extern char __smccc_workaround_1_smc_end[]; +extern char __smccc_workaround_1_hvc_start[]; +extern char __smccc_workaround_1_hvc_end[]; static void __copy_hyp_vect_bpi(int slot, const char *hyp_vecs_start, const char *hyp_vecs_end) @@ -96,8 +100,12 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, spin_unlock(&bp_lock); } #else -#define __psci_hyp_bp_inval_start NULL -#define __psci_hyp_bp_inval_end NULL +#define __psci_hyp_bp_inval_start NULL +#define __psci_hyp_bp_inval_end NULL +#define __smccc_workaround_1_smc_start NULL +#define __smccc_workaround_1_smc_end NULL +#define __smccc_workaround_1_hvc_start NULL +#define __smccc_workaround_1_hvc_end NULL static void __install_bp_hardening_cb(bp_hardening_cb_t fn, const char *hyp_vecs_start, @@ -124,17 +132,75 @@ static void install_bp_hardening_cb(const struct arm64_cpu_capabilities *entry, __install_bp_hardening_cb(fn, hyp_vecs_start, hyp_vecs_end); } +#include +#include #include +static void call_smc_arch_workaround_1(void) +{ + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); +} + +static void call_hvc_arch_workaround_1(void) +{ + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); +} + +static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry) +{ + bp_hardening_cb_t cb; + void *smccc_start, *smccc_end; + struct arm_smccc_res res; + + if (!entry->matches(entry, SCOPE_LOCAL_CPU)) + return false; + + if (psci_ops.smccc_version == SMCCC_VERSION_1_0) + return false; + + switch (psci_ops.conduit) { + case PSCI_CONDUIT_HVC: + arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); + if (res.a0) + return false; + cb = call_hvc_arch_workaround_1; + smccc_start = __smccc_workaround_1_hvc_start; + smccc_end = __smccc_workaround_1_hvc_end; + break; + + case PSCI_CONDUIT_SMC: + arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, + ARM_SMCCC_ARCH_WORKAROUND_1, &res); + if (res.a0) + return false; + cb = call_smc_arch_workaround_1; + smccc_start = __smccc_workaround_1_smc_start; + smccc_end = __smccc_workaround_1_smc_end; + break; + + default: + return false; + } + + install_bp_hardening_cb(entry, cb, smccc_start, smccc_end); + + return true; +} + static int enable_psci_bp_hardening(void *data) { const struct arm64_cpu_capabilities *entry = data; - if (psci_ops.get_version) + if (psci_ops.get_version) { + if (check_smccc_arch_workaround_1(entry)) + return 0; + install_bp_hardening_cb(entry, (bp_hardening_cb_t)psci_ops.get_version, __psci_hyp_bp_inval_start, __psci_hyp_bp_inval_end); + } return 0; } -- GitLab From 288b1dde54cbc930b8a61d1b7395141db86cc67a Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 12 Apr 2018 12:11:38 +0100 Subject: [PATCH 1376/1834] arm64: Kill PSCI_GET_VERSION as a variant-2 workaround From: Marc Zyngier commit 3a0a397ff5ff8b56ca9f7908b75dee6bf0b5fabb upstream. Now that we've standardised on SMCCC v1.1 to perform the branch prediction invalidation, let's drop the previous band-aid. If vendors haven't updated their firmware to do SMCCC 1.1, they haven't updated PSCI either, so we don't loose anything. Tested-by: Ard Biesheuvel Signed-off-by: Marc Zyngier Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Tested-by: Greg Hackmann Signed-off-by: Greg Kroah-Hartman --- arch/arm64/kernel/bpi.S | 24 ------------------ arch/arm64/kernel/cpu_errata.c | 45 ++++++++++------------------------ arch/arm64/kvm/hyp/switch.c | 14 ----------- 3 files changed, 13 insertions(+), 70 deletions(-) diff --git a/arch/arm64/kernel/bpi.S b/arch/arm64/kernel/bpi.S index c72f261f4b64..dc4eb154e33b 100644 --- a/arch/arm64/kernel/bpi.S +++ b/arch/arm64/kernel/bpi.S @@ -54,30 +54,6 @@ ENTRY(__bp_harden_hyp_vecs_start) vectors __kvm_hyp_vector .endr ENTRY(__bp_harden_hyp_vecs_end) -ENTRY(__psci_hyp_bp_inval_start) - sub sp, sp, #(8 * 18) - stp x16, x17, [sp, #(16 * 0)] - stp x14, x15, [sp, #(16 * 1)] - stp x12, x13, [sp, #(16 * 2)] - stp x10, x11, [sp, #(16 * 3)] - stp x8, x9, [sp, #(16 * 4)] - stp x6, x7, [sp, #(16 * 5)] - stp x4, x5, [sp, #(16 * 6)] - stp x2, x3, [sp, #(16 * 7)] - stp x0, x1, [sp, #(16 * 8)] - mov x0, #0x84000000 - smc #0 - ldp x16, x17, [sp, #(16 * 0)] - ldp x14, x15, [sp, #(16 * 1)] - ldp x12, x13, [sp, #(16 * 2)] - ldp x10, x11, [sp, #(16 * 3)] - ldp x8, x9, [sp, #(16 * 4)] - ldp x6, x7, [sp, #(16 * 5)] - ldp x4, x5, [sp, #(16 * 6)] - ldp x2, x3, [sp, #(16 * 7)] - ldp x0, x1, [sp, #(16 * 8)] - add sp, sp, #(8 * 18) -ENTRY(__psci_hyp_bp_inval_end) .macro smccc_workaround_1 inst sub sp, sp, #(8 * 4) diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index a91239bd8696..74107134cc30 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -53,7 +53,6 @@ static int cpu_enable_trap_ctr_access(void *__unused) DEFINE_PER_CPU_READ_MOSTLY(struct bp_hardening_data, bp_hardening_data); #ifdef CONFIG_KVM -extern char __psci_hyp_bp_inval_start[], __psci_hyp_bp_inval_end[]; extern char __smccc_workaround_1_smc_start[]; extern char __smccc_workaround_1_smc_end[]; extern char __smccc_workaround_1_hvc_start[]; @@ -100,8 +99,6 @@ static void __install_bp_hardening_cb(bp_hardening_cb_t fn, spin_unlock(&bp_lock); } #else -#define __psci_hyp_bp_inval_start NULL -#define __psci_hyp_bp_inval_end NULL #define __smccc_workaround_1_smc_start NULL #define __smccc_workaround_1_smc_end NULL #define __smccc_workaround_1_hvc_start NULL @@ -146,24 +143,25 @@ static void call_hvc_arch_workaround_1(void) arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_WORKAROUND_1, NULL); } -static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry) +static int enable_smccc_arch_workaround_1(void *data) { + const struct arm64_cpu_capabilities *entry = data; bp_hardening_cb_t cb; void *smccc_start, *smccc_end; struct arm_smccc_res res; if (!entry->matches(entry, SCOPE_LOCAL_CPU)) - return false; + return 0; if (psci_ops.smccc_version == SMCCC_VERSION_1_0) - return false; + return 0; switch (psci_ops.conduit) { case PSCI_CONDUIT_HVC: arm_smccc_1_1_hvc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); if (res.a0) - return false; + return 0; cb = call_hvc_arch_workaround_1; smccc_start = __smccc_workaround_1_hvc_start; smccc_end = __smccc_workaround_1_hvc_end; @@ -173,35 +171,18 @@ static bool check_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *e arm_smccc_1_1_smc(ARM_SMCCC_ARCH_FEATURES_FUNC_ID, ARM_SMCCC_ARCH_WORKAROUND_1, &res); if (res.a0) - return false; + return 0; cb = call_smc_arch_workaround_1; smccc_start = __smccc_workaround_1_smc_start; smccc_end = __smccc_workaround_1_smc_end; break; default: - return false; + return 0; } install_bp_hardening_cb(entry, cb, smccc_start, smccc_end); - return true; -} - -static int enable_psci_bp_hardening(void *data) -{ - const struct arm64_cpu_capabilities *entry = data; - - if (psci_ops.get_version) { - if (check_smccc_arch_workaround_1(entry)) - return 0; - - install_bp_hardening_cb(entry, - (bp_hardening_cb_t)psci_ops.get_version, - __psci_hyp_bp_inval_start, - __psci_hyp_bp_inval_end); - } - return 0; } #endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */ @@ -301,32 +282,32 @@ const struct arm64_cpu_capabilities arm64_errata[] = { { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, MIDR_ALL_VERSIONS(MIDR_CORTEX_A57), - .enable = enable_psci_bp_hardening, + .enable = enable_smccc_arch_workaround_1, }, { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, MIDR_ALL_VERSIONS(MIDR_CORTEX_A72), - .enable = enable_psci_bp_hardening, + .enable = enable_smccc_arch_workaround_1, }, { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, MIDR_ALL_VERSIONS(MIDR_CORTEX_A73), - .enable = enable_psci_bp_hardening, + .enable = enable_smccc_arch_workaround_1, }, { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, MIDR_ALL_VERSIONS(MIDR_CORTEX_A75), - .enable = enable_psci_bp_hardening, + .enable = enable_smccc_arch_workaround_1, }, { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, MIDR_ALL_VERSIONS(MIDR_BRCM_VULCAN), - .enable = enable_psci_bp_hardening, + .enable = enable_smccc_arch_workaround_1, }, { .capability = ARM64_HARDEN_BRANCH_PREDICTOR, MIDR_ALL_VERSIONS(MIDR_CAVIUM_THUNDERX2), - .enable = enable_psci_bp_hardening, + .enable = enable_smccc_arch_workaround_1, }, #endif { diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c index 849ee8a17525..c49d09387192 100644 --- a/arch/arm64/kvm/hyp/switch.c +++ b/arch/arm64/kvm/hyp/switch.c @@ -311,20 +311,6 @@ int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu) if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu)) goto again; - if (exit_code == ARM_EXCEPTION_TRAP && - (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC64 || - kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_HVC32)) { - u32 val = vcpu_get_reg(vcpu, 0); - - if (val == PSCI_0_2_FN_PSCI_VERSION) { - val = kvm_psci_version(vcpu, kern_hyp_va(vcpu->kvm)); - if (unlikely(val == KVM_ARM_PSCI_0_1)) - val = PSCI_RET_NOT_SUPPORTED; - vcpu_set_reg(vcpu, 0, val); - goto again; - } - } - if (static_branch_unlikely(&vgic_v2_cpuif_trap) && exit_code == ARM_EXCEPTION_TRAP) { bool valid; -- GitLab From 994baf8abdac7555e7008643053c13d69fb5e3e5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 28 Mar 2018 10:57:22 -0700 Subject: [PATCH 1377/1834] sunrpc: remove incorrect HMAC request initialization commit f3aefb6a7066e24bfea7fcf1b07907576de69d63 upstream. make_checksum_hmac_md5() is allocating an HMAC transform and doing crypto API calls in the following order: crypto_ahash_init() crypto_ahash_setkey() crypto_ahash_digest() This is wrong because it makes no sense to init() the request before a key has been set, given that the initial state depends on the key. And digest() is short for init() + update() + final(), so in this case there's no need to explicitly call init() at all. Before commit 9fa68f620041 ("crypto: hash - prevent using keyed hashes without setting key") the extra init() had no real effect, at least for the software HMAC implementation. (There are also hardware drivers that implement HMAC-MD5, and it's not immediately obvious how gracefully they handle init() before setkey().) But now the crypto API detects this incorrect initialization and returns -ENOKEY. This is breaking NFS mounts in some cases. Fix it by removing the incorrect call to crypto_ahash_init(). Reported-by: Michael Young Fixes: 9fa68f620041 ("crypto: hash - prevent using keyed hashes without setting key") Fixes: fffdaef2eb4a ("gss_krb5: Add support for rc4-hmac encryption") Cc: stable@vger.kernel.org Signed-off-by: Eric Biggers Signed-off-by: J. Bruce Fields Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/auth_gss/gss_krb5_crypto.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 79aec90259cd..4afd4149a632 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c @@ -237,9 +237,6 @@ make_checksum_hmac_md5(struct krb5_ctx *kctx, char *header, int hdrlen, ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL); - err = crypto_ahash_init(req); - if (err) - goto out; err = crypto_ahash_setkey(hmac_md5, cksumkey, kctx->gk5e->keylength); if (err) goto out; -- GitLab From 6ba906fca335e6f9e66a2ed00ced31686c6e0882 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 17 Apr 2018 14:56:21 +0200 Subject: [PATCH 1378/1834] Revert "perf tests: Decompress kernel module before objdump" This reverts commit 7525a238be8f46617cdda29d1be5b85ffe3b042d which is commit 94df1040b1e6aacd8dec0ba3c61d7e77cd695f26 upstream. It breaks the build of perf on 4.9.y, so I'm dropping it. Reported-by: Pavlos Parissis Reported-by: Lei Chen Reported-by: Maxime Hadjinlian Cc: Namhyung Kim Cc: Adrian Hunter Cc: Jiri Olsa Cc: David Ahern Cc: Peter Zijlstra Cc: Wang Nan Cc: kernel-team@lge.com Cc: Arnaldo Carvalho de Melo Cc: Sasha Levin Signed-off-by: Greg Kroah-Hartman --- tools/perf/tests/code-reading.c | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index 150334064071..ff5bc6363a79 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -224,8 +224,6 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, unsigned char buf2[BUFSZ]; size_t ret_len; u64 objdump_addr; - const char *objdump_name; - char decomp_name[KMOD_DECOMP_LEN]; int ret; pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr); @@ -286,25 +284,9 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, state->done[state->done_cnt++] = al.map->start; } - objdump_name = al.map->dso->long_name; - if (dso__needs_decompress(al.map->dso)) { - if (dso__decompress_kmodule_path(al.map->dso, objdump_name, - decomp_name, - sizeof(decomp_name)) < 0) { - pr_debug("decompression failed\n"); - return -1; - } - - objdump_name = decomp_name; - } - /* Read the object code using objdump */ objdump_addr = map__rip_2objdump(al.map, al.addr); - ret = read_via_objdump(objdump_name, objdump_addr, buf2, len); - - if (dso__needs_decompress(al.map->dso)) - unlink(objdump_name); - + ret = read_via_objdump(al.map->dso->long_name, objdump_addr, buf2, len); if (ret > 0) { /* * The kernel maps are inaccurate - assume objdump is right in -- GitLab From c3530143fe2442b2b84abe4d720efb2cf6ec4338 Mon Sep 17 00:00:00 2001 From: Tetsuo Handa Date: Fri, 6 Apr 2018 10:03:17 +0900 Subject: [PATCH 1379/1834] block/loop: fix deadlock after loop_set_status commit 1e047eaab3bb5564f25b41e9cd3a053009f4e789 upstream. syzbot is reporting deadlocks at __blkdev_get() [1]. ---------------------------------------- [ 92.493919] systemd-udevd D12696 525 1 0x00000000 [ 92.495891] Call Trace: [ 92.501560] schedule+0x23/0x80 [ 92.502923] schedule_preempt_disabled+0x5/0x10 [ 92.504645] __mutex_lock+0x416/0x9e0 [ 92.510760] __blkdev_get+0x73/0x4f0 [ 92.512220] blkdev_get+0x12e/0x390 [ 92.518151] do_dentry_open+0x1c3/0x2f0 [ 92.519815] path_openat+0x5d9/0xdc0 [ 92.521437] do_filp_open+0x7d/0xf0 [ 92.527365] do_sys_open+0x1b8/0x250 [ 92.528831] do_syscall_64+0x6e/0x270 [ 92.530341] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 92.931922] 1 lock held by systemd-udevd/525: [ 92.933642] #0: 00000000a2849e25 (&bdev->bd_mutex){+.+.}, at: __blkdev_get+0x73/0x4f0 ---------------------------------------- The reason of deadlock turned out that wait_event_interruptible() in blk_queue_enter() got stuck with bdev->bd_mutex held at __blkdev_put() due to q->mq_freeze_depth == 1. ---------------------------------------- [ 92.787172] a.out S12584 634 633 0x80000002 [ 92.789120] Call Trace: [ 92.796693] schedule+0x23/0x80 [ 92.797994] blk_queue_enter+0x3cb/0x540 [ 92.803272] generic_make_request+0xf0/0x3d0 [ 92.807970] submit_bio+0x67/0x130 [ 92.810928] submit_bh_wbc+0x15e/0x190 [ 92.812461] __block_write_full_page+0x218/0x460 [ 92.815792] __writepage+0x11/0x50 [ 92.817209] write_cache_pages+0x1ae/0x3d0 [ 92.825585] generic_writepages+0x5a/0x90 [ 92.831865] do_writepages+0x43/0xd0 [ 92.836972] __filemap_fdatawrite_range+0xc1/0x100 [ 92.838788] filemap_write_and_wait+0x24/0x70 [ 92.840491] __blkdev_put+0x69/0x1e0 [ 92.841949] blkdev_close+0x16/0x20 [ 92.843418] __fput+0xda/0x1f0 [ 92.844740] task_work_run+0x87/0xb0 [ 92.846215] do_exit+0x2f5/0xba0 [ 92.850528] do_group_exit+0x34/0xb0 [ 92.852018] SyS_exit_group+0xb/0x10 [ 92.853449] do_syscall_64+0x6e/0x270 [ 92.854944] entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ 92.943530] 1 lock held by a.out/634: [ 92.945105] #0: 00000000a2849e25 (&bdev->bd_mutex){+.+.}, at: __blkdev_put+0x3c/0x1e0 ---------------------------------------- The reason of q->mq_freeze_depth == 1 turned out that loop_set_status() forgot to call blk_mq_unfreeze_queue() at error paths for info->lo_encrypt_type != NULL case. ---------------------------------------- [ 37.509497] CPU: 2 PID: 634 Comm: a.out Tainted: G W 4.16.0+ #457 [ 37.513608] Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 05/19/2017 [ 37.518832] RIP: 0010:blk_freeze_queue_start+0x17/0x40 [ 37.521778] RSP: 0018:ffffb0c2013e7c60 EFLAGS: 00010246 [ 37.524078] RAX: 0000000000000000 RBX: ffff8b07b1519798 RCX: 0000000000000000 [ 37.527015] RDX: 0000000000000002 RSI: ffffb0c2013e7cc0 RDI: ffff8b07b1519798 [ 37.529934] RBP: ffffb0c2013e7cc0 R08: 0000000000000008 R09: 47a189966239b898 [ 37.532684] R10: dad78b99b278552f R11: 9332dca72259d5ef R12: ffff8b07acd73678 [ 37.535452] R13: 0000000000004c04 R14: 0000000000000000 R15: ffff8b07b841e940 [ 37.538186] FS: 00007fede33b9740(0000) GS:ffff8b07b8e80000(0000) knlGS:0000000000000000 [ 37.541168] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 37.543590] CR2: 00000000206fdf18 CR3: 0000000130b30006 CR4: 00000000000606e0 [ 37.546410] Call Trace: [ 37.547902] blk_freeze_queue+0x9/0x30 [ 37.549968] loop_set_status+0x67/0x3c0 [loop] [ 37.549975] loop_set_status64+0x3b/0x70 [loop] [ 37.549986] lo_ioctl+0x223/0x810 [loop] [ 37.549995] blkdev_ioctl+0x572/0x980 [ 37.550003] block_ioctl+0x34/0x40 [ 37.550006] do_vfs_ioctl+0xa7/0x6d0 [ 37.550017] ksys_ioctl+0x6b/0x80 [ 37.573076] SyS_ioctl+0x5/0x10 [ 37.574831] do_syscall_64+0x6e/0x270 [ 37.576769] entry_SYSCALL_64_after_hwframe+0x42/0xb7 ---------------------------------------- [1] https://syzkaller.appspot.com/bug?id=cd662bc3f6022c0979d01a262c318fab2ee9b56f Signed-off-by: Tetsuo Handa Reported-by: syzbot Fixes: ecdd09597a572513 ("block/loop: fix race between I/O and set_status") Cc: Ming Lei Cc: Dmitry Vyukov Cc: stable Cc: Jens Axboe Signed-off-by: Jens Axboe Signed-off-by: Greg Kroah-Hartman --- drivers/block/loop.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index dc318b9100c2..ff1c4d7aa025 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1110,11 +1110,15 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (info->lo_encrypt_type) { unsigned int type = info->lo_encrypt_type; - if (type >= MAX_LO_CRYPT) - return -EINVAL; + if (type >= MAX_LO_CRYPT) { + err = -EINVAL; + goto exit; + } xfer = xfer_funcs[type]; - if (xfer == NULL) - return -EINVAL; + if (xfer == NULL) { + err = -EINVAL; + goto exit; + } } else xfer = NULL; -- GitLab From 768fce44221a2db5a68fdd1bd12dd2aed107cfe0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Apr 2018 16:49:30 -0700 Subject: [PATCH 1380/1834] nfit: fix region registration vs block-data-window ranges commit 8d0d8ed3356aa9ed43b819aaedd39b08ca453007 upstream. Commit 1cf03c00e7c1 "nfit: scrub and register regions in a workqueue" mistakenly attempts to register a region per BLK aperture. There is nothing to register for individual apertures as they belong as a set to a BLK aperture group that are registered with a corresponding DIMM-control-region. Filter them for registration to prevent some needless devm_kzalloc() allocations. Cc: Fixes: 1cf03c00e7c1 ("nfit: scrub and register regions in a workqueue") Reviewed-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/nfit/core.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index b1815b20a99c..37032545c58e 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2547,15 +2547,21 @@ static void acpi_nfit_scrub(struct work_struct *work) static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc) { struct nfit_spa *nfit_spa; - int rc; - list_for_each_entry(nfit_spa, &acpi_desc->spas, list) - if (nfit_spa_type(nfit_spa->spa) == NFIT_SPA_DCR) { - /* BLK regions don't need to wait for ars results */ - rc = acpi_nfit_register_region(acpi_desc, nfit_spa); - if (rc) - return rc; - } + list_for_each_entry(nfit_spa, &acpi_desc->spas, list) { + int rc, type = nfit_spa_type(nfit_spa->spa); + + /* PMEM and VMEM will be registered by the ARS workqueue */ + if (type == NFIT_SPA_PM || type == NFIT_SPA_VOLATILE) + continue; + /* BLK apertures belong to BLK region registration below */ + if (type == NFIT_SPA_BDW) + continue; + /* BLK regions don't need to wait for ARS results */ + rc = acpi_nfit_register_region(acpi_desc, nfit_spa); + if (rc) + return rc; + } queue_work(nfit_wq, &acpi_desc->work); return 0; -- GitLab From deda8e039680411eb881fcea17f5a358bc4c4589 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Mon, 5 Mar 2018 09:39:38 +0100 Subject: [PATCH 1381/1834] s390/qdio: don't retry EQBS after CCQ 96 commit dae55b6fef58530c13df074bcc182c096609339e upstream. Immediate retry of EQBS after CCQ 96 means that we potentially misreport the state of buffers inspected during the first EQBS call. This occurs when 1. the first EQBS finds all inspected buffers still in the initial state set by the driver (ie INPUT EMPTY or OUTPUT PRIMED), 2. the EQBS terminates early with CCQ 96, and 3. by the time that the second EQBS comes around, the state of those previously inspected buffers has changed. If the state reported by the second EQBS is 'driver-owned', all we know is that the previous buffers are driver-owned now as well. But we can't tell if they all have the same state. So for instance - the second EQBS reports OUTPUT EMPTY, but any number of the previous buffers could be OUTPUT ERROR by now, - the second EQBS reports OUTPUT ERROR, but any number of the previous buffers could be OUTPUT EMPTY by now. Effectively, this can result in both over- and underreporting of errors. If the state reported by the second EQBS is 'HW-owned', that doesn't guarantee that the previous buffers have not been switched to driver-owned in the mean time. So for instance - the second EQBS reports INPUT EMPTY, but any number of the previous buffers could be INPUT PRIMED (or INPUT ERROR) by now. This would result in failure to process pending work on the queue. If it's the final check before yielding initiative, this can cause a (temporary) queue stall due to IRQ avoidance. Fixes: 25f269f17316 ("[S390] qdio: EQBS retry after CCQ 96") Cc: #v3.2+ Signed-off-by: Julian Wiedmann Reviewed-by: Benjamin Block Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/qdio_main.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 71bf9bded485..601010f2d270 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -126,7 +126,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, int start, int count, int auto_ack) { - int rc, tmp_count = count, tmp_start = start, nr = q->nr, retried = 0; + int rc, tmp_count = count, tmp_start = start, nr = q->nr; unsigned int ccq = 0; qperf_inc(q, eqbs); @@ -149,14 +149,7 @@ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, qperf_inc(q, eqbs_partial); DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS part:%02x", tmp_count); - /* - * Retry once, if that fails bail out and process the - * extracted buffers before trying again. - */ - if (!retried++) - goto again; - else - return count - tmp_count; + return count - tmp_count; } DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); -- GitLab From 5a768873810afbd22b1c22a9f2d962b3fde10312 Mon Sep 17 00:00:00 2001 From: Julian Wiedmann Date: Wed, 7 Mar 2018 14:01:01 +0100 Subject: [PATCH 1382/1834] s390/qdio: don't merge ERROR output buffers commit 0cf1e05157b9e5530dcc3ca9fec9bf617fc93375 upstream. On an Output queue, both EMPTY and PENDING buffer states imply that the buffer is ready for completion-processing by the upper-layer drivers. So for a non-QEBSM Output queue, get_buf_states() merges mixed batches of PENDING and EMPTY buffers into one large batch of EMPTY buffers. The upper-layer driver (ie. qeth) later distuingishes PENDING from EMPTY by inspecting the slsb_state for QDIO_OUTBUF_STATE_FLAG_PENDING. But the merge logic in get_buf_states() contains a bug that causes us to erronously also merge ERROR buffers into such a batch of EMPTY buffers (ERROR is 0xaf, EMPTY is 0xa1; so ERROR & EMPTY == EMPTY). Effectively, most outbound ERROR buffers are currently discarded silently and processed as if they had succeeded. Note that this affects _all_ non-QEBSM device types, not just IQD with CQ. Fix it by explicitly spelling out the exact conditions for merging. For extracting the "get initial state" part out of the loop, this relies on the fact that get_buf_states() is never called with a count of 0. The QEBSM path already strictly requires this, and the two callers with variable 'count' make sure of it. Fixes: 104ea556ee7f ("qdio: support asynchronous delivery of storage blocks") Cc: #v3.2+ Signed-off-by: Julian Wiedmann Reviewed-by: Ursula Braun Reviewed-by: Benjamin Block Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- drivers/s390/cio/qdio_main.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 601010f2d270..66e9bb053629 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -205,7 +205,10 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, return 0; } -/* returns number of examined buffers and their common state in *state */ +/* + * Returns number of examined buffers and their common state in *state. + * Requested number of buffers-to-examine must be > 0. + */ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, unsigned char *state, unsigned int count, int auto_ack, int merge_pending) @@ -216,17 +219,23 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, if (is_qebsm(q)) return qdio_do_eqbs(q, state, bufnr, count, auto_ack); - for (i = 0; i < count; i++) { - if (!__state) { - __state = q->slsb.val[bufnr]; - if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) - __state = SLSB_P_OUTPUT_EMPTY; - } else if (merge_pending) { - if ((q->slsb.val[bufnr] & __state) != __state) - break; - } else if (q->slsb.val[bufnr] != __state) - break; + /* get initial state: */ + __state = q->slsb.val[bufnr]; + if (merge_pending && __state == SLSB_P_OUTPUT_PENDING) + __state = SLSB_P_OUTPUT_EMPTY; + + for (i = 1; i < count; i++) { bufnr = next_buf(bufnr); + + /* merge PENDING into EMPTY: */ + if (merge_pending && + q->slsb.val[bufnr] == SLSB_P_OUTPUT_PENDING && + __state == SLSB_P_OUTPUT_EMPTY) + continue; + + /* stop if next state differs from initial state: */ + if (q->slsb.val[bufnr] != __state) + break; } *state = __state; return i; -- GitLab From d6bcc2153ba7649a8c742889489dbd5b4f3208cc Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 3 Apr 2018 16:02:15 +0200 Subject: [PATCH 1383/1834] s390/ipl: ensure loadparm valid flag is set commit 15deb080a6087b73089139569558965750e69d67 upstream. When loadparm is set in reipl parm block, the kernel should also set DIAG308_FLAGS_LP_VALID flag. This fixes loadparm ignoring during z/VM fcp -> ccw reipl and kvm direct boot -> ccw reipl. Cc: Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik Signed-off-by: Martin Schwidefsky Signed-off-by: Greg Kroah-Hartman --- arch/s390/kernel/ipl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 295bfb7124bc..39127b691b78 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -798,6 +798,7 @@ static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, /* copy and convert to ebcdic */ memcpy(ipb->hdr.loadparm, buf, lp_len); ASCEBC(ipb->hdr.loadparm, LOADPARM_LEN); + ipb->hdr.flags |= DIAG308_FLAGS_LP_VALID; return len; } -- GitLab From 960534a57db826558ba5eece275c81d8122eb6db Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 8 Apr 2018 11:57:10 -0400 Subject: [PATCH 1384/1834] getname_kernel() needs to make sure that ->name != ->iname in long case commit 30ce4d1903e1d8a7ccd110860a5eef3c638ed8be upstream. missed it in "kill struct filename.separate" several years ago. Cc: stable@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namei.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index 891670e0956b..85ac38b99065 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -221,9 +221,10 @@ getname_kernel(const char * filename) if (len <= EMBEDDED_NAME_MAX) { result->name = (char *)result->iname; } else if (len <= PATH_MAX) { + const size_t size = offsetof(struct filename, iname[1]); struct filename *tmp; - tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + tmp = kmalloc(size, GFP_KERNEL); if (unlikely(!tmp)) { __putname(result); return ERR_PTR(-ENOMEM); -- GitLab From b0a2a2b20b38fb0de45aa8c84b7e9109269a1176 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 3 Apr 2018 13:40:06 +0200 Subject: [PATCH 1385/1834] Bluetooth: Fix connection if directed advertising and privacy is used commit 082f2300cfa1a3d9d5221c38c5eba85d4ab98bd8 upstream. Local random address needs to be updated before creating connection if RPA from LE Direct Advertising Report was resolved in host. Otherwise remote device might ignore connection request due to address mismatch. This was affecting following qualification test cases: GAP/CONN/SCEP/BV-03-C, GAP/CONN/GCEP/BV-05-C, GAP/CONN/DCEP/BV-05-C Before patch: < HCI Command: LE Set Random Address (0x08|0x0005) plen 6 #11350 [hci0] 84680.231216 Address: 56:BC:E8:24:11:68 (Resolvable) Identity type: Random (0x01) Identity: F2:F1:06:3D:9C:42 (Static) > HCI Event: Command Complete (0x0e) plen 4 #11351 [hci0] 84680.246022 LE Set Random Address (0x08|0x0005) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 #11352 [hci0] 84680.246417 Type: Passive (0x00) Interval: 60.000 msec (0x0060) Window: 30.000 msec (0x0030) Own address type: Random (0x01) Filter policy: Accept all advertisement, inc. directed unresolved RPA (0x02) > HCI Event: Command Complete (0x0e) plen 4 #11353 [hci0] 84680.248854 LE Set Scan Parameters (0x08|0x000b) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #11354 [hci0] 84680.249466 Scanning: Enabled (0x01) Filter duplicates: Enabled (0x01) > HCI Event: Command Complete (0x0e) plen 4 #11355 [hci0] 84680.253222 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 18 #11356 [hci0] 84680.458387 LE Direct Advertising Report (0x0b) Num reports: 1 Event type: Connectable directed - ADV_DIRECT_IND (0x01) Address type: Random (0x01) Address: 53:38:DA:46:8C:45 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Direct address type: Random (0x01) Direct address: 7C:D6:76:8C:DF:82 (Resolvable) Identity type: Random (0x01) Identity: F2:F1:06:3D:9C:42 (Static) RSSI: -74 dBm (0xb6) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #11357 [hci0] 84680.458737 Scanning: Disabled (0x00) Filter duplicates: Disabled (0x00) > HCI Event: Command Complete (0x0e) plen 4 #11358 [hci0] 84680.469982 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) < HCI Command: LE Create Connection (0x08|0x000d) plen 25 #11359 [hci0] 84680.470444 Scan interval: 60.000 msec (0x0060) Scan window: 60.000 msec (0x0060) Filter policy: White list is not used (0x00) Peer address type: Random (0x01) Peer address: 53:38:DA:46:8C:45 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Own address type: Random (0x01) Min connection interval: 30.00 msec (0x0018) Max connection interval: 50.00 msec (0x0028) Connection latency: 0 (0x0000) Supervision timeout: 420 msec (0x002a) Min connection length: 0.000 msec (0x0000) Max connection length: 0.000 msec (0x0000) > HCI Event: Command Status (0x0f) plen 4 #11360 [hci0] 84680.474971 LE Create Connection (0x08|0x000d) ncmd 1 Status: Success (0x00) < HCI Command: LE Create Connection Cancel (0x08|0x000e) plen 0 #11361 [hci0] 84682.545385 > HCI Event: Command Complete (0x0e) plen 4 #11362 [hci0] 84682.551014 LE Create Connection Cancel (0x08|0x000e) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 19 #11363 [hci0] 84682.551074 LE Connection Complete (0x01) Status: Unknown Connection Identifier (0x02) Handle: 0 Role: Master (0x00) Peer address type: Public (0x00) Peer address: 00:00:00:00:00:00 (OUI 00-00-00) Connection interval: 0.00 msec (0x0000) Connection latency: 0 (0x0000) Supervision timeout: 0 msec (0x0000) Master clock accuracy: 0x00 After patch: < HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 #210 [hci0] 667.152459 Type: Passive (0x00) Interval: 60.000 msec (0x0060) Window: 30.000 msec (0x0030) Own address type: Random (0x01) Filter policy: Accept all advertisement, inc. directed unresolved RPA (0x02) > HCI Event: Command Complete (0x0e) plen 4 #211 [hci0] 667.153613 LE Set Scan Parameters (0x08|0x000b) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #212 [hci0] 667.153704 Scanning: Enabled (0x01) Filter duplicates: Enabled (0x01) > HCI Event: Command Complete (0x0e) plen 4 #213 [hci0] 667.154584 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 18 #214 [hci0] 667.182619 LE Direct Advertising Report (0x0b) Num reports: 1 Event type: Connectable directed - ADV_DIRECT_IND (0x01) Address type: Random (0x01) Address: 50:52:D9:A6:48:A0 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Direct address type: Random (0x01) Direct address: 7C:C1:57:A5:B7:A8 (Resolvable) Identity type: Random (0x01) Identity: F4:28:73:5D:38:B0 (Static) RSSI: -70 dBm (0xba) < HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 #215 [hci0] 667.182704 Scanning: Disabled (0x00) Filter duplicates: Disabled (0x00) > HCI Event: Command Complete (0x0e) plen 4 #216 [hci0] 667.183599 LE Set Scan Enable (0x08|0x000c) ncmd 1 Status: Success (0x00) < HCI Command: LE Set Random Address (0x08|0x0005) plen 6 #217 [hci0] 667.183645 Address: 7C:C1:57:A5:B7:A8 (Resolvable) Identity type: Random (0x01) Identity: F4:28:73:5D:38:B0 (Static) > HCI Event: Command Complete (0x0e) plen 4 #218 [hci0] 667.184590 LE Set Random Address (0x08|0x0005) ncmd 1 Status: Success (0x00) < HCI Command: LE Create Connection (0x08|0x000d) plen 25 #219 [hci0] 667.184613 Scan interval: 60.000 msec (0x0060) Scan window: 60.000 msec (0x0060) Filter policy: White list is not used (0x00) Peer address type: Random (0x01) Peer address: 50:52:D9:A6:48:A0 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Own address type: Random (0x01) Min connection interval: 30.00 msec (0x0018) Max connection interval: 50.00 msec (0x0028) Connection latency: 0 (0x0000) Supervision timeout: 420 msec (0x002a) Min connection length: 0.000 msec (0x0000) Max connection length: 0.000 msec (0x0000) > HCI Event: Command Status (0x0f) plen 4 #220 [hci0] 667.186558 LE Create Connection (0x08|0x000d) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 19 #221 [hci0] 667.485824 LE Connection Complete (0x01) Status: Success (0x00) Handle: 0 Role: Master (0x00) Peer address type: Random (0x01) Peer address: 50:52:D9:A6:48:A0 (Resolvable) Identity type: Public (0x00) Identity: 11:22:33:44:55:66 (OUI 11-22-33) Connection interval: 50.00 msec (0x0028) Connection latency: 0 (0x0000) Supervision timeout: 420 msec (0x002a) Master clock accuracy: 0x07 @ MGMT Event: Device Connected (0x000b) plen 13 {0x0002} [hci0] 667.485996 LE Address: 11:22:33:44:55:66 (OUI 11-22-33) Flags: 0x00000000 Data length: 0 Signed-off-by: Szymon Janc Signed-off-by: Marcel Holtmann Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_conn.c | 29 +++++++++++++++++++++-------- net/bluetooth/hci_event.c | 15 +++++++++++---- net/bluetooth/l2cap_core.c | 2 +- 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 554671c81f4a..4931787193c3 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -893,7 +893,7 @@ struct hci_conn *hci_connect_le_scan(struct hci_dev *hdev, bdaddr_t *dst, u16 conn_timeout); struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - u8 role); + u8 role, bdaddr_t *direct_rpa); struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, u8 sec_level, u8 auth_type); struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index dc59eae54717..cc061495f653 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -749,18 +749,31 @@ static bool conn_use_rpa(struct hci_conn *conn) } static void hci_req_add_le_create_conn(struct hci_request *req, - struct hci_conn *conn) + struct hci_conn *conn, + bdaddr_t *direct_rpa) { struct hci_cp_le_create_conn cp; struct hci_dev *hdev = conn->hdev; u8 own_addr_type; - /* Update random address, but set require_privacy to false so - * that we never connect with an non-resolvable address. + /* If direct address was provided we use it instead of current + * address. */ - if (hci_update_random_address(req, false, conn_use_rpa(conn), - &own_addr_type)) - return; + if (direct_rpa) { + if (bacmp(&req->hdev->random_addr, direct_rpa)) + hci_req_add(req, HCI_OP_LE_SET_RANDOM_ADDR, 6, + direct_rpa); + + /* direct address is always RPA */ + own_addr_type = ADDR_LE_DEV_RANDOM; + } else { + /* Update random address, but set require_privacy to false so + * that we never connect with an non-resolvable address. + */ + if (hci_update_random_address(req, false, conn_use_rpa(conn), + &own_addr_type)) + return; + } memset(&cp, 0, sizeof(cp)); @@ -825,7 +838,7 @@ static void hci_req_directed_advertising(struct hci_request *req, struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, u8 dst_type, u8 sec_level, u16 conn_timeout, - u8 role) + u8 role, bdaddr_t *direct_rpa) { struct hci_conn_params *params; struct hci_conn *conn; @@ -940,7 +953,7 @@ struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, hci_dev_set_flag(hdev, HCI_LE_SCAN_INTERRUPTED); } - hci_req_add_le_create_conn(&req, conn); + hci_req_add_le_create_conn(&req, conn, direct_rpa); create_conn: err = hci_req_run(&req, create_le_conn_complete); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e17aacbc5630..d2f9eb169ba8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -4646,7 +4646,8 @@ static void hci_le_conn_update_complete_evt(struct hci_dev *hdev, /* This function requires the caller holds hdev->lock */ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, bdaddr_t *addr, - u8 addr_type, u8 adv_type) + u8 addr_type, u8 adv_type, + bdaddr_t *direct_rpa) { struct hci_conn *conn; struct hci_conn_params *params; @@ -4697,7 +4698,8 @@ static struct hci_conn *check_pending_le_conn(struct hci_dev *hdev, } conn = hci_connect_le(hdev, addr, addr_type, BT_SECURITY_LOW, - HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER); + HCI_LE_AUTOCONN_TIMEOUT, HCI_ROLE_MASTER, + direct_rpa); if (!IS_ERR(conn)) { /* If HCI_AUTO_CONN_EXPLICIT is set, conn is already owned * by higher layer that tried to connect, if no then @@ -4807,8 +4809,13 @@ static void process_adv_report(struct hci_dev *hdev, u8 type, bdaddr_t *bdaddr, bdaddr_type = irk->addr_type; } - /* Check if we have been requested to connect to this device */ - conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type); + /* Check if we have been requested to connect to this device. + * + * direct_addr is set only for directed advertising reports (it is NULL + * for advertising reports) and is already verified to be RPA above. + */ + conn = check_pending_le_conn(hdev, bdaddr, bdaddr_type, type, + direct_addr); if (conn && type == LE_ADV_IND) { /* Store report for later inclusion by * mgmt_device_connected diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2bbca23a9d05..1fc23cb4a3e0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -7148,7 +7148,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, hcon = hci_connect_le(hdev, dst, dst_type, chan->sec_level, HCI_LE_CONN_TIMEOUT, - HCI_ROLE_SLAVE); + HCI_ROLE_SLAVE, NULL); else hcon = hci_connect_le_scan(hdev, dst, dst_type, chan->sec_level, -- GitLab From bcd7de03d68a6953d00453bc1380ee34d2f4e000 Mon Sep 17 00:00:00 2001 From: Sudhir Sreedharan Date: Thu, 15 Feb 2018 12:52:45 +0530 Subject: [PATCH 1386/1834] rtl8187: Fix NULL pointer dereference in priv->conf_mutex commit 7972326a26b5bf8dc2adac575c4e03ee7e9d193a upstream. This can be reproduced by bind/unbind the driver multiple times in AM3517 board. Analysis revealed that rtl8187_start() was invoked before probe finishes(ie. before the mutex is initialized). INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 0 PID: 821 Comm: wpa_supplicant Not tainted 4.9.80-dirty #250 Hardware name: Generic AM3517 (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (register_lock_class+0x4f4/0x55c) [] (register_lock_class) from [] (__lock_acquire+0x74/0x1938) [] (__lock_acquire) from [] (lock_acquire+0xfc/0x23c) [] (lock_acquire) from [] (mutex_lock_nested+0x50/0x3b0) [] (mutex_lock_nested) from [] (rtl8187_start+0x2c/0xd54) [] (rtl8187_start) from [] (drv_start+0xa8/0x320) [] (drv_start) from [] (ieee80211_do_open+0x2bc/0x8e4) [] (ieee80211_do_open) from [] (__dev_open+0xb8/0x120) [] (__dev_open) from [] (__dev_change_flags+0x88/0x14c) [] (__dev_change_flags) from [] (dev_change_flags+0x18/0x48) [] (dev_change_flags) from [] (devinet_ioctl+0x738/0x840) [] (devinet_ioctl) from [] (sock_ioctl+0x164/0x2f4) [] (sock_ioctl) from [] (do_vfs_ioctl+0x8c/0x9d0) [] (do_vfs_ioctl) from [] (SyS_ioctl+0x6c/0x7c) [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x1c) Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = cd1ec000 [00000000] *pgd=8d1de831, *pte=00000000, *ppte=00000000 Internal error: Oops: 817 [#1] PREEMPT ARM Modules linked in: CPU: 0 PID: 821 Comm: wpa_supplicant Not tainted 4.9.80-dirty #250 Hardware name: Generic AM3517 (Flattened Device Tree) task: ce73eec0 task.stack: cd1ea000 PC is at mutex_lock_nested+0xe8/0x3b0 LR is at mutex_lock_nested+0xd0/0x3b0 Cc: stable@vger.kernel.org Signed-off-by: Sudhir Sreedharan Signed-off-by: Kalle Valo Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 231f84db9ab0..6113624ccec3 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1454,6 +1454,7 @@ static int rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } mutex_init(&priv->io_mutex); + mutex_init(&priv->conf_mutex); SET_IEEE80211_DEV(dev, &intf->dev); usb_set_intfdata(intf, dev); @@ -1627,7 +1628,6 @@ static int rtl8187_probe(struct usb_interface *intf, printk(KERN_ERR "rtl8187: Cannot register device\n"); goto err_free_dmabuf; } - mutex_init(&priv->conf_mutex); skb_queue_head_init(&priv->b_tx_status.queue); wiphy_info(dev->wiphy, "hwaddr %pM, %s V%d + %s, rfkill mask %d\n", -- GitLab From ebdb0d5abc412a5461db8a1a562551d6b643d578 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 15 Jan 2018 14:58:21 +0100 Subject: [PATCH 1387/1834] hwmon: (ina2xx) Fix access to uninitialized mutex commit 0c4c5860e9983eb3da7a3d73ca987643c3ed034b upstream. Initialize data->config_lock mutex before it is used by the driver code. This fixes following warning on Odroid XU3 boards: INFO: trying to register non-static key. the code is fine but needs lockdep annotation. turning off the locking correctness validator. CPU: 5 PID: 1 Comm: swapper/0 Not tainted 4.15.0-rc7-next-20180115-00001-gb75575dee3f2 #107 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x90/0xc8) [] (dump_stack) from [] (register_lock_class+0x1c0/0x59c) [] (register_lock_class) from [] (__lock_acquire+0x78/0x1850) [] (__lock_acquire) from [] (lock_acquire+0xc8/0x2b8) [] (lock_acquire) from [] (__mutex_lock+0x60/0xa0c) [] (__mutex_lock) from [] (mutex_lock_nested+0x1c/0x24) [] (mutex_lock_nested) from [] (ina2xx_set_shunt+0x70/0xb0) [] (ina2xx_set_shunt) from [] (ina2xx_probe+0x88/0x1b0) [] (ina2xx_probe) from [] (i2c_device_probe+0x1e0/0x2d0) [] (i2c_device_probe) from [] (driver_probe_device+0x2b8/0x4a0) [] (driver_probe_device) from [] (__driver_attach+0xfc/0x120) [] (__driver_attach) from [] (bus_for_each_dev+0x58/0x7c) [] (bus_for_each_dev) from [] (bus_add_driver+0x174/0x250) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (i2c_register_driver+0x38/0xa8) [] (i2c_register_driver) from [] (do_one_initcall+0x48/0x18c) [] (do_one_initcall) from [] (kernel_init_freeable+0x110/0x1d4) [] (kernel_init_freeable) from [] (kernel_init+0x8/0x114) [] (kernel_init) from [] (ret_from_fork+0x14/0x20) Fixes: 5d389b125186 ("hwmon: (ina2xx) Make calibration register value fixed") Signed-off-by: Marek Szyprowski Signed-off-by: Guenter Roeck [backport to v4.4.y/v4.9.y: context changes] Signed-off-by: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- drivers/hwmon/ina2xx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index a629f7c130f0..ac63e562071f 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -447,6 +447,7 @@ static int ina2xx_probe(struct i2c_client *client, /* set the device type */ data->config = &ina2xx_config[id->driver_data]; + mutex_init(&data->config_lock); if (of_property_read_u32(dev->of_node, "shunt-resistor", &val) < 0) { struct ina2xx_platform_data *pdata = dev_get_platdata(dev); @@ -473,8 +474,6 @@ static int ina2xx_probe(struct i2c_client *client, return -ENODEV; } - mutex_init(&data->config_lock); - data->groups[group++] = &ina2xx_group; if (id->driver_data == ina226) data->groups[group++] = &ina226_group; -- GitLab From 6b61154b0680ebd3d82fd9415e9cd2c977bebcf2 Mon Sep 17 00:00:00 2001 From: Bassem Boubaker Date: Wed, 11 Apr 2018 13:15:53 +0200 Subject: [PATCH 1388/1834] cdc_ether: flag the Cinterion AHS8 modem by gemalto as WWAN [ Upstream commit 53765341ee821c0a0f1dec41adc89c9096ad694c ] The Cinterion AHS8 is a 3G device with one embedded WWAN interface using cdc_ether as a driver. The modem is controlled via AT commands through the exposed TTYs. AT+CGDCONT write command can be used to activate or deactivate a WWAN connection for a PDP context defined with the same command. UE supports one WWAN adapter. Signed-off-by: Bassem Boubaker Acked-by: Oliver Neukum Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/cdc_ether.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 1fca0024f294..4fb468666b19 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -773,6 +773,12 @@ static const struct usb_device_id products[] = { USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&wwan_info, +}, { + /* Cinterion AHS3 modem by GEMALTO */ + USB_DEVICE_AND_INTERFACE_INFO(0x1e2d, 0x0055, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&wwan_info, }, { /* Telit modules */ USB_VENDOR_AND_INTERFACE_INFO(0x1bc7, USB_CLASS_COMM, -- GitLab From fc89a75c246bbf7fc26b25ae29ee488abb6400c4 Mon Sep 17 00:00:00 2001 From: Ka-Cheong Poon Date: Wed, 11 Apr 2018 00:57:25 -0700 Subject: [PATCH 1389/1834] rds: MP-RDS may use an invalid c_path [ Upstream commit a43cced9a348901f9015f4730b70b69e7c41a9c9 ] rds_sendmsg() calls rds_send_mprds_hash() to find a c_path to use to send a message. Suppose the RDS connection is not yet up. In rds_send_mprds_hash(), it does if (conn->c_npaths == 0) wait_event_interruptible(conn->c_hs_waitq, (conn->c_npaths != 0)); If it is interrupted before the connection is set up, rds_send_mprds_hash() will return a non-zero hash value. Hence rds_sendmsg() will use a non-zero c_path to send the message. But if the RDS connection ends up to be non-MP capable, the message will be lost as only the zero c_path can be used. Signed-off-by: Ka-Cheong Poon Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- net/rds/send.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/net/rds/send.c b/net/rds/send.c index ef53d164e146..50241d30e16d 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Oracle. All rights reserved. + * Copyright (c) 2006, 2018 Oracle and/or its affiliates. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU @@ -983,10 +983,15 @@ static int rds_send_mprds_hash(struct rds_sock *rs, struct rds_connection *conn) if (conn->c_npaths == 0 && hash != 0) { rds_send_ping(conn); - if (conn->c_npaths == 0) { - wait_event_interruptible(conn->c_hs_waitq, - (conn->c_npaths != 0)); - } + /* The underlying connection is not up yet. Need to wait + * until it is up to be sure that the non-zero c_path can be + * used. But if we are interrupted, we have to use the zero + * c_path in case the connection ends up being non-MP capable. + */ + if (conn->c_npaths == 0) + if (wait_event_interruptible(conn->c_hs_waitq, + conn->c_npaths != 0)) + hash = 0; if (conn->c_npaths == 1) hash = 0; } -- GitLab From 0eecffb5e95390e72c5ac0c6d184881c14ad1b3a Mon Sep 17 00:00:00 2001 From: Tejaswi Tanikella Date: Wed, 11 Apr 2018 16:34:47 +0530 Subject: [PATCH 1390/1834] slip: Check if rstate is initialized before uncompressing [ Upstream commit 3f01ddb962dc506916c243f9524e8bef97119b77 ] On receiving a packet the state index points to the rstate which must be used to fill up IP and TCP headers. But if the state index points to a rstate which is unitialized, i.e. filled with zeros, it gets stuck in an infinite loop inside ip_fast_csum trying to compute the ip checsum of a header with zero length. 89.666953: <2> [] slhc_uncompress+0x464/0x468 89.666965: <2> [] ppp_receive_nonmp_frame+0x3b4/0x65c 89.666978: <2> [] ppp_receive_frame+0x64/0x7e0 89.666991: <2> [] ppp_input+0x104/0x198 89.667005: <2> [] pppopns_recv_core+0x238/0x370 89.667027: <2> [] __sk_receive_skb+0xdc/0x250 89.667040: <2> [] pppopns_recv+0x44/0x60 89.667053: <2> [] __sock_queue_rcv_skb+0x16c/0x24c 89.667065: <2> [] sock_queue_rcv_skb+0x2c/0x38 89.667085: <2> [] raw_rcv+0x124/0x154 89.667098: <2> [] raw_local_deliver+0x1e0/0x22c 89.667117: <2> [] ip_local_deliver_finish+0x70/0x24c 89.667131: <2> [] ip_local_deliver+0x100/0x10c ./scripts/faddr2line vmlinux slhc_uncompress+0x464/0x468 output: ip_fast_csum at arch/arm64/include/asm/checksum.h:40 (inlined by) slhc_uncompress at drivers/net/slip/slhc.c:615 Adding a variable to indicate if the current rstate is initialized. If such a packet arrives, move to toss state. Signed-off-by: Tejaswi Tanikella Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/slip/slhc.c | 5 +++++ include/net/slhc_vj.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 27ed25252aac..cfd81eb1b532 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -509,6 +509,10 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) if(x < 0 || x > comp->rslot_limit) goto bad; + /* Check if the cstate is initialized */ + if (!comp->rstate[x].initialized) + goto bad; + comp->flags &=~ SLF_TOSS; comp->recv_current = x; } else { @@ -673,6 +677,7 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) if (cs->cs_tcp.doff > 5) memcpy(cs->cs_tcpopt, icp + ihl*4 + sizeof(struct tcphdr), (cs->cs_tcp.doff - 5) * 4); cs->cs_hsize = ihl*2 + cs->cs_tcp.doff*2; + cs->initialized = true; /* Put headers back on packet * Neither header checksum is recalculated */ diff --git a/include/net/slhc_vj.h b/include/net/slhc_vj.h index 8716d5942b65..8fcf8908a694 100644 --- a/include/net/slhc_vj.h +++ b/include/net/slhc_vj.h @@ -127,6 +127,7 @@ typedef __u32 int32; */ struct cstate { byte_t cs_this; /* connection id number (xmit) */ + bool initialized; /* true if initialized */ struct cstate *next; /* next in ring (xmit) */ struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ struct tcphdr cs_tcp; -- GitLab From 72de9891b5f46f1f98e7e6243c47076a4b4daa3c Mon Sep 17 00:00:00 2001 From: Stefan Hajnoczi Date: Wed, 11 Apr 2018 10:35:40 +0800 Subject: [PATCH 1391/1834] vhost: fix vhost_vq_access_ok() log check [ Upstream commit d14d2b78090c7de0557362b26a4ca591aa6a9faa ] Commit d65026c6c62e7d9616c8ceb5a53b68bcdc050525 ("vhost: validate log when IOTLB is enabled") introduced a regression. The logic was originally: if (vq->iotlb) return 1; return A && B; After the patch the short-circuit logic for A was inverted: if (A || vq->iotlb) return A; return B; This patch fixes the regression by rewriting the checks in the obvious way, no longer returning A when vq->iotlb is non-NULL (which is hard to understand). Reported-by: syzbot+65a84dde0214b0387ccd@syzkaller.appspotmail.com Cc: Jason Wang Signed-off-by: Stefan Hajnoczi Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/vhost/vhost.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index e2c37aeed45a..fce49ebc575d 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1175,10 +1175,12 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, /* Caller should have vq mutex and device mutex */ int vhost_vq_access_ok(struct vhost_virtqueue *vq) { - int ret = vq_log_access_ok(vq, vq->log_base); + if (!vq_log_access_ok(vq, vq->log_base)) + return 0; - if (ret || vq->iotlb) - return ret; + /* Access validation occurs at prefetch time with IOTLB */ + if (vq->iotlb) + return 1; return vq_access_ok(vq, vq->num, vq->desc, vq->avail, vq->used); } -- GitLab From 82236561095d64471a3a38d3a8f1fd7d815df3dd Mon Sep 17 00:00:00 2001 From: Phil Elwell Date: Wed, 11 Apr 2018 10:59:17 +0100 Subject: [PATCH 1392/1834] lan78xx: Correctly indicate invalid OTP [ Upstream commit 4bfc33807a9a02764bdd1e42e794b3b401240f27 ] lan78xx_read_otp tries to return -EINVAL in the event of invalid OTP content, but the value gets overwritten before it is returned and the read goes ahead anyway. Make the read conditional as it should be and preserve the error code. Fixes: 55d7de9de6c3 ("Microchip's LAN7800 family USB 2/3 to 10/100/1000 Ethernet device driver") Signed-off-by: Phil Elwell Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/usb/lan78xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index c53385a0052f..f5a96678494b 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -873,7 +873,8 @@ static int lan78xx_read_otp(struct lan78xx_net *dev, u32 offset, offset += 0x100; else ret = -EINVAL; - ret = lan78xx_read_raw_otp(dev, offset, length, data); + if (!ret) + ret = lan78xx_read_raw_otp(dev, offset, length, data); } return ret; -- GitLab From 1cd969fdb447655e6f4b1e0a3213e27c7ad236c2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 5 Feb 2018 15:34:24 +0000 Subject: [PATCH 1393/1834] arm64: futex: Mask __user pointers prior to dereference commit 91b2d3442f6a44dce875670d702af22737ad5eff upstream. The arm64 futex code has some explicit dereferencing of user pointers where performing atomic operations in response to a futex command. This patch uses masking to limit any speculative futex operations to within the user address space. Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas Signed-off-by: Mark Rutland [v4.9 backport] Signed-off-by: Greg Kroah-Hartman --- arch/arm64/include/asm/futex.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 20dcb196b240..4e5f36a804b4 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -51,13 +51,14 @@ : "memory") static inline int -futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) +futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *_uaddr) { int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; int oparg = (int)(encoded_op << 8) >> 20; int cmparg = (int)(encoded_op << 20) >> 20; int oldval = 0, ret, tmp; + u32 __user *uaddr = __uaccess_mask_ptr(_uaddr); if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1U << (oparg & 0x1f); @@ -109,15 +110,17 @@ futex_atomic_op_inuser(unsigned int encoded_op, u32 __user *uaddr) } static inline int -futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *_uaddr, u32 oldval, u32 newval) { int ret = 0; u32 val, tmp; + u32 __user *uaddr; - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) + if (!access_ok(VERIFY_WRITE, _uaddr, sizeof(u32))) return -EFAULT; + uaddr = __uaccess_mask_ptr(_uaddr); asm volatile("// futex_atomic_cmpxchg_inatomic\n" ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, CONFIG_ARM64_PAN) " prfm pstl1strm, %2\n" -- GitLab From c3ba64bb3a6c8a4bc9fd3fd4e3a882e66f1942fa Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Apr 2018 16:00:32 +0200 Subject: [PATCH 1394/1834] Revert "net: phy: micrel: Restore led_mode and clk_sel on resume" This reverts commit d7ba3c00047dfd88fe0360a2d27169b54c88c4f1 which was commit 79e498a9c7da0737829ff864aae44df434105676 upstream. Turns out it breaks things, so drop it. Reported-by: Naresh Kamboju Cc: Leonard Crestez Cc: Florian Fainelli Cc: David S. Miller Cc: Sasha Levin Cc: Dan Rue Signed-off-by: Greg Kroah-Hartman --- drivers/net/phy/micrel.c | 42 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 4da73e2c37cf..2032a6de026b 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -268,12 +268,23 @@ static int kszphy_nand_tree_disable(struct phy_device *phydev) return ret; } -/* Some config bits need to be set again on resume, handle them here. */ -static int kszphy_config_reset(struct phy_device *phydev) +static int kszphy_config_init(struct phy_device *phydev) { struct kszphy_priv *priv = phydev->priv; + const struct kszphy_type *type; int ret; + if (!priv) + return 0; + + type = priv->type; + + if (type->has_broadcast_disable) + kszphy_broadcast_disable(phydev); + + if (type->has_nand_tree_disable) + kszphy_nand_tree_disable(phydev); + if (priv->rmii_ref_clk_sel) { ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val); if (ret) { @@ -284,7 +295,7 @@ static int kszphy_config_reset(struct phy_device *phydev) } if (priv->led_mode >= 0) - kszphy_setup_led(phydev, priv->type->led_mode_reg, priv->led_mode); + kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode); if (phy_interrupt_is_valid(phydev)) { int ctl = phy_read(phydev, MII_BMCR); @@ -300,25 +311,6 @@ static int kszphy_config_reset(struct phy_device *phydev) return 0; } -static int kszphy_config_init(struct phy_device *phydev) -{ - struct kszphy_priv *priv = phydev->priv; - const struct kszphy_type *type; - - if (!priv) - return 0; - - type = priv->type; - - if (type->has_broadcast_disable) - kszphy_broadcast_disable(phydev); - - if (type->has_nand_tree_disable) - kszphy_nand_tree_disable(phydev); - - return kszphy_config_reset(phydev); -} - static int ksz8041_config_init(struct phy_device *phydev) { struct device_node *of_node = phydev->mdio.dev.of_node; @@ -723,14 +715,8 @@ static int kszphy_suspend(struct phy_device *phydev) static int kszphy_resume(struct phy_device *phydev) { - int ret; - genphy_resume(phydev); - ret = kszphy_config_reset(phydev); - if (ret) - return ret; - /* Enable PHY Interrupts */ if (phy_interrupt_is_valid(phydev)) { phydev->interrupts = PHY_INTERRUPT_ENABLED; -- GitLab From eedaf21fb32353c81ea5eb7c910a1acd958523d1 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 20 Apr 2018 08:21:08 +0200 Subject: [PATCH 1395/1834] Linux 4.9.95 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 02188cf8e9af..1aeec9df709d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 94 +SUBLEVEL = 95 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 0c1acb02b0112fc6a5fd0a063df512f99bad811e Mon Sep 17 00:00:00 2001 From: Yahui Wang Date: Wed, 7 Jun 2017 09:40:03 +0800 Subject: [PATCH 1396/1834] msm: mdss: add support to control dcs brightness with HS state Some special panels may need high speed mode to send brightness to avoid panel issues, adding this change can make a better user experience using these panels. Change-Id: Id2cd4b3652892cc7677d7c6863a67d93e24d980f Signed-off-by: Yahui Wang --- .../devicetree/bindings/fb/mdss-dsi-panel.txt | 4 ++++ drivers/video/fbdev/msm/mdss_dsi.h | 1 + drivers/video/fbdev/msm/mdss_dsi_panel.c | 12 ++++++++++++ 3 files changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index b8cb9036262f..2b144dcee10c 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -195,6 +195,10 @@ Optional properties: "bl_ctrl_wled" = Backlight controlled by WLED. "bl_ctrl_dcs" = Backlight controlled by DCS commands. other: Unknown backlight control. (default) +- qcom,mdss-dsi-bl-dcs-command-state: A string that specifies the ctrl state for sending brightness + controlling commands, this is only available when backlight is controlled by DCS commands. + "dsi_lp_mode" = DSI low power mode (default). + "dsi_hs_mode" = DSI high speed mode. - qcom,mdss-dsi-bl-pwm-pmi: Boolean to indicate that PWM control is through second pmic chip. - qcom,mdss-dsi-bl-pmic-bank-select: LPG channel for backlight. Required if blpmiccontroltype is PWM diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 058c27a61130..5c130e0bbe04 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -436,6 +436,7 @@ struct mdss_dsi_ctrl_pdata { int mode_gpio; int intf_mux_gpio; int bklt_ctrl; /* backlight ctrl */ + enum dsi_ctrl_op_mode bklt_dcs_op_mode; /* backlight dcs ctrl mode */ bool pwm_pmi; int pwm_period; int pwm_pmic_gpio; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 2ef1695b15f1..dd03ca4d5e21 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -238,6 +238,11 @@ static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, int level) cmdreq.rlen = 0; cmdreq.cb = NULL; + if (ctrl->bklt_dcs_op_mode == DSI_HS_MODE) + cmdreq.flags |= CMD_REQ_HS_MODE; + else + cmdreq.flags |= CMD_REQ_LP_MODE; + mdss_dsi_cmdlist_put(ctrl, &cmdreq); } @@ -2271,6 +2276,13 @@ int mdss_panel_parse_bl_settings(struct device_node *np, } } else if (!strcmp(data, "bl_ctrl_dcs")) { ctrl_pdata->bklt_ctrl = BL_DCS_CMD; + data = of_get_property(np, + "qcom,mdss-dsi-bl-dcs-command-state", NULL); + if (data && !strcmp(data, "dsi_hs_mode")) + ctrl_pdata->bklt_dcs_op_mode = DSI_HS_MODE; + else + ctrl_pdata->bklt_dcs_op_mode = DSI_LP_MODE; + pr_debug("%s: Configured DCS_CMD bklt ctrl\n", __func__); } -- GitLab From 2f0444a0c1ac2f73b411123f6140253533157316 Mon Sep 17 00:00:00 2001 From: Kalyan Thota Date: Fri, 20 Apr 2018 17:50:33 +0530 Subject: [PATCH 1397/1834] drm/msm/sde: ignore last close during cont splash Ignore last close call to msm when continuous splash is still ON. This is to avoid cleaning up the states when we did not receive first commit. Change-Id: Ide8df725415d0ff15159be01790535b8a8ab0dfc Signed-off-by: Kalyan Thota --- drivers/gpu/drm/msm/msm_drv.c | 8 ++++++++ drivers/gpu/drm/msm/msm_kms.h | 4 +++- drivers/gpu/drm/msm/sde/sde_kms.c | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 19df8be48760..0697db831867 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -947,6 +947,14 @@ static void msm_lastclose(struct drm_device *dev) struct msm_kms *kms = priv->kms; int i; + /* check for splash status before triggering cleanup + * if we end up here with splash status ON i.e before first + * commit then ignore the last close call + */ + if (kms && kms->funcs && kms->funcs->check_for_splash + && kms->funcs->check_for_splash(kms)) + return; + /* * clean up vblank disable immediately as this is the last close. */ diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h index db9e7ee45f1a..e99ff9c53f6f 100644 --- a/drivers/gpu/drm/msm/msm_kms.h +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (C) 2013 Red Hat * Author: Rob Clark * @@ -106,6 +106,8 @@ struct msm_kms_funcs { unsigned int domain); /* handle continuous splash */ int (*cont_splash_config)(struct msm_kms *kms); + /* check for continuous splash status */ + bool (*check_for_splash)(struct msm_kms *kms); }; struct msm_kms { diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 33bdec9fa86f..71e29600d1e7 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -2704,6 +2704,19 @@ static int sde_kms_cont_splash_config(struct msm_kms *kms) return rc; } +static bool sde_kms_check_for_splash(struct msm_kms *kms) +{ + struct sde_kms *sde_kms; + + if (!kms) { + SDE_ERROR("invalid kms\n"); + return false; + } + + sde_kms = to_sde_kms(kms); + return sde_kms->splash_data.cont_splash_en; +} + static int sde_kms_pm_suspend(struct device *dev) { struct drm_device *ddev; @@ -2904,6 +2917,7 @@ static const struct msm_kms_funcs kms_funcs = { .register_events = _sde_kms_register_events, .get_address_space = _sde_kms_get_address_space, .postopen = _sde_kms_post_open, + .check_for_splash = sde_kms_check_for_splash, }; /* the caller api needs to turn on clock before calling it */ -- GitLab From 13cc54013b24007b8bbcb370d854ccaf3d66e546 Mon Sep 17 00:00:00 2001 From: Greg Hackmann Date: Fri, 2 Mar 2018 13:22:46 -0800 Subject: [PATCH 1398/1834] ANDROID: arm-smccc: fix clang build The SMCCC 1.1 helpers rely on a gcc extension to accept obsolete AArch32 register names in AArch64 mode, changing rN to xN or wN based on context. Unfortunately, as of April 2018, current clang releases don't support this extension. Support for this syntax has landed in LLVM SVN (https://reviews.llvm.org/rL328829) and is queued up for LLVM 6.0.1. In the meantime, to keep from breaking clang kernel builds, we'll temporarily switch to using xN instead of rN on ARM64. These helpers were backported to linux-stable for two specific callers, and both cases should use the full 64-bit register width. Fixes: ac63fdb4a2b2 ("arm/arm64: smccc: Implement SMCCC v1.1 inline primitive") Change-Id: I1eb14f7b6674f7dffcad9572e409f6bcdba69610 Signed-off-by: Greg Hackmann --- include/linux/arm-smccc.h | 42 ++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h index a031897fca76..43690f501712 100644 --- a/include/linux/arm-smccc.h +++ b/include/linux/arm-smccc.h @@ -155,6 +155,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, #define SMCCC_SMC_INST "smc #0" #define SMCCC_HVC_INST "hvc #0" +#define SMCCC_REG(n) asm("x" # n) #elif defined(CONFIG_ARM) #include @@ -162,6 +163,7 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, #define SMCCC_SMC_INST __SMC(0) #define SMCCC_HVC_INST __HVC(0) +#define SMCCC_REG(n) asm("r" # n) #endif @@ -194,47 +196,47 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1, #define __declare_arg_0(a0, res) \ struct arm_smccc_res *___res = res; \ - register u32 r0 asm("r0") = a0; \ - register unsigned long r1 asm("r1"); \ - register unsigned long r2 asm("r2"); \ - register unsigned long r3 asm("r3") + register u32 r0 SMCCC_REG(0) = a0; \ + register unsigned long r1 SMCCC_REG(1); \ + register unsigned long r2 SMCCC_REG(2); \ + register unsigned long r3 SMCCC_REG(3) #define __declare_arg_1(a0, a1, res) \ struct arm_smccc_res *___res = res; \ - register u32 r0 asm("r0") = a0; \ - register typeof(a1) r1 asm("r1") = a1; \ - register unsigned long r2 asm("r2"); \ - register unsigned long r3 asm("r3") + register u32 r0 SMCCC_REG(0) = a0; \ + register typeof(a1) r1 SMCCC_REG(1) = a1; \ + register unsigned long r2 SMCCC_REG(2); \ + register unsigned long r3 SMCCC_REG(3) #define __declare_arg_2(a0, a1, a2, res) \ struct arm_smccc_res *___res = res; \ - register u32 r0 asm("r0") = a0; \ - register typeof(a1) r1 asm("r1") = a1; \ - register typeof(a2) r2 asm("r2") = a2; \ - register unsigned long r3 asm("r3") + register u32 r0 SMCCC_REG(0) = a0; \ + register typeof(a1) r1 SMCCC_REG(1) = a1; \ + register typeof(a2) r2 SMCCC_REG(2) = a2; \ + register unsigned long r3 SMCCC_REG(3) #define __declare_arg_3(a0, a1, a2, a3, res) \ struct arm_smccc_res *___res = res; \ - register u32 r0 asm("r0") = a0; \ - register typeof(a1) r1 asm("r1") = a1; \ - register typeof(a2) r2 asm("r2") = a2; \ - register typeof(a3) r3 asm("r3") = a3 + register u32 r0 SMCCC_REG(0) = a0; \ + register typeof(a1) r1 SMCCC_REG(1) = a1; \ + register typeof(a2) r2 SMCCC_REG(2) = a2; \ + register typeof(a3) r3 SMCCC_REG(3) = a3 #define __declare_arg_4(a0, a1, a2, a3, a4, res) \ __declare_arg_3(a0, a1, a2, a3, res); \ - register typeof(a4) r4 asm("r4") = a4 + register typeof(a4) r4 SMCCC_REG(4) = a4 #define __declare_arg_5(a0, a1, a2, a3, a4, a5, res) \ __declare_arg_4(a0, a1, a2, a3, a4, res); \ - register typeof(a5) r5 asm("r5") = a5 + register typeof(a5) r5 SMCCC_REG(5) = a5 #define __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res) \ __declare_arg_5(a0, a1, a2, a3, a4, a5, res); \ - register typeof(a6) r6 asm("r6") = a6 + register typeof(a6) r6 SMCCC_REG(6) = a6 #define __declare_arg_7(a0, a1, a2, a3, a4, a5, a6, a7, res) \ __declare_arg_6(a0, a1, a2, a3, a4, a5, a6, res); \ - register typeof(a7) r7 asm("r7") = a7 + register typeof(a7) r7 SMCCC_REG(7) = a7 #define ___declare_args(count, ...) __declare_arg_ ## count(__VA_ARGS__) #define __declare_args(count, ...) ___declare_args(count, __VA_ARGS__) -- GitLab From 823fd560a2e622823489b160db497a2d957eb95a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 18 Apr 2018 11:09:47 -0700 Subject: [PATCH 1399/1834] fscrypt: allow synchronous bio decryption Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: 0509923bec1d ("fscrypt: allow synchronous bio decryption") Currently, fscrypt provides fscrypt_decrypt_bio_pages() which decrypts a bio's pages asynchronously, then unlocks them afterwards. But, this assumes that decryption is the last "postprocessing step" for the bio, so it's incompatible with additional postprocessing steps such as authenticity verification after decryption. Therefore, rename the existing fscrypt_decrypt_bio_pages() to fscrypt_enqueue_decrypt_bio(). Then, add fscrypt_decrypt_bio() which decrypts the pages in the bio synchronously without unlocking the pages, nor setting them Uptodate; and add fscrypt_enqueue_decrypt_work(), which enqueues work on the fscrypt_read_workqueue. The new functions will be used by filesystems that support both fscrypt and fs-verity. Change-Id: I3e39e4f2c38726664b01537b6c53fae674d7a3ee Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/crypto/bio.c | 35 +++++++++++++++++++++------------ fs/crypto/crypto.c | 8 +++++++- fs/crypto/fscrypt_private.h | 1 - fs/ext4/readpage.c | 2 +- fs/f2fs/data.c | 2 +- include/linux/fscrypt_notsupp.h | 13 +++++++++--- include/linux/fscrypt_supp.h | 5 ++++- 7 files changed, 45 insertions(+), 21 deletions(-) diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 2596c9ad6d77..d7b4c480e39e 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -25,15 +25,8 @@ #include #include "fscrypt_private.h" -/* - * Call fscrypt_decrypt_page on every single page, reusing the encryption - * context. - */ -static void completion_pages(struct work_struct *work) +static void __fscrypt_decrypt_bio(struct bio *bio, bool done) { - struct fscrypt_ctx *ctx = - container_of(work, struct fscrypt_ctx, r.work); - struct bio *bio = ctx->r.bio; struct bio_vec *bv; int i; @@ -45,22 +38,38 @@ static void completion_pages(struct work_struct *work) if (ret) { WARN_ON_ONCE(1); SetPageError(page); - } else { + } else if (done) { SetPageUptodate(page); } - unlock_page(page); + if (done) + unlock_page(page); } +} + +void fscrypt_decrypt_bio(struct bio *bio) +{ + __fscrypt_decrypt_bio(bio, false); +} +EXPORT_SYMBOL(fscrypt_decrypt_bio); + +static void completion_pages(struct work_struct *work) +{ + struct fscrypt_ctx *ctx = + container_of(work, struct fscrypt_ctx, r.work); + struct bio *bio = ctx->r.bio; + + __fscrypt_decrypt_bio(bio, true); fscrypt_release_ctx(ctx); bio_put(bio); } -void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, struct bio *bio) +void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio) { INIT_WORK(&ctx->r.work, completion_pages); ctx->r.bio = bio; - queue_work(fscrypt_read_workqueue, &ctx->r.work); + fscrypt_enqueue_decrypt_work(&ctx->r.work); } -EXPORT_SYMBOL(fscrypt_decrypt_bio_pages); +EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio); void fscrypt_pullback_bio_page(struct page **page, bool restore) { diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index ce654526c0fb..0758d32ad01b 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -45,12 +45,18 @@ static mempool_t *fscrypt_bounce_page_pool = NULL; static LIST_HEAD(fscrypt_free_ctxs); static DEFINE_SPINLOCK(fscrypt_ctx_lock); -struct workqueue_struct *fscrypt_read_workqueue; +static struct workqueue_struct *fscrypt_read_workqueue; static DEFINE_MUTEX(fscrypt_init_mutex); static struct kmem_cache *fscrypt_ctx_cachep; struct kmem_cache *fscrypt_info_cachep; +void fscrypt_enqueue_decrypt_work(struct work_struct *work) +{ + queue_work(fscrypt_read_workqueue, work); +} +EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work); + /** * fscrypt_release_ctx() - Releases an encryption context * @ctx: The encryption context to release. diff --git a/fs/crypto/fscrypt_private.h b/fs/crypto/fscrypt_private.h index 1fe00fd2f49e..d36a648cb2bb 100644 --- a/fs/crypto/fscrypt_private.h +++ b/fs/crypto/fscrypt_private.h @@ -96,7 +96,6 @@ static inline bool fscrypt_valid_enc_modes(u32 contents_mode, /* crypto.c */ extern struct kmem_cache *fscrypt_info_cachep; extern int fscrypt_initialize(unsigned int cop_flags); -extern struct workqueue_struct *fscrypt_read_workqueue; extern int fscrypt_do_page_crypto(const struct inode *inode, fscrypt_direction_t rw, u64 lblk_num, struct page *src_page, diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c index 2531cc1df4bd..c39a12d6d2d6 100644 --- a/fs/ext4/readpage.c +++ b/fs/ext4/readpage.c @@ -91,7 +91,7 @@ static void mpage_end_io(struct bio *bio) if (bio->bi_error) { fscrypt_release_ctx(bio->bi_private); } else { - fscrypt_decrypt_bio_pages(bio->bi_private, bio); + fscrypt_enqueue_decrypt_bio(bio->bi_private, bio); return; } } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c676c78919bc..b916613bfb3d 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -66,7 +66,7 @@ static void f2fs_read_end_io(struct bio *bio) if (bio->bi_error) { fscrypt_release_ctx(bio->bi_private); } else { - fscrypt_decrypt_bio_pages(bio->bi_private, bio); + fscrypt_enqueue_decrypt_bio(bio->bi_private, bio); return; } } diff --git a/include/linux/fscrypt_notsupp.h b/include/linux/fscrypt_notsupp.h index ecf2ac80128c..6f97714fbd88 100644 --- a/include/linux/fscrypt_notsupp.h +++ b/include/linux/fscrypt_notsupp.h @@ -24,6 +24,10 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode) } /* crypto.c */ +static inline void fscrypt_enqueue_decrypt_work(struct work_struct *work) +{ +} + static inline struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *inode, gfp_t gfp_flags) { @@ -159,10 +163,13 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, } /* bio.c */ -static inline void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *ctx, - struct bio *bio) +static inline void fscrypt_decrypt_bio(struct bio *bio) +{ +} + +static inline void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, + struct bio *bio) { - return; } static inline void fscrypt_pullback_bio_page(struct page **page, bool restore) diff --git a/include/linux/fscrypt_supp.h b/include/linux/fscrypt_supp.h index f382cf36cc2e..1ed79eeb2438 100644 --- a/include/linux/fscrypt_supp.h +++ b/include/linux/fscrypt_supp.h @@ -58,6 +58,7 @@ static inline bool fscrypt_dummy_context_enabled(struct inode *inode) } /* crypto.c */ +extern void fscrypt_enqueue_decrypt_work(struct work_struct *); extern struct fscrypt_ctx *fscrypt_get_ctx(const struct inode *, gfp_t); extern void fscrypt_release_ctx(struct fscrypt_ctx *); extern struct page *fscrypt_encrypt_page(const struct inode *, struct page *, @@ -187,7 +188,9 @@ static inline bool fscrypt_match_name(const struct fscrypt_name *fname, } /* bio.c */ -extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); +extern void fscrypt_decrypt_bio(struct bio *); +extern void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, + struct bio *bio); extern void fscrypt_pullback_bio_page(struct page **, bool); extern int fscrypt_zeroout_range(const struct inode *, pgoff_t, sector_t, unsigned int); -- GitLab From c6299745380d4a3645c7d0d18cecd7b28b07fcd0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 18 Apr 2018 11:09:48 -0700 Subject: [PATCH 1400/1834] f2fs: refactor read path to allow multiple postprocessing steps Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: f69e814ccf1e ("f2fs: refactor read path to allow multiple postprocessing steps") Currently f2fs's ->readpage() and ->readpages() assume that either the data undergoes no postprocessing, or decryption only. But with fs-verity, there will be an additional authenticity verification step, and it may be needed either by itself, or combined with decryption. To support this, store a 'struct bio_post_read_ctx' in ->bi_private which contains a work struct, a bitmask of postprocessing steps that are enabled, and an indicator of the current step. The bio completion routine, if there was no I/O error, enqueues the first postprocessing step. When that completes, it continues to the next step. Pages that fail any postprocessing step have PageError set. Once all steps have completed, pages without PageError set are set Uptodate, and all pages are unlocked. Also replace f2fs_encrypted_file() with a new function f2fs_post_read_required() in places like direct I/O and garbage collection that really should be testing whether the file needs special I/O processing, not whether it is encrypted specifically. This may also be useful for other future f2fs features such as compression. Change-Id: I9e1d7a21b8a7d89029c509df7edd895887993ab1 Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 166 +++++++++++++++++++++++++++++++++++------------ fs/f2fs/f2fs.h | 12 +++- fs/f2fs/file.c | 4 +- fs/f2fs/gc.c | 6 +- fs/f2fs/inline.c | 2 +- fs/f2fs/super.c | 6 ++ 6 files changed, 147 insertions(+), 49 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index b916613bfb3d..9d9abbbe6d18 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -30,6 +30,11 @@ #include #include +#define NUM_PREALLOC_POST_READ_CTXS 128 + +static struct kmem_cache *bio_post_read_ctx_cache; +static mempool_t *bio_post_read_ctx_pool; + static bool __is_cp_guaranteed(struct page *page) { struct address_space *mapping = page->mapping; @@ -50,11 +55,77 @@ static bool __is_cp_guaranteed(struct page *page) return false; } -static void f2fs_read_end_io(struct bio *bio) +/* postprocessing steps for read bios */ +enum bio_post_read_step { + STEP_INITIAL = 0, + STEP_DECRYPT, +}; + +struct bio_post_read_ctx { + struct bio *bio; + struct work_struct work; + unsigned int cur_step; + unsigned int enabled_steps; +}; + +static void __read_end_io(struct bio *bio) { - struct bio_vec *bvec; + struct page *page; + struct bio_vec *bv; int i; + bio_for_each_segment_all(bv, bio, i) { + page = bv->bv_page; + + /* PG_error was set if any post_read step failed */ + if (bio->bi_error || PageError(page)) { + ClearPageUptodate(page); + SetPageError(page); + } else { + SetPageUptodate(page); + } + unlock_page(page); + } + if (bio->bi_private) + mempool_free(bio->bi_private, bio_post_read_ctx_pool); + bio_put(bio); +} + +static void bio_post_read_processing(struct bio_post_read_ctx *ctx); + +static void decrypt_work(struct work_struct *work) +{ + struct bio_post_read_ctx *ctx = + container_of(work, struct bio_post_read_ctx, work); + + fscrypt_decrypt_bio(ctx->bio); + + bio_post_read_processing(ctx); +} + +static void bio_post_read_processing(struct bio_post_read_ctx *ctx) +{ + switch (++ctx->cur_step) { + case STEP_DECRYPT: + if (ctx->enabled_steps & (1 << STEP_DECRYPT)) { + INIT_WORK(&ctx->work, decrypt_work); + fscrypt_enqueue_decrypt_work(&ctx->work); + return; + } + ctx->cur_step++; + /* fall-through */ + default: + __read_end_io(ctx->bio); + } +} + +static bool f2fs_bio_post_read_required(struct bio *bio) +{ + return bio->bi_private && !bio->bi_error; +} + +static void f2fs_read_end_io(struct bio *bio) +{ #ifdef CONFIG_F2FS_FAULT_INJECTION if (time_to_inject(F2FS_P_SB(bio->bi_io_vec->bv_page), FAULT_IO)) { f2fs_show_injection_info(FAULT_IO); @@ -62,28 +133,15 @@ static void f2fs_read_end_io(struct bio *bio) } #endif - if (f2fs_bio_encrypted(bio)) { - if (bio->bi_error) { - fscrypt_release_ctx(bio->bi_private); - } else { - fscrypt_enqueue_decrypt_bio(bio->bi_private, bio); - return; - } - } - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; + if (f2fs_bio_post_read_required(bio)) { + struct bio_post_read_ctx *ctx = bio->bi_private; - if (!bio->bi_error) { - if (!PageUptodate(page)) - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); - } - unlock_page(page); + ctx->cur_step = STEP_INITIAL; + bio_post_read_processing(ctx); + return; } - bio_put(bio); + + __read_end_io(bio); } static void f2fs_write_end_io(struct bio *bio) @@ -480,29 +538,33 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr, unsigned nr_pages) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - struct fscrypt_ctx *ctx = NULL; struct bio *bio; - - if (f2fs_encrypted_file(inode)) { - ctx = fscrypt_get_ctx(inode, GFP_NOFS); - if (IS_ERR(ctx)) - return ERR_CAST(ctx); - - /* wait the page to be moved by cleaning */ - f2fs_wait_on_block_writeback(sbi, blkaddr); - } + struct bio_post_read_ctx *ctx; + unsigned int post_read_steps = 0; bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false); - if (!bio) { - if (ctx) - fscrypt_release_ctx(ctx); + if (!bio) return ERR_PTR(-ENOMEM); - } f2fs_target_device(sbi, blkaddr, bio); bio->bi_end_io = f2fs_read_end_io; - bio->bi_private = ctx; bio_set_op_attrs(bio, REQ_OP_READ, 0); + if (f2fs_encrypted_file(inode)) + post_read_steps |= 1 << STEP_DECRYPT; + if (post_read_steps) { + ctx = mempool_alloc(bio_post_read_ctx_pool, GFP_NOFS); + if (!ctx) { + bio_put(bio); + return ERR_PTR(-ENOMEM); + } + ctx->bio = bio; + ctx->enabled_steps = post_read_steps; + bio->bi_private = ctx; + + /* wait the page to be moved by cleaning */ + f2fs_wait_on_block_writeback(sbi, blkaddr); + } + return bio; } @@ -1524,7 +1586,7 @@ static int encrypt_one_page(struct f2fs_io_info *fio) if (!f2fs_encrypted_file(inode)) return 0; - /* wait for GCed encrypted page writeback */ + /* wait for GCed page writeback via META_MAPPING */ f2fs_wait_on_block_writeback(fio->sbi, fio->old_blkaddr); retry_encrypt: @@ -2236,8 +2298,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping, f2fs_wait_on_page_writeback(page, DATA, false); - /* wait for GCed encrypted page writeback */ - if (f2fs_encrypted_file(inode)) + /* wait for GCed page writeback via META_MAPPING */ + if (f2fs_post_read_required(inode)) f2fs_wait_on_block_writeback(sbi, blkaddr); if (len == PAGE_SIZE || PageUptodate(page)) @@ -2595,3 +2657,27 @@ const struct address_space_operations f2fs_dblock_aops = { .migratepage = f2fs_migrate_page, #endif }; + +int __init f2fs_init_post_read_processing(void) +{ + bio_post_read_ctx_cache = KMEM_CACHE(bio_post_read_ctx, 0); + if (!bio_post_read_ctx_cache) + goto fail; + bio_post_read_ctx_pool = + mempool_create_slab_pool(NUM_PREALLOC_POST_READ_CTXS, + bio_post_read_ctx_cache); + if (!bio_post_read_ctx_pool) + goto fail_free_cache; + return 0; + +fail_free_cache: + kmem_cache_destroy(bio_post_read_ctx_cache); +fail: + return -ENOMEM; +} + +void __exit f2fs_destroy_post_read_processing(void) +{ + mempool_destroy(bio_post_read_ctx_pool); + kmem_cache_destroy(bio_post_read_ctx_cache); +} diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 95434234d810..485b64b193c5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2886,6 +2886,8 @@ void destroy_checkpoint_caches(void); /* * data.c */ +int f2fs_init_post_read_processing(void); +void f2fs_destroy_post_read_processing(void); void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type); void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, struct inode *inode, nid_t ino, pgoff_t idx, @@ -3246,9 +3248,13 @@ static inline void f2fs_set_encrypted_inode(struct inode *inode) #endif } -static inline bool f2fs_bio_encrypted(struct bio *bio) +/* + * Returns true if the reads of the inode's data need to undergo some + * postprocessing step, like decryption or authenticity verification. + */ +static inline bool f2fs_post_read_required(struct inode *inode) { - return bio->bi_private != NULL; + return f2fs_encrypted_file(inode); } #define F2FS_FEATURE_FUNCS(name, flagname) \ @@ -3316,7 +3322,7 @@ static inline bool f2fs_may_encrypt(struct inode *inode) static inline bool f2fs_force_buffered_io(struct inode *inode, int rw) { - return (f2fs_encrypted_file(inode) || + return (f2fs_post_read_required(inode) || (rw == WRITE && test_opt(F2FS_I_SB(inode), LFS)) || F2FS_I_SB(inode)->s_ndevs); } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 7ed0463dc56e..0e39c7768a88 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -112,8 +112,8 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, /* fill the page */ f2fs_wait_on_page_writeback(page, DATA, false); - /* wait for GCed encrypted page writeback */ - if (f2fs_encrypted_file(inode)) + /* wait for GCed page writeback via META_MAPPING */ + if (f2fs_post_read_required(inode)) f2fs_wait_on_block_writeback(sbi, dn.data_blkaddr); out_sem: diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 0ad8b3a7a74d..604d3fcb8957 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -850,8 +850,8 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, if (IS_ERR(inode) || is_bad_inode(inode)) continue; - /* if encrypted inode, let's go phase 3 */ - if (f2fs_encrypted_file(inode)) { + /* if inode uses special I/O path, let's go phase 3 */ + if (f2fs_post_read_required(inode)) { add_gc_inode(gc_list, inode); continue; } @@ -899,7 +899,7 @@ static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, start_bidx = start_bidx_of_node(nofs, inode) + ofs_in_node; - if (f2fs_encrypted_file(inode)) + if (f2fs_post_read_required(inode)) move_data_block(inode, start_bidx, segno, off); else move_data_page(inode, start_bidx, gc_type, diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 1925814ac675..26832e778233 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -26,7 +26,7 @@ bool f2fs_may_inline_data(struct inode *inode) if (i_size_read(inode) > MAX_INLINE_DATA(inode)) return false; - if (f2fs_encrypted_file(inode)) + if (f2fs_post_read_required(inode)) return false; return true; diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 510c91b3a23b..7d4621a8a5e7 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -3096,8 +3096,13 @@ static int __init init_f2fs_fs(void) err = f2fs_create_root_stats(); if (err) goto free_filesystem; + err = f2fs_init_post_read_processing(); + if (err) + goto free_root_stats; return 0; +free_root_stats: + f2fs_destroy_root_stats(); free_filesystem: unregister_filesystem(&f2fs_fs_type); free_shrinker: @@ -3120,6 +3125,7 @@ static int __init init_f2fs_fs(void) static void __exit exit_f2fs_fs(void) { + f2fs_destroy_post_read_processing(); f2fs_destroy_root_stats(); unregister_filesystem(&f2fs_fs_type); unregister_shrinker(&f2fs_shrinker_info); -- GitLab From ee0bcd679075f2d1509334486dafa2a9caea890a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 18 Apr 2018 15:48:42 -0700 Subject: [PATCH 1401/1834] f2fs: call unlock_new_inode() before d_instantiate() Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: e605f836c89e ("f2fs: call unlock_new_inode() before d_instantiate()") xfstest generic/429 sometimes hangs on f2fs, caused by a thread being unable to take a directory's i_rwsem for write in vfs_rmdir(). In the test, one thread repeatedly creates and removes a directory, and other threads repeatedly look up a file in the directory. The bug is that f2fs_mkdir() calls d_instantiate() before unlock_new_inode(), resulting in the directory inode being exposed to lookups before it has been fully initialized. And with CONFIG_DEBUG_LOCK_ALLOC, unlock_new_inode() reinitializes ->i_rwsem, corrupting its state when it is already held. Fix it by calling unlock_new_inode() before d_instantiate(). This matches what other filesystems do. Fixes: 57397d86c62d ("f2fs: add inode operations for special inodes") Change-Id: I3f3a17bd5c22e69f685f4d00c2210876fb29a846 Signed-off-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 2d49029b392d..392d1ed99b56 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -294,8 +294,8 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode, alloc_nid_done(sbi, ino); - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); @@ -597,8 +597,8 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, err = page_symlink(inode, disk_link.name, disk_link.len); err_out: - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); /* * Let's flush symlink data in order to avoid broken symlink as much as @@ -661,8 +661,8 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) alloc_nid_done(sbi, inode->i_ino); - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); @@ -713,8 +713,8 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry, alloc_nid_done(sbi, inode->i_ino); - d_instantiate(dentry, inode); unlock_new_inode(inode); + d_instantiate(dentry, inode); if (IS_DIRSYNC(dir)) f2fs_sync_fs(sbi->sb, 1); -- GitLab From e09480fd930bb900024a0be339fe1a2211f0a2d8 Mon Sep 17 00:00:00 2001 From: Shankar Ravi Date: Mon, 2 Apr 2018 15:27:28 +0530 Subject: [PATCH 1402/1834] msm: camera: Increase CCI time out to 1.5 sec to fix the time out failures CCI is used by multiple slaves like sensor actuator, eeprom during boot time. Increasing the cci time out to reduce the actuator initialization failures. Change-Id: If63870f1f6e8df6672c7954a897cd8bd7bef2e38 Signed-off-by: Shankar Ravi --- .../platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c | 1 - .../platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c index fb37526fb0d2..da08bc7ab037 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.c @@ -16,7 +16,6 @@ #include "cam_cci_core.h" #define CCI_MAX_DELAY 1000000 -#define CCI_TIMEOUT msecs_to_jiffies(500) static struct v4l2_subdev *g_cci_subdev; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h index d25964e4def1..7cde6190f9db 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -45,7 +45,7 @@ #define CYCLES_PER_MICRO_SEC_DEFAULT 4915 #define CCI_MAX_DELAY 1000000 -#define CCI_TIMEOUT msecs_to_jiffies(500) +#define CCI_TIMEOUT msecs_to_jiffies(1500) #define NUM_MASTERS 2 #define NUM_QUEUES 2 -- GitLab From 860716c814eb0eb5cd3a8944311ecccccc5676f2 Mon Sep 17 00:00:00 2001 From: Vivek Veenam Date: Fri, 13 Apr 2018 16:58:43 +0530 Subject: [PATCH 1403/1834] msm: camera: Add NULL check before accessing power settings Sensor power settings can be freed by some thread while another thread try to access it. Add NULL check before to prevent this. Change-Id: Ice3d8c6da65afd5196be67860543eb974183c55e Signed-off-by: Vivek Veenam --- .../cam_sensor_utils/cam_sensor_util.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c index a39996311854..10d29c91f03e 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_utils/cam_sensor_util.c @@ -1303,6 +1303,11 @@ int cam_sensor_core_power_up(struct cam_sensor_power_ctrl_t *ctrl, for (index = 0; index < ctrl->power_setting_size; index++) { CAM_DBG(CAM_SENSOR, "index: %d", index); power_setting = &ctrl->power_setting[index]; + if (!power_setting) { + CAM_ERR(CAM_SENSOR, "Invalid power up settings"); + return -EINVAL; + } + CAM_DBG(CAM_SENSOR, "seq_type %d", power_setting->seq_type); switch (power_setting->seq_type) { @@ -1589,6 +1594,11 @@ static int cam_config_mclk_reg(struct cam_sensor_power_ctrl_t *ctrl, pd = &ctrl->power_down_setting[index]; + if (!pd) { + CAM_ERR(CAM_SENSOR, "Invalid power down setting"); + return -EINVAL; + } + for (j = 0; j < num_vreg; j++) { if (!strcmp(soc_info->rgltr_name[j], "cam_clk")) { -- GitLab From 3fc02ad43069054d4b3ad489557bef0ef525270e Mon Sep 17 00:00:00 2001 From: Animesh Kishore Date: Mon, 23 Apr 2018 15:17:40 +0530 Subject: [PATCH 1404/1834] mdss: mdp: Add error check for split ctl Exit with error if failed to get split ctl. Change-Id: Icf7ba54f774b5ea535e136230897515eb624e9ad Signed-off-by: Animesh Kishore --- drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 7a0542a45835..3a44bd5e4305 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -569,7 +569,9 @@ int mdss_mdp_resource_control(struct mdss_mdp_ctl *ctl, u32 sw_event) bool schedule_off = false; /* Get both controllers in the correct order for dual displays */ - mdss_mdp_get_split_display_ctls(&ctl, &sctl); + rc = mdss_mdp_get_split_display_ctls(&ctl, &sctl); + if (rc) + goto exit; ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx) { -- GitLab From 142d4b530f5adc01e1addcbb2e1f61e879898670 Mon Sep 17 00:00:00 2001 From: Patrik Torstensson Date: Thu, 22 Mar 2018 18:18:04 -0700 Subject: [PATCH 1405/1834] BACKPORT: dm verity: add 'check_at_most_once' option to only validate hashes once This allows platforms that are CPU/memory contrained to verify data blocks only the first time they are read from the data device, rather than every time. As such, it provides a reduced level of security because only offline tampering of the data device's content will be detected, not online tampering. Hash blocks are still verified each time they are read from the hash device, since verification of hash blocks is less performance critical than data blocks, and a hash block will not be verified any more after all the data blocks it covers have been verified anyway. This option introduces a bitset that is used to check if a block has been validated before or not. A block can be validated more than once as there is no thread protection for the bitset. These changes were developed and tested on entry-level Android Go devices. Change-Id: I4a0be2552acb04f7c2ce6665031199d9dcbc2430 Bug: 72664474 Signed-off-by: Mike Snitzer (cherry picked from commit 843f38d382b1ca2f6f4ae2ef7c35933e6319ffbb) (changed alloc to vzalloc/vfree) Signed-off-by: Patrik Torstensson --- Documentation/device-mapper/verity.txt | 11 +++++ drivers/md/dm-verity-target.c | 65 ++++++++++++++++++++++++-- drivers/md/dm-verity.h | 1 + 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt index 89fd8f9a259f..b3d2e4a42255 100644 --- a/Documentation/device-mapper/verity.txt +++ b/Documentation/device-mapper/verity.txt @@ -109,6 +109,17 @@ fec_start This is the offset, in blocks, from the start of the FEC device to the beginning of the encoding data. +check_at_most_once + Verify data blocks only the first time they are read from the data device, + rather than every time. This reduces the overhead of dm-verity so that it + can be used on systems that are memory and/or CPU constrained. However, it + provides a reduced level of security because only offline tampering of the + data device's content will be detected, not online tampering. + + Hash blocks are still verified each time they are read from the hash device, + since verification of hash blocks is less performance critical than data + blocks, and a hash block will not be verified any more after all the data + blocks it covers have been verified anyway. Theory of operation =================== diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c index 5d0a9963b108..d96aa84cacd2 100644 --- a/drivers/md/dm-verity-target.c +++ b/drivers/md/dm-verity-target.c @@ -19,6 +19,7 @@ #include #include +#include #define DM_MSG_PREFIX "verity" @@ -32,6 +33,7 @@ #define DM_VERITY_OPT_LOGGING "ignore_corruption" #define DM_VERITY_OPT_RESTART "restart_on_corruption" #define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks" +#define DM_VERITY_OPT_AT_MOST_ONCE "check_at_most_once" #define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC) @@ -394,6 +396,18 @@ static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io, return 0; } +/* + * Moves the bio iter one data block forward. + */ +static inline void verity_bv_skip_block(struct dm_verity *v, + struct dm_verity_io *io, + struct bvec_iter *iter) +{ + struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_io_data_size); + + bio_advance_iter(bio, iter, 1 << v->data_dev_block_bits); +} + /* * Verify one "dm_verity_io" structure. */ @@ -406,9 +420,16 @@ static int verity_verify_io(struct dm_verity_io *io) for (b = 0; b < io->n_blocks; b++) { int r; + sector_t cur_block = io->block + b; struct shash_desc *desc = verity_io_hash_desc(v, io); - r = verity_hash_for_block(v, io, io->block + b, + if (v->validated_blocks && + likely(test_bit(cur_block, v->validated_blocks))) { + verity_bv_skip_block(v, io, &io->iter); + continue; + } + + r = verity_hash_for_block(v, io, cur_block, verity_io_want_digest(v, io), &is_zero); if (unlikely(r < 0)) @@ -441,13 +462,16 @@ static int verity_verify_io(struct dm_verity_io *io) return r; if (likely(memcmp(verity_io_real_digest(v, io), - verity_io_want_digest(v, io), v->digest_size) == 0)) + verity_io_want_digest(v, io), v->digest_size) == 0)) { + if (v->validated_blocks) + set_bit(cur_block, v->validated_blocks); continue; + } else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA, - io->block + b, NULL, &start) == 0) + cur_block, NULL, &start) == 0) continue; else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA, - io->block + b)) + cur_block)) return -EIO; } @@ -641,6 +665,8 @@ void verity_status(struct dm_target *ti, status_type_t type, args += DM_VERITY_OPTS_FEC; if (v->zero_digest) args++; + if (v->validated_blocks) + args++; if (!args) return; DMEMIT(" %u", args); @@ -659,6 +685,8 @@ void verity_status(struct dm_target *ti, status_type_t type, } if (v->zero_digest) DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES); + if (v->validated_blocks) + DMEMIT(" " DM_VERITY_OPT_AT_MOST_ONCE); sz = verity_fec_status_table(v, sz, result, maxlen); break; } @@ -712,6 +740,7 @@ void verity_dtr(struct dm_target *ti) if (v->bufio) dm_bufio_client_destroy(v->bufio); + vfree(v->validated_blocks); kfree(v->salt); kfree(v->root_digest); kfree(v->zero_digest); @@ -733,6 +762,26 @@ void verity_dtr(struct dm_target *ti) } EXPORT_SYMBOL_GPL(verity_dtr); +static int verity_alloc_most_once(struct dm_verity *v) +{ + struct dm_target *ti = v->ti; + + /* the bitset can only handle INT_MAX blocks */ + if (v->data_blocks > INT_MAX) { + ti->error = "device too large to use check_at_most_once"; + return -E2BIG; + } + + v->validated_blocks = vzalloc(BITS_TO_LONGS(v->data_blocks) * + sizeof(unsigned long)); + if (!v->validated_blocks) { + ti->error = "failed to allocate bitset for check_at_most_once"; + return -ENOMEM; + } + + return 0; +} + static int verity_alloc_zero_digest(struct dm_verity *v) { int r = -ENOMEM; @@ -802,6 +851,12 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v) } continue; + } else if (!strcasecmp(arg_name, DM_VERITY_OPT_AT_MOST_ONCE)) { + r = verity_alloc_most_once(v); + if (r) + return r; + continue; + } else if (verity_is_fec_opt_arg(arg_name)) { r = verity_fec_parse_opt_args(as, v, &argc, arg_name); if (r) @@ -1070,7 +1125,7 @@ EXPORT_SYMBOL_GPL(verity_ctr); static struct target_type verity_target = { .name = "verity", - .version = {1, 3, 0}, + .version = {1, 4, 0}, .module = THIS_MODULE, .ctr = verity_ctr, .dtr = verity_dtr, diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h index 75effca400a3..6d6d8df5b58c 100644 --- a/drivers/md/dm-verity.h +++ b/drivers/md/dm-verity.h @@ -63,6 +63,7 @@ struct dm_verity { sector_t hash_level_block[DM_VERITY_MAX_LEVELS]; struct dm_verity_fec *fec; /* forward error correction */ + unsigned long *validated_blocks; /* bitset blocks validated */ }; struct dm_verity_io { -- GitLab From e14cca18b61d4f84a5e90496c75663479a011cc4 Mon Sep 17 00:00:00 2001 From: Junzhe Zou Date: Tue, 10 Apr 2018 14:56:51 -0700 Subject: [PATCH 1406/1834] msm: camera: isp: put tasklet cmd back to free list at start Put tasklet cmd back to free list when tasklet starts to avoid leak. Change-Id: I9cb2fcefc3e89062ad4b9267a97f54c11381c312 Signed-off-by: Junzhe Zou --- .../isp_hw_mgr/hw_utils/cam_tasklet_util.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c index 8863275b6323..3a897328eeb3 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/hw_utils/cam_tasklet_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -273,8 +273,7 @@ static void cam_tasklet_flush(void *tasklet_info) int cam_tasklet_start(void *tasklet_info) { struct cam_tasklet_info *tasklet = tasklet_info; - struct cam_tasklet_queue_cmd *tasklet_cmd; - struct cam_tasklet_queue_cmd *tasklet_cmd_temp; + int i = 0; if (atomic_read(&tasklet->tasklet_active)) { CAM_ERR(CAM_ISP, "Tasklet already active. idx = %d", @@ -283,11 +282,11 @@ int cam_tasklet_start(void *tasklet_info) } atomic_set(&tasklet->tasklet_active, 1); - /* flush the command queue first */ - list_for_each_entry_safe(tasklet_cmd, tasklet_cmd_temp, - &tasklet->used_cmd_list, list) { - list_del_init(&tasklet_cmd->list); - list_add_tail(&tasklet_cmd->list, &tasklet->free_cmd_list); + /* clean up the command queue first */ + for (i = 0; i < CAM_TASKLETQ_SIZE; i++) { + list_del_init(&tasklet->cmd_queue[i].list); + list_add_tail(&tasklet->cmd_queue[i].list, + &tasklet->free_cmd_list); } tasklet_enable(&tasklet->tasklet); -- GitLab From efeffe9d4334cacaeec5aec3706d42d11969ac40 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 11 Apr 2018 23:09:04 -0700 Subject: [PATCH 1407/1834] f2fs: clear PageError on writepage Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: commit 926b3701caff ("f2fs: clear PageError on writepage") This patch clears PageError in some pages tagged by read path, but when we write the pages with valid contents, writepage should clear the bit likewise ext4. Change-Id: I01ec79dc5e209c44b4b5e0de69459eb8c32b1a95 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 9d9abbbe6d18..521872dcae09 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1736,6 +1736,7 @@ int do_write_data_page(struct f2fs_io_info *fio) goto out_writepage; set_page_writeback(page); + ClearPageError(page); f2fs_put_dnode(&dn); if (fio->need_lock == LOCK_REQ) f2fs_unlock_op(fio->sbi); @@ -1758,6 +1759,7 @@ int do_write_data_page(struct f2fs_io_info *fio) goto out_writepage; set_page_writeback(page); + ClearPageError(page); /* LFS mode write path */ write_data_page(&dn, fio); -- GitLab From a25efd8e036a7f42fb57a20175c3acbbf4f22638 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 20 Apr 2018 19:29:52 -0700 Subject: [PATCH 1408/1834] Revert "f2fs: introduce f2fs_set_page_dirty_nobuffer" Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: commit 95459e9ebe19 ("Revert "f2fs: introduce f2fs_set_page_dirty_nobuffer"") This patch reverts copied f2fs_set_page_dirty_nobuffer to use generic function for stability. This reverts commit fe76b796fc5194cc3d57265002e3a748566d073f. Change-Id: I2d31d13eb14b2672f8d3c74c16c759ebbb6a1d32 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 2 +- fs/f2fs/data.c | 33 +-------------------------------- fs/f2fs/f2fs.h | 1 - fs/f2fs/node.c | 2 +- 4 files changed, 3 insertions(+), 35 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 6c7b0547a307..91b2d0056470 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -385,7 +385,7 @@ static int f2fs_set_meta_page_dirty(struct page *page) if (!PageUptodate(page)) SetPageUptodate(page); if (!PageDirty(page)) { - f2fs_set_page_dirty_nobuffers(page); + __set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_META); SetPagePrivate(page); f2fs_trace_pid(page); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 521872dcae09..b1fd4e2f63a5 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #include #include "f2fs.h" @@ -2514,35 +2512,6 @@ int f2fs_release_page(struct page *page, gfp_t wait) return 1; } -/* - * This was copied from __set_page_dirty_buffers which gives higher performance - * in very high speed storages. (e.g., pmem) - */ -void f2fs_set_page_dirty_nobuffers(struct page *page) -{ - struct address_space *mapping = page->mapping; - unsigned long flags; - - if (unlikely(!mapping)) - return; - - spin_lock(&mapping->private_lock); - lock_page_memcg(page); - SetPageDirty(page); - spin_unlock(&mapping->private_lock); - - spin_lock_irqsave(&mapping->tree_lock, flags); - WARN_ON_ONCE(!PageUptodate(page)); - account_page_dirtied(page, mapping); - radix_tree_tag_set(&mapping->page_tree, - page_index(page), PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - unlock_page_memcg(page); - - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - return; -} - static int f2fs_set_data_page_dirty(struct page *page) { struct address_space *mapping = page->mapping; @@ -2566,7 +2535,7 @@ static int f2fs_set_data_page_dirty(struct page *page) } if (!PageDirty(page)) { - f2fs_set_page_dirty_nobuffers(page); + __set_page_dirty_nobuffers(page); update_dirty_page(inode, page); return 1; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 485b64b193c5..7d586b302da5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2919,7 +2919,6 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); bool should_update_inplace(struct inode *inode, struct f2fs_io_info *fio); bool should_update_outplace(struct inode *inode, struct f2fs_io_info *fio); -void f2fs_set_page_dirty_nobuffers(struct page *page); int __f2fs_write_data_pages(struct address_space *mapping, struct writeback_control *wbc, enum iostat_type io_type); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 199170e2e221..ccf410af9192 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1772,7 +1772,7 @@ static int f2fs_set_node_page_dirty(struct page *page) if (!PageUptodate(page)) SetPageUptodate(page); if (!PageDirty(page)) { - f2fs_set_page_dirty_nobuffers(page); + __set_page_dirty_nobuffers(page); inc_page_count(F2FS_P_SB(page), F2FS_DIRTY_NODES); SetPagePrivate(page); f2fs_trace_pid(page); -- GitLab From a35dc729372b84fb410279162b05e33f546380e1 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 20 Apr 2018 23:44:59 -0700 Subject: [PATCH 1409/1834] f2fs: check cap_resource only for data blocks Cherry-pick from origin/upstream-f2fs-stable-linux-4.9.y: commit c8fb24500dfe ("f2fs: check cap_resource only for data blocks") This patch changes the rule to check cap_resource for data blocks, not inode or node blocks in order to avoid selinux denial. Change-Id: I7b4135b6abc33f4786c982e37ca6e1d3f3fe1f69 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 7d586b302da5..84be1e7db9b6 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1612,7 +1612,7 @@ static inline bool f2fs_has_xattr_block(unsigned int ofs) } static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, - struct inode *inode) + struct inode *inode, bool cap) { if (!inode) return true; @@ -1625,7 +1625,7 @@ static inline bool __allow_reserved_blocks(struct f2fs_sb_info *sbi, if (!gid_eq(F2FS_OPTION(sbi).s_resgid, GLOBAL_ROOT_GID) && in_group_p(F2FS_OPTION(sbi).s_resgid)) return true; - if (capable(CAP_SYS_RESOURCE)) + if (cap && capable(CAP_SYS_RESOURCE)) return true; return false; } @@ -1660,7 +1660,7 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, avail_user_block_count = sbi->user_block_count - sbi->current_reserved_blocks; - if (!__allow_reserved_blocks(sbi, inode)) + if (!__allow_reserved_blocks(sbi, inode, true)) avail_user_block_count -= F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(sbi->total_valid_block_count > avail_user_block_count)) { @@ -1867,7 +1867,7 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, valid_block_count = sbi->total_valid_block_count + sbi->current_reserved_blocks + 1; - if (!__allow_reserved_blocks(sbi, inode)) + if (!__allow_reserved_blocks(sbi, inode, false)) valid_block_count += F2FS_OPTION(sbi).root_reserved_blocks; if (unlikely(valid_block_count > sbi->user_block_count)) { -- GitLab From 582eb3bfd60ca04f5f42cd410a4d96fbf653c243 Mon Sep 17 00:00:00 2001 From: Shefali Jain Date: Tue, 24 Apr 2018 11:46:58 +0530 Subject: [PATCH 1410/1834] ARM: dts: msm: Update the CC count property for SDM845/670 Currently, the count for number of clock controllers for debug measurement is incorrect so fix the same by updating the correct clock controllers count which is the equal to the number of CCs. Change-Id: I4a09cfa6ebe1da8df4411c451b2026d18de3cf4e Signed-off-by: Shefali Jain --- arch/arm64/boot/dts/qcom/sdm670.dtsi | 2 +- arch/arm64/boot/dts/qcom/sdm845.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 4d4e91862fe2..d7c5a68ea9f0 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -1096,7 +1096,7 @@ clock_debug: qcom,cc-debug { compatible = "qcom,debugcc-sdm845"; - qcom,cc-count = <5>; + qcom,cc-count = <6>; qcom,gcc = <&clock_gcc>; qcom,videocc = <&clock_videocc>; qcom,camcc = <&clock_camcc>; diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi index 82e55c42380b..c3d712fbece5 100644 --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi @@ -1276,7 +1276,7 @@ clock_debug: qcom,cc-debug@100000 { compatible = "qcom,debugcc-sdm845"; - qcom,cc-count = <5>; + qcom,cc-count = <6>; qcom,gcc = <&clock_gcc>; qcom,videocc = <&clock_videocc>; qcom,camcc = <&clock_camcc>; -- GitLab From a7e19062d115e3acf71649a1fba6d5c7d65be3d1 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 13 Feb 2018 07:38:08 -0800 Subject: [PATCH 1411/1834] tty: make n_tty_read() always abort if hangup is in progress commit 28b0f8a6962a24ed21737578f3b1b07424635c9e upstream. A tty is hung up by __tty_hangup() setting file->f_op to hung_up_tty_fops, which is skipped on ttys whose write operation isn't tty_write(). This means that, for example, /dev/console whose write op is redirected_tty_write() is never actually marked hung up. Because n_tty_read() uses the hung up status to decide whether to abort the waiting readers, the lack of hung-up marking can lead to the following scenario. 1. A session contains two processes. The leader and its child. The child ignores SIGHUP. 2. The leader exits and starts disassociating from the controlling terminal (/dev/console). 3. __tty_hangup() skips setting f_op to hung_up_tty_fops. 4. SIGHUP is delivered and ignored. 5. tty_ldisc_hangup() is invoked. It wakes up the waits which should clear the read lockers of tty->ldisc_sem. 6. The reader wakes up but because tty_hung_up_p() is false, it doesn't abort and goes back to sleep while read-holding tty->ldisc_sem. 7. The leader progresses to tty_ldisc_lock() in tty_ldisc_hangup() and is now stuck in D sleep indefinitely waiting for tty->ldisc_sem. The following is Alan's explanation on why some ttys aren't hung up. http://lkml.kernel.org/r/20171101170908.6ad08580@alans-desktop 1. It broke the serial consoles because they would hang up and close down the hardware. With tty_port that *should* be fixable properly for any cases remaining. 2. The console layer was (and still is) completely broken and doens't refcount properly. So if you turn on console hangups it breaks (as indeed does freeing consoles and half a dozen other things). As neither can be fixed quickly, this patch works around the problem by introducing a new flag, TTY_HUPPING, which is used solely to tell n_tty_read() that hang-up is in progress for the console and the readers should be aborted regardless of the hung-up status of the device. The following is a sample hung task warning caused by this issue. INFO: task agetty:2662 blocked for more than 120 seconds. Not tainted 4.11.3-dbg-tty-lockup-02478-gfd6c7ee-dirty #28 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. 0 2662 1 0x00000086 Call Trace: __schedule+0x267/0x890 schedule+0x36/0x80 schedule_timeout+0x23c/0x2e0 ldsem_down_write+0xce/0x1f6 tty_ldisc_lock+0x16/0x30 tty_ldisc_hangup+0xb3/0x1b0 __tty_hangup+0x300/0x410 disassociate_ctty+0x6c/0x290 do_exit+0x7ef/0xb00 do_group_exit+0x3f/0xa0 get_signal+0x1b3/0x5d0 do_signal+0x28/0x660 exit_to_usermode_loop+0x46/0x86 do_syscall_64+0x9c/0xb0 entry_SYSCALL64_slow_path+0x25/0x25 The following is the repro. Run "$PROG /dev/console". The parent process hangs in D state. #include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { struct sigaction sact = { .sa_handler = SIG_IGN }; struct timespec ts1s = { .tv_sec = 1 }; pid_t pid; int fd; if (argc < 2) { fprintf(stderr, "test-hung-tty /dev/$TTY\n"); return 1; } /* fork a child to ensure that it isn't already the session leader */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { /* top parent, wait for everyone */ while (waitpid(-1, NULL, 0) >= 0) ; if (errno != ECHILD) perror("waitpid"); return 0; } /* new session, start a new session and set the controlling tty */ if (setsid() < 0) { perror("setsid"); return 1; } fd = open(argv[1], O_RDWR); if (fd < 0) { perror("open"); return 1; } if (ioctl(fd, TIOCSCTTY, 1) < 0) { perror("ioctl"); return 1; } /* fork a child, sleep a bit and exit */ pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid > 0) { nanosleep(&ts1s, NULL); printf("Session leader exiting\n"); exit(0); } /* * The child ignores SIGHUP and keeps reading from the controlling * tty. Because SIGHUP is ignored, the child doesn't get killed on * parent exit and the bug in n_tty makes the read(2) block the * parent's control terminal hangup attempt. The parent ends up in * D sleep until the child is explicitly killed. */ sigaction(SIGHUP, &sact, NULL); printf("Child reading tty\n"); while (1) { char buf[1024]; if (read(fd, buf, sizeof(buf)) < 0) { perror("read"); return 1; } } return 0; } Signed-off-by: Tejun Heo Cc: Alan Cox Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 6 ++++++ drivers/tty/tty_io.c | 9 +++++++++ include/linux/tty.h | 1 + 3 files changed, 16 insertions(+) diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index faf50df81622..1c70541a1467 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -2182,6 +2182,12 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, } if (tty_hung_up_p(file)) break; + /* + * Abort readers for ttys which never actually + * get hung up. See __tty_hangup(). + */ + if (test_bit(TTY_HUPPING, &tty->flags)) + break; if (!timeout) break; if (file->f_flags & O_NONBLOCK) { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index fb9bada5f1d5..4ee0a9de7556 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -709,6 +709,14 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) return; } + /* + * Some console devices aren't actually hung up for technical and + * historical reasons, which can lead to indefinite interruptible + * sleep in n_tty_read(). The following explicitly tells + * n_tty_read() to abort readers. + */ + set_bit(TTY_HUPPING, &tty->flags); + /* inuse_filps is protected by the single tty lock, this really needs to change if we want to flush the workqueue with the lock held */ @@ -763,6 +771,7 @@ static void __tty_hangup(struct tty_struct *tty, int exit_session) * from the ldisc side, which is now guaranteed. */ set_bit(TTY_HUPPED, &tty->flags); + clear_bit(TTY_HUPPING, &tty->flags); tty_unlock(tty); if (f) diff --git a/include/linux/tty.h b/include/linux/tty.h index a41244fe58d0..6f1ee8528210 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -355,6 +355,7 @@ struct tty_file_private { #define TTY_PTY_LOCK 16 /* pty private */ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ #define TTY_HUPPED 18 /* Post driver->hangup() */ +#define TTY_HUPPING 19 /* Hangup in progress */ #define TTY_LDISC_HALTED 22 /* Line discipline is halted */ /* Values for tty->flow_change */ -- GitLab From cf1595d865e78fa2f5ecf314e403aa539d71529c Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 17 Jan 2018 19:12:42 +0100 Subject: [PATCH 1412/1834] ubifs: Check ubifs_wbuf_sync() return code commit aac17948a7ce01fb60b9ee6cf902967a47b3ce26 upstream. If ubifs_wbuf_sync() fails we must not write a master node with the dirty marker cleared. Otherwise it is possible that in case of an IO error while syncing we mark the filesystem as clean and UBIFS refuses to recover upon next mount. Cc: Fixes: 1e51764a3c2a ("UBIFS: add new flash file system") Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- fs/ubifs/super.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 4ec051089186..03dda1cbe485 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1728,8 +1728,11 @@ static void ubifs_remount_ro(struct ubifs_info *c) dbg_save_space_info(c); - for (i = 0; i < c->jhead_cnt; i++) - ubifs_wbuf_sync(&c->jheads[i].wbuf); + for (i = 0; i < c->jhead_cnt; i++) { + err = ubifs_wbuf_sync(&c->jheads[i].wbuf); + if (err) + ubifs_ro_mode(c, err); + } c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY); c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); @@ -1795,8 +1798,11 @@ static void ubifs_put_super(struct super_block *sb) int err; /* Synchronize write-buffers */ - for (i = 0; i < c->jhead_cnt; i++) - ubifs_wbuf_sync(&c->jheads[i].wbuf); + for (i = 0; i < c->jhead_cnt; i++) { + err = ubifs_wbuf_sync(&c->jheads[i].wbuf); + if (err) + ubifs_ro_mode(c, err); + } /* * We are being cleanly unmounted which means the -- GitLab From 00f308c0eea4d2f7bc5bb3b9d0947f2219f53760 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Wed, 17 Jan 2018 23:15:57 +0100 Subject: [PATCH 1413/1834] ubi: fastmap: Don't flush fastmap work on detach commit 29b7a6fa1ec07e8480b0d9caf635a4498a438bf4 upstream. At this point UBI volumes have already been free()'ed and fastmap can no longer access these data structures. Reported-by: Martin Townsend Fixes: 74cdaf24004a ("UBI: Fastmap: Fix memory leaks while closing the WL sub-system") Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/fastmap-wl.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c index 4f0bd6b4422a..69dd21679a30 100644 --- a/drivers/mtd/ubi/fastmap-wl.c +++ b/drivers/mtd/ubi/fastmap-wl.c @@ -362,7 +362,6 @@ static void ubi_fastmap_close(struct ubi_device *ubi) { int i; - flush_work(&ubi->fm_work); return_unused_pool_pebs(ubi, &ubi->fm_pool); return_unused_pool_pebs(ubi, &ubi->fm_wl_pool); -- GitLab From 434a1dd2c0e4f6af3fa4ca9cc3e88bbf07b8f41c Mon Sep 17 00:00:00 2001 From: Romain Izard Date: Mon, 29 Jan 2018 11:18:20 +0100 Subject: [PATCH 1414/1834] ubi: Fix error for write access commit 78a8dfbabbece22bee58ac4cb26cab10e7a19c5d upstream. When opening a device with write access, ubiblock_open returns an error code. Currently, this error code is -EPERM, but this is not the right value. The open function for other block devices returns -EROFS when opening read-only devices with FMODE_WRITE set. When used with dm-verity, the veritysetup userspace tool is expecting EROFS, and refuses to use the ubiblock device. Use -EROFS for ubiblock as well. As a result, veritysetup accepts the ubiblock device as valid. Cc: stable@vger.kernel.org Fixes: 9d54c8a33eec (UBI: R/O block driver on top of UBI volumes) Signed-off-by: Romain Izard Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/block.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index 46913ef25bc0..479a5f02d10b 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -244,7 +244,7 @@ static int ubiblock_open(struct block_device *bdev, fmode_t mode) * in any case. */ if (mode & FMODE_WRITE) { - ret = -EPERM; + ret = -EROFS; goto out_unlock; } -- GitLab From c64c4c81aed52fc84be225ce47863a41eb4f7bb6 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sat, 3 Mar 2018 11:45:54 +0100 Subject: [PATCH 1415/1834] ubi: Reject MLC NAND commit b5094b7f135be34630e3ea8a98fa215715d0f29d upstream. While UBI and UBIFS seem to work at first sight with MLC NAND, you will most likely lose all your data upon a power-cut or due to read/write disturb. In order to protect users from bad surprises, refuse to attach to MLC NAND. Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger Acked-by: Boris Brezillon Acked-by: Artem Bityutskiy Signed-off-by: Greg Kroah-Hartman --- drivers/mtd/ubi/build.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 85d54f37e28f..6cb5ca52cb5a 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -894,6 +894,17 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, return -EINVAL; } + /* + * Both UBI and UBIFS have been designed for SLC NAND and NOR flashes. + * MLC NAND is different and needs special care, otherwise UBI or UBIFS + * will die soon and you will lose all your data. + */ + if (mtd->type == MTD_MLCNANDFLASH) { + pr_err("ubi: refuse attaching mtd%d - MLC NAND is not supported\n", + mtd->index); + return -EINVAL; + } + if (ubi_num == UBI_DEV_NUM_AUTO) { /* Search for an empty slot in the @ubi_devices array */ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) -- GitLab From 52b329d678e8495bda4d943df6444403f41c57ff Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 10 Apr 2018 16:34:41 -0700 Subject: [PATCH 1416/1834] fs/reiserfs/journal.c: add missing resierfs_warning() arg commit 9ad553abe66f8be3f4755e9fa0a6ba137ce76341 upstream. One use of the reiserfs_warning() macro in journal_init_dev() is missing a parameter, causing the following warning: REISERFS warning (device loop0): journal_init_dev: Cannot open '%s': %i journal_init_dev: This also causes a WARN_ONCE() warning in the vsprintf code, and then a panic if panic_on_warn is set. Please remove unsupported %/ in format string WARNING: CPU: 1 PID: 4480 at lib/vsprintf.c:2138 format_decode+0x77f/0x830 lib/vsprintf.c:2138 Kernel panic - not syncing: panic_on_warn set ... Just add another string argument to the macro invocation. Addresses https://syzkaller.appspot.com/bug?id=0627d4551fdc39bf1ef5d82cd9eef587047f7718 Link: http://lkml.kernel.org/r/d678ebe1-6f54-8090-df4c-b9affad62293@infradead.org Signed-off-by: Randy Dunlap Reported-by: Tested-by: Randy Dunlap Acked-by: Jeff Mahoney Cc: Alexander Viro Cc: Jan Kara Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/reiserfs/journal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 76108185854e..2a5c4813c47d 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -2640,7 +2640,7 @@ static int journal_init_dev(struct super_block *super, if (IS_ERR(journal->j_dev_bd)) { result = PTR_ERR(journal->j_dev_bd); journal->j_dev_bd = NULL; - reiserfs_warning(super, + reiserfs_warning(super, "sh-457", "journal_init_dev: Cannot open '%s': %i", jdev_name, result); return result; -- GitLab From 0df9b12d7790ccf259c24e8ad92abcfa8da2e0f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Apr 2018 15:35:13 -0700 Subject: [PATCH 1417/1834] resource: fix integer overflow at reallocation commit 60bb83b81169820c691fbfa33a6a4aef32aa4b0b upstream. We've got a bug report indicating a kernel panic at booting on an x86-32 system, and it turned out to be the invalid PCI resource assigned after reallocation. __find_resource() first aligns the resource start address and resets the end address with start+size-1 accordingly, then checks whether it's contained. Here the end address may overflow the integer, although resource_contains() still returns true because the function validates only start and end address. So this ends up with returning an invalid resource (start > end). There was already an attempt to cover such a problem in the commit 47ea91b4052d ("Resource: fix wrong resource window calculation"), but this case is an overseen one. This patch adds the validity check of the newly calculated resource for avoiding the integer overflow problem. Bugzilla: http://bugzilla.opensuse.org/show_bug.cgi?id=1086739 Link: http://lkml.kernel.org/r/s5hpo37d5l8.wl-tiwai@suse.de Fixes: 23c570a67448 ("resource: ability to resize an allocated resource") Signed-off-by: Takashi Iwai Reported-by: Michael Henders Tested-by: Michael Henders Reviewed-by: Andrew Morton Cc: Ram Pai Cc: Bjorn Helgaas Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- kernel/resource.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/resource.c b/kernel/resource.c index 9b5f04404152..7ee3dd1ad2af 100644 --- a/kernel/resource.c +++ b/kernel/resource.c @@ -633,7 +633,8 @@ static int __find_resource(struct resource *root, struct resource *old, alloc.start = constraint->alignf(constraint->alignf_data, &avail, size, constraint->align); alloc.end = alloc.start + size - 1; - if (resource_contains(&avail, &alloc)) { + if (alloc.start <= alloc.end && + resource_contains(&avail, &alloc)) { new->start = alloc.start; new->end = alloc.end; return 0; -- GitLab From 570ef10de6304dc20239d30a47b36c12e341d4be Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 13 Apr 2018 15:35:30 -0700 Subject: [PATCH 1418/1834] ipc/shm: fix use-after-free of shm file via remap_file_pages() commit 3f05317d9889ab75c7190dcd39491d2a97921984 upstream. syzbot reported a use-after-free of shm_file_data(file)->file->f_op in shm_get_unmapped_area(), called via sys_remap_file_pages(). Unfortunately it couldn't generate a reproducer, but I found a bug which I think caused it. When remap_file_pages() is passed a full System V shared memory segment, the memory is first unmapped, then a new map is created using the ->vm_file. Between these steps, the shm ID can be removed and reused for a new shm segment. But, shm_mmap() only checks whether the ID is currently valid before calling the underlying file's ->mmap(); it doesn't check whether it was reused. Thus it can use the wrong underlying file, one that was already freed. Fix this by making the "outer" shm file (the one that gets put in ->vm_file) hold a reference to the real shm file, and by making __shm_open() require that the file associated with the shm ID matches the one associated with the "outer" file. Taking the reference to the real shm file is needed to fully solve the problem, since otherwise sfd->file could point to a freed file, which then could be reallocated for the reused shm ID, causing the wrong shm segment to be mapped (and without the required permission checks). Commit 1ac0b6dec656 ("ipc/shm: handle removed segments gracefully in shm_mmap()") almost fixed this bug, but it didn't go far enough because it didn't consider the case where the shm ID is reused. The following program usually reproduces this bug: #include #include #include #include int main() { int is_parent = (fork() != 0); srand(getpid()); for (;;) { int id = shmget(0xF00F, 4096, IPC_CREAT|0700); if (is_parent) { void *addr = shmat(id, NULL, 0); usleep(rand() % 50); while (!syscall(__NR_remap_file_pages, addr, 4096, 0, 0, 0)); } else { usleep(rand() % 50); shmctl(id, IPC_RMID, NULL); } } } It causes the following NULL pointer dereference due to a 'struct file' being used while it's being freed. (I couldn't actually get a KASAN use-after-free splat like in the syzbot report. But I think it's possible with this bug; it would just take a more extraordinary race...) BUG: unable to handle kernel NULL pointer dereference at 0000000000000058 PGD 0 P4D 0 Oops: 0000 [#1] SMP NOPTI CPU: 9 PID: 258 Comm: syz_ipc Not tainted 4.16.0-05140-gf8cf2f16a7c95 #189 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-20171110_100015-anatol 04/01/2014 RIP: 0010:d_inode include/linux/dcache.h:519 [inline] RIP: 0010:touch_atime+0x25/0xd0 fs/inode.c:1724 [...] Call Trace: file_accessed include/linux/fs.h:2063 [inline] shmem_mmap+0x25/0x40 mm/shmem.c:2149 call_mmap include/linux/fs.h:1789 [inline] shm_mmap+0x34/0x80 ipc/shm.c:465 call_mmap include/linux/fs.h:1789 [inline] mmap_region+0x309/0x5b0 mm/mmap.c:1712 do_mmap+0x294/0x4a0 mm/mmap.c:1483 do_mmap_pgoff include/linux/mm.h:2235 [inline] SYSC_remap_file_pages mm/mmap.c:2853 [inline] SyS_remap_file_pages+0x232/0x310 mm/mmap.c:2769 do_syscall_64+0x64/0x1a0 arch/x86/entry/common.c:287 entry_SYSCALL_64_after_hwframe+0x42/0xb7 [ebiggers@google.com: add comment] Link: http://lkml.kernel.org/r/20180410192850.235835-1-ebiggers3@gmail.com Link: http://lkml.kernel.org/r/20180409043039.28915-1-ebiggers3@gmail.com Reported-by: syzbot+d11f321e7f1923157eac80aa990b446596f46439@syzkaller.appspotmail.com Fixes: c8d78c1823f4 ("mm: replace remap_file_pages() syscall with emulation") Signed-off-by: Eric Biggers Acked-by: Kirill A. Shutemov Acked-by: Davidlohr Bueso Cc: Manfred Spraul Cc: "Eric W . Biederman" Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- ipc/shm.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/ipc/shm.c b/ipc/shm.c index de93d01bfce2..b626745e771c 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -198,6 +198,12 @@ static int __shm_open(struct vm_area_struct *vma) if (IS_ERR(shp)) return PTR_ERR(shp); + if (shp->shm_file != sfd->file) { + /* ID was reused */ + shm_unlock(shp); + return -EINVAL; + } + shp->shm_atim = get_seconds(); shp->shm_lprid = task_tgid_vnr(current); shp->shm_nattch++; @@ -425,8 +431,9 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma) int ret; /* - * In case of remap_file_pages() emulation, the file can represent - * removed IPC ID: propogate shm_lock() error to caller. + * In case of remap_file_pages() emulation, the file can represent an + * IPC ID that was removed, and possibly even reused by another shm + * segment already. Propagate this case as an error to caller. */ ret =__shm_open(vma); if (ret) @@ -450,6 +457,7 @@ static int shm_release(struct inode *ino, struct file *file) struct shm_file_data *sfd = shm_file_data(file); put_ipc_ns(sfd->ns); + fput(sfd->file); shm_file_data(file) = NULL; kfree(sfd); return 0; @@ -1212,7 +1220,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, file->f_mapping = shp->shm_file->f_mapping; sfd->id = shp->shm_perm.id; sfd->ns = get_ipc_ns(ns); - sfd->file = shp->shm_file; + /* + * We need to take a reference to the real shm file to prevent the + * pointer from becoming stale in cases where the lifetime of the outer + * file extends beyond that of the shm segment. It's not usually + * possible, but it can happen during remap_file_pages() emulation as + * that unmaps the memory, then does ->mmap() via file reference only. + * We'll deny the ->mmap() if the shm segment was since removed, but to + * detect shm ID reuse we need to compare the file pointers. + */ + sfd->file = get_file(shp->shm_file); sfd->vm_ops = NULL; err = security_mmap_file(file, prot, flags); -- GitLab From 75e6359a1be39ae7cc964603a112f38b9110655a Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Fri, 13 Apr 2018 15:35:38 -0700 Subject: [PATCH 1419/1834] mm, slab: reschedule cache_reap() on the same CPU commit a9f2a846f0503e7d729f552e3ccfe2279010fe94 upstream. cache_reap() is initially scheduled in start_cpu_timer() via schedule_delayed_work_on(). But then the next iterations are scheduled via schedule_delayed_work(), i.e. using WORK_CPU_UNBOUND. Thus since commit ef557180447f ("workqueue: schedule WORK_CPU_UNBOUND work on wq_unbound_cpumask CPUs") there is no guarantee the future iterations will run on the originally intended cpu, although it's still preferred. I was able to demonstrate this with /sys/module/workqueue/parameters/debug_force_rr_cpu. IIUC, it may also happen due to migrating timers in nohz context. As a result, some cpu's would be calling cache_reap() more frequently and others never. This patch uses schedule_delayed_work_on() with the current cpu when scheduling the next iteration. Link: http://lkml.kernel.org/r/20180411070007.32225-1-vbabka@suse.cz Fixes: ef557180447f ("workqueue: schedule WORK_CPU_UNBOUND work on wq_unbound_cpumask CPUs") Signed-off-by: Vlastimil Babka Acked-by: Pekka Enberg Acked-by: Christoph Lameter Cc: Joonsoo Kim Cc: David Rientjes Cc: Tejun Heo Cc: Lai Jiangshan Cc: John Stultz Cc: Thomas Gleixner Cc: Stephen Boyd Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/slab.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/slab.c b/mm/slab.c index 1f82d16a0518..c59844dbd034 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -4096,7 +4096,8 @@ static void cache_reap(struct work_struct *w) next_reap_node(); out: /* Set up the next iteration */ - schedule_delayed_work(work, round_jiffies_relative(REAPTIMEOUT_AC)); + schedule_delayed_work_on(smp_processor_id(), work, + round_jiffies_relative(REAPTIMEOUT_AC)); } #ifdef CONFIG_SLABINFO -- GitLab From a576d7fea68be666b2a0d2104ddf936d587e65de Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 29 Mar 2018 10:48:28 -0500 Subject: [PATCH 1420/1834] usb: musb: gadget: misplaced out of bounds check commit af6f8529098aeb0e56a68671b450cf74e7a64fcd upstream. musb->endpoints[] has array size MUSB_C_NUM_EPS. We must check array bounds before accessing the array and not afterwards. Signed-off-by: Heinrich Schuchardt Signed-off-by: Bin Liu Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/musb/musb_gadget_ep0.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c index 844a309fe895..e85b9c2a4910 100644 --- a/drivers/usb/musb/musb_gadget_ep0.c +++ b/drivers/usb/musb/musb_gadget_ep0.c @@ -114,15 +114,19 @@ static int service_tx_status_request( } is_in = epnum & USB_DIR_IN; - if (is_in) { - epnum &= 0x0f; + epnum &= 0x0f; + if (epnum >= MUSB_C_NUM_EPS) { + handled = -EINVAL; + break; + } + + if (is_in) ep = &musb->endpoints[epnum].ep_in; - } else { + else ep = &musb->endpoints[epnum].ep_out; - } regs = musb->endpoints[epnum].regs; - if (epnum >= MUSB_C_NUM_EPS || !ep->desc) { + if (!ep->desc) { handled = -EINVAL; break; } -- GitLab From ba260ce74cb8acef791563a7d3f1445fe06d6805 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 26 Mar 2018 13:14:46 +0300 Subject: [PATCH 1421/1834] usb: gadget: udc: core: update usb_ep_queue() documentation commit eaa358c7790338d83bb6a31258bdc077de120414 upstream. Mention that ->complete() should never be called from within usb_ep_queue(). Signed-off-by: Felipe Balbi Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/udc/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 7d658565b20f..188961780b8a 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -248,6 +248,9 @@ EXPORT_SYMBOL_GPL(usb_ep_free_request); * arranges to poll once per interval, and the gadget driver usually will * have queued some data to transfer at that time. * + * Note that @req's ->complete() callback must never be called from + * within usb_ep_queue() as that can create deadlock situations. + * * Returns zero, or a negative error code. Endpoints that are not enabled * report errors; errors will also be * reported when the usb peripheral is disconnected. -- GitLab From 078728522c49bb3bc0413cf265d1c72b6c4bf81c Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 13 Mar 2018 16:20:05 +0100 Subject: [PATCH 1422/1834] ARM: dts: at91: at91sam9g25: fix mux-mask pinctrl property commit e8fd0adf105e132fd84545997bbef3d5edc2c9c1 upstream. There are only 19 PIOB pins having primary names PB0-PB18. Not all of them have a 'C' function. So the pinctrl property mask ends up being the same as the other SoC of the at91sam9x5 series. Reported-by: Marek Sieranski Signed-off-by: Nicolas Ferre Cc: # v3.8+ Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/at91sam9g25.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91sam9g25.dtsi b/arch/arm/boot/dts/at91sam9g25.dtsi index a7da0dd0c98f..0898213f3bb2 100644 --- a/arch/arm/boot/dts/at91sam9g25.dtsi +++ b/arch/arm/boot/dts/at91sam9g25.dtsi @@ -21,7 +21,7 @@ atmel,mux-mask = < /* A B C */ 0xffffffff 0xffe0399f 0xc000001c /* pioA */ - 0x0007ffff 0x8000fe3f 0x00000000 /* pioB */ + 0x0007ffff 0x00047e3f 0x00000000 /* pioB */ 0x80000000 0x07c0ffff 0xb83fffff /* pioC */ 0x003fffff 0x003f8000 0x00000000 /* pioD */ >; -- GitLab From 50b4737023740a76641561ae9182485b998b1d85 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 2 Mar 2018 17:07:42 +0100 Subject: [PATCH 1423/1834] ARM: dts: exynos: Fix IOMMU support for GScaler devices on Exynos5250 commit 6f4870753f29edf7dc39444246f9e39987b8b158 upstream. The proper name for the property, which assign given device to IOMMU is 'iommus', not 'iommu'. Fix incorrect name and let all GScaler devices to be properly handled when IOMMU support is enabled. Reported-by: Andrzej Hajda Signed-off-by: Marek Szyprowski Fixes: 6cbfdd73a94f ("ARM: dts: add sysmmu nodes for exynos5250") Cc: # v4.8+ Signed-off-by: Krzysztof Kozlowski Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/exynos5250.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index f7357d99b47c..64de33d067c9 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi @@ -640,7 +640,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL0>; clock-names = "gscl"; - iommu = <&sysmmu_gsc0>; + iommus = <&sysmmu_gsc0>; }; gsc_1: gsc@13e10000 { @@ -650,7 +650,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL1>; clock-names = "gscl"; - iommu = <&sysmmu_gsc1>; + iommus = <&sysmmu_gsc1>; }; gsc_2: gsc@13e20000 { @@ -660,7 +660,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL2>; clock-names = "gscl"; - iommu = <&sysmmu_gsc2>; + iommus = <&sysmmu_gsc2>; }; gsc_3: gsc@13e30000 { @@ -670,7 +670,7 @@ power-domains = <&pd_gsc>; clocks = <&clock CLK_GSCL3>; clock-names = "gscl"; - iommu = <&sysmmu_gsc3>; + iommus = <&sysmmu_gsc3>; }; hdmi: hdmi@14530000 { -- GitLab From 61ec8502373923c3bcad5e3b35155922bfc07d75 Mon Sep 17 00:00:00 2001 From: Santiago Esteban Date: Thu, 18 Jan 2018 15:38:47 +0100 Subject: [PATCH 1424/1834] ARM: dts: at91: sama5d4: fix pinctrl compatible string commit 9a06757dcc8509c162ac00488c8c82fc98e04227 upstream. The compatible string is incorrect. Add atmel,sama5d3-pinctrl since it's the appropriate compatible string. Remove the atmel,at91rm9200-pinctrl compatible string, this fallback is useless, there are too many changes. Signed-off-by: Santiago Esteban Signed-off-by: Ludovic Desroches Cc: stable@vger.kernel.org #v3.18 Signed-off-by: Alexandre Belloni Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/sama5d4.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 65e725fb5679..de0e189711f6 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1362,7 +1362,7 @@ pinctrl@fc06a000 { #address-cells = <1>; #size-cells = <1>; - compatible = "atmel,at91sam9x5-pinctrl", "atmel,at91rm9200-pinctrl", "simple-bus"; + compatible = "atmel,sama5d3-pinctrl", "atmel,at91sam9x5-pinctrl", "simple-bus"; ranges = <0xfc068000 0xfc068000 0x100 0xfc06a000 0xfc06a000 0x4000>; /* WARNING: revisit as pin spec has changed */ -- GitLab From 34023ca384a75c064544b92bad7bd347afdb3067 Mon Sep 17 00:00:00 2001 From: Maxime Chevallier Date: Fri, 2 Mar 2018 15:55:09 +0100 Subject: [PATCH 1425/1834] spi: Fix scatterlist elements size in spi_map_buf commit ce99319a182fe766be67f96338386f3ec73e321c upstream. When SPI transfers can be offloaded using DMA, the SPI core need to build a scatterlist to make sure that the buffer to be transferred is dma-able. This patch fixes the scatterlist entry size computation in the case where the maximum acceptable scatterlist entry supported by the DMA controller is less than PAGE_SIZE, when the buffer is vmalloced. For each entry, the actual size is given by the minimum between the desc_len (which is the max buffer size supported by the DMA controller) and the remaining buffer length until we cross a page boundary. Fixes: 65598c13fd66 ("spi: Fix per-page mapping of unaligned vmalloc-ed buffer") Signed-off-by: Maxime Chevallier Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 6db80635ace8..c2e85e23d538 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -743,8 +743,14 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, for (i = 0; i < sgs; i++) { if (vmalloced_buf || kmap_buf) { - min = min_t(size_t, - len, desc_len - offset_in_page(buf)); + /* + * Next scatterlist entry size is the minimum between + * the desc_len and the remaining buffer length that + * fits in a page. + */ + min = min_t(size_t, desc_len, + min_t(size_t, len, + PAGE_SIZE - offset_in_page(buf))); if (vmalloced_buf) vm_page = vmalloc_to_page(buf); else -- GitLab From 9c78aeef4272a6ded4bbf500ae611050904daaa9 Mon Sep 17 00:00:00 2001 From: Jason Andryuk Date: Wed, 28 Feb 2018 07:23:23 -0500 Subject: [PATCH 1426/1834] xen-netfront: Fix hang on device removal commit c2d2e6738a209f0f9dffa2dc8e7292fc45360d61 upstream. A toolstack may delete the vif frontend and backend xenstore entries while xen-netfront is in the removal code path. In that case, the checks for xenbus_read_driver_state would return XenbusStateUnknown, and xennet_remove would hang indefinitely. This hang prevents system shutdown. xennet_remove must be able to handle XenbusStateUnknown, and netback_changed must also wake up the wake_queue for that state as well. Fixes: 5b5971df3bc2 ("xen-netfront: remove warning when unloading module") Signed-off-by: Jason Andryuk Cc: Eduardo Otubo Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross Signed-off-by: Greg Kroah-Hartman --- drivers/net/xen-netfront.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index b09c81e882b4..1b287861e34f 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2038,7 +2038,10 @@ static void netback_changed(struct xenbus_device *dev, case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: + break; + case XenbusStateUnknown: + wake_up_all(&module_unload_q); break; case XenbusStateInitWait: @@ -2169,7 +2172,9 @@ static int xennet_remove(struct xenbus_device *dev) xenbus_switch_state(dev, XenbusStateClosing); wait_event(module_unload_q, xenbus_read_driver_state(dev->otherend) == - XenbusStateClosing); + XenbusStateClosing || + xenbus_read_driver_state(dev->otherend) == + XenbusStateUnknown); xenbus_switch_state(dev, XenbusStateClosed); wait_event(module_unload_q, -- GitLab From cddf0e1ce6c7d68e2f6e004079396a238de5f86a Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 8 Feb 2018 10:23:44 +0300 Subject: [PATCH 1427/1834] regmap: Fix reversed bounds check in regmap_raw_write() commit f00e71091ab92eba52122332586c6ecaa9cd1a56 upstream. We're supposed to be checking that "val_len" is not too large but instead we check if it is smaller than the max. The only function affected would be regmap_i2c_smbus_i2c_write() in drivers/base/regmap/regmap-i2c.c. Strangely that function has its own limit check which returns an error if (count >= I2C_SMBUS_BLOCK_MAX) so it doesn't look like it has ever been able to do anything except return an error. Fixes: c335931ed9d2 ("regmap: Add raw_write/read checks for max_raw_write/read sizes") Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/base/regmap/regmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ae63bb0875ea..a7b0fc7cb468 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1736,7 +1736,7 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL; - if (map->max_raw_write && map->max_raw_write > val_len) + if (map->max_raw_write && map->max_raw_write < val_len) return -E2BIG; map->lock(map->lock_arg); -- GitLab From e324a44b0443ec91c86b417f3a34792d1bf58f14 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 19 Mar 2018 18:01:45 +0100 Subject: [PATCH 1428/1834] ACPI / video: Add quirk to force acpi-video backlight on Samsung 670Z5E commit bbf038618a24d72e2efc19146ef421bb1e1eda1a upstream. Just like many other Samsung models, the 670Z5E needs to use the acpi-video backlight interface rather then the native one for backlight control to work, add a quirk for this. Buglink: https://bugzilla.redhat.com/show_bug.cgi?id=1557060 Cc: All applicable Signed-off-by: Hans de Goede Signed-off-by: Rafael J. Wysocki Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/video_detect.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 02ded25c82e4..cdc47375178e 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -213,6 +213,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = { "3570R/370R/470R/450R/510R/4450RV"), }, }, + { + /* https://bugzilla.redhat.com/show_bug.cgi?id=1557060 */ + .callback = video_detect_force_video, + .ident = "SAMSUNG 670Z5E", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), + DMI_MATCH(DMI_PRODUCT_NAME, "670Z5E"), + }, + }, { /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */ .callback = video_detect_force_video, -- GitLab From a59ba739a13f010eaecdd7a97e94dd94edefbfd8 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 12 Feb 2018 13:55:23 +0300 Subject: [PATCH 1429/1834] ACPI / hotplug / PCI: Check presence of slot itself in get_slot_status() commit 13d3047c81505cc0fb9bdae7810676e70523c8bf upstream. Mike Lothian reported that plugging in a USB-C device does not work properly in his Dell Alienware system. This system has an Intel Alpine Ridge Thunderbolt controller providing USB-C functionality. In these systems the USB controller (xHCI) is hotplugged whenever a device is connected to the port using ACPI-based hotplug. The ACPI description of the root port in question is as follows: Device (RP01) { Name (_ADR, 0x001C0000) Device (PXSX) { Name (_ADR, 0x02) Method (_RMV, 0, NotSerialized) { // ... } } Here _ADR 0x02 means device 0, function 2 on the bus under root port (RP01) but that seems to be incorrect because device 0 is the upstream port of the Alpine Ridge PCIe switch and it has no functions other than 0 (the bridge itself). When we get ACPI Notify() to the root port resulting from connecting a USB-C device, Linux tries to read PCI_VENDOR_ID from device 0, function 2 which of course always returns 0xffffffff because there is no such function and we never find the device. In Windows this works fine. Now, since we get ACPI Notify() to the root port and not to the PXSX device we should actually start our scan from there as well and not from the non-existent PXSX device. Fix this by checking presence of the slot itself (function 0) if we fail to do that otherwise. While there use pci_bus_read_dev_vendor_id() in get_slot_status(), which is the recommended way to read Device and Vendor IDs of devices on PCI buses. Link: https://bugzilla.kernel.org/show_bug.cgi?id=198557 Reported-by: Mike Lothian Signed-off-by: Mika Westerberg Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki Cc: Greg Kroah-Hartman Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/pci/hotplug/acpiphp_glue.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a46b585fae31..d44b55879c67 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -587,6 +587,7 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) { unsigned long long sta = 0; struct acpiphp_func *func; + u32 dvid; list_for_each_entry(func, &slot->funcs, sibling) { if (func->flags & FUNC_HAS_STA) { @@ -597,19 +598,27 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) if (ACPI_SUCCESS(status) && sta) break; } else { - u32 dvid; - - pci_bus_read_config_dword(slot->bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { + if (pci_bus_read_dev_vendor_id(slot->bus, + PCI_DEVFN(slot->device, func->function), + &dvid, 0)) { sta = ACPI_STA_ALL; break; } } } + if (!sta) { + /* + * Check for the slot itself since it may be that the + * ACPI slot is a device below PCIe upstream port so in + * that case it may not even be reachable yet. + */ + if (pci_bus_read_dev_vendor_id(slot->bus, + PCI_DEVFN(slot->device, 0), &dvid, 0)) { + sta = ACPI_STA_ALL; + } + } + return (unsigned int)sta; } -- GitLab From b3b0809ac25c3ffedc58e7f83bc01a03193e7834 Mon Sep 17 00:00:00 2001 From: "Yavuz, Tuba" Date: Fri, 23 Mar 2018 17:00:38 +0000 Subject: [PATCH 1430/1834] USB: gadget: f_midi: fixing a possible double-free in f_midi commit 7fafcfdf6377b18b2a726ea554d6e593ba44349f upstream. It looks like there is a possibility of a double-free vulnerability on an error path of the f_midi_set_alt function in the f_midi driver. If the path is feasible then free_ep_req gets called twice: req->complete = f_midi_complete; err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC); => ... usb_gadget_giveback_request => f_midi_complete (CALLBACK) (inside f_midi_complete, for various cases of status) free_ep_req(ep, req); // first kfree if (err) { ERROR(midi, "%s: couldn't enqueue request: %d\n", midi->out_ep->name, err); free_ep_req(midi->out_ep, req); // second kfree return err; } The double-free possibility was introduced with commit ad0d1a058eac ("usb: gadget: f_midi: fix leak on failed to enqueue out requests"). Found by MOXCAFE tool. Signed-off-by: Tuba Yavuz Fixes: ad0d1a058eac ("usb: gadget: f_midi: fix leak on failed to enqueue out requests") Acked-by: Felipe Balbi Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/gadget/function/f_midi.c | 3 ++- drivers/usb/gadget/u_f.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index a5719f271bf0..70ac1963b598 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -389,7 +389,8 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt) if (err) { ERROR(midi, "%s: couldn't enqueue request: %d\n", midi->out_ep->name, err); - free_ep_req(midi->out_ep, req); + if (req->buf != NULL) + free_ep_req(midi->out_ep, req); return err; } } diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h index 7d53a4773d1a..2f03334c6874 100644 --- a/drivers/usb/gadget/u_f.h +++ b/drivers/usb/gadget/u_f.h @@ -64,7 +64,9 @@ struct usb_request *alloc_ep_req(struct usb_ep *ep, size_t len); /* Frees a usb_request previously allocated by alloc_ep_req() */ static inline void free_ep_req(struct usb_ep *ep, struct usb_request *req) { + WARN_ON(req->buf == NULL); kfree(req->buf); + req->buf = NULL; usb_ep_free_request(ep, req); } -- GitLab From 73300bd1fdedcb4f0e78aab61737bda5bf7b0c24 Mon Sep 17 00:00:00 2001 From: Zhengjun Xing Date: Wed, 21 Mar 2018 13:29:42 +0800 Subject: [PATCH 1431/1834] USB:fix USB3 devices behind USB3 hubs not resuming at hibernate thaw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 64627388b50158fd24d6ad88132525b95a5ef573 upstream. USB3 hubs don't support global suspend. USB3 specification 10.10, Enhanced SuperSpeed hubs only support selective suspend and resume, they do not support global suspend/resume where the hub downstream facing ports states are not affected. When system enters hibernation it first enters freeze process where only the root hub enters suspend, usb_port_suspend() is not called for other devices, and suspend status flags are not set for them. Other devices are expected to suspend globally. Some external USB3 hubs will suspend the downstream facing port at global suspend. These devices won't be resumed at thaw as the suspend status flag is not set. A USB3 removable hard disk connected through a USB3 hub that won't resume at thaw will fail to synchronize SCSI cache, return “cmd cmplt err -71” error, and needs a 60 seconds timeout which causing system hang for 60s before the USB host reset the port for the USB3 removable hard disk to recover. Fix this by always calling usb_port_suspend() during freeze for USB3 devices. Signed-off-by: Zhengjun Xing Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/generic.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 358ca8dd784f..a5240b4d7ab9 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -208,8 +208,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg) if (!udev->parent) rc = hcd_bus_suspend(udev, msg); - /* Non-root devices don't need to do anything for FREEZE or PRETHAW */ - else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + /* + * Non-root USB2 devices don't need to do anything for FREEZE + * or PRETHAW. USB3 devices don't support global suspend and + * needs to be selectively suspended. + */ + else if ((msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW) + && (udev->speed < USB_SPEED_SUPER)) rc = 0; else rc = usb_port_suspend(udev, msg); -- GitLab From cd93ff92e1d71a2f13447ecc36e17e74bf897ef4 Mon Sep 17 00:00:00 2001 From: Thinh Nguyen Date: Mon, 19 Mar 2018 13:07:35 -0700 Subject: [PATCH 1432/1834] usb: dwc3: pci: Properly cleanup resource commit cabdf83dadfb3d83eec31e0f0638a92dbd716435 upstream. Platform device is allocated before adding resources. Make sure to properly cleanup on error case. Cc: Fixes: f1c7e7108109 ("usb: dwc3: convert to pcim_enable_device()") Signed-off-by: Thinh Nguyen Signed-off-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/usb/dwc3/dwc3-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 427291a19e6d..d6493abcf6bc 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -173,7 +173,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res)); if (ret) { dev_err(dev, "couldn't add resources to dwc3 device\n"); - return ret; + goto err; } dwc3->dev.parent = dev; -- GitLab From c4bc658f90b8e6614c6d55d211005d9c49b0c317 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 31 Mar 2018 18:13:38 -0500 Subject: [PATCH 1433/1834] smb3: Fix root directory when server returns inode number of zero commit 7ea884c77e5c97f1e0a1a422d961d27f78ca2745 upstream. Some servers return inode number zero for the root directory, which causes ls to display incorrect data (missing "." and ".."). If the server returns zero for the inode number of the root directory, fake an inode number for it. Signed-off-by: Steve French Reviewed-by: Pavel Shilovsky CC: Stable Signed-off-by: Greg Kroah-Hartman --- fs/cifs/cifsglob.h | 1 + fs/cifs/inode.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 7b496a4e650e..4ed4736b5bc6 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1412,6 +1412,7 @@ struct dfs_info3_param { #define CIFS_FATTR_NEED_REVAL 0x4 #define CIFS_FATTR_INO_COLLISION 0x8 #define CIFS_FATTR_UNKNOWN_NLINK 0x10 +#define CIFS_FATTR_FAKE_ROOT_INO 0x20 struct cifs_fattr { u32 cf_flags; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 7ab5be7944aa..24c19eb94fa3 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -701,6 +701,18 @@ cifs_get_file_info(struct file *filp) return rc; } +/* Simple function to return a 64 bit hash of string. Rarely called */ +static __u64 simple_hashstr(const char *str) +{ + const __u64 hash_mult = 1125899906842597L; /* a big enough prime */ + __u64 hash = 0; + + while (*str) + hash = (hash + (__u64) *str++) * hash_mult; + + return hash; +} + int cifs_get_inode_info(struct inode **inode, const char *full_path, FILE_ALL_INFO *data, struct super_block *sb, int xid, @@ -810,6 +822,14 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, tmprc); fattr.cf_uniqueid = iunique(sb, ROOT_I); cifs_autodisable_serverino(cifs_sb); + } else if ((fattr.cf_uniqueid == 0) && + strlen(full_path) == 0) { + /* some servers ret bad root ino ie 0 */ + cifs_dbg(FYI, "Invalid (0) inodenum\n"); + fattr.cf_flags |= + CIFS_FATTR_FAKE_ROOT_INO; + fattr.cf_uniqueid = + simple_hashstr(tcon->treeName); } } } else @@ -826,6 +846,16 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, &fattr.cf_uniqueid, data); if (tmprc) fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; + else if ((fattr.cf_uniqueid == 0) && + strlen(full_path) == 0) { + /* + * Reuse existing root inode num since + * inum zero for root causes ls of . and .. to + * not be returned + */ + cifs_dbg(FYI, "Srv ret 0 inode num for root\n"); + fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; + } } else fattr.cf_uniqueid = CIFS_I(*inode)->uniqueid; } @@ -887,6 +917,9 @@ cifs_get_inode_info(struct inode **inode, const char *full_path, } cgii_exit: + if ((*inode) && ((*inode)->i_ino == 0)) + cifs_dbg(FYI, "inode number of zero returned\n"); + kfree(buf); cifs_put_tlink(tlink); return rc; -- GitLab From b599902c30803a6b7f9818e6dc4710d4a64f55af Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Mon, 8 Jan 2018 10:41:40 +0800 Subject: [PATCH 1434/1834] HID: i2c-hid: fix size check and type usage commit ac75a041048b8c1f7418e27621ca5efda8571043 upstream. When convert char array with signed int, if the inbuf[x] is negative then upper bits will be set to 1. Fix this by using u8 instead of char. ret_size has to be at least 3, hid_input_report use it after minus 2 bytes. Cc: stable@vger.kernel.org Signed-off-by: Aaron Ma Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/i2c-hid/i2c-hid.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 7d6da9b43dab..2548c5dbdc75 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -142,10 +142,10 @@ struct i2c_hid { * register of the HID * descriptor. */ unsigned int bufsize; /* i2c buffer size */ - char *inbuf; /* Input buffer */ - char *rawbuf; /* Raw Input buffer */ - char *cmdbuf; /* Command buffer */ - char *argsbuf; /* Command arguments buffer */ + u8 *inbuf; /* Input buffer */ + u8 *rawbuf; /* Raw Input buffer */ + u8 *cmdbuf; /* Command buffer */ + u8 *argsbuf; /* Command arguments buffer */ unsigned long flags; /* device flags */ unsigned long quirks; /* Various quirks */ @@ -451,7 +451,8 @@ static int i2c_hid_hwreset(struct i2c_client *client) static void i2c_hid_get_input(struct i2c_hid *ihid) { - int ret, ret_size; + int ret; + u32 ret_size; int size = le16_to_cpu(ihid->hdesc.wMaxInputLength); if (size > ihid->bufsize) @@ -476,7 +477,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid) return; } - if (ret_size > size) { + if ((ret_size > size) || (ret_size <= 2)) { dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n", __func__, size, ret_size); return; -- GitLab From f3ccc325ffa4e966a44019fe1a679f251ff206b9 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 27 Mar 2018 01:02:33 +1000 Subject: [PATCH 1435/1834] powerpc/powernv: Handle unknown OPAL errors in opal_nvram_write() commit 741de617661794246f84a21a02fc5e327bffc9ad upstream. opal_nvram_write currently just assumes success if it encounters an error other than OPAL_BUSY or OPAL_BUSY_EVENT. Have it return -EIO on other errors instead. Fixes: 628daa8d5abf ("powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks") Cc: stable@vger.kernel.org # v3.2+ Signed-off-by: Nicholas Piggin Reviewed-by: Vasant Hegde Acked-by: Stewart Smith Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-nvram.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c index 9db4398ded5d..ba2ff06a2c98 100644 --- a/arch/powerpc/platforms/powernv/opal-nvram.c +++ b/arch/powerpc/platforms/powernv/opal-nvram.c @@ -59,6 +59,10 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) if (rc == OPAL_BUSY_EVENT) opal_poll_events(NULL); } + + if (rc) + return -EIO; + *index += count; return count; } -- GitLab From 59f404e2f21ce5d1de156a17a411b00591ea89b7 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Thu, 22 Mar 2018 20:41:46 +1000 Subject: [PATCH 1436/1834] powerpc/64: Fix smp_wmb barrier definition use use lwsync consistently commit 0bfdf598900fd62869659f360d3387ed80eb71cf upstream. asm/barrier.h is not always included after asm/synch.h, which meant it was missing __SUBARCH_HAS_LWSYNC, so in some files smp_wmb() would be eieio when it should be lwsync. kernel/time/hrtimer.c is one case. __SUBARCH_HAS_LWSYNC is only used in one place, so just fold it in to where it's used. Previously with my small simulator config, 377 instances of eieio in the tree. After this patch there are 55. Fixes: 46d075be585e ("powerpc: Optimise smp_wmb") Cc: stable@vger.kernel.org # v2.6.29+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/barrier.h | 3 ++- arch/powerpc/include/asm/synch.h | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h index c0deafc212b8..798ab37c9930 100644 --- a/arch/powerpc/include/asm/barrier.h +++ b/arch/powerpc/include/asm/barrier.h @@ -34,7 +34,8 @@ #define rmb() __asm__ __volatile__ ("sync" : : : "memory") #define wmb() __asm__ __volatile__ ("sync" : : : "memory") -#ifdef __SUBARCH_HAS_LWSYNC +/* The sub-arch has lwsync */ +#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) # define SMPWMB LWSYNC #else # define SMPWMB eieio diff --git a/arch/powerpc/include/asm/synch.h b/arch/powerpc/include/asm/synch.h index 78efe8d5d775..30f2d6d4c640 100644 --- a/arch/powerpc/include/asm/synch.h +++ b/arch/powerpc/include/asm/synch.h @@ -5,10 +5,6 @@ #include #include -#if defined(__powerpc64__) || defined(CONFIG_PPC_E500MC) -#define __SUBARCH_HAS_LWSYNC -#endif - #ifndef __ASSEMBLY__ extern unsigned int __start___lwsync_fixup, __stop___lwsync_fixup; extern void do_lwsync_fixups(unsigned long value, void *fixup_start, -- GitLab From 892314137104e42fefab454e09de6c2e8ae4fabb Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 10 Apr 2018 21:49:31 +1000 Subject: [PATCH 1437/1834] powerpc/powernv: define a standard delay for OPAL_BUSY type retry loops commit 34dd25de9fe3f60bfdb31b473bf04b28262d0896 upstream. This is the start of an effort to tidy up and standardise all the delays. Existing loops have a range of delay/sleep periods from 1ms to 20ms, and some have no delay. They all loop forever except rtc, which times out after 10 retries, and that uses 10ms delays. So use 10ms as our standard delay. The OPAL maintainer agrees 10ms is a reasonable starting point. The idea is to use the same recipe everywhere, once this is proven to work then it will be documented as an OPAL API standard. Then both firmware and OS can agree, and if a particular call needs something else, then that can be documented with reasoning. This is not the end-all of this effort, it's just a relatively easy change that fixes some existing high latency delays. There should be provision for standardising timeouts and/or interruptible loops where possible, so non-fatal firmware errors don't cause hangs. Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Cc: Nathan Chancellor Cc: Guenter Roeck Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/include/asm/opal.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index e958b7096f19..9e5e0d910b91 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -21,6 +21,9 @@ /* We calculate number of sg entries based on PAGE_SIZE */ #define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry)) +/* Default time to sleep or delay between OPAL_BUSY/OPAL_BUSY_EVENT loops */ +#define OPAL_BUSY_DELAY_MS 10 + /* /sys/firmware/opal */ extern struct kobject *opal_kobj; -- GitLab From 5aa8b5b8846e519015742c9592e50d2d13fa83de Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 10 Apr 2018 21:49:33 +1000 Subject: [PATCH 1438/1834] powerpc/powernv: Fix OPAL NVRAM driver OPAL_BUSY loops commit 3b8070335f751aac9f1526ae2e012e6f5b8b0f21 upstream. The OPAL NVRAM driver does not sleep in case it gets OPAL_BUSY or OPAL_BUSY_EVENT from firmware, which causes large scheduling latencies, and various lockup errors to trigger (again, BMC reboot can cause it). Fix this by converting it to the standard form OPAL_BUSY loop that sleeps. Fixes: 628daa8d5abf ("powerpc/powernv: Add RTC and NVRAM support plus RTAS fallbacks") Depends-on: 34dd25de9fe3 ("powerpc/powernv: define a standard delay for OPAL_BUSY type retry loops") Cc: stable@vger.kernel.org # v3.2+ Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/platforms/powernv/opal-nvram.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/opal-nvram.c b/arch/powerpc/platforms/powernv/opal-nvram.c index ba2ff06a2c98..1bceb95f422d 100644 --- a/arch/powerpc/platforms/powernv/opal-nvram.c +++ b/arch/powerpc/platforms/powernv/opal-nvram.c @@ -11,6 +11,7 @@ #define DEBUG +#include #include #include #include @@ -56,8 +57,12 @@ static ssize_t opal_nvram_write(char *buf, size_t count, loff_t *index) while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { rc = opal_write_nvram(__pa(buf), count, off); - if (rc == OPAL_BUSY_EVENT) + if (rc == OPAL_BUSY_EVENT) { + msleep(OPAL_BUSY_DELAY_MS); opal_poll_events(NULL); + } else if (rc == OPAL_BUSY) { + msleep(OPAL_BUSY_DELAY_MS); + } } if (rc) -- GitLab From 10ab7c947d4921b962c7c2a6bffa2486d0cd127d Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Sat, 3 Feb 2018 23:57:15 +0800 Subject: [PATCH 1439/1834] HID: Fix hid_report_len usage commit 3064a03b94e60388f0955fcc29f3e8a978d28f75 upstream. Follow the change of return type u32 of hid_report_len, fix all the types of variables those get the return value of hid_report_len to u32, and all other code already uses u32. Cc: stable@vger.kernel.org Signed-off-by: Aaron Ma Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-input.c | 3 ++- drivers/hid/hid-multitouch.c | 5 +++-- drivers/hid/hid-rmi.c | 4 ++-- drivers/hid/wacom_sys.c | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 40233315d5f5..5ff6dd8147b6 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1279,7 +1279,8 @@ static void hidinput_led_worker(struct work_struct *work) led_work); struct hid_field *field; struct hid_report *report; - int len, ret; + int ret; + u32 len; __u8 *buf; field = hidinput_get_led_field(hid); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 89e9032ab1e7..fba655d639af 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -315,7 +315,8 @@ static struct attribute_group mt_attribute_group = { static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hdev); - int ret, size = hid_report_len(report); + int ret; + u32 size = hid_report_len(report); u8 *buf; /* @@ -919,7 +920,7 @@ static void mt_set_input_mode(struct hid_device *hdev) struct hid_report_enum *re; struct mt_class *cls = &td->mtclass; char *buf; - int report_len; + u32 report_len; if (td->inputmode < 0) return; diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index be89bcbf6a71..276d12d4b576 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -110,8 +110,8 @@ struct rmi_data { u8 *writeReport; u8 *readReport; - int input_report_size; - int output_report_size; + u32 input_report_size; + u32 output_report_size; unsigned long flags; diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 7a4d39ce51d9..e8b90b534f08 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -351,7 +351,7 @@ static int wacom_set_device_mode(struct hid_device *hdev, u8 *rep_data; struct hid_report *r; struct hid_report_enum *re; - int length; + u32 length; int error = -ENOMEM, limit = 0; if (wacom_wac->mode_report < 0) -- GitLab From 4b43f4139e4054bc06a1f92be3018ebb6326f73f Mon Sep 17 00:00:00 2001 From: Aaron Ma Date: Mon, 8 Jan 2018 10:41:41 +0800 Subject: [PATCH 1440/1834] HID: core: Fix size as type u32 commit 6de0b13cc0b4ba10e98a9263d7a83b940720b77a upstream. When size is negative, calling memset will make segment fault. Declare the size as type u32 to keep memset safe. size in struct hid_report is unsigned, fix return type of hid_report_len to u32. Cc: stable@vger.kernel.org Signed-off-by: Aaron Ma Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hid-core.c | 10 +++++----- include/linux/hid.h | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 49406e106cee..7944a1f589eb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1370,7 +1370,7 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags) * of implement() working on 8 byte chunks */ - int len = hid_report_len(report) + 7; + u32 len = hid_report_len(report) + 7; return kmalloc(len, flags); } @@ -1435,7 +1435,7 @@ void __hid_request(struct hid_device *hid, struct hid_report *report, { char *buf; int ret; - int len; + u32 len; buf = hid_alloc_report_buf(report, GFP_KERNEL); if (!buf) @@ -1461,14 +1461,14 @@ void __hid_request(struct hid_device *hid, struct hid_report *report, } EXPORT_SYMBOL_GPL(__hid_request); -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, +int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt) { struct hid_report_enum *report_enum = hid->report_enum + type; struct hid_report *report; struct hid_driver *hdrv; unsigned int a; - int rsize, csize = size; + u32 rsize, csize = size; u8 *cdata = data; int ret = 0; @@ -1526,7 +1526,7 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event); * * This is data entry for lower layers. */ -int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt) +int hid_input_report(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt) { struct hid_report_enum *report_enum; struct hid_driver *hdrv; diff --git a/include/linux/hid.h b/include/linux/hid.h index b2ec82712baa..fab65b61d6d4 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -801,7 +801,7 @@ extern int hidinput_connect(struct hid_device *hid, unsigned int force); extern void hidinput_disconnect(struct hid_device *); int hid_set_field(struct hid_field *, unsigned, __s32); -int hid_input_report(struct hid_device *, int type, u8 *, int, int); +int hid_input_report(struct hid_device *, int type, u8 *, u32, int); int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); struct hid_field *hidinput_get_led_field(struct hid_device *hid); unsigned int hidinput_count_leds(struct hid_device *hid); @@ -1106,13 +1106,13 @@ static inline void hid_hw_wait(struct hid_device *hdev) * * @report: the report we want to know the length */ -static inline int hid_report_len(struct hid_report *report) +static inline u32 hid_report_len(struct hid_report *report) { /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */ return ((report->size - 1) >> 3) + 1 + (report->id > 0); } -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, +int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size, int interrupt); /* HID quirks API */ -- GitLab From 2e9feaf9feb84ab387ee10d8ced7d77b745b25d9 Mon Sep 17 00:00:00 2001 From: James Kelly Date: Mon, 19 Mar 2018 21:29:50 +1100 Subject: [PATCH 1441/1834] ASoC: ssm2602: Replace reg_default_raw with reg_default commit a01df75ce737951ad13a08d101306e88c3f57cb2 upstream. SSM2602 driver is broken on recent kernels (at least since 4.9). User space applications such as amixer or alsamixer get EIO when attempting to access codec controls via the relevant IOCTLs. Root cause of these failures is the regcache_hw_init function in drivers/base/regmap/regcache.c, which prevents regmap cache initalization from the reg_defaults_raw element of the regmap_config structure when registers are write only. It also disables the regmap cache entirely when all registers are write only or volatile as is the case for the SSM2602 driver. Using the reg_defaults element of the regmap_config structure rather than the reg_defaults_raw element to initalize the regmap cache avoids the logic in the regcache_hw_init function entirely. It also makes this driver consistent with other ASoC codec drivers, as this driver was the ONLY codec driver that used the reg_defaults_raw element to initalize the cache. Tested on Digilent Zybo Z7 development board which has a SSM2603 codec chip connected to a Xilinx Zynq SoC. Signed-off-by: James Kelly Signed-off-by: Mark Brown Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- sound/soc/codecs/ssm2602.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 993bde29ca1b..7693e63078b1 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c @@ -54,10 +54,17 @@ struct ssm2602_priv { * using 2 wire for device control, so we cache them instead. * There is no point in caching the reset register */ -static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { - 0x0097, 0x0097, 0x0079, 0x0079, - 0x000a, 0x0008, 0x009f, 0x000a, - 0x0000, 0x0000 +static const struct reg_default ssm2602_reg[SSM2602_CACHEREGNUM] = { + { .reg = 0x00, .def = 0x0097 }, + { .reg = 0x01, .def = 0x0097 }, + { .reg = 0x02, .def = 0x0079 }, + { .reg = 0x03, .def = 0x0079 }, + { .reg = 0x04, .def = 0x000a }, + { .reg = 0x05, .def = 0x0008 }, + { .reg = 0x06, .def = 0x009f }, + { .reg = 0x07, .def = 0x000a }, + { .reg = 0x08, .def = 0x0000 }, + { .reg = 0x09, .def = 0x0000 } }; @@ -620,8 +627,8 @@ const struct regmap_config ssm2602_regmap_config = { .volatile_reg = ssm2602_register_volatile, .cache_type = REGCACHE_RBTREE, - .reg_defaults_raw = ssm2602_reg, - .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg), + .reg_defaults = ssm2602_reg, + .num_reg_defaults = ARRAY_SIZE(ssm2602_reg), }; EXPORT_SYMBOL_GPL(ssm2602_regmap_config); -- GitLab From c9bb6fb2df18eda60e8dc125232338a76ffb7163 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 19 Dec 2017 12:44:56 +0300 Subject: [PATCH 1442/1834] thunderbolt: Resume control channel after hibernation image is created commit f2a659f7d8d5da803836583aa16df06bdf324252 upstream. The driver misses implementation of PM hook that undoes what ->freeze_noirq() does after the hibernation image is created. This means the control channel is not resumed properly and the Thunderbolt bus becomes useless in later stages of hibernation (when the image is stored or if the operation fails). Fix this by pointing ->thaw_noirq to driver nhi_resume_noirq(). This makes sure the control channel is resumed properly. Fixes: 23dd5bb49d98 ("thunderbolt: Add suspend/hibernate support") Signed-off-by: Mika Westerberg Reviewed-by: Andy Shevchenko Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/thunderbolt/nhi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index a8c20413dbda..cba6bc6ab9ed 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -628,6 +628,7 @@ static const struct dev_pm_ops nhi_pm_ops = { * we just disable hotplug, the * pci-tunnels stay alive. */ + .thaw_noirq = nhi_resume_noirq, .restore_noirq = nhi_resume_noirq, }; -- GitLab From 910d84009977441fcb5661683528f88ed1dcca93 Mon Sep 17 00:00:00 2001 From: Aniruddha Banerjee Date: Wed, 28 Mar 2018 19:12:00 +0530 Subject: [PATCH 1443/1834] irqchip/gic: Take lock when updating irq type commit aa08192a254d362a4d5317647a81de6996961aef upstream. Most MMIO GIC register accesses use a 1-hot bit scheme that avoids requiring any form of locking. This isn't true for the GICD_ICFGRn registers, which require a RMW sequence. Unfortunately, we seem to be missing a lock for these particular accesses, which could result in a race condition if changing the trigger type on any two interrupts within the same set of 16 interrupts (and thus controlled by the same CFGR register). Introduce a private lock in the GIC common comde for this particular case, making it cover both GIC implementations in one go. Cc: stable@vger.kernel.org Signed-off-by: Aniruddha Banerjee [maz: updated changelog] Signed-off-by: Marc Zyngier Signed-off-by: Greg Kroah-Hartman --- drivers/irqchip/irq-gic-common.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c index 9ae71804b5dd..1c2ca8d51a70 100644 --- a/drivers/irqchip/irq-gic-common.c +++ b/drivers/irqchip/irq-gic-common.c @@ -21,6 +21,8 @@ #include "irq-gic-common.h" +static DEFINE_RAW_SPINLOCK(irq_controller_lock); + static const struct gic_kvm_info *gic_kvm_info; const struct gic_kvm_info *gic_get_kvm_info(void) @@ -52,11 +54,13 @@ int gic_configure_irq(unsigned int irq, unsigned int type, u32 confoff = (irq / 16) * 4; u32 val, oldval; int ret = 0; + unsigned long flags; /* * Read current configuration register, and insert the config * for "irq", depending on "type". */ + raw_spin_lock_irqsave(&irq_controller_lock, flags); val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff); if (type & IRQ_TYPE_LEVEL_MASK) val &= ~confmask; @@ -64,8 +68,10 @@ int gic_configure_irq(unsigned int irq, unsigned int type, val |= confmask; /* If the current configuration is the same, then we are done */ - if (val == oldval) + if (val == oldval) { + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); return 0; + } /* * Write back the new configuration, and possibly re-enable @@ -83,6 +89,7 @@ int gic_configure_irq(unsigned int irq, unsigned int type, pr_warn("GIC: PPI%d is secure or misconfigured\n", irq - 16); } + raw_spin_unlock_irqrestore(&irq_controller_lock, flags); if (sync_access) sync_access(); -- GitLab From bb6f26a637b4da6cb752c55635baa425d803f02d Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sat, 25 Feb 2017 18:21:33 -0400 Subject: [PATCH 1444/1834] random: use a tighter cap in credit_entropy_bits_safe() commit 9f886f4d1d292442b2f22a0a33321eae821bde40 upstream. This fixes a harmless UBSAN where root could potentially end up causing an overflow while bumping the entropy_total field (which is ignored once the entropy pool has been initialized, and this generally is completed during the boot sequence). This is marginal for the stable kernel series, but it's a really trivial patch, and it fixes UBSAN warning that might cause security folks to get overly excited for no reason. Signed-off-by: Theodore Ts'o Reported-by: Chen Feng Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 0c23ced255cb..cf1b91e33a28 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -741,7 +741,7 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) static int credit_entropy_bits_safe(struct entropy_store *r, int nbits) { - const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); + const int nbits_max = r->poolinfo->poolwords * 32; if (nbits < 0) return -EINVAL; -- GitLab From 82aad4a72f154f48aacc6592779700b1bad0ae07 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 19 Feb 2018 12:22:53 -0500 Subject: [PATCH 1445/1834] jbd2: if the journal is aborted then don't allow update of the log tail commit 85e0c4e89c1b864e763c4e3bb15d0b6d501ad5d9 upstream. This updates the jbd2 superblock unnecessarily, and on an abort we shouldn't truncate the log. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/jbd2/journal.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 047c8ef620fe..542e33d29088 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -951,7 +951,7 @@ int __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) } /* - * This is a variaon of __jbd2_update_log_tail which checks for validity of + * This is a variation of __jbd2_update_log_tail which checks for validity of * provided log tail and locks j_checkpoint_mutex. So it is safe against races * with other threads updating log tail. */ @@ -1394,6 +1394,9 @@ int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, journal_superblock_t *sb = journal->j_superblock; int ret; + if (is_journal_aborted(journal)) + return -EIO; + BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n", tail_block, tail_tid); -- GitLab From a06b798c309ed8c919522c639e89613a013c13c4 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 19 Feb 2018 14:16:47 -0500 Subject: [PATCH 1446/1834] ext4: don't update checksum of new initialized bitmaps commit 044e6e3d74a3d7103a0c8a9305dfd94d64000660 upstream. When reading the inode or block allocation bitmap, if the bitmap needs to be initialized, do not update the checksum in the block group descriptor. That's because we're not set up to journal those changes. Instead, just set the verified bit on the bitmap block, so that it's not necessary to validate the checksum. When a block or inode allocation actually happens, at that point the checksum will be calculated, and update of the bg descriptor block will be properly journalled. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/balloc.c | 3 +-- fs/ext4/ialloc.c | 47 +++-------------------------------------------- 2 files changed, 4 insertions(+), 46 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e04ec868e37e..176b4b27a27a 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -242,8 +242,6 @@ static int ext4_init_block_bitmap(struct super_block *sb, */ ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), sb->s_blocksize * 8, bh->b_data); - ext4_block_bitmap_csum_set(sb, block_group, gdp, bh); - ext4_group_desc_csum_set(sb, block_group, gdp); return 0; } @@ -447,6 +445,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) err = ext4_init_block_bitmap(sb, bh, block_group, desc); set_bitmap_uptodate(bh); set_buffer_uptodate(bh); + set_buffer_verified(bh); ext4_unlock_group(sb, block_group); unlock_buffer(bh); if (err) { diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 2d94e8524839..79a9a1bddafc 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -63,44 +63,6 @@ void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap) memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); } -/* Initializes an uninitialized inode bitmap */ -static int ext4_init_inode_bitmap(struct super_block *sb, - struct buffer_head *bh, - ext4_group_t block_group, - struct ext4_group_desc *gdp) -{ - struct ext4_group_info *grp; - struct ext4_sb_info *sbi = EXT4_SB(sb); - J_ASSERT_BH(bh, buffer_locked(bh)); - - /* If checksum is bad mark all blocks and inodes use to prevent - * allocation, essentially implementing a per-group read-only flag. */ - if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { - grp = ext4_get_group_info(sb, block_group); - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - grp->bb_free); - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); - if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { - int count; - count = ext4_free_inodes_count(sb, gdp); - percpu_counter_sub(&sbi->s_freeinodes_counter, - count); - } - set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); - return -EFSBADCRC; - } - - memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); - ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, - bh->b_data); - ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh, - EXT4_INODES_PER_GROUP(sb) / 8); - ext4_group_desc_csum_set(sb, block_group, gdp); - - return 0; -} - void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate) { if (uptodate) { @@ -184,17 +146,14 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) ext4_lock_group(sb, block_group); if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { - err = ext4_init_inode_bitmap(sb, bh, block_group, desc); + memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); + ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), + sb->s_blocksize * 8, bh->b_data); set_bitmap_uptodate(bh); set_buffer_uptodate(bh); set_buffer_verified(bh); ext4_unlock_group(sb, block_group); unlock_buffer(bh); - if (err) { - ext4_error(sb, "Failed to init inode bitmap for group " - "%u: %d", block_group, err); - goto out; - } return bh; } ext4_unlock_group(sb, block_group); -- GitLab From c636feb8ffe56f1cc1fafce87a67b1020761d24d Mon Sep 17 00:00:00 2001 From: Eryu Guan Date: Thu, 22 Mar 2018 11:41:25 -0400 Subject: [PATCH 1447/1834] ext4: protect i_disksize update by i_data_sem in direct write path commit 73fdad00b208b139cf43f3163fbc0f67e4c6047c upstream. i_disksize update should be protected by i_data_sem, by either taking the lock explicitly or by using ext4_update_i_disksize() helper. But the i_disksize updates in ext4_direct_IO_write() are not protected at all, which may be racing with i_disksize updates in writeback path in delalloc buffer write path. This is found by code inspection, and I didn't hit any i_disksize corruption due to this bug. Thanks to Jan Kara for catching this bug and suggesting the fix! Reported-by: Jan Kara Suggested-by: Jan Kara Signed-off-by: Eryu Guan Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 5cccec68a0a5..6eaa864c05a9 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3396,7 +3396,6 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct ext4_inode_info *ei = EXT4_I(inode); ssize_t ret; loff_t offset = iocb->ki_pos; size_t count = iov_iter_count(iter); @@ -3420,7 +3419,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) goto out; } orphan = 1; - ei->i_disksize = inode->i_size; + ext4_update_i_disksize(inode, inode->i_size); ext4_journal_stop(handle); } @@ -3548,7 +3547,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) if (ret > 0) { loff_t end = offset + ret; if (end > inode->i_size) { - ei->i_disksize = end; + ext4_update_i_disksize(inode, end); i_size_write(inode, end); /* * We're going to return a positive `ret' -- GitLab From 6b289a7c34d72212bcd5a8ab9b6a657f2f44f0ee Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 29 Mar 2018 21:56:09 -0400 Subject: [PATCH 1448/1834] ext4: fail ext4_iget for root directory if unallocated commit 8e4b5eae5decd9dfe5a4ee369c22028f90ab4c44 upstream. If the root directory has an i_links_count of zero, then when the file system is mounted, then when ext4_fill_super() notices the problem and tries to call iput() the root directory in the error return path, ext4_evict_inode() will try to free the inode on disk, before all of the file system structures are set up, and this will result in an OOPS caused by a NULL pointer dereference. This issue has been assigned CVE-2018-1092. https://bugzilla.kernel.org/show_bug.cgi?id=199179 https://bugzilla.redhat.com/show_bug.cgi?id=1560777 Reported-by: Wen Xu Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- fs/ext4/inode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 6eaa864c05a9..340428274532 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4493,6 +4493,12 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) goto bad_inode; raw_inode = ext4_raw_inode(&iloc); + if ((ino == EXT4_ROOT_INO) && (raw_inode->i_links_count == 0)) { + EXT4_ERROR_INODE(inode, "root inode unallocated"); + ret = -EFSCORRUPTED; + goto bad_inode; + } + if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > -- GitLab From 8e455917885613ce6fdbbfb981364c983b29060d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 3 Apr 2018 15:33:01 -0700 Subject: [PATCH 1449/1834] RDMA/ucma: Don't allow setting RDMA_OPTION_IB_PATH without an RDMA device commit 8435168d50e66fa5eae01852769d20a36f9e5e83 upstream. Check to make sure that ctx->cm_id->device is set before we use it. Otherwise userspace can trigger a NULL dereference by doing RDMA_USER_CM_CMD_SET_OPTION on an ID that is not bound to a device. Cc: Reported-by: Signed-off-by: Roland Dreier Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/core/ucma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 4d732810f6fc..cb79d171d1e4 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1231,6 +1231,9 @@ static int ucma_set_ib_path(struct ucma_context *ctx, if (!optlen) return -EINVAL; + if (!ctx->cm_id->device) + return -EINVAL; + memset(&sa_path, 0, sizeof(sa_path)); ib_sa_unpack_path(path_data->path_rec, &sa_path); -- GitLab From 4b37ec8703b3131c3f8b39735046c64d33ccb921 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 1 Mar 2018 14:00:29 -0800 Subject: [PATCH 1450/1834] RDMA/rxe: Fix an out-of-bounds read commit a6544a624c3ff92a64e4aca3931fa064607bd3da upstream. This patch avoids that KASAN reports the following when the SRP initiator calls srp_post_send(): ================================================================== BUG: KASAN: stack-out-of-bounds in rxe_post_send+0x5c4/0x980 [rdma_rxe] Read of size 8 at addr ffff880066606e30 by task 02-mq/1074 CPU: 2 PID: 1074 Comm: 02-mq Not tainted 4.16.0-rc3-dbg+ #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014 Call Trace: dump_stack+0x85/0xc7 print_address_description+0x65/0x270 kasan_report+0x231/0x350 rxe_post_send+0x5c4/0x980 [rdma_rxe] srp_post_send.isra.16+0x149/0x190 [ib_srp] srp_queuecommand+0x94d/0x1670 [ib_srp] scsi_dispatch_cmd+0x1c2/0x550 [scsi_mod] scsi_queue_rq+0x843/0xa70 [scsi_mod] blk_mq_dispatch_rq_list+0x143/0xac0 blk_mq_do_dispatch_ctx+0x1c5/0x260 blk_mq_sched_dispatch_requests+0x2bf/0x2f0 __blk_mq_run_hw_queue+0xdb/0x160 __blk_mq_delay_run_hw_queue+0xba/0x100 blk_mq_run_hw_queue+0xf2/0x190 blk_mq_sched_insert_request+0x163/0x2f0 blk_execute_rq+0xb0/0x130 scsi_execute+0x14e/0x260 [scsi_mod] scsi_probe_and_add_lun+0x366/0x13d0 [scsi_mod] __scsi_scan_target+0x18a/0x810 [scsi_mod] scsi_scan_target+0x11e/0x130 [scsi_mod] srp_create_target+0x1522/0x19e0 [ib_srp] kernfs_fop_write+0x180/0x210 __vfs_write+0xb1/0x2e0 vfs_write+0xf6/0x250 SyS_write+0x99/0x110 do_syscall_64+0xee/0x2b0 entry_SYSCALL_64_after_hwframe+0x42/0xb7 The buggy address belongs to the page: page:ffffea0001998180 count:0 mapcount:0 mapping:0000000000000000 index:0x0 flags: 0x4000000000000000() raw: 4000000000000000 0000000000000000 0000000000000000 00000000ffffffff raw: dead000000000100 dead000000000200 0000000000000000 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff880066606d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 ffff880066606d80: f1 00 f2 f2 f2 f2 f2 f2 f2 00 00 f2 f2 f2 f2 f2 >ffff880066606e00: f2 00 00 00 00 00 f2 f2 f2 f3 f3 f3 f3 00 00 00 ^ ffff880066606e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ffff880066606f00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ================================================================== Fixes: 8700e3e7c485 ("Soft RoCE driver") Signed-off-by: Bart Van Assche Cc: Moni Shoua Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/sw/rxe/rxe_verbs.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 59f37f412a7f..ced416f5dffb 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -747,9 +747,8 @@ static int init_send_wqe(struct rxe_qp *qp, struct ib_send_wr *ibwr, memcpy(wqe->dma.sge, ibwr->sg_list, num_sge * sizeof(struct ib_sge)); - wqe->iova = (mask & WR_ATOMIC_MASK) ? - atomic_wr(ibwr)->remote_addr : - rdma_wr(ibwr)->remote_addr; + wqe->iova = mask & WR_ATOMIC_MASK ? atomic_wr(ibwr)->remote_addr : + mask & WR_READ_OR_WRITE_MASK ? rdma_wr(ibwr)->remote_addr : 0; wqe->mask = mask; wqe->dma.length = length; wqe->dma.resid = length; -- GitLab From dd34b663a8a63050d87da428061b07a8253fa7ac Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Apr 2018 22:41:43 +0200 Subject: [PATCH 1451/1834] ALSA: pcm: Fix UAF at PCM release via PCM timer access commit a820ccbe21e8ce8e86c39cd1d3bc8c7d1cbb949b upstream. The PCM runtime object is created and freed dynamically at PCM stream open / close time. This is tracked via substream->runtime, and it's cleared at snd_pcm_detach_substream(). The runtime object assignment is protected by PCM open_mutex, so for all PCM operations, it's safely handled. However, each PCM substream provides also an ALSA timer interface, and user-space can access to this while closing a PCM substream. This may eventually lead to a UAF, as snd_pcm_timer_resolution() tries to access the runtime while clearing it in other side. Fortunately, it's the only concurrent access from the PCM timer, and it merely reads runtime->timer_resolution field. So, we can avoid the race by reordering kfree() and wrapping the substream->runtime clearance with the corresponding timer lock. Reported-by: syzbot+8e62ff4e07aa2ce87826@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/pcm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 074363b63cc4..6bda8f6c5f84 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -1025,8 +1026,13 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) snd_free_pages((void*)runtime->control, PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); kfree(runtime->hw_constraints.rules); - kfree(runtime); + /* Avoid concurrent access to runtime via PCM timer interface */ + if (substream->timer) + spin_lock_irq(&substream->timer->lock); substream->runtime = NULL; + if (substream->timer) + spin_unlock_irq(&substream->timer->lock); + kfree(runtime); put_pid(substream->pid); substream->pid = NULL; substream->pstr->substream_opened--; -- GitLab From f4374991ddd73e1b23a62decb9548a2d599716a4 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 23 Feb 2018 14:09:24 -0800 Subject: [PATCH 1452/1834] IB/srp: Fix srp_abort() commit e68088e78d82920632eba112b968e49d588d02a2 upstream. Before commit e494f6a72839 ("[SCSI] improved eh timeout handler") it did not really matter whether or not abort handlers like srp_abort() called .scsi_done() when returning another value than SUCCESS. Since that commit however this matters. Hence only call .scsi_done() when returning SUCCESS. Signed-off-by: Bart Van Assche Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srp/ib_srp.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 84f91858b5e6..245a59bab27c 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2626,9 +2626,11 @@ static int srp_abort(struct scsi_cmnd *scmnd) ret = FAST_IO_FAIL; else ret = FAILED; - srp_free_req(ch, req, scmnd, 0); - scmnd->result = DID_ABORT << 16; - scmnd->scsi_done(scmnd); + if (ret == SUCCESS) { + srp_free_req(ch, req, scmnd, 0); + scmnd->result = DID_ABORT << 16; + scmnd->scsi_done(scmnd); + } return ret; } -- GitLab From 16757e775dd6db0fda7cf7da1eaa31d8e5a11ff1 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 12 Feb 2018 09:50:25 -0800 Subject: [PATCH 1453/1834] IB/srp: Fix completion vector assignment algorithm commit 3a148896b24adf8688dc0c59af54531931677a40 upstream. Ensure that cv_end is equal to ibdev->num_comp_vectors for the NUMA node with the highest index. This patch improves spreading of RDMA channels over completion vectors and thereby improves performance, especially on systems with only a single NUMA node. This patch drops support for the comp_vector login parameter by ignoring the value of that parameter since I have not found a good way to combine support for that parameter and automatic spreading of RDMA channels over completion vectors. Fixes: d92c0da71a35 ("IB/srp: Add multichannel support") Reported-by: Alexander Schmid Signed-off-by: Bart Van Assche Cc: Alexander Schmid Cc: stable@vger.kernel.org Signed-off-by: Jason Gunthorpe Signed-off-by: Greg Kroah-Hartman --- drivers/infiniband/ulp/srp/ib_srp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 245a59bab27c..463ea592a42a 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -3397,12 +3397,10 @@ static ssize_t srp_create_target(struct device *dev, num_online_nodes()); const int ch_end = ((node_idx + 1) * target->ch_count / num_online_nodes()); - const int cv_start = (node_idx * ibdev->num_comp_vectors / - num_online_nodes() + target->comp_vector) - % ibdev->num_comp_vectors; - const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors / - num_online_nodes() + target->comp_vector) - % ibdev->num_comp_vectors; + const int cv_start = node_idx * ibdev->num_comp_vectors / + num_online_nodes(); + const int cv_end = (node_idx + 1) * ibdev->num_comp_vectors / + num_online_nodes(); int cpu_idx = 0; for_each_online_cpu(cpu) { -- GitLab From 5d151871b1cb6338daac36e5c7c375c1f4b83ded Mon Sep 17 00:00:00 2001 From: Maxime Jayat Date: Thu, 22 Feb 2018 12:39:55 +0100 Subject: [PATCH 1454/1834] dmaengine: at_xdmac: fix rare residue corruption commit c5637476bbf9bb86c7f0413b8f4822a73d8d2d07 upstream. Despite the efforts made to correctly read the NDA and CUBC registers, the order in which the registers are read could sometimes lead to an inconsistent state. Re-using the timeline from the comments, this following timing of registers reads could lead to reading NDA with value "@desc2" and CUBC with value "MAX desc1": INITD -------- ------------ |____________________| _______________________ _______________ NDA @desc2 \/ @desc3 _______________________/\_______________ __________ ___________ _______________ CUBC 0 \/ MAX desc1 \/ MAX desc2 __________/\___________/\_______________ | | | | Events:(1)(2) (3)(4) (1) check_nda = @desc2 (2) initd = 1 (3) cur_ubc = MAX desc1 (4) cur_nda = @desc2 This is allowed by the condition ((check_nda == cur_nda) && initd), despite cur_ubc and cur_nda being in the precise state we don't want. This error leads to incorrect residue computation. Fix it by inversing the order in which CUBC and INITD are read. This makes sure that NDA and CUBC are always read together either _before_ INITD goes to 0 or _after_ it is back at 1. The case where NDA is read before INITD is at 0 and CUBC is read after INITD is back at 1 will be rejected by check_nda and cur_nda being different. Fixes: 53398f488821 ("dmaengine: at_xdmac: fix residue corruption") Cc: stable@vger.kernel.org Signed-off-by: Maxime Jayat Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/at_xdmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b7d7f2d443a1..ee7b48d5243c 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1473,10 +1473,10 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, for (retry = 0; retry < AT_XDMAC_RESIDUE_MAX_RETRIES; retry++) { check_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; rmb(); - initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); - rmb(); cur_ubc = at_xdmac_chan_read(atchan, AT_XDMAC_CUBC); rmb(); + initd = !!(at_xdmac_chan_read(atchan, AT_XDMAC_CC) & AT_XDMAC_CC_INITD); + rmb(); cur_nda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA) & 0xfffffffc; rmb(); -- GitLab From a1ada79437d7120050c38db6501ac1de62474da9 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 6 Apr 2018 16:37:21 -0700 Subject: [PATCH 1455/1834] libnvdimm, namespace: use a safe lookup for dimm device name commit 4f8672201b7e7ed4f5f6c3cf6dcd080648580582 upstream. The following NULL dereference results from incorrectly assuming that ndd is valid in this print: struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); /* * Give up if we don't find an instance of a uuid at each * position (from 0 to nd_region->ndr_mappings - 1), or if we * find a dimm with two instances of the same uuid. */ dev_err(&nd_region->dev, "%s missing label for %pUb\n", dev_name(ndd->dev), nd_label->uuid); BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 IP: nd_region_register_namespaces+0xd67/0x13c0 [libnvdimm] PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 43 PID: 673 Comm: kworker/u609:10 Not tainted 4.16.0-rc4+ #1 [..] RIP: 0010:nd_region_register_namespaces+0xd67/0x13c0 [libnvdimm] [..] Call Trace: ? devres_add+0x2f/0x40 ? devm_kmalloc+0x52/0x60 ? nd_region_activate+0x9c/0x320 [libnvdimm] nd_region_probe+0x94/0x260 [libnvdimm] ? kernfs_add_one+0xe4/0x130 nvdimm_bus_probe+0x63/0x100 [libnvdimm] Switch to using the nvdimm device directly. Fixes: 0e3b0d123c8f ("libnvdimm, namespace: allow multiple pmem...") Cc: Reported-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/nvdimm/namespace_devs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index b8fb1ef1fc15..74257ac92490 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1747,7 +1747,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, } if (i < nd_region->ndr_mappings) { - struct nvdimm_drvdata *ndd = to_ndd(&nd_region->mapping[i]); + struct nvdimm *nvdimm = nd_region->mapping[i].nvdimm; /* * Give up if we don't find an instance of a uuid at each @@ -1755,7 +1755,7 @@ struct device *create_namespace_pmem(struct nd_region *nd_region, * find a dimm with two instances of the same uuid. */ dev_err(&nd_region->dev, "%s missing label for %pUb\n", - dev_name(ndd->dev), nd_label->uuid); + nvdimm_name(nvdimm), nd_label->uuid); rc = -EINVAL; goto err; } -- GitLab From 1c72e231eb06499e376842defa03e1e295d63ba0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 2 Apr 2018 16:40:04 -0700 Subject: [PATCH 1456/1834] nfit, address-range-scrub: fix scrub in-progress reporting commit 78727137fdf49edf9f731bde79d7189067b4047a upstream. There is a small window whereby ARS scan requests can schedule work that userspace will miss when polling scrub_show. Hold the init_mutex lock over calls to report the status to close this potential escape. Also, make sure that requests to cancel the ARS workqueue are treated as an idle event. Cc: Cc: Vishal Verma Fixes: 37b137ff8c83 ("nfit, libnvdimm: allow an ARS scrub...") Reviewed-by: Dave Jiang Signed-off-by: Dan Williams Signed-off-by: Greg Kroah-Hartman --- drivers/acpi/nfit/core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 37032545c58e..3874eec972cd 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -967,8 +967,11 @@ static ssize_t scrub_show(struct device *dev, if (nd_desc) { struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); + mutex_lock(&acpi_desc->init_mutex); rc = sprintf(buf, "%d%s", acpi_desc->scrub_count, - (work_busy(&acpi_desc->work)) ? "+\n" : "\n"); + work_busy(&acpi_desc->work) + && !acpi_desc->cancel ? "+\n" : "\n"); + mutex_unlock(&acpi_desc->init_mutex); } device_unlock(dev); return rc; -- GitLab From 8280752089fb63d8c8043878a2bb68ba6854a54b Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Thu, 14 Dec 2017 03:23:37 +0100 Subject: [PATCH 1457/1834] um: Compile with modern headers commit 530ba6c7cb3c22435a4d26de47037bb6f86a5329 upstream. Recent libcs have gotten a bit more strict, so we actually need to include the right headers and use the right types. This enables UML to compile again. Signed-off-by: Jason A. Donenfeld Cc: stable@vger.kernel.org Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- arch/um/os-Linux/file.c | 1 + arch/um/os-Linux/signal.c | 1 + arch/x86/um/stub_segv.c | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index 2db18cbbb0ea..c0197097c86e 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index a86d7cc2c2d8..fa29e92a16d1 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -16,6 +16,7 @@ #include #include #include +#include void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = { [SIGTRAP] = relay_signal, diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c index 1518d2805ae8..41780110252e 100644 --- a/arch/x86/um/stub_segv.c +++ b/arch/x86/um/stub_segv.c @@ -6,6 +6,7 @@ #include #include #include +#include void __attribute__ ((__section__ (".__syscall_stub"))) stub_segv_handler(int sig, siginfo_t *info, void *p) -- GitLab From 2413ed888ab4c43311e5a16df3abdea2ab2df983 Mon Sep 17 00:00:00 2001 From: Krzysztof Mazur Date: Wed, 15 Nov 2017 11:12:39 +0100 Subject: [PATCH 1458/1834] um: Use POSIX ucontext_t instead of struct ucontext commit 4d1a535b8ec5e74b42dfd9dc809142653b2597f6 upstream. glibc 2.26 removed the 'struct ucontext' to "improve" POSIX compliance and break programs, including User Mode Linux. Fix User Mode Linux by using POSIX ucontext_t. This fixes: arch/um/os-Linux/signal.c: In function 'hard_handler': arch/um/os-Linux/signal.c:163:22: error: dereferencing pointer to incomplete type 'struct ucontext' mcontext_t *mc = &uc->uc_mcontext; arch/x86/um/stub_segv.c: In function 'stub_segv_handler': arch/x86/um/stub_segv.c:16:13: error: dereferencing pointer to incomplete type 'struct ucontext' &uc->uc_mcontext); Cc: stable@vger.kernel.org Signed-off-by: Krzysztof Mazur Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- arch/um/os-Linux/signal.c | 2 +- arch/x86/um/stub_segv.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c index fa29e92a16d1..bf0acb8aad8b 100644 --- a/arch/um/os-Linux/signal.c +++ b/arch/um/os-Linux/signal.c @@ -160,7 +160,7 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = { static void hard_handler(int sig, siginfo_t *si, void *p) { - struct ucontext *uc = p; + ucontext_t *uc = p; mcontext_t *mc = &uc->uc_mcontext; unsigned long pending = 1UL << sig; diff --git a/arch/x86/um/stub_segv.c b/arch/x86/um/stub_segv.c index 41780110252e..27361cbb7ca9 100644 --- a/arch/x86/um/stub_segv.c +++ b/arch/x86/um/stub_segv.c @@ -11,7 +11,7 @@ void __attribute__ ((__section__ (".__syscall_stub"))) stub_segv_handler(int sig, siginfo_t *info, void *p) { - struct ucontext *uc = p; + ucontext_t *uc = p; GET_FAULTINFO_FROM_MC(*((struct faultinfo *) STUB_DATA), &uc->uc_mcontext); -- GitLab From 94911a0cded960b5e85f9ef33e9861007e84cd16 Mon Sep 17 00:00:00 2001 From: Lu Baolu Date: Sat, 24 Feb 2018 13:42:27 +0800 Subject: [PATCH 1459/1834] iommu/vt-d: Fix a potential memory leak commit bbe4b3af9d9e3172fb9aa1f8dcdfaedcb381fc64 upstream. A memory block was allocated in intel_svm_bind_mm() but never freed in a failure path. This patch fixes this by free it to avoid memory leakage. Cc: Ashok Raj Cc: Jacob Pan Cc: # v4.4+ Signed-off-by: Lu Baolu Fixes: 2f26e0a9c9860 ('iommu/vt-d: Add basic SVM PASID support') Signed-off-by: Joerg Roedel Signed-off-by: Greg Kroah-Hartman --- drivers/iommu/intel-svm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index 3a1c40684213..f846f0140a9d 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -389,6 +389,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ pasid_max - 1, GFP_KERNEL); if (ret < 0) { kfree(svm); + kfree(sdev); goto out; } svm->pasid = ret; -- GitLab From 4685f789b234f7e5e19f45b430becf1a723ce1d6 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Wed, 28 Mar 2018 18:00:43 -0300 Subject: [PATCH 1460/1834] mmc: jz4740: Fix race condition in IRQ mask update commit a04f0017c22453613d5f423326b190c61e3b4f98 upstream. A spinlock is held while updating the internal copy of the IRQ mask, but not while writing it to the actual IMASK register. After the lock is released, an IRQ can occur before the IMASK register is written. If handling this IRQ causes the mask to be changed, when the handler returns back to the middle of the first mask update, a stale value will be written to the mask register. If this causes an IRQ to become unmasked that cannot have its status cleared by writing a 1 to it in the IREG register, e.g. the SDIO IRQ, then we can end up stuck with the same IRQ repeatedly being fired but not handled. Normally the MMC IRQ handler attempts to clear any unexpected IRQs by writing IREG, but for those that cannot be cleared in this way then the IRQ will just repeatedly fire. This was resulting in lockups after a while of using Wi-Fi on the CI20 (GitHub issue #19). Resolve by holding the spinlock until after the IMASK register has been updated. Cc: stable@vger.kernel.org Link: https://github.com/MIPS/CI20_linux/issues/19 Fixes: 61bfbdb85687 ("MMC: Add support for the controller on JZ4740 SoCs.") Tested-by: Mathieu Malaterre Signed-off-by: Alex Smith Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/jz4740_mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/jz4740_mmc.c b/drivers/mmc/host/jz4740_mmc.c index 684087db170b..1752007397f9 100644 --- a/drivers/mmc/host/jz4740_mmc.c +++ b/drivers/mmc/host/jz4740_mmc.c @@ -368,9 +368,9 @@ static void jz4740_mmc_set_irq_enabled(struct jz4740_mmc_host *host, host->irq_mask &= ~irq; else host->irq_mask |= irq; - spin_unlock_irqrestore(&host->lock, flags); writew(host->irq_mask, host->base + JZ_REG_MMC_IMASK); + spin_unlock_irqrestore(&host->lock, flags); } static void jz4740_mmc_clock_enable(struct jz4740_mmc_host *host, -- GitLab From 1b22bdc3a303d26329abf3abbb441f97cfaecc3b Mon Sep 17 00:00:00 2001 From: Ralph Sennhauser Date: Wed, 24 May 2017 16:58:52 +0200 Subject: [PATCH 1461/1834] clk: mvebu: armada-38x: add support for 1866MHz variants commit 9593f4f56cf5d1c443f66660a0c7f01de38f979d upstream. The Linksys WRT3200ACM CPU is clocked at 1866MHz. Add 1866MHz to the list of supported CPU frequencies. Also update multiplier and divisor for the l2clk and ddrclk. Noticed by the following warning: [ 0.000000] Selected CPU frequency (16) unsupported Signed-off-by: Ralph Sennhauser Reviewed-by: Gregory CLEMENT Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/mvebu/armada-38x.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c index 8bccf4ecdab6..394aa6f03f01 100644 --- a/drivers/clk/mvebu/armada-38x.c +++ b/drivers/clk/mvebu/armada-38x.c @@ -49,7 +49,8 @@ static const u32 armada_38x_cpu_frequencies[] __initconst = { 0, 0, 0, 0, 1066 * 1000 * 1000, 0, 0, 0, 1332 * 1000 * 1000, 0, 0, 0, - 1600 * 1000 * 1000, + 1600 * 1000 * 1000, 0, 0, 0, + 1866 * 1000 * 1000, }; static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) @@ -79,7 +80,7 @@ static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, @@ -90,7 +91,7 @@ static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {0, 1}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, -- GitLab From b2c89d89eefa43ab6dbfd09b3dc18f14125877f6 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Tue, 13 Mar 2018 16:27:02 +0100 Subject: [PATCH 1462/1834] clk: mvebu: armada-38x: add support for missing clocks commit 6a4a4595804548e173f0763a0e7274a3521c59a9 upstream. Clearfog boards can come with a CPU clocked at 1600MHz (commercial) or 1333MHz (industrial). They have also some dip-switches to select a different clock (666, 800, 1066, 1200). The funny thing is that the recovery button is on the MPP34 fq selector. So, when booting an industrial board with this button down, the frequency 666MHz is selected (and the kernel didn't boot). This patch add all the missing clocks. The only mode I didn't test is 2GHz (uboot found 4294MHz instead :/ ). Fixes: 0e85aeced4d6 ("clk: mvebu: add clock support for Armada 380/385") Cc: # 3.16.x: 9593f4f56cf5: clk: mvebu: armada-38x: add support for 1866MHz variants Cc: # 3.16.x Signed-off-by: Richard Genoud Acked-by: Gregory CLEMENT Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/mvebu/armada-38x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/clk/mvebu/armada-38x.c b/drivers/clk/mvebu/armada-38x.c index 394aa6f03f01..9ff4ea63932d 100644 --- a/drivers/clk/mvebu/armada-38x.c +++ b/drivers/clk/mvebu/armada-38x.c @@ -46,11 +46,11 @@ static u32 __init armada_38x_get_tclk_freq(void __iomem *sar) } static const u32 armada_38x_cpu_frequencies[] __initconst = { - 0, 0, 0, 0, - 1066 * 1000 * 1000, 0, 0, 0, + 666 * 1000 * 1000, 0, 800 * 1000 * 1000, 0, + 1066 * 1000 * 1000, 0, 1200 * 1000 * 1000, 0, 1332 * 1000 * 1000, 0, 0, 0, 1600 * 1000 * 1000, 0, 0, 0, - 1866 * 1000 * 1000, + 1866 * 1000 * 1000, 0, 0, 2000 * 1000 * 1000, }; static u32 __init armada_38x_get_cpu_freq(void __iomem *sar) @@ -76,11 +76,11 @@ static const struct coreclk_ratio armada_38x_coreclk_ratios[] __initconst = { }; static const int armada_38x_cpu_l2_ratios[32][2] __initconst = { - {0, 1}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, + {1, 2}, {0, 1}, {1, 2}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, @@ -91,7 +91,7 @@ static const int armada_38x_cpu_ddr_ratios[32][2] __initconst = { {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, {1, 2}, {0, 1}, {0, 1}, {0, 1}, - {1, 2}, {0, 1}, {0, 1}, {0, 1}, + {1, 2}, {0, 1}, {0, 1}, {7, 15}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, -- GitLab From 5971ee251010e1ce4969cded71800ce993a36a33 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Feb 2018 16:27:47 +0100 Subject: [PATCH 1463/1834] clk: fix false-positive Wmaybe-uninitialized warning commit ce33f284935e08229046b30635e6aadcbab02b53 upstream. When we build this driver with on x86-32, gcc produces a false-positive warning: drivers/clk/renesas/clk-sh73a0.c: In function 'sh73a0_cpg_clocks_init': drivers/clk/renesas/clk-sh73a0.c:155:10: error: 'parent_name' may be used uninitialized in this function [-Werror=maybe-uninitialized] return clk_register_fixed_factor(NULL, name, parent_name, 0, We can work around that warning by adding a fake initialization, I tried and failed to come up with any better workaround. This is currently one of few remaining warnings for a 4.14.y randconfig build, so it would be good to also have it backported at least to that version. Older versions have more randconfig warnings, so we might not care. I had not noticed this earlier, because one patch in my randconfig test tree removes the '-ffreestanding' option on x86-32, and that avoids the warning. The -ffreestanding flag was originally global but moved into arch/i386 by Andi Kleen in commit 6edfba1b33c7 ("[PATCH] x86_64: Don't define string functions to builtin") as a 'temporary workaround'. Like many temporary hacks, this turned out to be rather long-lived, from all I can tell we still need a simple fix to asm/string_32.h before it can be removed, but I'm not sure about how to best do that. Cc: stable@vger.kernel.org Cc: Andi Kleen Signed-off-by: Arnd Bergmann Acked-by: Geert Uytterhoeven Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/renesas/clk-sh73a0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/clk/renesas/clk-sh73a0.c b/drivers/clk/renesas/clk-sh73a0.c index eea38f6ea77e..3892346c4fcc 100644 --- a/drivers/clk/renesas/clk-sh73a0.c +++ b/drivers/clk/renesas/clk-sh73a0.c @@ -46,7 +46,7 @@ struct div4_clk { unsigned int shift; }; -static struct div4_clk div4_clks[] = { +static const struct div4_clk div4_clks[] = { { "zg", "pll0", CPG_FRQCRA, 16 }, { "m3", "pll1", CPG_FRQCRA, 12 }, { "b", "pll1", CPG_FRQCRA, 8 }, @@ -79,7 +79,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, { const struct clk_div_table *table = NULL; unsigned int shift, reg, width; - const char *parent_name; + const char *parent_name = NULL; unsigned int mult = 1; unsigned int div = 1; @@ -135,7 +135,7 @@ sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg, shift = 24; width = 5; } else { - struct div4_clk *c; + const struct div4_clk *c; for (c = div4_clks; c->name; c++) { if (!strcmp(name, c->name)) { -- GitLab From 6af2423153c430055c39947550ca341d75d0120f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 22 Mar 2018 10:11:30 +0100 Subject: [PATCH 1464/1834] clk: bcm2835: De-assert/assert PLL reset signal when appropriate commit 753872373b599384ac7df809aa61ea12d1c4d5d1 upstream. In order to enable a PLL, not only the PLL has to be powered up and locked, but you also have to de-assert the reset signal. The last part was missing. Add it so PLLs that were not enabled by the FW/bootloader can be enabled from Linux. Fixes: 41691b8862e2 ("clk: bcm2835: Add support for programming the audio domain clocks") Cc: Signed-off-by: Boris Brezillon Reviewed-by: Eric Anholt Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/clk/bcm/clk-bcm2835.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index abdc149941e2..73aab6e984cd 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -545,9 +545,7 @@ static void bcm2835_pll_off(struct clk_hw *hw) const struct bcm2835_pll_data *data = pll->data; spin_lock(&cprman->regs_lock); - cprman_write(cprman, data->cm_ctrl_reg, - cprman_read(cprman, data->cm_ctrl_reg) | - CM_PLL_ANARST); + cprman_write(cprman, data->cm_ctrl_reg, CM_PLL_ANARST); cprman_write(cprman, data->a2w_ctrl_reg, cprman_read(cprman, data->a2w_ctrl_reg) | A2W_PLL_CTRL_PWRDN); @@ -583,6 +581,10 @@ static int bcm2835_pll_on(struct clk_hw *hw) cpu_relax(); } + cprman_write(cprman, data->a2w_ctrl_reg, + cprman_read(cprman, data->a2w_ctrl_reg) | + A2W_PLL_CTRL_PRST_DISABLE); + return 0; } -- GitLab From f6ed0ff4c7de070c630eac654627ce5a402712db Mon Sep 17 00:00:00 2001 From: Ryo Kodama Date: Fri, 9 Mar 2018 20:24:21 +0900 Subject: [PATCH 1465/1834] pwm: rcar: Fix a condition to prevent mismatch value setting to duty commit 6225f9c64b40bc8a22503e9cda70f55d7a9dd3c6 upstream. This patch fixes an issue that is possible to set mismatch value to duty for R-Car PWM if we input the following commands: # cd /sys/class/pwm// # echo 0 > export # cd pwm0 # echo 30 > period # echo 30 > duty_cycle # echo 0 > duty_cycle # cat duty_cycle 0 # echo 1 > enable --> Then, the actual duty_cycle is 30, not 0. So, this patch adds a condition into rcar_pwm_config() to fix this issue. Signed-off-by: Ryo Kodama [shimoda: revise the commit log and add Fixes and Cc tags] Fixes: ed6c1476bf7f ("pwm: Add support for R-Car PWM Timer") Cc: Cc: # v4.4+ Signed-off-by: Yoshihiro Shimoda Signed-off-by: Thierry Reding Signed-off-by: Greg Kroah-Hartman --- drivers/pwm/pwm-rcar.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c index 1c85ecc9e7ac..0fcf94ffad32 100644 --- a/drivers/pwm/pwm-rcar.c +++ b/drivers/pwm/pwm-rcar.c @@ -156,8 +156,12 @@ static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, if (div < 0) return div; - /* Let the core driver set pwm->period if disabled and duty_ns == 0 */ - if (!pwm_is_enabled(pwm) && !duty_ns) + /* + * Let the core driver set pwm->period if disabled and duty_ns == 0. + * But, this driver should prevent to set the new duty_ns if current + * duty_cycle is not set + */ + if (!pwm_is_enabled(pwm) && !duty_ns && !pwm->state.duty_cycle) return 0; rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR); -- GitLab From a84a584c08783919a0e138e1e15ee2c45cdc0751 Mon Sep 17 00:00:00 2001 From: Mikhail Lappo Date: Fri, 2 Feb 2018 16:17:46 -0200 Subject: [PATCH 1466/1834] thermal: imx: Fix race condition in imx_thermal_probe() commit cf1ba1d73a33944d8c1a75370a35434bf146b8a7 upstream. When device boots with T > T_trip_1 and requests interrupt, the race condition takes place. The interrupt comes before THERMAL_DEVICE_ENABLED is set. This leads to an attempt to reading sensor value from irq and disabling the sensor, based on the data->mode field, which expected to be THERMAL_DEVICE_ENABLED, but still stays as THERMAL_DEVICE_DISABLED. Afher this issue sensor is never re-enabled, as the driver state is wrong. Fix this problem by setting the 'data' members prior to requesting the interrupts. Fixes: 37713a1e8e4c ("thermal: imx: implement thermal alarm interrupt handling") Cc: Signed-off-by: Mikhail Lappo Signed-off-by: Fabio Estevam Reviewed-by: Philipp Zabel Acked-by: Dong Aisheng Signed-off-by: Zhang Rui Signed-off-by: Greg Kroah-Hartman --- drivers/thermal/imx_thermal.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 06912f0602b7..b7cb49afa056 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -587,6 +587,9 @@ static int imx_thermal_probe(struct platform_device *pdev) regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); + data->irq_enabled = true; + data->mode = THERMAL_DEVICE_ENABLED; + ret = devm_request_threaded_irq(&pdev->dev, data->irq, imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread, 0, "imx_thermal", data); @@ -598,9 +601,6 @@ static int imx_thermal_probe(struct platform_device *pdev) return ret; } - data->irq_enabled = true; - data->mode = THERMAL_DEVICE_ENABLED; - return 0; } -- GitLab From e58d3bccad82019ec63a628dd52756c298bd2be1 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Thu, 1 Mar 2018 11:27:50 +0800 Subject: [PATCH 1467/1834] dt-bindings: clock: mediatek: add binding for fixed-factor clock axisel_d4 commit 55a5fcafe3a94e8a0777bb993d09107d362258d2 upstream. Just add binding for a fixed-factor clock axisel_d4, which would be referenced by PWM devices on MT7623 or MT2701 SoC. Cc: stable@vger.kernel.org Fixes: 1de9b21633d6 ("clk: mediatek: Add dt-bindings for MT2701 clocks") Signed-off-by: Sean Wang Reviewed-by: Rob Herring Cc: Mark Rutland Cc: devicetree@vger.kernel.org Signed-off-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- include/dt-bindings/clock/mt2701-clk.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/dt-bindings/clock/mt2701-clk.h b/include/dt-bindings/clock/mt2701-clk.h index 2062c67e2e51..a72db8d23ed6 100644 --- a/include/dt-bindings/clock/mt2701-clk.h +++ b/include/dt-bindings/clock/mt2701-clk.h @@ -176,7 +176,8 @@ #define CLK_TOP_AUD_EXT1 156 #define CLK_TOP_AUD_EXT2 157 #define CLK_TOP_NFI1X_PAD 158 -#define CLK_TOP_NR 159 +#define CLK_TOP_AXISEL_D4 159 +#define CLK_TOP_NR 160 /* APMIXEDSYS */ -- GitLab From 4076d92cc204fde02b07ca3a399c89d217c9ff0f Mon Sep 17 00:00:00 2001 From: Igor Pylypiv Date: Tue, 6 Mar 2018 23:47:25 -0800 Subject: [PATCH 1468/1834] watchdog: f71808e_wdt: Fix WD_EN register read commit 977f6f68331f94bb72ad84ee96b7b87ce737d89d upstream. F71808FG_FLAG_WD_EN defines bit position, not a bitmask Signed-off-by: Igor Pylypiv Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/watchdog/f71808e_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 8658dba21768..e682bf046e50 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c @@ -496,7 +496,7 @@ static bool watchdog_is_running(void) is_running = (superio_inb(watchdog.sioaddr, SIO_REG_ENABLE) & BIT(0)) && (superio_inb(watchdog.sioaddr, F71808FG_REG_WDT_CONF) - & F71808FG_FLAG_WD_EN); + & BIT(F71808FG_FLAG_WD_EN)); superio_exit(watchdog.sioaddr); -- GitLab From 502b50e87038e63011dbe83f210292b1c505b6c9 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 2 Oct 2017 12:39:10 -0600 Subject: [PATCH 1469/1834] vfio/pci: Virtualize Maximum Read Request Size commit cf0d53ba4947aad6e471491d5b20a567cbe92e56 upstream. MRRS defines the maximum read request size a device is allowed to make. Drivers will often increase this to allow more data transfer with a single request. Completions to this request are bound by the MPS setting for the bus. Aside from device quirks (none known), it doesn't seem to make sense to set an MRRS value less than MPS, yet this is a likely scenario given that user drivers do not have a system-wide view of the PCI topology. Virtualize MRRS such that the user can set MRRS >= MPS, but use MPS as the floor value that we'll write to hardware. Signed-off-by: Alex Williamson Signed-off-by: Greg Kroah-Hartman --- drivers/vfio/pci/vfio_pci_config.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 9f1ec4392209..7b8a957b008d 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -810,6 +810,7 @@ static int vfio_exp_config_write(struct vfio_pci_device *vdev, int pos, { __le16 *ctrl = (__le16 *)(vdev->vconfig + pos - offset + PCI_EXP_DEVCTL); + int readrq = le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ; count = vfio_default_config_write(vdev, pos, count, perm, offset, val); if (count < 0) @@ -835,6 +836,27 @@ static int vfio_exp_config_write(struct vfio_pci_device *vdev, int pos, pci_try_reset_function(vdev->pdev); } + /* + * MPS is virtualized to the user, writes do not change the physical + * register since determining a proper MPS value requires a system wide + * device view. The MRRS is largely independent of MPS, but since the + * user does not have that system-wide view, they might set a safe, but + * inefficiently low value. Here we allow writes through to hardware, + * but we set the floor to the physical device MPS setting, so that + * we can at least use full TLPs, as defined by the MPS value. + * + * NB, if any devices actually depend on an artificially low MRRS + * setting, this will need to be revisited, perhaps with a quirk + * though pcie_set_readrq(). + */ + if (readrq != (le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ)) { + readrq = 128 << + ((le16_to_cpu(*ctrl) & PCI_EXP_DEVCTL_READRQ) >> 12); + readrq = max(readrq, pcie_get_mps(vdev->pdev)); + + pcie_set_readrq(vdev->pdev, readrq); + } + return count; } @@ -853,11 +875,12 @@ static int __init init_pci_cap_exp_perm(struct perm_bits *perm) * Allow writes to device control fields, except devctl_phantom, * which could confuse IOMMU, MPS, which can break communication * with other physical devices, and the ARI bit in devctl2, which - * is set at probe time. FLR gets virtualized via our writefn. + * is set at probe time. FLR and MRRS get virtualized via our + * writefn. */ p_setw(perm, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD, - ~PCI_EXP_DEVCTL_PHANTOM); + PCI_EXP_DEVCTL_BCR_FLR | PCI_EXP_DEVCTL_PAYLOAD | + PCI_EXP_DEVCTL_READRQ, ~PCI_EXP_DEVCTL_PHANTOM); p_setw(perm, PCI_EXP_DEVCTL2, NO_VIRT, ~PCI_EXP_DEVCTL2_ARI); return 0; } -- GitLab From 8ede8ba723630f9200f72f5cb63900a42b5799f8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 9 Jan 2018 08:51:02 +0100 Subject: [PATCH 1470/1834] ALSA: pcm: Use ERESTARTSYS instead of EINTR in OSS emulation commit c64ed5dd9feba193c76eb460b451225ac2a0d87b upstream. Fix the last standing EINTR in the whole subsystem. Use more correct ERESTARTSYS for pending signals. Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index fa8741afadf5..f0d2c85e0975 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -853,7 +853,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, if (!(mutex_trylock(&runtime->oss.params_lock))) return -EAGAIN; } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -EINTR; + return -ERESTARTSYS; sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); -- GitLab From 159a13647f3fafa26809b939bd9a5f0a54c87118 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 22 Mar 2018 18:10:14 +0100 Subject: [PATCH 1471/1834] ALSA: pcm: Avoid potential races between OSS ioctls and read/write commit 02a5d6925cd34c3b774bdb8eefb057c40a30e870 upstream. Although we apply the params_lock mutex to the whole read and write operations as well as snd_pcm_oss_change_params(), we may still face some races. First off, the params_lock is taken inside the read and write loop. This is intentional for avoiding the too long locking, but it allows the in-between parameter change, which might lead to invalid pointers. We check the readiness of the stream and set up via snd_pcm_oss_make_ready() at the beginning of read and write, but it's called only once, by assuming that it remains ready in the rest. Second, many ioctls that may change the actual parameters (i.e. setting runtime->oss.params=1) aren't protected, hence they can be processed in a half-baked state. This patch is an attempt to plug these holes. The stream readiness check is moved inside the read/write inner loop, so that the stream is always set up in a proper state before further processing. Also, each ioctl that may change the parameter is wrapped with the params_lock for avoiding the races. The issues were triggered by syzkaller in a few different scenarios, particularly the one below appearing as GPF in loopback_pos_update. Reported-by: syzbot+c4227aec125487ec3efa@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 134 +++++++++++++++++++++++++++++++-------- 1 file changed, 106 insertions(+), 28 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index f0d2c85e0975..bf5f3f1b6824 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -834,8 +834,8 @@ static int choose_rate(struct snd_pcm_substream *substream, return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); } -static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, - bool trylock) +/* call with params_lock held */ +static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_pcm_hw_params *params, *sparams; @@ -849,11 +849,8 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, struct snd_mask sformat_mask; struct snd_mask mask; - if (trylock) { - if (!(mutex_trylock(&runtime->oss.params_lock))) - return -EAGAIN; - } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + if (!runtime->oss.params) + return 0; sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); @@ -1079,6 +1076,23 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, kfree(sw_params); kfree(params); kfree(sparams); + return err; +} + +/* this one takes the lock by itself */ +static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream, + bool trylock) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + int err; + + if (trylock) { + if (!(mutex_trylock(&runtime->oss.params_lock))) + return -EAGAIN; + } else if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + + err = snd_pcm_oss_change_params_locked(substream); mutex_unlock(&runtime->oss.params_lock); return err; } @@ -1107,11 +1121,14 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil return 0; } +/* call with params_lock held */ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) { int err; struct snd_pcm_runtime *runtime = substream->runtime; + if (!runtime->oss.prepare) + return 0; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (err < 0) { pcm_dbg(substream->pcm, @@ -1131,14 +1148,35 @@ static int snd_pcm_oss_make_ready(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime; int err; - if (substream == NULL) - return 0; runtime = substream->runtime; if (runtime->oss.params) { err = snd_pcm_oss_change_params(substream, false); if (err < 0) return err; } + if (runtime->oss.prepare) { + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + err = snd_pcm_oss_prepare(substream); + mutex_unlock(&runtime->oss.params_lock); + if (err < 0) + return err; + } + return 0; +} + +/* call with params_lock held */ +static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + int err; + + runtime = substream->runtime; + if (runtime->oss.params) { + err = snd_pcm_oss_change_params_locked(substream); + if (err < 0) + return err; + } if (runtime->oss.prepare) { err = snd_pcm_oss_prepare(substream); if (err < 0) @@ -1367,13 +1405,14 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha if (atomic_read(&substream->mmap_count)) return -ENXIO; - if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) - return tmp; while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; break; } + tmp = snd_pcm_oss_make_ready_locked(substream); + if (tmp < 0) + goto err; if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { tmp = bytes; if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes) @@ -1474,13 +1513,14 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use if (atomic_read(&substream->mmap_count)) return -ENXIO; - if ((tmp = snd_pcm_oss_make_ready(substream)) < 0) - return tmp; while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; break; } + tmp = snd_pcm_oss_make_ready_locked(substream); + if (tmp < 0) + goto err; if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) { if (runtime->oss.buffer_used == 0) { tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1); @@ -1536,10 +1576,12 @@ static int snd_pcm_oss_reset(struct snd_pcm_oss_file *pcm_oss_file) continue; runtime = substream->runtime; snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); + mutex_lock(&runtime->oss.params_lock); runtime->oss.prepare = 1; runtime->oss.buffer_used = 0; runtime->oss.prev_hw_ptr_period = 0; runtime->oss.period_ptr = 0; + mutex_unlock(&runtime->oss.params_lock); } return 0; } @@ -1625,9 +1667,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) goto __direct; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); - mutex_lock(&runtime->oss.params_lock); if (runtime->oss.buffer_used > 0) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "sync: buffer_used\n"); @@ -1695,7 +1738,9 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) substream->f_flags = saved_f_flags; if (err < 0) return err; + mutex_lock(&runtime->oss.params_lock); runtime->oss.prepare = 1; + mutex_unlock(&runtime->oss.params_lock); } substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE]; @@ -1706,8 +1751,10 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL); if (err < 0) return err; + mutex_lock(&runtime->oss.params_lock); runtime->oss.buffer_used = 0; runtime->oss.prepare = 1; + mutex_unlock(&runtime->oss.params_lock); } return 0; } @@ -1726,10 +1773,13 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) rate = 1000; else if (rate > 192000) rate = 192000; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; } + mutex_unlock(&runtime->oss.params_lock); } return snd_pcm_oss_get_rate(pcm_oss_file); } @@ -1757,10 +1807,13 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig if (substream == NULL) continue; runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (runtime->oss.channels != channels) { runtime->oss.params = 1; runtime->oss.channels = channels; } + mutex_unlock(&runtime->oss.params_lock); } return snd_pcm_oss_get_channels(pcm_oss_file); } @@ -1846,10 +1899,13 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for if (substream == NULL) continue; runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (runtime->oss.format != format) { runtime->oss.params = 1; runtime->oss.format = format; } + mutex_unlock(&runtime->oss.params_lock); } } return snd_pcm_oss_get_format(pcm_oss_file); @@ -1869,8 +1925,6 @@ static int snd_pcm_oss_set_subdivide1(struct snd_pcm_substream *substream, int s { struct snd_pcm_runtime *runtime; - if (substream == NULL) - return 0; runtime = substream->runtime; if (subdivide == 0) { subdivide = runtime->oss.subdivision; @@ -1894,9 +1948,16 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; + struct snd_pcm_runtime *runtime; + if (substream == NULL) continue; - if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0) + runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + err = snd_pcm_oss_set_subdivide1(substream, subdivide); + mutex_unlock(&runtime->oss.params_lock); + if (err < 0) return err; } return err; @@ -1906,8 +1967,6 @@ static int snd_pcm_oss_set_fragment1(struct snd_pcm_substream *substream, unsign { struct snd_pcm_runtime *runtime; - if (substream == NULL) - return 0; runtime = substream->runtime; if (runtime->oss.subdivision || runtime->oss.fragshift) return -EINVAL; @@ -1927,9 +1986,16 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; + struct snd_pcm_runtime *runtime; + if (substream == NULL) continue; - if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0) + runtime = substream->runtime; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + err = snd_pcm_oss_set_fragment1(substream, val); + mutex_unlock(&runtime->oss.params_lock); + if (err < 0) return err; } return err; @@ -2013,6 +2079,9 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr } if (psubstream) { runtime = psubstream->runtime; + cmd = 0; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (trigger & PCM_ENABLE_OUTPUT) { if (runtime->oss.trigger) goto _skip1; @@ -2030,13 +2099,19 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr cmd = SNDRV_PCM_IOCTL_DROP; runtime->oss.prepare = 1; } - err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL); - if (err < 0) - return err; - } _skip1: + mutex_unlock(&runtime->oss.params_lock); + if (cmd) { + err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL); + if (err < 0) + return err; + } + } if (csubstream) { runtime = csubstream->runtime; + cmd = 0; + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; if (trigger & PCM_ENABLE_INPUT) { if (runtime->oss.trigger) goto _skip2; @@ -2051,11 +2126,14 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr cmd = SNDRV_PCM_IOCTL_DROP; runtime->oss.prepare = 1; } - err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL); - if (err < 0) - return err; - } _skip2: + mutex_unlock(&runtime->oss.params_lock); + if (cmd) { + err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL); + if (err < 0) + return err; + } + } return 0; } -- GitLab From 3724f9c7dd1e7373d5db4098b1e17a48b2fe2421 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 23 Mar 2018 08:03:26 +0100 Subject: [PATCH 1472/1834] ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams commit 40cab6e88cb0b6c56d3f30b7491a20e803f948f6 upstream. OSS PCM stream management isn't modal but it allows ioctls issued at any time for changing the parameters. In the previous hardening patch ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write"), we covered these races and prevent the corruption by protecting the concurrent accesses via params_lock mutex. However, this means that some ioctls that try to change the stream parameter (e.g. channels or format) would be blocked until the read/write finishes, and it may take really long. Basically changing the parameter while reading/writing is an invalid operation, hence it's even more user-friendly from the API POV if it returns -EBUSY in such a situation. This patch adds such checks in the relevant ioctls with the addition of read/write access refcount. Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/pcm_oss.h | 1 + sound/core/oss/pcm_oss.c | 36 +++++++++++++++++++++++++++--------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h index 760c969d885d..12bbf8c81112 100644 --- a/include/sound/pcm_oss.h +++ b/include/sound/pcm_oss.h @@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime { char *buffer; /* vmallocated period */ size_t buffer_used; /* used length from period buffer */ struct mutex params_lock; + atomic_t rw_ref; /* concurrent read/write accesses */ #ifdef CONFIG_SND_PCM_OSS_PLUGINS struct snd_pcm_plugin *plugin_first; struct snd_pcm_plugin *plugin_last; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index bf5f3f1b6824..702bfccce036 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1405,6 +1405,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha if (atomic_read(&substream->mmap_count)) return -ENXIO; + atomic_inc(&runtime->oss.rw_ref); while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; @@ -1468,6 +1469,7 @@ static ssize_t snd_pcm_oss_write1(struct snd_pcm_substream *substream, const cha } tmp = 0; } + atomic_dec(&runtime->oss.rw_ref); return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } @@ -1513,6 +1515,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use if (atomic_read(&substream->mmap_count)) return -ENXIO; + atomic_inc(&runtime->oss.rw_ref); while (bytes > 0) { if (mutex_lock_interruptible(&runtime->oss.params_lock)) { tmp = -ERESTARTSYS; @@ -1561,6 +1564,7 @@ static ssize_t snd_pcm_oss_read1(struct snd_pcm_substream *substream, char __use } tmp = 0; } + atomic_dec(&runtime->oss.rw_ref); return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; } @@ -1667,8 +1671,11 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) goto __direct; if ((err = snd_pcm_oss_make_ready(substream)) < 0) return err; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) + atomic_inc(&runtime->oss.rw_ref); + if (mutex_lock_interruptible(&runtime->oss.params_lock)) { + atomic_dec(&runtime->oss.rw_ref); return -ERESTARTSYS; + } format = snd_pcm_oss_format_from(runtime->oss.format); width = snd_pcm_format_physical_width(format); if (runtime->oss.buffer_used > 0) { @@ -1680,10 +1687,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime->oss.buffer + runtime->oss.buffer_used, size); err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes); - if (err < 0) { - mutex_unlock(&runtime->oss.params_lock); - return err; - } + if (err < 0) + goto unlock; } else if (runtime->oss.period_ptr > 0) { #ifdef OSS_DEBUG pcm_dbg(substream->pcm, "sync: period_ptr\n"); @@ -1693,10 +1698,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) runtime->oss.buffer, size * 8 / width); err = snd_pcm_oss_sync1(substream, size); - if (err < 0) { - mutex_unlock(&runtime->oss.params_lock); - return err; - } + if (err < 0) + goto unlock; } /* * The ALSA's period might be a bit large than OSS one. @@ -1727,7 +1730,11 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file) snd_pcm_lib_writev(substream, buffers, size); } } +unlock: mutex_unlock(&runtime->oss.params_lock); + atomic_dec(&runtime->oss.rw_ref); + if (err < 0) + return err; /* * finish sync: drain the buffer */ @@ -1775,6 +1782,8 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) rate = 192000; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; @@ -1809,6 +1818,8 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig runtime = substream->runtime; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (runtime->oss.channels != channels) { runtime->oss.params = 1; runtime->oss.channels = channels; @@ -1899,6 +1910,8 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for if (substream == NULL) continue; runtime = substream->runtime; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; if (runtime->oss.format != format) { @@ -1953,6 +1966,8 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int if (substream == NULL) continue; runtime = substream->runtime; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; err = snd_pcm_oss_set_subdivide1(substream, subdivide); @@ -1991,6 +2006,8 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig if (substream == NULL) continue; runtime = substream->runtime; + if (atomic_read(&runtime->oss.rw_ref)) + return -EBUSY; if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -ERESTARTSYS; err = snd_pcm_oss_set_fragment1(substream, val); @@ -2385,6 +2402,7 @@ static void snd_pcm_oss_init_substream(struct snd_pcm_substream *substream, runtime->oss.maxfrags = 0; runtime->oss.subdivision = 0; substream->pcm_release = snd_pcm_oss_release_substream; + atomic_set(&runtime->oss.rw_ref, 0); } static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file) -- GitLab From 24fd21ae8ea69d9f9d25efb4292c46d5bc19e15d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 27 Mar 2018 14:32:23 +0200 Subject: [PATCH 1473/1834] ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls commit f6d297df4dd47ef949540e4a201230d0c5308325 upstream. The previous fix 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams") introduced some mutex unbalance; the check of runtime->oss.rw_ref was inserted in a wrong place after the mutex lock. This patch fixes the inconsistency by rewriting with the helper functions to lock/unlock parameters with the stream check. Fixes: 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams") Reported-by: Dan Carpenter Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 67 +++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 702bfccce036..5cc65d185033 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -834,6 +834,23 @@ static int choose_rate(struct snd_pcm_substream *substream, return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL); } +/* parameter locking: returns immediately if tried during streaming */ +static int lock_params(struct snd_pcm_runtime *runtime) +{ + if (mutex_lock_interruptible(&runtime->oss.params_lock)) + return -ERESTARTSYS; + if (atomic_read(&runtime->oss.rw_ref)) { + mutex_unlock(&runtime->oss.params_lock); + return -EBUSY; + } + return 0; +} + +static void unlock_params(struct snd_pcm_runtime *runtime) +{ + mutex_unlock(&runtime->oss.params_lock); +} + /* call with params_lock held */ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) { @@ -1773,6 +1790,8 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; struct snd_pcm_runtime *runtime; + int err; + if (substream == NULL) continue; runtime = substream->runtime; @@ -1780,15 +1799,14 @@ static int snd_pcm_oss_set_rate(struct snd_pcm_oss_file *pcm_oss_file, int rate) rate = 1000; else if (rate > 192000) rate = 192000; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; + err = lock_params(runtime); + if (err < 0) + return err; if (runtime->oss.rate != rate) { runtime->oss.params = 1; runtime->oss.rate = rate; } - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); } return snd_pcm_oss_get_rate(pcm_oss_file); } @@ -1813,18 +1831,19 @@ static int snd_pcm_oss_set_channels(struct snd_pcm_oss_file *pcm_oss_file, unsig for (idx = 1; idx >= 0; --idx) { struct snd_pcm_substream *substream = pcm_oss_file->streams[idx]; struct snd_pcm_runtime *runtime; + int err; + if (substream == NULL) continue; runtime = substream->runtime; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; + err = lock_params(runtime); + if (err < 0) + return err; if (runtime->oss.channels != channels) { runtime->oss.params = 1; runtime->oss.channels = channels; } - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); } return snd_pcm_oss_get_channels(pcm_oss_file); } @@ -1897,6 +1916,7 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file) static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format) { int formats, idx; + int err; if (format != AFMT_QUERY) { formats = snd_pcm_oss_get_formats(pcm_oss_file); @@ -1910,15 +1930,14 @@ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int for if (substream == NULL) continue; runtime = substream->runtime; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + err = lock_params(runtime); + if (err < 0) + return err; if (runtime->oss.format != format) { runtime->oss.params = 1; runtime->oss.format = format; } - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); } } return snd_pcm_oss_get_format(pcm_oss_file); @@ -1966,12 +1985,11 @@ static int snd_pcm_oss_set_subdivide(struct snd_pcm_oss_file *pcm_oss_file, int if (substream == NULL) continue; runtime = substream->runtime; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + err = lock_params(runtime); + if (err < 0) + return err; err = snd_pcm_oss_set_subdivide1(substream, subdivide); - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); if (err < 0) return err; } @@ -2006,12 +2024,11 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig if (substream == NULL) continue; runtime = substream->runtime; - if (atomic_read(&runtime->oss.rw_ref)) - return -EBUSY; - if (mutex_lock_interruptible(&runtime->oss.params_lock)) - return -ERESTARTSYS; + err = lock_params(runtime); + if (err < 0) + return err; err = snd_pcm_oss_set_fragment1(substream, val); - mutex_unlock(&runtime->oss.params_lock); + unlock_params(runtime); if (err < 0) return err; } -- GitLab From ad811550b1248d19af77724b77cb83bf0ab8b5dc Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 7 Apr 2018 11:48:58 +0200 Subject: [PATCH 1474/1834] ALSA: pcm: Fix endless loop for XRUN recovery in OSS emulation commit e15dc99dbb9cf99f6432e8e3c0b3a8f7a3403a86 upstream. The commit 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write") split the PCM preparation code to a locked version, and it added a sanity check of runtime->oss.prepare flag along with the change. This leaded to an endless loop when the stream gets XRUN: namely, snd_pcm_oss_write3() and co call snd_pcm_oss_prepare() without setting runtime->oss.prepare flag and the loop continues until the PCM state reaches to another one. As the function is supposed to execute the preparation unconditionally, drop the invalid state check there. The bug was triggered by syzkaller. Fixes: 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write") Reported-by: syzbot+150189c103427d31a053@syzkaller.appspotmail.com Reported-by: syzbot+7e3f31a52646f939c052@syzkaller.appspotmail.com Reported-by: syzbot+4f2016cf5185da7759dc@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/oss/pcm_oss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 5cc65d185033..cfb8f5896787 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -1139,13 +1139,14 @@ static int snd_pcm_oss_get_active_substream(struct snd_pcm_oss_file *pcm_oss_fil } /* call with params_lock held */ +/* NOTE: this always call PREPARE unconditionally no matter whether + * runtime->oss.prepare is set or not + */ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) { int err; struct snd_pcm_runtime *runtime = substream->runtime; - if (!runtime->oss.prepare) - return 0; err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL); if (err < 0) { pcm_dbg(substream->pcm, -- GitLab From 68e3579a5fef4b45e14802808476baac5797e741 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 29 Mar 2018 22:10:35 -0400 Subject: [PATCH 1475/1834] ext4: don't allow r/w mounts if metadata blocks overlap the superblock commit 18db4b4e6fc31eda838dd1c1296d67dbcb3dc957 upstream. If some metadata block, such as an allocation bitmap, overlaps the superblock, it's very likely that if the file system is mounted read/write, the results will not be pretty. So disallow r/w mounts for file systems corrupted in this particular way. Backport notes: 3.18.y is missing bc98a42c1f7d ("VFS: Convert sb->s_flags & MS_RDONLY to sb_rdonly(sb)") and e462ec50cb5f ("VFS: Differentiate mount flags (MS_*) from internal superblock flags") so we simply use the sb MS_RDONLY check from pre bc98a42c1f7d in place of the sb_rdonly function used in the upstream variant of the patch. Signed-off-by: Theodore Ts'o Cc: stable@vger.kernel.org Signed-off-by: Harsh Shandilya Signed-off-by: Greg Kroah-Hartman --- fs/ext4/super.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1ec4b6e34747..bfb83d76d128 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -2260,6 +2260,8 @@ static int ext4_check_descriptors(struct super_block *sb, ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Block bitmap for group %u overlaps " "superblock", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; } if (block_bitmap < first_block || block_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " @@ -2272,6 +2274,8 @@ static int ext4_check_descriptors(struct super_block *sb, ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Inode bitmap for group %u overlaps " "superblock", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; } if (inode_bitmap < first_block || inode_bitmap > last_block) { ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " @@ -2284,6 +2288,8 @@ static int ext4_check_descriptors(struct super_block *sb, ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " "Inode table for group %u overlaps " "superblock", i); + if (!(sb->s_flags & MS_RDONLY)) + return 0; } if (inode_table < first_block || inode_table + sbi->s_itb_per_group - 1 > last_block) { -- GitLab From 54279928a84d5fc6f9e15d43ad31170c7eae1c1d Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 21 Mar 2018 21:05:46 -0500 Subject: [PATCH 1476/1834] drm/amdgpu: Add an ATPX quirk for hybrid laptop commit 13b40935cf64f59b93cf1c716a2033488e5a228c upstream. _PR3 doesn't seem to work properly, use ATPX instead. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=104064 Reviewed-by: Huang Rui Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c index 0e8f8972a160..0217f5d6ecb9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atpx_handler.c @@ -569,6 +569,7 @@ static const struct amdgpu_px_quirk amdgpu_px_quirk_list[] = { { 0x1002, 0x6900, 0x1002, 0x0124, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0812, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0x1002, 0x6900, 0x1028, 0x0813, AMDGPU_PX_QUIRK_FORCE_ATPX }, + { 0x1002, 0x67DF, 0x1028, 0x0774, AMDGPU_PX_QUIRK_FORCE_ATPX }, { 0, 0, 0, 0, 0 }, }; -- GitLab From 267e6921ca7c7e776804a8be6aa53fca37d68fd6 Mon Sep 17 00:00:00 2001 From: Bas Nieuwenhuizen Date: Wed, 31 Jan 2018 13:58:55 +0100 Subject: [PATCH 1477/1834] drm/amdgpu: Fix always_valid bos multiple LRU insertions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit a20ee0b1f8b42e2568f3a4408003d22b2dfcc706 upstream. If these bos are evicted and are in the validated list things blow up, so do not put them in there. Notably, that tries to add the bo to the LRU twice, which results in a BUG_ON in ttm_bo.c. While for the bo_list an alternative would be to not allow always valid bos in there, that does not work for the user fence. v2: Fixed whitespace issue pointed out by checkpatch.pl Signed-off-by: Bas Nieuwenhuizen Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 6 ++++-- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index c02db01f6583..fe011c7ec70a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -201,8 +201,10 @@ void amdgpu_bo_list_get_list(struct amdgpu_bo_list *list, for (i = 0; i < list->num_entries; i++) { unsigned priority = list->array[i].priority; - list_add_tail(&list->array[i].tv.head, - &bucket[priority]); + if (!list->array[i].robj->parent) + list_add_tail(&list->array[i].tv.head, + &bucket[priority]); + list->array[i].user_pages = NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index cb505f66d3aa..c801624f33bd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -519,7 +519,7 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p, INIT_LIST_HEAD(&duplicates); amdgpu_vm_get_pd_bo(&fpriv->vm, &p->validated, &p->vm_pd); - if (p->uf_entry.robj) + if (p->uf_entry.robj && !p->uf_entry.robj->parent) list_add(&p->uf_entry.tv.head, &p->validated); if (need_mmap_lock) -- GitLab From aab59482e65969b176e97bb6cff7e443d3115ec8 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 2 Apr 2018 12:29:26 -0500 Subject: [PATCH 1478/1834] drm/amdgpu: Fix PCIe lane width calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 41212e2fe72b26ded7ed78224d9eab720c2891e2 upstream. The calculation of the lane widths via ATOM_PPLIB_PCIE_LINK_WIDTH_MASK and ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT macros did not increment the resulting value, per the comment in pptable.h ("lanes - 1"), and per usage elsewhere. Port of the radeon fix to amdgpu. Acked-by: Christian König Acked-by: Chunming Zhou Bug: https://bugs.freedesktop.org/show_bug.cgi?id=102553 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/amd/amdgpu/si_dpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 002862be2df6..3fa8320e49c1 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -6449,9 +6449,9 @@ static void si_set_pcie_lane_width_in_smc(struct amdgpu_device *adev, { u32 lane_width; u32 new_lane_width = - (amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((amdgpu_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; u32 current_lane_width = - (amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((amdgpu_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; if (new_lane_width != current_lane_width) { amdgpu_set_pcie_lanes(adev, new_lane_width); -- GitLab From 7c320edaa4c8b5c864b11c5e5c51b9dfd36a19c4 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 20 Feb 2018 13:01:18 +0000 Subject: [PATCH 1479/1834] drm/rockchip: Clear all interrupts before requesting the IRQ commit 5f9e93fed4d45e9a8f84728aff1a8f2ab8922902 upstream. Calling request_irq() followed by disable_irq() is usually a bad idea, specially if the interrupt can be pending, and you're not yet in a position to handle it. This is exactly what happens on my kevin system when rebooting in a second kernel using kexec: Some interrupt is left pending from the previous kernel, and we take it too early, before disable_irq() could do anything. Let's clear the pending interrupts as we initialize the HW, and move the interrupt request after that point. This ensures that we're in a sane state when the interrupt is requested. Cc: stable@vger.kernel.org Signed-off-by: Marc Zyngier [adapted to recent rockchip-drm changes] Signed-off-by: Heiko Stuebner Link: https://patchwork.freedesktop.org/patch/msgid/20180220130120.5254-2-marc.zyngier@arm.com Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 23 +++++++++++---------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 6e3c4acb16ac..32d87c6035c9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -1386,6 +1386,9 @@ static int vop_initial(struct vop *vop) usleep_range(10, 20); reset_control_deassert(ahb_rst); + VOP_INTR_SET_TYPE(vop, clear, INTR_MASK, 1); + VOP_INTR_SET_TYPE(vop, enable, INTR_MASK, 0); + memcpy(vop->regsbak, vop->regs, vop->len); for (i = 0; i < vop_data->table_size; i++) @@ -1541,17 +1544,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data) mutex_init(&vop->vsync_mutex); - ret = devm_request_irq(dev, vop->irq, vop_isr, - IRQF_SHARED, dev_name(dev), vop); - if (ret) - return ret; - - /* IRQ is initially disabled; it gets enabled in power_on */ - disable_irq(vop->irq); - ret = vop_create_crtc(vop); if (ret) - goto err_enable_irq; + return ret; pm_runtime_enable(&pdev->dev); @@ -1561,13 +1556,19 @@ static int vop_bind(struct device *dev, struct device *master, void *data) goto err_disable_pm_runtime; } + ret = devm_request_irq(dev, vop->irq, vop_isr, + IRQF_SHARED, dev_name(dev), vop); + if (ret) + goto err_disable_pm_runtime; + + /* IRQ is initially disabled; it gets enabled in power_on */ + disable_irq(vop->irq); + return 0; err_disable_pm_runtime: pm_runtime_disable(&pdev->dev); vop_destroy_crtc(vop); -err_enable_irq: - enable_irq(vop->irq); /* To balance out the disable_irq above */ return ret; } -- GitLab From 9607290a18352cba4a7d015d826c1ce40bdb25bb Mon Sep 17 00:00:00 2001 From: Paul Parsons Date: Sat, 2 Apr 2016 12:32:30 +0100 Subject: [PATCH 1480/1834] drm/radeon: Fix PCIe lane width calculation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 85e290d92b4b794d0c758c53007eb4248d385386 upstream. Two years ago I tried an AMD Radeon E8860 embedded GPU with the drm driver. The dmesg output included driver warnings about an invalid PCIe lane width. Tracking the problem back led to si_set_pcie_lane_width_in_smc(). The calculation of the lane widths via ATOM_PPLIB_PCIE_LINK_WIDTH_MASK and ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT macros did not increment the resulting value, per the comment in pptable.h ("lanes - 1"), and per usage elsewhere. Applying the increment silenced the warnings. The code has not changed since, so either my analysis was incorrect or the bug has gone unnoticed. Hence submitting this as an RFC. Acked-by: Christian König Acked-by: Chunming Zhou Signed-off-by: Paul Parsons Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/gpu/drm/radeon/si_dpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 574ab0016a57..b82ef5ed727c 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -5969,9 +5969,9 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev, { u32 lane_width; u32 new_lane_width = - (radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((radeon_new_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; u32 current_lane_width = - (radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT; + ((radeon_current_state->caps & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; if (new_lane_width != current_lane_width) { radeon_set_pcie_lanes(rdev, new_lane_width); -- GitLab From f93f5adacfd2cd1e4234b5c5fd6316124c728dc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabi=C3=A1n=20Inostroza?= Date: Thu, 12 Apr 2018 00:37:35 -0300 Subject: [PATCH 1481/1834] ALSA: line6: Use correct endpoint type for midi output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 7ecb46e9ee9af18e304eb9e7d6804c59a408e846 upstream. Sending MIDI messages to a PODxt through the USB connection shows "usb_submit_urb failed" in dmesg and the message is not received by the POD. The error is caused because in the funcion send_midi_async() in midi.c there is a call to usb_sndbulkpipe() for endpoint 3 OUT, but the PODxt USB descriptor shows that this endpoint it's an interrupt endpoint. Patch tested with PODxt only. [ The bug has been present from the very beginning in the staging driver time, but Fixes below points to the commit moving to sound/ directory so that the fix can be cleanly applied -- tiwai ] Fixes: 61864d844c29 ("ALSA: move line6 usb driver into sound/usb") Signed-off-by: Fabián Inostroza Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/usb/line6/midi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c index d0fb2f205bd9..4f4ebe90f1a8 100644 --- a/sound/usb/line6/midi.c +++ b/sound/usb/line6/midi.c @@ -125,7 +125,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, } usb_fill_int_urb(urb, line6->usbdev, - usb_sndbulkpipe(line6->usbdev, + usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), transfer_buffer, length, midi_sent, line6, line6->interval); -- GitLab From b291c272c1ff23206e8338444735e3825f757b35 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Apr 2018 18:16:15 +0200 Subject: [PATCH 1482/1834] ALSA: rawmidi: Fix missing input substream checks in compat ioctls commit 8a56ef4f3ffba9ebf4967b61ef600b0a7ba10f11 upstream. Some rawmidi compat ioctls lack of the input substream checks (although they do check only for rfile->output). This many eventually lead to an Oops as NULL substream is passed to the rawmidi core functions. Fix it by adding the proper checks before each function call. The bug was spotted by syzkaller. Reported-by: syzbot+f7a0348affc3b67bc617@syzkaller.appspotmail.com Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/core/rawmidi_compat.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/sound/core/rawmidi_compat.c b/sound/core/rawmidi_compat.c index f69764d7cdd7..e30e30ba6e39 100644 --- a/sound/core/rawmidi_compat.c +++ b/sound/core/rawmidi_compat.c @@ -36,8 +36,6 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, struct snd_rawmidi_params params; unsigned int val; - if (rfile->output == NULL) - return -EINVAL; if (get_user(params.stream, &src->stream) || get_user(params.buffer_size, &src->buffer_size) || get_user(params.avail_min, &src->avail_min) || @@ -46,8 +44,12 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile, params.no_active_sensing = val; switch (params.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; return snd_rawmidi_output_params(rfile->output, ¶ms); case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; return snd_rawmidi_input_params(rfile->input, ¶ms); } return -EINVAL; @@ -67,16 +69,18 @@ static int snd_rawmidi_ioctl_status_compat(struct snd_rawmidi_file *rfile, int err; struct snd_rawmidi_status status; - if (rfile->output == NULL) - return -EINVAL; if (get_user(status.stream, &src->stream)) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; err = snd_rawmidi_output_status(rfile->output, &status); break; case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; err = snd_rawmidi_input_status(rfile->input, &status); break; default: @@ -112,16 +116,18 @@ static int snd_rawmidi_ioctl_status_x32(struct snd_rawmidi_file *rfile, int err; struct snd_rawmidi_status status; - if (rfile->output == NULL) - return -EINVAL; if (get_user(status.stream, &src->stream)) return -EFAULT; switch (status.stream) { case SNDRV_RAWMIDI_STREAM_OUTPUT: + if (!rfile->output) + return -EINVAL; err = snd_rawmidi_output_status(rfile->output, &status); break; case SNDRV_RAWMIDI_STREAM_INPUT: + if (!rfile->input) + return -EINVAL; err = snd_rawmidi_input_status(rfile->input, &status); break; default: -- GitLab From 2e2389a07923a888d6e22337391b08092f213416 Mon Sep 17 00:00:00 2001 From: David Wang Date: Mon, 16 Apr 2018 17:48:09 +0800 Subject: [PATCH 1483/1834] ALSA: hda - New VIA controller suppor no-snoop path commit af52f9982e410edac21ca4b49563053ffc9da1eb upstream. This patch is used to tell kernel that new VIA HDAC controller also support no-snoop path. [ minor coding style fix by tiwai ] Signed-off-by: David Wang Cc: Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/pci/hda/hda_intel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 733b3423baa2..7d3f88d90eec 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -1514,7 +1514,8 @@ static void azx_check_snoop_available(struct azx *chip) */ u8 val; pci_read_config_byte(chip->pci, 0x42, &val); - if (!(val & 0x80) && chip->pci->revision == 0x30) + if (!(val & 0x80) && (chip->pci->revision == 0x30 || + chip->pci->revision == 0x20)) snoop = false; } -- GitLab From 4dfb3442bb7e1fb80515df4a199ca5a7a8edf900 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Apr 2018 13:27:52 -0400 Subject: [PATCH 1484/1834] random: fix crng_ready() test commit 43838a23a05fbd13e47d750d3dfd77001536dd33 upstream. The crng_init variable has three states: 0: The CRNG is not initialized at all 1: The CRNG has a small amount of entropy, hopefully good enough for early-boot, non-cryptographical use cases 2: The CRNG is fully initialized and we are sure it is safe for cryptographic use cases. The crng_ready() function should only return true once we are in the last state. This addresses CVE-2018-1108. Reported-by: Jann Horn Fixes: e192be9d9a30 ("random: replace non-blocking pool...") Cc: stable@kernel.org # 4.8+ Signed-off-by: Theodore Ts'o Reviewed-by: Jann Horn Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index cf1b91e33a28..4f82fe0789e4 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -434,7 +434,7 @@ struct crng_state primary_crng = { * its value (from 0->1->2). */ static int crng_init = 0; -#define crng_ready() (likely(crng_init > 0)) +#define crng_ready() (likely(crng_init > 1)) static int crng_init_cnt = 0; #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) static void _extract_crng(struct crng_state *crng, @@ -800,7 +800,7 @@ static int crng_fast_load(const char *cp, size_t len) if (!spin_trylock_irqsave(&primary_crng.lock, flags)) return 0; - if (crng_ready()) { + if (crng_init != 0) { spin_unlock_irqrestore(&primary_crng.lock, flags); return 0; } @@ -872,7 +872,7 @@ static void _extract_crng(struct crng_state *crng, { unsigned long v, flags; - if (crng_init > 1 && + if (crng_ready() && time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)) crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL); spin_lock_irqsave(&crng->lock, flags); @@ -1153,7 +1153,7 @@ void add_interrupt_randomness(int irq, int irq_flags) fast_mix(fast_pool); add_interrupt_bench(cycles); - if (!crng_ready()) { + if (unlikely(crng_init == 0)) { if ((fast_pool->count >= 64) && crng_fast_load((char *) fast_pool->pool, sizeof(fast_pool->pool))) { @@ -2148,7 +2148,7 @@ void add_hwgenerator_randomness(const char *buffer, size_t count, { struct entropy_store *poolp = &input_pool; - if (!crng_ready()) { + if (unlikely(crng_init == 0)) { crng_fast_load(buffer, count); return; } -- GitLab From befd00cfc189672adfdf6850cf460a7f53c56cf0 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 12 Apr 2018 00:50:45 -0400 Subject: [PATCH 1485/1834] random: crng_reseed() should lock the crng instance that it is modifying commit 0bb29a849a6433b72e249eea7695477b02056e94 upstream. Reported-by: Jann Horn Fixes: 1e7f583af67b ("random: make /dev/urandom scalable for silly...") Cc: stable@kernel.org # 4.8+ Signed-off-by: Theodore Ts'o Reviewed-by: Jann Horn Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 4f82fe0789e4..9d24f3cdc9bb 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -836,7 +836,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) _crng_backtrack_protect(&primary_crng, buf.block, CHACHA20_KEY_SIZE); } - spin_lock_irqsave(&primary_crng.lock, flags); + spin_lock_irqsave(&crng->lock, flags); for (i = 0; i < 8; i++) { unsigned long rv; if (!arch_get_random_seed_long(&rv) && @@ -852,7 +852,7 @@ static void crng_reseed(struct crng_state *crng, struct entropy_store *r) wake_up_interruptible(&crng_init_wait); pr_notice("random: crng init done\n"); } - spin_unlock_irqrestore(&primary_crng.lock, flags); + spin_unlock_irqrestore(&crng->lock, flags); } static inline void maybe_reseed_primary_crng(void) -- GitLab From 1d49e2ab766df649c540959a96f1ab839471fbe8 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 11 Apr 2018 16:32:17 -0400 Subject: [PATCH 1486/1834] random: add new ioctl RNDRESEEDCRNG commit d848e5f8e1ebdb227d045db55fe4f825e82965fa upstream. Add a new ioctl which forces the the crng to be reseeded. Signed-off-by: Theodore Ts'o Cc: stable@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/random.c | 13 ++++++++++++- include/uapi/linux/random.h | 3 +++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/char/random.c b/drivers/char/random.c index 9d24f3cdc9bb..8d08a8062904 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -436,6 +436,7 @@ struct crng_state primary_crng = { static int crng_init = 0; #define crng_ready() (likely(crng_init > 1)) static int crng_init_cnt = 0; +static unsigned long crng_global_init_time = 0; #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) static void _extract_crng(struct crng_state *crng, __u8 out[CHACHA20_BLOCK_SIZE]); @@ -873,7 +874,8 @@ static void _extract_crng(struct crng_state *crng, unsigned long v, flags; if (crng_ready() && - time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)) + (time_after(crng_global_init_time, crng->init_time) || + time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL))) crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL); spin_lock_irqsave(&crng->lock, flags); if (arch_get_random_long(&v)) @@ -1668,6 +1670,7 @@ static int rand_initialize(void) init_std_data(&input_pool); init_std_data(&blocking_pool); crng_initialize(&primary_crng); + crng_global_init_time = jiffies; #ifdef CONFIG_NUMA pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); @@ -1854,6 +1857,14 @@ static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) input_pool.entropy_count = 0; blocking_pool.entropy_count = 0; return 0; + case RNDRESEEDCRNG: + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (crng_init < 2) + return -ENODATA; + crng_reseed(&primary_crng, NULL); + crng_global_init_time = jiffies - 1; + return 0; default: return -EINVAL; } diff --git a/include/uapi/linux/random.h b/include/uapi/linux/random.h index 3f93d1695e7f..b455b0d86f26 100644 --- a/include/uapi/linux/random.h +++ b/include/uapi/linux/random.h @@ -34,6 +34,9 @@ /* Clear the entropy pool and associated counters. (Superuser only.) */ #define RNDCLEARPOOL _IO( 'R', 0x06 ) +/* Reseed CRNG. (Superuser only.) */ +#define RNDRESEEDCRNG _IO( 'R', 0x07 ) + struct rand_pool_info { int entropy_count; int buf_size; -- GitLab From d385cc6917c4fb27f883694b5f53253a289b60c8 Mon Sep 17 00:00:00 2001 From: Rodrigo Rivas Costa Date: Fri, 6 Apr 2018 01:09:36 +0200 Subject: [PATCH 1487/1834] HID: hidraw: Fix crash on HIDIOCGFEATURE with a destroyed device commit a955358d54695e4ad9f7d6489a7ac4d69a8fc711 upstream. Doing `ioctl(HIDIOCGFEATURE)` in a tight loop on a hidraw device and then disconnecting the device, or unloading the driver, can cause a NULL pointer dereference. When a hidraw device is destroyed it sets 0 to `dev->exist`. Most functions check 'dev->exist' before doing its work, but `hidraw_get_report()` was missing that check. Cc: stable@vger.kernel.org Signed-off-by: Rodrigo Rivas Costa Signed-off-by: Jiri Kosina Signed-off-by: Greg Kroah-Hartman --- drivers/hid/hidraw.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index f0e2757cb909..216f0338a1f7 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -192,6 +192,11 @@ static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t int ret = 0, len; unsigned char report_number; + if (!hidraw_table[minor] || !hidraw_table[minor]->exist) { + ret = -ENODEV; + goto out; + } + dev = hidraw_table[minor]->hid; if (!dev->ll_driver->raw_request) { -- GitLab From 1179774213638107fcaf8745435e39cd27babddb Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 17 Apr 2018 16:40:01 +0100 Subject: [PATCH 1488/1834] MIPS: uaccess: Add micromips clobbers to bzero invocation commit b3d7e55c3f886493235bfee08e1e5a4a27cbcce8 upstream. The micromips implementation of bzero additionally clobbers registers t7 & t8. Specify this in the clobbers list when invoking bzero. Fixes: 26c5e07d1478 ("MIPS: microMIPS: Optimise 'memset' core library function.") Reported-by: James Hogan Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: # 3.10+ Patchwork: https://patchwork.linux-mips.org/patch/19110/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/include/asm/uaccess.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index 89fa5c0b1579..c92f4c28db7f 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h @@ -1257,6 +1257,13 @@ __clear_user(void __user *addr, __kernel_size_t size) { __kernel_size_t res; +#ifdef CONFIG_CPU_MICROMIPS +/* micromips memset / bzero also clobbers t7 & t8 */ +#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$15", "$24", "$31" +#else +#define bzero_clobbers "$4", "$5", "$6", __UA_t0, __UA_t1, "$31" +#endif /* CONFIG_CPU_MICROMIPS */ + if (eva_kernel_access()) { __asm__ __volatile__( "move\t$4, %1\n\t" @@ -1266,7 +1273,7 @@ __clear_user(void __user *addr, __kernel_size_t size) "move\t%0, $6" : "=r" (res) : "r" (addr), "r" (size) - : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"); + : bzero_clobbers); } else { might_fault(); __asm__ __volatile__( @@ -1277,7 +1284,7 @@ __clear_user(void __user *addr, __kernel_size_t size) "move\t%0, $6" : "=r" (res) : "r" (addr), "r" (size) - : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31"); + : bzero_clobbers); } return res; -- GitLab From 7177f0b3a8585687abf28234edb80fe209ac2f62 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 29 Mar 2018 10:28:23 +0100 Subject: [PATCH 1489/1834] MIPS: memset.S: EVA & fault support for small_memset commit 8a8158c85e1e774a44fbe81106fa41138580dfd1 upstream. The MIPS kernel memset / bzero implementation includes a small_memset branch which is used when the region to be set is smaller than a long (4 bytes on 32bit, 8 bytes on 64bit). The current small_memset implementation uses a simple store byte loop to write the destination. There are 2 issues with this implementation: 1. When EVA mode is active, user and kernel address spaces may overlap. Currently the use of the sb instruction means kernel mode addressing is always used and an intended write to userspace may actually overwrite some critical kernel data. 2. If the write triggers a page fault, for example by calling __clear_user(NULL, 2), instead of gracefully handling the fault, an OOPS is triggered. Fix these issues by replacing the sb instruction with the EX() macro, which will emit EVA compatible instuctions as required. Additionally implement a fault fixup for small_memset which sets a2 to the number of bytes that could not be cleared (as defined by __clear_user). Reported-by: Chuanhua Lei Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/18975/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/lib/memset.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 18a1ccd4d134..442197eea2fe 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -218,7 +218,7 @@ 1: PTR_ADDIU a0, 1 /* fill bytewise */ R10KCBARRIER(0(ra)) bne t1, a0, 1b - sb a1, -1(a0) + EX(sb, a1, -1(a0), .Lsmall_fixup\@) 2: jr ra /* done */ move a2, zero @@ -259,6 +259,11 @@ jr ra andi v1, a2, STORMASK +.Lsmall_fixup\@: + PTR_SUBU a2, t1, a0 + jr ra + PTR_ADDIU a2, 1 + .endm /* -- GitLab From 6cd712bfbbf1957289ad906d4d6191c1a3fc31a1 Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 17 Apr 2018 15:52:21 +0100 Subject: [PATCH 1490/1834] MIPS: memset.S: Fix return of __clear_user from Lpartial_fixup commit daf70d89f80c6e1772233da9e020114b1254e7e0 upstream. The __clear_user function is defined to return the number of bytes that could not be cleared. From the underlying memset / bzero implementation this means setting register a2 to that number on return. Currently if a page fault is triggered within the memset_partial block, the value loaded into a2 on return is meaningless. The label .Lpartial_fixup\@ is jumped to on page fault. In order to work out how many bytes failed to copy, the exception handler should find how many bytes left in the partial block (andi a2, STORMASK), add that to the partial block end address (a2), and subtract the faulting address to get the remainder. Currently it incorrectly subtracts the partial block start address (t1), which has additionally been clobbered to generate a jump target in memset_partial. Fix this by adding the block end address instead. This issue was found with the following test code: int j, k; for (j = 0; j < 512; j++) { if ((k = clear_user(NULL, j)) != j) { pr_err("clear_user (NULL %d) returned %d\n", j, k); } } Which now passes on Creator Ci40 (MIPS32) and Cavium Octeon II (MIPS64). Suggested-by: James Hogan Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/19108/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/lib/memset.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index 442197eea2fe..c6b2e3178b26 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -251,7 +251,7 @@ PTR_L t0, TI_TASK($28) andi a2, STORMASK LONG_L t0, THREAD_BUADDR(t0) - LONG_ADDU a2, t1 + LONG_ADDU a2, a0 jr ra LONG_SUBU a2, t0 -- GitLab From 95a9a529aeb82d88ca25449e1ebb25e5ecdafade Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Tue, 17 Apr 2018 16:40:00 +0100 Subject: [PATCH 1491/1834] MIPS: memset.S: Fix clobber of v1 in last_fixup commit c96eebf07692e53bf4dd5987510d8b550e793598 upstream. The label .Llast_fixup\@ is jumped to on page fault within the final byte set loop of memset (on < MIPSR6 architectures). For some reason, in this fault handler, the v1 register is randomly set to a2 & STORMASK. This clobbers v1 for the calling function. This can be observed with the following test code: static int __init __attribute__((optimize("O0"))) test_clear_user(void) { register int t asm("v1"); char *test; int j, k; pr_info("\n\n\nTesting clear_user\n"); test = vmalloc(PAGE_SIZE); for (j = 256; j < 512; j++) { t = 0xa5a5a5a5; if ((k = clear_user(test + PAGE_SIZE - 256, j)) != j - 256) { pr_err("clear_user (%px %d) returned %d\n", test + PAGE_SIZE - 256, j, k); } if (t != 0xa5a5a5a5) { pr_err("v1 was clobbered to 0x%x!\n", t); } } return 0; } late_initcall(test_clear_user); Which demonstrates that v1 is indeed clobbered (MIPS64): Testing clear_user v1 was clobbered to 0x1! v1 was clobbered to 0x2! v1 was clobbered to 0x3! v1 was clobbered to 0x4! v1 was clobbered to 0x5! v1 was clobbered to 0x6! v1 was clobbered to 0x7! Since the number of bytes that could not be set is already contained in a2, the andi placing a value in v1 is not necessary and actively harmful in clobbering v1. Reported-by: James Hogan Signed-off-by: Matt Redfearn Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: stable@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/19109/ Signed-off-by: James Hogan Signed-off-by: Greg Kroah-Hartman --- arch/mips/lib/memset.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S index c6b2e3178b26..2b1bf93b5c80 100644 --- a/arch/mips/lib/memset.S +++ b/arch/mips/lib/memset.S @@ -257,7 +257,7 @@ .Llast_fixup\@: jr ra - andi v1, a2, STORMASK + nop .Lsmall_fixup\@: PTR_SUBU a2, t1, a0 -- GitLab From 73de98fb50b077934776563c97b75d6f764a2066 Mon Sep 17 00:00:00 2001 From: Michael Neuling Date: Wed, 11 Apr 2018 13:37:58 +1000 Subject: [PATCH 1492/1834] powerpc/eeh: Fix enabling bridge MMIO windows commit 13a83eac373c49c0a081cbcd137e79210fe78acd upstream. On boot we save the configuration space of PCIe bridges. We do this so when we get an EEH event and everything gets reset that we can restore them. Unfortunately we save this state before we've enabled the MMIO space on the bridges. Hence if we have to reset the bridge when we come back MMIO is not enabled and we end up taking an PE freeze when the driver starts accessing again. This patch forces the memory/MMIO and bus mastering on when restoring bridges on EEH. Ideally we'd do this correctly by saving the configuration space writes later, but that will have to come later in a larger EEH rewrite. For now we have this simple fix. The original bug can be triggered on a boston machine by doing: echo 0x8000000000000000 > /sys/kernel/debug/powerpc/PCI0001/err_injct_outbound On boston, this PHB has a PCIe switch on it. Without this patch, you'll see two EEH events, 1 expected and 1 the failure we are fixing here. The second EEH event causes the anything under the PHB to disappear (i.e. the i40e eth). With this patch, only 1 EEH event occurs and devices properly recover. Fixes: 652defed4875 ("powerpc/eeh: Check PCIe link after reset") Cc: stable@vger.kernel.org # v3.11+ Reported-by: Pridhiviraj Paidipeddi Signed-off-by: Michael Neuling Acked-by: Russell Currey Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/kernel/eeh_pe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kernel/eeh_pe.c b/arch/powerpc/kernel/eeh_pe.c index de7d091c4c31..1abd8dd77ec1 100644 --- a/arch/powerpc/kernel/eeh_pe.c +++ b/arch/powerpc/kernel/eeh_pe.c @@ -795,7 +795,8 @@ static void eeh_restore_bridge_bars(struct eeh_dev *edev) eeh_ops->write_config(pdn, 15*4, 4, edev->config_space[15]); /* PCI Command: 0x4 */ - eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1]); + eeh_ops->write_config(pdn, PCI_COMMAND, 4, edev->config_space[1] | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); /* Check the PCIe link is ready */ eeh_bridge_check_link(edev); -- GitLab From 22578e220a870d7e677839eab207185faec3144a Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 16 Apr 2018 23:25:19 +1000 Subject: [PATCH 1493/1834] powerpc/lib: Fix off-by-one in alternate feature patching commit b8858581febb050688e276b956796bc4a78299ed upstream. When we patch an alternate feature section, we have to adjust any relative branches that branch out of the alternate section. But currently we have a bug if we have a branch that points to past the last instruction of the alternate section, eg: FTR_SECTION_ELSE 1: b 2f or 6,6,6 2: ALT_FTR_SECTION_END(...) nop This will result in a relative branch at 1 with a target that equals the end of the alternate section. That branch does not need adjusting when it's moved to the non-else location. Currently we do adjust it, resulting in a branch that goes off into the link-time location of the else section, which is junk. The fix is to not patch branches that have a target == end of the alternate section. Fixes: d20fe50a7b3c ("KVM: PPC: Book3S HV: Branch inside feature section") Fixes: 9b1a735de64c ("powerpc: Add logic to patch alternative feature sections") Cc: stable@vger.kernel.org # v2.6.27+ Signed-off-by: Michael Ellerman Signed-off-by: Greg Kroah-Hartman --- arch/powerpc/lib/feature-fixups.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/lib/feature-fixups.c b/arch/powerpc/lib/feature-fixups.c index e86bfa111f3c..46c8338a61bc 100644 --- a/arch/powerpc/lib/feature-fixups.c +++ b/arch/powerpc/lib/feature-fixups.c @@ -55,7 +55,7 @@ static int patch_alt_instruction(unsigned int *src, unsigned int *dest, unsigned int *target = (unsigned int *)branch_target(src); /* Branch within the section doesn't need translating */ - if (target < alt_start || target >= alt_end) { + if (target < alt_start || target > alt_end) { instr = translate_branch(dest, src); if (!instr) return 1; -- GitLab From 8c72cf489860f43bc974de9ecbc594c567bbe49a Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 12 Apr 2018 17:22:23 +0200 Subject: [PATCH 1494/1834] udf: Fix leak of UTF-16 surrogates into encoded strings commit 44f06ba8297c7e9dfd0e49b40cbe119113cca094 upstream. OSTA UDF specification does not mention whether the CS0 charset in case of two bytes per character encoding should be treated in UTF-16 or UCS-2. The sample code in the standard does not treat UTF-16 surrogates in any special way but on systems such as Windows which work in UTF-16 internally, filenames would be treated as being in UTF-16 effectively. In Linux it is more difficult to handle characters outside of Base Multilingual plane (beyond 0xffff) as NLS framework works with 2-byte characters only. Just make sure we don't leak UTF-16 surrogates into the resulting string when loading names from the filesystem for now. CC: stable@vger.kernel.org # >= v4.6 Reported-by: Mingye Wang Signed-off-by: Jan Kara Signed-off-by: Greg Kroah-Hartman --- fs/udf/unicode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c index 695389a4fc23..3a3be23689b3 100644 --- a/fs/udf/unicode.c +++ b/fs/udf/unicode.c @@ -28,6 +28,9 @@ #include "udf_sb.h" +#define SURROGATE_MASK 0xfffff800 +#define SURROGATE_PAIR 0x0000d800 + static int udf_uni2char_utf8(wchar_t uni, unsigned char *out, int boundlen) @@ -37,6 +40,9 @@ static int udf_uni2char_utf8(wchar_t uni, if (boundlen <= 0) return -ENAMETOOLONG; + if ((uni & SURROGATE_MASK) == SURROGATE_PAIR) + return -EINVAL; + if (uni < 0x80) { out[u_len++] = (unsigned char)uni; } else if (uni < 0x800) { -- GitLab From 02d20e670e6ba449ff2d75c3c91771b68543bb71 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Apr 2018 23:56:44 -0400 Subject: [PATCH 1495/1834] jffs2_kill_sb(): deal with failed allocations commit c66b23c2840446a82c389e4cb1a12eb2a71fa2e4 upstream. jffs2_fill_super() might fail to allocate jffs2_sb_info; jffs2_kill_sb() must survive that. Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/jffs2/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 5ef21f4c4c77..59c019a148f6 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -342,7 +342,7 @@ static void jffs2_put_super (struct super_block *sb) static void jffs2_kill_sb(struct super_block *sb) { struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - if (!(sb->s_flags & MS_RDONLY)) + if (c && !(sb->s_flags & MS_RDONLY)) jffs2_stop_garbage_collect_thread(c); kill_mtd_super(sb); kfree(c); -- GitLab From f3ba3eaaee8bc8c07d58d2a6050f9892ba01c306 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 2 Apr 2018 23:50:31 -0400 Subject: [PATCH 1496/1834] hypfs_kill_super(): deal with failed allocations commit a24cd490739586a7d2da3549a1844e1d7c4f4fc4 upstream. hypfs_fill_super() might fail to allocate sbi; hypfs_kill_super() should not oops on that. Cc: stable@vger.kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- arch/s390/hypfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 09bccb224d03..2a17123130d3 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -318,7 +318,7 @@ static void hypfs_kill_super(struct super_block *sb) if (sb->s_root) hypfs_delete_tree(sb->s_root); - if (sb_info->update_file) + if (sb_info && sb_info->update_file) hypfs_remove(sb_info->update_file); kfree(sb->s_fs_info); sb->s_fs_info = NULL; -- GitLab From e2210c5414a8e05e14c5864180ec215dec343828 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 3 Apr 2018 00:13:17 -0400 Subject: [PATCH 1497/1834] orangefs_kill_sb(): deal with allocation failures commit 659038428cb43a66e3eff71e2c845c9de3611a98 upstream. orangefs_fill_sb() might've failed to allocate ORANGEFS_SB(s); don't oops in that case. Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/orangefs/super.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/orangefs/super.c b/fs/orangefs/super.c index 629d8c917fa6..6e35ef6521b4 100644 --- a/fs/orangefs/super.c +++ b/fs/orangefs/super.c @@ -559,6 +559,11 @@ void orangefs_kill_sb(struct super_block *sb) /* provided sb cleanup */ kill_anon_super(sb); + if (!ORANGEFS_SB(sb)) { + mutex_lock(&orangefs_request_mutex); + mutex_unlock(&orangefs_request_mutex); + return; + } /* * issue the unmount to userspace to tell it to remove the * dynamic mount info it has for this superblock -- GitLab From 463f845986289852fa7a38a5ae78216a64b569c6 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 3 Apr 2018 01:15:46 -0400 Subject: [PATCH 1498/1834] rpc_pipefs: fix double-dput() commit 4a3877c4cedd95543f8726b0a98743ed8db0c0fb upstream. if we ever hit rpc_gssd_dummy_depopulate() dentry passed to it has refcount equal to 1. __rpc_rmpipe() drops it and dput() done after that hits an already freed dentry. Cc: stable@kernel.org Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- net/sunrpc/rpc_pipe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 61a504fb1ae2..34f94052c519 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1375,6 +1375,7 @@ rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry) struct dentry *clnt_dir = pipe_dentry->d_parent; struct dentry *gssd_dir = clnt_dir->d_parent; + dget(pipe_dentry); __rpc_rmpipe(d_inode(clnt_dir), pipe_dentry); __rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1); __rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1); -- GitLab From 3f68e22e9bd1f06a0b752c742bfab530fcd8bd74 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 19 Apr 2018 22:03:08 -0400 Subject: [PATCH 1499/1834] Don't leak MNT_INTERNAL away from internal mounts commit 16a34adb9392b2fe4195267475ab5b472e55292c upstream. We want it only for the stuff created by SB_KERNMOUNT mounts, *not* for their copies. As it is, creating a deep stack of bindings of /proc/*/ns/* somewhere in a new namespace and exiting yields a stack overflow. Cc: stable@kernel.org Reported-by: Alexander Aring Bisected-by: Kirill Tkhai Tested-by: Kirill Tkhai Tested-by: Alexander Aring Signed-off-by: Al Viro Signed-off-by: Greg Kroah-Hartman --- fs/namespace.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/namespace.c b/fs/namespace.c index d7360f9897b4..6c873b330a93 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1033,7 +1033,8 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, goto out_free; } - mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED); + mnt->mnt.mnt_flags = old->mnt.mnt_flags; + mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL); /* Don't allow unprivileged users to change mount flags */ if (flag & CL_UNPRIVILEGED) { mnt->mnt.mnt_flags |= MNT_LOCK_ATIME; -- GitLab From 858052b1f2f2d6a07af920b670a31fc8d5043755 Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Fri, 20 Apr 2018 14:55:59 -0700 Subject: [PATCH 1500/1834] autofs: mount point create should honour passed in mode commit 1e6306652ba18723015d1b4967fe9de55f042499 upstream. The autofs file system mkdir inode operation blindly sets the created directory mode to S_IFDIR | 0555, ingoring the passed in mode, which can cause selinux dac_override denials. But the function also checks if the caller is the daemon (as no-one else should be able to do anything here) so there's no point in not honouring the passed in mode, allowing the daemon to set appropriate mode when required. Link: http://lkml.kernel.org/r/152361593601.8051.14014139124905996173.stgit@pluto.themaw.net Signed-off-by: Ian Kent Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- fs/autofs4/root.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index a11f73174877..6182d693cf43 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -746,7 +746,7 @@ static int autofs4_dir_mkdir(struct inode *dir, autofs4_del_active(dentry); - inode = autofs4_get_inode(dir->i_sb, S_IFDIR | 0555); + inode = autofs4_get_inode(dir->i_sb, S_IFDIR | mode); if (!inode) return -ENOMEM; d_add(dentry, inode); -- GitLab From f4c86fa0e2c3ed3eb4fbbb145ce9dabeec12c2c7 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 20 Apr 2018 14:56:20 -0700 Subject: [PATCH 1501/1834] mm/filemap.c: fix NULL pointer in page_cache_tree_insert() commit abc1be13fd113ddef5e2d807a466286b864caed3 upstream. f2fs specifies the __GFP_ZERO flag for allocating some of its pages. Unfortunately, the page cache also uses the mapping's GFP flags for allocating radix tree nodes. It always masked off the __GFP_HIGHMEM flag, and masks off __GFP_ZERO in some paths, but not all. That causes radix tree nodes to be allocated with a NULL list_head, which causes backtraces like: __list_del_entry+0x30/0xd0 list_lru_del+0xac/0x1ac page_cache_tree_insert+0xd8/0x110 The __GFP_DMA and __GFP_DMA32 flags would also be able to sneak through if they are ever used. Fix them all by using GFP_RECLAIM_MASK at the innermost location, and remove it from earlier in the callchain. Link: http://lkml.kernel.org/r/20180411060320.14458-2-willy@infradead.org Fixes: 449dd6984d0e ("mm: keep page cache radix tree nodes in check") Signed-off-by: Matthew Wilcox Reported-by: Chris Fries Debugged-by: Minchan Kim Acked-by: Johannes Weiner Acked-by: Michal Hocko Reviewed-by: Jan Kara Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- mm/filemap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index edfb90e3830c..6d2f561d517c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -616,7 +616,7 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask) VM_BUG_ON_PAGE(!PageLocked(new), new); VM_BUG_ON_PAGE(new->mapping, new); - error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); + error = radix_tree_preload(gfp_mask & GFP_RECLAIM_MASK); if (!error) { struct address_space *mapping = old->mapping; void (*freepage)(struct page *); @@ -672,7 +672,7 @@ static int __add_to_page_cache_locked(struct page *page, return error; } - error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM); + error = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK); if (error) { if (!huge) mem_cgroup_cancel_charge(page, memcg, false); @@ -1247,8 +1247,7 @@ struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset, if (fgp_flags & FGP_ACCESSED) __SetPageReferenced(page); - err = add_to_page_cache_lru(page, mapping, offset, - gfp_mask & GFP_RECLAIM_MASK); + err = add_to_page_cache_lru(page, mapping, offset, gfp_mask); if (unlikely(err)) { put_page(page); page = NULL; @@ -1996,7 +1995,7 @@ static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask) if (!page) return -ENOMEM; - ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL); + ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask); if (ret == 0) ret = mapping->a_ops->readpage(file, page); else if (ret == -EEXIST) -- GitLab From 71f24a91305670bb4f22f214608c2e75aa45f99e Mon Sep 17 00:00:00 2001 From: Amir Goldstein Date: Wed, 4 Apr 2018 23:42:18 +0300 Subject: [PATCH 1502/1834] fanotify: fix logic of events on child commit 54a307ba8d3cd00a3902337ffaae28f436eeb1a4 upstream. When event on child inodes are sent to the parent inode mark and parent inode mark was not marked with FAN_EVENT_ON_CHILD, the event will not be delivered to the listener process. However, if the same process also has a mount mark, the event to the parent inode will be delivered regadless of the mount mark mask. This behavior is incorrect in the case where the mount mark mask does not contain the specific event type. For example, the process adds a mark on a directory with mask FAN_MODIFY (without FAN_EVENT_ON_CHILD) and a mount mark with mask FAN_CLOSE_NOWRITE (without FAN_ONDIR). A modify event on a file inside that directory (and inside that mount) should not create a FAN_MODIFY event, because neither of the marks requested to get that event on the file. Fixes: 1968f5eed54c ("fanotify: use both marks when possible") Cc: stable Signed-off-by: Amir Goldstein Signed-off-by: Jan Kara [natechancellor: Fix small conflict due to lack of 3cd5eca8d7a2f] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- fs/notify/fanotify/fanotify.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index e0e5f7c3c99f..8a459b179183 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -92,7 +92,7 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, u32 event_mask, void *data, int data_type) { - __u32 marks_mask, marks_ignored_mask; + __u32 marks_mask = 0, marks_ignored_mask = 0; struct path *path = data; pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p" @@ -108,24 +108,20 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark, !d_can_lookup(path->dentry)) return false; - if (inode_mark && vfsmnt_mark) { - marks_mask = (vfsmnt_mark->mask | inode_mark->mask); - marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask); - } else if (inode_mark) { - /* - * if the event is for a child and this inode doesn't care about - * events on the child, don't send it! - */ - if ((event_mask & FS_EVENT_ON_CHILD) && - !(inode_mark->mask & FS_EVENT_ON_CHILD)) - return false; - marks_mask = inode_mark->mask; - marks_ignored_mask = inode_mark->ignored_mask; - } else if (vfsmnt_mark) { - marks_mask = vfsmnt_mark->mask; - marks_ignored_mask = vfsmnt_mark->ignored_mask; - } else { - BUG(); + /* + * if the event is for a child and this inode doesn't care about + * events on the child, don't send it! + */ + if (inode_mark && + (!(event_mask & FS_EVENT_ON_CHILD) || + (inode_mark->mask & FS_EVENT_ON_CHILD))) { + marks_mask |= inode_mark->mask; + marks_ignored_mask |= inode_mark->ignored_mask; + } + + if (vfsmnt_mark) { + marks_mask |= vfsmnt_mark->mask; + marks_ignored_mask |= vfsmnt_mark->ignored_mask; } if (d_is_dir(path->dentry) && -- GitLab From 18484eb932e2bdbdab83700c6d7d68f9f743f4c8 Mon Sep 17 00:00:00 2001 From: Greg Thelen Date: Fri, 20 Apr 2018 14:55:42 -0700 Subject: [PATCH 1503/1834] writeback: safer lock nesting commit 2e898e4c0a3897ccd434adac5abb8330194f527b upstream. lock_page_memcg()/unlock_page_memcg() use spin_lock_irqsave/restore() if the page's memcg is undergoing move accounting, which occurs when a process leaves its memcg for a new one that has memory.move_charge_at_immigrate set. unlocked_inode_to_wb_begin,end() use spin_lock_irq/spin_unlock_irq() if the given inode is switching writeback domains. Switches occur when enough writes are issued from a new domain. This existing pattern is thus suspicious: lock_page_memcg(page); unlocked_inode_to_wb_begin(inode, &locked); ... unlocked_inode_to_wb_end(inode, locked); unlock_page_memcg(page); If both inode switch and process memcg migration are both in-flight then unlocked_inode_to_wb_end() will unconditionally enable interrupts while still holding the lock_page_memcg() irq spinlock. This suggests the possibility of deadlock if an interrupt occurs before unlock_page_memcg(). truncate __cancel_dirty_page lock_page_memcg unlocked_inode_to_wb_begin unlocked_inode_to_wb_end end_page_writeback test_clear_page_writeback lock_page_memcg unlock_page_memcg Due to configuration limitations this deadlock is not currently possible because we don't mix cgroup writeback (a cgroupv2 feature) and memory.move_charge_at_immigrate (a cgroupv1 feature). If the kernel is hacked to always claim inode switching and memcg moving_account, then this script triggers lockup in less than a minute: cd /mnt/cgroup/memory mkdir a b echo 1 > a/memory.move_charge_at_immigrate echo 1 > b/memory.move_charge_at_immigrate ( echo $BASHPID > a/cgroup.procs while true; do dd if=/dev/zero of=/mnt/big bs=1M count=256 done ) & while true; do sync done & sleep 1h & SLEEP=$! while true; do echo $SLEEP > a/cgroup.procs echo $SLEEP > b/cgroup.procs done The deadlock does not seem possible, so it's debatable if there's any reason to modify the kernel. I suggest we should to prevent future surprises. And Wang Long said "this deadlock occurs three times in our environment", so there's more reason to apply this, even to stable. Stable 4.4 has minor conflicts applying this patch. For a clean 4.4 patch see "[PATCH for-4.4] writeback: safer lock nesting" https://lkml.org/lkml/2018/4/11/146 Wang Long said "this deadlock occurs three times in our environment" [gthelen@google.com: v4] Link: http://lkml.kernel.org/r/20180411084653.254724-1-gthelen@google.com [akpm@linux-foundation.org: comment tweaks, struct initialization simplification] Change-Id: Ibb773e8045852978f6207074491d262f1b3fb613 Link: http://lkml.kernel.org/r/20180410005908.167976-1-gthelen@google.com Fixes: 682aa8e1a6a1 ("writeback: implement unlocked_inode_to_wb transaction and use it for stat updates") Signed-off-by: Greg Thelen Reported-by: Wang Long Acked-by: Wang Long Acked-by: Michal Hocko Reviewed-by: Andrew Morton Cc: Johannes Weiner Cc: Tejun Heo Cc: Nicholas Piggin Cc: [v4.2+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds [natechancellor: Adjust context due to lack of b93b016313b3b] Signed-off-by: Nathan Chancellor Signed-off-by: Greg Kroah-Hartman --- fs/fs-writeback.c | 7 ++++--- include/linux/backing-dev-defs.h | 5 +++++ include/linux/backing-dev.h | 30 ++++++++++++++++-------------- mm/page-writeback.c | 18 +++++++++--------- 4 files changed, 34 insertions(+), 26 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 0703a1179847..3d8b35f28a9b 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -745,11 +745,12 @@ int inode_congested(struct inode *inode, int cong_bits) */ if (inode && inode_to_wb_is_valid(inode)) { struct bdi_writeback *wb; - bool locked, congested; + struct wb_lock_cookie lock_cookie = {}; + bool congested; - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &lock_cookie); congested = wb_congested(wb, cong_bits); - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &lock_cookie); return congested; } diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index c357f27d5483..32728ff8095c 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h @@ -191,6 +191,11 @@ static inline void set_bdi_congested(struct backing_dev_info *bdi, int sync) set_wb_congested(bdi->wb.congested, sync); } +struct wb_lock_cookie { + bool locked; + unsigned long flags; +}; + #ifdef CONFIG_CGROUP_WRITEBACK /** diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 43b93a947e61..63f17b106a4a 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -366,7 +366,7 @@ static inline struct bdi_writeback *inode_to_wb(struct inode *inode) /** * unlocked_inode_to_wb_begin - begin unlocked inode wb access transaction * @inode: target inode - * @lockedp: temp bool output param, to be passed to the end function + * @cookie: output param, to be passed to the end function * * The caller wants to access the wb associated with @inode but isn't * holding inode->i_lock, mapping->tree_lock or wb->list_lock. This @@ -374,12 +374,12 @@ static inline struct bdi_writeback *inode_to_wb(struct inode *inode) * association doesn't change until the transaction is finished with * unlocked_inode_to_wb_end(). * - * The caller must call unlocked_inode_to_wb_end() with *@lockdep - * afterwards and can't sleep during transaction. IRQ may or may not be - * disabled on return. + * The caller must call unlocked_inode_to_wb_end() with *@cookie afterwards and + * can't sleep during the transaction. IRQs may or may not be disabled on + * return. */ static inline struct bdi_writeback * -unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) +unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie) { rcu_read_lock(); @@ -387,10 +387,10 @@ unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) * Paired with store_release in inode_switch_wb_work_fn() and * ensures that we see the new wb if we see cleared I_WB_SWITCH. */ - *lockedp = smp_load_acquire(&inode->i_state) & I_WB_SWITCH; + cookie->locked = smp_load_acquire(&inode->i_state) & I_WB_SWITCH; - if (unlikely(*lockedp)) - spin_lock_irq(&inode->i_mapping->tree_lock); + if (unlikely(cookie->locked)) + spin_lock_irqsave(&inode->i_mapping->tree_lock, cookie->flags); /* * Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock. @@ -402,12 +402,13 @@ unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) /** * unlocked_inode_to_wb_end - end inode wb access transaction * @inode: target inode - * @locked: *@lockedp from unlocked_inode_to_wb_begin() + * @cookie: @cookie from unlocked_inode_to_wb_begin() */ -static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked) +static inline void unlocked_inode_to_wb_end(struct inode *inode, + struct wb_lock_cookie *cookie) { - if (unlikely(locked)) - spin_unlock_irq(&inode->i_mapping->tree_lock); + if (unlikely(cookie->locked)) + spin_unlock_irqrestore(&inode->i_mapping->tree_lock, cookie->flags); rcu_read_unlock(); } @@ -454,12 +455,13 @@ static inline struct bdi_writeback *inode_to_wb(struct inode *inode) } static inline struct bdi_writeback * -unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) +unlocked_inode_to_wb_begin(struct inode *inode, struct wb_lock_cookie *cookie) { return inode_to_wb(inode); } -static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked) +static inline void unlocked_inode_to_wb_end(struct inode *inode, + struct wb_lock_cookie *cookie) { } diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 439cc63ad903..807236aed275 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -2506,13 +2506,13 @@ void account_page_redirty(struct page *page) if (mapping && mapping_cap_account_dirty(mapping)) { struct inode *inode = mapping->host; struct bdi_writeback *wb; - bool locked; + struct wb_lock_cookie cookie = {}; - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &cookie); current->nr_dirtied--; dec_node_page_state(page, NR_DIRTIED); dec_wb_stat(wb, WB_DIRTIED); - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &cookie); } } EXPORT_SYMBOL(account_page_redirty); @@ -2618,15 +2618,15 @@ void cancel_dirty_page(struct page *page) if (mapping_cap_account_dirty(mapping)) { struct inode *inode = mapping->host; struct bdi_writeback *wb; - bool locked; + struct wb_lock_cookie cookie = {}; lock_page_memcg(page); - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &cookie); if (TestClearPageDirty(page)) account_page_cleaned(page, mapping, wb); - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &cookie); unlock_page_memcg(page); } else { ClearPageDirty(page); @@ -2658,7 +2658,7 @@ int clear_page_dirty_for_io(struct page *page) if (mapping && mapping_cap_account_dirty(mapping)) { struct inode *inode = mapping->host; struct bdi_writeback *wb; - bool locked; + struct wb_lock_cookie cookie = {}; /* * Yes, Virginia, this is indeed insane. @@ -2695,7 +2695,7 @@ int clear_page_dirty_for_io(struct page *page) * always locked coming in here, so we get the desired * exclusion. */ - wb = unlocked_inode_to_wb_begin(inode, &locked); + wb = unlocked_inode_to_wb_begin(inode, &cookie); if (TestClearPageDirty(page)) { mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY); dec_node_page_state(page, NR_FILE_DIRTY); @@ -2703,7 +2703,7 @@ int clear_page_dirty_for_io(struct page *page) dec_wb_stat(wb, WB_RECLAIMABLE); ret = 1; } - unlocked_inode_to_wb_end(inode, locked); + unlocked_inode_to_wb_end(inode, &cookie); return ret; } return TestClearPageDirty(page); -- GitLab From 8d7f1fde9d8df8ae9393c6902470222305ac03b0 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Sun, 7 May 2017 00:14:22 -0700 Subject: [PATCH 1504/1834] block/mq: fix potential deadlock during cpu hotplug commit 51d638b1f56a0bfd9219800620994794a1a2b219 upstream. This can be triggered by hot-unplug one cpu. ====================================================== [ INFO: possible circular locking dependency detected ] 4.11.0+ #17 Not tainted ------------------------------------------------------- step_after_susp/2640 is trying to acquire lock: (all_q_mutex){+.+...}, at: [] blk_mq_queue_reinit_work+0x18/0x110 but task is already holding lock: (cpu_hotplug.lock){+.+.+.}, at: [] cpu_hotplug_begin+0x7f/0xe0 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (cpu_hotplug.lock){+.+.+.}: lock_acquire+0x11c/0x230 __mutex_lock+0x92/0x990 mutex_lock_nested+0x1b/0x20 get_online_cpus+0x64/0x80 blk_mq_init_allocated_queue+0x3a0/0x4e0 blk_mq_init_queue+0x3a/0x60 loop_add+0xe5/0x280 loop_init+0x124/0x177 do_one_initcall+0x53/0x1c0 kernel_init_freeable+0x1e3/0x27f kernel_init+0xe/0x100 ret_from_fork+0x31/0x40 -> #0 (all_q_mutex){+.+...}: __lock_acquire+0x189a/0x18a0 lock_acquire+0x11c/0x230 __mutex_lock+0x92/0x990 mutex_lock_nested+0x1b/0x20 blk_mq_queue_reinit_work+0x18/0x110 blk_mq_queue_reinit_dead+0x1c/0x20 cpuhp_invoke_callback+0x1f2/0x810 cpuhp_down_callbacks+0x42/0x80 _cpu_down+0xb2/0xe0 freeze_secondary_cpus+0xb6/0x390 suspend_devices_and_enter+0x3b3/0xa40 pm_suspend+0x129/0x490 state_store+0x82/0xf0 kobj_attr_store+0xf/0x20 sysfs_kf_write+0x45/0x60 kernfs_fop_write+0x135/0x1c0 __vfs_write+0x37/0x160 vfs_write+0xcd/0x1d0 SyS_write+0x58/0xc0 do_syscall_64+0x8f/0x710 return_from_SYSCALL_64+0x0/0x7a other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(cpu_hotplug.lock); lock(all_q_mutex); lock(cpu_hotplug.lock); lock(all_q_mutex); *** DEADLOCK *** 8 locks held by step_after_susp/2640: #0: (sb_writers#6){.+.+.+}, at: [] vfs_write+0x1ad/0x1d0 #1: (&of->mutex){+.+.+.}, at: [] kernfs_fop_write+0x101/0x1c0 #2: (s_active#166){.+.+.+}, at: [] kernfs_fop_write+0x109/0x1c0 #3: (pm_mutex){+.+...}, at: [] pm_suspend+0x21d/0x490 #4: (acpi_scan_lock){+.+.+.}, at: [] acpi_scan_lock_acquire+0x17/0x20 #5: (cpu_add_remove_lock){+.+.+.}, at: [] freeze_secondary_cpus+0x27/0x390 #6: (cpu_hotplug.dep_map){++++++}, at: [] cpu_hotplug_begin+0x5/0xe0 #7: (cpu_hotplug.lock){+.+.+.}, at: [] cpu_hotplug_begin+0x7f/0xe0 stack backtrace: CPU: 3 PID: 2640 Comm: step_after_susp Not tainted 4.11.0+ #17 Hardware name: Dell Inc. OptiPlex 7040/0JCTF8, BIOS 1.4.9 09/12/2016 Call Trace: dump_stack+0x99/0xce print_circular_bug+0x1fa/0x270 __lock_acquire+0x189a/0x18a0 lock_acquire+0x11c/0x230 ? lock_acquire+0x11c/0x230 ? blk_mq_queue_reinit_work+0x18/0x110 ? blk_mq_queue_reinit_work+0x18/0x110 __mutex_lock+0x92/0x990 ? blk_mq_queue_reinit_work+0x18/0x110 ? kmem_cache_free+0x2cb/0x330 ? anon_transport_class_unregister+0x20/0x20 ? blk_mq_queue_reinit_work+0x110/0x110 mutex_lock_nested+0x1b/0x20 ? mutex_lock_nested+0x1b/0x20 blk_mq_queue_reinit_work+0x18/0x110 blk_mq_queue_reinit_dead+0x1c/0x20 cpuhp_invoke_callback+0x1f2/0x810 ? __flow_cache_shrink+0x160/0x160 cpuhp_down_callbacks+0x42/0x80 _cpu_down+0xb2/0xe0 freeze_secondary_cpus+0xb6/0x390 suspend_devices_and_enter+0x3b3/0xa40 ? rcu_read_lock_sched_held+0x79/0x80 pm_suspend+0x129/0x490 state_store+0x82/0xf0 kobj_attr_store+0xf/0x20 sysfs_kf_write+0x45/0x60 kernfs_fop_write+0x135/0x1c0 __vfs_write+0x37/0x160 ? rcu_read_lock_sched_held+0x79/0x80 ? rcu_sync_lockdep_assert+0x2f/0x60 ? __sb_start_write+0xd9/0x1c0 ? vfs_write+0x1ad/0x1d0 vfs_write+0xcd/0x1d0 SyS_write+0x58/0xc0 ? rcu_read_lock_sched_held+0x79/0x80 do_syscall_64+0x8f/0x710 ? trace_hardirqs_on_thunk+0x1a/0x1c entry_SYSCALL64_slow_path+0x25/0x25 The cpu hotplug path will hold cpu_hotplug.lock and then reinit all exiting queues for blk mq w/ all_q_mutex, however, blk_mq_init_allocated_queue() will contend these two locks in the inversion order. This is due to commit eabe06595d62 (blk/mq: Cure cpu hotplug lock inversion), it fixes a cpu hotplug lock inversion issue because of hotplug rework, however the hotplug rework is still work-in-progress and lives in a -tip branch and mainline cannot yet trigger that splat. The commit breaks the linus's tree in the merge window, so this patch reverts the lock order and avoids to splat linus's tree. Cc: Jens Axboe Cc: Peter Zijlstra (Intel) Cc: Thomas Gleixner Signed-off-by: Wanpeng Li Signed-off-by: Jens Axboe Cc: Thierry Escande Signed-off-by: Greg Kroah-Hartman --- block/blk-mq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/blk-mq.c b/block/blk-mq.c index 5ca4e4cd8cba..24fc09cf7f17 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -2019,15 +2019,15 @@ struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, blk_mq_init_cpu_queues(q, set->nr_hw_queues); - mutex_lock(&all_q_mutex); get_online_cpus(); + mutex_lock(&all_q_mutex); list_add_tail(&q->all_q_node, &all_q_list); blk_mq_add_queue_tag_set(set, q); blk_mq_map_swqueue(q, cpu_online_mask); - put_online_cpus(); mutex_unlock(&all_q_mutex); + put_online_cpus(); return q; -- GitLab From 5cd35f3eb5384f30d1a10d87f088bacd8839c22b Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 24 Apr 2018 09:34:18 +0200 Subject: [PATCH 1505/1834] Linux 4.9.96 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 1aeec9df709d..50ae573e8951 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 4 PATCHLEVEL = 9 -SUBLEVEL = 95 +SUBLEVEL = 96 EXTRAVERSION = NAME = Roaring Lionus -- GitLab From 6d51fc3f0162454daf0b580e6d220e9b906bd525 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Tue, 23 Jan 2018 14:11:56 +0530 Subject: [PATCH 1506/1834] regulator: cpr4-apss: Modify suspend/resume ops Use device suspend/resume ops rather than platform device suspend/resume ops. Change-Id: I82444f04c62caefe98b9248e9f3497daa6451f59 Signed-off-by: Tirupathi Reddy --- drivers/regulator/cpr4-apss-regulator.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/regulator/cpr4-apss-regulator.c b/drivers/regulator/cpr4-apss-regulator.c index 1f8f8be8e9c6..d5a0e33078d4 100644 --- a/drivers/regulator/cpr4-apss-regulator.c +++ b/drivers/regulator/cpr4-apss-regulator.c @@ -1840,20 +1840,29 @@ static int cpr4_apss_init_controller(struct cpr3_controller *ctrl) return 0; } -static int cpr4_apss_regulator_suspend(struct platform_device *pdev, - pm_message_t state) +#if CONFIG_PM +static int cpr4_apss_regulator_suspend(struct device *dev) { - struct cpr3_controller *ctrl = platform_get_drvdata(pdev); + struct cpr3_controller *ctrl = dev_get_drvdata(dev); return cpr3_regulator_suspend(ctrl); } -static int cpr4_apss_regulator_resume(struct platform_device *pdev) +static int cpr4_apss_regulator_resume(struct device *dev) { - struct cpr3_controller *ctrl = platform_get_drvdata(pdev); + struct cpr3_controller *ctrl = dev_get_drvdata(dev); return cpr3_regulator_resume(ctrl); } +#else +#define cpr4_apss_regulator_suspend NULL +#define cpr4_apss_regulator_resume NULL +#endif + +static const struct dev_pm_ops cpr4_apss_regulator_pm_ops = { + .suspend = cpr4_apss_regulator_suspend, + .resume = cpr4_apss_regulator_resume, +}; /* Data corresponds to the SoC revision */ static const struct of_device_id cpr4_regulator_match_table[] = { @@ -1977,11 +1986,10 @@ static struct platform_driver cpr4_apss_regulator_driver = { .name = "qcom,cpr4-apss-regulator", .of_match_table = cpr4_regulator_match_table, .owner = THIS_MODULE, + .pm = &cpr4_apss_regulator_pm_ops, }, .probe = cpr4_apss_regulator_probe, .remove = cpr4_apss_regulator_remove, - .suspend = cpr4_apss_regulator_suspend, - .resume = cpr4_apss_regulator_resume, }; static int cpr4_regulator_init(void) -- GitLab From e782d53fb4e77d59d0969b426e3a62484c92c0ca Mon Sep 17 00:00:00 2001 From: Shubhashree Dhar Date: Mon, 23 Apr 2018 16:25:10 +0530 Subject: [PATCH 1507/1834] sde: rotator: Add null pointer checks Pointers in some cases are dereferenced even after freeing memory region pointed by them. Assign NULL to free pointers and perform proper NULL pointer checks. Change-Id: Id9caef8af0c9d06e40e99ed71db68197fc6cf4f4 Signed-off-by: Shubhashree Dhar --- .../platform/msm/sde/rotator/sde_rotator_dev.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index a46194f62ada..dfb169c79c07 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1084,6 +1084,7 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( mutex_unlock(&rot_dev->lock); error_lock: kfree(ctx); + ctx = NULL; return ERR_PTR(ret); } @@ -1096,10 +1097,18 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, struct file *file) { - struct sde_rotator_device *rot_dev = ctx->rot_dev; - u32 session_id = ctx->session_id; + struct sde_rotator_device *rot_dev; + u32 session_id; struct list_head *curr, *next; + if (!ctx) { + SDEROT_DBG("ctx is NULL\n"); + return -EINVAL; + } + + rot_dev = ctx->rot_dev; + session_id = ctx->session_id; + ATRACE_END(ctx->kobj.name); SDEDEV_DBG(rot_dev->dev, "release s:%d\n", session_id); -- GitLab From 0eb0a0c183e1c79fc3c3dcea265ac81d5d94a326 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Tue, 24 Apr 2018 14:11:53 +0530 Subject: [PATCH 1508/1834] msm: kgsl: Track RSCC sleep sequence state RSCC wake-up sequence should only be triggered if RSCC sleep sequence was done earlier i.e. they should always be balanced to make sure GMU FW, RSCC and PDC state are in sync. Add GMU_RSCC_SLEEP_SEQ_DONE GMU flag to track whether RSCC sleep sequence was done or not and trigger sleep and wake-up sequence based on this flag to make they are always balanced. Change-Id: I78d8be52a770bd6e939da91fa68b6fd01f10034e Signed-off-by: Deepak Kumar --- drivers/gpu/msm/adreno_a6xx.c | 15 ++++++++++++--- drivers/gpu/msm/kgsl_gmu.c | 4 ++-- drivers/gpu/msm/kgsl_gmu.h | 5 ++--- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 7096d7ca0280..7fd11d9366ca 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1708,6 +1708,10 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) struct device *dev = &gmu->pdev->dev; int val; + /* Only trigger wakeup sequence if sleep sequence was done earlier */ + if (!test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags)) + return 0; + kgsl_gmu_regread(device, A6XX_GPU_CC_GX_DOMAIN_MISC, &val); if (!(val & 0x1)) dev_err_ratelimited(&gmu->pdev->dev, @@ -1737,6 +1741,9 @@ static int a6xx_rpmh_power_on_gpu(struct kgsl_device *device) kgsl_gmu_regwrite(device, A6XX_GMU_RSCC_CONTROL_REQ, 0); + /* Clear sleep sequence flag as wakeup sequence is successful */ + clear_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); + /* Enable the power counter because it was disabled before slumber */ kgsl_gmu_regwrite(device, A6XX_GMU_CX_GMU_POWER_COUNTER_ENABLE, 1); @@ -1752,6 +1759,9 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) struct adreno_device *adreno_dev = ADRENO_DEVICE(device); int ret; + if (test_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags)) + return 0; + /* RSC sleep sequence is different on v1 */ if (adreno_is_a630v1(adreno_dev)) kgsl_gmu_regwrite(device, A6XX_RSCC_TIMESTAMP_UNIT1_EN_DRV0, 1); @@ -1793,6 +1803,7 @@ static int a6xx_rpmh_power_off_gpu(struct kgsl_device *device) test_bit(ADRENO_LM_CTRL, &adreno_dev->pwrctrl_flag)) kgsl_gmu_regwrite(device, A6XX_GMU_AO_SPARE_CNTL, 0); + set_bit(GMU_RSCC_SLEEP_SEQ_DONE, &gmu->flags); return 0; } @@ -1811,15 +1822,13 @@ static int a6xx_gmu_fw_start(struct kgsl_device *device, unsigned int chipid = 0; switch (boot_state) { - case GMU_RESET: - /* fall through */ case GMU_COLD_BOOT: /* Turn on TCM retention */ kgsl_gmu_regwrite(device, A6XX_GMU_GENERAL_7, 1); if (!test_and_set_bit(GMU_BOOT_INIT_DONE, &gmu->flags)) _load_gmu_rpmh_ucode(device); - else if (boot_state != GMU_RESET) { + else { ret = a6xx_rpmh_power_on_gpu(device); if (ret) return ret; diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index dbf517a8627b..61edcc8a32dd 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1461,7 +1461,7 @@ int gmu_start(struct kgsl_device *device) gmu_irq_enable(device); ret = gpudev->rpmh_gpu_pwrctrl( - adreno_dev, GMU_FW_START, GMU_RESET, 0); + adreno_dev, GMU_FW_START, GMU_COLD_BOOT, 0); if (ret) goto error_gmu; @@ -1478,7 +1478,7 @@ int gmu_start(struct kgsl_device *device) hfi_stop(gmu); ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, - GMU_RESET, 0); + GMU_COLD_BOOT, 0); if (ret) goto error_gmu; diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 19fa9728ca67..4ef182a297f0 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -102,6 +102,7 @@ enum gmu_flags { GMU_HFI_ON = 2, GMU_FAULT = 3, GMU_DCVS_REPLAY = 4, + GMU_RSCC_SLEEP_SEQ_DONE = 5, }; /** @@ -139,13 +140,11 @@ struct rpmh_votes_t { /* * These are the different ways the GMU can boot. GMU_WARM_BOOT is waking up - * from slumber. GMU_COLD_BOOT is booting for the first time. GMU_RESET - * is a soft reset of the GMU. + * from slumber. GMU_COLD_BOOT is booting for the first time. */ enum gmu_boot { GMU_WARM_BOOT = 0, GMU_COLD_BOOT = 1, - GMU_RESET = 2 }; enum gmu_load_mode { -- GitLab From 5657f9ddd2ee311dac22d3489658c5bee494c157 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 17 Apr 2018 13:50:11 -0700 Subject: [PATCH 1509/1834] usb: dwc3: Pass USB connector type info from device tree Currently driver is using power supply property to query USB connector type. But on some targets power supply property may not be available. Hence pass the connector type info from HW platform specific device tree file using qcom,connector-type-uAB property. Change-Id: I17e18a12cb9520e36d02b207cffcd26a85f84f88 Signed-off-by: Hemant Kumar --- Documentation/devicetree/bindings/usb/msm-ssusb.txt | 1 + drivers/usb/dwc3/dwc3-msm.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/msm-ssusb.txt b/Documentation/devicetree/bindings/usb/msm-ssusb.txt index 881f9ca12a34..0cc8b00bc47f 100644 --- a/Documentation/devicetree/bindings/usb/msm-ssusb.txt +++ b/Documentation/devicetree/bindings/usb/msm-ssusb.txt @@ -82,6 +82,7 @@ Optional properties : - qcom,smmu-s1-bypass: If present, configure SMMU to bypass stage 1 translation. - qcom,no-vbus-vote-with-type-C: If present, then do not try to get and enable VBUS regulator in type-C host mode from dwc3-msm driver. +- qcom,connector-type-uAB: HW platform is using micro-AB USB connector type. Sub nodes: - Sub node for "DWC3- USB3 controller". diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 3650b988348d..48447556d691 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -3589,6 +3589,8 @@ static int dwc3_msm_probe(struct platform_device *pdev) mutex_init(&mdwc->suspend_resume_mutex); /* Mark type-C as true by default */ mdwc->type_c = true; + if (of_property_read_bool(node, "qcom,connector-type-uAB")) + mdwc->type_c = false; mdwc->usb_psy = power_supply_get_by_name("usb"); if (!mdwc->usb_psy) { -- GitLab From 794766b21bdaf16648110702ef83cd91ef69686e Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 24 Apr 2018 11:52:27 -0700 Subject: [PATCH 1510/1834] ARM: dts: msm: Add extcon handle for VBUS notification on sdxpoorwills Add gpio-usbdetect as extcon handle to receive usb device mode vbus connect/disconnect notification. Change-Id: I3f33c3406cfe1905e0f17594ebf78f9ea5d67895 Signed-off-by: Hemant Kumar --- arch/arm/boot/dts/qcom/sdxpoorwills-atp.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-atp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-atp.dtsi index 6a3b39110262..519367c0ace5 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-atp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-atp.dtsi @@ -23,3 +23,13 @@ &qnand_1 { status = "ok"; }; + +&vbus_detect { + status = "okay"; +}; + +&usb { + status = "okay"; + qcom,connector-type-uAB; + extcon = <0>, <0>, <0>, <&vbus_detect>; +}; -- GitLab From f925db278c814d850f81fd13a2fe2d1359e496e6 Mon Sep 17 00:00:00 2001 From: Ray Zhang Date: Tue, 17 Apr 2018 10:46:31 +0800 Subject: [PATCH 1511/1834] msm: clk: qcom: power on PLL when reading PLL registers Reading register of DSI PLL would fail if PLL is not powered up, so enable DSI PLL power before reading operation. CRs-Fixed: 2267622 Change-Id: Ie9933745035392744bb49241342f05a6be9daedc Signed-off-by: Ray Zhang --- drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c index 874c229910cf..7b23db46c121 100644 --- a/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c +++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-10nm.c @@ -174,6 +174,7 @@ static inline int pll_reg_read(void *context, unsigned int reg, unsigned int *val) { int rc = 0; + u32 data; struct mdss_pll_resources *rsc = context; rc = mdss_pll_resource_enable(rsc, true); @@ -182,7 +183,19 @@ static inline int pll_reg_read(void *context, unsigned int reg, return rc; } + /* + * DSI PHY/PLL should be both powered on when reading PLL + * registers. Since PHY power has been enabled in DSI PHY + * driver, only PLL power is needed to enable here. + */ + data = MDSS_PLL_REG_R(rsc->phy_base, PHY_CMN_CTRL_0); + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data | BIT(5)); + ndelay(250); + *val = MDSS_PLL_REG_R(rsc->pll_base, reg); + + MDSS_PLL_REG_W(rsc->phy_base, PHY_CMN_CTRL_0, data); + (void)mdss_pll_resource_enable(rsc, false); return rc; -- GitLab From d016c0752b244a0b96275d43ce9409af538b8c3c Mon Sep 17 00:00:00 2001 From: Avraham Stern Date: Mon, 19 Feb 2018 14:48:38 +0200 Subject: [PATCH 1512/1834] cfg80211: clear wep keys after disconnection When a low level driver calls cfg80211_disconnected(), wep keys are not cleared. As a result, following connection requests will fail since cfg80211 internal state shows a connection is still in progress. Fix this by clearing the wep keys when disconnecting. Signed-off-by: Avraham Stern Signed-off-by: Luca Coelho Signed-off-by: Johannes Berg Git-commit: 3027a8e799b20fc922496a12f8ad2f9f36a8a696 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next.git Change-Id: If86c857b350d3941e016108d44c60ab9b583f7a3 CRs-Fixed: 2229833 Signed-off-by: Zhu Jianmin --- net/wireless/sme.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 2d64e0f45d06..0dc41fdc27c8 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -1012,6 +1012,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, wdev->current_bss = NULL; wdev->ssid_len = 0; wdev->conn_owner_nlportid = 0; + kzfree(wdev->connect_keys); + wdev->connect_keys = NULL; nl80211_send_disconnected(rdev, dev, reason, ie, ie_len, from_ap); -- GitLab From 029e846b980510bf3787f31d128f601d9b65cd76 Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Thu, 19 Apr 2018 18:10:47 +0530 Subject: [PATCH 1513/1834] net: ipc_router: Remove wakeup-source for Sensor ports In high speed sensor data stream case system is not entering into suspend state due to edge and port specific wake-up sources. Add flag to check and avoid the wakeup sources for all sensor ports. CRs-Fixed: 2196601 Change-Id: Ibf642619b969925dc96e8a57e11f7e349b85c024 Signed-off-by: Arun Kumar Neelakantam --- net/ipc_router/ipc_router_core.c | 64 ++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/net/ipc_router/ipc_router_core.c b/net/ipc_router/ipc_router_core.c index f3c81c286862..34031088cfd8 100644 --- a/net/ipc_router/ipc_router_core.c +++ b/net/ipc_router/ipc_router_core.c @@ -223,6 +223,25 @@ void msm_ipc_router_set_ws_allowed(bool flag) is_wakeup_source_allowed = flag; } +/** + * is_sensor_port() - Check if the remote port is sensor service or not + * @rport: Pointer to the remote port. + * + * Return: true if the remote port is sensor service else false. + */ +static int is_sensor_port(struct msm_ipc_router_remote_port *rport) +{ + u32 svcid = 0; + + if (rport && rport->server) { + svcid = rport->server->name.service; + if (svcid == 400 || (svcid >= 256 && svcid <= 320)) + return true; + } + + return false; +} + static void init_routing_table(void) { int i; @@ -2729,7 +2748,6 @@ static void do_read_data(struct work_struct *work) struct rr_packet *pkt = NULL; struct msm_ipc_port *port_ptr; struct msm_ipc_router_remote_port *rport_ptr; - int ret; struct msm_ipc_router_xprt_info *xprt_info = container_of(work, @@ -2737,16 +2755,7 @@ static void do_read_data(struct work_struct *work) read_data); while ((pkt = rr_read(xprt_info)) != NULL) { - if (pkt->length < calc_rx_header_size(xprt_info) || - pkt->length > MAX_IPC_PKT_SIZE) { - IPC_RTR_ERR("%s: Invalid pkt length %d\n", __func__, - pkt->length); - goto read_next_pkt1; - } - ret = extract_header(pkt); - if (ret < 0) - goto read_next_pkt1; hdr = &pkt->hdr; if ((hdr->dst_node_id != IPC_ROUTER_NID_LOCAL) && @@ -4173,6 +4182,7 @@ void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt, { struct msm_ipc_router_xprt_info *xprt_info = xprt->priv; struct msm_ipc_router_xprt_work *xprt_work; + struct msm_ipc_router_remote_port *rport_ptr = NULL; struct rr_packet *pkt; int ret; @@ -4223,16 +4233,40 @@ void msm_ipc_router_xprt_notify(struct msm_ipc_router_xprt *xprt, if (!pkt) return; + if (pkt->length < calc_rx_header_size(xprt_info) || + pkt->length > MAX_IPC_PKT_SIZE) { + IPC_RTR_ERR("%s: Invalid pkt length %d\n", + __func__, pkt->length); + release_pkt(pkt); + return; + } + + ret = extract_header(pkt); + if (ret < 0) { + release_pkt(pkt); + return; + } + pkt->ws_need = false; + + if (pkt->hdr.type == IPC_ROUTER_CTRL_CMD_DATA) + rport_ptr = ipc_router_get_rport_ref(pkt->hdr.src_node_id, + pkt->hdr.src_port_id); + mutex_lock(&xprt_info->rx_lock_lhb2); list_add_tail(&pkt->list, &xprt_info->pkt_list); - if (!xprt_info->dynamic_ws) { - __pm_stay_awake(&xprt_info->ws); - pkt->ws_need = true; - } else { - if (is_wakeup_source_allowed) { + /* check every pkt is from SENSOR services or not and + * avoid holding both edge and port specific wake-up sources + */ + if (!is_sensor_port(rport_ptr)) { + if (!xprt_info->dynamic_ws) { __pm_stay_awake(&xprt_info->ws); pkt->ws_need = true; + } else { + if (is_wakeup_source_allowed) { + __pm_stay_awake(&xprt_info->ws); + pkt->ws_need = true; + } } } mutex_unlock(&xprt_info->rx_lock_lhb2); -- GitLab From d603d63beba1056f1dacc56a5360794f35f64a0f Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 15 Mar 2018 22:48:46 +0530 Subject: [PATCH 1514/1834] drm/msm/dsi-staging: disable dsi irq before core clock off Disable dsi irq before dsi core clock off, since dsi irq disable sequence involves register access and this may lead to NOC errors. Change-Id: If0444c6da1c37ad0159080ff96e6b9bc892f98a9 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 199833d13264..57729fdc5561 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -3050,6 +3050,8 @@ int dsi_pre_clkoff_cb(void *priv, pr_err("%s: failed to disable ulps. rc=%d\n", __func__, rc); } + /* dsi will not be able to serve irqs from here on */ + dsi_display_ctrl_irq_update(display, false); } return rc; @@ -3157,9 +3159,6 @@ int dsi_post_clkoff_cb(void *priv, if ((clk_type & DSI_CORE_CLK) && (curr_state == DSI_CLK_OFF)) { - /* dsi will not be able to serve irqs from here */ - dsi_display_ctrl_irq_update(display, false); - rc = dsi_display_phy_power_off(display); if (rc) pr_err("[%s] failed to power off PHY, rc=%d\n", -- GitLab From df3a536985e3bdd13dc8c06f5a1e6c12262e0c7e Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Mon, 23 Apr 2018 17:25:10 +0530 Subject: [PATCH 1515/1834] msm: mdss: fix the use after free problem in rotator ioctl Currently the fence fd is installed too early. This can cause a use after free problem if the fence fd is closed in some other thread. This change will install the fence fd where it is required and eliminates the problem. Change-Id: I5cf585ea87ef75fccae06da6cb5a6c16fc74eff3 Signed-off-by: Harsh Sahu Signed-off-by: Krishna Manikandan --- drivers/video/fbdev/msm/mdss_rotator.c | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_rotator.c b/drivers/video/fbdev/msm/mdss_rotator.c index f51a1b8d9e3c..4952e7ec13b9 100644 --- a/drivers/video/fbdev/msm/mdss_rotator.c +++ b/drivers/video/fbdev/msm/mdss_rotator.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "mdss_rotator_internal.h" #include "mdss_mdp.h" @@ -374,6 +375,24 @@ static bool mdss_rotator_is_work_pending(struct mdss_rot_mgr *mgr, return false; } +static int mdss_rotator_install_fence_fd(struct mdss_rot_entry_container *req) +{ + int i; + int ret = 0; + struct sync_file *sync_file; + + for (i = 0; i < req->count; i++) { + sync_file = sync_file_create((struct fence *) + (req->entries[i].output_fence)); + if (!sync_file) { + ret = -ENOMEM; + break; + } + fd_install(req->entries[i].output_fence_fd, sync_file->file); + } + return ret; +} + static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) { int ret = 0, fd; @@ -395,9 +414,10 @@ static int mdss_rotator_create_fence(struct mdss_rot_entry *entry) pr_err("cannot create sync point\n"); goto sync_pt_create_err; } - fd = mdss_get_sync_fence_fd(fence); + + fd = get_unused_fd_flags(O_CLOEXEC); if (fd < 0) { - pr_err("get_unused_fd_flags failed error:0x%x\n", fd); + pr_err("fail to get unused fd\n"); ret = fd; goto get_fd_err; } @@ -2245,6 +2265,13 @@ static int mdss_rotator_handle_request(struct mdss_rot_mgr *mgr, goto handle_request_err1; } + ret = mdss_rotator_install_fence_fd(req); + if (ret) { + pr_err("get_unused_fd_flags failed error:0x%x\n", ret); + mdss_rotator_remove_request(mgr, private, req); + goto handle_request_err1; + } + mdss_rotator_queue_request(mgr, private, req); mutex_unlock(&mgr->lock); @@ -2404,6 +2431,13 @@ static int mdss_rotator_handle_request32(struct mdss_rot_mgr *mgr, goto handle_request32_err1; } + ret = mdss_rotator_install_fence_fd(req); + if (ret) { + pr_err("get_unused_fd_flags failed error:0x%x\n", ret); + mdss_rotator_remove_request(mgr, private, req); + goto handle_request32_err1; + } + mdss_rotator_queue_request(mgr, private, req); mutex_unlock(&mgr->lock); -- GitLab From 402506b6bcd70a995dca8c06a358b1a472e3e519 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 9 Apr 2018 12:00:47 +0530 Subject: [PATCH 1516/1834] drm/msm/dsi-staging: add support for custom cmd dma scheduling Some panels take more time to post-process the video data sent from dsi host and hence BTA acknowledgment may take more than one line time. This will cause dsi host to miss out sync packets and which in turn will manifest as corruption on display panel. To fix this, dsi host should send the BTA request after some specified lines, once vertical active area ends. This change adds support for configuring the custom line number at which command dma needs to be scheduled to avoid such issues. Change-Id: I3c83310dd755881c78fed9486f81f71d1e29916e Signed-off-by: Sandeep Panda --- .../devicetree/bindings/drm/msm/mdss-dsi-panel.txt | 3 +++ drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 5 +++++ drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h | 3 +++ drivers/gpu/drm/msm/dsi-staging/dsi_defs.h | 5 ++++- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 3 ++- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 12 ++++++++++++ 6 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt index 806c45823205..24290c86302c 100644 --- a/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/drm/msm/mdss-dsi-panel.txt @@ -519,6 +519,8 @@ Optional properties: to identify the default topology for the display. The first set is indexed by the value 0. +- qcom,mdss-dsi-dma-schedule-line: An integer value indicates the line number after vertical active + region, at which command DMA needs to be triggered. Required properties for sub-nodes: None Optional properties: @@ -771,5 +773,6 @@ Example: qcom,display-topology = <1 1 1>, <2 2 1>; qcom,default-topology-index = <0>; + qcom,mdss-dsi-dma-schedule-line = <5>; }; }; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index 93e364de2362..c7c640f51a49 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1133,6 +1133,11 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl, } kickoff: + /* check if custom dma scheduling line needed */ + if ((dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) && + (flags & DSI_CTRL_CMD_CUSTOM_DMA_SCHED)) + line_no = dsi_ctrl->host_config.u.video_engine.dma_sched_line; + timing = &(dsi_ctrl->host_config.video_timing); if (timing) line_no += timing->v_back_porch + timing->v_sync_width + diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index 4f85cdaf5ddb..e08ef99911b6 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -38,6 +38,8 @@ * @DSI_CTRL_CMD_LAST_COMMAND: Trigger the DMA cmd transfer if this is last * command in the batch. * @DSI_CTRL_CMD_NON_EMBEDDED_MODE:Trasfer cmd packets in non embedded mode. + * @DSI_CTRL_CMD_CUSTOM_DMA_SCHED: Use the dma scheduling line number defined in + * display panel dtsi file instead of default. */ #define DSI_CTRL_CMD_READ 0x1 #define DSI_CTRL_CMD_BROADCAST 0x2 @@ -47,6 +49,7 @@ #define DSI_CTRL_CMD_FETCH_MEMORY 0x20 #define DSI_CTRL_CMD_LAST_COMMAND 0x40 #define DSI_CTRL_CMD_NON_EMBEDDED_MODE 0x80 +#define DSI_CTRL_CMD_CUSTOM_DMA_SCHED 0x100 /* DSI embedded mode fifo size * If the command is greater than 256 bytes it is sent in non-embedded mode. diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h index d45f8493d29d..6540182c529c 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -438,6 +438,8 @@ struct dsi_host_common_cfg { * @bllp_lp11_en: Enter low power stop mode (LP-11) during BLLP. * @traffic_mode: Traffic mode for video stream. * @vc_id: Virtual channel identifier. + * @dma_sched_line: Line number, after vactive end, at which command dma + * needs to be triggered. */ struct dsi_video_engine_cfg { bool last_line_interleave_en; @@ -449,6 +451,7 @@ struct dsi_video_engine_cfg { bool bllp_lp11_en; enum dsi_video_traffic_mode traffic_mode; u32 vc_id; + u32 dma_sched_line; }; /** diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index 199833d13264..1f94728d2e58 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -566,7 +566,8 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, lenp = config->status_valid_params ?: config->status_cmds_rlen; count = config->status_cmd.count; cmds = config->status_cmd.cmds; - flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ); + flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ | + DSI_CTRL_CMD_CUSTOM_DMA_SCHED); for (i = 0; i < count; ++i) { memset(config->status_buf, 0x0, SZ_4K); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index e62c65ebe2ff..79df63152ac4 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1217,6 +1217,7 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, const char *traffic_mode; u32 vc_id = 0; u32 val = 0; + u32 line_no = 0; rc = of_property_read_u32(of_node, "qcom,mdss-dsi-h-sync-pulse", &val); if (rc) { @@ -1279,6 +1280,17 @@ static int dsi_panel_parse_video_host_config(struct dsi_video_engine_cfg *cfg, cfg->vc_id = vc_id; } + rc = of_property_read_u32(of_node, "qcom,mdss-dsi-dma-schedule-line", + &line_no); + if (rc) { + pr_debug("[%s] set default dma scheduling line no\n", name); + cfg->dma_sched_line = 0x1; + /* do not fail since we have default value */ + rc = 0; + } else { + cfg->dma_sched_line = line_no; + } + error: return rc; } -- GitLab From 510d40b475c82b2ef7f0be5f50549fcbec99112c Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Mon, 9 Apr 2018 12:13:28 +0530 Subject: [PATCH 1517/1834] ARM: dts: msm: configure dma scheduling line for nt35597 truly panel Configure the command dma scheduling line number to 5 for nt35597 truly dsc video mode panel as recommended by HW design. Change-Id: I918a8a5a82efab4be38e16cb292263936f891185 Signed-off-by: Sandeep Panda --- .../boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi index 2c54504dc8cd..b2a541d9384e 100644 --- a/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi +++ b/arch/arm64/boot/dts/qcom/dsi-panel-nt35597-truly-dsc-wqxga-video.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -37,6 +37,7 @@ qcom,mdss-dsi-reset-sequence = <1 10>, <0 10>, <1 10>; qcom,mdss-pan-physical-width-dimension = <74>; qcom,mdss-pan-physical-height-dimension = <131>; + qcom,mdss-dsi-dma-schedule-line = <5>; qcom,mdss-dsi-display-timings { timing@0{ -- GitLab From 285ac186d6a81cac514056884eae56aebfac395a Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Mon, 23 Apr 2018 17:37:13 +0530 Subject: [PATCH 1518/1834] msm: mdss: update the MDSS DSI ULPS exit sequence Add change to exit the DSI ULPS mode after enabling the DSI escape clock and before enabling the DSI PLL. Check for the DSI PLL unlock error bit and clear it before enabling the DSI PLL to avoid false error interrupt after turning on the PLL. Change-Id: I53042fed9e4e45b64f75190abd4a295c0bc76baa Signed-off-by: Padmanabhan Komanduru --- drivers/video/fbdev/msm/msm_mdss_io_8974.c | 30 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index f0e46f77a0ad..153b39f04b17 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -2280,7 +2280,8 @@ int mdss_dsi_post_clkon_cb(void *priv, if (ctrl->phy_power_off || mmss_clamp) mdss_dsi_phy_power_on(ctrl, mmss_clamp); } - if ((clk & MDSS_DSI_LINK_CLK) && (l_type == MDSS_DSI_LINK_HS_CLK)) { + + if ((clk & MDSS_DSI_LINK_CLK) && (l_type == MDSS_DSI_LINK_LP_CLK)) { if (ctrl->ulps) { /* * ULPS Entry Request. This is needed if the lanes were @@ -2311,9 +2312,12 @@ int mdss_dsi_post_clkon_cb(void *priv, goto error; } } - /* Enable HS TX driver in DSI PHY if applicable */ - mdss_dsi_phy_hstx_drv_ctrl(ctrl, true); } + + /* Enable HS TX driver in DSI PHY if applicable */ + if ((clk & MDSS_DSI_LINK_CLK) && (l_type == MDSS_DSI_LINK_HS_CLK)) + mdss_dsi_phy_hstx_drv_ctrl(ctrl, true); + error: return rc; } @@ -2429,6 +2433,26 @@ int mdss_dsi_pre_clkon_cb(void *priv, if (ctrl->mdss_util->dyn_clk_gating_ctrl) ctrl->mdss_util->dyn_clk_gating_ctrl(0); + if ((clk_type & MDSS_DSI_LINK_CLK) && + (l_type == MDSS_DSI_LINK_HS_CLK)) { + u32 data = 0; + + data = MIPI_INP((ctrl->ctrl_io.base) + 0x0120); + /* + * For 12nm PHY, the PLL unlock bit in DSI_CLK_STATUS gets set + * when PLL is turned off. When device comes out of static + * screen without the DSI controller getting power collapsed, + * the bit might not clear sometimes. Clear the bit before + * turning ON the PLL. This avoids false error interrupt due to + * PLL unlocked bit after PLL is turned ON. + */ + if (data & BIT(16)) { + pr_debug("pll unlocked: 0x%x\n", data); + MIPI_OUTP((ctrl->ctrl_io.base) + 0x120, BIT(16)); + } + + } + return rc; } -- GitLab From 911408c3cea843646a1e123835540b5e492ad4cf Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Mon, 23 Apr 2018 17:43:51 +0530 Subject: [PATCH 1519/1834] msm: mdss: fix the string comparison logic for ESD thread Fix the string comparison logic in the fb notifier callback to enable ESD thread feature whenever valid. Change-Id: I2fd6488f649254f09573e52aa5ea012fe0a806d8 Signed-off-by: Padmanabhan Komanduru --- drivers/video/fbdev/msm/mdss_dsi_status.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c index 992d687edc19..ef0ee4da4dab 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_status.c +++ b/drivers/video/fbdev/msm/mdss_dsi_status.c @@ -133,14 +133,16 @@ static int fb_event_callback(struct notifier_block *self, struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct mdss_panel_info *pinfo; struct msm_fb_data_type *mfd; + char fb_id[7] = {'\0'}; if (!evdata) { pr_err("%s: event data not available\n", __func__); return NOTIFY_BAD; } + strlcpy(fb_id, evdata->info->fix.id, 7); /* handle only mdss fb device */ - if (strcmp("mdssfb", evdata->info->fix.id)) + if (strcmp("mdssfb", fb_id)) return NOTIFY_DONE; mfd = evdata->info->par; -- GitLab From 399d3c3b6c6448ff4baa4423ec0926316182ef2b Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Mon, 23 Apr 2018 17:34:04 +0530 Subject: [PATCH 1520/1834] ARM: dts: msm: add support for truly 1080p panel for SDM439 Add the dtsi nodes to enable support for truly 1080p video mode and command mode panels for SDM439 target. Enable ULPS, dynamic fps and ESD thread feature for the panels. Change-Id: I9c44e67e5083fe456d8b879e605193b2d065f89c Signed-off-by: Padmanabhan Komanduru --- .../boot/dts/qcom/msm8937-mdss-panels.dtsi | 2 + arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi | 328 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi | 13 + arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi | 13 + 4 files changed, 356 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi index 436b8a751cfb..ef4f4b09c451 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-mdss-panels.dtsi @@ -23,6 +23,8 @@ #include "dsi-adv7533-720p.dtsi" #include "dsi-panel-hx8399c-fhd-plus-video.dtsi" #include "dsi-panel-hx8399c-hd-plus-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-video.dtsi" +#include "dsi-panel-nt35695b-truly-fhd-cmd.dtsi" &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi index a27c8f81fbfe..dce6f6898210 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi @@ -154,6 +154,19 @@ qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; qcom,mdss-dsi-bl-pmic-bank-select = <0>; qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-status-read-length = <4>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; }; @@ -166,3 +179,318 @@ qcom,mdss-dsi-bl-pmic-bank-select = <0>; qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; }; + +&dsi_nt35695b_truly_fhd_cmd { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 10 + 15 01 00 00 00 00 02 35 00 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 14 + 00 02 28 00 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-timings-phy-12nm = [17 0a 0f 06 03 08 06 0e]; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; + qcom,ulps-enabled; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9c>; + qcom,mdss-dsi-panel-on-check-value = <0x9c>; + qcom,mdss-dsi-panel-status-read-length = <1>; + qcom,mdss-dsi-panel-max-error-count = <3>; + /delete-node/ qcom,mdss-dsi-display-timings; +}; + +&dsi_nt35695b_truly_fhd_video { + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <1920>; + qcom,mdss-dsi-h-front-porch = <120>; + qcom,mdss-dsi-h-back-porch = <60>; + qcom,mdss-dsi-h-pulse-width = <12>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-h-sync-pulse = <0>; + qcom,mdss-dsi-v-back-porch = <2>; + qcom,mdss-dsi-v-front-porch = <12>; + qcom,mdss-dsi-v-pulse-width = <2>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-on-command = + [15 01 00 00 10 00 02 ff 20 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 55 + 15 01 00 00 00 00 02 02 45 + 15 01 00 00 00 00 02 03 55 + 15 01 00 00 00 00 02 05 50 + 15 01 00 00 00 00 02 06 a8 + 15 01 00 00 00 00 02 07 ad + 15 01 00 00 00 00 02 08 0c + 15 01 00 00 00 00 02 0b aa + 15 01 00 00 00 00 02 0c aa + 15 01 00 00 00 00 02 0e b0 + 15 01 00 00 00 00 02 0f b3 + 15 01 00 00 00 00 02 11 28 + 15 01 00 00 00 00 02 12 10 + 15 01 00 00 00 00 02 13 01 + 15 01 00 00 00 00 02 14 4a + 15 01 00 00 00 00 02 15 12 + 15 01 00 00 00 00 02 16 12 + 15 01 00 00 00 00 02 30 01 + 15 01 00 00 00 00 02 72 11 + 15 01 00 00 00 00 02 58 82 + 15 01 00 00 00 00 02 59 00 + 15 01 00 00 00 00 02 5a 02 + 15 01 00 00 00 00 02 5b 00 + 15 01 00 00 00 00 02 5c 82 + 15 01 00 00 00 00 02 5d 80 + 15 01 00 00 00 00 02 5e 02 + 15 01 00 00 00 00 02 5f 00 + 15 01 00 00 00 00 02 ff 24 + 15 01 00 00 00 00 02 fb 01 + 15 01 00 00 00 00 02 00 01 + 15 01 00 00 00 00 02 01 0b + 15 01 00 00 00 00 02 02 0c + 15 01 00 00 00 00 02 03 89 + 15 01 00 00 00 00 02 04 8a + 15 01 00 00 00 00 02 05 0f + 15 01 00 00 00 00 02 06 10 + 15 01 00 00 00 00 02 07 10 + 15 01 00 00 00 00 02 08 1c + 15 01 00 00 00 00 02 09 00 + 15 01 00 00 00 00 02 0a 00 + 15 01 00 00 00 00 02 0b 00 + 15 01 00 00 00 00 02 0c 00 + 15 01 00 00 00 00 02 0d 13 + 15 01 00 00 00 00 02 0e 15 + 15 01 00 00 00 00 02 0f 17 + 15 01 00 00 00 00 02 10 01 + 15 01 00 00 00 00 02 11 0b + 15 01 00 00 00 00 02 12 0c + 15 01 00 00 00 00 02 13 89 + 15 01 00 00 00 00 02 14 8a + 15 01 00 00 00 00 02 15 0f + 15 01 00 00 00 00 02 16 10 + 15 01 00 00 00 00 02 17 10 + 15 01 00 00 00 00 02 18 1c + 15 01 00 00 00 00 02 19 00 + 15 01 00 00 00 00 02 1a 00 + 15 01 00 00 00 00 02 1b 00 + 15 01 00 00 00 00 02 1c 00 + 15 01 00 00 00 00 02 1d 13 + 15 01 00 00 00 00 02 1e 15 + 15 01 00 00 00 00 02 1f 17 + 15 01 00 00 00 00 02 20 00 + 15 01 00 00 00 00 02 21 01 + 15 01 00 00 00 00 02 22 00 + 15 01 00 00 00 00 02 23 40 + 15 01 00 00 00 00 02 24 40 + 15 01 00 00 00 00 02 25 6d + 15 01 00 00 00 00 02 26 40 + 15 01 00 00 00 00 02 27 40 + 15 01 00 00 00 00 02 29 d8 + 15 01 00 00 00 00 02 2a 2a + 15 01 00 00 00 00 02 4b 03 + 15 01 00 00 00 00 02 4c 11 + 15 01 00 00 00 00 02 4d 10 + 15 01 00 00 00 00 02 4e 01 + 15 01 00 00 00 00 02 4f 01 + 15 01 00 00 00 00 02 50 10 + 15 01 00 00 00 00 02 51 00 + 15 01 00 00 00 00 02 52 80 + 15 01 00 00 00 00 02 53 00 + 15 01 00 00 00 00 02 54 07 + 15 01 00 00 00 00 02 55 25 + 15 01 00 00 00 00 02 56 00 + 15 01 00 00 00 00 02 58 07 + 15 01 00 00 00 00 02 5b 43 + 15 01 00 00 00 00 02 5c 00 + 15 01 00 00 00 00 02 5f 73 + 15 01 00 00 00 00 02 60 73 + 15 01 00 00 00 00 02 63 22 + 15 01 00 00 00 00 02 64 00 + 15 01 00 00 00 00 02 67 08 + 15 01 00 00 00 00 02 68 04 + 15 01 00 00 00 00 02 7a 80 + 15 01 00 00 00 00 02 7b 91 + 15 01 00 00 00 00 02 7c d8 + 15 01 00 00 00 00 02 7d 60 + 15 01 00 00 00 00 02 93 06 + 15 01 00 00 00 00 02 94 06 + 15 01 00 00 00 00 02 8a 00 + 15 01 00 00 00 00 02 9b 0f + 15 01 00 00 00 00 02 b3 c0 + 15 01 00 00 00 00 02 b4 00 + 15 01 00 00 00 00 02 b5 00 + 15 01 00 00 00 00 02 b6 21 + 15 01 00 00 00 00 02 b7 22 + 15 01 00 00 00 00 02 b8 07 + 15 01 00 00 00 00 02 b9 07 + 15 01 00 00 00 00 02 ba 22 + 15 01 00 00 00 00 02 bd 20 + 15 01 00 00 00 00 02 be 07 + 15 01 00 00 00 00 02 bf 07 + 15 01 00 00 00 00 02 c1 6d + 15 01 00 00 00 00 02 c4 24 + 15 01 00 00 00 00 02 e3 00 + 15 01 00 00 00 00 02 ec 00 + 15 01 00 00 00 00 02 ff 10 + 15 01 00 00 00 00 02 bb 03 + 05 01 00 00 78 00 02 11 00 + 05 01 00 00 78 00 02 29 00]; + qcom,mdss-dsi-off-command = [05 01 00 00 + 14 00 02 28 00 05 01 00 00 78 00 + 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-timings-phy-12nm = [17 0a 0f 06 03 08 06 0e]; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; + /delete-node/ qcom,mdss-dsi-display-timings; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi index 9c5cb33d726b..6e3ba056dcff 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi @@ -154,6 +154,19 @@ qcom,mdss-dsi-bl-pmic-bank-select = <0>; qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-status-read-length = <4>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; }; &dsi_hx8399c_hd_vid { diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index a102053b0d53..87850cd1d930 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -249,4 +249,17 @@ qcom,mdss-dsi-panel-timings-phy-12nm = [18 0a 10 06 03 08 06 0e]; qcom,mdss-dsi-t-clk-post = <0x02>; qcom,mdss-dsi-t-clk-pre = <0x2d>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "reg_read"; + qcom,mdss-dsi-panel-status-command = [06 01 00 01 00 00 01 0a]; + qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-panel-status-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-on-check-value = <0x9d 0x9d 0x9d 0x9d>; + qcom,mdss-dsi-panel-status-read-length = <4>; + qcom,mdss-dsi-panel-max-error-count = <3>; + qcom,mdss-dsi-min-refresh-rate = <48>; + qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = + "dfps_immediate_porch_mode_vfp"; }; -- GitLab From 8e24ce1b3e77fc489bedfa5eb6a86754f2c04a0d Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Wed, 21 Mar 2018 22:16:36 +0530 Subject: [PATCH 1521/1834] ARM: dts: msm: Enable display panel support for msm8909w Add panel and display nodes to support 390p AUO command mode panel. Add corresponding mdss node information for all msm8909 wearable variants. Change-Id: I25a24f27ad8240b1227f122d28f28fe33f17e2be Signed-off-by: Arun kumar --- .../arm64/boot/dts/qcom/apq8009w-bg-alpha.dts | 5 + .../boot/dts/qcom/apq8009w-bg-wtp-v2.dts | 5 + .../boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi | 98 +++++++++++++++++++ .../boot/dts/qcom/msm8909-mdss-panels.dtsi | 75 ++++++++++++++ arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi | 12 ++- .../boot/dts/qcom/msm8909w-bg-wtp-v2.dts | 5 + arch/arm64/boot/dts/qcom/msm8909w.dtsi | 11 +++ 7 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8909-mdss-panels.dtsi diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts index 57a28d015ccf..89e1b761576f 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts @@ -296,3 +296,8 @@ output-high; }; }; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; + qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts index 454ba81684a3..9fb662603175 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts @@ -313,3 +313,8 @@ output-high; }; }; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; + qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi new file mode 100644 index 000000000000..b4ac287f8bad --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-390p-auo-cmd.dtsi @@ -0,0 +1,98 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&mdss_mdp { + dsi_auo_390p_cmd: qcom,mdss_dsi_auo_390p_cmd { + qcom,mdss-dsi-panel-name = "AUO 390p command mode dsi panel"; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-panel-framerate = <45>; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-panel-width = <390>; + qcom,mdss-dsi-panel-height = <390>; + qcom,mdss-pan-physical-height-dimension = <29>; + qcom,mdss-pan-physical-width-dimension = <29>; + qcom,mdss-dsi-h-front-porch = <4>; + qcom,mdss-dsi-h-back-porch = <4>; + qcom,mdss-dsi-h-pulse-width = <4>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <8>; + qcom,mdss-dsi-v-front-porch = <8>; + qcom,mdss-dsi-v-pulse-width = <8>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-color-order = "rgb_swap_rgb"; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-tear-check-frame-rate = <4500>; + qcom,mdss-dsi-on-command = [ + 15 01 00 00 00 00 02 fe 01 + 15 01 00 00 00 00 02 0a f0 + 15 01 00 00 00 00 02 fe 00 + 15 01 00 00 00 00 02 35 00 + 29 01 00 00 00 00 05 2a 00 04 01 89 + 29 01 00 00 00 00 05 2b 00 00 01 85 + 29 01 00 00 00 00 05 30 00 00 01 85 + 29 01 00 00 00 00 05 31 00 04 01 89 + 05 01 00 00 00 00 02 12 00 + 15 01 00 00 00 00 02 53 20 + 05 01 00 00 96 00 02 11 00 + 05 01 00 00 00 00 02 29 00 + 39 01 00 00 00 00 06 f0 55 aa 52 08 01 + 39 01 00 00 00 00 07 ff 00 55 aa 52 08 01 + ]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00 + ]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-idle-on-command = [ + 05 01 00 00 00 00 01 39 /* Idle-Mode On */ + ]; + qcom,mdss-dsi-idle-on-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-idle-off-command = [ + 05 01 00 00 00 00 01 38 /* Idle-Mode Off */ + /* Reset column start address*/ + 29 01 00 00 00 00 05 2a 00 04 01 89 + /* Reset row start address */ + 29 01 00 00 00 00 05 2b 00 00 01 85 + ]; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-lane-map = "lane_map_0123"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-panel-timings = [5f 12 0a 00 32 34 10 + 16 0f 03 04 00]; + qcom,mdss-dsi-t-clk-post = <0x05>; + qcom,mdss-dsi-t-clk-pre = <0x11>; + qcom,mdss-dsi-bl-min-level = <1>; + qcom,mdss-dsi-bl-max-level = <255>; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-reset-sequence = <1 20>, <0 20>, <1 20>; + /* clk = totlaH * totalV * bpp* 66fps */ + qcom,mdss-dsi-panel-clockrate = <276705792>; + qcom,esd-check-enabled; + qcom,mdss-dsi-panel-status-check-mode = "te_signal_check"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8909-mdss-panels.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mdss-panels.dtsi new file mode 100644 index 000000000000..0a657daa20aa --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8909-mdss-panels.dtsi @@ -0,0 +1,75 @@ +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "dsi-panel-390p-auo-cmd.dtsi" + +&soc { + dsi_panel_pwr_supply: dsi_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <2850000>; + qcom,supply-max-voltage = <2850000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + }; + + dsi_pm660_panel_pwr_supply: dsi_pm660_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdd"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "bklt"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + }; + }; +}; + +&dsi_auo_390p_cmd { + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,panel-supply-entries = <&dsi_pm660_panel_pwr_supply>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi index 0d824e089d93..67c6d0670b00 100644 --- a/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909-mdss.dtsi @@ -38,9 +38,11 @@ smmu_mdp_unsec: qcom,smmu_mdp_unsec_cb { compatible = "qcom,smmu_mdp_unsec"; + iommus = <&apps_iommu 0xC00 0>; /* For NS ctx bank */ }; smmu_mdp_sec: qcom,smmu_mdp_sec_cb { compatible = "qcom,smmu_mdp_sec"; + iommus = <&apps_iommu 0xC01 0>; /* For SEC Ctx Bank */ }; }; @@ -51,8 +53,8 @@ #size-cells = <1>; qcom,mdss-fb-map-prim = <&mdss_fb0>; gdsc-supply = <&gdsc_mdss>; - vdda-supply = <&pm8909_l2>; - vddio-supply = <&pm8909_l6>; + vdda-supply = <&pm660_l2>; + vddio-supply = <&pm660_l6>; /* Bus Scale Settings */ qcom,msm-bus,name = "mdss_dsi"; @@ -133,8 +135,8 @@ interrupts = <0 80 0>; qcom,mdss-mdp = <&mdss_mdp>; - vdd-supply = <&pm8909_l17>; - vddio-supply = <&pm8909_l6>; + vdd-supply = <&pm660_l17>; + vddio-supply = <&pm660_l6>; clocks = <&clock_gcc_mdss clk_gcc_mdss_byte0_clk>, <&clock_gcc_mdss clk_gcc_mdss_pclk0_clk>, @@ -157,4 +159,4 @@ }; }; -/* #include "msm8909-mdss-panels.dtsi" */ +#include "msm8909-mdss-panels.dtsi" diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts index d9fa6fb5a411..8149eb2f76e0 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts @@ -316,3 +316,8 @@ output-high; }; }; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; + qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8909w.dtsi b/arch/arm64/boot/dts/qcom/msm8909w.dtsi index 707b56ef82de..c2e28d147730 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909w.dtsi @@ -94,3 +94,14 @@ <55 512 196800 196800>, <55 512 393600 393600>; }; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_auo_cx_qvga_cmd>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&msm_gpio 24 0>; + qcom,platform-reset-gpio = <&msm_gpio 25 0>; + qcom,platform-bklight-en-gpio = <&msm_gpio 37 0>; +}; -- GitLab From a270f9a46adcdaee2b02c1bb90ee0bc1a44656dd Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Fri, 13 Apr 2018 19:06:42 +0530 Subject: [PATCH 1522/1834] soc: qcom: glink_smem_native_xprt: Move rx_worker in irq handler Tx_data cmd is processed in tasklet which is not guranteed to be scheduled immidiatley. This decreases performance of glink. Process tx_data command in irq handler. CRs-Fixed: 2225619 Change-Id: Ida5e51b83fa46c76f72ae886260752baa8b942b9 Signed-off-by: Dhoat Harpal --- drivers/soc/qcom/glink_smem_native_xprt.c | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/drivers/soc/qcom/glink_smem_native_xprt.c b/drivers/soc/qcom/glink_smem_native_xprt.c index dda2178b0370..ca9953a9467e 100644 --- a/drivers/soc/qcom/glink_smem_native_xprt.c +++ b/drivers/soc/qcom/glink_smem_native_xprt.c @@ -175,8 +175,6 @@ struct mailbox_config_info { * @kwork: Work to be executed when an irq is received. * @kworker: Handle to the entity processing of deferred commands. - * @tasklet Handle to tasklet to process incoming data - packets in atomic manner. * @task: Handle to the task context used to run @kworker. * @use_ref: Active uses of this transport use this to grab * a reference. Used for ssr synchronization. @@ -222,7 +220,6 @@ struct edge_info { struct kthread_work kwork; struct kthread_worker kworker; struct task_struct *task; - struct tasklet_struct tasklet; struct srcu_struct use_ref; bool in_ssr; spinlock_t rx_lock; @@ -1253,18 +1250,6 @@ static void __rx_worker(struct edge_info *einfo, bool atomic_ctx) srcu_read_unlock(&einfo->use_ref, rcu_id); } -/** - * rx_worker_atomic() - worker function to process received command in atomic - * context. - * @param: The param parameter passed during initialization of the tasklet. - */ -static void rx_worker_atomic(unsigned long param) -{ - struct edge_info *einfo = (struct edge_info *)param; - - __rx_worker(einfo, true); -} - /** * rx_worker() - worker function to process received commands * @work: kwork associated with the edge to process commands on. @@ -1284,7 +1269,7 @@ irqreturn_t irq_handler(int irq, void *priv) if (einfo->rx_reset_reg) writel_relaxed(einfo->out_irq_mask, einfo->rx_reset_reg); - tasklet_hi_schedule(&einfo->tasklet); + __rx_worker(einfo, true); einfo->rx_irq_count++; return IRQ_HANDLED; @@ -2479,7 +2464,6 @@ static int glink_smem_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); kthread_init_work(&einfo->kwork, rx_worker); kthread_init_worker(&einfo->kworker); - tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; init_srcu_struct(&einfo->use_ref); @@ -2607,7 +2591,6 @@ static int glink_smem_native_probe(struct platform_device *pdev) kthread_flush_worker(&einfo->kworker); kthread_stop(einfo->task); einfo->task = NULL; - tasklet_kill(&einfo->tasklet); kthread_fail: iounmap(einfo->out_irq_reg); ioremap_fail: @@ -2693,7 +2676,6 @@ static int glink_rpm_native_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); kthread_init_work(&einfo->kwork, rx_worker); kthread_init_worker(&einfo->kworker); - tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->intentless = true; einfo->read_from_fifo = memcpy32_fromio; einfo->write_to_fifo = memcpy32_toio; @@ -2864,7 +2846,6 @@ static int glink_rpm_native_probe(struct platform_device *pdev) kthread_flush_worker(&einfo->kworker); kthread_stop(einfo->task); einfo->task = NULL; - tasklet_kill(&einfo->tasklet); kthread_fail: iounmap(msgram); msgram_ioremap_fail: @@ -2994,7 +2975,6 @@ static int glink_mailbox_probe(struct platform_device *pdev) init_waitqueue_head(&einfo->tx_blocked_queue); kthread_init_work(&einfo->kwork, rx_worker); kthread_init_worker(&einfo->kworker); - tasklet_init(&einfo->tasklet, rx_worker_atomic, (unsigned long)einfo); einfo->read_from_fifo = read_from_fifo; einfo->write_to_fifo = write_to_fifo; init_srcu_struct(&einfo->use_ref); @@ -3126,7 +3106,6 @@ static int glink_mailbox_probe(struct platform_device *pdev) kthread_flush_worker(&einfo->kworker); kthread_stop(einfo->task); einfo->task = NULL; - tasklet_kill(&einfo->tasklet); kthread_fail: iounmap(einfo->rx_reset_reg); rx_reset_ioremap_fail: -- GitLab From c234b86ebe71e6508482c09755c501b92b6ca384 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 26 Feb 2018 19:49:41 -0800 Subject: [PATCH 1523/1834] ARM: dts: msm: Correct gpu smmu interrupt type for sdm845 Update the interrupt configuration to level high. Change-Id: I52c7ce70f900fee7078f2c17a8b96899159b82e7 Signed-off-by: Patrick Daly --- .../boot/dts/qcom/msm-arm-smmu-sdm845.dtsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi index e4fe2e392ea2..0ac9c2a1dc3f 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm845.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,14 +27,14 @@ vdd-supply = <&gpu_cx_gdsc>; interrupts = , , - , - , - , - , - , - , - , - ; + , + , + , + , + , + , + , + ; clock-names = "gcc_gpu_memnoc_gfx_clk"; clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; attach-impl-defs = -- GitLab From 93cef68ce702c1d7ce36d415e0a3f568007677fc Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 26 Apr 2018 16:10:41 +0530 Subject: [PATCH 1524/1834] ARM: dts: msm: Add thermistor support on PMI632 for SDM450 and SDM632 Add nodes and GPIO pin configurations for thermistor channels on PMI632 for SDM450 and SDM632. Change-Id: I3815a4247ea77442d5cb0fcf84e27f0e45803e5a Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/pmi632.dtsi | 17 ----------------- arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index b8f8b6834b74..5a28f996ca77 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -43,8 +43,6 @@ interrupt-names = "eoc-int-en-set"; qcom,adc-vdd-reference = <1875>; qcom,adc-full-scale-code = <0x70e4>; - pinctrl-names = "default"; - pinctrl-0 = <&quiet_therm_default &smb_therm_default>; chan@0 { label = "ref_gnd"; @@ -279,21 +277,6 @@ gpio-controller; #gpio-cells = <2>; qcom,gpios-disallowed = <1>; - - quiet_therm { - quiet_therm_default: quiet_therm_default { - pins = "gpio3"; - bias-high-impedance; - }; - }; - - smb_therm { - smb_therm_default: smb_therm_default { - pins = "gpio4"; - bias-high-impedance; - }; - }; - }; pmi632_charger: qcom,qpnp-smb5 { diff --git a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi index 5c127bc57518..e09d637ce513 100644 --- a/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm450-pmi632.dtsi @@ -41,6 +41,27 @@ }; }; +&pmi632_vadc { + pinctrl-names = "default"; + pinctrl-0 = <&quiet_therm_default &smb_therm_default>; +}; + +&pmi632_gpios { + quiet_therm { + quiet_therm_default: quiet_therm_default { + pins = "gpio3"; + bias-high-impedance; + }; + }; + + smb_therm { + smb_therm_default: smb_therm_default { + pins = "gpio4"; + bias-high-impedance; + }; + }; +}; + &pmi632_qg { qcom,battery-data = <&mtp_batterydata>; }; -- GitLab From dde128ac0ff2993b74d8f48b3e26754944ad364c Mon Sep 17 00:00:00 2001 From: Umang Agrawal Date: Mon, 16 Apr 2018 17:42:21 +0530 Subject: [PATCH 1525/1834] power: smb1390: Configure SMB1390 to improve ILIM accuracy Configure WIN_OV to 10V and VOUT tracking value to 1V to improve the accuracy of ILIM IRQ trigger. Change-Id: Ifadda6faea6acfbf4fe283aebb25fb4c5118087a Signed-off-by: Umang Agrawal --- drivers/power/supply/qcom/smb1390-charger.c | 28 +++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index 636265bdb7ae..55a1f457faee 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -67,6 +67,15 @@ #define CORE_FTRIM_ILIM_REG 0x1030 #define CFG_ILIM_MASK GENMASK(4, 0) +#define CORE_FTRIM_LVL_REG 0x1033 +#define CFG_WIN_HI_MASK GENMASK(3, 2) +#define WIN_OV_LVL_1000MV 0x08 + +#define CORE_FTRIM_MISC_REG 0x1034 +#define TR_WIN_1P5X_BIT BIT(0) +#define WINDOW_DETECTION_DELTA_X1P0 0 +#define WINDOW_DETECTION_DELTA_X1P5 1 + #define CP_VOTER "CP_VOTER" #define USER_VOTER "USER_VOTER" #define ILIM_VOTER "ILIM_VOTER" @@ -591,11 +600,30 @@ static void smb1390_destroy_votables(struct smb1390 *chip) static int smb1390_init_hw(struct smb1390 *chip) { + int rc; + /* * charge pump is initially disabled; this indirectly votes to allow * traditional parallel charging if present */ vote(chip->disable_votable, USER_VOTER, true, 0); + + /* + * Improve ILIM accuracy: + * - Configure window (Vin - 2Vout) OV level to 1000mV + * - Configure VOUT tracking value to 1.0 + */ + rc = smb1390_masked_write(chip, CORE_FTRIM_LVL_REG, + CFG_WIN_HI_MASK, WIN_OV_LVL_1000MV); + if (rc < 0) + return rc; + + rc = smb1390_masked_write(chip, CORE_FTRIM_MISC_REG, + TR_WIN_1P5X_BIT, WINDOW_DETECTION_DELTA_X1P0); + if (rc < 0) + return rc; + + return 0; } -- GitLab From 8267e99e76a6597762f27f97ec82dc2b0f0ecaa1 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Thu, 26 Apr 2018 11:16:55 +0530 Subject: [PATCH 1526/1834] msm: kgsl: Log external and transaction stalled iommu faults Add check to log external and transaction stalled iommu faults also instead of dumping fault type as unknown for these faults. Signed-off-by: Deepak Kumar Change-Id: Id95082eba94d480335a3c5569d7ab34f6c500c71 --- drivers/gpu/msm/kgsl_gmu.c | 4 ++++ drivers/gpu/msm/kgsl_iommu.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index dbf517a8627b..6f684a0caf62 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -131,6 +131,10 @@ static int _gmu_iommu_fault_handler(struct device *dev, fault_type = "translation"; else if (flags & IOMMU_FAULT_PERMISSION) fault_type = "permission"; + else if (flags & IOMMU_FAULT_EXTERNAL) + fault_type = "external"; + else if (flags & IOMMU_FAULT_TRANSACTION_STALLED) + fault_type = "transaction stalled"; dev_err(dev, "GMU fault addr = %lX, context=%s (%s %s fault)\n", addr, name, diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index 0ce72f636d6e..325d44ad8913 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -789,6 +789,10 @@ static int kgsl_iommu_fault_handler(struct iommu_domain *domain, fault_type = "translation"; else if (flags & IOMMU_FAULT_PERMISSION) fault_type = "permission"; + else if (flags & IOMMU_FAULT_EXTERNAL) + fault_type = "external"; + else if (flags & IOMMU_FAULT_TRANSACTION_STALLED) + fault_type = "transaction stalled"; if (kgsl_iommu_suppress_pagefault(addr, write, context)) { iommu->pagefault_suppression_count++; -- GitLab From 200f4849fbc26e9ee559a80402174f834764e726 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Thu, 26 Apr 2018 16:44:27 +0530 Subject: [PATCH 1527/1834] usb: gadget: f_rndis: allocate/free net device upon driver bind/unbind Driver registers net device in bind but does not unregister it on driver unbind. Upon composition switch rndis net device is no longer in use, hence unregister and free it in driver unbind. Unregistering net device sends notification to user space which can be used by user space entities to perform necessary actions for example updating UI. Symmetrically allocate and register net device in driver bind. Change-Id: I19f26745e4e1477a71f8dd70cdb0b201c82e77b7 Signed-off-by: Ajay Agarwal --- drivers/usb/gadget/function/f_rndis.c | 37 +++++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 6153c54e9fc4..bc4f9f72af8a 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -766,18 +766,31 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) * with regard to rndis_opts->bound access */ if (!rndis_opts->bound) { + mutex_lock(&rndis_opts->lock); + rndis_opts->net = gether_setup_default(); + if (IS_ERR(rndis_opts->net)) { + status = PTR_ERR(rndis_opts->net); + mutex_unlock(&rndis_opts->lock); + goto error; + } gether_set_gadget(rndis_opts->net, cdev->gadget); status = gether_register_netdev(rndis_opts->net); - if (status) - goto fail; + mutex_unlock(&rndis_opts->lock); + if (status) { + free_netdev(rndis_opts->net); + goto error; + } rndis_opts->bound = true; } + gether_get_host_addr_u8(rndis_opts->net, rndis->ethaddr); + rndis->port.ioport = netdev_priv(rndis_opts->net); + us = usb_gstrings_attach(cdev, rndis_strings, ARRAY_SIZE(rndis_string_defs)); if (IS_ERR(us)) { status = PTR_ERR(us); - goto fail; + goto netdev_cleanup; } rndis_control_intf.iInterface = us[0].id; rndis_data_intf.iInterface = us[1].id; @@ -894,7 +907,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); } - +netdev_cleanup: + gether_cleanup(rndis->port.ioport); +error: ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); return status; @@ -957,8 +972,6 @@ static void rndis_free_inst(struct usb_function_instance *f) if (!opts->borrowed_net) { if (opts->bound) gether_cleanup(netdev_priv(opts->net)); - else - free_netdev(opts->net); } kfree(opts->rndis_interf_group); /* single VLA chunk */ @@ -980,12 +993,6 @@ static struct usb_function_instance *rndis_alloc_inst(void) mutex_init(&opts->lock); spin_lock_init(&_rndis_lock); opts->func_inst.free_func_inst = rndis_free_inst; - opts->net = gether_setup_default(); - if (IS_ERR(opts->net)) { - struct net_device *net = opts->net; - kfree(opts); - return ERR_CAST(net); - } INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); descs[0] = &opts->rndis_os_desc; @@ -1025,6 +1032,8 @@ static void rndis_free(struct usb_function *f) static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); + struct f_rndis_opts *opts = container_of(f->fi, struct f_rndis_opts, + func_inst); kfree(f->os_desc_table); f->os_desc_n = 0; @@ -1032,6 +1041,8 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); + gether_cleanup(rndis->port.ioport); + opts->bound = false; } static struct usb_function *rndis_alloc(struct usb_function_instance *fi) @@ -1051,11 +1062,9 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi) mutex_lock(&opts->lock); opts->refcnt++; - gether_get_host_addr_u8(opts->net, rndis->ethaddr); rndis->vendorID = opts->vendor_id; rndis->manufacturer = opts->manufacturer; - rndis->port.ioport = netdev_priv(opts->net); mutex_unlock(&opts->lock); /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; -- GitLab From eaa6a3cc4ee73e92438b28afd5d18d35cc33712a Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Thu, 26 Apr 2018 15:15:32 +0530 Subject: [PATCH 1528/1834] drivers: lpm-levels: return zero for parse_cluster_params function return zero from parse_cluster_params when parse params successfully. Change-Id: I3d3eeb0de8a2568031b4fb24e72c7749c50f8204 Signed-off-by: Raghavendra Kakarla --- drivers/cpuidle/lpm-levels-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index ad0be45c2dcd..fe3ef48b886d 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -474,7 +474,7 @@ static int parse_cluster_params(struct device_node *node, /* Set default_level to 0 as default */ c->default_level = 0; - return ret; + return 0; fail: pr_err("Failed to read key: %s ret: %d\n", key, ret); -- GitLab From 91f5005747e8b96b82c9ad702d0dc9db91914711 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 26 Apr 2018 20:30:07 +0800 Subject: [PATCH 1529/1834] ARM: dts: msm: Remove fcm_dump for MSM8953 Remove fcm_dump as there is no fcm in MSM8953. CRs-Fixed: 2220870 Change-Id: Id632284f2c7ba58c6b77bd94ea667390dd060fd7 Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 5 ----- 1 file changed, 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index b33a7db11332..17c422a415a6 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -349,11 +349,6 @@ compatible = "qcom,mem-dump"; memory-region = <&dump_mem>; - fcm_dump { - qcom,dump-size = <0x8400>; - qcom,dump-id = <0xee>; - }; - rpm_sw_dump { qcom,dump-size = <0x28000>; qcom,dump-id = <0xea>; -- GitLab From d1230c8d6d1f46739b9074521704ef2cc60cf968 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 26 Apr 2018 20:34:26 +0800 Subject: [PATCH 1530/1834] ARM: dts: msm: Remove rpmh_dump fcm_dump for MSM8937 Remove rpmh_dump and fcm_dump as there is no rpmh_dump and fcm_dump on MSM8937. CRs-Fixed: 2220870 Change-Id: I31b4e6feee2bdd0b45d0adffa9a04c918606020f Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/msm8937.dtsi | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi index 7b9f74b80244..1b82c4b7d8a9 100644 --- a/arch/arm64/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi @@ -325,16 +325,6 @@ compatible = "qcom,mem-dump"; memory-region = <&dump_mem>; - rpmh_dump { - qcom,dump-size = <0x2000000>; - qcom,dump-id = <0xec>; - }; - - fcm_dump { - qcom,dump-size = <0x8400>; - qcom,dump-id = <0xee>; - }; - rpm_sw_dump { qcom,dump-size = <0x28000>; qcom,dump-id = <0xea>; -- GitLab From db0d7bf43a77f11092884c02628e8a36b252e849 Mon Sep 17 00:00:00 2001 From: Paras Nagda Date: Thu, 26 Apr 2018 20:38:02 +0530 Subject: [PATCH 1531/1834] ARM: dts: msm: update the SID for context banks Due to mismatch in the SID value secure playback is failing.Hence updating the values for various context banks based on the mappings in SID2CB. Change-Id: I17a37d1cecc01c891b68528fe43c910cd8f604ff Signed-off-by: Paras Nagda --- arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi index c4d5b90371af..ce6692da688b 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-vidc.dtsi @@ -78,7 +78,9 @@ secure_bitstream_cb { compatible = "qcom,msm-vidc,context-bank"; label = "venus_sec_bitstream"; - iommus = <&apps_iommu 0x90c 0x20>; + iommus = <&apps_iommu 0x900 0x00>, + <&apps_iommu 0x90a 0x04>, + <&apps_iommu 0x909 0x22>; buffer-types = <0x241>; virtual-addr-pool = <0x4b000000 0x12c00000>; qcom,secure-context-bank; @@ -87,10 +89,7 @@ secure_pixel_cb { compatible = "qcom,msm-vidc,context-bank"; label = "venus_sec_pixel"; - iommus = <&apps_iommu 0x940 0x00>, - <&apps_iommu 0x907 0x08>, - <&apps_iommu 0x908 0x20>, - <&apps_iommu 0x90d 0x20>; + iommus = <&apps_iommu 0x90c 0x20>; buffer-types = <0x106>; virtual-addr-pool = <0x25800000 0x25800000>; qcom,secure-context-bank; @@ -99,9 +98,10 @@ secure_non_pixel_cb { compatible = "qcom,msm-vidc,context-bank"; label = "venus_sec_non_pixel"; - iommus = <&apps_iommu 0x900 0x00>, - <&apps_iommu 0x90a 0x04>, - <&apps_iommu 0x909 0x22>; + iommus = <&apps_iommu 0x940 0x00>, + <&apps_iommu 0x907 0x08>, + <&apps_iommu 0x908 0x20>, + <&apps_iommu 0x90d 0x20>; buffer-types = <0x480>; virtual-addr-pool = <0x1000000 0x24800000>; qcom,secure-context-bank; -- GitLab From 2861d9db8dfa4936f7ab643376c2ed29d0ef1feb Mon Sep 17 00:00:00 2001 From: Dhoat Harpal Date: Fri, 20 Apr 2018 16:42:50 +0530 Subject: [PATCH 1532/1834] ARM: dts: msm: Add Glink pkt device node for sdxpoorwills Add glink pkt device node to enable userspace clients to communicate with modem clients using Glink. CRs-Fixed: 2228375 Change-Id: I993393e02ffd82810cc13affce151858d13f1818 Signed-off-by: Dhoat Harpal --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 38ba7fc7c3e1..d0f484cdee16 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -691,6 +691,34 @@ qcom,glinkpkt-dev-name = "glink_pkt_loopback"; }; + qcom,glinkpkt-data5-cntl { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA5_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl0"; + }; + + qcom,glinkpkt-data6-cntl { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA6_CNTL"; + qcom,glinkpkt-dev-name = "smdcntl1"; + }; + + qcom,glinkpkt-apr-apps2 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "apr_apps2"; + qcom,glinkpkt-dev-name = "apr_apps2"; + }; + + qcom,glinkpkt-data22 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA22"; + qcom,glinkpkt-dev-name = "smd22"; + }; + qcom,glinkpkt-data40-cntl { qcom,glinkpkt-transport = "smem"; qcom,glinkpkt-edge = "mpss"; @@ -718,6 +746,13 @@ qcom,glinkpkt-ch-name = "DATA11"; qcom,glinkpkt-dev-name = "smd11"; }; + + qcom,glinkpkt-data21 { + qcom,glinkpkt-transport = "smem"; + qcom,glinkpkt-edge = "mpss"; + qcom,glinkpkt-ch-name = "DATA21"; + qcom,glinkpkt-dev-name = "smd21"; + }; }; pil_modem: qcom,mss@4080000 { -- GitLab From dd5939d09c4b55159af6f3b58f2147e418c66bc6 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Wed, 21 Mar 2018 21:04:25 -0700 Subject: [PATCH 1533/1834] msm: sde: avoid dynamic kthread create for each rot session Each rotator session open request creates a thread and destroys it on close session. These threads are created to trigger rotation complete fences. Such dynamic allocation can easily be avoided by creating threads at probe time. Change-Id: I1a443ca8627b5cf2b2e770ad7ea2863c52aa7d9b Signed-off-by: Dhaval Patel --- .../msm/sde/rotator/sde_rotator_core.c | 2 +- .../msm/sde/rotator/sde_rotator_core.h | 14 +++- .../msm/sde/rotator/sde_rotator_dev.c | 73 +++++++++++++------ .../msm/sde/rotator/sde_rotator_dev.h | 16 +++- 4 files changed, 77 insertions(+), 28 deletions(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c index f3814e0cb9c8..ce50dcda961d 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.c @@ -3385,7 +3385,7 @@ int sde_rotator_resume(struct platform_device *dev) */ int sde_rotator_session_open(struct sde_rot_mgr *mgr, struct sde_rot_file_private **pprivate, int session_id, - struct sde_rot_queue *queue) + struct sde_rot_queue_v1 *queue) { int ret; struct sde_rot_file_private *private; diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h index 8421873a9297..f6fdb9072503 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_core.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -242,6 +242,12 @@ struct sde_rot_queue { struct sde_rot_hw_resource *hw; }; +struct sde_rot_queue_v1 { + struct kthread_worker *rot_kw; + struct task_struct *rot_thread; + struct sde_rot_timeline *timeline; + struct sde_rot_hw_resource *hw; +}; /* * struct sde_rot_entry_container - rotation request * @list: list of active requests managed by rotator manager @@ -294,7 +300,7 @@ struct sde_rot_entry { struct kthread_work commit_work; struct kthread_work done_work; struct sde_rot_queue *commitq; - struct sde_rot_queue *fenceq; + struct sde_rot_queue_v1 *fenceq; struct sde_rot_queue *doneq; struct sde_rot_entry_container *request; @@ -351,7 +357,7 @@ struct sde_rot_file_private { struct list_head req_list; struct list_head perf_list; struct sde_rot_mgr *mgr; - struct sde_rot_queue *fenceq; + struct sde_rot_queue_v1 *fenceq; }; /* @@ -586,7 +592,7 @@ void sde_rotator_core_dump(struct sde_rot_mgr *mgr); */ int sde_rotator_session_open(struct sde_rot_mgr *mgr, struct sde_rot_file_private **pprivate, int session_id, - struct sde_rot_queue *queue); + struct sde_rot_queue_v1 *queue); /* * sde_rotator_session_close - close the given rotator per file session diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index a46194f62ada..12bc8e30fc33 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -942,6 +942,7 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( ctx->rotate = 0; ctx->secure = 0; ctx->abort_pending = 0; + ctx->kthread_id = -1; ctx->format_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ctx->format_cap.fmt.pix.pixelformat = SDE_PIX_FMT_Y_CBCR_H2V2; ctx->format_cap.fmt.pix.width = 640; @@ -999,18 +1000,22 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( goto error_create_sysfs; } - snprintf(name, sizeof(name), "rot_fenceq_%d_%d", rot_dev->dev->id, - ctx->session_id); - kthread_init_worker(&ctx->work_queue.rot_kw); - ctx->work_queue.rot_thread = kthread_run(kthread_worker_fn, - &ctx->work_queue.rot_kw, name); - if (IS_ERR(ctx->work_queue.rot_thread)) { - SDEDEV_ERR(ctx->rot_dev->dev, "fail allocate kthread\n"); - ret = -EPERM; - ctx->work_queue.rot_thread = NULL; - goto error_alloc_workqueue; + for (i = 0; i < MAX_ROT_OPEN_SESSION; i++) { + if (rot_dev->kthread_free[i]) { + rot_dev->kthread_free[i] = false; + ctx->kthread_id = i; + ctx->work_queue.rot_kw = &rot_dev->rot_kw[i]; + ctx->work_queue.rot_thread = rot_dev->rot_thread[i]; + break; + } + } + + if (ctx->kthread_id < 0) { + SDEDEV_ERR(ctx->rot_dev->dev, + "fail to acquire the kthread\n"); + ret = -EINVAL; + goto error_alloc_kthread; } - SDEDEV_DBG(ctx->rot_dev->dev, "kthread name=%s\n", name); snprintf(name, sizeof(name), "%d_%d", rot_dev->dev->id, ctx->session_id); @@ -1069,9 +1074,9 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( error_open_session: sde_rot_mgr_unlock(rot_dev->mgr); sde_rotator_destroy_timeline(ctx->work_queue.timeline); - kthread_flush_worker(&ctx->work_queue.rot_kw); - kthread_stop(ctx->work_queue.rot_thread); -error_alloc_workqueue: + rot_dev->kthread_free[ctx->kthread_id] = true; + ctx->kthread_id = -1; +error_alloc_kthread: sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); error_create_sysfs: kobject_put(&ctx->kobj); @@ -1146,8 +1151,10 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, mutex_lock(&rot_dev->lock); SDEDEV_DBG(rot_dev->dev, "release context s:%d\n", session_id); sde_rotator_destroy_timeline(ctx->work_queue.timeline); - kthread_flush_worker(&ctx->work_queue.rot_kw); - kthread_stop(ctx->work_queue.rot_thread); + if (ctx->kthread_id >= 0 && ctx->work_queue.rot_kw) { + kthread_flush_worker(ctx->work_queue.rot_kw); + rot_dev->kthread_free[ctx->kthread_id] = true; + } sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); kobject_put(&ctx->kobj); if (ctx->file) { @@ -1834,7 +1841,7 @@ int sde_rotator_inline_commit(void *handle, struct sde_rotator_inline_cmd *cmd, } else { SDEROT_ERR("invalid stats timestamp\n"); } - req->retire_kw = &ctx->work_queue.rot_kw; + req->retire_kw = ctx->work_queue.rot_kw; req->retire_work = &request->retire_work; trace_rot_entry_fence( @@ -3187,7 +3194,7 @@ static int sde_rotator_process_buffers(struct sde_rotator_ctx *ctx, goto error_init_request; } - req->retire_kw = &ctx->work_queue.rot_kw; + req->retire_kw = ctx->work_queue.rot_kw; req->retire_work = &request->retire_work; ret = sde_rotator_handle_request_common( @@ -3485,7 +3492,7 @@ static int sde_rotator_job_ready(void *priv) list_del_init(&request->list); list_add_tail(&request->list, &ctx->pending_list); spin_unlock(&ctx->list_lock); - kthread_queue_work(&ctx->work_queue.rot_kw, + kthread_queue_work(ctx->work_queue.rot_kw, &request->submit_work); } } else if (request && !atomic_read(&request->req->pending_count)) { @@ -3539,7 +3546,8 @@ static int sde_rotator_probe(struct platform_device *pdev) { struct sde_rotator_device *rot_dev; struct video_device *vdev; - int ret; + int ret, i; + char name[32]; SDEDEV_DBG(&pdev->dev, "SDE v4l2 rotator probed\n"); @@ -3622,9 +3630,29 @@ static int sde_rotator_probe(struct platform_device *pdev) rot_dev->debugfs_root = sde_rotator_create_debugfs(rot_dev); + for (i = 0; i < MAX_ROT_OPEN_SESSION; i++) { + snprintf(name, sizeof(name), "rot_fenceq_%d_%d", + rot_dev->dev->id, i); + kthread_init_worker(&rot_dev->rot_kw[i]); + rot_dev->rot_thread[i] = kthread_run(kthread_worker_fn, + &rot_dev->rot_kw[i], name); + if (IS_ERR(rot_dev->rot_thread[i])) { + SDEDEV_ERR(rot_dev->dev, + "fail allocate kthread i:%d\n", i); + ret = -EPERM; + goto error_kthread_create; + } + rot_dev->kthread_free[i] = true; + } + SDEDEV_INFO(&pdev->dev, "SDE v4l2 rotator probe success\n"); return 0; +error_kthread_create: + for (i--; i >= 0; i--) + kthread_stop(rot_dev->rot_thread[i]); + sde_rotator_destroy_debugfs(rot_dev->debugfs_root); + video_unregister_device(rot_dev->vdev); error_video_register: video_device_release(vdev); error_alloc_video_device: @@ -3647,6 +3675,7 @@ static int sde_rotator_probe(struct platform_device *pdev) static int sde_rotator_remove(struct platform_device *pdev) { struct sde_rotator_device *rot_dev; + int i; rot_dev = platform_get_drvdata(pdev); if (rot_dev == NULL) { @@ -3655,6 +3684,8 @@ static int sde_rotator_remove(struct platform_device *pdev) } sde_rotator_pm_qos_remove(rot_dev->mdata); + for (i = MAX_ROT_OPEN_SESSION - 1; i >= 0; i--) + kthread_stop(rot_dev->rot_thread[i]); sde_rotator_destroy_debugfs(rot_dev->debugfs_root); video_unregister_device(rot_dev->vdev); video_device_release(rot_dev->vdev); diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h index ab27043ce0db..f81801675c83 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -42,6 +42,8 @@ /* maximum number of outstanding requests per ctx session */ #define SDE_ROTATOR_REQUEST_MAX 2 +#define MAX_ROT_OPEN_SESSION 16 + struct sde_rotator_device; struct sde_rotator_ctx; @@ -140,6 +142,7 @@ struct sde_rotator_request { * @retired_list: list of retired/free request * @requests: static allocation of free requests * @rotcfg: current core rotation configuration + * @kthread_id: thread_id used for fence management */ struct sde_rotator_ctx { struct kobject kobj; @@ -164,7 +167,7 @@ struct sde_rotator_ctx { struct sde_rotator_vbinfo *vbinfo_cap; struct sde_rotator_vbinfo *vbinfo_out; wait_queue_head_t wait_queue; - struct sde_rot_queue work_queue; + struct sde_rot_queue_v1 work_queue; struct sde_rot_file_private *private; struct llcc_slice_desc *slice; u32 commit_sequence_id; @@ -174,6 +177,8 @@ struct sde_rotator_ctx { struct list_head retired_list; struct sde_rotator_request requests[SDE_ROTATOR_REQUEST_MAX]; struct sde_rotation_config rotcfg; + + int kthread_id; }; /* @@ -212,6 +217,9 @@ struct sde_rotator_statistics { * @open_timeout: maximum wait time for ctx open in msec * @open_wq: wait queue for ctx open * @excl_ctx: Pointer to exclusive ctx + * @rot_kw: rotator thread work + * @rot_thread: rotator threads + * @kthread_free: check if thread is available or not */ struct sde_rotator_device { struct mutex lock; @@ -237,6 +245,10 @@ struct sde_rotator_device { u32 open_timeout; wait_queue_head_t open_wq; struct sde_rotator_ctx *excl_ctx; + + struct kthread_worker rot_kw[MAX_ROT_OPEN_SESSION]; + struct task_struct *rot_thread[MAX_ROT_OPEN_SESSION]; + bool kthread_free[MAX_ROT_OPEN_SESSION]; }; static inline -- GitLab From 8f25e7d871ce41fec1bbfae3848fc16e05f72d25 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 17 Apr 2018 14:39:03 -0700 Subject: [PATCH 1534/1834] ARM: dts: msm: Pass USB connector type for sdxpoorwills Driver registers extcon handle based upon fixed index assigned to USB connector type. Hence pass USB connector type and update extcon handle accordingly. Change-Id: I4f6f89bcf1e8d76f5101310c91779cec6a470ac5 Signed-off-by: Hemant Kumar --- arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi | 3 ++- arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi index 518d8a1e2271..0c90a20c44f6 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi @@ -18,7 +18,8 @@ &usb { status = "okay"; - extcon = <&vbus_detect>; + qcom,connector-type-uAB; + extcon = <0>, <0>, <0>, <&vbus_detect>; }; &pcie_ep { diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi index eb544e6fe6f8..f01dd351c794 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi @@ -18,7 +18,8 @@ &usb { status = "okay"; - extcon = <&vbus_detect>; + qcom,connector-type-uAB; + extcon = <0>, <0>, <0>, <&vbus_detect>; }; &pcie_ep { -- GitLab From c35d9bca84761eb739cde30745c900ba893379d4 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Tue, 6 Mar 2018 16:39:07 -0800 Subject: [PATCH 1535/1834] drm/msm/sde: disable dither for 10bit dsc panel Current MDSS driver enables dither for all cases except when DSI color component is 10bits. This is wrong assumption for 10 bit panel with 3.75 dsc compression ratio. Such invalid configuration may cause image quality issue. Avoid enabling dither in these cases by checking bits per component or bits per pixel. Change-Id: I5dabb035fbe59769015136d4ba112af185168810 Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde/sde_encoder.c | 30 ++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 30214967efde..bea66931f967 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -3402,22 +3402,42 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) { void *dither_cfg; - int ret = 0; + int ret = 0, rc; size_t len = 0; enum sde_rm_topology_name topology; + struct drm_encoder *drm_enc; + struct msm_mode_info mode_info; + struct msm_display_dsc_info *dsc = NULL; + struct sde_encoder_virt *sde_enc; if (!phys || !phys->connector || !phys->hw_pp || - !phys->hw_pp->ops.setup_dither) + !phys->hw_pp->ops.setup_dither || !phys->parent) return; + topology = sde_connector_get_topology_name(phys->connector); if ((topology == SDE_RM_TOPOLOGY_PPSPLIT) && (phys->split_role == ENC_ROLE_SLAVE)) return; - ret = sde_connector_get_dither_cfg(phys->connector, + drm_enc = phys->parent; + sde_enc = to_sde_encoder_virt(drm_enc); + rc = _sde_encoder_get_mode_info(&sde_enc->base, &mode_info); + if (rc) { + SDE_ERROR_ENC(sde_enc, "failed to get mode info\n"); + return; + } + + dsc = &mode_info.comp_info.dsc_info; + /* disable dither for 10 bpp or 10bpc dsc config */ + if (dsc->bpp == 10 || dsc->bpc == 10) { + phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0); + } else { + ret = sde_connector_get_dither_cfg(phys->connector, phys->connector->state, &dither_cfg, &len); - if (!ret) - phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len); + if (!ret) + phys->hw_pp->ops.setup_dither(phys->hw_pp, + dither_cfg, len); + } } static u32 _sde_encoder_calculate_linetime(struct sde_encoder_virt *sde_enc, -- GitLab From b2c041c4aa0a6459e4c4b11b5bb39b189167c1ae Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 26 Apr 2018 20:52:33 +0800 Subject: [PATCH 1536/1834] coresight: Kconfig: remove dependency on arch for ETM4X The coresight ETMV4 has both arm32 bit and arm64 bit support. Remove the dependency of architecture in Kconfig. CRs-Fixed: 2226673 Change-Id: I5615cfd5fbe572e98096c5b96a1ec5d359ab219f Signed-off-by: Saranya Chidura Signed-off-by: Mao Jinlong --- drivers/hwtracing/coresight/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 95c887caf596..2d4da74c58f9 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -63,7 +63,6 @@ config CORESIGHT_SOURCE_ETM3X config CORESIGHT_SOURCE_ETM4X bool "CoreSight Embedded Trace Macrocell 4.x driver" - depends on ARM64 select CORESIGHT_LINKS_AND_SINKS help This driver provides support for the ETM4.x tracer module, tracing the -- GitLab From af2e9911b6056422575d91576c5abe0b370e52eb Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 26 Apr 2018 21:28:28 +0800 Subject: [PATCH 1537/1834] defconfig: arm: Add coresight configs for MSM8937 Add coresight configs for arm MSM8937. CRs-Fixed: 2226673 Change-Id: Ic65da8117ed61ea878acf7a22deeef5a6925ec31 Signed-off-by: Mao Jinlong --- arch/arm/configs/msm8937-perf_defconfig | 5 +++++ arch/arm/configs/msm8937_defconfig | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index a6a85f18db0c..585e4d64c463 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -549,6 +549,7 @@ CONFIG_QCOM_DCC=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MEM_SHARE_QMI_SERVICE=y +# CONFIG_MSM_JTAGV8 is not set CONFIG_MSM_BAM_DMUX=y CONFIG_WCNSS_CORE=y CONFIG_WCNSS_CORE_PRONTO=y @@ -595,8 +596,12 @@ CONFIG_SCHED_STACK_END_CHECK=y CONFIG_IPC_LOGGING=y CONFIG_CPU_FREQ_SWITCH_PROFILER=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_DBGUI=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 54461cf024ac..d99d3d2d1e2a 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -565,6 +565,7 @@ CONFIG_QCOM_DCC=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MEM_SHARE_QMI_SERVICE=y +# CONFIG_MSM_JTAGV8 is not set CONFIG_MSM_BAM_DMUX=y CONFIG_WCNSS_CORE=y CONFIG_WCNSS_CORE_PRONTO=y @@ -654,8 +655,12 @@ CONFIG_DEBUG_USER=y CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_LINK_AND_SINK_TMC=y +CONFIG_CORESIGHT_SOURCE_ETM4X=y CONFIG_CORESIGHT_REMOTE_ETM=y CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_QCOM_REPLICATOR=y +CONFIG_CORESIGHT_DBGUI=y CONFIG_CORESIGHT_STM=y CONFIG_CORESIGHT_TPDA=y CONFIG_CORESIGHT_TPDM=y -- GitLab From 7d0a803b7769941fd5a584c251efecb45c183d12 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 26 Apr 2018 14:39:52 +0800 Subject: [PATCH 1538/1834] ARM: dts: msm: Add coresight dtsi for SDM632 Some coresight nodes of SDM632 are different from MSM8953. Create coresight dtsi to correct the difference. CRs-Fixed: 2226539 Change-Id: I13516b8563e79d2892a3bf8266033fc4e46c538e Signed-off-by: Mao Jinlong --- .../arm64/boot/dts/qcom/sdm632-coresight.dtsi | 154 ++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm632.dtsi | 1 + 2 files changed, 155 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm632-coresight.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm632-coresight.dtsi b/arch/arm64/boot/dts/qcom/sdm632-coresight.dtsi new file mode 100644 index 000000000000..62eeb65ea968 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm632-coresight.dtsi @@ -0,0 +1,154 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +&soc { + + /delete-node/ etm@61bc000; + /delete-node/ etm@61bd000; + /delete-node/ etm@61be000; + /delete-node/ etm@61bf000; + /delete-node/ cti@61b8000; + /delete-node/ cti@61b9000; + /delete-node/ cti@61ba000; + /delete-node/ cti@61bb000; + + etm4: etm@61b3000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb959>; + + reg = <0x61b3000 0x1000>; + cpu = <&CPU4>; + coresight-name = "coresight-etm4"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm4_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm4>; + }; + }; + }; + + etm5: etm@61b7000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb959>; + + reg = <0x61b7000 0x1000>; + cpu = <&CPU5>; + coresight-name = "coresight-etm5"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm5_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm5>; + }; + }; + }; + + etm6: etm@61bb000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb959>; + + reg = <0x61bb000 0x1000>; + cpu = <&CPU6>; + coresight-name = "coresight-etm6"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm6_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm6>; + }; + }; + }; + + etm7: etm@61bf000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb959>; + + reg = <0x61bf000 0x1000>; + coresight-name = "coresight-etm7"; + cpu = <&CPU7>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm7_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm7>; + }; + }; + }; + + cti_cpu4: cti@61b1000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61b1000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu4"; + cpu = <&CPU4>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu5: cti@61b5000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61b5000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu5"; + cpu = <&CPU5>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu6: cti@61b9000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61b9000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu6"; + cpu = <&CPU6>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu7: cti@61bd000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61bd000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu7"; + cpu = <&CPU7>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi index 62689f597e86..69cb36fd8cb8 100644 --- a/arch/arm64/boot/dts/qcom/sdm632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -983,3 +983,4 @@ /delete-node/ case-therm-step; }; +#include "sdm632-coresight.dtsi" -- GitLab From 56b12f69d9491ac75ab4241a1835cef667167818 Mon Sep 17 00:00:00 2001 From: Vijay kumar Tumati Date: Thu, 19 Apr 2018 09:46:47 +0530 Subject: [PATCH 1539/1834] ARM: dts: msm: Use correct camera csi vdd voltage on SDM439 Align the voltage requested from camera to the PMIC support. Change-Id: I05f1bed83deb943c8e0a18b5ac4d54a5e69183db Signed-off-by: Vijay kumar Tumati --- arch/arm64/boot/dts/qcom/sdm439.dtsi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 6cfd2d7ab4da..9a452294d115 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -23,12 +23,15 @@ &soc { qcom,csid@1b30000 { + qcom,csi-vdd-voltage = <800000>; qcom,mipi-csi-vdd-supply = <&pm8953_l23>; }; qcom,csid@1b30400 { + qcom,csi-vdd-voltage = <800000>; qcom,mipi-csi-vdd-supply = <&pm8953_l23>; }; qcom,csid@1b30800 { + qcom,csi-vdd-voltage = <800000>; qcom,mipi-csi-vdd-supply = <&pm8953_l23>; }; -- GitLab From 9898c2fd9e6282be317f3be06f095bae349732aa Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Tue, 24 Apr 2018 12:12:50 +0530 Subject: [PATCH 1540/1834] pinctrl: qcom: Update direct connect mapping for GPIOs Some GPIOs are connected through an internal pad to the PDC. Updating the mapping accordingly. Change-Id: Id14e1868701d99c974d52f241211f43dab64c02c Signed-off-by: Maulik Shah --- drivers/pinctrl/qcom/pinctrl-sdm670.c | 4 ++++ drivers/pinctrl/qcom/pinctrl-sdm845-v2.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-sdm670.c b/drivers/pinctrl/qcom/pinctrl-sdm670.c index 196559cf06a1..e9d7dfc4acc8 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm670.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm670.c @@ -1636,6 +1636,9 @@ static struct msm_dir_conn sdm670_dir_conn[] = { {97, 563}, {101, 564}, {103, 565}, + {108, 567}, + {112, 568}, + {113, 569}, {115, 570}, {116, 571}, {117, 572}, @@ -1647,6 +1650,7 @@ static struct msm_dir_conn sdm670_dir_conn[] = { {123, 613}, {124, 614}, {125, 615}, + {126, 616}, {127, 617}, {128, 618}, {129, 619}, diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c index 72b730d2fbe0..bc8ec394d620 100644 --- a/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c +++ b/drivers/pinctrl/qcom/pinctrl-sdm845-v2.c @@ -1738,6 +1738,9 @@ static struct msm_dir_conn sdm845_dir_conn[] = { {97, 563}, {101, 564}, {103, 565}, + {108, 567}, + {112, 568}, + {113, 569}, {104, 566}, {115, 570}, {116, 571}, -- GitLab From 56aafb0ecf87a2d9c7fd3bb443e86f68ac6a6566 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Fri, 27 Apr 2018 13:28:56 +0530 Subject: [PATCH 1541/1834] defconfig : enable quota feature for MSM8909W The recent Android O upgrade mandates disk quota feature to be enabled by default on /data. Hence, enable the required kernel config options to support the same. Change-Id: I4dea5af644f26718889e7b15fe90aaa2396861fa Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909w-perf_defconfig | 1 + arch/arm/configs/msm8909w_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index dfe5fd8d5bc5..c4f7cfa5728c 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -468,6 +468,7 @@ CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index df7f1c909c3a..3fdcc91d48ec 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -473,6 +473,7 @@ CONFIG_EXT3_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y -- GitLab From 3ea60b882ed5cc41761a0c69d9cf69451b8e8092 Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Fri, 27 Apr 2018 15:41:18 +0530 Subject: [PATCH 1542/1834] drm/msm/sde: fix race condition in vblank control interrupts When register/deregister of interrupts happen across multiple threads, there can be a race condition where irq idx can be in invalid state. Fixed it with adding mutex lock to avoid the race condition. Change-Id: Ic95d0fc4c4890cf6d98aa677aa65aca1adc93d54 Signed-off-by: Raviteja Tamatam --- drivers/gpu/drm/msm/sde/sde_encoder.c | 3 +++ drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 2 ++ drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c | 3 +++ drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c | 3 +++ drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 3 ++- 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 30214967efde..cfa240c33bba 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -215,6 +215,7 @@ enum sde_enc_rc_states { struct sde_encoder_virt { struct drm_encoder base; spinlock_t enc_spinlock; + struct mutex vblank_ctl_lock; uint32_t bus_scaling_client; uint32_t display_num_of_h_tiles; @@ -4368,6 +4369,7 @@ static int sde_encoder_setup_display(struct sde_encoder_virt *sde_enc, phys_params.parent = &sde_enc->base; phys_params.parent_ops = parent_ops; phys_params.enc_spinlock = &sde_enc->enc_spinlock; + phys_params.vblank_ctl_lock = &sde_enc->vblank_ctl_lock; SDE_DEBUG("\n"); @@ -4510,6 +4512,7 @@ struct drm_encoder *sde_encoder_init( sde_enc->cur_master = NULL; spin_lock_init(&sde_enc->enc_spinlock); + mutex_init(&sde_enc->vblank_ctl_lock); drm_enc = &sde_enc->base; drm_encoder_init(dev, drm_enc, &sde_encoder_funcs, drm_enc_mode, NULL); drm_encoder_helper_add(drm_enc, &sde_encoder_helper_funcs); diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 9557d41dd8c9..ea53af99658c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -284,6 +284,7 @@ struct sde_encoder_phys { enum msm_display_compression_type comp_type; spinlock_t *enc_spinlock; enum sde_enc_enable_state enable_state; + struct mutex *vblank_ctl_lock; atomic_t vblank_refcount; atomic_t vsync_cnt; atomic_t underrun_cnt; @@ -434,6 +435,7 @@ struct sde_enc_phys_init_params { enum sde_wb wb_idx; enum msm_display_compression_type comp_type; spinlock_t *enc_spinlock; + struct mutex *vblank_ctl_lock; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index 828d771acedb..f06ceb7e5f5c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -680,6 +680,7 @@ static int sde_encoder_phys_cmd_control_vblank_irq( return -EINVAL; } + mutex_lock(phys_enc->vblank_ctl_lock); refcount = atomic_read(&phys_enc->vblank_refcount); /* Slave encoders don't report vblank */ @@ -713,6 +714,7 @@ static int sde_encoder_phys_cmd_control_vblank_irq( enable, refcount, SDE_EVTLOG_ERROR); } + mutex_unlock(phys_enc->vblank_ctl_lock); return ret; } @@ -1398,6 +1400,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( phys_enc->split_role = p->split_role; phys_enc->intf_mode = INTF_MODE_CMD; phys_enc->enc_spinlock = p->enc_spinlock; + phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; cmd_enc->stream_sel = 0; phys_enc->enable_state = SDE_ENC_DISABLED; phys_enc->comp_type = p->comp_type; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index 862a8b36a428..f60f572405f2 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -625,6 +625,7 @@ static int sde_encoder_phys_vid_control_vblank_irq( return -EINVAL; } + mutex_lock(phys_enc->vblank_ctl_lock); refcount = atomic_read(&phys_enc->vblank_refcount); vid_enc = to_sde_encoder_phys_vid(phys_enc); @@ -660,6 +661,7 @@ static int sde_encoder_phys_vid_control_vblank_irq( vid_enc->hw_intf->idx - INTF_0, enable, refcount, SDE_EVTLOG_ERROR); } + mutex_unlock(phys_enc->vblank_ctl_lock); return ret; } @@ -1233,6 +1235,7 @@ struct sde_encoder_phys *sde_encoder_phys_vid_init( phys_enc->split_role = p->split_role; phys_enc->intf_mode = INTF_MODE_VIDEO; phys_enc->enc_spinlock = p->enc_spinlock; + phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; phys_enc->comp_type = p->comp_type; for (i = 0; i < INTR_IDX_MAX; i++) { irq = &phys_enc->irq[i]; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 9a90075d8993..a3f2c730bae4 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1410,6 +1410,7 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( phys_enc->intf_mode = INTF_MODE_WB_LINE; phys_enc->intf_idx = p->intf_idx; phys_enc->enc_spinlock = p->enc_spinlock; + phys_enc->vblank_ctl_lock = p->vblank_ctl_lock; atomic_set(&phys_enc->pending_retire_fence_cnt, 0); INIT_LIST_HEAD(&wb_enc->irq_cb.list); -- GitLab From 7ef5b5ce0b482ae7b0012b858beb0f8e70102cd8 Mon Sep 17 00:00:00 2001 From: Krishna Manikandan Date: Fri, 27 Apr 2018 17:09:41 +0530 Subject: [PATCH 1543/1834] fbdev: msm: Perform a fence_get before waiting during SYNC_BLIT A fence_get on the release fence is performed before queueing the blit work to make sure that the fence is not released before the wait is completed during sync blit. Change-Id: I15510a354844fa284e9cbc6f2d45e02f9f6e7249 Signed-off-by: Krishna Manikandan --- drivers/video/fbdev/msm/mdp3_ppp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c index 612cccc961f9..9253a69f927b 100644 --- a/drivers/video/fbdev/msm/mdp3_ppp.c +++ b/drivers/video/fbdev/msm/mdp3_ppp.c @@ -22,6 +22,7 @@ #include #include "linux/proc_fs.h" #include +#include #include "mdss_fb.h" #include "mdp3_ppp.h" @@ -1645,6 +1646,7 @@ int mdp3_ppp_parse_req(void __user *p, } } else { fence = req->cur_rel_fence; + fence_get((struct fence *) fence); } mdp3_ppp_req_push(req_q, req); -- GitLab From 365352a8a365161a92b6c7871bdbd9786812d441 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Wed, 21 Dec 2016 11:11:32 +0530 Subject: [PATCH 1544/1834] clk: msm: Update boot frequency in case PLL is configured At the early init the PLL is configured by cpu clock to a early init rate. But there could a requirement for the PLL to be preconfigured by bootloader and in those conditions the cpu clock driver is not required to configure the PLL again. Update the boot frequency to set the software clock rates later. Change-Id: I4a16e3463fc85db8a9709b0f727849ce3468002e Signed-off-by: Taniya Das --- drivers/clk/msm/clock-cpu-8953.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/clk/msm/clock-cpu-8953.c b/drivers/clk/msm/clock-cpu-8953.c index 4ba25431b392..fb393c9b246f 100644 --- a/drivers/clk/msm/clock-cpu-8953.c +++ b/drivers/clk/msm/clock-cpu-8953.c @@ -796,11 +796,13 @@ static struct notifier_block clock_panic_notifier = { .priority = 1, }; +static unsigned long pwrcl_boot_rate = 883200000; + static int clock_cpu_probe(struct platform_device *pdev) { int speed_bin, version, rc, cpu, mux_id; char prop_name[] = "qcom,speedX-bin-vX-XXX"; - unsigned long ccirate, pwrcl_boot_rate = 883200000; + unsigned long ccirate; get_speed_bin(pdev, &speed_bin, &version); @@ -952,7 +954,7 @@ arch_initcall(clock_cpu_init); #define SRC_DIV 0x1 /* Configure PLL at Low frequency */ -unsigned long pwrcl_early_boot_rate = 652800000; +static unsigned long pwrcl_early_boot_rate = 652800000; static int __init cpu_clock_pwr_init(void) { @@ -968,9 +970,20 @@ static int __init cpu_clock_pwr_init(void) clk_ops_variable_rate = clk_ops_variable_rate_pll_hwfsm; clk_ops_variable_rate.list_registers = variable_pll_list_registers; - __variable_rate_pll_init(&apcs_hf_pll.c); - apcs_hf_pll.c.ops->set_rate(&apcs_hf_pll.c, pwrcl_early_boot_rate); - clk_ops_variable_rate_pll.enable(&apcs_hf_pll.c); + /* Read back the L-val of PLL */ + regval = readl_relaxed(virt_bases[APCS_C0_PLL_BASE] + APCS_PLL_L_VAL); + if (regval) { + pr_debug("PLL preconfigured for frequency %ld\n", + (19200000UL * regval)); + pwrcl_boot_rate = (apcs_hf_pll.src_rate * regval); + apcs_hf_pll.c.ops->set_rate(&apcs_hf_pll.c, pwrcl_boot_rate); + clk_ops_variable_rate_pll_hwfsm.enable(&apcs_hf_pll.c); + } else { + __variable_rate_pll_init(&apcs_hf_pll.c); + apcs_hf_pll.c.ops->set_rate(&apcs_hf_pll.c, + pwrcl_early_boot_rate); + clk_ops_variable_rate_pll.enable(&apcs_hf_pll.c); + } base = ioremap_nocache(APCS_ALIAS1_CMD_RCGR, SZ_8); regval = readl_relaxed(base); -- GitLab From 51dc5c1aad0a5c1b250fb100bac651141759a963 Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Tue, 10 Apr 2018 15:13:21 +0530 Subject: [PATCH 1545/1834] ion: ion_system_heap: update supported page-orders for ion pool The supported mappings for ARMv8 are 1GB, 2MB, 64KB and 4KB. So 1MB allocations from ion pool is not used for ARMv8 section map. Such allocations end up being mapped as multiple 64K sections map, while still using 1MB contiguous memory. In case of ARMv7s, page-order 9 allocations are not used as section map. Drop page-order 8 ion pool for builds using ARMv8 pagetables and page-order 9 ion pool for builds using ARMv7s. Change-Id: Ifff2d8f1cf61ce443311d16c11b8edc191b27a22 Signed-off-by: Prakash Gupta --- drivers/staging/android/ion/ion_system_heap.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 800c167c8412..3ac71ed62619 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -2,7 +2,7 @@ * drivers/staging/android/ion/ion_system_heap.c * * Copyright (C) 2011 Google, Inc. - * Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -36,7 +36,11 @@ static gfp_t high_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN | static gfp_t low_order_gfp_flags = (GFP_HIGHUSER | __GFP_NOWARN); #ifndef CONFIG_ALLOC_BUFFERS_IN_4K_CHUNKS -static const unsigned int orders[] = {9, 8, 4, 0}; +#if defined(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) +static const unsigned int orders[] = {8, 4, 0}; +#else +static const unsigned int orders[] = {9, 4, 0}; +#endif #else static const unsigned int orders[] = {0}; #endif -- GitLab From a38e5dcb6b97401ac063793b6eef52530090a23d Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Mon, 23 Apr 2018 16:36:32 +0530 Subject: [PATCH 1546/1834] ARM: dts: msm: Add pm-qos-latency for SDM845 Enable pm-qos-latency voting for SDM845 from dtsi, which helps improve throughputs. Change-Id: Iad9013a09d34dcbcbb32b82d55d6a49b51099fc7 Signed-off-by: Vijayavardhan Vennapusa --- arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi index f6fa948a3530..41bb925bebe5 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi @@ -36,6 +36,7 @@ qcom,dwc-usb3-msm-tx-fifo-size = <21288>; qcom,num-gsi-evt-buffs = <0x3>; qcom,use-pdc-interrupts; + qcom,pm-qos-latency = <44>; extcon = <0>, <0>, <&eud>, <0>, <0>; clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>, -- GitLab From f8c7558117be14c627aaf5d9fe8fa432184022a9 Mon Sep 17 00:00:00 2001 From: Dhaval Patel Date: Tue, 3 Apr 2018 17:20:20 -0700 Subject: [PATCH 1547/1834] rot: add null checks before calling release API Add null checks before calling release API in sde rotator dev. Change-Id: Ia6e2f436caba3f2d0fbabad90150cd67592124d3 Signed-off-by: Dhaval Patel --- .../msm/sde/rotator/sde_rotator_dev.c | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index 12bc8e30fc33..38c3d79965cc 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -981,6 +981,7 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( ctx, sde_rotator_queue_init); if (IS_ERR_OR_NULL(ctx->fh.m2m_ctx)) { ret = PTR_ERR(ctx->fh.m2m_ctx); + ctx->fh.m2m_ctx = NULL; goto error_m2m_init; } } @@ -1081,6 +1082,10 @@ struct sde_rotator_ctx *sde_rotator_ctx_open( error_create_sysfs: kobject_put(&ctx->kobj); error_kobj_init: + if (ctx->file) { + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + ctx->fh.m2m_ctx = NULL; + } error_m2m_init: if (ctx->file) { v4l2_fh_del(&ctx->fh); @@ -1118,10 +1123,12 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, if (ctx->file) { v4l2_ctrl_handler_free(&ctx->ctrl_handler); SDEDEV_DBG(rot_dev->dev, "release streams s:%d\n", session_id); - v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, + if (ctx->fh.m2m_ctx) { + v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, + v4l2_m2m_streamoff(file, ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + } } mutex_unlock(&rot_dev->lock); SDEDEV_DBG(rot_dev->dev, "release submit work s:%d\n", session_id); @@ -1158,9 +1165,12 @@ static int sde_rotator_ctx_release(struct sde_rotator_ctx *ctx, sysfs_remove_group(&ctx->kobj, &sde_rotator_fs_attr_group); kobject_put(&ctx->kobj); if (ctx->file) { - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); + if (ctx->fh.m2m_ctx) + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + if (ctx->fh.vdev) { + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + } } kfree(ctx->vbinfo_out); kfree(ctx->vbinfo_cap); -- GitLab From 40edda1b9784d64f586a772d178d6189bd614446 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Fri, 27 Apr 2018 13:58:25 -0600 Subject: [PATCH 1548/1834] defconfig: arm: msm: enable QMP debugfs support for sdxpoorwills Enable QMP_DEBUGFS_CLIENT to allow debugfs support to write to AOP on sdxpoorwills. Change-Id: I414fce461f8f4a6a45c89f77ef0baec95ba80a35 Signed-off-by: Lina Iyer --- arch/arm/configs/sdxpoorwills-perf_defconfig | 1 + arch/arm/configs/sdxpoorwills_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index 32ff4467e61c..11530a513624 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -368,6 +368,7 @@ CONFIG_QCOM_COMMAND_DB=y CONFIG_MSM_PM=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_EXTCON_QCOM_SPMI_MISC=y CONFIG_IIO=y CONFIG_PWM=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index a6063c8b3217..2493d1f5d5dc 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -373,6 +373,7 @@ CONFIG_QCOM_COMMAND_DB=y CONFIG_MSM_PM=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QMP_DEBUGFS_CLIENT=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON_QCOM_SPMI_MISC=y CONFIG_IIO=y -- GitLab From 7c843c2a75c8806aa2d002ad41213a19c063f689 Mon Sep 17 00:00:00 2001 From: Amit Kushwaha Date: Mon, 9 Apr 2018 20:41:14 +0530 Subject: [PATCH 1549/1834] msm: kgsl: create sysfs entries to expose memory usage Added sysfs entries to show kgsl memory usage statistics. gpumem_mapped: kgsl memory mapped in the process address space. gpumem_unmapped: kgsl allocated memory but not mapped in process. imported_mem: graphics memory not allocated by the kgsl. Below is the sysfs path for new entries: /sys/class/kgsl/kgsl/proc// Change-Id: I08c2014d28dc0ca1e2b54ebf966d00143b303b54 Signed-off-by: Amit Kushwaha --- drivers/gpu/msm/kgsl.c | 11 ++++- drivers/gpu/msm/kgsl_device.h | 2 + drivers/gpu/msm/kgsl_sharedmem.c | 75 ++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 2e617429b2c8..174da8d9e3b7 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -458,6 +458,10 @@ static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry) type = kgsl_memdesc_usermem_type(&entry->memdesc); entry->priv->stats[type].cur -= entry->memdesc.size; + + if (type != KGSL_MEM_ENTRY_ION) + entry->priv->gpumem_mapped -= entry->memdesc.mapsize; + spin_unlock(&entry->priv->mem_lock); kgsl_mmu_put_gpuaddr(&entry->memdesc); @@ -4132,13 +4136,18 @@ static int kgsl_gpumem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct kgsl_mem_entry *entry = vma->vm_private_data; + int ret; if (!entry) return VM_FAULT_SIGBUS; if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault) return VM_FAULT_SIGBUS; - return entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf); + ret = entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf); + if ((ret == 0) || (ret == VM_FAULT_NOPAGE)) + entry->priv->gpumem_mapped += PAGE_SIZE; + + return ret; } static void diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index c737801bdb0b..c8c6456343e5 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -446,6 +446,7 @@ struct kgsl_context { * @kobj: Pointer to a kobj for the sysfs directory for this process * @debug_root: Pointer to the debugfs root for this process * @stats: Memory allocation statistics for this process + * @gpumem_mapped: KGSL memory mapped in the process address space * @syncsource_idr: sync sources created by this process * @syncsource_lock: Spinlock to protect the syncsource idr * @fd_count: Counter for the number of FDs for this process @@ -467,6 +468,7 @@ struct kgsl_process_private { uint64_t cur; uint64_t max; } stats[KGSL_MEM_ENTRY_MAX]; + uint64_t gpumem_mapped; struct idr syncsource_idr; spinlock_t syncsource_lock; int fd_count; diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 3702893566b5..2e84bade75ee 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -97,6 +97,75 @@ struct mem_entry_stats { static void kgsl_cma_unlock_secure(struct kgsl_memdesc *memdesc); +static ssize_t +imported_mem_show(struct kgsl_process_private *priv, + int type, char *buf) +{ + struct kgsl_mem_entry *entry; + uint64_t imported_mem = 0; + int id = 0; + + spin_lock(&priv->mem_lock); + for (entry = idr_get_next(&priv->mem_idr, &id); entry; + id++, entry = idr_get_next(&priv->mem_idr, &id)) { + + int egl_surface_count = 0, egl_image_count = 0; + struct kgsl_memdesc *m; + + if (kgsl_mem_entry_get(entry) == 0) + continue; + spin_unlock(&priv->mem_lock); + + m = &entry->memdesc; + if (kgsl_memdesc_usermem_type(m) == KGSL_MEM_ENTRY_ION) { + kgsl_get_egl_counts(entry, &egl_surface_count, + &egl_image_count); + + if (kgsl_memdesc_get_memtype(m) == + KGSL_MEMTYPE_EGL_SURFACE) + imported_mem += m->size; + else if (egl_surface_count == 0) { + uint64_t size = m->size; + + do_div(size, (egl_image_count ? + egl_image_count : 1)); + imported_mem += size; + } + } + + kgsl_mem_entry_put(entry); + spin_lock(&priv->mem_lock); + } + spin_unlock(&priv->mem_lock); + + return scnprintf(buf, PAGE_SIZE, "%llu\n", imported_mem); +} + +static ssize_t +gpumem_mapped_show(struct kgsl_process_private *priv, + int type, char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%llu\n", + priv->gpumem_mapped); +} + +static ssize_t +gpumem_unmapped_show(struct kgsl_process_private *priv, int type, char *buf) +{ + if (priv->gpumem_mapped > priv->stats[type].cur) + return -EIO; + + return scnprintf(buf, PAGE_SIZE, "%llu\n", + priv->stats[type].cur - priv->gpumem_mapped); +} + +static struct kgsl_mem_entry_attribute debug_memstats[] = { + __MEM_ENTRY_ATTR(0, imported_mem, imported_mem_show), + __MEM_ENTRY_ATTR(0, gpumem_mapped, gpumem_mapped_show), + __MEM_ENTRY_ATTR(KGSL_MEM_ENTRY_KERNEL, gpumem_unmapped, + gpumem_unmapped_show), +}; + /** * Show the current amount of memory allocated for the given memtype */ @@ -219,7 +288,13 @@ void kgsl_process_init_sysfs(struct kgsl_device *device, &mem_stats[i].max_attr.attr)) WARN(1, "Couldn't create sysfs file '%s'\n", mem_stats[i].max_attr.attr.name); + } + for (i = 0; i < ARRAY_SIZE(debug_memstats); i++) { + if (sysfs_create_file(&private->kobj, + &debug_memstats[i].attr)) + WARN(1, "Couldn't create sysfs file '%s'\n", + debug_memstats[i].attr.name); } } -- GitLab From c7438af682d99bb7e57d04d6fa5a4d5da0a0093f Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Tue, 13 Mar 2018 16:11:24 +0530 Subject: [PATCH 1550/1834] clk: msm: mdss: add support for DSI 12nm PLL driver Add change to support DSI PLL 12nm driver for SDM439 target. DSI PLL is needed to drive the DSI host controller and DSI PHY interface. Change-Id: I955db504f57c32f5f16a86f586f44c894d893feb Signed-off-by: Padmanabhan Komanduru --- .../devicetree/bindings/fb/mdss-pll.txt | 2 +- drivers/clk/msm/mdss/Makefile | 2 + drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c | 820 ++++++++++++++++++ drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c | 738 ++++++++++++++++ drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h | 89 ++ drivers/clk/msm/mdss/mdss-dsi-pll.h | 4 +- drivers/clk/msm/mdss/mdss-pll.c | 7 + drivers/clk/msm/mdss/mdss-pll.h | 2 + include/dt-bindings/clock/msm-clocks-8952.h | 5 + 9 files changed, 1667 insertions(+), 2 deletions(-) create mode 100644 drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c create mode 100644 drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c create mode 100644 drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h diff --git a/Documentation/devicetree/bindings/fb/mdss-pll.txt b/Documentation/devicetree/bindings/fb/mdss-pll.txt index 6b9238c4bf30..5c0bb2a9526b 100644 --- a/Documentation/devicetree/bindings/fb/mdss-pll.txt +++ b/Documentation/devicetree/bindings/fb/mdss-pll.txt @@ -14,7 +14,7 @@ Required properties: "qcom,mdss_hdmi_pll_8996_v2", "qcom,mdss_dsi_pll_8996_v2", "qcom,mdss_hdmi_pll_8996_v3", "qcom,mdss_dsi_pll_8952", "qcom,mdss_dsi_pll_8937", "qcom,mdss_hdmi_pll_8996_v3_1p8", - "qcom,mdss_dsi_pll_8953" + "qcom,mdss_dsi_pll_8953", "qcom,mdss_dsi_pll_sdm439" - cell-index: Specifies the controller used - reg: offset and length of the register set for the device. - reg-names : names to refer to register sets related to this device diff --git a/drivers/clk/msm/mdss/Makefile b/drivers/clk/msm/mdss/Makefile index 6285714ddbc1..3b884dc72951 100644 --- a/drivers/clk/msm/mdss/Makefile +++ b/drivers/clk/msm/mdss/Makefile @@ -5,3 +5,5 @@ obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-28lpm.o obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996.o obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-8996-util.o obj-$(CONFIG_MSM_MDSS_PLL) += mdss-hdmi-pll-8996.o +obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-12nm.o +obj-$(CONFIG_MSM_MDSS_PLL) += mdss-dsi-pll-12nm-util.o diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c new file mode 100644 index 000000000000..f2ed36ca1d6c --- /dev/null +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm-util.c @@ -0,0 +1,820 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include + +#include "mdss-pll.h" +#include "mdss-dsi-pll.h" +#include "mdss-dsi-pll-12nm.h" + +#define DSI_PLL_POLL_MAX_READS 15 +#define DSI_PLL_POLL_TIMEOUT_US 1000 + +int pixel_div_set_div(struct div_clk *clk, int div) +{ + struct mdss_pll_resources *pll = clk->priv; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; + + /* Programming during vco_prepare. Keep this value */ + pdb->param.pixel_divhf = (div - 1); + + pr_debug("ndx=%d div=%d divhf=%d\n", + pll->index, div, pdb->param.pixel_divhf); + + return 0; +} + +int pixel_div_get_div(struct div_clk *clk) +{ + u32 div; + int rc; + struct mdss_pll_resources *pll = clk->priv; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + div = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SSC9); + div &= 0x7f; + pr_debug("pixel_div = %d\n", (div+1)); + + mdss_pll_resource_enable(pll, false); + + return (div + 1); +} + +int set_post_div_mux_sel(struct mux_clk *clk, int sel) +{ + struct mdss_pll_resources *pll = clk->priv; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; + + /* Programming during vco_prepare. Keep this value */ + pdb->param.post_div_mux = sel; + + pr_debug("ndx=%d post_div_mux_sel=%d p_div=%d\n", + pll->index, sel, (u32) BIT(sel)); + + return 0; +} + +int get_post_div_mux_sel(struct mux_clk *clk) +{ + u32 sel = 0; + u32 vco_cntrl = 0, cpbias_cntrl = 0; + int rc; + struct mdss_pll_resources *pll = clk->priv; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + vco_cntrl = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_VCO_CTRL); + vco_cntrl &= 0x30; + + cpbias_cntrl = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL); + cpbias_cntrl = ((cpbias_cntrl >> 6) & 0x1); + + if (cpbias_cntrl == 0) { + if (vco_cntrl == 0x00) + sel = 0; + else if (vco_cntrl == 0x10) + sel = 2; + else if (vco_cntrl == 0x20) + sel = 3; + else if (vco_cntrl == 0x30) + sel = 4; + } else if (cpbias_cntrl == 1) { + if (vco_cntrl == 0x30) + sel = 2; + else if (vco_cntrl == 0x00) + sel = 5; + } + + mdss_pll_resource_enable(pll, false); + + return sel; +} + +int set_gp_mux_sel(struct mux_clk *clk, int sel) +{ + struct mdss_pll_resources *pll = clk->priv; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; + + /* Programming during vco_prepare. Keep this value */ + pdb->param.gp_div_mux = sel; + + pr_debug("ndx=%d gp_div_mux_sel=%d gp_cntrl=%d\n", + pll->index, sel, (u32) BIT(sel)); + + return 0; +} + +int get_gp_mux_sel(struct mux_clk *clk) +{ + u32 sel = 0; + int rc; + struct mdss_pll_resources *pll = clk->priv; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll resources\n"); + return rc; + } + + sel = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_PLL_CTRL); + sel = (sel >> 5) & 0x7; + pr_debug("gp_cntrl = %d\n", sel); + + mdss_pll_resource_enable(pll, false); + + return sel; +} + +static bool pll_is_pll_locked_12nm(struct mdss_pll_resources *pll) +{ + u32 status; + bool pll_locked; + + /* poll for PLL ready status */ + if (readl_poll_timeout_atomic((pll->pll_base + + DSIPHY_STAT0), + status, + ((status & BIT(1)) > 0), + DSI_PLL_POLL_MAX_READS, + DSI_PLL_POLL_TIMEOUT_US)) { + pr_err("DSI PLL ndx=%d status=%x failed to Lock\n", + pll->index, status); + pll_locked = false; + } else { + pll_locked = true; + } + + return pll_locked; +} + +int dsi_pll_enable_seq_12nm(struct mdss_pll_resources *pll) +{ + int rc = 0; + struct dsi_pll_db *pdb; + void __iomem *pll_base; + + if (!pll) { + pr_err("Invalid PLL resources\n"); + return -EINVAL; + } + + pdb = (struct dsi_pll_db *)pll->priv; + if (!pdb) { + pr_err("No priv found\n"); + return -EINVAL; + } + + pll_base = pll->pll_base; + + MDSS_PLL_REG_W(pll_base, DSIPHY_SYS_CTRL, 0x49); + wmb(); /* make sure register committed before enabling branch clocks */ + udelay(5); /* h/w recommended delay */ + MDSS_PLL_REG_W(pll_base, DSIPHY_SYS_CTRL, 0xc9); + wmb(); /* make sure register committed before enabling branch clocks */ + udelay(50); /* h/w recommended delay */ + + if (!pll_is_pll_locked_12nm(pll)) { + pr_err("DSI PLL ndx=%d lock failed!\n", + pll->index); + rc = -EINVAL; + goto init_lock_err; + } + + pr_debug("DSI PLL ndx:%d Locked!\n", pll->index); + +init_lock_err: + return rc; +} + +static int dsi_pll_enable(struct clk *c) +{ + int i, rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + /* Try all enable sequences until one succeeds */ + for (i = 0; i < vco->pll_en_seq_cnt; i++) { + rc = vco->pll_enable_seqs[i](pll); + pr_debug("DSI PLL %s after sequence #%d\n", + rc ? "unlocked" : "locked", i + 1); + if (!rc) + break; + } + + if (rc) + pr_err("ndx=%d DSI PLL failed to lock\n", pll->index); + else + pll->pll_on = true; + + return rc; +} + +static int dsi_pll_relock(struct mdss_pll_resources *pll) +{ + void __iomem *pll_base = pll->pll_base; + u32 data = 0; + int rc = 0; + + data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_POWERUP_CTRL); + data &= ~BIT(1); /* remove ONPLL_OVR_EN bit */ + data |= 0x1; /* set ONPLL_OVN to 0x1 */ + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_POWERUP_CTRL, data); + ndelay(500); /* h/w recommended delay */ + + if (!pll_is_pll_locked_12nm(pll)) { + pr_err("DSI PLL ndx=%d lock failed!\n", + pll->index); + rc = -EINVAL; + goto relock_err; + } + ndelay(50); /* h/w recommended delay */ + + data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_CTRL); + data |= 0x01; /* set CLK_SEL bits to 0x1 */ + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); + ndelay(500); /* h/w recommended delay */ + wmb(); /* make sure register committed before enabling branch clocks */ + pll->pll_on = true; +relock_err: + return rc; +} + +static void dsi_pll_disable(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + void __iomem *pll_base = pll->pll_base; + u32 data = 0; + + if (!pll->pll_on && + mdss_pll_resource_enable(pll, true)) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return; + } + + data = MDSS_PLL_REG_R(pll_base, DSIPHY_SSC0); + data &= ~BIT(6); /* disable GP_CLK_EN */ + MDSS_PLL_REG_W(pll_base, DSIPHY_SSC0, data); + ndelay(500); /* h/w recommended delay */ + + data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_CTRL); + data &= ~0x03; /* remove CLK_SEL bits */ + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); + ndelay(500); /* h/w recommended delay */ + + data = MDSS_PLL_REG_R(pll_base, DSIPHY_PLL_POWERUP_CTRL); + data &= ~0x1; /* remove ONPLL_OVR bit */ + data |= BIT(1); /* set ONPLL_OVR_EN to 0x1 */ + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_POWERUP_CTRL, data); + ndelay(500); /* h/w recommended delay */ + wmb(); /* make sure register committed before disabling branch clocks */ + pll->handoff_resources = false; + + mdss_pll_resource_enable(pll, false); + + pll->pll_on = false; + + pr_debug("DSI PLL ndx=%d Disabled\n", pll->index); +} + +static u32 __mdss_dsi_get_hsfreqrange(u64 target_freq) +{ + u64 bitclk_rate_mhz = div_u64((target_freq * 2), 1000000); + + if (bitclk_rate_mhz >= 80 && bitclk_rate_mhz < 90) + return 0x00; + else if (bitclk_rate_mhz >= 90 && bitclk_rate_mhz < 100) + return 0x10; + else if (bitclk_rate_mhz >= 100 && bitclk_rate_mhz < 110) + return 0x20; + else if (bitclk_rate_mhz >= 110 && bitclk_rate_mhz < 120) + return 0x30; + else if (bitclk_rate_mhz >= 120 && bitclk_rate_mhz < 130) + return 0x01; + else if (bitclk_rate_mhz >= 130 && bitclk_rate_mhz < 140) + return 0x11; + else if (bitclk_rate_mhz >= 140 && bitclk_rate_mhz < 150) + return 0x21; + else if (bitclk_rate_mhz >= 150 && bitclk_rate_mhz < 160) + return 0x31; + else if (bitclk_rate_mhz >= 160 && bitclk_rate_mhz < 170) + return 0x02; + else if (bitclk_rate_mhz >= 170 && bitclk_rate_mhz < 180) + return 0x12; + else if (bitclk_rate_mhz >= 180 && bitclk_rate_mhz < 190) + return 0x22; + else if (bitclk_rate_mhz >= 190 && bitclk_rate_mhz < 205) + return 0x32; + else if (bitclk_rate_mhz >= 205 && bitclk_rate_mhz < 220) + return 0x03; + else if (bitclk_rate_mhz >= 220 && bitclk_rate_mhz < 235) + return 0x13; + else if (bitclk_rate_mhz >= 235 && bitclk_rate_mhz < 250) + return 0x23; + else if (bitclk_rate_mhz >= 250 && bitclk_rate_mhz < 275) + return 0x33; + else if (bitclk_rate_mhz >= 275 && bitclk_rate_mhz < 300) + return 0x04; + else if (bitclk_rate_mhz >= 300 && bitclk_rate_mhz < 325) + return 0x14; + else if (bitclk_rate_mhz >= 325 && bitclk_rate_mhz < 350) + return 0x25; + else if (bitclk_rate_mhz >= 350 && bitclk_rate_mhz < 400) + return 0x35; + else if (bitclk_rate_mhz >= 400 && bitclk_rate_mhz < 450) + return 0x05; + else if (bitclk_rate_mhz >= 450 && bitclk_rate_mhz < 500) + return 0x16; + else if (bitclk_rate_mhz >= 500 && bitclk_rate_mhz < 550) + return 0x26; + else if (bitclk_rate_mhz >= 550 && bitclk_rate_mhz < 600) + return 0x37; + else if (bitclk_rate_mhz >= 600 && bitclk_rate_mhz < 650) + return 0x07; + else if (bitclk_rate_mhz >= 650 && bitclk_rate_mhz < 700) + return 0x18; + else if (bitclk_rate_mhz >= 700 && bitclk_rate_mhz < 750) + return 0x28; + else if (bitclk_rate_mhz >= 750 && bitclk_rate_mhz < 800) + return 0x39; + else if (bitclk_rate_mhz >= 800 && bitclk_rate_mhz < 850) + return 0x09; + else if (bitclk_rate_mhz >= 850 && bitclk_rate_mhz < 900) + return 0x19; + else if (bitclk_rate_mhz >= 900 && bitclk_rate_mhz < 950) + return 0x29; + else if (bitclk_rate_mhz >= 950 && bitclk_rate_mhz < 1000) + return 0x3a; + else if (bitclk_rate_mhz >= 1000 && bitclk_rate_mhz < 1050) + return 0x0a; + else if (bitclk_rate_mhz >= 1050 && bitclk_rate_mhz < 1100) + return 0x1a; + else if (bitclk_rate_mhz >= 1100 && bitclk_rate_mhz < 1150) + return 0x2a; + else if (bitclk_rate_mhz >= 1150 && bitclk_rate_mhz < 1200) + return 0x3b; + else if (bitclk_rate_mhz >= 1200 && bitclk_rate_mhz < 1250) + return 0x0b; + else if (bitclk_rate_mhz >= 1250 && bitclk_rate_mhz < 1300) + return 0x1b; + else if (bitclk_rate_mhz >= 1300 && bitclk_rate_mhz < 1350) + return 0x2b; + else if (bitclk_rate_mhz >= 1350 && bitclk_rate_mhz < 1400) + return 0x3c; + else if (bitclk_rate_mhz >= 1400 && bitclk_rate_mhz < 1450) + return 0x0c; + else if (bitclk_rate_mhz >= 1450 && bitclk_rate_mhz < 1500) + return 0x1c; + else if (bitclk_rate_mhz >= 1500 && bitclk_rate_mhz < 1550) + return 0x2c; + else if (bitclk_rate_mhz >= 1550 && bitclk_rate_mhz < 1600) + return 0x3d; + else if (bitclk_rate_mhz >= 1600 && bitclk_rate_mhz < 1650) + return 0x0d; + else if (bitclk_rate_mhz >= 1650 && bitclk_rate_mhz < 1700) + return 0x1d; + else if (bitclk_rate_mhz >= 1700 && bitclk_rate_mhz < 1750) + return 0x2e; + else if (bitclk_rate_mhz >= 1750 && bitclk_rate_mhz < 1800) + return 0x3e; + else if (bitclk_rate_mhz >= 1800 && bitclk_rate_mhz < 1850) + return 0x0e; + else if (bitclk_rate_mhz >= 1850 && bitclk_rate_mhz < 1900) + return 0x1e; + else if (bitclk_rate_mhz >= 1900 && bitclk_rate_mhz < 1950) + return 0x2f; + else if (bitclk_rate_mhz >= 1950 && bitclk_rate_mhz < 2000) + return 0x3f; + else if (bitclk_rate_mhz >= 2000 && bitclk_rate_mhz < 2050) + return 0x0f; + else if (bitclk_rate_mhz >= 2050 && bitclk_rate_mhz < 2100) + return 0x40; + else if (bitclk_rate_mhz >= 2100 && bitclk_rate_mhz < 2150) + return 0x41; + else if (bitclk_rate_mhz >= 2150 && bitclk_rate_mhz < 2200) + return 0x42; + else if (bitclk_rate_mhz >= 2200 && bitclk_rate_mhz < 2250) + return 0x43; + else if (bitclk_rate_mhz >= 2250 && bitclk_rate_mhz < 2300) + return 0x44; + else if (bitclk_rate_mhz >= 2300 && bitclk_rate_mhz < 2350) + return 0x45; + else if (bitclk_rate_mhz >= 2350 && bitclk_rate_mhz < 2400) + return 0x46; + else if (bitclk_rate_mhz >= 2400 && bitclk_rate_mhz < 2450) + return 0x47; + else if (bitclk_rate_mhz >= 2450 && bitclk_rate_mhz < 2500) + return 0x48; + else + return 0x49; +} + +static void __mdss_dsi_get_pll_vco_cntrl(u64 target_freq, u32 post_div_mux, + u32 *vco_cntrl, u32 *cpbias_cntrl) +{ + u64 target_freq_mhz = div_u64(target_freq, 1000000); + u32 p_div = BIT(post_div_mux); + + if (p_div == 1) { + *vco_cntrl = 0x00; + *cpbias_cntrl = 0; + } else if (p_div == 2) { + *vco_cntrl = 0x30; + *cpbias_cntrl = 1; + } else if (p_div == 4) { + *vco_cntrl = 0x10; + *cpbias_cntrl = 0; + } else if (p_div == 8) { + *vco_cntrl = 0x20; + *cpbias_cntrl = 0; + } else if (p_div == 16) { + *vco_cntrl = 0x30; + *cpbias_cntrl = 0; + } else { + *vco_cntrl = 0x00; + *cpbias_cntrl = 1; + } + + if (target_freq_mhz <= 1250 && target_freq_mhz >= 1092) + *vco_cntrl = *vco_cntrl | 2; + else if (target_freq_mhz < 1092 && target_freq_mhz >= 950) + *vco_cntrl = *vco_cntrl | 3; + else if (target_freq_mhz < 950 && target_freq_mhz >= 712) + *vco_cntrl = *vco_cntrl | 1; + else if (target_freq_mhz < 712 && target_freq_mhz >= 546) + *vco_cntrl = *vco_cntrl | 2; + else if (target_freq_mhz < 546 && target_freq_mhz >= 475) + *vco_cntrl = *vco_cntrl | 3; + else if (target_freq_mhz < 475 && target_freq_mhz >= 356) + *vco_cntrl = *vco_cntrl | 1; + else if (target_freq_mhz < 356 && target_freq_mhz >= 273) + *vco_cntrl = *vco_cntrl | 2; + else if (target_freq_mhz < 273 && target_freq_mhz >= 237) + *vco_cntrl = *vco_cntrl | 3; + else if (target_freq_mhz < 237 && target_freq_mhz >= 178) + *vco_cntrl = *vco_cntrl | 1; + else if (target_freq_mhz < 178 && target_freq_mhz >= 136) + *vco_cntrl = *vco_cntrl | 2; + else if (target_freq_mhz < 136 && target_freq_mhz >= 118) + *vco_cntrl = *vco_cntrl | 3; + else if (target_freq_mhz < 118 && target_freq_mhz >= 89) + *vco_cntrl = *vco_cntrl | 1; + else if (target_freq_mhz < 89 && target_freq_mhz >= 68) + *vco_cntrl = *vco_cntrl | 2; + else if (target_freq_mhz < 68 && target_freq_mhz >= 57) + *vco_cntrl = *vco_cntrl | 3; + else if (target_freq_mhz < 57 && target_freq_mhz >= 44) + *vco_cntrl = *vco_cntrl | 1; + else + *vco_cntrl = *vco_cntrl | 2; +} + +static u32 __mdss_dsi_get_osc_freq_target(u64 target_freq) +{ + u64 target_freq_mhz = div_u64(target_freq, 1000000); + + if (target_freq_mhz <= 1000) + return 1315; + else if (target_freq_mhz > 1000 && target_freq_mhz <= 1500) + return 1839; + else + return 0; +} + +static u64 __mdss_dsi_pll_get_m_div(u64 vco_rate) +{ + return div_u64((vco_rate * 4), 19200000); +} + +static u32 __mdss_dsi_get_fsm_ovr_ctrl(u64 target_freq) +{ + u64 bitclk_rate_mhz = div_u64((target_freq * 2), 1000000); + + if (bitclk_rate_mhz > 1500 && bitclk_rate_mhz <= 2500) + return 0; + else + return BIT(6); +} + +static void mdss_dsi_pll_12nm_calc_reg(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + struct dsi_pll_param *param = &pdb->param; + u64 target_freq = 0; + + target_freq = div_u64(pll->vco_current_rate, + BIT(pdb->param.post_div_mux)); + + param->hsfreqrange = __mdss_dsi_get_hsfreqrange(target_freq); + __mdss_dsi_get_pll_vco_cntrl(target_freq, param->post_div_mux, + ¶m->vco_cntrl, ¶m->cpbias_cntrl); + param->osc_freq_target = __mdss_dsi_get_osc_freq_target(target_freq); + param->m_div = (u32) __mdss_dsi_pll_get_m_div(pll->vco_current_rate); + param->fsm_ovr_ctrl = __mdss_dsi_get_fsm_ovr_ctrl(target_freq); + param->prop_cntrl = 0x05; + param->int_cntrl = 0x00; + param->gmp_cntrl = 0x1; +} + +static void pll_db_commit_12nm(struct mdss_pll_resources *pll, + struct dsi_pll_db *pdb) +{ + void __iomem *pll_base = pll->pll_base; + struct dsi_pll_param *param = &pdb->param; + char data = 0; + + MDSS_PLL_REG_W(pll_base, DSIPHY_CTRL0, 0x01); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, 0x05); + MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_LOOP_CTRL, 0x01); + + data = ((param->hsfreqrange & 0x7f) | BIT(7)); + MDSS_PLL_REG_W(pll_base, DSIPHY_HS_FREQ_RAN_SEL, data); + + data = ((param->vco_cntrl & 0x3f) | BIT(6)); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_VCO_CTRL, data); + + data = (param->osc_freq_target & 0x7f); + MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0, data); + + data = ((param->osc_freq_target & 0xf80) >> 7); + MDSS_PLL_REG_W(pll_base, DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_1, data); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_INPUT_LOOP_DIV_RAT_CTRL, 0x30); + + data = (param->m_div & 0x3f); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOOP_DIV_RATIO_0, data); + + data = ((param->m_div & 0xfc0) >> 6); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOOP_DIV_RATIO_1, data); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_INPUT_DIV_PLL_OVR, 0x60); + + data = (param->prop_cntrl & 0x3f); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PROP_CHRG_PUMP_CTRL, data); + + data = (param->int_cntrl & 0x3f); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_INTEG_CHRG_PUMP_CTRL, data); + + data = ((param->gmp_cntrl & 0x3) << 4); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_GMP_CTRL_DIG_TST, data); + + data = ((param->cpbias_cntrl & 0x1) << 6) | BIT(4); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL, data); + + data = ((param->gp_div_mux & 0x7) << 5) | 0x5; + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_CTRL, data); + + data = (param->pixel_divhf & 0x7f); + MDSS_PLL_REG_W(pll_base, DSIPHY_SSC9, data); + + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_PROG_CTRL, 0x03); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL, 0x50); + MDSS_PLL_REG_W(pll_base, + DSIPHY_SLEWRATE_FSM_OVR_CTRL, param->fsm_ovr_ctrl); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PHA_ERR_CTRL_0, 0x01); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PHA_ERR_CTRL_1, 0x00); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOCK_FILTER, 0xff); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_UNLOCK_FILTER, 0x03); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_PRO_DLY_RELOCK, 0x0c); + MDSS_PLL_REG_W(pll_base, DSIPHY_PLL_LOCK_DET_MODE_SEL, 0x02); + + pr_debug("pll:%d\n", pll->index); + wmb(); /* make sure register committed before preparing the clocks */ +} + +int pll_vco_set_rate_12nm(struct clk *c, unsigned long rate) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + struct dsi_pll_db *pdb; + + pdb = (struct dsi_pll_db *)pll->priv; + if (!pdb) { + pr_err("pll pdb not found\n"); + rc = -EINVAL; + goto error; + } + + pr_debug("%s: ndx=%d rate=%lu\n", __func__, pll->index, rate); + + pll->vco_current_rate = rate; + pll->vco_ref_clk_rate = vco->ref_clk_rate; +error: + return rc; +} + +static unsigned long pll_vco_get_rate_12nm(struct clk *c) +{ + u64 vco_rate = 0; + u32 m_div_5_0 = 0, m_div_11_6 = 0, m_div = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + u64 ref_clk = vco->ref_clk_rate; + int rc; + struct mdss_pll_resources *pll = vco->priv; + + if (is_gdsc_disabled(pll)) + return 0; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return rc; + } + + m_div_5_0 = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_LOOP_DIV_RATIO_0); + m_div_5_0 &= 0x3f; + pr_debug("m_div_5_0 = 0x%x\n", m_div_5_0); + + m_div_11_6 = MDSS_PLL_REG_R(pll->pll_base, + DSIPHY_PLL_LOOP_DIV_RATIO_1); + m_div_11_6 &= 0x3f; + pr_debug("m_div_11_6 = 0x%x\n", m_div_11_6); + + m_div = ((m_div_11_6 << 6) | (m_div_5_0)); + + vco_rate = div_u64((ref_clk * m_div), 4); + + pr_debug("returning vco rate = %lu\n", (unsigned long)vco_rate); + + mdss_pll_resource_enable(pll, false); + + return (unsigned long)vco_rate; +} + +long pll_vco_round_rate_12nm(struct clk *c, unsigned long rate) +{ + unsigned long rrate = rate; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + + if (rate < vco->min_rate) + rrate = vco->min_rate; + if (rate > vco->max_rate) + rrate = vco->max_rate; + + return rrate; +} + +enum handoff pll_vco_handoff_12nm(struct clk *c) +{ + int rc; + enum handoff ret = HANDOFF_DISABLED_CLK; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + if (is_gdsc_disabled(pll)) + return HANDOFF_DISABLED_CLK; + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("Failed to enable mdss dsi pll=%d\n", pll->index); + return ret; + } + + if (pll_is_pll_locked_12nm(pll)) { + pll->handoff_resources = true; + pll->pll_on = true; + c->rate = pll_vco_get_rate_12nm(c); + ret = HANDOFF_ENABLED_CLK; + } else { + mdss_pll_resource_enable(pll, false); + } + + return ret; +} + +int pll_vco_prepare_12nm(struct clk *c) +{ + int rc = 0; + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + struct dsi_pll_db *pdb; + u32 data = 0; + + if (!pll) { + pr_err("Dsi pll resources are not available\n"); + return -EINVAL; + } + + pdb = (struct dsi_pll_db *)pll->priv; + if (!pdb) { + pr_err("No prov found\n"); + return -EINVAL; + } + + rc = mdss_pll_resource_enable(pll, true); + if (rc) { + pr_err("ndx=%d Failed to enable mdss dsi pll resources\n", + pll->index); + return rc; + } + + if ((pll->vco_cached_rate != 0) + && (pll->vco_cached_rate == c->rate)) { + rc = c->ops->set_rate(c, pll->vco_cached_rate); + if (rc) { + pr_err("index=%d vco_set_rate failed. rc=%d\n", + rc, pll->index); + goto error; + } + + data = MDSS_PLL_REG_R(pll->pll_base, DSIPHY_SYS_CTRL); + if (data & BIT(7)) { /* DSI PHY in LP-11 or ULPS */ + rc = dsi_pll_relock(pll); + if (rc) + goto error; + else + goto end; + } + } + + mdss_dsi_pll_12nm_calc_reg(pll, pdb); + + /* commit DSI vco */ + pll_db_commit_12nm(pll, pdb); + + rc = dsi_pll_enable(c); + +error: + if (rc) { + mdss_pll_resource_enable(pll, false); + pr_err("ndx=%d failed to enable dsi pll\n", pll->index); + } + +end: + return rc; +} + +void pll_vco_unprepare_12nm(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("Dsi pll resources are not available\n"); + return; + } + + pll->vco_cached_rate = c->rate; + dsi_pll_disable(c); +} + +int pll_vco_enable_12nm(struct clk *c) +{ + struct dsi_pll_vco_clk *vco = to_vco_clk(c); + struct mdss_pll_resources *pll = vco->priv; + + if (!pll) { + pr_err("Dsi pll resources are not available\n"); + return -EINVAL; + } + + if (!pll->pll_on) { + pr_err("DSI PLL not enabled, return\n"); + return -EINVAL; + } + + MDSS_PLL_REG_W(pll->pll_base, DSIPHY_SSC0, 0x40); + wmb(); /* make sure register committed before enabling branch clocks */ + + return 0; +} diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c new file mode 100644 index 000000000000..210742b93373 --- /dev/null +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.c @@ -0,0 +1,738 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdss-pll.h" +#include "mdss-dsi-pll.h" +#include "mdss-dsi-pll-12nm.h" + +/* + * Clock tree model for generating DSI byte clock and pclk for 12nm DSI PLL + * + * + * +---------------+ + * +----------| vco_clk |----------+ + * | +---------------+ | + * | | + * | | + * | | + * +---------+---------+----+----+---------+---------+ | + * | | | | | | | + * | | | | | | | + * | | | | | | | + * +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ | + * | DIV(1)| | DIV(2)| | DIV(4)| | DIV(8)| |DIV(16)| |DIV(32)| | + * +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ | + * | | | | | | | + * | | +---+ +---+ | | | + * | +-----------+ | | +-----------+ | | + * +-------------------+ | | | | +-------------------+ | + * | | | | | | | + * +--v-v-v-v-v-v---+ | + * \ post_div_mux / | + * \ / | + * +-----+----+ +---------------------+ + * | | + * +------------------------+ | + * | | + * +----v----+ +---------+---------+----+----+---------+---------+ + * | DIV-4 | | | | | | | + * +----+----+ | | | | | | + * | +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ +---v---+ + * | | DIV(1)| | DIV(2)| | DIV(4)| | DIV(8)| |DIV(16)| |DIV(32)| + * | +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ +---+---+ + * | | | | | | | + * v | | +---+ +---+ | | + * byte_clk_src | +-----------+ | | +-----------+ | + * +-------------------+ | | | | +-------------------+ + * | | | | | | + * +--v-v-v-v-v-v---+ + * \ gp_cntrl_mux / + * \ / + * +-----+----+ + * | + * | + * +-------v-------+ + * | (DIV + 1) | + * | DIV = 0...127 | + * +-------+-------+ + * | + * | + * v + * dsi_pclk input to Clock Controller MND + */ + +static struct dsi_pll_db pll_db[DSI_PLL_NUM]; + +static struct clk_ops pixel_div_clk_src_ops; + +/* Op structures */ +static const struct clk_ops clk_ops_dsi_vco = { + .set_rate = pll_vco_set_rate_12nm, + .round_rate = pll_vco_round_rate_12nm, + .handoff = pll_vco_handoff_12nm, + .prepare = pll_vco_prepare_12nm, + .unprepare = pll_vco_unprepare_12nm, + .enable = pll_vco_enable_12nm, +}; + +static struct clk_div_ops pixel_div_ops = { + .set_div = pixel_div_set_div, + .get_div = pixel_div_get_div, +}; + +static struct clk_mux_ops post_div_mux_ops = { + .set_mux_sel = set_post_div_mux_sel, + .get_mux_sel = get_post_div_mux_sel, +}; + +static struct clk_mux_ops gp_div_mux_ops = { + .set_mux_sel = set_gp_mux_sel, + .get_mux_sel = get_gp_mux_sel, +}; + +static struct dsi_pll_vco_clk dsi0pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 2000000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_12nm, + .c = { + .dbg_name = "dsi0pll_vco_clk_12nm", + .ops = &clk_ops_dsi_vco, + CLK_INIT(dsi0pll_vco_clk.c), + }, +}; + +static struct dsi_pll_vco_clk dsi1pll_vco_clk = { + .ref_clk_rate = 19200000UL, + .min_rate = 1000000000UL, + .max_rate = 2000000000UL, + .pll_en_seq_cnt = 1, + .pll_enable_seqs[0] = dsi_pll_enable_seq_12nm, + .c = { + .dbg_name = "dsi1pll_vco_clk_12nm", + .ops = &clk_ops_dsi_vco, + CLK_INIT(dsi1pll_vco_clk.c), + }, +}; + +static struct div_clk dsi0pll_post_div1 = { + .data = { + .div = 1, + .min_div = 1, + .max_div = 1, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_post_div1", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_div1.c), + }, +}; + +static struct div_clk dsi0pll_post_div2 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_post_div2", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_div2.c), + }, +}; + +static struct div_clk dsi0pll_post_div4 = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_post_div4", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_div4.c), + }, +}; + +static struct div_clk dsi0pll_post_div8 = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_post_div8", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_div8.c), + }, +}; + +static struct div_clk dsi0pll_post_div16 = { + .data = { + .div = 16, + .min_div = 16, + .max_div = 16, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_post_div16", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_div16.c), + }, +}; + +static struct div_clk dsi0pll_post_div32 = { + .data = { + .div = 32, + .min_div = 32, + .max_div = 32, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_post_div32", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_div32.c), + }, +}; + +static struct mux_clk dsi0pll_post_div_mux = { + .num_parents = 6, + .parents = (struct clk_src[]) { + {&dsi0pll_post_div1.c, 0}, + {&dsi0pll_post_div2.c, 1}, + {&dsi0pll_post_div4.c, 2}, + {&dsi0pll_post_div8.c, 3}, + {&dsi0pll_post_div16.c, 4}, + {&dsi0pll_post_div32.c, 5}, + }, + .ops = &post_div_mux_ops, + .c = { + .parent = &dsi0pll_post_div1.c, + .dbg_name = "dsi0pll_post_div_mux", + .ops = &clk_ops_gen_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_post_div_mux.c), + } +}; + +static struct div_clk dsi1pll_post_div1 = { + .data = { + .div = 1, + .min_div = 1, + .max_div = 1, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_post_div1", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_div1.c), + }, +}; + +static struct div_clk dsi1pll_post_div2 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_post_div2", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_div2.c), + }, +}; + +static struct div_clk dsi1pll_post_div4 = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_post_div4", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_div4.c), + }, +}; + +static struct div_clk dsi1pll_post_div8 = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_post_div8", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_div8.c), + }, +}; + +static struct div_clk dsi1pll_post_div16 = { + .data = { + .div = 16, + .min_div = 16, + .max_div = 16, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_post_div16", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_div16.c), + }, +}; + +static struct div_clk dsi1pll_post_div32 = { + .data = { + .div = 32, + .min_div = 32, + .max_div = 32, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_post_div32", + .ops = &clk_ops_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_div32.c), + }, +}; + +static struct mux_clk dsi1pll_post_div_mux = { + .num_parents = 6, + .parents = (struct clk_src[]) { + {&dsi1pll_post_div1.c, 0}, + {&dsi1pll_post_div2.c, 1}, + {&dsi1pll_post_div4.c, 2}, + {&dsi1pll_post_div8.c, 3}, + {&dsi1pll_post_div16.c, 4}, + {&dsi1pll_post_div32.c, 5}, + }, + .ops = &post_div_mux_ops, + .c = { + .parent = &dsi1pll_post_div1.c, + .dbg_name = "dsi1pll_post_div_mux", + .ops = &clk_ops_gen_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_post_div_mux.c), + } +}; + +static struct div_clk dsi0pll_gp_div1 = { + .data = { + .div = 1, + .min_div = 1, + .max_div = 1, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_gp_div1", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_gp_div1.c), + }, +}; + +static struct div_clk dsi0pll_gp_div2 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_gp_div2", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_gp_div2.c), + }, +}; + +static struct div_clk dsi0pll_gp_div4 = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_gp_div4", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_gp_div4.c), + }, +}; + +static struct div_clk dsi0pll_gp_div8 = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_gp_div8", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_gp_div8.c), + }, +}; + +static struct div_clk dsi0pll_gp_div16 = { + .data = { + .div = 16, + .min_div = 16, + .max_div = 16, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_gp_div16", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_gp_div16.c), + }, +}; + +static struct div_clk dsi0pll_gp_div32 = { + .data = { + .div = 32, + .min_div = 32, + .max_div = 32, + }, + .c = { + .parent = &dsi0pll_vco_clk.c, + .dbg_name = "dsi0pll_gp_div32", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_gp_div32.c), + }, +}; + +static struct mux_clk dsi0pll_gp_div_mux = { + .num_parents = 6, + .parents = (struct clk_src[]) { + {&dsi0pll_gp_div1.c, 0}, + {&dsi0pll_gp_div2.c, 1}, + {&dsi0pll_gp_div4.c, 2}, + {&dsi0pll_gp_div8.c, 3}, + {&dsi0pll_gp_div16.c, 4}, + {&dsi0pll_gp_div32.c, 5}, + }, + .ops = &gp_div_mux_ops, + .c = { + .parent = &dsi0pll_gp_div1.c, + .dbg_name = "dsi0pll_gp_div_mux", + .ops = &clk_ops_gen_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_gp_div_mux.c), + } +}; + +static struct div_clk dsi1pll_gp_div1 = { + .data = { + .div = 1, + .min_div = 1, + .max_div = 1, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_gp_div1", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_gp_div1.c), + }, +}; + +static struct div_clk dsi1pll_gp_div2 = { + .data = { + .div = 2, + .min_div = 2, + .max_div = 2, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_gp_div2", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_gp_div2.c), + }, +}; + +static struct div_clk dsi1pll_gp_div4 = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_gp_div4", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_gp_div4.c), + }, +}; + +static struct div_clk dsi1pll_gp_div8 = { + .data = { + .div = 8, + .min_div = 8, + .max_div = 8, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_gp_div8", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_gp_div8.c), + }, +}; + +static struct div_clk dsi1pll_gp_div16 = { + .data = { + .div = 16, + .min_div = 16, + .max_div = 16, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_gp_div16", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_gp_div16.c), + }, +}; + +static struct div_clk dsi1pll_gp_div32 = { + .data = { + .div = 32, + .min_div = 32, + .max_div = 32, + }, + .c = { + .parent = &dsi1pll_vco_clk.c, + .dbg_name = "dsi1pll_gp_div32", + .ops = &clk_ops_slave_div, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_gp_div32.c), + }, +}; + +static struct mux_clk dsi1pll_gp_div_mux = { + .num_parents = 6, + .parents = (struct clk_src[]) { + {&dsi1pll_gp_div1.c, 0}, + {&dsi1pll_gp_div2.c, 1}, + {&dsi1pll_gp_div4.c, 2}, + {&dsi1pll_gp_div8.c, 3}, + {&dsi1pll_gp_div16.c, 4}, + {&dsi1pll_gp_div32.c, 5}, + }, + .ops = &gp_div_mux_ops, + .c = { + .parent = &dsi1pll_gp_div1.c, + .dbg_name = "dsi1pll_gp_div_mux", + .ops = &clk_ops_gen_mux, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_gp_div_mux.c), + } +}; + +static struct div_clk dsi0pll_pixel_clk_src = { + .data = { + .max_div = 128, + .min_div = 1, + }, + .ops = &pixel_div_ops, + .c = { + .parent = &dsi0pll_gp_div_mux.c, + .dbg_name = "dsi0pll_pixel_clk_src", + .ops = &pixel_div_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi0pll_pixel_clk_src.c), + }, +}; + +static struct div_clk dsi1pll_pixel_clk_src = { + .data = { + .max_div = 128, + .min_div = 1, + }, + .ops = &pixel_div_ops, + .c = { + .parent = &dsi1pll_gp_div_mux.c, + .dbg_name = "dsi1pll_pixel_clk_src", + .ops = &pixel_div_clk_src_ops, + .flags = CLKFLAG_NO_RATE_CACHE, + CLK_INIT(dsi1pll_pixel_clk_src.c), + }, +}; + +static struct div_clk dsi0pll_byte_clk_src = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi0pll_post_div_mux.c, + .dbg_name = "dsi0pll_byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(dsi0pll_byte_clk_src.c), + }, +}; + +static struct div_clk dsi1pll_byte_clk_src = { + .data = { + .div = 4, + .min_div = 4, + .max_div = 4, + }, + .c = { + .parent = &dsi1pll_post_div_mux.c, + .dbg_name = "dsi1pll_byte_clk_src", + .ops = &clk_ops_div, + CLK_INIT(dsi1pll_byte_clk_src.c), + }, +}; + +static struct clk_lookup mdss_dsi_pllcc_12nm[] = { + CLK_LIST(dsi0pll_byte_clk_src), + CLK_LIST(dsi0pll_pixel_clk_src), +}; + +static struct clk_lookup mdss_dsi_pllcc_12nm_1[] = { + CLK_LIST(dsi1pll_byte_clk_src), + CLK_LIST(dsi1pll_pixel_clk_src), +}; + +int dsi_pll_clock_register_12nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res) +{ + int rc = 0, ndx; + struct dsi_pll_db *pdb; + + if (!pdev || !pdev->dev.of_node) { + pr_err("Invalid input parameters\n"); + return -EINVAL; + } + + if (!pll_res || !pll_res->pll_base) { + pr_err("Invalid PLL resources\n"); + return -EPROBE_DEFER; + } + + if (pll_res->index >= DSI_PLL_NUM) { + pr_err("pll ndx=%d is NOT supported\n", pll_res->index); + return -EINVAL; + } + + ndx = pll_res->index; + pdb = &pll_db[ndx]; + pll_res->priv = pdb; + pdb->pll = pll_res; + ndx++; + ndx %= DSI_PLL_NUM; + pdb->next = &pll_db[ndx]; + + /* Set clock source operations */ + + /* pixel_clk */ + pixel_div_clk_src_ops = clk_ops_div; + pixel_div_clk_src_ops.prepare = dsi_pll_div_prepare; + + /* Set client data to mux, div and vco clocks. */ + if (pll_res->index == DSI_PLL_1) { + dsi1pll_byte_clk_src.priv = pll_res; + dsi1pll_post_div_mux.priv = pll_res; + dsi1pll_post_div1.priv = pll_res; + dsi1pll_post_div2.priv = pll_res; + dsi1pll_post_div4.priv = pll_res; + dsi1pll_post_div8.priv = pll_res; + dsi1pll_post_div16.priv = pll_res; + dsi1pll_post_div32.priv = pll_res; + dsi1pll_pixel_clk_src.priv = pll_res; + dsi1pll_gp_div_mux.priv = pll_res; + dsi1pll_gp_div1.priv = pll_res; + dsi1pll_gp_div2.priv = pll_res; + dsi1pll_gp_div4.priv = pll_res; + dsi1pll_gp_div8.priv = pll_res; + dsi1pll_gp_div16.priv = pll_res; + dsi1pll_gp_div32.priv = pll_res; + dsi1pll_vco_clk.priv = pll_res; + + if (pll_res->target_id == MDSS_PLL_TARGET_SDM439) + rc = of_msm_clock_register(pdev->dev.of_node, + mdss_dsi_pllcc_12nm_1, + ARRAY_SIZE(mdss_dsi_pllcc_12nm_1)); + } else { + dsi0pll_byte_clk_src.priv = pll_res; + dsi0pll_post_div_mux.priv = pll_res; + dsi0pll_post_div1.priv = pll_res; + dsi0pll_post_div2.priv = pll_res; + dsi0pll_post_div4.priv = pll_res; + dsi0pll_post_div8.priv = pll_res; + dsi0pll_post_div16.priv = pll_res; + dsi0pll_post_div32.priv = pll_res; + dsi0pll_pixel_clk_src.priv = pll_res; + dsi0pll_gp_div_mux.priv = pll_res; + dsi0pll_gp_div1.priv = pll_res; + dsi0pll_gp_div2.priv = pll_res; + dsi0pll_gp_div4.priv = pll_res; + dsi0pll_gp_div8.priv = pll_res; + dsi0pll_gp_div16.priv = pll_res; + dsi0pll_gp_div32.priv = pll_res; + dsi0pll_vco_clk.priv = pll_res; + + if (pll_res->target_id == MDSS_PLL_TARGET_SDM439) + rc = of_msm_clock_register(pdev->dev.of_node, + mdss_dsi_pllcc_12nm, + ARRAY_SIZE(mdss_dsi_pllcc_12nm)); + } + + if (!rc) { + pr_info("Registered DSI PLL ndx=%d clocks successfully\n", + pll_res->index); + } + + return rc; +} diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h new file mode 100644 index 000000000000..6912ff4ff543 --- /dev/null +++ b/drivers/clk/msm/mdss/mdss-dsi-pll-12nm.h @@ -0,0 +1,89 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef MDSS_DSI_PLL_12NM_H +#define MDSS_DSI_PLL_12NM_H + +#define DSIPHY_PLL_POWERUP_CTRL 0x034 +#define DSIPHY_PLL_PROP_CHRG_PUMP_CTRL 0x038 +#define DSIPHY_PLL_INTEG_CHRG_PUMP_CTRL 0x03c +#define DSIPHY_PLL_ANA_TST_LOCK_ST_OVR_CTRL 0x044 +#define DSIPHY_PLL_VCO_CTRL 0x048 +#define DSIPHY_PLL_GMP_CTRL_DIG_TST 0x04c +#define DSIPHY_PLL_PHA_ERR_CTRL_0 0x050 +#define DSIPHY_PLL_LOCK_FILTER 0x054 +#define DSIPHY_PLL_UNLOCK_FILTER 0x058 +#define DSIPHY_PLL_INPUT_DIV_PLL_OVR 0x05c +#define DSIPHY_PLL_LOOP_DIV_RATIO_0 0x060 +#define DSIPHY_PLL_INPUT_LOOP_DIV_RAT_CTRL 0x064 +#define DSIPHY_PLL_PRO_DLY_RELOCK 0x06c +#define DSIPHY_PLL_CHAR_PUMP_BIAS_CTRL 0x070 +#define DSIPHY_PLL_LOCK_DET_MODE_SEL 0x074 +#define DSIPHY_PLL_ANA_PROG_CTRL 0x07c +#define DSIPHY_HS_FREQ_RAN_SEL 0x110 +#define DSIPHY_SLEWRATE_FSM_OVR_CTRL 0x280 +#define DSIPHY_SLEWRATE_DDL_LOOP_CTRL 0x28c +#define DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_0 0x290 +#define DSIPHY_PLL_PHA_ERR_CTRL_1 0x2e4 +#define DSIPHY_PLL_LOOP_DIV_RATIO_1 0x2e8 +#define DSIPHY_SLEWRATE_DDL_CYC_FRQ_ADJ_1 0x328 +#define DSIPHY_SSC0 0x394 +#define DSIPHY_SSC9 0x3b8 +#define DSIPHY_STAT0 0x3e0 +#define DSIPHY_CTRL0 0x3e8 +#define DSIPHY_SYS_CTRL 0x3f0 +#define DSIPHY_PLL_CTRL 0x3f8 + +struct dsi_pll_param { + u32 hsfreqrange; + u32 vco_cntrl; + u32 osc_freq_target; + u32 m_div; + u32 prop_cntrl; + u32 int_cntrl; + u32 gmp_cntrl; + u32 cpbias_cntrl; + + /* mux and dividers */ + u32 gp_div_mux; + u32 post_div_mux; + u32 pixel_divhf; + u32 fsm_ovr_ctrl; +}; + +enum { + DSI_PLL_0, + DSI_PLL_1, + DSI_PLL_NUM +}; + +struct dsi_pll_db { + struct dsi_pll_db *next; + struct mdss_pll_resources *pll; + struct dsi_pll_param param; +}; + +int pll_vco_set_rate_12nm(struct clk *c, unsigned long rate); +long pll_vco_round_rate_12nm(struct clk *c, unsigned long rate); +enum handoff pll_vco_handoff_12nm(struct clk *c); +int pll_vco_prepare_12nm(struct clk *c); +void pll_vco_unprepare_12nm(struct clk *c); +int pll_vco_enable_12nm(struct clk *c); +int pixel_div_set_div(struct div_clk *clk, int div); +int pixel_div_get_div(struct div_clk *clk); +int set_post_div_mux_sel(struct mux_clk *clk, int sel); +int get_post_div_mux_sel(struct mux_clk *clk); +int set_gp_mux_sel(struct mux_clk *clk, int sel); +int get_gp_mux_sel(struct mux_clk *clk); +int dsi_pll_enable_seq_12nm(struct mdss_pll_resources *pll); + +#endif /* MDSS_DSI_PLL_12NM_H */ diff --git a/drivers/clk/msm/mdss/mdss-dsi-pll.h b/drivers/clk/msm/mdss/mdss-dsi-pll.h index 4a9bb64ba5b4..84982592579a 100644 --- a/drivers/clk/msm/mdss/mdss-dsi-pll.h +++ b/drivers/clk/msm/mdss/mdss-dsi-pll.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2015, 2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -81,6 +81,8 @@ int dsi_pll_clock_register_lpm(struct platform_device *pdev, struct mdss_pll_resources *pll_res); int dsi_pll_clock_register_8996(struct platform_device *pdev, struct mdss_pll_resources *pll_res); +int dsi_pll_clock_register_12nm(struct platform_device *pdev, + struct mdss_pll_resources *pll_res); int set_byte_mux_sel(struct mux_clk *clk, int sel); int get_byte_mux_sel(struct mux_clk *clk); diff --git a/drivers/clk/msm/mdss/mdss-pll.c b/drivers/clk/msm/mdss/mdss-pll.c index 49f3d7be25ca..b8b6883678c1 100644 --- a/drivers/clk/msm/mdss/mdss-pll.c +++ b/drivers/clk/msm/mdss/mdss-pll.c @@ -136,6 +136,9 @@ static int mdss_pll_resource_parse(struct platform_device *pdev, } else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8909")) { pll_res->pll_interface_type = MDSS_DSI_PLL_LPM; pll_res->target_id = MDSS_PLL_TARGET_8909; + } else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_sdm439")) { + pll_res->pll_interface_type = MDSS_DSI_PLL_12NM; + pll_res->target_id = MDSS_PLL_TARGET_SDM439; } else if (!strcmp(compatible_stream, "qcom,mdss_dsi_pll_8996")) { pll_res->pll_interface_type = MDSS_DSI_PLL_8996; pll_res->target_id = MDSS_PLL_TARGET_8996; @@ -186,6 +189,9 @@ static int mdss_pll_clock_register(struct platform_device *pdev, case MDSS_DSI_PLL_8996: rc = dsi_pll_clock_register_8996(pdev, pll_res); break; + case MDSS_DSI_PLL_12NM: + rc = dsi_pll_clock_register_12nm(pdev, pll_res); + break; case MDSS_HDMI_PLL_8996: rc = hdmi_8996_v1_pll_clock_register(pdev, pll_res); break; @@ -403,6 +409,7 @@ static const struct of_device_id mdss_pll_dt_match[] = { {.compatible = "qcom,mdss_dsi_pll_8937"}, {.compatible = "qcom,mdss_dsi_pll_8909"}, {.compatible = "qcom,mdss_dsi_pll_8953"}, + {.compatible = "qcom,mdss_dsi_pll_sdm439"}, {} }; diff --git a/drivers/clk/msm/mdss/mdss-pll.h b/drivers/clk/msm/mdss/mdss-pll.h index 1fa5cffab6c2..026ac8e53115 100644 --- a/drivers/clk/msm/mdss/mdss-pll.h +++ b/drivers/clk/msm/mdss/mdss-pll.h @@ -31,6 +31,7 @@ enum { MDSS_DSI_PLL_LPM, MDSS_DSI_PLL_8996, + MDSS_DSI_PLL_12NM, MDSS_HDMI_PLL_8996, MDSS_HDMI_PLL_8996_V2, MDSS_HDMI_PLL_8996_V3, @@ -44,6 +45,7 @@ enum { MDSS_PLL_TARGET_8937, MDSS_PLL_TARGET_8953, MDSS_PLL_TARGET_8909, + MDSS_PLL_TARGET_SDM439, }; struct mdss_pll_resources { diff --git a/include/dt-bindings/clock/msm-clocks-8952.h b/include/dt-bindings/clock/msm-clocks-8952.h index 4547751bbd41..3190d4f7495d 100644 --- a/include/dt-bindings/clock/msm-clocks-8952.h +++ b/include/dt-bindings/clock/msm-clocks-8952.h @@ -235,6 +235,11 @@ #define clk_ext_pclk0_clk_src 0x087c1612 #define clk_ext_byte0_clk_src 0xfb32f31e +#define clk_dsi0pll_byte_clk_src 0xbbaa30be +#define clk_dsi0pll_pixel_clk_src 0x45b3260f +#define clk_dsi1pll_byte_clk_src 0x63930a8f +#define clk_dsi1pll_pixel_clk_src 0x0e4c9b56 + #define clk_dsi_pll0_byte_clk_src 0x44539836 #define clk_dsi_pll0_pixel_clk_src 0x5767c287 #define clk_dsi_pll1_byte_clk_src 0x73e88d02 -- GitLab From 36df875626cf179488c67dc9a0caea3bca5cf8db Mon Sep 17 00:00:00 2001 From: Girish Mahadevan Date: Thu, 16 Nov 2017 10:53:15 -0700 Subject: [PATCH 1551/1834] spi: spi-geni-qcom: Fix the interpretation of cs_change flag Interpret and implement the cs_change flag control parameter. If the cs_change flag is set then toggle the CS line in-between transfers and de-assert the CS line at the end of the message. If the cs_change flag is not set then keep the CS line asserted in-between transfers and de-assert the CS line at the end of the message. Change-Id: I876f1d40aec0c0f23ff303385fd8b8f551e35253 Signed-off-by: Dilip Kota --- drivers/spi/spi-geni-qcom.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index a074763baaf2..dfa387c24fed 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -356,9 +356,6 @@ static struct msm_gpi_tre *setup_config0_tre(struct spi_transfer *xfer, if (mode & SPI_CPHA) flags |= GSI_CPHA; - if (xfer->cs_change) - flags |= GSI_CS_TOGGLE; - word_len = xfer->bits_per_word - MIN_WORD_LEN; pack |= (GSI_TX_PACK_EN | GSI_RX_PACK_EN); ret = get_spi_clk_cfg(mas->cur_speed_hz, mas, &idx, &div); @@ -586,8 +583,11 @@ static int setup_gsi_xfer(struct spi_transfer *xfer, } cs |= spi_slv->chip_select; - if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers)) - go_flags |= FRAGMENTATION; + if (!xfer->cs_change) { + if (!list_is_last(&xfer->transfer_list, + &spi->cur_msg->transfers)) + go_flags |= FRAGMENTATION; + } go_tre = setup_go_tre(cmd, cs, rx_len, go_flags, mas); sg_init_table(xfer_tx_sg, tx_nent); @@ -940,8 +940,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, m_cmd = SPI_RX_ONLY; spi_tx_cfg &= ~CS_TOGGLE; - if (xfer->cs_change) - spi_tx_cfg |= CS_TOGGLE; if (!(mas->cur_word_len % MIN_WORD_LEN)) { trans_len = ((xfer->len << 3) / mas->cur_word_len) & TRANS_LEN_MSK; @@ -950,8 +948,12 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, trans_len = (xfer->len / bytes_per_word) & TRANS_LEN_MSK; } - if (!list_is_last(&xfer->transfer_list, &spi->cur_msg->transfers)) - m_param |= FRAGMENTATION; + + if (!xfer->cs_change) { + if (!list_is_last(&xfer->transfer_list, + &spi->cur_msg->transfers)) + m_param |= FRAGMENTATION; + } mas->cur_xfer = xfer; if (m_cmd & SPI_TX_ONLY) { @@ -966,8 +968,9 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, geni_write_reg(spi_tx_cfg, mas->base, SE_SPI_TRANS_CFG); geni_setup_m_cmd(mas->base, m_cmd, m_param); GENI_SE_DBG(mas->ipc, false, mas->dev, - "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x\n", - __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd); + "%s: trans_len %d xferlen%d tx_cfg 0x%x cmd 0x%x cs %d\n", + __func__, trans_len, xfer->len, spi_tx_cfg, m_cmd, + xfer->cs_change); if (m_cmd & SPI_TX_ONLY) geni_write_reg(mas->tx_wm, mas->base, SE_GENI_TX_WATERMARK_REG); /* Ensure all writes are done before the WM interrupt */ -- GitLab From 5e6daf815879d98d22321db6190c37292d7a259b Mon Sep 17 00:00:00 2001 From: Charan Teja Reddy Date: Fri, 27 Apr 2018 16:09:49 +0530 Subject: [PATCH 1552/1834] coresight: place pm_runtime_put() properly When we register coresight device to the amba bus, before calling driver probe, clocks will be enabled by the amba bus framework and disabled only in failure cases returned by driver probe. So, ensure not to call the pm_runtime_put, which also disables the clocks, in probe failure cases. Otherwise clocks gets disabled twice, once by amba bus framework and then by the pm_runtime_put, that leads to the loss of the clock vote by the previous coresight module, if any. Change-Id: Ied492303458ad12acb65bf2e80fb30efc5fee837 Signed-off-by: Charan Teja Reddy --- drivers/hwtracing/coresight/coresight-etb10.c | 4 ++-- drivers/hwtracing/coresight/coresight-replicator-qcom.c | 4 ++-- drivers/hwtracing/coresight/coresight-tmc.c | 6 ++++-- drivers/hwtracing/coresight/coresight-tpda.c | 6 +++--- drivers/hwtracing/coresight/coresight-tpdm.c | 4 ++-- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etb10.c b/drivers/hwtracing/coresight/coresight-etb10.c index d7325c6534ad..7e041d9cdbec 100644 --- a/drivers/hwtracing/coresight/coresight-etb10.c +++ b/drivers/hwtracing/coresight/coresight-etb10.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2012,2018 The Linux Foundation. All rights reserved. * * Description: CoreSight Embedded Trace Buffer driver * @@ -669,7 +669,6 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) spin_lock_init(&drvdata->spinlock); drvdata->buffer_depth = etb_get_buffer_depth(drvdata); - pm_runtime_put(&adev->dev); if (drvdata->buffer_depth & 0x80000000) return -EINVAL; @@ -698,6 +697,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id) ret = misc_register(&drvdata->miscdev); if (ret) goto err_misc_register; + pm_runtime_put(&adev->dev); return 0; diff --git a/drivers/hwtracing/coresight/coresight-replicator-qcom.c b/drivers/hwtracing/coresight/coresight-replicator-qcom.c index 98547a926a13..09901643b041 100644 --- a/drivers/hwtracing/coresight/coresight-replicator-qcom.c +++ b/drivers/hwtracing/coresight/coresight-replicator-qcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2015, 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2011-2015,2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -132,7 +132,6 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id) drvdata->base = base; dev_set_drvdata(dev, drvdata); - pm_runtime_put(&adev->dev); desc.type = CORESIGHT_DEV_TYPE_LINK; desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT; @@ -143,6 +142,7 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id) if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); + pm_runtime_put(&adev->dev); dev_info(dev, "%s initialized\n", (char *)id->data); return 0; } diff --git a/drivers/hwtracing/coresight/coresight-tmc.c b/drivers/hwtracing/coresight/coresight-tmc.c index 3948a50248f1..87d9162ca057 100644 --- a/drivers/hwtracing/coresight/coresight-tmc.c +++ b/drivers/hwtracing/coresight/coresight-tmc.c @@ -689,8 +689,6 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) drvdata->size = readl_relaxed(drvdata->base + TMC_RSZ) * 4; } - pm_runtime_put(&adev->dev); - ctidata = of_get_coresight_cti_data(dev, adev->dev.of_node); if (IS_ERR(ctidata)) { dev_err(dev, "invalid cti data\n"); @@ -754,6 +752,10 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id) ret = misc_register(&drvdata->miscdev); if (ret) coresight_unregister(drvdata->csdev); + + if (!ret) + pm_runtime_put(&adev->dev); + out: return ret; } diff --git a/drivers/hwtracing/coresight/coresight-tpda.c b/drivers/hwtracing/coresight/coresight-tpda.c index 5d2d0879bb55..261b8c8fc157 100644 --- a/drivers/hwtracing/coresight/coresight-tpda.c +++ b/drivers/hwtracing/coresight/coresight-tpda.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -678,8 +678,6 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id) if (!coresight_authstatus_enabled(drvdata->base)) goto err; - pm_runtime_put(&adev->dev); - tpda_init_default_data(drvdata); desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); @@ -695,6 +693,8 @@ static int tpda_probe(struct amba_device *adev, const struct amba_id *id) if (IS_ERR(drvdata->csdev)) return PTR_ERR(drvdata->csdev); + pm_runtime_put(&adev->dev); + dev_dbg(drvdata->dev, "TPDA initialized\n"); return 0; err: diff --git a/drivers/hwtracing/coresight/coresight-tpdm.c b/drivers/hwtracing/coresight/coresight-tpdm.c index 7cdb45989a9d..6463a4703e37 100644 --- a/drivers/hwtracing/coresight/coresight-tpdm.c +++ b/drivers/hwtracing/coresight/coresight-tpdm.c @@ -4029,8 +4029,6 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) drvdata->bc_counters_avail = BMVAL(devid, 6, 10) + 1; drvdata->tc_counters_avail = BMVAL(devid, 4, 5) + 1; - pm_runtime_put(&adev->dev); - drvdata->traceid = traceid++; desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); @@ -4051,6 +4049,8 @@ static int tpdm_probe(struct amba_device *adev, const struct amba_id *id) if (boot_enable) coresight_enable(drvdata->csdev); + pm_runtime_put(&adev->dev); + return 0; } -- GitLab From 5bcb0cda437206eb9dde8dc6677b8282cce8f501 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Thu, 19 Apr 2018 13:41:16 +0530 Subject: [PATCH 1553/1834] msm: ipa: rmnet: Make code changes with respect to CR#2046006 Check for CAP_NET_ADMIN capability of the user space application which tries to access rmnet driver IOCTL. Change-Id: If6bb4b54659306c5103b5e34bf02c7234c851e0a CRs-Fixed: 2226355 Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c | 2 ++ drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c index c86b0dfd476e..130afc729c21 100644 --- a/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/rmnet_ipa.c @@ -1433,6 +1433,8 @@ static int ipa_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Extended IOCTLs */ case RMNET_IOCTL_EXTENDED: + if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) + return -EPERM; IPAWANDBG("get ioctl: RMNET_IOCTL_EXTENDED\n"); if (copy_from_user(&extend_ioctl_data, (u8 *)ifr->ifr_ifru.ifru_data, diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 561c533eebd8..f1e2e6df037f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1565,6 +1565,8 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) /* Extended IOCTLs */ case RMNET_IOCTL_EXTENDED: + if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) + return -EPERM; IPAWANDBG("get ioctl: RMNET_IOCTL_EXTENDED\n"); if (copy_from_user(&extend_ioctl_data, (u8 *)ifr->ifr_ifru.ifru_data, -- GitLab From bdb36e74f6b7f5eac4ed25c1892eb1b3ea4c4b33 Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Mon, 30 Apr 2018 13:52:07 +0530 Subject: [PATCH 1554/1834] defconfig: msm8937: Add virtual keys support Enable gen_vkeys driver for msm8937_defconfig and msm8937-perf_defconfig. Change-Id: Ic553cde7e5b07fd186e2e58ed0089aac36fe13b0 Signed-off-by: Venkata Prahlad Valluru --- arch/arm/configs/msm8937-perf_defconfig | 1 + arch/arm/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index a6a85f18db0c..2d4e8ea921dc 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -289,6 +289,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 54461cf024ac..d338dcffdc04 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -294,6 +294,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y -- GitLab From cc9b107709732172f4c89687bba78bf57675cdce Mon Sep 17 00:00:00 2001 From: Venkata Prahlad Valluru Date: Mon, 30 Apr 2018 13:54:57 +0530 Subject: [PATCH 1555/1834] defconfig: msm8937: Add ft5x06 touchscreen support Enable ft5x06 touch driver for msm8937_defconfig and msm8937-perf_defconfig. Change-Id: Ie3bddf47d6f72667f701eda60a1a710bb91db4a0 Signed-off-by: Venkata Prahlad Valluru --- arch/arm/configs/msm8937-perf_defconfig | 1 + arch/arm/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 2d4e8ea921dc..e2051a8179c5 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -289,6 +289,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index d338dcffdc04..c1d24ba295bb 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -294,6 +294,7 @@ CONFIG_KEYBOARD_GPIO=y # CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y -- GitLab From e58c19e7aa9553b5a0cc594849ac410a54790418 Mon Sep 17 00:00:00 2001 From: Vijayanand Jitta Date: Tue, 24 Apr 2018 10:51:17 +0530 Subject: [PATCH 1556/1834] ARM: dts: msm: Correct gpu smmu interrupt type for sdm670 Update the interrupt configuration to level high. Change-Id: Ic555af8c279f18d7cc93fcf29d03f700db8f97ad Signed-off-by: Vijayanand Jitta --- .../boot/dts/qcom/msm-arm-smmu-sdm670.dtsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi index ab088b89359e..707875baf50e 100644 --- a/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-arm-smmu-sdm670.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -27,14 +27,14 @@ vdd-supply = <&gpu_cx_gdsc>; interrupts = , , - , - , - , - , - , - , - , - ; + , + , + , + , + , + , + , + ; clock-names = "gcc_gpu_memnoc_gfx_clk"; clocks = <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>; attach-impl-defs = -- GitLab From 5336589d9ee2645ffadfff799b5271cfb8a9a5c5 Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Fri, 13 Apr 2018 14:03:35 -0700 Subject: [PATCH 1557/1834] msm: vidc: Add HEIF encode support HEIF encoding uses HEVC encoder with tile based frame encoding. Supports configuration of Quality-factor, Constant-quality rate control, MainStill profile and Grid-info params. Change-Id: I8c83a54a2e47735b34390011cda982e499770f09 Signed-off-by: Amit Shekhar --- .../platform/msm/vidc/hfi_packetization.c | 48 ++++++++ .../platform/msm/vidc/hfi_response_handler.c | 6 + drivers/media/platform/msm/vidc/msm_venc.c | 107 +++++++++++++++++- drivers/media/platform/msm/vidc/msm_vidc.c | 4 +- .../media/platform/msm/vidc/msm_vidc_common.c | 85 +++++++++++++- .../platform/msm/vidc/msm_vidc_internal.h | 8 ++ drivers/media/platform/msm/vidc/vidc_hfi.h | 3 +- .../media/platform/msm/vidc/vidc_hfi_api.h | 21 ++++ .../media/platform/msm/vidc/vidc_hfi_helper.h | 24 ++++ include/uapi/linux/v4l2-controls.h | 7 ++ 10 files changed, 304 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/msm/vidc/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi_packetization.c index e3a5cc723765..9ef9d05d92f4 100644 --- a/drivers/media/platform/msm/vidc/hfi_packetization.c +++ b/drivers/media/platform/msm/vidc/hfi_packetization.c @@ -1239,6 +1239,51 @@ int create_pkt_cmd_session_set_property( struct hfi_h264_entropy_control); break; } + case HAL_CONFIG_HEIC_FRAME_QUALITY: + { + struct hfi_heic_frame_quality *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY; + hfi = + (struct hfi_heic_frame_quality *) &pkt->rg_property_data[1]; + hfi->frame_quality = + ((struct hal_heic_frame_quality *)pdata)->frame_quality; + pkt->size += sizeof(u32) + + sizeof(struct hfi_heic_frame_quality); + break; + } + case HAL_CONFIG_HEIC_GRID_ENABLE: + { + struct hfi_heic_grid_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_HEIC_GRID_ENABLE; + hfi = (struct hfi_heic_grid_enable *) &pkt->rg_property_data[1]; + hfi->grid_enable = + ((struct hal_heic_grid_enable *)pdata)->grid_enable; + pkt->size += sizeof(u32) + sizeof(struct hfi_heic_grid_enable); + break; + } + case HAL_CONFIG_HEIC_FRAME_CROP_INFO: + { + struct hfi_frame_crop *hfi_crop_info; + struct hal_frame_crop *hal_crop_info = + (struct hal_frame_crop *) pdata; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_HEIC_FRAME_CROP_INFO; + hfi_crop_info = + (struct hfi_frame_crop *) &pkt->rg_property_data[1]; + + hfi_crop_info->left = hal_crop_info->left; + hfi_crop_info->top = hal_crop_info->top; + hfi_crop_info->width = hal_crop_info->width; + hfi_crop_info->height = hal_crop_info->height; + + pkt->size += sizeof(u32) + sizeof(struct hfi_frame_crop); + break; + } case HAL_PARAM_VENC_RATE_CONTROL: { u32 *rc; @@ -1266,6 +1311,9 @@ int create_pkt_cmd_session_set_property( case HAL_RATE_CONTROL_MBR_VFR: pkt->rg_property_data[1] = HFI_RATE_CONTROL_MBR_VFR; break; + case HAL_RATE_CONTROL_CQ: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_CQ; + break; default: dprintk(VIDC_ERR, "Invalid Rate control setting: %pK\n", diff --git a/drivers/media/platform/msm/vidc/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi_response_handler.c index 97f5ca2ac1e1..0cdcbd6e0df1 100644 --- a/drivers/media/platform/msm/vidc/hfi_response_handler.c +++ b/drivers/media/platform/msm/vidc/hfi_response_handler.c @@ -599,6 +599,9 @@ enum hal_capability get_hal_cap_type(u32 capability_type) case HFI_CAPABILITY_UBWC_CR_STATS: hal_cap = HAL_CAPABILITY_UBWC_CR_STATS; break; + case HFI_CAPABILITY_IMG_GRID_DIMENSION: + hal_cap = HAL_CAPABILITY_IMG_GRID_DIMENSION; + break; default: dprintk(VIDC_DBG, "%s: unknown capablity %#x\n", __func__, capability_type); @@ -723,6 +726,9 @@ static inline void copy_cap_prop( case HFI_CAPABILITY_UBWC_CR_STATS: out = &capability->ubwc_cr_stats; break; + case HFI_CAPABILITY_IMG_GRID_DIMENSION: + out = &capability->img_grid_dimension; + break; default: dprintk(VIDC_DBG, "%s: unknown capablity %#x\n", __func__, in->capability_type); diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c index be24f8df68e3..9a7d272bd629 100644 --- a/drivers/media/platform/msm/vidc/msm_venc.c +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -24,6 +24,14 @@ #define BIT_RATE_STEP 1 #define DEFAULT_FRAME_RATE 15 #define OPERATING_FRAME_RATE_STEP (1 << 16) +#define MIN_FRAME_QUALITY 0 +#define MAX_FRAME_QUALITY 100 +#define DEFAULT_FRAME_QUALITY 80 +#define FRAME_QUALITY_STEP 1 +#define MIN_GRID_DIMENSION 512 +#define MAX_GRID_DIMENSION 8192 +#define DEFAULT_GRID_DIMENSION 512 +#define GRID_DIMENSION_STEP 256 #define MAX_SLICE_BYTE_SIZE ((MAX_BIT_RATE)>>3) #define MIN_SLICE_BYTE_SIZE 512 #define MAX_SLICE_MB_SIZE ((4096 * 2304) >> 8) @@ -50,6 +58,7 @@ static const char *const mpeg_video_rate_control[] = { "CBR CFR", "MBR CFR", "MBR VFR", + "CQ", NULL }; @@ -358,7 +367,7 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { .name = "Video Framerate and Bitrate Control", .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF, - .maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CQ, .default_value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF, .step = 0, .menu_skip_mask = ~( @@ -368,10 +377,34 @@ static struct msm_vidc_ctrl msm_venc_ctrls[] = { (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR) | (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR) | (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR) | - (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR) + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CQ) ), .qmenu = mpeg_video_rate_control, }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY, + .name = "Frame quality", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_FRAME_QUALITY, + .maximum = MAX_FRAME_QUALITY, + .default_value = DEFAULT_FRAME_QUALITY, + .step = FRAME_QUALITY_STEP, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_IMG_GRID_DIMENSION, + .name = "Image grid", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_GRID_DIMENSION, + .maximum = MAX_GRID_DIMENSION, + .default_value = DEFAULT_GRID_DIMENSION, + .step = GRID_DIMENSION_STEP, + .menu_skip_mask = 0, + .qmenu = NULL, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, { .id = V4L2_CID_MPEG_VIDEO_BITRATE, .name = "Bit Rate", @@ -1383,6 +1416,8 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) enum hal_iframesize_type iframesize_type = HAL_IFRAMESIZE_TYPE_DEFAULT; u32 color_primaries, custom_matrix; struct hal_nal_stream_format_select stream_format; + struct hal_heic_frame_quality frame_quality; + struct hal_heic_grid_enable grid_enable; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); @@ -1483,6 +1518,13 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) rc = -ENOTSUPP; break; } + if ((ctrl->val == + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CQ) && + inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) { + dprintk(VIDC_ERR, "CQ supported only for HEVC\n"); + rc = -ENOTSUPP; + break; + } property_id = HAL_PARAM_VENC_RATE_CONTROL; property_val = ctrl->val; pdata = &property_val; @@ -1497,6 +1539,67 @@ int msm_venc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) inst->clk_data.bitrate = ctrl->val; break; } + case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY: + { + property_id = HAL_CONFIG_HEIC_FRAME_QUALITY; + frame_quality.frame_quality = ctrl->val; + pdata = &frame_quality; + break; + } + case V4L2_CID_MPEG_VIDC_IMG_GRID_DIMENSION: + { + int i = 0, j = 0; + u32 width = 0, height = 0; + u32 trows, tcols; + + property_id = HAL_CONFIG_HEIC_GRID_ENABLE; + if (inst->fmts[CAPTURE_PORT].fourcc != V4L2_PIX_FMT_HEVC) { + dprintk(VIDC_ERR, "Grid is supported only for HEVC\n"); + rc = -ENOTSUPP; + break; + } + if (ctrl->val == 0) { + dprintk(VIDC_ERR, "Dimension 0 is not supported\n"); + rc = -ENOTSUPP; + break; + } + grid_enable.grid_enable = ctrl->val; + inst->img_grid_dimension = ctrl->val; + pdata = &grid_enable; + + /* Update tile info table */ + width = inst->prop.width[OUTPUT_PORT]; + height = inst->prop.height[OUTPUT_PORT]; + tcols = (width + inst->img_grid_dimension - 1) / + inst->img_grid_dimension; + trows = (height + inst->img_grid_dimension - 1) / + inst->img_grid_dimension; + inst->tinfo.count = trows * tcols; + if (inst->tinfo.count > MAX_HEIC_TILES_COUNT) { + dprintk(VIDC_ERR, "Tiles count exceeds maximum\n"); + rc = -ENOTSUPP; + break; + } + + dprintk(VIDC_DBG, + "Grid dimension %d width %d height %d row %d col %d\n", + inst->img_grid_dimension, width, height, + trows, tcols); + + for (j = 0; j < trows; ++j) { + for (i = 0; i < tcols; ++i) { + inst->tinfo.tile_rects[j*tcols+i].left = + (i * inst->img_grid_dimension); + inst->tinfo.tile_rects[j*tcols+i].top = + (j * inst->img_grid_dimension); + inst->tinfo.tile_rects[j*tcols+i].width = + inst->img_grid_dimension; + inst->tinfo.tile_rects[j*tcols+i].height = + inst->img_grid_dimension; + } + } + break; + } case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: { struct v4l2_ctrl *avg_bitrate = TRY_GET_CTRL( diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index f077e3bc7c7a..8e3250465e8f 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1480,7 +1480,9 @@ static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE, inst->profile); break; - + case V4L2_CID_MPEG_VIDC_IMG_GRID_DIMENSION: + ctrl->val = inst->img_grid_dimension; + break; case V4L2_CID_MPEG_VIDEO_H264_LEVEL: ctrl->val = msm_comm_hal_to_v4l2( V4L2_CID_MPEG_VIDEO_H264_LEVEL, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 7d9bbed94599..b3926101ced1 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1564,6 +1564,7 @@ static void handle_session_init_done(enum hal_command_response cmd, void *data) print_cap("max_video_cores", &inst->capability.max_video_cores); print_cap("max_work_modes", &inst->capability.max_work_modes); print_cap("ubwc_cr_stats", &inst->capability.ubwc_cr_stats); + print_cap("image_grid_dimension", &inst->capability.img_grid_dimension); dprintk(VIDC_DBG, "profile count : %u", inst->capability.profile_level.profile_count); @@ -2397,6 +2398,14 @@ static void handle_ebd(enum hal_command_response cmd, void *data) } empty_buf_done = (struct vidc_hal_ebd *)&response->input_done; + if ((get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == + HAL_VIDEO_CODEC_HEVC) && + (inst->img_grid_dimension > 0) && + (empty_buf_done->input_tag < inst->tinfo.count - 1)) { + dprintk(VIDC_DBG, "Wait for last tile. Current tile no: %d\n", + empty_buf_done->input_tag); + return; + } /* If this is internal EOS buffer, handle it in driver */ if (is_eos_buffer(inst, empty_buf_done->packet_buffer)) { dprintk(VIDC_DBG, "Received EOS buffer 0x%x\n", @@ -4148,6 +4157,58 @@ enum hal_buffer get_hal_buffer_type(unsigned int type, } } +static int msm_comm_qbuf_heic_tiles(struct msm_vidc_inst *inst, + struct vidc_frame_data *frame_data) +{ + int rc = 0, tindex; + struct hfi_device *hdev; + + if (!inst || !inst->core || !inst->core->device) { + dprintk(VIDC_ERR, "%s invalid parameters\n", __func__); + return -EINVAL; + } + + if (inst->tinfo.count > MAX_HEIC_TILES_COUNT) { + dprintk(VIDC_ERR, "%s tiles count exceeds maximum\n", __func__); + return -EINVAL; + } + + hdev = inst->core->device; + + for (tindex = 0; tindex < inst->tinfo.count; ++tindex) { + dprintk(VIDC_DBG, + "%s tile# %d Crop: left %u top %u width %u height %u\n", + __func__, tindex, + inst->tinfo.tile_rects[tindex].left, + inst->tinfo.tile_rects[tindex].top, + inst->tinfo.tile_rects[tindex].width, + inst->tinfo.tile_rects[tindex].height); + + rc = call_hfi_op(hdev, session_set_property, + (void *)inst->session, + HAL_CONFIG_HEIC_FRAME_CROP_INFO, + &inst->tinfo.tile_rects[tindex]); + if (rc) { + dprintk(VIDC_WARN, + "Failed to set HEIC crop info %d\n", rc); + goto err_bad_input; + } + + frame_data->input_tag = tindex; + + rc = call_hfi_op(hdev, session_etb, + (void *)inst->session, frame_data); + if (rc) { + dprintk(VIDC_ERR, + "Failed to issue etb: %d\n", rc); + goto err_bad_input; + } + } + +err_bad_input: + return rc; +} + static int msm_comm_qbuf_rbr(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) { @@ -4355,12 +4416,26 @@ int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) for (c = 0; c < etbs.count; ++c) { struct vidc_frame_data *frame_data = &etbs.data[c]; - rc = call_hfi_op(hdev, session_etb, inst->session, - frame_data); - if (rc) { - dprintk(VIDC_ERR, "Failed to issue etb: %d\n", + if (get_hal_codec(inst->fmts[CAPTURE_PORT].fourcc) == + HAL_VIDEO_CODEC_HEVC && + (inst->img_grid_dimension > 0)) { + rc = msm_comm_qbuf_heic_tiles(inst, frame_data); + if (rc) { + dprintk(VIDC_ERR, + "Failed to send tiles: %d\n", rc); - goto err_bad_input; + goto err_bad_input; + } + } else { + + rc = call_hfi_op(hdev, session_etb, + inst->session, frame_data); + if (rc) { + dprintk(VIDC_ERR, + "Failed to issue etb: %d\n", + rc); + goto err_bad_input; + } } log_frame(inst, frame_data, diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 60cdd183f3a4..e107609ea41d 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -51,6 +51,7 @@ #define MAX_NUM_CAPTURE_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME #define MAX_SUPPORTED_INSTANCES 16 +#define MAX_HEIC_TILES_COUNT 256 /* Maintains the number of FTB's between each FBD over a window */ #define DCVS_FTB_WINDOW 16 @@ -264,6 +265,11 @@ struct session_crop { u32 height; }; +struct tile_info { + u32 count; + struct session_crop tile_rects[MAX_HEIC_TILES_COUNT]; +}; + struct session_prop { u32 width[MAX_PORT_NUM]; u32 height[MAX_PORT_NUM]; @@ -419,6 +425,8 @@ struct msm_vidc_inst { u32 profile; u32 level; u32 entropy_mode; + u32 img_grid_dimension; + struct tile_info tinfo; struct msm_vidc_codec_data *codec_data; struct hal_hdr10_pq_sei hdr10_sei_params; }; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi.h b/drivers/media/platform/msm/vidc/vidc_hfi.h index e899af363d2a..0cfe6934520a 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -298,6 +298,7 @@ struct hfi_hybrid_hierp { #define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5) #define HFI_RATE_CONTROL_MBR_CFR (HFI_OX_BASE + 0x6) #define HFI_RATE_CONTROL_MBR_VFR (HFI_OX_BASE + 0x7) +#define HFI_RATE_CONTROL_CQ (HFI_OX_BASE + 0x8) struct hfi_uncompressed_plane_actual_constraints_info { diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/vidc_hfi_api.h index 9290c487137b..f69b98e828b6 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_api.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_api.h @@ -229,6 +229,9 @@ enum hal_property { HAL_PARAM_VIDEO_WORK_MODE, HAL_PARAM_SECURE, HAL_PARAM_VENC_HDR10_PQ_SEI, + HAL_CONFIG_HEIC_FRAME_CROP_INFO, + HAL_CONFIG_HEIC_FRAME_QUALITY, + HAL_CONFIG_HEIC_GRID_ENABLE, }; enum hal_domain { @@ -604,6 +607,7 @@ enum hal_rate_control { HAL_RATE_CONTROL_CBR_CFR, HAL_RATE_CONTROL_MBR_CFR, HAL_RATE_CONTROL_MBR_VFR, + HAL_RATE_CONTROL_CQ, HAL_UNUSED_RC = 0x10000000, }; @@ -651,6 +655,14 @@ struct hal_idr_period { u32 idr_period; }; +struct hal_heic_frame_quality { + u32 frame_quality; +}; + +struct hal_heic_grid_enable { + u32 grid_enable; +}; + enum hal_rotate { HAL_ROTATE_NONE, HAL_ROTATE_90, @@ -795,6 +807,7 @@ enum hal_capability { HAL_CAPABILITY_MAX_VIDEOCORES, HAL_CAPABILITY_MAX_WORKMODES, HAL_CAPABILITY_UBWC_CR_STATS, + HAL_CAPABILITY_IMG_GRID_DIMENSION, HAL_UNUSED_CAPABILITY = 0x10000000, }; @@ -834,6 +847,13 @@ struct hal_aspect_ratio { u32 aspect_height; }; +struct hal_frame_crop { + u32 left; + u32 top; + u32 width; + u32 height; +}; + struct hal_codec_supported { u32 decoder_codec_supported; u32 encoder_codec_supported; @@ -1232,6 +1252,7 @@ struct msm_vidc_capability { struct hal_capability_supported max_video_cores; struct hal_capability_supported max_work_modes; struct hal_capability_supported ubwc_cr_stats; + struct hal_capability_supported img_grid_dimension; struct hal_profile_level_supported profile_level; struct hal_uncompressed_format_supported uncomp_format; struct hal_interlace_format_supported HAL_format; diff --git a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h index 7615736e78bf..f4ea86b6e654 100644 --- a/drivers/media/platform/msm/vidc/vidc_hfi_helper.h +++ b/drivers/media/platform/msm/vidc/vidc_hfi_helper.h @@ -356,6 +356,12 @@ struct hfi_buffer_info { (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x010) #define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \ (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x012) +#define HFI_PROPERTY_CONFIG_HEIC_FRAME_CROP_INFO \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x013) +#define HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x014) +#define HFI_PROPERTY_CONFIG_HEIC_GRID_ENABLE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x015) #define HFI_PROPERTY_PARAM_VPE_COMMON_START \ (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000) @@ -380,6 +386,14 @@ struct hfi_colour_space { u32 colour_space; }; +struct hfi_frame_crop { + u32 left; + u32 top; + u32 width; + u32 height; + u32 reserved[3]; +}; + #define HFI_CAPABILITY_FRAME_WIDTH (HFI_COMMON_BASE + 0x1) #define HFI_CAPABILITY_FRAME_HEIGHT (HFI_COMMON_BASE + 0x2) #define HFI_CAPABILITY_MBS_PER_FRAME (HFI_COMMON_BASE + 0x3) @@ -414,6 +428,8 @@ struct hfi_colour_space { #define HFI_CAPABILITY_MAX_VIDEOCORES (HFI_COMMON_BASE + 0X2B) #define HFI_CAPABILITY_MAX_WORKMODES (HFI_COMMON_BASE + 0X2C) #define HFI_CAPABILITY_UBWC_CR_STATS (HFI_COMMON_BASE + 0X2D) +#define HFI_CAPABILITY_CQ_QUALITY_LEVEL (HFI_COMMON_BASE + 0X32) +#define HFI_CAPABILITY_IMG_GRID_DIMENSION (HFI_COMMON_BASE + 0X33) struct hfi_capability_supported { u32 capability_type; @@ -474,6 +490,14 @@ struct hfi_frame_rate { u32 frame_rate; }; +struct hfi_heic_frame_quality { + u32 frame_quality; +}; + +struct hfi_heic_grid_enable { + u32 grid_enable; +}; + #define HFI_INTRA_REFRESH_NONE (HFI_COMMON_BASE + 0x1) #define HFI_INTRA_REFRESH_CYCLIC (HFI_COMMON_BASE + 0x2) #define HFI_INTRA_REFRESH_RANDOM (HFI_COMMON_BASE + 0x5) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 0b5ff0fb10e8..d14cd8fabee1 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -696,6 +696,7 @@ enum v4l2_mpeg_vidc_video_rate_control { V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR = 4, V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR = 5, V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_VFR = 6, + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CQ = 7, }; #define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR \ V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_MBR_CFR @@ -1343,6 +1344,12 @@ enum v4l2_mpeg_vidc_video_divx_format_type { V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6 = 2, }; +#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_QUALITY \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+160) + +#define V4L2_CID_MPEG_VIDC_IMG_GRID_DIMENSION \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+161) + enum v4l2_mpeg_vidc_video_mbi_statistics_mode { V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_DEFAULT = 0, V4L2_CID_MPEG_VIDC_VIDEO_MBI_MODE_1 = 1, -- GitLab From edcb6638da24fb3f98facfa219fda5f5a4318348 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Mon, 30 Apr 2018 15:21:27 +0530 Subject: [PATCH 1558/1834] usb: gadget: Makefile: Compile u_data_ipa driver with RMNET Move the compilation of u_data_ipa.c driver from QCRNDIS config to RMNET_BAM config. This helps in reducing memory footprint on targets which use RNDIS via SW transport path, since we do not have to compile QCRNDIS to compile IPA USB driver. Change-Id: If257ba12fe1363c4e7b1363c62e64fad3c2539db Signed-off-by: Ajay Agarwal --- drivers/usb/gadget/function/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index a9344a57b7f8..b8fa93e6c224 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile @@ -64,7 +64,7 @@ usb_f_gsi-y := f_gsi.o rndis.o obj-$(CONFIG_USB_F_GSI) += usb_f_gsi.o usb_f_qdss-y := f_qdss.o u_qdss.o obj-$(CONFIG_USB_F_QDSS) += usb_f_qdss.o -usb_f_qcrndis-y := f_qc_rndis.o u_data_ipa.o +usb_f_qcrndis-y := f_qc_rndis.o obj-$(CONFIG_USB_F_QCRNDIS) += usb_f_qcrndis.o -usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o u_bam_dmux.o +usb_f_rmnet_bam-y := f_rmnet.o u_ctrl_qti.o u_bam_dmux.o u_data_ipa.o obj-$(CONFIG_USB_F_RMNET_BAM) += usb_f_rmnet_bam.o -- GitLab From 7c6f008e3595edb1374d3a7a43f09707edfca74c Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Fri, 27 Apr 2018 15:23:10 +0530 Subject: [PATCH 1559/1834] msm: kgsl: Avoid unnecessary "AHB fence stuck in ISR" error logs Kgsl driver polls GMU for fence status to become zero in case it was one in IRQ handler and prints "AHB fence stuck in ISR" error log in case it doesn't happen in multiple retries. Add a small delay between two retries to make sure GMU firmware gets sufficient time to abort power collapse. This will avoid this error prints in scenarios where waiting loop finish much faster and GMU is still in process of aborting power collapse. This will also reduce number of retries. Also, dump register GMU_AO_RBBM_INT_UNMASKED_STATUS_SHADOW as part of error message to identify the unhandled IRQ when this error happens. Change-Id: Ia67a44db43d5a4ec3dd7f3323e7754d950490aec Signed-off-by: Deepak Kumar --- drivers/gpu/msm/adreno.c | 20 ++++++++++++++++---- drivers/gpu/msm/adreno.h | 1 + drivers/gpu/msm/adreno_a6xx.c | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index cb916ae82bfe..cb17656c4651 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -613,6 +613,7 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) struct adreno_irq *irq_params = gpudev->irq; irqreturn_t ret = IRQ_NONE; unsigned int status = 0, fence = 0, fence_retries = 0, tmp, int_bit; + unsigned int shadow_status = 0; int i; atomic_inc(&adreno_dev->pending_irq_refcnt); @@ -635,18 +636,29 @@ static irqreturn_t adreno_irq_handler(struct kgsl_device *device) * and change the fence back to ALLOW. Poll so that this can happen. */ if (kgsl_gmu_isenabled(device)) { - do { + adreno_readreg(adreno_dev, + ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, + &fence); + + while (fence != 0) { + /* Wait for small time before trying again */ + udelay(1); adreno_readreg(adreno_dev, ADRENO_REG_GMU_AO_AHB_FENCE_CTRL, &fence); - if (fence_retries == FENCE_RETRY_MAX) { + if (fence_retries == FENCE_RETRY_MAX && fence != 0) { + adreno_readreg(adreno_dev, + ADRENO_REG_GMU_RBBM_INT_UNMASKED_STATUS, + &shadow_status); + KGSL_DRV_CRIT_RATELIMIT(device, - "AHB fence stuck in ISR\n"); + "AHB fence stuck in ISR: Shadow INT status=%8.8X\n", + shadow_status & irq_params->mask); goto done; } fence_retries++; - } while (fence != 0); + } } adreno_readreg(adreno_dev, ADRENO_REG_RBBM_INT_0_STATUS, &status); diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 686ed34d629e..5fb5d3158425 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -722,6 +722,7 @@ enum adreno_regs { ADRENO_REG_GMU_HOST2GMU_INTR_RAW_INFO, ADRENO_REG_GMU_NMI_CONTROL_STATUS, ADRENO_REG_GMU_CM3_CFG, + ADRENO_REG_GMU_RBBM_INT_UNMASKED_STATUS, ADRENO_REG_GPMU_POWER_COUNTER_ENABLE, ADRENO_REG_REGISTER_MAX, }; diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 7fd11d9366ca..14e1b1d6a5bc 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -3785,6 +3785,8 @@ static unsigned int a6xx_register_offsets[ADRENO_REG_REGISTER_MAX] = { A6XX_GMU_NMI_CONTROL_STATUS), ADRENO_REG_DEFINE(ADRENO_REG_GMU_CM3_CFG, A6XX_GMU_CM3_CFG), + ADRENO_REG_DEFINE(ADRENO_REG_GMU_RBBM_INT_UNMASKED_STATUS, + A6XX_GMU_RBBM_INT_UNMASKED_STATUS), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TRUST_CONTROL, A6XX_RBBM_SECVID_TRUST_CNTL), ADRENO_REG_DEFINE(ADRENO_REG_RBBM_SECVID_TSB_TRUSTED_BASE, -- GitLab From 31bb0355769231632ac16be6008e8315fd1c78b0 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Fri, 13 Apr 2018 11:50:09 +0530 Subject: [PATCH 1560/1834] msm: kgsl: Suspend GMU on recovery failure On GMU recovery failure, kgsl clears the GMU_FAULT bit and also restores the kgsl state to orginal state from which GMU/GPU wake up was triggered to make sure any attempt to wake GMU/GPU after this is treated as a fresh start/hard reset. But on recovery failure, GMU HS, clocks and IRQ are still ON/enabled because of which any attempt of GMU/GPU wakeup results in multiple warnings from GMU start as HS, clocks and IRQ are still ON while doing a fresh start i.e. wake up from SLUMBER. Suspend the GMU on recovery failure to make sure next attempt to wake up GMU/GPU is indeed a fresh start/ hard reset. Change-Id: Ib0ffa8e19bbcf6ace1c438ec04275f7aabddce1b Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl_gmu.c | 18 +++++++++++++++--- drivers/gpu/msm/kgsl_gmu.h | 3 +++ drivers/gpu/msm/kgsl_pwrctrl.c | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/msm/kgsl_gmu.c b/drivers/gpu/msm/kgsl_gmu.c index 61edcc8a32dd..5e0eef4a6e49 100644 --- a/drivers/gpu/msm/kgsl_gmu.c +++ b/drivers/gpu/msm/kgsl_gmu.c @@ -1318,7 +1318,7 @@ static int gmu_disable_gdsc(struct gmu_device *gmu) return -ETIMEDOUT; } -static int gmu_suspend(struct kgsl_device *device) +int gmu_suspend(struct kgsl_device *device) { struct adreno_device *adreno_dev = ADRENO_DEVICE(device); struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); @@ -1404,6 +1404,7 @@ int gmu_start(struct kgsl_device *device) struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev); struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct gmu_device *gmu = &device->gmu; + unsigned int boot_state = GMU_WARM_BOOT; switch (device->state) { case KGSL_STATE_INIT: @@ -1440,12 +1441,21 @@ int gmu_start(struct kgsl_device *device) gmu_enable_clks(gmu); gmu_irq_enable(device); + /* + * If unrecovered is set that means last + * wakeup from SLUMBER state failed. Use GMU + * and HFI boot state as COLD as this is a + * boot after RESET. + */ + if (gmu->unrecovered) + boot_state = GMU_COLD_BOOT; + ret = gpudev->rpmh_gpu_pwrctrl(adreno_dev, GMU_FW_START, - GMU_WARM_BOOT, 0); + boot_state, 0); if (ret) goto error_gmu; - ret = hfi_start(gmu, GMU_WARM_BOOT); + ret = hfi_start(gmu, boot_state); if (ret) goto error_gmu; @@ -1491,6 +1501,8 @@ int gmu_start(struct kgsl_device *device) break; } + /* Clear unrecovered as GMU start is successful */ + gmu->unrecovered = false; return ret; error_gmu: diff --git a/drivers/gpu/msm/kgsl_gmu.h b/drivers/gpu/msm/kgsl_gmu.h index 4ef182a297f0..130d4004bf77 100644 --- a/drivers/gpu/msm/kgsl_gmu.h +++ b/drivers/gpu/msm/kgsl_gmu.h @@ -212,6 +212,7 @@ enum gpu_idle_level { * @ccl: CNOC BW scaling client * @idle_level: Minimal GPU idle power level * @fault_count: GMU fault count + * @unrecovered: Indicates whether GMU recovery failed or not */ struct gmu_device { unsigned int ver; @@ -246,6 +247,7 @@ struct gmu_device { unsigned int ccl; unsigned int idle_level; unsigned int fault_count; + bool unrecovered; }; void gmu_snapshot(struct kgsl_device *device); @@ -255,6 +257,7 @@ void gmu_remove(struct kgsl_device *device); int allocate_gmu_image(struct gmu_device *gmu, unsigned int size); int gmu_start(struct kgsl_device *device); void gmu_stop(struct kgsl_device *device); +int gmu_suspend(struct kgsl_device *device); int gmu_dcvs_set(struct gmu_device *gmu, unsigned int gpu_pwrlevel, unsigned int bus_level); #endif /* __KGSL_GMU_H */ diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c index ee9e5df06d0f..2a149ac87ed1 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.c +++ b/drivers/gpu/msm/kgsl_pwrctrl.c @@ -2798,6 +2798,25 @@ _aware(struct kgsl_device *device) WARN_ONCE(1, "Failed to recover GMU\n"); if (device->snapshot) device->snapshot->recovered = false; + /* + * On recovery failure, we are clearing + * GMU_FAULT bit and also not keeping + * the state as RESET to make sure any + * attempt to wake GMU/GPU after this + * is treated as a fresh start. But on + * recovery failure, GMU HS, clocks and + * IRQs are still ON/enabled because of + * which next GMU/GPU wakeup results in + * multiple warnings from GMU start as HS, + * clocks and IRQ were ON while doing a + * fresh start i.e. wake from SLUMBER. + * + * Suspend the GMU on recovery failure + * to make sure next attempt to wake up + * GMU/GPU is indeed a fresh start. + */ + gmu_suspend(device); + gmu->unrecovered = true; kgsl_pwrctrl_set_state(device, state); } else { if (device->snapshot) -- GitLab From 59268be8aee4ea62e6a69d4577edfe8f0c59e322 Mon Sep 17 00:00:00 2001 From: Konstantin Dorfman Date: Mon, 30 Apr 2018 14:51:57 +0300 Subject: [PATCH 1561/1834] soc: qcom: spcom: create control channel For commands that don't required SPU communication: is-link-up and create channel, instead of using sp_kernel channel (the one used for application loading) control channel /dev/spcom used. Change-Id: I4d6abd83d77f3b1a3d277dbfec076faa0cbc72af Signed-off-by: Konstantin Dorfman --- drivers/soc/qcom/spcom.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/soc/qcom/spcom.c b/drivers/soc/qcom/spcom.c index 0b037d48d49b..d568014b52c4 100644 --- a/drivers/soc/qcom/spcom.c +++ b/drivers/soc/qcom/spcom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -374,7 +374,7 @@ static void spcom_link_state_notif_cb(struct glink_link_state_cb_info *cb_info, switch (cb_info->link_state) { case GLINK_LINK_STATE_UP: - pr_info("GLINK_LINK_STATE_UP.\n"); + pr_debug("GLINK_LINK_STATE_UP.\n"); spcom_create_predefined_channels_chardev(); break; case GLINK_LINK_STATE_DOWN: @@ -1170,7 +1170,7 @@ struct spcom_client *spcom_register_client(struct spcom_client_info *info) kfree(client); client = NULL; } else { - pr_info("remote side connect to channel [%s].\n", name); + pr_debug("remote side connect to channel [%s].\n", name); } return client; @@ -2010,6 +2010,11 @@ static int spcom_handle_write(struct spcom_channel *ch, pr_debug("cmd_id [0x%x] cmd_name [%s].\n", cmd_id, cmd_name); + if (!ch && cmd_id != SPCOM_CMD_CREATE_CHANNEL) { + pr_err("channel context is null\n"); + return -EINVAL; + } + switch (cmd_id) { case SPCOM_CMD_SEND: ret = spcom_handle_send_command(ch, buf, buf_size); @@ -2342,8 +2347,12 @@ static ssize_t spcom_device_write(struct file *filp, ch = filp->private_data; if (!ch) { - pr_err("invalid ch pointer, command not allowed.\n"); - return -EINVAL; + if (strcmp(name, DEVICE_NAME) == 0) { + pr_debug("control device - no channel context.\n"); + } else { + pr_err("NULL ch pointer, command not allowed.\n"); + return -EINVAL; + } } else { /* Check if remote side connect */ if (!spcom_is_channel_connected(ch)) { @@ -2784,7 +2793,7 @@ static int spcom_probe(struct platform_device *pdev) goto fail_ion_client; } - pr_info("Driver Initialization ok.\n"); + pr_debug("Driver Initialization ok.\n"); return 0; @@ -2821,7 +2830,7 @@ static int __init spcom_init(void) { int ret; - pr_info("spcom driver version 1.3 28-Dec-2017.\n"); + pr_debug("spcom driver version 1.4 30-Apr-2018.\n"); ret = platform_driver_register(&spcom_driver); if (ret) -- GitLab From a1cd1988e4b6f7dfb0982113875368eb84869dc9 Mon Sep 17 00:00:00 2001 From: Vaishnavi Kommaraju Date: Wed, 25 Apr 2018 19:59:21 +0530 Subject: [PATCH 1562/1834] ARM: dts: msm: Update audio codec vdd mic bias voltage for sdm439 Update cdc-vdd-mic-bias-voltage to 3075000 as per l13 regulator max voltage limit. Change-Id: I4fab2b0c018ff4948024971c2c2a7c8ee2666a4f Signed-off-by: Vaishnavi Kommaraju --- arch/arm64/boot/dts/qcom/sdm439-audio.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi index f6751d2445aa..07633cb8dbb4 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi @@ -76,7 +76,7 @@ qcom,cdc-vdd-pa-current = <260000>; cdc-vdd-mic-bias-supply = <&pm8953_l13>; - qcom,cdc-vdd-mic-bias-voltage = <3125000 3125000>; + qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>; qcom,cdc-vdd-mic-bias-current = <5000>; qcom,cdc-mclk-clk-rate = <9600000>; -- GitLab From b3b650b9306e45c52a2ff0bfb9def73d64d0c9b8 Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Mon, 30 Apr 2018 09:00:14 +0530 Subject: [PATCH 1563/1834] ARM: dts: msm: add support for MDSS clocks for sdm439/sdm429 Add the DT node for GCC MDSS clock node for sdm439/sdm429. This maps the parents of MDSS DSI RCG clocks with the corresponding DSI PLL clocks. Change-Id: I6b2d846be4a91546211564b3f36f9910b7dc62ee Signed-off-by: Padmanabhan Komanduru --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 11 +++++++++++ arch/arm64/boot/dts/qcom/sdm439.dtsi | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 33b352d8f922..49be6e42b972 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -178,3 +178,14 @@ #clock-cells = <1>; }; }; + +&clock_gcc_mdss { + compatible = "qcom,gcc-mdss-sdm429"; + clocks = <&mdss_dsi0_pll clk_dsi0pll_pixel_clk_src>, + <&mdss_dsi0_pll clk_dsi0pll_byte_clk_src>, + <&mdss_dsi1_pll clk_dsi1pll_pixel_clk_src>, + <&mdss_dsi1_pll clk_dsi1pll_byte_clk_src>; + clock-names = "pclk0_src", "byte0_src", "pclk1_src", + "byte1_src"; + #clock-cells = <1>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 6cfd2d7ab4da..7262b8ef582e 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -258,3 +258,14 @@ vdd_hf_dig-supply = <&pm8953_s2_level_ao>; vdd_hf_pll-supply = <&pm8953_l7_ao>; }; + +&clock_gcc_mdss { + compatible = "qcom,gcc-mdss-sdm439"; + clocks = <&mdss_dsi0_pll clk_dsi0pll_pixel_clk_src>, + <&mdss_dsi0_pll clk_dsi0pll_byte_clk_src>, + <&mdss_dsi1_pll clk_dsi1pll_pixel_clk_src>, + <&mdss_dsi1_pll clk_dsi1pll_byte_clk_src>; + clock-names = "pclk0_src", "byte0_src", "pclk1_src", + "byte1_src"; + #clock-cells = <1>; +}; -- GitLab From dfeb2d816c8120b4fe9e124a5eb576c90053b58c Mon Sep 17 00:00:00 2001 From: Padmanabhan Komanduru Date: Tue, 24 Apr 2018 10:39:16 +0530 Subject: [PATCH 1564/1834] ARM: dts: msm: update the MDSS DSI nodes for SDM439/SDM429 MDSS DSI PHY is 12nm based process for SDM439/SDM429. Update the MDSS DSI nodes to take care of this. Change-Id: I2640a591262248da9477b361607a63a1314c6de7 Signed-off-by: Padmanabhan Komanduru --- arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi | 3 ++ arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi | 3 ++ arch/arm64/boot/dts/qcom/sdm439.dtsi | 53 ++++++++++++++++++++++++ 3 files changed, 59 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi index f0e550ea2842..0ad5dfe627f2 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi @@ -175,7 +175,10 @@ qcom,platform-reset-gpio = <&tlmm 60 0>; lab-supply = <&lcdb_ldo_vreg>; ibb-supply = <&lcdb_ncp_vreg>; +}; +&mdss_dsi1 { + status = "disabled"; }; &dsi_hx8399c_truly_vid { diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi index c6cec5360ed0..50f8ae1ca010 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp.dtsi @@ -175,7 +175,10 @@ qcom,platform-reset-gpio = <&tlmm 60 0>; lab-supply = <&lcdb_ldo_vreg>; ibb-supply = <&lcdb_ncp_vreg>; +}; +&mdss_dsi1 { + status = "disabled"; }; &dsi_hx8399c_truly_vid { diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 7262b8ef582e..e03b781aec1a 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -269,3 +269,56 @@ "byte1_src"; #clock-cells = <1>; }; + +&mdss_dsi0_pll { + compatible = "qcom,mdss_dsi_pll_sdm439"; + reg = <0x001a94400 0x400>, + <0x0184d074 0x8>; + reg-names = "pll_base", "gdsc_base"; + /delete-property/ qcom,dsi-pll-ssc-en; + /delete-property/ qcom,dsi-pll-ssc-mode; + /delete-property/ qcom,ssc-frequency-hz; + /delete-property/ qcom,ssc-ppm; +}; + +&mdss_dsi1_pll { + compatible = "qcom,mdss_dsi_pll_sdm439"; + reg = <0x001a96400 0x400>, + <0x0184d074 0x8>; + reg-names = "pll_base", "gdsc_base"; + /delete-property/ qcom,dsi-pll-ssc-en; + /delete-property/ qcom,dsi-pll-ssc-mode; + /delete-property/ qcom,ssc-frequency-hz; + /delete-property/ qcom,ssc-ppm; +}; + +&mdss_dsi { + ranges = <0x1a94000 0x1a94000 0x300 + 0x1a94400 0x1a94400 0x400 + 0x193e000 0x193e000 0x30 + 0x1a96000 0x1a96000 0x300 + 0x1a96400 0x1a96400 0x400 + 0x193e000 0x193e000 0x30>; +}; + +&mdss_dsi0 { + reg = <0x1a94000 0x300>, + <0x1a94400 0x400>, + <0x193e000 0x30>; + reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys"; + /delete-property/ qcom,platform-strength-ctrl; + /delete-property/ qcom,platform-bist-ctrl; + /delete-property/ qcom,platform-regulator-settings; + /delete-property/ qcom,platform-lane-config; +}; + +&mdss_dsi1 { + reg = <0x1a96000 0x300>, + <0x1a96400 0x400>, + <0x193e000 0x30>; + reg-names = "dsi_ctrl", "dsi_phy", "mmss_misc_phys"; + /delete-property/ qcom,platform-strength-ctrl; + /delete-property/ qcom,platform-bist-ctrl; + /delete-property/ qcom,platform-regulator-settings; + /delete-property/ qcom,platform-lane-config; +}; -- GitLab From 4d334f478517a255366b56b1ead000df1b7da937 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Wed, 25 Apr 2018 10:58:49 +0530 Subject: [PATCH 1565/1834] power: smb5: add support to enable/disable hvdcp optimization On certain PMICs, Flash has a requirement to limit VBUS at 5V when it is active. This is to prevent the VIN_FLASH from seeing a high input voltage. Add support for this by forcing VBUS to 5V when there is a notification from flash driver based on flash_active power-supply property. The userspace is also notified to stop any further VBUS optimizations by setting the hvdcp_opti_allowed property. The optimization is re-enabled when flash_active is cleared by the flash driver. Change-Id: I3748fe75f467969ecc4ec2a60c5360dba13953f1 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 34 +++++++++++++++++++++++++-- drivers/power/supply/qcom/smb5-lib.c | 2 +- drivers/power/supply/qcom/smb5-lib.h | 1 + drivers/power/supply/qcom/smb5-reg.h | 1 + 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 7a3a4dcc3969..be4765817cca 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -389,6 +389,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_CONNECTOR_TYPE, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED, }; static int smb5_usb_get_prop(struct power_supply *psy, @@ -504,6 +505,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, : chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM : POWER_SUPPLY_SCOPE_UNKNOWN; break; + case POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED: + val->intval = !chg->flash_active; + break; default: pr_err("get prop %d is not supported in usb\n", psp); rc = -EINVAL; @@ -789,6 +793,7 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, { struct smb5 *chip = power_supply_get_drvdata(psy); struct smb_charger *chg = &chip->chg; + union power_supply_propval pval = {0, }; int rc = 0; switch (psp) { @@ -802,7 +807,31 @@ static int smb5_usb_main_set_prop(struct power_supply *psy, rc = smblib_set_icl_current(chg, val->intval); break; case POWER_SUPPLY_PROP_FLASH_ACTIVE: - chg->flash_active = val->intval; + if ((chg->smb_version == PMI632_SUBTYPE) + && (chg->flash_active != val->intval)) { + chg->flash_active = val->intval; + + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) + pr_err("Failed to get USB preset status rc=%d\n", + rc); + if (pval.intval) { + rc = smblib_force_vbus_voltage(chg, + chg->flash_active ? FORCE_5V_BIT + : IDLE_BIT); + if (rc < 0) + pr_err("Failed to force 5V\n"); + else + chg->pulse_cnt = 0; + } + + pr_debug("flash active VBUS 5V restriction %s\n", + chg->flash_active ? "applied" : "removed"); + + /* Update userspace */ + if (chg->batt_psy) + power_supply_changed(chg->batt_psy); + } break; default: pr_err("set prop %d is not supported\n", psp); @@ -1146,7 +1175,8 @@ static int smb5_batt_set_prop(struct power_supply *psy, rc = smblib_rerun_aicl(chg); break; case POWER_SUPPLY_PROP_DP_DM: - rc = smblib_dp_dm(chg, val->intval); + if (!chg->flash_active) + rc = smblib_dp_dm(chg, val->intval); break; case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: rc = smblib_set_prop_input_current_limited(chg, val); diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 3152669ef15b..8eed5894daa0 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1590,7 +1590,7 @@ static int smblib_dm_pulse(struct smb_charger *chg) return rc; } -static int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val) +int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val) { int rc; diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 668ce5ffaed5..57154474da57 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -528,6 +528,7 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val); int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override); int smblib_configure_wdog(struct smb_charger *chg, bool enable); +int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index bb2842332e45..48ef12e1a6c6 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -194,6 +194,7 @@ enum { #define FORCE_12V_BIT BIT(5) #define FORCE_9V_BIT BIT(4) #define FORCE_5V_BIT BIT(3) +#define IDLE_BIT BIT(2) #define SINGLE_DECREMENT_BIT BIT(1) #define SINGLE_INCREMENT_BIT BIT(0) -- GitLab From 35adef4688d2eb90572fa44a4cac4cfbadda8634 Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Tue, 3 Apr 2018 14:08:28 +0800 Subject: [PATCH 1566/1834] ARM: dts: msm: Add audio apr device for SDM845 Add device node for audio apr device for SDM845 target. This device is added to represent APR module. Change-Id: If06029065a583561e701c469fabd667f6a4d347a Signed-off-by: Meng Wang --- arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi index 46069560f8c8..94672972531c 100644 --- a/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -302,6 +302,10 @@ compatible = "qcom,msm-pcm-hostless"; }; + audio_apr: qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + }; + dai_pri_auxpcm: qcom,msm-pri-auxpcm { compatible = "qcom,msm-auxpcm-dev"; qcom,msm-cpudai-auxpcm-mode = <0>, <0>; -- GitLab From f2cc6d89aced1645397525bad65e9c4fff3b1ee5 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 16 Apr 2018 18:19:17 -0700 Subject: [PATCH 1567/1834] ARM: Add option to build Image/dtb combo Add a target Image-dtb which will build an uncompressed kernel with an appended dtb image. Change-Id: I2ede8fd935327d75d7378c2868d39c416d704724 Signed-off-by: Patrick Daly --- arch/arm/Makefile | 4 ++++ arch/arm/boot/.gitignore | 4 +++- arch/arm/boot/Makefile | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index f42fcd4561dd..b0d17fd9a762 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -352,6 +352,10 @@ endif zImage-dtb: vmlinux scripts dtbs $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) DTSSUBDIR=$(DTSSUBDIR) $(boot)/$@ +Image-dtb: vmlinux scripts dtbs + $(Q)$(MAKE) $(build)=$(boot) MACHINE=$(MACHINE) DTSSUBDIR=$(DTSSUBDIR) $(boot)/$@ + + # We use MRPROPER_FILES and CLEAN_FILES now archclean: $(Q)$(MAKE) $(clean)=$(boot) diff --git a/arch/arm/boot/.gitignore b/arch/arm/boot/.gitignore index ad7a0253ea96..271e1241be95 100644 --- a/arch/arm/boot/.gitignore +++ b/arch/arm/boot/.gitignore @@ -4,4 +4,6 @@ xipImage bootpImage uImage *.dtb -zImage-dtb \ No newline at end of file +zImage-dtb +Image-dtb-hdr +Image-dtb diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 4175dfe43225..2fa123e315cc 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -59,6 +59,14 @@ $(obj)/xipImage: FORCE $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) +$(obj)/Image-dtb-hdr: $(obj)/Image FORCE + echo -n 'UNCOMPRESSED_IMG' > $@ && \ + $(call size_append, $(filter-out FORCE,$^)) >> $@ + +$(obj)/Image-dtb: $(obj)/Image-dtb-hdr $(obj)/Image $(DTB_OBJS) FORCE + $(call if_changed,cat) + @echo ' Kernel: $@ is ready' + $(obj)/compressed/vmlinux: $(obj)/Image FORCE $(Q)$(MAKE) $(build)=$(obj)/compressed $@ -- GitLab From d3f0abe4299252d205263d4674d4347b50d27f8f Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Tue, 28 Mar 2017 13:30:18 -0700 Subject: [PATCH 1568/1834] ANDROID: ARM: Allow to choose appended kernel image By default appended kernel image is Image.gz-dtb. New config option BUILD_ARM_APPENDED_KERNEL_IMAGE_NAME allows to choose between zImage-dtb and Image-dtb. Change-Id: I1c71b85136f1beeb61782e4646820718c1ccd7e4 Signed-off-by: Dmitry Shmidt Git-Repo: https://android.googlesource.com/kernel/common Git-Commit: 4bdcc9366ab74f0880ba72f7a1a98391359f127f [pdaly] Ported to ARM32 Signed-off-by: Patrick Daly --- arch/arm/Kconfig | 20 ++++++++++++++++++++ arch/arm/Makefile | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 41245ce40162..04b1c061c927 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1937,6 +1937,26 @@ config BUILD_ARM_APPENDED_DTB_IMAGE Enabling this option will cause a concatenated zImage and list of DTBs to be built by default (instead of a standalone zImage.) The image will built in arch/arm/boot/zImage-dtb +choice + prompt "Appended DTB Kernel Image name" + depends on BUILD_ARM_APPENDED_DTB_IMAGE + default ZIMG_DTB + help + Enabling this option will cause a specific kernel image Image or + Image.gz to be used for final image creation. + The image will built in arch/arm/boot/IMAGE-NAME-dtb + + config ZIMG_DTB + bool "zImage-dtb" + config IMG_DTB + bool "Image-dtb" +endchoice + +config BUILD_ARM_APPENDED_KERNEL_IMAGE_NAME + string + depends on BUILD_ARM_APPENDED_DTB_IMAGE + default "zImage-dtb" if ZIMG_DTB + default "Image-dtb" if IMG_DTB config BUILD_ARM_APPENDED_DTB_IMAGE_NAMES string "Default dtb names" diff --git a/arch/arm/Makefile b/arch/arm/Makefile index b0d17fd9a762..a6d57944fbda 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -299,7 +299,7 @@ libs-y := arch/arm/lib/ $(libs-y) ifeq ($(CONFIG_XIP_KERNEL),y) KBUILD_IMAGE := xipImage else ifeq ($(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE),y) -KBUILD_IMAGE := zImage-dtb +KBUILD_IMAGE := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_KERNEL_IMAGE_NAME)) else KBUILD_IMAGE := zImage endif -- GitLab From 681e6619a809f9be4106fcf2b81db173063726d3 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Mon, 16 Jan 2017 08:16:07 +0100 Subject: [PATCH 1569/1834] iommu/arm-smmu: Fix for ThunderX erratum #27704 The goal of erratum #27704 workaround was to make sure that ASIDs and VMIDs are unique across all SMMU instances on affected Cavium systems. Currently, the workaround code partitions ASIDs and VMIDs by increasing global cavium_smmu_context_count which in turn becomes the base ASID and VMID value for the given SMMU instance upon the context bank initialization. For systems with multiple SMMU instances this approach implies the risk of crossing 8-bit ASID, like for 1-socket CN88xx capable of 4 SMMUv2, 128 context banks each: SMMU_0 (0-127 ASID RANGE) SMMU_1 (127-255 ASID RANGE) SMMU_2 (256-383 ASID RANGE) <--- crossing 8-bit ASID SMMU_3 (384-511 ASID RANGE) <--- crossing 8-bit ASID Since now we use 8-bit ASID (SMMU_CBn_TCR2.AS = 0) we effectively misconfigure ASID[15:8] bits of SMMU_CBn_TTBRm register for SMMU_2/3. Moreover, we still assume non-zero ASID[15:8] bits upon context invalidation. In the end, except SMMU_0/1 devices all other devices under other SMMUs will fail on guest power off/on. Since we try to invalidate TLB with 16-bit ASID but we actually have 8-bit zero padded 16-bit entry. This patch adds 16-bit ASID support for stage-1 AArch64 contexts so that we use ASIDs consistently for all SMMU instances. Change-Id: I7949517de95b4a6b28125e8f3d18b453168658b2 Signed-off-by: Tomasz Nowicki Reviewed-by: Robin Murphy Reviewed-by: Tirumalesh Chalamarla Signed-off-by: Will Deacon Git-commit: 3677a649a751c8f061ba379a98c369473ccac980 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Patrick Daly --- drivers/iommu/arm-smmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 8005ab877792..c76291bf6380 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -292,6 +292,7 @@ enum arm_smmu_s2cr_privcfg { #define TTBCR2_SEP_SHIFT 15 #define TTBCR2_SEP_UPSTREAM (0x7 << TTBCR2_SEP_SHIFT) +#define TTBCR2_AS (1 << 4) #define TTBRn_ASID_SHIFT 48 @@ -1698,6 +1699,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr; reg2 = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; reg2 |= TTBCR2_SEP_UPSTREAM; + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) + reg2 |= TTBCR2_AS; } if (smmu->version > ARM_SMMU_V1) writel_relaxed(reg2, cb_base + ARM_SMMU_CB_TTBCR2); -- GitLab From f0b0a2a863e1a5045fc967925fb88501f70adefc Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Tue, 28 Mar 2017 16:11:12 +0530 Subject: [PATCH 1570/1834] iommu/arm-smmu: Fix 16-bit ASID configuration 16-bit ASID should be enabled before initializing TTBR0/1, otherwise only LSB 8-bit ASID will be considered. Hence moving configuration of TTBCR register ahead of TTBR0/1 while initializing context bank. Change-Id: If76f9c3d201289245292d1fab47278eadff6f4db Signed-off-by: Sunil Goutham [will: rewrote comment] Signed-off-by: Will Deacon Git-commit: 125458ab3aefe9cf2f72dcfe7338dc9ad967da0b Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git Signed-off-by: Patrick Daly --- drivers/iommu/arm-smmu.c | 42 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index c76291bf6380..2abcc42dac56 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1667,6 +1667,29 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, } writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx)); + /* + * TTBCR + * We must write this before the TTBRs, since it determines the + * access behaviour of some fields (in particular, ASID[15:8]). + */ + if (stage1) { + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { + reg = pgtbl_cfg->arm_v7s_cfg.tcr; + reg2 = 0; + } else { + reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr; + reg2 = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; + reg2 |= TTBCR2_SEP_UPSTREAM; + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) + reg2 |= TTBCR2_AS; + } + if (smmu->version > ARM_SMMU_V1) + writel_relaxed(reg2, cb_base + ARM_SMMU_CB_TTBCR2); + } else { + reg = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; + } + writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); + /* TTBRs */ if (stage1) { u16 asid = ARM_SMMU_CB_ASID(smmu, cfg); @@ -1690,25 +1713,6 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0); } - /* TTBCR */ - if (stage1) { - if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { - reg = pgtbl_cfg->arm_v7s_cfg.tcr; - reg2 = 0; - } else { - reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr; - reg2 = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; - reg2 |= TTBCR2_SEP_UPSTREAM; - if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) - reg2 |= TTBCR2_AS; - } - if (smmu->version > ARM_SMMU_V1) - writel_relaxed(reg2, cb_base + ARM_SMMU_CB_TTBCR2); - } else { - reg = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; - } - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); - /* MAIRs (stage-1 only) */ if (stage1) { if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { -- GitLab From 6549a1ff6ee30bc962e68e48a45ba2cb63f05294 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Tue, 8 Aug 2017 14:56:14 +0100 Subject: [PATCH 1571/1834] iommu/arm-smmu: Track context bank state Echoing what we do for Stream Map Entries, maintain a software shadow state for context bank configuration. With this in place, we are mere moments away from blissfully easy suspend/resume support. Change-Id: Ieb9ee45d31474dbc3f9cb1fa5054f18b1e414a40 Reviewed-by: Sricharan R Signed-off-by: Robin Murphy [will: fix sparse warning by only clearing .cfg during domain destruction] Signed-off-by: Will Deacon Git-commit: 90df373cc62e527b010025249d11d10d19b086bd Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git [pdaly: Add attributes field. Modify DOMAIN_ATTRIBUTE_EARLY_MAP handling] Signed-off-by: Patrick Daly --- drivers/iommu/arm-smmu.c | 179 +++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 71 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 2abcc42dac56..cf7e9c0e8445 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -370,6 +370,14 @@ struct arm_smmu_smr { bool valid; }; +struct arm_smmu_cb { + u64 ttbr[2]; + u32 tcr[2]; + u32 mair[2]; + struct arm_smmu_cfg *cfg; + u32 attributes; +}; + struct arm_smmu_master_cfg { struct arm_smmu_device *smmu; s16 smendx[]; @@ -441,6 +449,7 @@ struct arm_smmu_device { u32 num_s2_context_banks; DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS); DECLARE_BITMAP(secure_context_map, ARM_SMMU_MAX_CBS); + struct arm_smmu_cb *cbs; atomic_t irptndx; u32 num_mapping_groups; @@ -1626,17 +1635,76 @@ static int arm_smmu_set_pt_format(struct arm_smmu_domain *smmu_domain, static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, struct io_pgtable_cfg *pgtbl_cfg) { - u32 reg, reg2; - u64 reg64; - bool stage1; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - struct arm_smmu_device *smmu = smmu_domain->smmu; + struct arm_smmu_cb *cb = &smmu_domain->smmu->cbs[cfg->cbndx]; + bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; + + cb->cfg = cfg; + + /* TTBCR */ + if (stage1) { + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { + cb->tcr[0] = pgtbl_cfg->arm_v7s_cfg.tcr; + } else { + cb->tcr[0] = pgtbl_cfg->arm_lpae_s1_cfg.tcr; + cb->tcr[1] = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; + cb->tcr[1] |= TTBCR2_SEP_UPSTREAM; + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) + cb->tcr[1] |= TTBCR2_AS; + } + } else { + cb->tcr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; + } + + /* TTBRs */ + if (stage1) { + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { + cb->ttbr[0] = pgtbl_cfg->arm_v7s_cfg.ttbr[0]; + cb->ttbr[1] = pgtbl_cfg->arm_v7s_cfg.ttbr[1]; + } else { + cb->ttbr[0] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; + cb->ttbr[0] |= (u64)cfg->asid << TTBRn_ASID_SHIFT; + cb->ttbr[1] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; + cb->ttbr[1] |= (u64)cfg->asid << TTBRn_ASID_SHIFT; + } + } else { + cb->ttbr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; + } + + /* MAIRs (stage-1 only) */ + if (stage1) { + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { + cb->mair[0] = pgtbl_cfg->arm_v7s_cfg.prrr; + cb->mair[1] = pgtbl_cfg->arm_v7s_cfg.nmrr; + } else { + cb->mair[0] = pgtbl_cfg->arm_lpae_s1_cfg.mair[0]; + cb->mair[1] = pgtbl_cfg->arm_lpae_s1_cfg.mair[1]; + } + } + + cb->attributes = smmu_domain->attributes; +} + +static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx) +{ + u32 reg; + bool stage1; + struct arm_smmu_cb *cb = &smmu->cbs[idx]; + struct arm_smmu_cfg *cfg = cb->cfg; void __iomem *cb_base, *gr1_base; + cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, idx); + + /* Unassigned context banks only need disabling */ + if (!cfg) { + writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); + return; + } + gr1_base = ARM_SMMU_GR1(smmu); stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS; - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); + /* CBA2R */ if (smmu->version > ARM_SMMU_V1) { if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) reg = CBA2R_RW64_64BIT; @@ -1646,7 +1714,7 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, if (smmu->features & ARM_SMMU_FEAT_VMID16) reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBA2R_VMID_SHIFT; - writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx)); + writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(idx)); } /* CBAR */ @@ -1665,65 +1733,32 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, /* 8-bit VMIDs live in CBAR */ reg |= ARM_SMMU_CB_VMID(smmu, cfg) << CBAR_VMID_SHIFT; } - writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(cfg->cbndx)); + writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(idx)); /* * TTBCR * We must write this before the TTBRs, since it determines the * access behaviour of some fields (in particular, ASID[15:8]). */ - if (stage1) { - if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { - reg = pgtbl_cfg->arm_v7s_cfg.tcr; - reg2 = 0; - } else { - reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr; - reg2 = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; - reg2 |= TTBCR2_SEP_UPSTREAM; - if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) - reg2 |= TTBCR2_AS; - } - if (smmu->version > ARM_SMMU_V1) - writel_relaxed(reg2, cb_base + ARM_SMMU_CB_TTBCR2); - } else { - reg = pgtbl_cfg->arm_lpae_s2_cfg.vtcr; - } - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR); + if (stage1 && smmu->version > ARM_SMMU_V1) + writel_relaxed(cb->tcr[1], cb_base + ARM_SMMU_CB_TTBCR2); + writel_relaxed(cb->tcr[0], cb_base + ARM_SMMU_CB_TTBCR); /* TTBRs */ - if (stage1) { - u16 asid = ARM_SMMU_CB_ASID(smmu, cfg); - - if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { - reg = pgtbl_cfg->arm_v7s_cfg.ttbr[0]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0); - reg = pgtbl_cfg->arm_v7s_cfg.ttbr[1]; - writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1); - writel_relaxed(asid, cb_base + ARM_SMMU_CB_CONTEXTIDR); - } else { - reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0]; - reg64 |= (u64)asid << TTBRn_ASID_SHIFT; - writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0); - reg64 = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1]; - reg64 |= (u64)asid << TTBRn_ASID_SHIFT; - writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR1); - } + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { + writel_relaxed(cfg->asid, cb_base + ARM_SMMU_CB_CONTEXTIDR); + writel_relaxed(cb->ttbr[0], cb_base + ARM_SMMU_CB_TTBR0); + writel_relaxed(cb->ttbr[1], cb_base + ARM_SMMU_CB_TTBR1); } else { - reg64 = pgtbl_cfg->arm_lpae_s2_cfg.vttbr; - writeq_relaxed(reg64, cb_base + ARM_SMMU_CB_TTBR0); + writeq_relaxed(cb->ttbr[0], cb_base + ARM_SMMU_CB_TTBR0); + if (stage1) + writeq_relaxed(cb->ttbr[1], cb_base + ARM_SMMU_CB_TTBR1); } /* MAIRs (stage-1 only) */ if (stage1) { - if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) { - reg = pgtbl_cfg->arm_v7s_cfg.prrr; - reg2 = pgtbl_cfg->arm_v7s_cfg.nmrr; - } else { - reg = pgtbl_cfg->arm_lpae_s1_cfg.mair[0]; - reg2 = pgtbl_cfg->arm_lpae_s1_cfg.mair[1]; - } - writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0); - writel_relaxed(reg2, cb_base + ARM_SMMU_CB_S1_MAIR1); + writel_relaxed(cb->mair[0], cb_base + ARM_SMMU_CB_S1_MAIR0); + writel_relaxed(cb->mair[1], cb_base + ARM_SMMU_CB_S1_MAIR1); } /* SCTLR */ @@ -1732,20 +1767,20 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, /* Ensure bypass transactions are Non-shareable */ reg |= SCTLR_SHCFG_NSH << SCTLR_SHCFG_SHIFT; - if (smmu_domain->attributes & (1 << DOMAIN_ATTR_CB_STALL_DISABLE)) { + if (cb->attributes & (1 << DOMAIN_ATTR_CB_STALL_DISABLE)) { reg &= ~SCTLR_CFCFG; reg |= SCTLR_HUPCF; } - if ((!(smmu_domain->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) && - !(smmu_domain->attributes & (1 << DOMAIN_ATTR_EARLY_MAP))) || + if ((!(cb->attributes & (1 << DOMAIN_ATTR_S1_BYPASS)) && + !(cb->attributes & (1 << DOMAIN_ATTR_EARLY_MAP))) || !stage1) reg |= SCTLR_M; if (stage1) reg |= SCTLR_S1_ASIDPNE; -#ifdef __BIG_ENDIAN - reg |= SCTLR_E; -#endif + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + reg |= SCTLR_E; + writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); } @@ -1995,7 +2030,8 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, if (!dynamic) { /* Initialise the context bank with our page table cfg */ arm_smmu_init_context_bank(smmu_domain, - &smmu_domain->pgtbl_cfg); + &smmu_domain->pgtbl_cfg); + arm_smmu_write_context_bank(smmu, cfg->cbndx); /* for slave side secure, we may have to force the pagetable * format to V8L. */ @@ -2053,7 +2089,6 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain); struct arm_smmu_device *smmu = smmu_domain->smmu; struct arm_smmu_cfg *cfg = &smmu_domain->cfg; - void __iomem *cb_base; int irq; bool dynamic; int ret; @@ -2085,8 +2120,8 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain) * Disable the context bank and free the page tables before freeing * it. */ - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); - writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); + smmu->cbs[cfg->cbndx].cfg = NULL; + arm_smmu_write_context_bank(smmu, cfg->cbndx); if (cfg->irptndx != INVALID_IRPTNDX) { irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx]; @@ -3509,19 +3544,16 @@ static int arm_smmu_enable_s1_translations(struct arm_smmu_domain *smmu_domain) { struct arm_smmu_cfg *cfg = &smmu_domain->cfg; struct arm_smmu_device *smmu = smmu_domain->smmu; - void __iomem *cb_base; - u32 reg; + struct arm_smmu_cb *cb = &smmu->cbs[cfg->cbndx]; int ret; - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx); ret = arm_smmu_power_on(smmu->pwr); if (ret) return ret; - reg = readl_relaxed(cb_base + ARM_SMMU_CB_SCTLR); - reg |= SCTLR_M; + cb->attributes &= ~(1 << DOMAIN_ATTR_EARLY_MAP); + arm_smmu_write_context_bank(smmu, cfg->cbndx); - writel_relaxed(reg, cb_base + ARM_SMMU_CB_SCTLR); arm_smmu_power_off(smmu->pwr); return ret; } @@ -3784,7 +3816,6 @@ static void arm_smmu_context_bank_reset(struct arm_smmu_device *smmu) int i; u32 reg, major; void __iomem *gr0_base = ARM_SMMU_GR0(smmu); - void __iomem *cb_base; /* * Before clearing ARM_MMU500_ACTLR_CPRE, need to @@ -3801,8 +3832,10 @@ static void arm_smmu_context_bank_reset(struct arm_smmu_device *smmu) /* Make sure all context banks are disabled and clear CB_FSR */ for (i = 0; i < smmu->num_context_banks; ++i) { - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, i); - writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR); + void __iomem *cb_base = ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, i); + + arm_smmu_write_context_bank(smmu, i); writel_relaxed(FSR_FAULT, cb_base + ARM_SMMU_CB_FSR); /* * Disable MMU-500's not-particularly-beneficial next-page @@ -4432,6 +4465,10 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) &cavium_smmu_context_count); smmu->cavium_id_base -= smmu->num_context_banks; } + smmu->cbs = devm_kcalloc(smmu->dev, smmu->num_context_banks, + sizeof(*smmu->cbs), GFP_KERNEL); + if (!smmu->cbs) + return -ENOMEM; /* ID2 */ id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2); -- GitLab From ad52108eecef9e7a4498810cb089f287dd0d076d Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 6 Apr 2018 18:07:13 -0700 Subject: [PATCH 1572/1834] iommu: arm-smmu: Add PM support for actlr register Save the value of the actlr register so it can be restored upon resume from hibernation/suspend. Change-Id: I02dda54ee5905870adae05357e043c4d95003412 Signed-off-by: Patrick Daly --- drivers/iommu/arm-smmu.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index cf7e9c0e8445..e0b2f635f926 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -375,6 +375,7 @@ struct arm_smmu_cb { u32 tcr[2]; u32 mair[2]; struct arm_smmu_cfg *cfg; + u32 actlr; u32 attributes; }; @@ -1761,6 +1762,9 @@ static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx) writel_relaxed(cb->mair[1], cb_base + ARM_SMMU_CB_S1_MAIR1); } + /* ACTLR (implementation defined) */ + writel_relaxed(cb->actlr, cb_base + ARM_SMMU_CB_ACTLR); + /* SCTLR */ reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE; @@ -2031,6 +2035,7 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, /* Initialise the context bank with our page table cfg */ arm_smmu_init_context_bank(smmu_domain, &smmu_domain->pgtbl_cfg); + arm_smmu_arch_init_context_bank(smmu_domain, dev); arm_smmu_write_context_bank(smmu, cfg->cbndx); /* for slave side secure, we may have to force the pagetable * format to V8L. @@ -2040,8 +2045,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, if (ret) goto out_clear_smmu; - arm_smmu_arch_init_context_bank(smmu_domain, dev); - /* * Request context fault interrupt. Do this last to avoid the * handler seeing a half-initialised domain state. @@ -3740,18 +3743,17 @@ static void qsmmuv2_device_reset(struct arm_smmu_device *smmu) int i; u32 val; struct arm_smmu_impl_def_reg *regs = smmu->impl_def_attach_registers; - void __iomem *cb_base; - /* * SCTLR.M must be disabled here per ARM SMMUv2 spec * to prevent table walks with an inconsistent state. */ for (i = 0; i < smmu->num_context_banks; ++i) { - cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, i); + struct arm_smmu_cb *cb = &smmu->cbs[i]; + val = ACTLR_QCOM_ISH << ACTLR_QCOM_ISH_SHIFT | ACTLR_QCOM_OSH << ACTLR_QCOM_OSH_SHIFT | ACTLR_QCOM_NSH << ACTLR_QCOM_NSH_SHIFT; - writel_relaxed(val, cb_base + ARM_SMMU_CB_ACTLR); + cb->actlr = val; } /* Program implementation defined registers */ @@ -5429,20 +5431,14 @@ static void qsmmuv500_init_cb(struct arm_smmu_domain *smmu_domain, struct device *dev) { struct arm_smmu_device *smmu = smmu_domain->smmu; + struct arm_smmu_cb *cb = &smmu->cbs[smmu_domain->cfg.cbndx]; struct qsmmuv500_group_iommudata *iommudata = to_qsmmuv500_group_iommudata(dev->iommu_group); - void __iomem *cb_base; - const struct iommu_gather_ops *tlb; if (!iommudata->has_actlr) return; - tlb = smmu_domain->pgtbl_cfg.tlb; - cb_base = ARM_SMMU_CB_BASE(smmu) + - ARM_SMMU_CB(smmu, smmu_domain->cfg.cbndx); - - writel_relaxed(iommudata->actlr, cb_base + ARM_SMMU_CB_ACTLR); - + cb->actlr = iommudata->actlr; /* * Prefetch only works properly if the start and end of all * buffers in the page table are aligned to 16 Kb. @@ -5450,12 +5446,6 @@ static void qsmmuv500_init_cb(struct arm_smmu_domain *smmu_domain, if ((iommudata->actlr >> QSMMUV500_ACTLR_DEEP_PREFETCH_SHIFT) & QSMMUV500_ACTLR_DEEP_PREFETCH_MASK) smmu_domain->qsmmuv500_errata2_min_align = true; - - /* - * Flush the context bank after modifying ACTLR to ensure there - * are no cache entries with stale state - */ - tlb->tlb_flush_all(smmu_domain); } static int qsmmuv500_tbu_register(struct device *dev, void *cookie) -- GitLab From 32c8278d63ddb2c191817a182114267a53105533 Mon Sep 17 00:00:00 2001 From: Rupesh Tatiya Date: Wed, 28 Mar 2018 17:13:14 +0530 Subject: [PATCH 1573/1834] ARM: dts: msm: update bluetooth device node for qcs605 lc variant - Updated the regulators powering the BT module. - Enable UART for sdm670 Change-Id: I05a810fb7a74e123ec6d47d004795d9ccc134106 Signed-off-by: Rupesh Tatiya Signed-off-by: Bandari Ramesh Signed-off-by: Bikshapathi Kothapeta --- arch/arm64/boot/dts/qcom/qcs605-lc.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi index 15b23ded8c18..f8dde3965b88 100644 --- a/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605-lc.dtsi @@ -369,3 +369,13 @@ &int_codec { /delete-property/ qcom,ext-disp-audio-rx; }; + +&bluetooth { + qca,bt-vdd-core-supply = <&pm660_l9>; + qca,bt-vdd-pa-supply = <&pm660_l3>; + /delete-property/ qca,bt-vdd-ldo-supply; +}; + +&qupv3_se6_4uart { + status = "ok"; +}; -- GitLab From 844aa17b84905ea781266eac38413ade8446a26f Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Thu, 25 Jan 2018 01:12:08 +0530 Subject: [PATCH 1574/1834] sched/walt: improve the scheduler This change is for general scheduler improvement. Change-Id: I03c9e0c333c139ef848c4c2143606c6fe0335a7d Signed-off-by: Pavankumar Kondeti --- kernel/sched/walt.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index a9fb3678fdb1..80342cd51786 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -847,8 +847,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) if (p == src_rq->ed_task) { src_rq->ed_task = NULL; - if (!dest_rq->ed_task) - dest_rq->ed_task = p; + dest_rq->ed_task = p; } done: -- GitLab From a230edb87279938eae106c69a7b0ca776d6789cd Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Wed, 25 Apr 2018 15:44:40 +0530 Subject: [PATCH 1575/1834] ARM: dts: msm: Add BAM_DMUX nodes for msm8909w Add the BAM_DMUX nodes for RMNET support on msm8909w. Change-Id: I85cd5ffe87b628607ac5cab3fa559c7a8a34287f Signed-off-by: Sundara Vinayagam --- arch/arm64/boot/dts/qcom/msm8909.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi index 90a4c8336e0d..a6d42f1c6ec8 100644 --- a/arch/arm64/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi @@ -700,6 +700,16 @@ rpm-channel-type = <15>; /* SMD_APPS_RPM */ }; + qcom,bam_dmux@4044000 { + compatible = "qcom,bam_dmux"; + reg = <0x4044000 0x19000>; + interrupts = <0 29 1>; + qcom,rx-ring-size = <32>; + qcom,max-rx-mtu = <4096>; + qcom,fast-shutdown; + qcom,no-cpu-affinity; + }; + qcom,smdtty { compatible = "qcom,smdtty"; -- GitLab From 65c40e534a0e56f6726541ff594bd83c41e3f427 Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Mon, 30 Apr 2018 20:43:46 +0530 Subject: [PATCH 1576/1834] ARM: dts: msm: Add quiet_therm based thermal zone config for SDM439 Add quiet_therm based thermal zone rule for SDM439 QRD platform. It includes cpu mitigation, gpu mitigation and charger mitigation. SDM439 QRD thermal zone rules will be the default thermal zone rules for SDM439. Disable quiet_therm based thermal zone rule for SDM439 MTP platform. Change-Id: I882174253d122fd2e556d0bc1a26895fd4e228b0 Signed-off-by: Manaf Meethalavalappu Pallikunhi --- .../dts/qcom/msm8937-interposer-sdm429.dtsi | 9 +++ arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi | 7 ++ arch/arm64/boot/dts/qcom/sdm429.dtsi | 9 +++ arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi | 79 +++++++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi index 5ae93333d054..885d8b609e6e 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi @@ -55,4 +55,13 @@ }; /delete-node/ cpuss0-step; + + quiet-therm-step { + cooling-maps { + /delete-node/ skin_cpu4; + /delete-node/ skin_cpu5; + /delete-node/ skin_cpu6; + /delete-node/ skin_cpu7; + }; + }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi index 42f1b5c5b472..57823b8c48f4 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-mtp.dtsi @@ -152,5 +152,12 @@ linux,can-disable; gpio-key,wakeup; }; + + }; +}; + +&thermal_zones { + quiet-therm-step { + status = "disabled"; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 33b352d8f922..1c1c5bed029b 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -107,6 +107,15 @@ }; /delete-node/ cpuss0-step; + + quiet-therm-step { + cooling-maps { + /delete-node/ skin_cpu4; + /delete-node/ skin_cpu5; + /delete-node/ skin_cpu6; + /delete-node/ skin_cpu7; + }; + }; }; &clock_gcc { diff --git a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi index 300c83aebf03..bc2ba9f04d17 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-pmi632.dtsi @@ -105,4 +105,83 @@ }; }; }; + + quiet-therm-step { + polling-delay-passive = <1000>; + polling-delay = <0>; + thermal-sensors = <&pmi632_adc_tm 0x53>; + thermal-governor = "step_wise"; + + trips { + batt_trip1: batt-trip1 { + temperature = <41000>; + hysteresis = <2000>; + type = "passive"; + }; + cpus_trip: cpus-trip { + temperature = <44000>; + hysteresis = <0>; + type = "passive"; + }; + batt_trip2: batt-trip2 { + temperature = <45000>; + hysteresis = <4000>; + type = "passive"; + }; + gpu_trip: gpu-trip { + temperature = <50000>; + hysteresis = <0>; + type = "passive"; + }; + }; + + cooling-maps { + skin_cpu0 { + trip = <&cpus_trip>; + /* throttle from fmax to 1094400KHz */ + cooling-device = <&CPU0 THERMAL_NO_LIMIT 5>; + }; + skin_cpu1 { + trip = <&cpus_trip>; + cooling-device = <&CPU1 THERMAL_NO_LIMIT 5>; + }; + skin_cpu2 { + trip = <&cpus_trip>; + cooling-device = <&CPU2 THERMAL_NO_LIMIT 5>; + }; + skin_cpu3 { + trip = <&cpus_trip>; + cooling-device = <&CPU3 THERMAL_NO_LIMIT 5>; + }; + skin_cpu4 { + trip = <&cpus_trip>; + cooling-device = <&CPU4 THERMAL_NO_LIMIT 3>; + }; + skin_cpu5 { + trip = <&cpus_trip>; + cooling-device = <&CPU5 THERMAL_NO_LIMIT 3>; + }; + skin_cpu6 { + trip = <&cpus_trip>; + cooling-device = <&CPU6 THERMAL_NO_LIMIT 3>; + }; + skin_cpu7 { + trip = <&cpus_trip>; + cooling-device = <&CPU7 THERMAL_NO_LIMIT 3>; + }; + skin_gpu { + trip = <&gpu_trip>; + /* throttle from fmax to 375000000Hz */ + cooling-device = <&msm_gpu THERMAL_NO_LIMIT 2>; + }; + battery_lvl1 { + trip = <&batt_trip1>; + cooling-device = <&pmi632_charger 4 4>; + }; + battery_lvl2 { + trip = <&batt_trip2>; + cooling-device = <&pmi632_charger 5 5>; + }; + }; + }; }; -- GitLab From 34f65226a24c41366b17b8a124d3c69097220738 Mon Sep 17 00:00:00 2001 From: Narender Ankam Date: Mon, 30 Apr 2018 18:11:34 +0530 Subject: [PATCH 1577/1834] drm/msm/dp: set bpp and cc values correctly DP_MISC1_MISC0 register was retaining its previous bit_depth and colorimetry values. Set only current values of bit_depth and cc values. Change-Id: I806ae2bd4b7e615d02286c9d00226537656d26f4 Signed-off-by: Narender Ankam --- drivers/gpu/drm/msm/dp/dp_catalog.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c index 5e73dfac1e75..bfe98b505cf6 100644 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ b/drivers/gpu/drm/msm/dp/dp_catalog.c @@ -772,8 +772,6 @@ static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl, catalog = dp_catalog_get_priv(ctrl); io_data = catalog->io.dp_link; - misc_val = dp_read(catalog, io_data, DP_MISC1_MISC0); - misc_val |= cc; misc_val |= (tb << 5); misc_val |= BIT(0); /* Configure clock to synchronous mode */ -- GitLab From 67cf1dc75238c963ce8a31291e92b7ca4b7c5d34 Mon Sep 17 00:00:00 2001 From: Jingbiao Lu Date: Fri, 13 Apr 2018 14:58:10 +0800 Subject: [PATCH 1578/1834] ARM: dts: msm: update cpuss_dump for sdm429 sdm429 have quad core, so update cpuss_dump for sdm429. Change-Id: I721fd54ee823e2ff4469e1824dd1beca7830e408 Signed-off-by: Jingbiao Lu --- arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi index ab874c9d94db..80aeb246181a 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi @@ -156,5 +156,15 @@ }; &soc { - /delete-node/ cpuss_dump; + cpuss_dump { + /delete-node/ qcom,l2_dump0; + /delete-node/ qcom,l1_i_cache0; + /delete-node/ qcom,l1_i_cache1; + /delete-node/ qcom,l1_i_cache2; + /delete-node/ qcom,l1_i_cache3; + /delete-node/ qcom,l1_d_cache0; + /delete-node/ qcom,l1_d_cache1; + /delete-node/ qcom,l1_d_cache2; + /delete-node/ qcom,l1_d_cache3; + }; }; -- GitLab From 6433428ce1e49f7d1cfcba57fa1f31cfaf3e1109 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Wed, 25 Apr 2018 16:01:44 +0530 Subject: [PATCH 1579/1834] defconfig: Enable support of RMNET for msm8909w Enable RMNET support for msm8909w target. Change-Id: I72b3ea38723c6fbabb68281e759f9260bdd0db3e Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909w-perf_defconfig | 4 ++++ arch/arm/configs/msm8909w_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index c4f7cfa5728c..0e3a3ec7feff 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -361,6 +361,7 @@ CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_ACM=y CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_EEM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y @@ -400,10 +401,13 @@ CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_REVID=y CONFIG_USB_BAM=y +CONFIG_MSM_RMNET_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index 3fdcc91d48ec..bb6bc88e548f 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -366,6 +366,7 @@ CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_ACM=y CONFIG_USB_CONFIGFS_NCM=y CONFIG_USB_CONFIGFS_ECM=y +CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_EEM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y @@ -405,10 +406,13 @@ CONFIG_ASHMEM=y CONFIG_ANDROID_LOW_MEMORY_KILLER=y CONFIG_ION=y CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RMNET_IPA=y CONFIG_SPS=y CONFIG_SPS_SUPPORT_NDP_BAM=y CONFIG_QPNP_REVID=y CONFIG_USB_BAM=y +CONFIG_MSM_RMNET_BAM=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y -- GitLab From 7bea04c2cbf09ce4d29c068b11593022a1cb1a47 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Tue, 9 Aug 2016 15:17:56 +0530 Subject: [PATCH 1580/1834] power: qpnp-smbcharger: add voting logic for enabling/disabling HVDCP HVDCP can be enabled from multiple location in the charger driver. Update HVDCP enable/disable logic to use voting mechanism. Also optimize shutdown() hook and Fix ICL voting on USB removal, update usb status after APSD re-reun, release hvdcp wakelock when usb removed and enable parallel charger only if charger is present. CRs-Fixed: 1050520 Change-Id: Ifa42d0d13a10ce803d5ce19e59659d56d0c92f43 Signed-off-by: Ashay Jaiswal Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/qpnp-smbcharger.c | 95 +++++++++++++++------ 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index 59478a9c08f0..699ba7d5ac88 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -287,7 +287,7 @@ struct smbchg_chip { struct votable *hw_aicl_rerun_disable_votable; struct votable *hw_aicl_rerun_enable_indirect_votable; struct votable *aicl_deglitch_short_votable; - + struct votable *hvdcp_enable_votable; /* extcon for VBUS / ID notification to USB */ struct extcon_dev *extcon; }; @@ -413,6 +413,10 @@ enum wake_reason { "VARB_WRKARND_SHORT_DEGLITCH_VOTER" /* QC 2.0 */ #define HVDCP_SHORT_DEGLITCH_VOTER "HVDCP_SHORT_DEGLITCH_VOTER" +/* Hvdcp enable voters*/ +#define HVDCP_PMIC_VOTER "HVDCP_PMIC_VOTER" +#define HVDCP_OTG_VOTER "HVDCP_OTG_VOTER" +#define HVDCP_PULSING_VOTER "HVDCP_PULSING_VOTER" static const unsigned int smbchg_extcon_cable[] = { EXTCON_USB, @@ -2435,6 +2439,27 @@ static int dc_suspend_vote_cb(struct votable *votable, return rc; } +#define HVDCP_EN_BIT BIT(3) +static int smbchg_hvdcp_enable_cb(struct votable *votable, + void *data, + int enable, + const char *client) +{ + int rc = 0; + struct smbchg_chip *chip = data; + + pr_err("smbchg_hvdcp_enable_cb HVDCP %s\n", + enable ? "enabled" : "disabled"); + rc = smbchg_sec_masked_write(chip, + chip->usb_chgpth_base + CHGPTH_CFG, + HVDCP_EN_BIT, enable ? HVDCP_EN_BIT : 0); + if (rc < 0) + dev_err(chip->dev, "Couldn't %s HVDCP rc=%d\n", + enable ? "enable" : "disable", rc); + + return rc; +} + static int set_fastchg_current_vote_cb(struct votable *votable, void *data, int fcc_ma, @@ -3795,7 +3820,6 @@ struct regulator_ops smbchg_otg_reg_ops = { #define USBIN_ADAPTER_9V 0x3 #define USBIN_ADAPTER_5V_9V_CONT 0x2 #define USBIN_ADAPTER_5V_UNREGULATED_9V 0x5 -#define HVDCP_EN_BIT BIT(3) static int smbchg_external_otg_regulator_enable(struct regulator_dev *rdev) { int rc = 0; @@ -3819,9 +3843,7 @@ static int smbchg_external_otg_regulator_enable(struct regulator_dev *rdev) * allowance to 9V, so that the audio boost operating in reverse never * gets detected as a valid input */ - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, 0); + rc = vote(chip->hvdcp_enable_votable, HVDCP_OTG_VOTER, true, 0); if (rc < 0) { dev_err(chip->dev, "Couldn't disable HVDCP rc=%d\n", rc); return rc; @@ -3855,9 +3877,7 @@ static int smbchg_external_otg_regulator_disable(struct regulator_dev *rdev) * value in order to allow normal USBs to be recognized as a valid * input. */ - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, HVDCP_EN_BIT); + rc = vote(chip->hvdcp_enable_votable, HVDCP_OTG_VOTER, false, 1); if (rc < 0) { dev_err(chip->dev, "Couldn't enable HVDCP rc=%d\n", rc); return rc; @@ -4435,10 +4455,13 @@ static int smbchg_change_usb_supply_type(struct smbchg_chip *chip, goto out; } - /* otherwise if it is unknown, set type after the vote */ - if (type == POWER_SUPPLY_TYPE_UNKNOWN) + /* otherwise if it is unknown, set type after removing the vote */ + if (type == POWER_SUPPLY_TYPE_UNKNOWN) { + rc = vote(chip->usb_icl_votable, PSY_ICL_VOTER, true, 0); + if (rc < 0) + pr_err("Couldn't vote for new USB ICL rc=%d\n", rc); chip->usb_supply_type = type; - + } /* * Update TYPE property to DCP for HVDCP/HVDCP3 charger types * so that they can be recongized as AC chargers by healthd. @@ -4577,9 +4600,7 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) pr_err("Couldn't configure HVDCP 9V rc=%d\n", rc); /* enable HVDCP */ - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, HVDCP_EN_BIT); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, false, 1); if (rc < 0) pr_err("Couldn't enable HVDCP rc=%d\n", rc); @@ -4647,6 +4668,7 @@ static void handle_usb_removal(struct smbchg_chip *chip) chip->typec_current_ma = 0; /* cancel/wait for hvdcp pending work if any */ cancel_delayed_work_sync(&chip->hvdcp_det_work); + smbchg_relax(chip, PM_DETECT_HVDCP); smbchg_change_usb_supply_type(chip, POWER_SUPPLY_TYPE_UNKNOWN); extcon_set_cable_state_(chip->extcon, EXTCON_USB, chip->usb_present); if (chip->dpdm_reg) @@ -5118,8 +5140,7 @@ static int smbchg_prepare_for_pulsing(struct smbchg_chip *chip) /* disable HVDCP */ pr_smb(PR_MISC, "Disable HVDCP\n"); - rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, 0); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, true, 0); if (rc < 0) { pr_err("Couldn't disable HVDCP rc=%d\n", rc); goto out; @@ -5228,9 +5249,7 @@ static int smbchg_unprepare_for_pulsing(struct smbchg_chip *chip) /* enable HVDCP */ pr_smb(PR_MISC, "Enable HVDCP\n"); - rc = smbchg_sec_masked_write(chip, - chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, HVDCP_EN_BIT); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PULSING_VOTER, false, 1); if (rc < 0) { pr_err("Couldn't enable HVDCP rc=%d\n", rc); return rc; @@ -6250,7 +6269,8 @@ static irqreturn_t fastchg_handler(int irq, void *_chip) struct smbchg_chip *chip = _chip; pr_smb(PR_INTERRUPT, "p2f triggered\n"); - smbchg_parallel_usb_check_ok(chip); + if (is_usb_present(chip) || is_dc_present(chip)) + smbchg_parallel_usb_check_ok(chip); if (chip->batt_psy) power_supply_changed(chip->batt_psy); smbchg_charging_status_change(chip); @@ -6863,7 +6883,22 @@ static int smbchg_hw_init(struct smbchg_chip *chip) chip->revision[ANA_MAJOR], chip->revision[ANA_MINOR]); /* Setup 9V HVDCP */ - if (!chip->hvdcp_not_supported) { + if (chip->hvdcp_not_supported) { + rc = vote(chip->hvdcp_enable_votable, HVDCP_PMIC_VOTER, + true, 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't disable HVDCP rc=%d\n", + rc); + return rc; + } + } else { + rc = vote(chip->hvdcp_enable_votable, HVDCP_PMIC_VOTER, + true, 1); + if (rc < 0) { + dev_err(chip->dev, "Couldn't enable HVDCP rc=%d\n", + rc); + return rc; + } rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_9V); @@ -8211,6 +8246,15 @@ static int smbchg_probe(struct platform_device *pdev) goto votables_cleanup; } + chip->hvdcp_enable_votable = create_votable( + "HVDCP_ENABLE", + VOTE_MIN, + smbchg_hvdcp_enable_cb, chip); + if (IS_ERR(chip->hvdcp_enable_votable)) { + rc = PTR_ERR(chip->hvdcp_enable_votable); + goto votables_cleanup; + } + INIT_WORK(&chip->usb_set_online_work, smbchg_usb_update_online_work); INIT_DELAYED_WORK(&chip->parallel_en_work, smbchg_parallel_usb_en_work); @@ -8397,6 +8441,7 @@ static int smbchg_probe(struct platform_device *pdev) rerun_hvdcp_det_if_necessary(chip); + update_usb_status(chip, is_usb_present(chip), false); dump_regs(chip); create_debugfs_entries(chip); dev_info(chip->dev, @@ -8493,11 +8538,9 @@ static void smbchg_shutdown(struct platform_device *pdev) disable_irq(chip->otg_oc_irq); disable_irq(chip->power_ok_irq); disable_irq(chip->recharge_irq); - disable_irq(chip->src_detect_irq); disable_irq(chip->taper_irq); disable_irq(chip->usbid_change_irq); disable_irq(chip->usbin_ov_irq); - disable_irq(chip->usbin_uv_irq); disable_irq(chip->vbat_low_irq); disable_irq(chip->wdog_timeout_irq); @@ -8540,8 +8583,7 @@ static void smbchg_shutdown(struct platform_device *pdev) /* disable HVDCP */ pr_smb(PR_MISC, "Disable HVDCP\n"); - rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, - HVDCP_EN_BIT, 0); + rc = vote(chip->hvdcp_enable_votable, HVDCP_PMIC_VOTER, true, 0); if (rc < 0) pr_err("Couldn't disable HVDCP rc=%d\n", rc); @@ -8558,6 +8600,9 @@ static void smbchg_shutdown(struct platform_device *pdev) if (rc < 0) pr_err("Couldn't fake insertion rc=%d\n", rc); + disable_irq(chip->src_detect_irq); + disable_irq(chip->usbin_uv_irq); + pr_smb(PR_MISC, "Wait 1S to settle\n"); msleep(1000); chip->hvdcp_3_det_ignore_uv = false; -- GitLab From 23765c4835580ccf5f9380cf2af4f9e05b76b3f4 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 4 Apr 2016 16:13:50 -0700 Subject: [PATCH 1581/1834] power: qpnp-smbcharger: fix usage of un-initialized variable Initialize variables to valid values before using them in charger drivers. Also Enable SMBCHG restart workaround for PMI8950. CRs-Fixed: 996609 Change-Id: I3a9f2ef71b657b3926ccd2325585c9b2a4edead9 Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/qpnp-smbcharger.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index 699ba7d5ac88..65ade2f40a60 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -8020,6 +8020,7 @@ static int smbchg_check_chg_version(struct smbchg_chip *chip) chip->schg_version = QPNP_SCHG; break; case PMI8950: + chip->wa_flags |= SMBCHG_RESTART_WA; case PMI8937: chip->wa_flags |= SMBCHG_BATT_OV_WA; if (pmic_rev_id->rev4 < 2) /* PMI8950 1.0 */ { @@ -8112,7 +8113,7 @@ static int smbchg_probe(struct platform_device *pdev) int rc; struct smbchg_chip *chip; struct power_supply *typec_psy = NULL; - struct qpnp_vadc_chip *vadc_dev, *vchg_vadc_dev; + struct qpnp_vadc_chip *vadc_dev = NULL, *vchg_vadc_dev = NULL; const char *typec_psy_name; struct power_supply_config usb_psy_cfg = {}; struct power_supply_config batt_psy_cfg = {}; -- GitLab From 7af26138e1e26d1e2058f3f19e108ed3659e295b Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Mon, 1 Feb 2016 18:45:28 +0530 Subject: [PATCH 1582/1834] power: qpnp-smbcharger: re-arrange parallel charger detection check In scenarios where fast-charge/taper interrupt fires even before src_detect_handler detects the parallel charger, parallel charging will remain disabled. Fix this by adding a parallel charger detection check in fastcharge and taper handler. Also Force input current limit to 300mA during QC3.0 DP/DM pulsing for PMI8950. CRs-Fixed: 984187 Change-Id: I082cad6cf1bc3e8d9a5c327222f72d046190f9ca Signed-off-by: Ashay Jaiswal Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/qpnp-smbcharger.c | 65 +++++++++++++-------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index 65ade2f40a60..6a29d23e5183 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -1883,6 +1883,22 @@ static bool smbchg_is_usbin_active_pwr_src(struct smbchg_chip *chip) && (reg & USBIN_ACTIVE_PWR_SRC_BIT); } +static void smbchg_detect_parallel_charger(struct smbchg_chip *chip) +{ + int rc; + struct power_supply *parallel_psy = get_parallel_psy(chip); + union power_supply_propval pval = {0, }; + + if (parallel_psy) { + pval.intval = true; + rc = power_supply_set_property(parallel_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + chip->parallel_charger_detected = rc ? false : true; + if (rc) + pr_debug("parallel-charger absent rc=%d\n", rc); + } +} + static int smbchg_parallel_usb_charging_en(struct smbchg_chip *chip, bool en) { struct power_supply *parallel_psy = get_parallel_psy(chip); @@ -2020,7 +2036,8 @@ static void smbchg_parallel_usb_taper(struct smbchg_chip *chip) int parallel_fcc_ma, tries = 0; u8 reg = 0; - if (!parallel_psy || !chip->parallel_charger_detected) + smbchg_detect_parallel_charger(chip); + if (!chip->parallel_charger_detected) return; smbchg_stay_awake(chip, PM_PARALLEL_TAPER); @@ -4588,11 +4605,6 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) { int rc; - pr_smb(PR_MISC, "Retracting HVDCP vote for ICL\n"); - rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, false, 0); - if (rc < 0) - pr_err("Couldn't retract HVDCP ICL vote rc=%d\n", rc); - /* switch to 9V HVDCP */ rc = smbchg_sec_masked_write(chip, chip->usb_chgpth_base + CHGPTH_CFG, HVDCP_ADAPTER_SEL_MASK, HVDCP_9V); @@ -4625,6 +4637,19 @@ static void restore_from_hvdcp_detection(struct smbchg_chip *chip) chip->hvdcp_3_det_ignore_uv = false; chip->pulse_cnt = 0; + + if ((chip->schg_version == QPNP_SCHG_LITE) + && is_hvdcp_present(chip)) { + pr_smb(PR_MISC, "Forcing 9V HVDCP 2.0\n"); + rc = force_9v_hvdcp(chip); + if (rc) + pr_err("Failed to force 9V HVDCP=%d\n", rc); + } + + pr_smb(PR_MISC, "Retracting HVDCP vote for ICL\n"); + rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, false, 0); + if (rc < 0) + pr_err("Couldn't retract HVDCP ICL vote rc=%d\n", rc); } #define RESTRICTED_CHG_FCC_PERCENT 50 @@ -4721,8 +4746,6 @@ static bool is_usbin_uv_high(struct smbchg_chip *chip) #define HVDCP_NOTIFY_MS 2500 static void handle_usb_insertion(struct smbchg_chip *chip) { - struct power_supply *parallel_psy = get_parallel_psy(chip); - union power_supply_propval pval = {0, }; enum power_supply_type usb_supply_type; int rc; char *usb_type_name = "null"; @@ -4769,14 +4792,7 @@ static void handle_usb_insertion(struct smbchg_chip *chip) msecs_to_jiffies(HVDCP_NOTIFY_MS)); } - if (parallel_psy) { - pval.intval = true; - rc = power_supply_set_property(parallel_psy, - POWER_SUPPLY_PROP_PRESENT, &pval); - chip->parallel_charger_detected = rc ? false : true; - if (rc) - pr_debug("parallel-charger absent rc=%d\n", rc); - } + smbchg_detect_parallel_charger(chip); if (chip->parallel.avail && chip->aicl_done_irq && !chip->enable_aicl_wake) { @@ -5436,6 +5452,12 @@ static int smbchg_prepare_for_pulsing_lite(struct smbchg_chip *chip) { int rc = 0; + pr_smb(PR_MISC, "HVDCP voting for 300mA ICL\n"); + rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, true, 300); + if (rc < 0) { + pr_err("Couldn't vote for 300mA HVDCP ICL rc=%d\n", rc); + return rc; + } /* check if HVDCP is already in 5V continuous mode */ if (is_hvdcp_5v_cont_mode(chip)) { pr_smb(PR_MISC, "HVDCP by default is in 5V continuous mode\n"); @@ -5462,13 +5484,6 @@ static int smbchg_prepare_for_pulsing_lite(struct smbchg_chip *chip) goto out; } - pr_smb(PR_MISC, "HVDCP voting for 300mA ICL\n"); - rc = vote(chip->usb_icl_votable, HVDCP_ICL_VOTER, true, 300); - if (rc < 0) { - pr_err("Couldn't vote for 300mA HVDCP ICL rc=%d\n", rc); - goto out; - } - pr_smb(PR_MISC, "Disable AICL\n"); smbchg_sec_masked_write(chip, chip->usb_chgpth_base + USB_AICL_CFG, AICL_EN_BIT, 0); @@ -6269,8 +6284,10 @@ static irqreturn_t fastchg_handler(int irq, void *_chip) struct smbchg_chip *chip = _chip; pr_smb(PR_INTERRUPT, "p2f triggered\n"); - if (is_usb_present(chip) || is_dc_present(chip)) + if (is_usb_present(chip) || is_dc_present(chip)) { + smbchg_detect_parallel_charger(chip); smbchg_parallel_usb_check_ok(chip); + } if (chip->batt_psy) power_supply_changed(chip->batt_psy); smbchg_charging_status_change(chip); -- GitLab From a5361ab005dd5e2167cea83c2a5cdb687fb54d41 Mon Sep 17 00:00:00 2001 From: Amir Levy Date: Tue, 1 May 2018 13:25:37 +0300 Subject: [PATCH 1583/1834] msm: ipa4: add IOCTL for reading vlan mode Add IOCTL for reading LAN interfaces VLAN mode from user space. Change-Id: I85634b21adf2b1b79feb1b282597289e89ad1df1 Signed-off-by: Amir Levy --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 24 ++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 2 +- include/linux/ipa.h | 13 ---------- include/uapi/linux/msm_ipa.h | 27 +++++++++++++++++++++ 5 files changed, 53 insertions(+), 14 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 0fc7b0eabf01..af926fb9498f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -737,6 +737,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) u32 pyld_sz; u8 header[128] = { 0 }; u8 *param = NULL; + bool is_vlan_mode; struct ipa_ioc_nat_alloc_mem nat_mem; struct ipa_ioc_nat_ipv6ct_table_alloc table_alloc; struct ipa_ioc_v4_nat_init nat_init; @@ -746,6 +747,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ipa_ioc_nat_pdn_entry mdfy_pdn; struct ipa_ioc_rm_dependency rm_depend; struct ipa_ioc_nat_dma_cmd *table_dma_cmd; + struct ipa_ioc_get_vlan_mode vlan_mode; size_t sz; int pre_entry; @@ -1843,6 +1845,28 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; + case IPA_IOC_GET_VLAN_MODE: + if (copy_from_user(&vlan_mode, (const void __user *)arg, + sizeof(struct ipa_ioc_get_vlan_mode))) { + retval = -EFAULT; + break; + } + retval = ipa3_is_vlan_mode( + vlan_mode.iface, + &is_vlan_mode); + if (retval) + break; + + vlan_mode.is_vlan_mode = is_vlan_mode; + + if (copy_to_user((void __user *)arg, + &vlan_mode, + sizeof(struct ipa_ioc_get_vlan_mode))) { + retval = -EFAULT; + break; + } + break; + case IPA_IOC_ADD_VLAN_IFACE: if (ipa3_send_vlan_l2tp_msg(arg, ADD_VLAN_IFACE)) { retval = -EFAULT; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 50c1e3feb75e..56b5740da501 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -2380,4 +2380,5 @@ void __ipa_gsi_irq_rx_scedule_poll(struct ipa3_sys_context *sys); int ipa3_tz_unlock_reg(struct ipa_tz_unlock_reg_info *reg_info, u16 num_regs); void ipa3_init_imm_cmd_desc(struct ipa3_desc *desc, struct ipahal_imm_cmd_pyld *cmd_pyld); +int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res); #endif /* _IPA3_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 80155f9e2060..861a783360f6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -4326,7 +4326,7 @@ static void ipa3_set_tag_process_before_gating(bool val) * * Returns: 0 on success, negative on failure */ -static int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res) +int ipa3_is_vlan_mode(enum ipa_vlan_ifaces iface, bool *res) { if (!res) { IPAERR("NULL out param\n"); diff --git a/include/linux/ipa.h b/include/linux/ipa.h index f966e0c0d946..1a1c68e3a44e 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -116,19 +116,6 @@ enum hdr_total_len_or_pad_type { IPA_HDR_TOTAL_LEN = 1, }; -/** -* enum ipa_vlan_ifaces - vlan interfaces types -* @IPA_VLAN_IF_EMAC: used for EMAC ethernet device -* @IPA_VLAN_IF_RNDIS: used for RNDIS USB device -* @IPA_VLAN_IF_ECM: used for ECM USB device -*/ -enum ipa_vlan_ifaces { - IPA_VLAN_IF_EMAC, - IPA_VLAN_IF_RNDIS, - IPA_VLAN_IF_ECM, - IPA_VLAN_IF_MAX -}; - /** * struct ipa_ep_cfg_nat - NAT configuration in IPA end-point * @nat_en: This defines the default NAT mode for the pipe: in case of diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 062a1b9c3e99..1c39dafa68d4 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -97,6 +97,7 @@ #define IPA_IOCTL_DEL_IPV6CT_TABLE 55 #define IPA_IOCTL_CLEANUP 56 #define IPA_IOCTL_QUERY_WLAN_CLIENT 57 +#define IPA_IOCTL_GET_VLAN_MODE 58 /** * max size of the header to be inserted @@ -1847,6 +1848,29 @@ struct ipa_tether_device_info { struct ipa_lan_client lan_client[IPA_MAX_NUM_HW_PATH_CLIENTS]; }; +/** + * enum ipa_vlan_ifaces - vlan interfaces types + */ +enum ipa_vlan_ifaces { + IPA_VLAN_IF_ETH, + IPA_VLAN_IF_RNDIS, + IPA_VLAN_IF_ECM +}; + +#define IPA_VLAN_IF_EMAC IPA_VLAN_IF_ETH +#define IPA_VLAN_IF_MAX (IPA_VLAN_IF_ECM + 1) + +/** + * struct ipa_get_vlan_mode - get vlan mode of a Lan interface + * @iface: Lan interface type to be queried. + * @is_vlan_mode: output parameter, is interface in vlan mode, valid only when + * ioctl return val is non-negative + */ +struct ipa_ioc_get_vlan_mode { + enum ipa_vlan_ifaces iface; + uint32_t is_vlan_mode; +}; + /** * actual IOCTLs supported by IPA driver */ @@ -2029,6 +2053,9 @@ struct ipa_tether_device_info { IPA_IOCTL_CLEANUP) #define IPA_IOC_QUERY_WLAN_CLIENT _IO(IPA_IOC_MAGIC,\ IPA_IOCTL_QUERY_WLAN_CLIENT) +#define IPA_IOC_GET_VLAN_MODE _IOWR(IPA_IOC_MAGIC, \ + IPA_IOCTL_GET_VLAN_MODE, \ + struct ipa_ioc_get_vlan_mode *) /* * unique magic number of the Tethering bridge ioctls */ -- GitLab From a61fac4e9cd7e646d221d30b740ca8c84fb361c0 Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Fri, 27 Apr 2018 17:02:16 +0530 Subject: [PATCH 1584/1834] defconfig: Enable CONFIG_NETFILTER_XT_MATCH_BPF Enable bpf match support for targets with kernel 4.9 and above so that iptable command from netd (userspace module) with -m bpf doesn't fail. CRs-Fixed: 2228931 Change-Id: Ia8fd39e33bfffaeae6121d6a66658cdbd5a76430 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/msm8953-perf_defconfig | 1 + arch/arm64/configs/msm8953_defconfig | 1 + arch/arm64/configs/sdm670-perf_defconfig | 1 + arch/arm64/configs/sdm670_defconfig | 1 + arch/arm64/configs/sdm845-perf_defconfig | 1 + arch/arm64/configs/sdm845_defconfig | 1 + 6 files changed, 6 insertions(+) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index 46b34b30c470..e903be297dd5 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -147,6 +147,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index dc58fc369cd9..e1df4c0ab6d8 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -151,6 +151,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index f82678ed7691..d75fd140c7ca 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -146,6 +146,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index ee3418bd8c5f..447ad5dd07c5 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -151,6 +151,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index f5dc2a8f4043..bf4c78afacbb 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -145,6 +145,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index 8dc560d8d0ea..1f8427b98b67 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -148,6 +148,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -- GitLab From b38d329c2732be94ad1f345c12449fae3a2e3ab9 Mon Sep 17 00:00:00 2001 From: Gopikrishnaiah Anandan Date: Wed, 28 Feb 2018 19:25:15 -0800 Subject: [PATCH 1585/1834] drm/msm/sde: decouple early mapping of display splash buffer Currently in display driver splash buffer is allocated after resource manager is initialized. LUT dma block should be initialized before the resource manager init so that dspp/sspp blocks can use the AXI path for lut programming. Change-Id: I1ecb69379988148068daf68adab1f227050c9879 Signed-off-by: Gopikrishnaiah Anandan Signed-off-by: Dhaval Patel --- drivers/gpu/drm/msm/sde/sde_hw_mdss.h | 5 +- drivers/gpu/drm/msm/sde/sde_kms.c | 129 +++++++++++++++----------- 2 files changed, 76 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h index 8022f2340481..9b4e03d65098 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_mdss.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_mdss.h @@ -570,7 +570,8 @@ struct ctl_top { /** * struct sde_splash_data - Struct contains details of continuous splash * memory region and initial pipeline configuration. - * @smmu_handoff_pending:boolean to notify handoff from splash memory to smmu + * @resource_handoff_pending: boolean to notify boot up resource handoff + * is pending. * @splash_base: Base address of continuous splash region reserved * by bootloader * @splash_size: Size of continuous splash region @@ -585,7 +586,7 @@ struct ctl_top { * @single_flush_en: Stores if the single flush is enabled. */ struct sde_splash_data { - bool smmu_handoff_pending; + bool resource_handoff_pending; unsigned long splash_base; u32 splash_size; struct ctl_top top[CTL_MAX - CTL_0]; diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index 33bdec9fa86f..c7e6bc587bdf 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -936,9 +936,6 @@ static void sde_kms_prepare_commit(struct msm_kms *kms, } } - if (sde_kms->splash_data.smmu_handoff_pending) - sde_kms->splash_data.smmu_handoff_pending = false; - /* * NOTE: for secure use cases we want to apply the new HW * configuration only after completing preparation for secure @@ -972,6 +969,62 @@ static void sde_kms_commit(struct msm_kms *kms, } } +static void _sde_kms_release_splash_resource(struct sde_kms *sde_kms, + struct drm_atomic_state *old_state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + bool primary_crtc_active = false; + struct msm_drm_private *priv; + int i, rc = 0; + + priv = sde_kms->dev->dev_private; + + if (!sde_kms->splash_data.resource_handoff_pending) + return; + + SDE_EVT32(SDE_EVTLOG_FUNC_CASE1); + for_each_crtc_in_state(old_state, crtc, crtc_state, i) { + if (crtc->state->active) + primary_crtc_active = true; + SDE_EVT32(crtc->base.id, crtc->state->active); + } + + if (!primary_crtc_active) { + SDE_EVT32(SDE_EVTLOG_FUNC_CASE2); + return; + } + + sde_kms->splash_data.resource_handoff_pending = false; + + if (sde_kms->splash_data.cont_splash_en) { + SDE_DEBUG("disabling cont_splash feature\n"); + sde_kms->splash_data.cont_splash_en = false; + + for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) + sde_power_data_bus_set_quota(&priv->phandle, + sde_kms->core_client, + SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, i, + SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, + SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + + sde_power_resource_enable(&priv->phandle, sde_kms->core_client, + false); + } + + if (sde_kms->splash_data.splash_base) { + _sde_kms_splash_smmu_unmap(sde_kms); + + rc = _sde_kms_release_splash_buffer( + sde_kms->splash_data.splash_base, + sde_kms->splash_data.splash_size); + if (rc) + pr_err("failed to release splash memory\n"); + sde_kms->splash_data.splash_base = 0; + sde_kms->splash_data.splash_size = 0; + } +} + static void sde_kms_complete_commit(struct msm_kms *kms, struct drm_atomic_state *old_state) { @@ -1019,39 +1072,9 @@ static void sde_kms_complete_commit(struct msm_kms *kms, sde_power_resource_enable(&priv->phandle, sde_kms->core_client, false); - SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT); - - if (sde_kms->splash_data.cont_splash_en) { - /* Releasing splash resources as we have first frame update */ - rc = _sde_kms_splash_smmu_unmap(sde_kms); - SDE_DEBUG("Disabling cont_splash feature\n"); - sde_kms->splash_data.cont_splash_en = false; - - for (i = 0; i < SDE_POWER_HANDLE_DBUS_ID_MAX; i++) - sde_power_data_bus_set_quota(&priv->phandle, - sde_kms->core_client, - SDE_POWER_HANDLE_DATA_BUS_CLIENT_RT, i, - SDE_POWER_HANDLE_ENABLE_BUS_AB_QUOTA, - SDE_POWER_HANDLE_ENABLE_BUS_IB_QUOTA); + _sde_kms_release_splash_resource(sde_kms, old_state); - sde_power_resource_enable(&priv->phandle, - sde_kms->core_client, false); - SDE_DEBUG("removing Vote for MDP Resources\n"); - } - - /* - * Even for continuous splash disabled cases we have to release - * splash memory reservation back to system after first frame update. - */ - if (sde_kms->splash_data.splash_base) { - rc = _sde_kms_release_splash_buffer( - sde_kms->splash_data.splash_base, - sde_kms->splash_data.splash_size); - if (rc) - pr_err("Failed to release splash memory\n"); - sde_kms->splash_data.splash_base = 0; - sde_kms->splash_data.splash_size = 0; - } + SDE_EVT32_VERBOSE(SDE_EVTLOG_FUNC_EXIT); } static void sde_kms_wait_for_commit_done(struct msm_kms *kms, @@ -2956,8 +2979,7 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) * address. To facilitate this requirement we need to have a * one to one mapping on SMMU until we have our first frame. */ - if ((i == MSM_SMMU_DOMAIN_UNSECURE) && - sde_kms->splash_data.smmu_handoff_pending) { + if (i == MSM_SMMU_DOMAIN_UNSECURE) { ret = mmu->funcs->set_attribute(mmu, DOMAIN_ATTR_EARLY_MAP, &early_map); @@ -2986,27 +3008,27 @@ static int _sde_kms_mmu_init(struct sde_kms *sde_kms) } aspace->domain_attached = true; early_map = 0; + /* Mapping splash memory block */ if ((i == MSM_SMMU_DOMAIN_UNSECURE) && - sde_kms->splash_data.smmu_handoff_pending) { + sde_kms->splash_data.splash_base) { ret = _sde_kms_splash_smmu_map(sde_kms->dev, mmu, &sde_kms->splash_data); if (ret) { SDE_ERROR("failed to map ret:%d\n", ret); goto fail; } - /* - * Turning off early map after generating one to one - * mapping for splash address space. - */ - ret = mmu->funcs->set_attribute(mmu, - DOMAIN_ATTR_EARLY_MAP, - &early_map); - if (ret) { - SDE_ERROR("failed to set map att ret:%d\n", - ret); - goto early_map_fail; - } + } + + /* + * Turning off early map after generating one to one + * mapping for splash address space. + */ + ret = mmu->funcs->set_attribute(mmu, DOMAIN_ATTR_EARLY_MAP, + &early_map); + if (ret) { + SDE_ERROR("failed to set map att ret:%d\n", ret); + goto early_map_fail; } } @@ -3285,12 +3307,7 @@ static int sde_kms_hw_init(struct msm_kms *kms) &sde_kms->splash_data, sde_kms->catalog); - /* - * SMMU handoff is necessary for continuous splash enabled - * scenario. - */ - if (sde_kms->splash_data.cont_splash_en) - sde_kms->splash_data.smmu_handoff_pending = true; + sde_kms->splash_data.resource_handoff_pending = true; /* Initialize reg dma block which is a singleton */ rc = sde_reg_dma_init(sde_kms->reg_dma, sde_kms->catalog, -- GitLab From 826d12a8fbaed96374fc7496c22126e2ad693a48 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Tue, 1 May 2018 18:16:28 -0400 Subject: [PATCH 1586/1834] drm/msm/sde: Add check before applying color-prop properties After device goes into suspend state for a while, we notice that atomic commit calls are made, and they will cause all the dirty color-processing properties to be applied during suspend state. When device actually resumes, all the dirty color-processing won't be applied again and cause color-processing features not persist over suspend/resume. This change adds a check to make sure sde_crtc is enabled before applying color-processing properties to avoid the issue. Signed-off-by: Ping Li Change-Id: Ia001b5d4074da05d0ad266cb0876e5283b9bdda1 CRs-Fixed: 2234358 --- drivers/gpu/drm/msm/sde/sde_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index ce2997d64860..7daab2acf8a6 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -3099,7 +3099,7 @@ static void sde_crtc_atomic_begin(struct drm_crtc *crtc, * apply color processing properties only if * smmu state is attached, */ - if (!sde_kms_is_secure_session_inprogress(sde_kms)) + if (!sde_kms_is_secure_session_inprogress(sde_kms) && sde_crtc->enabled) sde_cp_crtc_apply_properties(crtc); /* -- GitLab From addf1f836f581d89bd5bf804fc4f5f9af443d914 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 23 Apr 2018 14:39:19 -0700 Subject: [PATCH 1587/1834] iommu: arm-smmu: Add hibernation support for slave-side secure devices Some targets restrict HLOS access to certain iommu context banks. Previously these context banks were indicated by the client driver by setting the IOMMU_DOMAIN_ATTR_SECURE_VMID property. However, the iommu driver may require this knowledge at probe time, before all client drivers are available. Therfore pass this information as a devicetree flag. Additionally, add ops for hibernation. Change-Id: I2abf9beaa0d17315f0b9399889cd89f0afd8bb7e Signed-off-by: Patrick Daly --- .../devicetree/bindings/iommu/arm,smmu.txt | 15 ++++ drivers/iommu/arm-smmu.c | 90 +++++++++++++++++-- include/dt-bindings/arm/arm-smmu.h | 1 + 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt b/Documentation/devicetree/bindings/iommu/arm,smmu.txt index 78aa1d78062c..4839df482cbe 100644 --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt @@ -77,6 +77,21 @@ conditions. - qcom,tz-device-id : A string indicating the device ID for this SMMU known to TZ. See msm_tz_smmu.c for a full list of mappings. +- qcom,enable-static-cb: + A boolean indicating that the SMMU global register space, + as well as some context banks, are managed by secure software + and may not be modified by HLOS. + +- qcom,static-ns-cbs: + A list of u32. + When qcom,enable-static-cb is selected, indicates which + iommu context banks may be used by HLOS. + +- qcom,hibernation-support: + A boolean, indicates that hibernation should be supported and + all secure usecases should be disabled, since they cannot be + restored properly. + - qcom,skip-init : Disable resetting configuration for all context banks during device reset. This is useful for targets where some context banks are dedicated to other execution diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index e0b2f635f926..17193366d28f 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -579,6 +579,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = { { ARM_SMMU_OPT_MMU500_ERRATA1, "qcom,mmu500-errata-1" }, { ARM_SMMU_OPT_STATIC_CB, "qcom,enable-static-cb"}, { ARM_SMMU_OPT_HALT, "qcom,enable-smmu-halt"}, + { ARM_SMMU_OPT_HIBERNATION, "qcom,hibernation-support"}, { 0, NULL}, }; @@ -704,6 +705,11 @@ static void arm_smmu_secure_domain_unlock(struct arm_smmu_domain *smmu_domain) mutex_unlock(&smmu_domain->assign_lock); } +static bool arm_smmu_opt_hibernation(struct arm_smmu_device *smmu) +{ + return smmu->options & ARM_SMMU_OPT_HIBERNATION; +} + /* * init() * Hook for additional device tree parsing at probe time. @@ -1859,6 +1865,14 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain, goto out_unlock; } + if (arm_smmu_has_secure_vmid(smmu_domain) && + arm_smmu_opt_hibernation(smmu)) { + dev_err(smmu->dev, + "Secure usecases not supported with hibernation\n"); + ret = -EPERM; + goto out_unlock; + } + /* * Mapping the requested stage onto what we support is surprisingly * complicated, mainly because the spec allows S1+S2 SMMUs without @@ -3994,6 +4008,33 @@ static int arm_smmu_alloc_cb(struct iommu_domain *domain, return cb; } +static void parse_static_cb_cfg(struct arm_smmu_device *smmu) +{ + u32 idx = 0; + u32 val; + int ret; + + if (!(arm_smmu_is_static_cb(smmu) && + arm_smmu_opt_hibernation(smmu))) + return; + + /* + * Context banks may be xpu-protected. Require a devicetree property to + * indicate which context banks HLOS has access to. + */ + bitmap_set(smmu->secure_context_map, 0, ARM_SMMU_MAX_CBS); + while (idx < ARM_SMMU_MAX_CBS) { + ret = of_property_read_u32_index( + smmu->dev->of_node, "qcom,static-ns-cbs", + idx++, &val); + if (ret) + break; + + bitmap_clear(smmu->secure_context_map, val, 1); + dev_dbg(smmu->dev, "Detected NS context bank: %d\n", idx); + } +} + static int arm_smmu_handoff_cbs(struct arm_smmu_device *smmu) { u32 i, raw_smr, raw_s2cr; @@ -4693,6 +4734,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) } parse_driver_options(smmu); + parse_static_cb_cfg(smmu); smmu->pwr = arm_smmu_init_power_resources(pdev); if (IS_ERR(smmu->pwr)) @@ -4799,8 +4841,9 @@ static int arm_smmu_device_remove(struct platform_device *pdev) if (arm_smmu_power_on(smmu->pwr)) return -EINVAL; - if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS) || - !bitmap_empty(smmu->secure_context_map, ARM_SMMU_MAX_CBS)) + if (!(bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS) && + (bitmap_empty(smmu->secure_context_map, ARM_SMMU_MAX_CBS) || + arm_smmu_opt_hibernation(smmu)))) dev_err(&pdev->dev, "removing device with active domains!\n"); idr_destroy(&smmu->asid_idr); @@ -4814,10 +4857,43 @@ static int arm_smmu_device_remove(struct platform_device *pdev) return 0; } +static int arm_smmu_pm_freeze(struct device *dev) +{ + struct arm_smmu_device *smmu = dev_get_drvdata(dev); + + if (!arm_smmu_opt_hibernation(smmu)) { + dev_err(smmu->dev, "Aborting: Hibernation not supported\n"); + return -EINVAL; + } + return 0; +} + +static int arm_smmu_pm_restore(struct device *dev) +{ + struct arm_smmu_device *smmu = dev_get_drvdata(dev); + int ret; + + ret = arm_smmu_power_on(smmu->pwr); + if (ret) + return ret; + + arm_smmu_device_reset(smmu); + arm_smmu_power_off(smmu->pwr); + return 0; +} + +static const struct dev_pm_ops arm_smmu_pm_ops = { +#ifdef CONFIG_PM_SLEEP + .freeze = arm_smmu_pm_freeze, + .restore = arm_smmu_pm_restore, +#endif +}; + static struct platform_driver arm_smmu_driver = { .driver = { .name = "arm-smmu", .of_match_table = of_match_ptr(arm_smmu_of_match), + .pm = &arm_smmu_pm_ops, }, .probe = arm_smmu_device_dt_probe, .remove = arm_smmu_device_remove, @@ -4828,6 +4904,7 @@ static int __init arm_smmu_init(void) { static bool registered; int ret = 0; + struct device_node *node; ktime_t cur; if (registered) @@ -4839,9 +4916,12 @@ static int __init arm_smmu_init(void) return ret; ret = platform_driver_register(&arm_smmu_driver); -#ifdef CONFIG_MSM_TZ_SMMU - ret = register_iommu_sec_ptbl(); -#endif + /* Disable secure usecases if hibernation support is enabled */ + node = of_find_compatible_node(NULL, NULL, "qcom,qsmmu-v500"); + if (IS_ENABLED(CONFIG_MSM_TZ_SMMU) && node && + !of_find_property(node, "qcom,hibernation-support", NULL)) + ret = register_iommu_sec_ptbl(); + registered = !ret; trace_smmu_init(ktime_us_delta(ktime_get(), cur)); diff --git a/include/dt-bindings/arm/arm-smmu.h b/include/dt-bindings/arm/arm-smmu.h index 3a1dbd333e2a..1de45a92f1e6 100644 --- a/include/dt-bindings/arm/arm-smmu.h +++ b/include/dt-bindings/arm/arm-smmu.h @@ -23,5 +23,6 @@ #define ARM_SMMU_OPT_MMU500_ERRATA1 (1 << 7) #define ARM_SMMU_OPT_STATIC_CB (1 << 8) #define ARM_SMMU_OPT_HALT (1 << 9) +#define ARM_SMMU_OPT_HIBERNATION (1 << 10) #endif -- GitLab From f77a1cafc11e6952d7aa1f086254b1bb79eafbff Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 15 Mar 2018 14:59:57 +0800 Subject: [PATCH 1588/1834] ARM: dts: msm: Add jtagv8 support for MSM8953 jtagv8 driver can be used to save and restore debug and ETM registers across power collapse. Add jtag nodes to support save/restore ETM registers for MSM8953. CRs-Fixed: 2230899 Change-Id: I1d61450320a8a79a67b0b9e3ec90bfd7a7ae985d Signed-off-by: Mao Jinlong --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 97 +++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 64e76645221e..a3528d60e99d 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -1322,6 +1322,103 @@ label = "modem"; }; }; + + jtag_mm0: jtagmm@619c000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619c000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + + jtag_mm1: jtagmm@619d000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619d000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + + jtag_mm2: jtagmm@619e000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619e000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + + jtag_mm3: jtagmm@619f000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619f000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + + jtag_mm4: jtagmm@61bc000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bc000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + + jtag_mm5: jtagmm@61bd000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bd000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + + jtag_mm6: jtagmm@61be000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61be000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + + jtag_mm7: jtagmm@61bf000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bf000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk"; + }; + sdcc1_ice: sdcc1ice@7803000 { compatible = "qcom,ice"; reg = <0x7803000 0x8000>; -- GitLab From 669e24e413d57c31c6ac914ef37d35f41a26fe27 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 15 Mar 2018 15:11:18 +0800 Subject: [PATCH 1589/1834] ARM: dts: msm: Add jtagv8 support for MSM8937 jtagv8 driver can be used to save and restore debug and ETM registers across power collapse. Add jtag nodes to support save/restore ETM registers for MSM8937. CRs-Fixed: 2230899 Change-Id: Iad3400fee87a13d7c88c7242e0781c92f289b900 Signed-off-by: Mao Jinlong --- .../dts/qcom/msm8937-interposer-sdm429.dtsi | 4 + arch/arm64/boot/dts/qcom/msm8937.dtsi | 88 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sdm429.dtsi | 4 + 3 files changed, 96 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi index 5ae93333d054..53d415ab617b 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-interposer-sdm429.dtsi @@ -23,6 +23,10 @@ /delete-node/ cti@61b9000; /delete-node/ cti@61ba000; /delete-node/ cti@61bb000; + /delete-node/ jtagmm@619c000; + /delete-node/ jtagmm@619d000; + /delete-node/ jtagmm@619e000; + /delete-node/ jtagmm@619f000; qcom,spm@b1d2000 { qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>; diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi index 240cc04fe244..4f96fd71b504 100644 --- a/arch/arm64/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi @@ -1111,6 +1111,94 @@ }; }; + jtag_mm0: jtagmm@61bc000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bc000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + + jtag_mm1: jtagmm@61bd000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bd000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + + jtag_mm2: jtagmm@61be000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61be000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + + jtag_mm3: jtagmm@61bf000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bf000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + + jtag_mm4: jtagmm@619c000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619c000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU4>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + + jtag_mm5: jtagmm@619d000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619d000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU5>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + + jtag_mm6: jtagmm@619e000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619e000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU6>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + + jtag_mm7: jtagmm@619f000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x619f000 0x1000>; + reg-names = "etm-base"; + + qcom,coresight-jtagmm-cpu = <&CPU7>; + + clocks = <&clock_gcc clk_qdss_clk>; + clock-names = "core_clk"; + }; + qcom,smdtty { compatible = "qcom,smdtty"; diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 49be6e42b972..6c4db5ce338a 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -28,6 +28,10 @@ /delete-node/ cti@61b9000; /delete-node/ cti@61ba000; /delete-node/ cti@61bb000; + /delete-node/ jtagmm@619c000; + /delete-node/ jtagmm@619d000; + /delete-node/ jtagmm@619e000; + /delete-node/ jtagmm@619f000; qcom,spm@b1d2000 { qcom,cpu-vctl-list = <&CPU0 &CPU1 &CPU2 &CPU3>; -- GitLab From b6e9cb26840618ed2ae7550ff182b410d3bab008 Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Wed, 2 May 2018 11:56:34 +0530 Subject: [PATCH 1590/1834] ARM: dts: msm: optimize CMA regions for qcs605 Reduced mem_dump_region size to 8MB from 36MB for QCS605. Change-Id: Ic8c5bf8553da49a61ce774d49023a1d6a5055014 Signed-off-by: Vishwanath Raju K --- arch/arm64/boot/dts/qcom/qcs605.dtsi | 10 ++++++++++ arch/arm64/boot/dts/qcom/sdm670.dtsi | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index 1e1d82c38954..be88a5dfead1 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -66,6 +66,10 @@ status = "disabled"; }; +&dump_mem { + size = <0 0x800000>; +}; + &soc { qcom,rmnet-ipa { status = "disabled"; @@ -76,6 +80,12 @@ status = "disabled"; }; +&mem_dump { + rpmh { + qcom,dump-size = <0x400000>; + }; +}; + &thermal_zones { lmh-dcvs-00 { trips { diff --git a/arch/arm64/boot/dts/qcom/sdm670.dtsi b/arch/arm64/boot/dts/qcom/sdm670.dtsi index 3ca33b2d2583..7302296688ea 100644 --- a/arch/arm64/boot/dts/qcom/sdm670.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670.dtsi @@ -1389,7 +1389,7 @@ }; }; - mem_dump { + mem_dump: mem_dump { compatible = "qcom,mem-dump"; memory-region = <&dump_mem>; -- GitLab From f7ed52d26cc696fc47f38a4363077b99b0e5e26f Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 13 Mar 2018 16:30:12 +0530 Subject: [PATCH 1591/1834] core_ctl: Fix an issue where CPUs are left un-isolated for long time When SCHED_CORE_ROTATE config is enabled, the CPUs that are eligible for isolation are kept rotated for every system suspend and resume cycle. cluster->set_cur holds this eligible mask. It is also reconfigured when min_cpus tunable is changed. The CPUs that are part of this eligible mask are only isolated in try_to_isolate(). A CPU that is part of this mask but is busy at that time left isolated. Since the new need is same as the last need, eval_need() does not kick core_ctl thread next time when the CPU becomes idle. To fix this issue, kick the core_ctl thread when there more active CPUs than currently needed. The kicks are rate limited by an existing tunable called offline_delay_ms. Change-Id: I9d3815c6c6bede4b93a708ae6edb15f94d296399 Signed-off-by: Pavankumar Kondeti --- kernel/sched/core_ctl.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel/sched/core_ctl.c b/kernel/sched/core_ctl.c index c0a8a2af9cb6..26c9cf4cc170 100644 --- a/kernel/sched/core_ctl.c +++ b/kernel/sched/core_ctl.c @@ -588,7 +588,12 @@ static bool eval_need(struct cluster_data *cluster) if (new_need > cluster->active_cpus) { ret = 1; } else { - if (new_need == last_need) { + /* + * When there is no change in need and there are no more + * active CPUs than currently needed, just update the + * need time stamp and return. + */ + if (new_need == last_need && new_need == cluster->active_cpus) { cluster->need_ts = now; spin_unlock_irqrestore(&state_lock, flags); return 0; -- GitLab From 7deb2a6b2a08f7c3c2c45c2752834e1338abfec9 Mon Sep 17 00:00:00 2001 From: blong Date: Fri, 20 Apr 2018 11:30:57 +0800 Subject: [PATCH 1592/1834] ARM: dts: msm: Update cpufreq for sdm439/429 Update cpufreq,devfreq,sched energy-cost data,and cci cache for sdm439/429. CRs-Fixed: 2225705 Change-Id: I9db7c0f823fcc25af00b451adf170e5845e0eda5 Signed-off-by: Biao long --- arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi | 6 +- arch/arm64/boot/dts/qcom/sdm429.dtsi | 25 +-- arch/arm64/boot/dts/qcom/sdm439.dtsi | 194 +++++++++++++++-------- 3 files changed, 146 insertions(+), 79 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi index 80aeb246181a..6c4ea9f2a73e 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-cpu.dtsi @@ -129,10 +129,10 @@ CPU_COST_0: core-cost0 { busy-cost-data = < 960000 159 - 1001600 165 1305600 207 1497600 256 1708800 327 + 1804800 343 1958400 445 >; idle-cost-data = < @@ -141,11 +141,11 @@ }; CLUSTER_COST_0: cluster-cost0 { busy-cost-data = < - 960000 52 - 1001600 53 + 960000 53 1305600 61 1497600 71 1708800 85 + 1804800 88 1958400 110 >; idle-cost-data = < diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 49be6e42b972..a16d2d3094c5 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -39,6 +39,7 @@ }; }; + /delete-node/ qcom,msm-cpufreq; msm_cpufreq: qcom,msm-cpufreq { compatible = "qcom,msm-cpufreq"; clock-names = @@ -54,35 +55,39 @@ < 1305600 >, < 1497600 >, < 1708800 >, + < 1804800 >, < 1958400 >; }; + /delete-node/ devfreq-cpufreq; devfreq-cpufreq { cpubw-cpufreq { target-dev = <&cpubw>; cpu-to-dev-map = - < 960000 2929 >, - < 1305600 5053 >, - < 1497600 5712 >, - < 1708800 7031 >, - < 1958400 7031 >; + < 960000 2929 >, + < 1305600 5126 >, + < 1497600 5859 >, + < 1708800 6445 >, + < 1804800 7104 >, + < 1958400 7104 >; }; cci-cpufreq { target-dev = <&cci_cache>; cpu-to-dev-map = - < 960000 400000 >, + < 960000 400000 >, < 1305600 400000 >, - < 1497600 533333 >, - < 1708800 533333 >, - < 1958400 533333 >; + < 1497600 400000 >, + < 1708800 533000 >, + < 1804800 576000 >, + < 1958400 576000 >; }; mincpubw-cpufreq { target-dev = <&mincpubw>; cpu-to-dev-map = < 1305600 2929 >, - < 1958400 4248 >; + < 1804800 5859 >; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 74d97a6ae5e3..8093c6147a52 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -35,6 +35,7 @@ qcom,mipi-csi-vdd-supply = <&pm8953_l23>; }; + /delete-node/ qcom,msm-cpufreq; msm_cpufreq: qcom,msm-cpufreq { compatible = "qcom,msm-cpufreq"; clock-names = @@ -51,30 +52,87 @@ < 1305600 >, < 1497600 >, < 1708800 >, + < 1804800 >, < 1958400 >; qcom,cpufreq-table-4 = < 768000 >, - < 1001600 >, + < 998400 >, < 1171200 >, < 1305600 >, < 1459200 >; }; + /delete-node/ qcom,cpubw; + cpubw: qcom,cpubw { + compatible = "qcom,devbw"; + governor = "cpufreq"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < 769 /* 100.8 MHz */ >, + < 1611 /* 211.2 MHz */ >, /*Low SVS*/ + < 2124 /* 278.4 MHz */ >, + < 2929 /* 384 MHz */ >, /* SVS */ + < 3221 /* 422.4 MHz */ >, + < 4248 /* 556.8 MHz */ >, + < 5126 /* 662.4 MHz */ >, /* SVS+ */ + < 5859 /* 748.8 MHz */ >, /* NOM */ + < 6152 /* 806.4 MHz */ >, /* NOM+ */ + < 6445 /* 844.8 MHz */ >, + < 7104 /* 931.2 MHz */ >; /* TURBO */ + }; + + /delete-node/ qcom,mincpubw; + mincpubw: qcom,mincpubw { + compatible = "qcom,devbw"; + governor = "cpufreq"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < 769 /* 100.8 MHz */ >, + < 1611 /* 211.2 MHz */ >, /*Low SVS*/ + < 2124 /* 278.4 MHz */ >, + < 2929 /* 384 MHz */ >, /* SVS */ + < 3221 /* 422.4 MHz */ >, + < 4248 /* 556.8 MHz */ >, + < 5126 /* 662.4 MHz */ >, /* SVS+ */ + < 5859 /* 748.8 MHz */ >, /* NOM */ + < 6152 /* 806.4 MHz */ >, /* NOM+ */ + < 6445 /* 844.8 MHz */ >, + < 7104 /* 931.2 MHz */ >; /* TURBO */ + }; + + /delete-node/ qcom,cci; + cci_cache: qcom,cci { + compatible = "devfreq-simple-dev"; + clock-names = "devfreq_clk"; + clocks = <&clock_cpu clk_cci_clk>; + governor = "cpufreq"; + freq-tbl-khz = + < 400000 >, + < 400000 >, + < 400000 >, + < 533000 >, + < 576000 >; + }; + + /delete-node/ devfreq-cpufreq; devfreq-cpufreq { cpubw-cpufreq { target-dev = <&cpubw>; cpu-to-dev-map-0 = - < 1305600 2929 >, - < 1497600 5053 >, - < 1708800 5712 >, - < 1958400 7031 >; + < 1305600 5126 >, + < 1497600 5859 >, + < 1708800 6445 >, + < 1804800 7104 >, + < 1958400 7104 >; cpu-to-dev-map-4 = < 768000 2929 >, - < 1001600 4101 >, - < 1171200 5053 >, + < 998400 5126 >, + < 1171200 5859 >, < 1305600 6152 >, - < 1459200 7031 >; + < 1459200 7104 >; }; @@ -83,80 +141,84 @@ cpu-to-dev-map-0 = < 1305600 400000 >, < 1497600 400000 >, - < 1708800 533333 >, - < 1958400 533333 >; + < 1708800 533000 >, + < 1804800 576000 >, + < 1958400 576000 >; cpu-to-dev-map-4 = < 768000 400000 >, - < 1001600 400000 >, - < 1171200 533333 >, - < 1305600 533333 >, - < 1459200 533333 >; + < 998400 400000 >, + < 1171200 400000 >, + < 1305600 533000 >, + < 1459200 576000 >; }; mincpubw-cpufreq { target-dev = <&mincpubw>; cpu-to-dev-map-0 = < 1305600 2929 >, - < 1958400 4248 >; + < 1804800 5859 >; cpu-to-dev-map-4 = < 1171200 2929 >, - < 1459200 4248 >; + < 1459200 5859 >; }; }; }; -&energy_costs { - compatible = "sched-energy"; - - CPU_COST_0: core-cost0 { - busy-cost-data = < - 800000 137 - 1001600 165 - 1305600 207 - 1497600 256 - 1708800 327 - 1958400 445 - >; - idle-cost-data = < - 100 80 60 40 - >; - }; - CPU_COST_1: core-cost1 { - busy-cost-data = < - 768000 43 - 1001600 56 - 1171200 71 - 1305600 89 - 1459200 120 - >; - idle-cost-data = < - 40 20 10 8 - >; - }; - CLUSTER_COST_0: cluster-cost0 { +/{ + /delete-node/ energy-costs; + energy_costs: energy-costs { + compatible = "sched-energy"; + + CPU_COST_0: core-cost0 { busy-cost-data = < - 800000 49 - 1001600 53 - 1305600 61 - 1497600 71 - 1708800 85 - 1958400 110 - >; - idle-cost-data = < - 4 3 2 1 - >; - }; - CLUSTER_COST_1: cluster-cost1 { + 800000 137 + 1305600 207 + 1497600 256 + 1708800 327 + 1804800 343 + 1958400 445 + >; + idle-cost-data = < + 100 80 60 40 + >; + }; + CPU_COST_1: core-cost1 { + busy-cost-data = < + 768000 43 + 998400 56 + 1171200 71 + 1305600 89 + 1459200 120 + >; + idle-cost-data = < + 40 20 10 8 + >; + }; + CLUSTER_COST_0: cluster-cost0 { + busy-cost-data = < + 800000 49 + 1305600 61 + 1497600 71 + 1708800 85 + 1804800 88 + 1958400 110 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; + CLUSTER_COST_1: cluster-cost1 { busy-cost-data = < - 768000 8 - 1001600 10 - 1171200 13 - 1305600 15 - 1459200 20 - >; - idle-cost-data = < - 4 3 2 1 - >; + 768000 8 + 998400 10 + 1171200 13 + 1305600 15 + 1459200 20 + >; + idle-cost-data = < + 4 3 2 1 + >; + }; }; }; -- GitLab From 20688264bdccde407a22b87c04ccb3064fa525a5 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Wed, 25 Apr 2018 11:45:34 +0530 Subject: [PATCH 1593/1834] power: smb5: add support to read USB voltage and current Add support to read USB voltage and current via ADC channels, this is used by user-space daemon for VBUS optimisation. Change-Id: I2e0a7455295958d3c55acdb3f657213343fe3598 Signed-off-by: Ashay Jaiswal --- .../bindings/power/supply/qcom/qpnp-smb5.txt | 6 ++ drivers/power/supply/qcom/qpnp-smb5.c | 75 +++++++++++++++++++ drivers/power/supply/qcom/smb5-lib.h | 1 + 3 files changed, 82 insertions(+) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt index de273cdda4dc..8ee2749aea35 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-smb5.txt @@ -195,6 +195,12 @@ Charger specific properties: This is only applicable to certain PMICs like PMI632 which has SCHGM_FLASH peripheral. +- qcom,chg-vadc + Usage: optional + Value type: + Definition: Phandle for the VADC node, it is used to obtain USBIN_V + and USBIN_I readings on PMIC632 based platform. + ============================================= Second Level Nodes - SMB5 Charger Peripherals ============================================= diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index be4765817cca..d3aaf264a075 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "smb5-reg.h" #include "smb5-lib.h" #include "schgm-flash.h" @@ -181,6 +182,11 @@ module_param_named( weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600 ); +enum { + USBIN_CURRENT, + USBIN_VOLTAGE, +}; + #define PMI632_MAX_ICL_UA 3000000 static int smb5_chg_config_init(struct smb5 *chip) { @@ -361,6 +367,61 @@ static int smb5_parse_dt(struct smb5 *chip) return 0; } +static int smb5_get_adc_data(struct smb_charger *chg, int channel, + union power_supply_propval *val) +{ + int rc; + struct qpnp_vadc_result result; + + if (!chg->vadc_dev) { + if (of_find_property(chg->dev->of_node, "qcom,chg-vadc", + NULL)) { + chg->vadc_dev = qpnp_get_vadc(chg->dev, "chg"); + if (IS_ERR(chg->vadc_dev)) { + rc = PTR_ERR(chg->vadc_dev); + if (rc != -EPROBE_DEFER) + pr_debug("Failed to find VADC node, rc=%d\n", + rc); + else + chg->vadc_dev = NULL; + + return rc; + } + } else { + return -ENODATA; + } + } + + if (IS_ERR(chg->vadc_dev)) + return PTR_ERR(chg->vadc_dev); + + switch (channel) { + case USBIN_VOLTAGE: + rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_V_DIV_16_PM5, + &result); + if (rc < 0) { + pr_err("Failed to read USBIN_V over vadc, rc=%d\n", rc); + return rc; + } + val->intval = result.physical; + break; + case USBIN_CURRENT: + rc = qpnp_vadc_read(chg->vadc_dev, VADC_USB_IN_I_PM5, &result); + if (rc < 0) { + pr_err("Failed to read USBIN_I over vadc, rc=%d\n", rc); + return rc; + } + val->intval = result.physical; + break; + default: + pr_debug("Invalid channel\n"); + return -EINVAL; + } + + return 0; +} + + /************************ * USB PSY REGISTRATION * ************************/ @@ -389,6 +450,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_CONNECTOR_TYPE, POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_SCOPE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED, }; @@ -505,6 +567,19 @@ static int smb5_usb_get_prop(struct power_supply *psy, : chg->otg_present ? POWER_SUPPLY_SCOPE_SYSTEM : POWER_SUPPLY_SCOPE_UNKNOWN; break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_NOW: + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0 || !pval.intval) { + val->intval = 0; + return rc; + } + if (chg->smb_version == PMI632_SUBTYPE) + rc = smb5_get_adc_data(chg, USBIN_CURRENT, val); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (chg->smb_version == PMI632_SUBTYPE) + rc = smb5_get_adc_data(chg, USBIN_VOLTAGE, val); + break; case POWER_SUPPLY_PROP_HVDCP_OPTI_ALLOWED: val->intval = !chg->flash_active; break; diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 57154474da57..5d6d3a64a8f6 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -264,6 +264,7 @@ struct smb_charger { int smb_version; int otg_delay_ms; int *weak_chg_icl_ua; + struct qpnp_vadc_chip *vadc_dev; /* locks */ struct mutex lock; -- GitLab From c4e345db2d0eb35a4f56fdbaa0cec7b84c0e2b15 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Fri, 16 Mar 2018 20:15:50 -0700 Subject: [PATCH 1594/1834] power: smb5: Fix VCONN orientation under SW control SW is selected in the driver as the source to enable VCONN. However, Its orientation, i.e., on the CC pin which has Ra connected, is not explicitly specified when enabled and hence always defaulted to CC1. This is incorrect since it may shift and is always opposite to CC orientation. Fix it. Change-Id: Ibd74c12b25bfb45e0fecc48995e8a26379f98ea0 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb5-lib.c | 23 ++++++++++++++--------- drivers/power/supply/qcom/smb5-reg.h | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 8eed5894daa0..87561867e23f 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1026,13 +1026,25 @@ int smblib_vconn_regulator_enable(struct regulator_dev *rdev) { struct smb_charger *chg = rdev_get_drvdata(rdev); int rc = 0; + u8 stat, orientation; smblib_dbg(chg, PR_OTG, "enabling VCONN\n"); + rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); + return rc; + } + + /* VCONN orientation is opposite to that of CC */ + orientation = + stat & TYPEC_CCOUT_VALUE_BIT ? 0 : VCONN_EN_ORIENTATION_BIT; rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG, - VCONN_EN_VALUE_BIT, VCONN_EN_VALUE_BIT); + VCONN_EN_VALUE_BIT | VCONN_EN_ORIENTATION_BIT, + VCONN_EN_VALUE_BIT | orientation); if (rc < 0) { - smblib_err(chg, "Couldn't enable vconn setting rc=%d\n", rc); + smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", + rc); return rc; } @@ -3107,13 +3119,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc); - - rc = smblib_masked_write(chg, TYPE_C_VCONN_CONTROL_REG, - VCONN_EN_SRC_BIT, 0); - if (rc < 0) - smblib_err(chg, "Couldn't set TYPE_C_VCONN_CONTROL_REG rc=%d\n", - rc); - /* clear exit sink based on cc */ rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, EXIT_SNK_BASED_ON_CC_BIT, 0); diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 48ef12e1a6c6..e199087c907b 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -282,10 +282,12 @@ enum { #define TYPEC_DISABLE_CMD_BIT BIT(0) #define TYPE_C_VCONN_CONTROL_REG (TYPEC_BASE + 0x46) +#define VCONN_EN_ORIENTATION_BIT BIT(2) #define VCONN_EN_VALUE_BIT BIT(1) #define VCONN_EN_SRC_BIT BIT(0) #define TYPE_C_CCOUT_CONTROL_REG (TYPEC_BASE + 0x48) +#define TYPEC_CCOUT_VALUE_BIT BIT(1) #define TYPEC_CCOUT_SRC_BIT BIT(0) #define TYPE_C_EXIT_STATE_CFG_REG (TYPEC_BASE + 0x50) -- GitLab From 338074e49de1c5bec0c66a45465e67b99d07b678 Mon Sep 17 00:00:00 2001 From: Samyukta Mogily Date: Mon, 23 Apr 2018 16:17:17 +0530 Subject: [PATCH 1595/1834] msm: camera: Change data type of data rate Change data rate to uint64, to ensure that the value sent to kernel is not corrupted. Change-Id: I692c1c3e591cbac24931078e0fb8938900fc991c Signed-off-by: Samyukta Mogily --- .../msm/camera_v2/sensor/csiphy/msm_csiphy.c | 17 ++++++++++------- include/uapi/media/msm_camera.h | 2 +- include/uapi/media/msm_camsensor_sdk.h | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 58a43904006e..72586fa214c3 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -16,6 +16,7 @@ #include #include #include +#include #include "msm_csiphy.h" #include "msm_sd.h" #include "include/msm_csiphy_2_0_hwreg.h" @@ -179,12 +180,13 @@ static int msm_csiphy_snps_2_lane_config( enum snps_csiphy_mode mode, int num_lanes) { + uint64_t local_data_rate = 0; uint32_t offset; uint32_t value, i, diff, diff_i; void __iomem *csiphybase; csiphybase = csiphy_dev->base; - + local_data_rate = csiphy_params->data_rate; if (mode == TWO_LANE_PHY_A) offset = 0x0; else if (mode == TWO_LANE_PHY_B) @@ -192,13 +194,14 @@ static int msm_csiphy_snps_2_lane_config( else return -EINVAL; + do_div(local_data_rate, num_lanes * MBPS); diff = abs(snps_v100_freq_values[0].default_bit_rate - - ((csiphy_params->data_rate / num_lanes) / MBPS)); + local_data_rate); /* ToDo: Can be optimized to a O(1) search */ for (i = 1; i < sizeof(snps_v100_freq_values)/ sizeof(snps_v100_freq_values[0]); i++) { diff_i = abs(snps_v100_freq_values[i].default_bit_rate - - ((csiphy_params->data_rate / num_lanes) / MBPS)); + local_data_rate); if (diff_i > diff) { i--; break; @@ -208,7 +211,7 @@ static int msm_csiphy_snps_2_lane_config( if (i == (sizeof(snps_v100_freq_values)/ sizeof(snps_v100_freq_values[0]))) { - if (((csiphy_params->data_rate / num_lanes) / MBPS) > + if (local_data_rate > snps_v100_freq_values[--i].default_bit_rate) { pr_err("unsupported data rate\n"); return -EINVAL; @@ -318,7 +321,7 @@ static int msm_csiphy_snps_lane_config( } else if (lane_mask == LANE_MASK_PHY_A) { /* PHY A */ /* 2 lane config */ num_lanes = 2; - if (csiphy_dev->snps_state != NOT_CONFIGURED) { + if (csiphy_dev->snps_state == NOT_CONFIGURED) { mode = TWO_LANE_PHY_A; csiphy_dev->snps_state = CONFIGURED_TWO_LANE_PHY_A; } else if (csiphy_dev->snps_state == @@ -333,7 +336,7 @@ static int msm_csiphy_snps_lane_config( } else if (lane_mask == LANE_MASK_PHY_B) { /* PHY B */ /* 2 lane config */ num_lanes = 2; - if (csiphy_dev->snps_state != NOT_CONFIGURED) { + if (csiphy_dev->snps_state == NOT_CONFIGURED) { mode = TWO_LANE_PHY_B; csiphy_dev->snps_state = CONFIGURED_TWO_LANE_PHY_B; } else if (csiphy_dev->snps_state == @@ -1233,7 +1236,7 @@ static int msm_csiphy_lane_config(struct csiphy_device *csiphy_dev, ratio = csiphy_dev->csiphy_max_clk/clk_rate; csiphy_params->settle_cnt = csiphy_params->settle_cnt/ratio; } - CDBG("%s csiphy_params, mask = 0x%x cnt = %d, data rate = %lu\n", + CDBG("%s csiphy_params, mask = 0x%x cnt = %d, data rate = %llu\n", __func__, csiphy_params->lane_mask, csiphy_params->lane_cnt, csiphy_params->data_rate); diff --git a/include/uapi/media/msm_camera.h b/include/uapi/media/msm_camera.h index c58a2734dfa9..7b2b966ce5c6 100644 --- a/include/uapi/media/msm_camera.h +++ b/include/uapi/media/msm_camera.h @@ -1392,7 +1392,7 @@ struct msm_camera_csiphy_params { uint16_t lane_mask; uint8_t combo_mode; uint8_t csid_core; - unsigned long data_rate; + uint64_t data_rate; }; struct msm_camera_csi2_params { diff --git a/include/uapi/media/msm_camsensor_sdk.h b/include/uapi/media/msm_camsensor_sdk.h index 2283933f325b..6d25967d1ca8 100644 --- a/include/uapi/media/msm_camsensor_sdk.h +++ b/include/uapi/media/msm_camsensor_sdk.h @@ -367,7 +367,7 @@ struct msm_camera_csiphy_params { unsigned char csid_core; unsigned int csiphy_clk; unsigned char csi_3phase; - unsigned long data_rate; + uint64_t data_rate; }; struct msm_camera_i2c_seq_reg_array { -- GitLab From 3171489fe16534353e4cd96451a04159be432c71 Mon Sep 17 00:00:00 2001 From: Manapragada Sai Date: Tue, 1 May 2018 12:32:23 +0530 Subject: [PATCH 1596/1834] defconfig: msm: Config Cleanup on SDM439 Disabling few extra configs seen on 4.9 compared to 3.18 kernel Change-Id: I62cd713e64b5befc4ba8125ed70b7f6d4cff6196 Signed-off-by: Manapragada Sai --- arch/arm/configs/msm8937-perf_defconfig | 41 +++++++++++++--------- arch/arm/configs/msm8937_defconfig | 41 +++++++++++++--------- arch/arm64/configs/msm8937-perf_defconfig | 42 ++++++++++++++--------- arch/arm64/configs/msm8937_defconfig | 42 ++++++++++++++--------- 4 files changed, 100 insertions(+), 66 deletions(-) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index a6a85f18db0c..0b6e0b0a786b 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -68,6 +68,7 @@ CONFIG_HIGHMEM=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y +CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ=y @@ -207,8 +208,6 @@ CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_PRIO=y -CONFIG_NET_SCH_MULTIQ=y -CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y CONFIG_CLS_U32_MARK=y @@ -220,9 +219,6 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_GACT=y -CONFIG_NET_ACT_MIRRED=y -CONFIG_NET_ACT_SKBEDIT=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y @@ -269,6 +265,14 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -282,6 +286,21 @@ CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y @@ -419,12 +438,9 @@ CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y -CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_ACM=y CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_DATAFAB=y @@ -438,14 +454,10 @@ CONFIG_USB_STORAGE_ALAUDA=y CONFIG_USB_STORAGE_ONETOUCH=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y -CONFIG_USB_DWC3=y -CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -454,7 +466,6 @@ CONFIG_USB_CI13XXX_MSM=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y -CONFIG_USB_CONFIGFS_QCRNDIS=y CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y @@ -567,9 +578,7 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 54461cf024ac..0388c86441f7 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -71,6 +71,7 @@ CONFIG_HIGHMEM=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y +CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ=y @@ -211,8 +212,6 @@ CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_PRIO=y -CONFIG_NET_SCH_MULTIQ=y -CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y CONFIG_CLS_U32_MARK=y @@ -224,9 +223,6 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_GACT=y -CONFIG_NET_ACT_MIRRED=y -CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y @@ -274,6 +270,14 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -287,6 +291,21 @@ CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y @@ -427,12 +446,9 @@ CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y -CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_ACM=y CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_DATAFAB=y @@ -446,14 +462,10 @@ CONFIG_USB_STORAGE_ALAUDA=y CONFIG_USB_STORAGE_ONETOUCH=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y -CONFIG_USB_DWC3=y -CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -462,7 +474,6 @@ CONFIG_USB_CI13XXX_MSM=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y -CONFIG_USB_CONFIGFS_QCRNDIS=y CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y @@ -583,9 +594,7 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 78f09fc3f420..4c6b6a1b39b4 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -66,6 +66,7 @@ CONFIG_PREEMPT=y CONFIG_HZ_100=y CONFIG_CMA=y CONFIG_ZSMALLOC=y +CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y CONFIG_HARDEN_BRANCH_PREDICTOR=y CONFIG_ARMV8_DEPRECATED=y @@ -208,8 +209,6 @@ CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_PRIO=y -CONFIG_NET_SCH_MULTIQ=y -CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y CONFIG_CLS_U32_MARK=y @@ -221,9 +220,6 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_GACT=y -CONFIG_NET_ACT_MIRRED=y -CONFIG_NET_ACT_SKBEDIT=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y @@ -270,6 +266,14 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -283,6 +287,21 @@ CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y @@ -399,7 +418,6 @@ CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y -CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_QCOM_KGSL=y @@ -426,12 +444,9 @@ CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y -CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_ACM=y CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_DATAFAB=y @@ -445,14 +460,10 @@ CONFIG_USB_STORAGE_ALAUDA=y CONFIG_USB_STORAGE_ONETOUCH=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y -CONFIG_USB_DWC3=y -CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -461,7 +472,6 @@ CONFIG_USB_CI13XXX_MSM=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y -CONFIG_USB_CONFIGFS_QCRNDIS=y CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y @@ -577,9 +587,7 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index b4a8e29f718d..11bd200bdd36 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -69,6 +69,7 @@ CONFIG_CLEANCACHE=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y +CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y CONFIG_HARDEN_BRANCH_PREDICTOR=y CONFIG_ARMV8_DEPRECATED=y @@ -213,8 +214,6 @@ CONFIG_BRIDGE=y CONFIG_NET_SCHED=y CONFIG_NET_SCH_HTB=y CONFIG_NET_SCH_PRIO=y -CONFIG_NET_SCH_MULTIQ=y -CONFIG_NET_SCH_INGRESS=y CONFIG_NET_CLS_FW=y CONFIG_NET_CLS_U32=y CONFIG_CLS_U32_MARK=y @@ -226,9 +225,6 @@ CONFIG_NET_EMATCH_U32=y CONFIG_NET_EMATCH_META=y CONFIG_NET_EMATCH_TEXT=y CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_GACT=y -CONFIG_NET_ACT_MIRRED=y -CONFIG_NET_ACT_SKBEDIT=y CONFIG_DNS_RESOLVER=y CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y @@ -276,6 +272,14 @@ CONFIG_DM_VERITY_FEC=y CONFIG_NETDEVICES=y CONFIG_DUMMY=y CONFIG_TUN=y +# CONFIG_NET_VENDOR_AMAZON is not set +# CONFIG_NET_CADENCE is not set +# CONFIG_NET_VENDOR_EZCHIP is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_NETRONOME is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SYNOPSYS is not set CONFIG_PPP=y CONFIG_PPP_BSDCOMP=y CONFIG_PPP_DEFLATE=y @@ -289,6 +293,21 @@ CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_USB_USBNET=y +# CONFIG_WLAN_VENDOR_ADMTEK is not set +# CONFIG_WLAN_VENDOR_ATH is not set +# CONFIG_WLAN_VENDOR_ATMEL is not set +# CONFIG_WLAN_VENDOR_BROADCOM is not set +# CONFIG_WLAN_VENDOR_CISCO is not set +# CONFIG_WLAN_VENDOR_INTEL is not set +# CONFIG_WLAN_VENDOR_INTERSIL is not set +# CONFIG_WLAN_VENDOR_MARVELL is not set +# CONFIG_WLAN_VENDOR_MEDIATEK is not set +# CONFIG_WLAN_VENDOR_RALINK is not set +# CONFIG_WLAN_VENDOR_REALTEK is not set +# CONFIG_WLAN_VENDOR_RSI is not set +# CONFIG_WLAN_VENDOR_ST is not set +# CONFIG_WLAN_VENDOR_TI is not set +# CONFIG_WLAN_VENDOR_ZYDAS is not set CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y @@ -407,7 +426,6 @@ CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y -CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_QCOM_KGSL=y @@ -435,12 +453,9 @@ CONFIG_USB_HIDDEV=y CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_MON=y -CONFIG_USB_XHCI_HCD=y CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_MSM=y CONFIG_USB_EHCI_HCD_PLATFORM=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_ACM=y CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE_DATAFAB=y @@ -454,14 +469,10 @@ CONFIG_USB_STORAGE_ALAUDA=y CONFIG_USB_STORAGE_ONETOUCH=y CONFIG_USB_STORAGE_KARMA=y CONFIG_USB_STORAGE_CYPRESS_ATACB=y -CONFIG_USB_DWC3=y -CONFIG_USB_DWC3_MSM=y CONFIG_USB_SERIAL=y CONFIG_USB_EHSET_TEST_FIXTURE=y CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -470,7 +481,6 @@ CONFIG_USB_CI13XXX_MSM=y CONFIG_USB_CONFIGFS=y CONFIG_USB_CONFIGFS_SERIAL=y CONFIG_USB_CONFIGFS_NCM=y -CONFIG_USB_CONFIGFS_QCRNDIS=y CONFIG_USB_CONFIGFS_RNDIS=y CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y @@ -595,9 +605,7 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y -- GitLab From eff63e5885bcf84167b1568e49849a82e3e9c63d Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Wed, 2 May 2018 16:26:18 +0530 Subject: [PATCH 1597/1834] ARM: dts: msm: Enable MHI mode boot up flag on sdxpoorwills Enable MHI mode boot up flag in device tree to boot up IPA driver with MHI config. Change-Id: I178962afa2c3413a0a2dd736061b07c710582444 Signed-off-by: Mohammed Javid --- arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dtsi | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dtsi | 4 ++++ arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dtsi index 518d8a1e2271..dafd0b8dc877 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp-256.dtsi @@ -25,6 +25,10 @@ status = "okay"; }; +&ipa_hw { + qcom,use-ipa-in-mhi-mode; +}; + &pcie0 { status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi index 518d8a1e2271..dafd0b8dc877 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-cdp.dtsi @@ -25,6 +25,10 @@ status = "okay"; }; +&ipa_hw { + qcom,use-ipa-in-mhi-mode; +}; + &pcie0 { status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dtsi index eb544e6fe6f8..6c5f3c3795ae 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp-256.dtsi @@ -25,6 +25,10 @@ status = "okay"; }; +&ipa_hw { + qcom,use-ipa-in-mhi-mode; +}; + &pcie0 { status = "disabled"; }; diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi index eb544e6fe6f8..6c5f3c3795ae 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pcie-ep-mtp.dtsi @@ -25,6 +25,10 @@ status = "okay"; }; +&ipa_hw { + qcom,use-ipa-in-mhi-mode; +}; + &pcie0 { status = "disabled"; }; -- GitLab From cec0f9c0b7f4b9d1788aedf1b588d251e776a36d Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Wed, 4 Apr 2018 15:42:17 +0530 Subject: [PATCH 1598/1834] power: vm-bms: Add snapshot of qpnp-vm-bms driver Initial snapshot of vm-bms device driver is taken from msm-3.18 kernel version @ commit f8b6819d0432d6 ("msm: ipa: Fix to handle NULL pointer dereference") Add vm-bms, batterydata-interface, battery-lib support Change spmi driver framework to platform driver framework in 4.9 kernel. Add support to access spmi register via regmap. Change-Id: Ic2133fcf8dc73e6c1327a8583ccdaa2f5695cfbe Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- .../power/supply/qcom/qpnp-vm-bms.txt | 180 + drivers/power/supply/qcom/Kconfig | 9 + drivers/power/supply/qcom/Makefile | 1 + .../power/supply/qcom/batterydata-interface.c | 218 + drivers/power/supply/qcom/batterydata-lib.c | 493 ++ drivers/power/supply/qcom/qpnp-vm-bms.c | 4255 +++++++++++++++++ include/linux/batterydata-interface.h | 15 + include/uapi/linux/Kbuild | 2 + include/uapi/linux/batterydata-interface.h | 30 + include/uapi/linux/vm_bms.h | 34 + 10 files changed, 5237 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/qcom/qpnp-vm-bms.txt create mode 100644 drivers/power/supply/qcom/batterydata-interface.c create mode 100644 drivers/power/supply/qcom/batterydata-lib.c create mode 100644 drivers/power/supply/qcom/qpnp-vm-bms.c create mode 100644 include/linux/batterydata-interface.h create mode 100644 include/uapi/linux/batterydata-interface.h create mode 100644 include/uapi/linux/vm_bms.h diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-vm-bms.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-vm-bms.txt new file mode 100644 index 000000000000..690a0473dcd7 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-vm-bms.txt @@ -0,0 +1,180 @@ +Qualcomm's QPNP Voltage-Mode(VM) PMIC Battery Management System + +QPNP PMIC VM BMS provides interface to clients to read properties related +to the battery. Its main function is to calculate the SOC (state of charge) +of the battery based on periodic sampling of the VBAT (battery voltage). + +Parent node required properties: +- compatible : Must be "qcom,qpnp-vm-bms" for the BM driver. +- reg : Offset and length of the PMIC peripheral register map. +- interrupts : The interrupt mappings. + The format should be + . +- interrupt-names : names for the mapped bms interrupt + The following interrupts are required: + 0 : leave CV state + 1 : enter CV state + 2 : good ocv generated + 3 : ocv_thr + 4 : fifo update + 5 : fsm state chnaged + +Additionally, optional subnodes may be included: +- qcom,batt-pres-status : A subnode with a register address for the SMBB + battery interface's BATT_PRES_STATUS register. If this node is + added, then the BMS will try to detect offmode battery removal + via the battery interface's offmode battery removal circuit. +- qcom,battery-data : A phandle to a node containing the available batterydata + profiles. See the batterydata bindings documentation for more + details. + +Parent node required properties: +- qcom,v-cutoff-uv : cutoff voltage where the battery is considered dead in + micro-volts. +- qcom,max-voltage-uv : maximum voltage for the battery in micro-volts. +- qcom,r-conn-mohm : connector resistance in milli-ohms. +- qcom,shutdown-soc-valid-limit : If the ocv upon restart is within this + distance of the shutdown ocv, the BMS will try to force + the new SoC to the old one to provide charge continuity. + That is to say, + if (abs(shutdown-soc - current-soc) < limit) + then use old SoC. +- qcom,low-soc-calculate-soc-threshold : The SoC threshold for when + the periodic calculate_soc work speeds up. This ensures + SoC is updated in userspace constantly when we are near + shutdown. +- qcom,low-voltage-threshold : The battery voltage threshold in micro-volts for + when the BMS tries to wake up and hold a wakelock to + ensure a clean shutdown. +- qcom,low-voltage-calculate-soc-ms : The time period between subsequent + SoC recalculations when the current voltage is below + qcom,low-voltage threshold. This takes precedence over + qcom,low-soc-calculate-soc-ms. +- qcom,low-soc-calculate-soc-ms : The time period between subsequent + SoC recalculations when the current SoC is below + qcom,low-soc-calculate-soc-threshold. This takes + precedence over qcom,calculate-soc-ms. +- qcom,calculate-soc-ms : The time period between subsequent SoC + recalculations when the current SoC is above or equal + qcom,low-soc-calculate-soc-threshold. +- qcom,volatge-soc-timeout-ms : The timeout period after which the module starts + reporting volage based SOC and does not use the VMBMS + algorithm for SOC calculation. +- qcom,bms-vadc: Corresponding VADC device's phandle. +- qcom,bms-adc_tm: Corresponding ADC_TM device's phandle to set recurring + measurements and receive notifications for vbatt. +- qcom,pmic-revid : Phandle pointing to the revision peripheral node. + +Parent node Optional properties +- qcom,s1-sample-interval-ms: The sampling rate in ms of the accumulator in state + S1. (i.e) the rate at which the accumulator is being + filled with vbat samples. Minimum value = 0 and + Maximum value = 2550ms. +- qcom,s2-sample-interval-ms: The sampling rate in ms of the accumulator in state + S2. (i.e) the rate at which the accumulator is being + filled with vbat samples. Minimum value = 0 and + Maximum value = 2550ms. +- qcom,s1-sample-count: The number of samples to be accululated for one FIFO in + state S1. Possible values are - 0, 4, 8, 16, 32, 64, 128, + 256. +- qcom,s2-sample-count: The number of samples to be accululated for one FIFO in + state S2. Possible values are - 0, 4, 8, 16, 32, 64, 128, + 256. +- qcom,s1-fifo-legth: Number of FIFO's to be filled in state S1, to generate + the fifo_update_done interrupt. Possile values - 0 to 8 +- qcom,s2-fifo-legth: Number of FIFO's to be filled in state S2, to generate + the fifo_update_done interrupt. Possible values- 0 to 8 +- qcom,force-s3-on-suspend : Bool property to force the BMS into S3 (sleep) state + while entering into system suspend. +- qcom,force-bms-active-on-charger: Bool property to keep BMS FSM active + if charger is present. +- qcom,report-charger-eoc : Bool property to indicate if BMS needs to indicate + EOC to charger. +- qcom,ignore-shutdown-soc: A boolean that controls whether BMS will + try to force the startup SoC to be the same as the + shutdown SoC. Defining it will make BMS ignore the + shutdown SoC. +- qcom,use-voltage-soc : A boolean that controls whether BMS will use + voltage-based SoC instead of a coulomb counter based + one. Voltage-based SoC will not guarantee linearity. +- qcom,disable-bms : Bool property to disable the VMBMS hardware module. + Enable this property if BMS is not supported or an external + fuel gauge is used. +- qcom,s3-ocv-tolerence-uv : The S3 state OCV tolerence threshold in uV. The + LSB value is 300uV and maximum value is 76500uV. +- qcom,low-soc-fifo-length : The fifo length (of S2 STATE) to be used at lower + SOCs. If this value is not specified the system uses + default length. +- qcom,resume-soc: Capacity in percent at which charging should resume + when a fully charged battery drops below this level. +- qcom,low-temp-threshold : The temperature threshold below which the IBAT + averaging and UUC smoothening is disabled. This value + is in deci-degrees centigrade. If not specified it + defaults to 0. +- qcom,ibat-avg-samples : The number of samples to be averaged for IBAT + estimation. If not specified it defaults to 16. + The possible values are 1 to 16. +- qcom,batt-aging-comp : A boolean that defines if battery aging compensation + is enabled. +- qcom,use-reported-soc : Bool property to enable the reported_soc logic. To + enable this feature, qcom,resume-soc must be defined as + a proper value. The BMS is also required to control the + charging, discharging and recharging. + +qcom,batt-pres-status node required properties: +- reg : offset and length of the PMIC LBC battery interface BATT_PRES_STATUS + register. + +qcom,qpnp-chg-pres required properties: +- reg : offset and length of the PMIC LBC charger interafce CHARGER_OPTION + register. + +Example: +pm8916_bms: qcom,qpnp-vm-bms { + spmi-dev-container; + compatible = "qcom,qpnp-vm-bms"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + qcom,v-cutoff-uv = <3400000>; + qcom,max-voltage-uv = <4200000>; + qcom,r-conn-mohm = <18>; + qcom,shutdown-soc-valid-limit = <20>; + qcom,low-soc-calculate-soc-threshold = <15>; + qcom,low-voltage-threshold = <3420000>; + qcom,low-voltage-calculate-soc-ms = <1000>; + qcom,low-soc-calculate-soc-ms = <5000>; + qcom,low-soc-fifo-length = <2>; + qcom,calculate-soc-ms = <20000>; + qcom,s3-ocv-tolerence-uv = <1200>; + qcom,volatge-soc-timeout-ms = <60000>; + qcom,battery-data = <&mtp_batterydata>; + qcom,bms-vadc = <&pm8916_vadc>; + qcom,bms-adc_tm = <&pm8916_adc_tm>; + + qcom,batt-pres-status@1208 { + reg = <0x1208 0x1>; + } + + qcom,qpnp-chg-pres@1208 { + reg = <0x1108 0x1>; + } + + qcom,bms-bms@4000 { + reg = <0x4000 0x100>; + interrupts = <0x0 0x40 0x0>, + <0x0 0x40 0x1>, + <0x0 0x40 0x2>, + <0x0 0x40 0x3>, + <0x0 0x40 0x4>, + <0x0 0x40 0x5>, + + interrupt-names = "leave_cv", + "enter_cv", + "good_ocv", + "ocv_thr", + "fifo_updtaed", + "fsm_state_change"; + }; +}; diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index e571eb472dac..15498673682a 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -104,6 +104,15 @@ config QPNP_QNOVO module. It also allows userspace code to read diagnostics of voltage and current measured during certain phases of the pulses. +config QPNP_VM_BMS + tristate "QPNP Voltage-Mode Battery Monitoring System driver" + depends on MFD_SPMI_PMIC + help + Say Y here to enable support for QPNP chip vm-bms device. + The voltage-mode (vm) BMS driver uses periodic VBATT + readings from the battery to calculate the State of + Charge. + config QPNP_TYPEC tristate "QPNP Type-C driver" depends on MFD_SPMI_PMIC diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index de76a5bdeacf..52a33f0f8f03 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o obj-$(CONFIG_QPNP_TYPEC) += qpnp-typec.o obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o obj-$(CONFIG_SMB1390_CHARGE_PUMP) += smb1390-charger.o pmic-voter.o +obj-$(CONFIG_QPNP_VM_BMS) += qpnp-vm-bms.o batterydata-lib.o batterydata-interface.o diff --git a/drivers/power/supply/qcom/batterydata-interface.c b/drivers/power/supply/qcom/batterydata-interface.c new file mode 100644 index 000000000000..01878279b0f5 --- /dev/null +++ b/drivers/power/supply/qcom/batterydata-interface.c @@ -0,0 +1,218 @@ +/* Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "BATTERY: %s: " fmt, __func__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct battery_data { + dev_t dev_no; + struct class *battery_class; + struct device *battery_device; + struct cdev battery_cdev; + struct bms_battery_data *profile; +}; +static struct battery_data *the_battery; + +static int battery_data_open(struct inode *inode, struct file *file) +{ + struct battery_data *battery = container_of(inode->i_cdev, + struct battery_data, battery_cdev); + + pr_debug("battery_data device opened\n"); + + file->private_data = battery; + + return 0; +} + +static long battery_data_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct battery_data *battery = file->private_data; + struct battery_params __user *bp_user = + (struct battery_params __user *)arg; + struct battery_params bp; + int soc, rbatt_sf, slope, fcc_mah; + int rc = 0; + + if (!battery->profile) { + pr_err("Battery data not set!\n"); + return -EINVAL; + } + if (copy_from_user(&bp, bp_user, sizeof(bp))) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + + switch (cmd) { + case BPIOCXSOC: + soc = interpolate_pc(battery->profile->pc_temp_ocv_lut, + bp.batt_temp, bp.ocv_uv / 1000); + rc = put_user(soc, &bp_user->soc); + if (rc) { + pr_err("BPIOCXSOC: Failed to 'put_user' rc=%d\n", rc); + goto ret_err; + } + pr_debug("BPIOCXSOC: ocv=%d batt_temp=%d soc=%d\n", + bp.ocv_uv / 1000, bp.batt_temp, soc); + break; + case BPIOCXRBATT: + rbatt_sf = interpolate_scalingfactor( + battery->profile->rbatt_sf_lut, + bp.batt_temp, bp.soc); + rc = put_user(rbatt_sf, &bp_user->rbatt_sf); + if (rc) { + pr_err("BPIOCXRBATT: Failed to 'put_user' rc=%d\n", rc); + goto ret_err; + } + pr_debug("BPIOCXRBATT: soc=%d batt_temp=%d rbatt_sf=%d\n", + bp.soc, bp.batt_temp, rbatt_sf); + break; + case BPIOCXSLOPE: + slope = interpolate_slope(battery->profile->pc_temp_ocv_lut, + bp.batt_temp, bp.soc); + rc = put_user(slope, &bp_user->slope); + if (rc) { + pr_err("BPIOCXSLOPE: Failed to 'put_user' rc=%d\n", rc); + goto ret_err; + } + pr_debug("BPIOCXSLOPE: soc=%d batt_temp=%d slope=%d\n", + bp.soc, bp.batt_temp, slope); + break; + case BPIOCXFCC: + fcc_mah = interpolate_fcc(battery->profile->fcc_temp_lut, + bp.batt_temp); + rc = put_user(fcc_mah, &bp_user->fcc_mah); + if (rc) { + pr_err("BPIOCXFCC: Failed to 'put_user' rc=%d\n", rc); + goto ret_err; + } + pr_debug("BPIOCXFCC: batt_temp=%d fcc_mah=%d\n", + bp.batt_temp, fcc_mah); + break; + default: + pr_err("IOCTL %d not supported\n", cmd); + rc = -EINVAL; + + } +ret_err: + return rc; +} + +static int battery_data_release(struct inode *inode, struct file *file) +{ + pr_debug("battery_data device closed\n"); + + return 0; +} + +static const struct file_operations battery_data_fops = { + .owner = THIS_MODULE, + .open = battery_data_open, + .unlocked_ioctl = battery_data_ioctl, + .compat_ioctl = battery_data_ioctl, + .release = battery_data_release, +}; + +int config_battery_data(struct bms_battery_data *profile) +{ + if (!the_battery) { + pr_err("Battery data not initialized\n"); + return -ENODEV; + } + + the_battery->profile = profile; + + pr_debug("Battery profile set - %s\n", + the_battery->profile->battery_type); + + return 0; +} + +static int batterydata_init(void) +{ + int rc; + struct battery_data *battery; + + battery = kzalloc(sizeof(*battery), GFP_KERNEL); + if (!battery) + return -ENOMEM; + + /* character device to access the battery-data from userspace */ + rc = alloc_chrdev_region(&battery->dev_no, 0, 1, "battery_data"); + if (rc) { + pr_err("Unable to allocate chrdev rc=%d\n", rc); + return rc; + } + cdev_init(&battery->battery_cdev, &battery_data_fops); + rc = cdev_add(&battery->battery_cdev, battery->dev_no, 1); + if (rc) { + pr_err("Unable to add battery_cdev rc=%d\n", rc); + goto unregister_chrdev; + } + + battery->battery_class = class_create(THIS_MODULE, "battery_data"); + if (IS_ERR_OR_NULL(battery->battery_class)) { + pr_err("Fail to create battery class\n"); + rc = -ENODEV; + goto delete_cdev; + } + + battery->battery_device = device_create(battery->battery_class, + NULL, battery->dev_no, + NULL, "battery_data"); + if (IS_ERR(battery->battery_device)) { + pr_err("Fail to create battery_device device\n"); + rc = -ENODEV; + goto delete_cdev; + } + + the_battery = battery; + + pr_info("Battery-data device created!\n"); + + return 0; + +delete_cdev: + cdev_del(&battery->battery_cdev); +unregister_chrdev: + unregister_chrdev_region(battery->dev_no, 1); + the_battery = NULL; + return rc; +} +subsys_initcall(batterydata_init); + +static void batterydata_exit(void) +{ + if (the_battery) { + device_destroy(the_battery->battery_class, the_battery->dev_no); + cdev_del(&the_battery->battery_cdev); + unregister_chrdev_region(the_battery->dev_no, 1); + } + kfree(the_battery); + the_battery = NULL; +} +module_exit(batterydata_exit); + +MODULE_DESCRIPTION("Battery-data Interface driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/qcom/batterydata-lib.c b/drivers/power/supply/qcom/batterydata-lib.c new file mode 100644 index 000000000000..fae5658067d4 --- /dev/null +++ b/drivers/power/supply/qcom/batterydata-lib.c @@ -0,0 +1,493 @@ +/* Copyright (c) 2012-2014, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include + +int linear_interpolate(int y0, int x0, int y1, int x1, int x) +{ + if (y0 == y1 || x == x0) + return y0; + if (x1 == x0 || x == x1) + return y1; + + return y0 + ((y1 - y0) * (x - x0) / (x1 - x0)); +} + +static int interpolate_single_lut_scaled(struct single_row_lut *lut, + int x, int scale) +{ + int i, result; + + if (x < lut->x[0] * scale) { + pr_debug("x %d less than known range return y = %d lut = %pS\n", + x, lut->y[0], lut); + return lut->y[0]; + } + if (x > lut->x[lut->cols - 1] * scale) { + pr_debug("x %d more than known range return y = %d lut = %pS\n", + x, lut->y[lut->cols - 1], lut); + return lut->y[lut->cols - 1]; + } + + for (i = 0; i < lut->cols; i++) + if (x <= lut->x[i] * scale) + break; + if (x == lut->x[i] * scale) { + result = lut->y[i]; + } else { + result = linear_interpolate( + lut->y[i - 1], + lut->x[i - 1] * scale, + lut->y[i], + lut->x[i] * scale, + x); + } + return result; +} + +int interpolate_fcc(struct single_row_lut *fcc_temp_lut, int batt_temp) +{ + return interpolate_single_lut_scaled(fcc_temp_lut, + batt_temp, + DEGC_SCALE); +} + +int interpolate_scalingfactor_fcc(struct single_row_lut *fcc_sf_lut, + int cycles) +{ + /* + * sf table could be null when no battery aging data is available, in + * that case return 100% + */ + if (fcc_sf_lut) + return interpolate_single_lut_scaled(fcc_sf_lut, cycles, 1); + else + return 100; +} + +int interpolate_scalingfactor(struct sf_lut *sf_lut, int row_entry, int pc) +{ + int i, scalefactorrow1, scalefactorrow2, scalefactor, rows, cols; + int row1 = 0; + int row2 = 0; + + /* + * sf table could be null when no battery aging data is available, in + * that case return 100% + */ + if (!sf_lut) + return 100; + + rows = sf_lut->rows; + cols = sf_lut->cols; + if (pc > sf_lut->percent[0]) { + pr_debug("pc %d greater than known pc ranges for sfd\n", pc); + row1 = 0; + row2 = 0; + } else if (pc < sf_lut->percent[rows - 1]) { + pr_debug("pc %d less than known pc ranges for sf\n", pc); + row1 = rows - 1; + row2 = rows - 1; + } else { + for (i = 0; i < rows; i++) { + if (pc == sf_lut->percent[i]) { + row1 = i; + row2 = i; + break; + } + if (pc > sf_lut->percent[i]) { + row1 = i - 1; + row2 = i; + break; + } + } + } + + if (row_entry < sf_lut->row_entries[0] * DEGC_SCALE) + row_entry = sf_lut->row_entries[0] * DEGC_SCALE; + if (row_entry > sf_lut->row_entries[cols - 1] * DEGC_SCALE) + row_entry = sf_lut->row_entries[cols - 1] * DEGC_SCALE; + + for (i = 0; i < cols; i++) + if (row_entry <= sf_lut->row_entries[i] * DEGC_SCALE) + break; + if (row_entry == sf_lut->row_entries[i] * DEGC_SCALE) { + scalefactor = linear_interpolate( + sf_lut->sf[row1][i], + sf_lut->percent[row1], + sf_lut->sf[row2][i], + sf_lut->percent[row2], + pc); + return scalefactor; + } + + scalefactorrow1 = linear_interpolate( + sf_lut->sf[row1][i - 1], + sf_lut->row_entries[i - 1] * DEGC_SCALE, + sf_lut->sf[row1][i], + sf_lut->row_entries[i] * DEGC_SCALE, + row_entry); + + scalefactorrow2 = linear_interpolate( + sf_lut->sf[row2][i - 1], + sf_lut->row_entries[i - 1] * DEGC_SCALE, + sf_lut->sf[row2][i], + sf_lut->row_entries[i] * DEGC_SCALE, + row_entry); + + scalefactor = linear_interpolate( + scalefactorrow1, + sf_lut->percent[row1], + scalefactorrow2, + sf_lut->percent[row2], + pc); + + return scalefactor; +} + +/* get ocv given a soc -- reverse lookup */ +int interpolate_ocv(struct pc_temp_ocv_lut *pc_temp_ocv, + int batt_temp, int pc) +{ + int i, ocvrow1, ocvrow2, ocv, rows, cols; + int row1 = 0; + int row2 = 0; + + rows = pc_temp_ocv->rows; + cols = pc_temp_ocv->cols; + if (pc > pc_temp_ocv->percent[0]) { + pr_debug("pc %d greater than known pc ranges for sfd\n", pc); + row1 = 0; + row2 = 0; + } else if (pc < pc_temp_ocv->percent[rows - 1]) { + pr_debug("pc %d less than known pc ranges for sf\n", pc); + row1 = rows - 1; + row2 = rows - 1; + } else { + for (i = 0; i < rows; i++) { + if (pc == pc_temp_ocv->percent[i]) { + row1 = i; + row2 = i; + break; + } + if (pc > pc_temp_ocv->percent[i]) { + row1 = i - 1; + row2 = i; + break; + } + } + } + + if (batt_temp < pc_temp_ocv->temp[0] * DEGC_SCALE) + batt_temp = pc_temp_ocv->temp[0] * DEGC_SCALE; + if (batt_temp > pc_temp_ocv->temp[cols - 1] * DEGC_SCALE) + batt_temp = pc_temp_ocv->temp[cols - 1] * DEGC_SCALE; + + for (i = 0; i < cols; i++) + if (batt_temp <= pc_temp_ocv->temp[i] * DEGC_SCALE) + break; + if (batt_temp == pc_temp_ocv->temp[i] * DEGC_SCALE) { + ocv = linear_interpolate( + pc_temp_ocv->ocv[row1][i], + pc_temp_ocv->percent[row1], + pc_temp_ocv->ocv[row2][i], + pc_temp_ocv->percent[row2], + pc); + return ocv; + } + + ocvrow1 = linear_interpolate( + pc_temp_ocv->ocv[row1][i - 1], + pc_temp_ocv->temp[i - 1] * DEGC_SCALE, + pc_temp_ocv->ocv[row1][i], + pc_temp_ocv->temp[i] * DEGC_SCALE, + batt_temp); + + ocvrow2 = linear_interpolate( + pc_temp_ocv->ocv[row2][i - 1], + pc_temp_ocv->temp[i - 1] * DEGC_SCALE, + pc_temp_ocv->ocv[row2][i], + pc_temp_ocv->temp[i] * DEGC_SCALE, + batt_temp); + + ocv = linear_interpolate( + ocvrow1, + pc_temp_ocv->percent[row1], + ocvrow2, + pc_temp_ocv->percent[row2], + pc); + + return ocv; +} + +int interpolate_pc(struct pc_temp_ocv_lut *pc_temp_ocv, + int batt_temp, int ocv) +{ + int i, j, pcj, pcj_minus_one, pc; + int rows = pc_temp_ocv->rows; + int cols = pc_temp_ocv->cols; + + if (batt_temp < pc_temp_ocv->temp[0] * DEGC_SCALE) { + pr_debug("batt_temp %d < known temp range\n", batt_temp); + batt_temp = pc_temp_ocv->temp[0] * DEGC_SCALE; + } + + if (batt_temp > pc_temp_ocv->temp[cols - 1] * DEGC_SCALE) { + pr_debug("batt_temp %d > known temp range\n", batt_temp); + batt_temp = pc_temp_ocv->temp[cols - 1] * DEGC_SCALE; + } + + for (j = 0; j < cols; j++) + if (batt_temp <= pc_temp_ocv->temp[j] * DEGC_SCALE) + break; + if (batt_temp == pc_temp_ocv->temp[j] * DEGC_SCALE) { + /* found an exact match for temp in the table */ + if (ocv >= pc_temp_ocv->ocv[0][j]) + return pc_temp_ocv->percent[0]; + if (ocv <= pc_temp_ocv->ocv[rows - 1][j]) + return pc_temp_ocv->percent[rows - 1]; + for (i = 0; i < rows; i++) { + if (ocv >= pc_temp_ocv->ocv[i][j]) { + if (ocv == pc_temp_ocv->ocv[i][j]) + return pc_temp_ocv->percent[i]; + pc = linear_interpolate( + pc_temp_ocv->percent[i], + pc_temp_ocv->ocv[i][j], + pc_temp_ocv->percent[i - 1], + pc_temp_ocv->ocv[i - 1][j], + ocv); + return pc; + } + } + } + + /* + * batt_temp is within temperature for + * column j-1 and j + */ + if (ocv >= pc_temp_ocv->ocv[0][j]) + return pc_temp_ocv->percent[0]; + if (ocv <= pc_temp_ocv->ocv[rows - 1][j - 1]) + return pc_temp_ocv->percent[rows - 1]; + + pcj_minus_one = 0; + pcj = 0; + for (i = 0; i < rows-1; i++) { + if (pcj == 0 + && is_between(pc_temp_ocv->ocv[i][j], + pc_temp_ocv->ocv[i+1][j], ocv)) { + pcj = linear_interpolate( + pc_temp_ocv->percent[i], + pc_temp_ocv->ocv[i][j], + pc_temp_ocv->percent[i + 1], + pc_temp_ocv->ocv[i+1][j], + ocv); + } + + if (pcj_minus_one == 0 + && is_between(pc_temp_ocv->ocv[i][j-1], + pc_temp_ocv->ocv[i+1][j-1], ocv)) { + pcj_minus_one = linear_interpolate( + pc_temp_ocv->percent[i], + pc_temp_ocv->ocv[i][j-1], + pc_temp_ocv->percent[i + 1], + pc_temp_ocv->ocv[i+1][j-1], + ocv); + } + + if (pcj && pcj_minus_one) { + pc = linear_interpolate( + pcj_minus_one, + pc_temp_ocv->temp[j-1] * DEGC_SCALE, + pcj, + pc_temp_ocv->temp[j] * DEGC_SCALE, + batt_temp); + return pc; + } + } + + if (pcj) + return pcj; + + if (pcj_minus_one) + return pcj_minus_one; + + pr_debug("%d ocv wasn't found for temp %d in the LUT returning 100%%\n", + ocv, batt_temp); + return 100; +} + +int interpolate_slope(struct pc_temp_ocv_lut *pc_temp_ocv, + int batt_temp, int pc) +{ + int i, ocvrow1, ocvrow2, rows, cols; + int row1 = 0; + int row2 = 0; + int slope; + + rows = pc_temp_ocv->rows; + cols = pc_temp_ocv->cols; + if (pc >= pc_temp_ocv->percent[0]) { + pr_debug("pc %d >= max pc range - use the slope at pc=%d\n", + pc, pc_temp_ocv->percent[0]); + row1 = 0; + row2 = 1; + } else if (pc <= pc_temp_ocv->percent[rows - 1]) { + pr_debug("pc %d is <= min pc range - use the slope at pc=%d\n", + pc, pc_temp_ocv->percent[rows - 1]); + row1 = rows - 2; + row2 = rows - 1; + } else { + for (i = 0; i < rows; i++) { + if (pc == pc_temp_ocv->percent[i]) { + row1 = i - 1; + row2 = i; + break; + } + if (pc > pc_temp_ocv->percent[i]) { + row1 = i - 1; + row2 = i; + break; + } + } + } + + if (batt_temp < pc_temp_ocv->temp[0] * DEGC_SCALE) + batt_temp = pc_temp_ocv->temp[0] * DEGC_SCALE; + if (batt_temp > pc_temp_ocv->temp[cols - 1] * DEGC_SCALE) + batt_temp = pc_temp_ocv->temp[cols - 1] * DEGC_SCALE; + + for (i = 0; i < cols; i++) + if (batt_temp <= pc_temp_ocv->temp[i] * DEGC_SCALE) + break; + + if (batt_temp == pc_temp_ocv->temp[i] * DEGC_SCALE) { + slope = (pc_temp_ocv->ocv[row1][i] - + pc_temp_ocv->ocv[row2][i]); + if (slope <= 0) { + pr_warn("Slope=%d for pc=%d, using 1\n", slope, pc); + slope = 1; + } + slope *= 1000; + slope /= (pc_temp_ocv->percent[row1] - + pc_temp_ocv->percent[row2]); + return slope; + } + ocvrow1 = linear_interpolate( + pc_temp_ocv->ocv[row1][i - 1], + pc_temp_ocv->temp[i - 1] * DEGC_SCALE, + pc_temp_ocv->ocv[row1][i], + pc_temp_ocv->temp[i] * DEGC_SCALE, + batt_temp); + + ocvrow2 = linear_interpolate( + pc_temp_ocv->ocv[row2][i - 1], + pc_temp_ocv->temp[i - 1] * DEGC_SCALE, + pc_temp_ocv->ocv[row2][i], + pc_temp_ocv->temp[i] * DEGC_SCALE, + batt_temp); + + slope = (ocvrow1 - ocvrow2); + if (slope <= 0) { + pr_warn("Slope=%d for pc=%d, using 1\n", slope, pc); + slope = 1; + } + slope *= 1000; + slope /= (pc_temp_ocv->percent[row1] - pc_temp_ocv->percent[row2]); + + return slope; +} + + +int interpolate_acc(struct ibat_temp_acc_lut *ibat_acc_lut, + int batt_temp, int ibat) +{ + int i, accrow1, accrow2, rows, cols; + int row1 = 0; + int row2 = 0; + int acc; + + rows = ibat_acc_lut->rows; + cols = ibat_acc_lut->cols; + + if (ibat > ibat_acc_lut->ibat[rows - 1]) { + pr_debug("ibatt(%d) > max range(%d)\n", ibat, + ibat_acc_lut->ibat[rows - 1]); + row1 = rows - 1; + row2 = rows - 2; + } else if (ibat < ibat_acc_lut->ibat[0]) { + pr_debug("ibatt(%d) < max range(%d)\n", ibat, + ibat_acc_lut->ibat[0]); + row1 = 0; + row2 = 0; + } else { + for (i = 0; i < rows; i++) { + if (ibat == ibat_acc_lut->ibat[i]) { + row1 = i; + row2 = i; + break; + } + if (ibat < ibat_acc_lut->ibat[i]) { + row1 = i; + row2 = i - 1; + break; + } + } + } + + if (batt_temp < ibat_acc_lut->temp[0] * DEGC_SCALE) + batt_temp = ibat_acc_lut->temp[0] * DEGC_SCALE; + if (batt_temp > ibat_acc_lut->temp[cols - 1] * DEGC_SCALE) + batt_temp = ibat_acc_lut->temp[cols - 1] * DEGC_SCALE; + + for (i = 0; i < cols; i++) + if (batt_temp <= ibat_acc_lut->temp[i] * DEGC_SCALE) + break; + + if (batt_temp == (ibat_acc_lut->temp[i] * DEGC_SCALE)) { + acc = linear_interpolate( + ibat_acc_lut->acc[row1][i], + ibat_acc_lut->ibat[row1], + ibat_acc_lut->acc[row2][i], + ibat_acc_lut->ibat[row2], + ibat); + return acc; + } + + accrow1 = linear_interpolate( + ibat_acc_lut->acc[row1][i - 1], + ibat_acc_lut->temp[i - 1] * DEGC_SCALE, + ibat_acc_lut->acc[row1][i], + ibat_acc_lut->temp[i] * DEGC_SCALE, + batt_temp); + + accrow2 = linear_interpolate( + ibat_acc_lut->acc[row2][i - 1], + ibat_acc_lut->temp[i - 1] * DEGC_SCALE, + ibat_acc_lut->acc[row2][i], + ibat_acc_lut->temp[i] * DEGC_SCALE, + batt_temp); + + acc = linear_interpolate(accrow1, + ibat_acc_lut->ibat[row1], + accrow2, + ibat_acc_lut->ibat[row2], + ibat); + + if (acc < 0) + acc = 0; + + return acc; +} diff --git a/drivers/power/supply/qcom/qpnp-vm-bms.c b/drivers/power/supply/qcom/qpnp-vm-bms.c new file mode 100644 index 000000000000..042ce99d6b98 --- /dev/null +++ b/drivers/power/supply/qcom/qpnp-vm-bms.c @@ -0,0 +1,4255 @@ +/* Copyright (c) 2014-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define pr_fmt(fmt) "VBMS: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _BMS_MASK(BITS, POS) \ + ((unsigned char)(((1 << (BITS)) - 1) << (POS))) +#define BMS_MASK(LEFT_BIT_POS, RIGHT_BIT_POS) \ + _BMS_MASK((LEFT_BIT_POS) - (RIGHT_BIT_POS) + 1, \ + (RIGHT_BIT_POS)) + +/* Config / Data registers */ +#define REVISION1_REG 0x0 +#define STATUS1_REG 0x8 +#define FSM_STATE_MASK BMS_MASK(5, 3) +#define FSM_STATE_SHIFT 3 + +#define STATUS2_REG 0x9 +#define FIFO_CNT_SD_MASK BMS_MASK(7, 4) +#define FIFO_CNT_SD_SHIFT 4 + +#define MODE_CTL_REG 0x40 +#define FORCE_S3_MODE BIT(0) +#define ENABLE_S3_MODE BIT(1) +#define FORCE_S2_MODE BIT(2) +#define ENABLE_S2_MODE BIT(3) +#define S2_MODE_MASK BMS_MASK(3, 2) +#define S3_MODE_MASK BMS_MASK(1, 0) + +#define DATA_CTL1_REG 0x42 +#define MASTER_HOLD_BIT BIT(0) + +#define DATA_CTL2_REG 0x43 +#define FIFO_CNT_SD_CLR_BIT BIT(2) +#define ACC_DATA_SD_CLR_BIT BIT(1) +#define ACC_CNT_SD_CLR_BIT BIT(0) + +#define S3_OCV_TOL_CTL_REG 0x44 + +#define EN_CTL_REG 0x46 +#define BMS_EN_BIT BIT(7) + +#define FIFO_LENGTH_REG 0x47 +#define S1_FIFO_LENGTH_MASK BMS_MASK(3, 0) +#define S2_FIFO_LENGTH_MASK BMS_MASK(7, 4) +#define S2_FIFO_LENGTH_SHIFT 4 + +#define S1_SAMPLE_INTVL_REG 0x55 +#define S2_SAMPLE_INTVL_REG 0x56 +#define S3_SAMPLE_INTVL_REG 0x57 + +#define S1_ACC_CNT_REG 0x5E +#define S2_ACC_CNT_REG 0x5F +#define ACC_CNT_MASK BMS_MASK(2, 0) + +#define ACC_DATA0_SD_REG 0x63 +#define ACC_CNT_SD_REG 0x67 +#define OCV_DATA0_REG 0x6A +#define FIFO_0_LSB_REG 0xC0 + +#define BMS_SOC_REG 0xB0 +#define BMS_OCV_REG 0xB1 /* B1 & B2 */ +#define SOC_STORAGE_MASK 0xFE + +#define CHARGE_INCREASE_STORAGE 0xB3 +#define CHARGE_CYCLE_STORAGE_LSB 0xB4 /* B4 & B5 */ + +#define SEC_ACCESS 0xD0 + +#define QPNP_CHARGER_PRESENT BIT(7) + +/* Constants */ +#define OCV_TOL_LSB_UV 300 +#define MAX_OCV_TOL_THRESHOLD (OCV_TOL_LSB_UV * 0xFF) +#define MAX_SAMPLE_COUNT 256 +#define MAX_SAMPLE_INTERVAL 2550 +#define BMS_READ_TIMEOUT 500 +#define BMS_DEFAULT_TEMP 250 +#define OCV_INVALID 0xFFFF +#define SOC_INVALID 0xFF +#define OCV_UNINITIALIZED 0xFFFF +#define VBATT_ERROR_MARGIN 20000 +#define CV_DROP_MARGIN 10000 +#define MIN_OCV_UV 2000000 +#define TIME_PER_PERCENT_UUC 60 +#define IAVG_SAMPLES 16 +#define MIN_SOC_UUC 3 + +#define QPNP_VM_BMS_DEV_NAME "qcom,qpnp-vm-bms" + +/* indicates the state of BMS */ +enum { + IDLE_STATE, + S1_STATE, + S2_STATE, + S3_STATE, + S7_STATE, +}; + +enum { + WRKARND_PON_OCV_COMP = BIT(0), +}; + +struct bms_irq { + int irq; + unsigned long disabled; +}; + +struct bms_wakeup_source { + struct wakeup_source source; + unsigned long disabled; +}; + +struct temp_curr_comp_map { + int temp_decideg; + int current_ma; +}; + +struct bms_dt_cfg { + bool cfg_report_charger_eoc; + bool cfg_force_bms_active_on_charger; + bool cfg_force_s3_on_suspend; + bool cfg_ignore_shutdown_soc; + bool cfg_use_voltage_soc; + int cfg_v_cutoff_uv; + int cfg_max_voltage_uv; + int cfg_r_conn_mohm; + int cfg_shutdown_soc_valid_limit; + int cfg_low_soc_calc_threshold; + int cfg_low_soc_calculate_soc_ms; + int cfg_low_voltage_threshold; + int cfg_low_voltage_calculate_soc_ms; + int cfg_low_soc_fifo_length; + int cfg_calculate_soc_ms; + int cfg_voltage_soc_timeout_ms; + int cfg_s1_sample_interval_ms; + int cfg_s2_sample_interval_ms; + int cfg_s1_sample_count; + int cfg_s2_sample_count; + int cfg_s1_fifo_length; + int cfg_s2_fifo_length; + int cfg_disable_bms; + int cfg_s3_ocv_tol_uv; + int cfg_soc_resume_limit; + int cfg_low_temp_threshold; + int cfg_ibat_avg_samples; + int cfg_battery_aging_comp; + bool cfg_use_reported_soc; +}; + +struct qpnp_bms_chip { + struct device *dev; + struct platform_device *pdev; + struct regmap *regmap; + dev_t dev_no; + u16 base; + u8 revision[2]; + u32 batt_pres_addr; + u32 chg_pres_addr; + + /* status variables */ + u8 current_fsm_state; + bool last_soc_invalid; + bool warm_reset; + bool bms_psy_registered; + bool battery_full; + bool bms_dev_open; + bool data_ready; + bool apply_suspend_config; + bool in_cv_state; + bool low_soc_fifo_set; + int battery_status; + int calculated_soc; + int current_now; + int prev_current_now; + int prev_voltage_based_soc; + int calculate_soc_ms; + int voltage_soc_uv; + int battery_present; + int last_soc; + int last_soc_unbound; + int last_soc_change_sec; + int charge_start_tm_sec; + int catch_up_time_sec; + int delta_time_s; + int uuc_delta_time_s; + int ocv_at_100; + int last_ocv_uv; + int s2_fifo_length; + int last_acc; + int hi_power_state; + unsigned int vadc_v0625; + unsigned int vadc_v1250; + unsigned long tm_sec; + unsigned long workaround_flag; + unsigned long uuc_tm_sec; + u32 seq_num; + u8 shutdown_soc; + bool shutdown_soc_invalid; + u16 last_ocv_raw; + u32 shutdown_ocv; + bool suspend_data_valid; + int iavg_num_samples; + unsigned int iavg_index; + int iavg_samples_ma[IAVG_SAMPLES]; + int iavg_ma; + int prev_soc_uuc; + int eoc_reported; + u8 charge_increase; + u16 charge_cycles; + unsigned int start_soc; + unsigned int end_soc; + unsigned int chg_start_soc; + + struct bms_battery_data *batt_data; + struct bms_dt_cfg dt; + + struct dentry *debug_root; + struct bms_wakeup_source vbms_lv_wake_source; + struct bms_wakeup_source vbms_cv_wake_source; + struct bms_wakeup_source vbms_soc_wake_source; + wait_queue_head_t bms_wait_q; + struct delayed_work monitor_soc_work; + struct delayed_work voltage_soc_timeout_work; + struct mutex bms_data_mutex; + struct mutex bms_device_mutex; + struct mutex last_soc_mutex; + struct mutex state_change_mutex; + struct class *bms_class; + struct device *bms_device; + struct cdev bms_cdev; + struct qpnp_vm_bms_data bms_data; + struct qpnp_vadc_chip *vadc_dev; + struct qpnp_adc_tm_chip *adc_tm_dev; + struct pmic_revid_data *revid_data; + struct qpnp_adc_tm_btm_param vbat_monitor_params; + struct bms_irq fifo_update_done_irq; + struct bms_irq fsm_state_change_irq; + struct power_supply_desc bms_psy_d; + struct power_supply *bms_psy; + struct power_supply *batt_psy; + struct power_supply *usb_psy; + bool reported_soc_in_use; + bool charger_removed_since_full; + bool charger_reinserted; + bool reported_soc_high_current; + int reported_soc; + int reported_soc_change_sec; + int reported_soc_delta; +}; + +static struct qpnp_bms_chip *the_chip; + +static struct temp_curr_comp_map temp_curr_comp_lut[] = { + {-300, 15}, + {250, 17}, + {850, 28}, +}; + +static void disable_bms_irq(struct bms_irq *irq) +{ + if (!__test_and_set_bit(0, &irq->disabled)) { + disable_irq(irq->irq); + pr_debug("disabled irq %d\n", irq->irq); + } +} + +static void enable_bms_irq(struct bms_irq *irq) +{ + if (__test_and_clear_bit(0, &irq->disabled)) { + enable_irq(irq->irq); + pr_debug("enable irq %d\n", irq->irq); + } +} + +static void bms_stay_awake(struct bms_wakeup_source *source) +{ + if (__test_and_clear_bit(0, &source->disabled)) { + __pm_stay_awake(&source->source); + pr_debug("enabled source %s\n", source->source.name); + } +} + +static void bms_relax(struct bms_wakeup_source *source) +{ + if (!__test_and_set_bit(0, &source->disabled)) { + __pm_relax(&source->source); + pr_debug("disabled source %s\n", source->source.name); + } +} + +static bool bms_wake_active(struct bms_wakeup_source *source) +{ + return !source->disabled; +} + +static int bound_soc(int soc) +{ + soc = max(0, soc); + soc = min(100, soc); + + return soc; +} + +static char *qpnp_vm_bms_supplicants[] = { + "battery", +}; + +static int qpnp_read_wrapper(struct qpnp_bms_chip *chip, u8 *val, + u16 base, int count) +{ + int rc; + + rc = regmap_bulk_read(chip->regmap, base, val, count); + if (rc) + pr_err("Regmap read failed rc=%d\n", rc); + + return rc; +} + +static int qpnp_write_wrapper(struct qpnp_bms_chip *chip, u8 *val, + u16 base, int count) +{ + int rc; + + rc = regmap_bulk_write(chip->regmap, base, val, count); + if (rc) + pr_err("Regmap write failed rc=%d\n", rc); + + return rc; +} + +static int qpnp_masked_write_base(struct qpnp_bms_chip *chip, u16 addr, + u8 mask, u8 val) +{ + int rc; + u8 reg; + + rc = qpnp_read_wrapper(chip, ®, addr, 1); + if (rc) { + pr_err("read failed addr = %03X, rc = %d\n", addr, rc); + return rc; + } + reg &= ~mask; + reg |= val & mask; + rc = qpnp_write_wrapper(chip, ®, addr, 1); + if (rc) + pr_err("write failed addr = %03X, val = %02x, mask = %02x, reg = %02x, rc = %d\n", + addr, val, mask, reg, rc); + + return rc; +} + +static int qpnp_secure_write_wrapper(struct qpnp_bms_chip *chip, u8 *val, + u16 base) +{ + int rc; + u8 reg; + + reg = 0xA5; + rc = qpnp_write_wrapper(chip, ®, chip->base + SEC_ACCESS, 1); + if (rc) { + pr_err("Error %d writing 0xA5 to 0x%x reg\n", + rc, SEC_ACCESS); + return rc; + } + rc = qpnp_write_wrapper(chip, val, base, 1); + if (rc) + pr_err("Error %d writing %d to 0x%x reg\n", rc, *val, base); + + return rc; +} + +static int backup_ocv_soc(struct qpnp_bms_chip *chip, int ocv_uv, int soc) +{ + int rc; + u16 ocv_mv = ocv_uv / 1000; + + rc = qpnp_write_wrapper(chip, (u8 *)&ocv_mv, + chip->base + BMS_OCV_REG, 2); + if (rc) + pr_err("Unable to backup OCV rc=%d\n", rc); + + rc = qpnp_masked_write_base(chip, chip->base + BMS_SOC_REG, + SOC_STORAGE_MASK, (soc + 1) << 1); + if (rc) + pr_err("Unable to backup SOC rc=%d\n", rc); + + pr_debug("ocv_mv=%d soc=%d\n", ocv_mv, soc); + + return rc; +} + +static int get_current_time(unsigned long *now_tm_sec) +{ + struct rtc_time tm; + struct rtc_device *rtc; + int rc; + + rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + if (rtc == NULL) { + pr_err("%s: unable to open rtc device (%s)\n", + __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); + return -EINVAL; + } + + rc = rtc_read_time(rtc, &tm); + if (rc) { + pr_err("Error reading rtc device (%s) : %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + + rc = rtc_valid_tm(&tm); + if (rc) { + pr_err("Invalid RTC time (%s): %d\n", + CONFIG_RTC_HCTOSYS_DEVICE, rc); + goto close_time; + } + rtc_tm_to_time(&tm, now_tm_sec); + +close_time: + rtc_class_close(rtc); + return rc; +} + +static int calculate_delta_time(unsigned long *time_stamp, int *delta_time_s) +{ + unsigned long now_tm_sec = 0; + + /* default to delta time = 0 if anything fails */ + *delta_time_s = 0; + + if (get_current_time(&now_tm_sec)) { + pr_err("RTC read failed\n"); + return 0; + } + + *delta_time_s = (now_tm_sec - *time_stamp); + + /* remember this time */ + *time_stamp = now_tm_sec; + return 0; +} + +static bool is_charger_present(struct qpnp_bms_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (chip->usb_psy == NULL) + chip->usb_psy = power_supply_get_by_name("usb"); + if (chip->usb_psy) { + power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &ret); + return ret.intval; + } + + return false; +} + +static bool is_battery_charging(struct qpnp_bms_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (chip->batt_psy == NULL) + chip->batt_psy = power_supply_get_by_name("battery"); + if (chip->batt_psy) { + /* if battery has been registered, use the type property */ + power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &ret); + return ret.intval != POWER_SUPPLY_CHARGE_TYPE_NONE; + } + + /* Default to false if the battery power supply is not registered. */ + pr_debug("battery power supply is not registered\n"); + return false; +} + +#define BAT_PRES_BIT BIT(7) +static bool is_battery_present(struct qpnp_bms_chip *chip) +{ + union power_supply_propval ret = {0,}; + int rc; + u8 batt_pres; + + /* first try to use the batt_pres register if given */ + if (chip->batt_pres_addr) { + rc = qpnp_read_wrapper(chip, &batt_pres, + chip->batt_pres_addr, 1); + if (!rc && (batt_pres & BAT_PRES_BIT)) + return true; + else + return false; + } + if (chip->batt_psy == NULL) + chip->batt_psy = power_supply_get_by_name("battery"); + if (chip->batt_psy) { + /* if battery has been registered, use the present property */ + power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_PRESENT, &ret); + return ret.intval; + } + + /* Default to false if the battery power supply is not registered. */ + pr_debug("battery power supply is not registered\n"); + return false; +} + +#define BAT_REMOVED_OFFMODE_BIT BIT(6) +static bool is_battery_replaced_in_offmode(struct qpnp_bms_chip *chip) +{ + u8 batt_pres; + int rc; + + if (chip->batt_pres_addr) { + rc = qpnp_read_wrapper(chip, &batt_pres, + chip->batt_pres_addr, 1); + pr_debug("offmode removed: %02x\n", batt_pres); + if (!rc && (batt_pres & BAT_REMOVED_OFFMODE_BIT)) + return true; + } + + return false; +} + +static bool is_battery_taper_charging(struct qpnp_bms_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (chip->batt_psy == NULL) + chip->batt_psy = power_supply_get_by_name("battery"); + + if (chip->batt_psy) { + power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &ret); + return ret.intval == POWER_SUPPLY_CHARGE_TYPE_TAPER; + } + + return false; +} + +static int master_hold_control(struct qpnp_bms_chip *chip, bool enable) +{ + u8 reg = 0; + int rc; + + reg = enable ? MASTER_HOLD_BIT : 0; + + rc = qpnp_secure_write_wrapper(chip, ®, + chip->base + DATA_CTL1_REG); + if (rc) + pr_err("Unable to write reg=%x rc=%d\n", DATA_CTL1_REG, rc); + + return rc; +} + +static int force_fsm_state(struct qpnp_bms_chip *chip, u8 state) +{ + int rc; + u8 mode_ctl = 0; + + switch (state) { + case S2_STATE: + mode_ctl = (FORCE_S2_MODE | ENABLE_S2_MODE); + break; + case S3_STATE: + mode_ctl = (FORCE_S3_MODE | ENABLE_S3_MODE); + break; + default: + pr_debug("Invalid state %d\n", state); + return -EINVAL; + } + + rc = qpnp_secure_write_wrapper(chip, &mode_ctl, + chip->base + MODE_CTL_REG); + if (rc) { + pr_err("Unable to write reg=%x rc=%d\n", MODE_CTL_REG, rc); + return rc; + } + /* delay for the FSM state to take affect in hardware */ + usleep_range(500, 600); + + pr_debug("force_mode=%d mode_cntl_reg=%x\n", state, mode_ctl); + + return 0; +} + +static int get_sample_interval(struct qpnp_bms_chip *chip, + u8 fsm_state, u32 *interval) +{ + int rc; + u8 val = 0, reg; + + *interval = 0; + + switch (fsm_state) { + case S1_STATE: + reg = S1_SAMPLE_INTVL_REG; + break; + case S2_STATE: + reg = S2_SAMPLE_INTVL_REG; + break; + case S3_STATE: + reg = S3_SAMPLE_INTVL_REG; + break; + default: + pr_err("Invalid state %d\n", fsm_state); + return -EINVAL; + } + + rc = qpnp_read_wrapper(chip, &val, chip->base + reg, 1); + if (rc) { + pr_err("Failed to get state(%d) sample_interval, rc=%d\n", + fsm_state, rc); + return rc; + } + + *interval = val * 10; + + return 0; +} + +static int get_sample_count(struct qpnp_bms_chip *chip, + u8 fsm_state, u32 *count) +{ + int rc; + u8 val = 0, reg; + + *count = 0; + + switch (fsm_state) { + case S1_STATE: + reg = S1_ACC_CNT_REG; + break; + case S2_STATE: + reg = S2_ACC_CNT_REG; + break; + default: + pr_err("Invalid state %d\n", fsm_state); + return -EINVAL; + } + + rc = qpnp_read_wrapper(chip, &val, chip->base + reg, 1); + if (rc) { + pr_err("Failed to get state(%d) sample_count, rc=%d\n", + fsm_state, rc); + return rc; + } + val &= ACC_CNT_MASK; + + *count = val ? (1 << (val + 1)) : 1; + + return 0; +} + +static int get_fifo_length(struct qpnp_bms_chip *chip, + u8 fsm_state, u32 *fifo_length) +{ + int rc; + u8 val = 0, reg, mask = 0, shift = 0; + + *fifo_length = 0; + + switch (fsm_state) { + case S1_STATE: + reg = FIFO_LENGTH_REG; + mask = S1_FIFO_LENGTH_MASK; + shift = 0; + break; + case S2_STATE: + reg = FIFO_LENGTH_REG; + mask = S2_FIFO_LENGTH_MASK; + shift = S2_FIFO_LENGTH_SHIFT; + break; + default: + pr_err("Invalid state %d\n", fsm_state); + return -EINVAL; + } + + rc = qpnp_read_wrapper(chip, &val, chip->base + reg, 1); + if (rc) { + pr_err("Failed to get state(%d) fifo_length, rc=%d\n", + fsm_state, rc); + return rc; + } + + val &= mask; + val >>= shift; + + *fifo_length = val; + + return 0; +} + +static int set_fifo_length(struct qpnp_bms_chip *chip, + u8 fsm_state, u32 fifo_length) +{ + int rc; + u8 reg, mask = 0, shift = 0; + + /* fifo_length of 1 is not supported due to a hardware issue */ + if ((fifo_length <= 1) || (fifo_length > MAX_FIFO_REGS)) { + pr_err("Invalid FIFO length = %d\n", fifo_length); + return -EINVAL; + } + + switch (fsm_state) { + case S1_STATE: + reg = FIFO_LENGTH_REG; + mask = S1_FIFO_LENGTH_MASK; + shift = 0; + break; + case S2_STATE: + reg = FIFO_LENGTH_REG; + mask = S2_FIFO_LENGTH_MASK; + shift = S2_FIFO_LENGTH_SHIFT; + break; + default: + pr_err("Invalid state %d\n", fsm_state); + return -EINVAL; + } + + rc = master_hold_control(chip, true); + if (rc) + pr_err("Unable to apply master_hold rc=%d\n", rc); + + rc = qpnp_masked_write_base(chip, chip->base + reg, mask, + fifo_length << shift); + if (rc) + pr_err("Unable to set fifo length rc=%d\n", rc); + + rc = master_hold_control(chip, false); + if (rc) + pr_err("Unable to apply master_hold rc=%d\n", rc); + + return rc; +} + +static int get_fsm_state(struct qpnp_bms_chip *chip, u8 *state) +{ + int rc; + + /* + * To read the STATUS1 register, write a value(any) to this register, + * wait for 10ms and then read the register. + */ + *state = 0; + rc = qpnp_write_wrapper(chip, state, chip->base + STATUS1_REG, 1); + if (rc) { + pr_err("Unable to write STATUS1_REG rc=%d\n", rc); + return rc; + } + usleep_range(10000, 11000); + + /* read the current FSM state */ + rc = qpnp_read_wrapper(chip, state, chip->base + STATUS1_REG, 1); + if (rc) { + pr_err("Unable to read STATUS1_REG rc=%d\n", rc); + return rc; + } + *state = (*state & FSM_STATE_MASK) >> FSM_STATE_SHIFT; + + return rc; +} + +static int update_fsm_state(struct qpnp_bms_chip *chip) +{ + u8 state = 0; + int rc; + + mutex_lock(&chip->state_change_mutex); + rc = get_fsm_state(chip, &state); + if (rc) { + pr_err("Unable to get fsm_state rc=%d\n", rc); + goto fail_fsm; + } + + chip->current_fsm_state = state; + +fail_fsm: + mutex_unlock(&chip->state_change_mutex); + return rc; +} + +static int backup_charge_cycle(struct qpnp_bms_chip *chip) +{ + int rc = 0; + + if (chip->charge_increase >= 0) { + rc = qpnp_write_wrapper(chip, &chip->charge_increase, + chip->base + CHARGE_INCREASE_STORAGE, 1); + if (rc) + pr_err("Unable to backup charge_increase rc=%d\n", rc); + } + + if (chip->charge_cycles >= 0) { + rc = qpnp_write_wrapper(chip, (u8 *)&chip->charge_cycles, + chip->base + CHARGE_CYCLE_STORAGE_LSB, 2); + if (rc) + pr_err("Unable to backup charge_cycles rc=%d\n", rc); + } + + pr_debug("%s storing charge_increase=%u charge_cycle=%u\n", + rc ? "Unable to" : "Successfully", + chip->charge_increase, chip->charge_cycles); + + return rc; +} + +static int read_chgcycle_data_from_backup(struct qpnp_bms_chip *chip) +{ + int rc; + uint16_t temp_u16 = 0; + u8 temp_u8 = 0; + + rc = qpnp_read_wrapper(chip, &temp_u8, + chip->base + CHARGE_INCREASE_STORAGE, 1); + if (rc) { + pr_err("Unable to read charge_increase rc=%d\n", rc); + return rc; + } + + rc = qpnp_read_wrapper(chip, (u8 *)&temp_u16, + chip->base + CHARGE_CYCLE_STORAGE_LSB, 2); + if (rc) { + pr_err("Unable to read charge_cycle rc=%d\n", rc); + return rc; + } + + if ((temp_u8 == 0xFF) || (temp_u16 == 0xFFFF)) { + chip->charge_cycles = 0; + chip->charge_increase = 0; + pr_info("rejecting aging data charge_increase=%u charge_cycle=%u\n", + temp_u8, temp_u16); + rc = backup_charge_cycle(chip); + if (rc) + pr_err("Unable to reset charge cycles rc=%d\n", rc); + } else { + chip->charge_increase = temp_u8; + chip->charge_cycles = temp_u16; + } + + pr_debug("charge_increase=%u charge_cycle=%u\n", + chip->charge_increase, chip->charge_cycles); + return rc; +} + +static int calculate_uuc_iavg(struct qpnp_bms_chip *chip) +{ + int i; + int iavg_ma = chip->current_now / 1000; + + /* only continue if ibat has changed */ + if (chip->current_now == chip->prev_current_now) + goto ibat_unchanged; + else + chip->prev_current_now = chip->current_now; + + chip->iavg_samples_ma[chip->iavg_index] = iavg_ma; + chip->iavg_index = (chip->iavg_index + 1) % + chip->dt.cfg_ibat_avg_samples; + chip->iavg_num_samples++; + if (chip->iavg_num_samples >= chip->dt.cfg_ibat_avg_samples) + chip->iavg_num_samples = chip->dt.cfg_ibat_avg_samples; + + if (chip->iavg_num_samples) { + iavg_ma = 0; + /* maintain a 16 sample average of ibat */ + for (i = 0; i < chip->iavg_num_samples; i++) { + pr_debug("iavg_samples_ma[%d] = %d\n", i, + chip->iavg_samples_ma[i]); + iavg_ma += chip->iavg_samples_ma[i]; + } + + chip->iavg_ma = DIV_ROUND_CLOSEST(iavg_ma, + chip->iavg_num_samples); + } + +ibat_unchanged: + pr_debug("current_now_ma=%d averaged_iavg_ma=%d\n", + chip->current_now / 1000, chip->iavg_ma); + + return chip->iavg_ma; +} + +static int adjust_uuc(struct qpnp_bms_chip *chip, int soc_uuc) +{ + int max_percent_change; + + calculate_delta_time(&chip->uuc_tm_sec, &chip->uuc_delta_time_s); + + /* make sure that the UUC changes 1% at a time */ + max_percent_change = max(chip->uuc_delta_time_s + / TIME_PER_PERCENT_UUC, 1); + + if (chip->prev_soc_uuc == -EINVAL) { + /* start with a minimum UUC if the initial UUC is high */ + if (soc_uuc > MIN_SOC_UUC) + chip->prev_soc_uuc = MIN_SOC_UUC; + else + chip->prev_soc_uuc = soc_uuc; + } else { + if (abs(chip->prev_soc_uuc - soc_uuc) <= max_percent_change) + chip->prev_soc_uuc = soc_uuc; + else if (soc_uuc > chip->prev_soc_uuc) + chip->prev_soc_uuc += max_percent_change; + else + chip->prev_soc_uuc -= max_percent_change; + } + + pr_debug("soc_uuc=%d new_soc_uuc=%d\n", soc_uuc, chip->prev_soc_uuc); + + return chip->prev_soc_uuc; +} + +static int lookup_soc_ocv(struct qpnp_bms_chip *chip, int ocv_uv, int batt_temp) +{ + int soc_ocv = 0, soc_cutoff = 0, soc_final = 0; + int fcc, acc, soc_uuc = 0, soc_acc = 0, iavg_ma = 0; + + soc_ocv = interpolate_pc(chip->batt_data->pc_temp_ocv_lut, + batt_temp, ocv_uv / 1000); + soc_cutoff = interpolate_pc(chip->batt_data->pc_temp_ocv_lut, + batt_temp, chip->dt.cfg_v_cutoff_uv / 1000); + + soc_final = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_cutoff), + (100 - soc_cutoff)); + + if (chip->batt_data->ibat_acc_lut) { + /* Apply ACC logic only if we discharging */ + if (chip->current_now > 0) { + + /* + * IBAT averaging is disabled at low temp. + * allowing the SOC to catcup quickly. + */ + if (batt_temp > chip->dt.cfg_low_temp_threshold) + iavg_ma = calculate_uuc_iavg(chip); + else + iavg_ma = chip->current_now / 1000; + + fcc = interpolate_fcc(chip->batt_data->fcc_temp_lut, + batt_temp); + acc = interpolate_acc(chip->batt_data->ibat_acc_lut, + batt_temp, iavg_ma); + if (acc <= 0) { + if (chip->last_acc) + acc = chip->last_acc; + else + acc = fcc; + } + soc_uuc = ((fcc - acc) * 100) / fcc; + + if (batt_temp > chip->dt.cfg_low_temp_threshold) + soc_uuc = adjust_uuc(chip, soc_uuc); + + soc_acc = DIV_ROUND_CLOSEST(100 * (soc_ocv - soc_uuc), + (100 - soc_uuc)); + + pr_debug("fcc=%d acc=%d soc_final=%d soc_uuc=%d soc_acc=%d current_now=%d iavg_ma=%d\n", + fcc, acc, soc_final, soc_uuc, + soc_acc, chip->current_now / 1000, iavg_ma); + + soc_final = soc_acc; + chip->last_acc = acc; + } else { + /* charging - reset all the counters */ + chip->last_acc = 0; + chip->iavg_num_samples = 0; + chip->iavg_index = 0; + chip->iavg_ma = 0; + chip->prev_current_now = 0; + chip->prev_soc_uuc = -EINVAL; + } + } + + soc_final = bound_soc(soc_final); + + pr_debug("soc_final=%d soc_ocv=%d soc_cutoff=%d ocv_uv=%u batt_temp=%d\n", + soc_final, soc_ocv, soc_cutoff, ocv_uv, batt_temp); + + return soc_final; +} + +#define V_PER_BIT_MUL_FACTOR 97656 +#define V_PER_BIT_DIV_FACTOR 1000 +#define VADC_INTRINSIC_OFFSET 0x6000 +static int vadc_reading_to_uv(int reading, bool vadc_bms) +{ + int64_t value; + + if (!vadc_bms) { + /* + * All the BMS H/W VADC values are pre-compensated + * for VADC_INTRINSIC_OFFSET, subtract this offset + * only if this reading is not obtained from BMS + */ + + if (reading <= VADC_INTRINSIC_OFFSET) + return 0; + + reading -= VADC_INTRINSIC_OFFSET; + } + + value = (reading * V_PER_BIT_MUL_FACTOR); + + return div_u64(value, (u32)V_PER_BIT_DIV_FACTOR); +} + +static int get_calculation_delay_ms(struct qpnp_bms_chip *chip) +{ + if (bms_wake_active(&chip->vbms_lv_wake_source)) + return chip->dt.cfg_low_voltage_calculate_soc_ms; + if (chip->calculated_soc < chip->dt.cfg_low_soc_calc_threshold) + return chip->dt.cfg_low_soc_calculate_soc_ms; + else + return chip->dt.cfg_calculate_soc_ms; +} + +#define VADC_CALIB_UV 625000 +#define VBATT_MUL_FACTOR 3 +static int adjust_vbatt_reading(struct qpnp_bms_chip *chip, int reading_uv) +{ + s64 numerator, denominator; + + if (reading_uv == 0) + return 0; + + /* don't adjust if not calibrated */ + if (chip->vadc_v0625 == 0 || chip->vadc_v1250 == 0) { + pr_debug("No cal yet return %d\n", + VBATT_MUL_FACTOR * reading_uv); + return VBATT_MUL_FACTOR * reading_uv; + } + + numerator = ((s64)reading_uv - chip->vadc_v0625) * VADC_CALIB_UV; + denominator = (s64)chip->vadc_v1250 - chip->vadc_v0625; + + if (denominator == 0) + return reading_uv * VBATT_MUL_FACTOR; + + return (VADC_CALIB_UV + div_s64(numerator, denominator)) + * VBATT_MUL_FACTOR; +} + +static int calib_vadc(struct qpnp_bms_chip *chip) +{ + int rc, raw_0625, raw_1250; + struct qpnp_vadc_result result; + + rc = qpnp_vadc_read(chip->vadc_dev, REF_625MV, &result); + if (rc) { + pr_debug("vadc read failed with rc = %d\n", rc); + return rc; + } + raw_0625 = result.adc_code; + + rc = qpnp_vadc_read(chip->vadc_dev, REF_125V, &result); + if (rc) { + pr_debug("vadc read failed with rc = %d\n", rc); + return rc; + } + raw_1250 = result.adc_code; + + chip->vadc_v0625 = vadc_reading_to_uv(raw_0625, false); + chip->vadc_v1250 = vadc_reading_to_uv(raw_1250, false); + + pr_debug("vadc calib: 0625=%d raw (%d uv), 1250=%d raw (%d uv)\n", + raw_0625, chip->vadc_v0625, raw_1250, chip->vadc_v1250); + + return 0; +} + +static int convert_vbatt_raw_to_uv(struct qpnp_bms_chip *chip, + u16 reading, bool is_pon_ocv) +{ + int64_t uv, vbatt; + int rc; + + uv = vadc_reading_to_uv(reading, true); + pr_debug("%u raw converted into %lld uv\n", reading, uv); + + uv = adjust_vbatt_reading(chip, uv); + pr_debug("adjusted into %lld uv\n", uv); + + vbatt = uv; + rc = qpnp_vbat_sns_comp_result(chip->vadc_dev, &uv, is_pon_ocv); + if (rc) { + pr_debug("Vbatt compensation failed rc = %d\n", rc); + uv = vbatt; + } else { + pr_debug("temp-compensated %lld into %lld uv\n", vbatt, uv); + } + + return uv; +} + +static void convert_and_store_ocv(struct qpnp_bms_chip *chip, + int batt_temp, bool is_pon_ocv) +{ + int rc; + + rc = calib_vadc(chip); + if (rc) + pr_err("Vadc reference voltage read failed, rc = %d\n", rc); + + chip->last_ocv_uv = convert_vbatt_raw_to_uv(chip, + chip->last_ocv_raw, is_pon_ocv); + + pr_debug("last_ocv_uv = %d\n", chip->last_ocv_uv); +} + +static int read_and_update_ocv(struct qpnp_bms_chip *chip, int batt_temp, + bool is_pon_ocv) +{ + int rc, ocv_uv; + u16 ocv_data = 0; + + /* read the BMS h/w OCV */ + rc = qpnp_read_wrapper(chip, (u8 *)&ocv_data, + chip->base + OCV_DATA0_REG, 2); + if (rc) { + pr_err("Error reading ocv: rc = %d\n", rc); + return -ENXIO; + } + + /* check if OCV is within limits */ + ocv_uv = convert_vbatt_raw_to_uv(chip, ocv_data, is_pon_ocv); + if (ocv_uv < MIN_OCV_UV) { + pr_err("OCV too low or invalid (%d)- rejecting it\n", ocv_uv); + return 0; + } + + if ((chip->last_ocv_raw == OCV_UNINITIALIZED) || + (chip->last_ocv_raw != ocv_data)) { + pr_debug("new OCV!\n"); + chip->last_ocv_raw = ocv_data; + convert_and_store_ocv(chip, batt_temp, is_pon_ocv); + } + + pr_debug("ocv_raw=0x%x last_ocv_raw=0x%x last_ocv_uv=%d\n", + ocv_data, chip->last_ocv_raw, chip->last_ocv_uv); + + return 0; +} + +static int get_battery_voltage(struct qpnp_bms_chip *chip, int *result_uv) +{ + int rc; + struct qpnp_vadc_result adc_result; + + rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &adc_result); + if (rc) { + pr_err("error reading adc channel = %d, rc = %d\n", + VBAT_SNS, rc); + return rc; + } + pr_debug("mvolts phy=%lld meas=0x%llx\n", adc_result.physical, + adc_result.measurement); + *result_uv = (int)adc_result.physical; + + return 0; +} + +static int get_battery_status(struct qpnp_bms_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (chip->batt_psy == NULL) + chip->batt_psy = power_supply_get_by_name("battery"); + if (chip->batt_psy) { + /* if battery has been registered, use the status property */ + power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &ret); + return ret.intval; + } + + /* Default to false if the battery power supply is not registered. */ + pr_debug("battery power supply is not registered\n"); + return POWER_SUPPLY_STATUS_UNKNOWN; +} + +static int get_batt_therm(struct qpnp_bms_chip *chip, int *batt_temp) +{ + int rc; + struct qpnp_vadc_result result; + + rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &result); + if (rc) { + pr_err("error reading adc channel = %d, rc = %d\n", + LR_MUX1_BATT_THERM, rc); + return rc; + } + pr_debug("batt_temp phy = %lld meas = 0x%llx\n", + result.physical, result.measurement); + + *batt_temp = (int)result.physical; + + return 0; +} + +static int get_prop_bms_rbatt(struct qpnp_bms_chip *chip) +{ + return chip->batt_data->default_rbatt_mohm; +} + +static int get_rbatt(struct qpnp_bms_chip *chip, int soc, int batt_temp) +{ + int rbatt_mohm, scalefactor; + + rbatt_mohm = chip->batt_data->default_rbatt_mohm; + if (chip->batt_data->rbatt_sf_lut == NULL) { + pr_debug("RBATT = %d\n", rbatt_mohm); + return rbatt_mohm; + } + + scalefactor = interpolate_scalingfactor(chip->batt_data->rbatt_sf_lut, + batt_temp, soc); + rbatt_mohm = (rbatt_mohm * scalefactor) / 100; + + if (chip->dt.cfg_r_conn_mohm > 0) + rbatt_mohm += chip->dt.cfg_r_conn_mohm; + + return rbatt_mohm; +} + +static void charging_began(struct qpnp_bms_chip *chip) +{ + int rc; + u8 state; + + mutex_lock(&chip->last_soc_mutex); + + chip->charge_start_tm_sec = 0; + chip->catch_up_time_sec = 0; + chip->start_soc = chip->last_soc; + + /* + * reset ocv_at_100 to -EINVAL to indicate + * start of charging. + */ + chip->ocv_at_100 = -EINVAL; + + mutex_unlock(&chip->last_soc_mutex); + + /* + * If the BMS state is not in S2, force it in S2. Such + * a condition can only occur if we are coming out of + * suspend. + */ + mutex_lock(&chip->state_change_mutex); + rc = get_fsm_state(chip, &state); + if (rc) + pr_err("Unable to get FSM state rc=%d\n", rc); + if (rc || (state != S2_STATE)) { + pr_debug("Forcing S2 state\n"); + rc = force_fsm_state(chip, S2_STATE); + if (rc) + pr_err("Unable to set FSM state rc=%d\n", rc); + } + mutex_unlock(&chip->state_change_mutex); +} + +static void charging_ended(struct qpnp_bms_chip *chip) +{ + u8 state; + int rc, status = get_battery_status(chip); + + mutex_lock(&chip->last_soc_mutex); + + chip->charge_start_tm_sec = 0; + chip->catch_up_time_sec = 0; + chip->end_soc = chip->last_soc; + + if (status == POWER_SUPPLY_STATUS_FULL) + chip->last_soc_invalid = true; + + mutex_unlock(&chip->last_soc_mutex); + + /* + * If the BMS state is not in S2, force it in S2. Such + * a condition can only occur if we are coming out of + * suspend. + */ + mutex_lock(&chip->state_change_mutex); + rc = get_fsm_state(chip, &state); + if (rc) + pr_err("Unable to get FSM state rc=%d\n", rc); + if (rc || (state != S2_STATE)) { + pr_debug("Forcing S2 state\n"); + rc = force_fsm_state(chip, S2_STATE); + if (rc) + pr_err("Unable to set FSM state rc=%d\n", rc); + } + mutex_unlock(&chip->state_change_mutex); + + /* Calculate charge accumulated and update charge cycle */ + if (chip->dt.cfg_battery_aging_comp && + (chip->end_soc > chip->start_soc)) { + chip->charge_increase += (chip->end_soc - chip->start_soc); + if (chip->charge_increase > 100) { + chip->charge_cycles++; + chip->charge_increase %= 100; + } + pr_debug("start_soc=%u end_soc=%u charge_cycles=%u charge_increase=%u\n", + chip->start_soc, chip->end_soc, + chip->charge_cycles, chip->charge_increase); + rc = backup_charge_cycle(chip); + if (rc) + pr_err("Unable to store charge cycles rc=%d\n", rc); + } +} + +static int estimate_ocv(struct qpnp_bms_chip *chip) +{ + int i, rc, vbatt = 0, vbatt_final = 0; + + for (i = 0; i < 5; i++) { + rc = get_battery_voltage(chip, &vbatt); + if (rc) { + pr_err("Unable to read battery-voltage rc=%d\n", rc); + return rc; + } + /* + * Conservatively select the lowest vbatt to avoid reporting + * a higher ocv due to variations in bootup current. + */ + + if (i == 0) + vbatt_final = vbatt; + else if (vbatt < vbatt_final) + vbatt_final = vbatt; + + msleep(20); + } + + /* + * TODO: Revisit the OCV calcuations to use approximate ibatt + * and rbatt. + */ + return vbatt_final; +} + +static int scale_soc_while_chg(struct qpnp_bms_chip *chip, int chg_time_sec, + int catch_up_sec, int new_soc, int prev_soc) +{ + int scaled_soc; + int numerator; + + /* + * Don't report a high value immediately slowly scale the + * value from prev_soc to the new soc based on a charge time + * weighted average + */ + pr_debug("cts=%d catch_up_sec=%d\n", chg_time_sec, catch_up_sec); + if (catch_up_sec == 0) + return new_soc; + + if (chg_time_sec > catch_up_sec) + return new_soc; + + numerator = (catch_up_sec - chg_time_sec) * prev_soc + + chg_time_sec * new_soc; + scaled_soc = numerator / catch_up_sec; + + pr_debug("cts=%d new_soc=%d prev_soc=%d scaled_soc=%d\n", + chg_time_sec, new_soc, prev_soc, scaled_soc); + + return scaled_soc; +} + +static int report_eoc(struct qpnp_bms_chip *chip) +{ + int rc = -EINVAL; + union power_supply_propval ret = {0,}; + + if (chip->batt_psy == NULL) + chip->batt_psy = power_supply_get_by_name("battery"); + if (chip->batt_psy) { + power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &ret); + if (rc) { + pr_err("Unable to get battery 'STATUS' rc=%d\n", rc); + } else if (ret.intval != POWER_SUPPLY_STATUS_FULL) { + pr_debug("Report EOC to charger\n"); + ret.intval = POWER_SUPPLY_STATUS_FULL; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &ret); + if (rc) { + pr_err("Unable to set 'STATUS' rc=%d\n", rc); + return rc; + } + chip->eoc_reported = true; + } + } else { + pr_err("battery psy not registered\n"); + } + + return rc; +} + +static void check_recharge_condition(struct qpnp_bms_chip *chip) +{ + int rc; + union power_supply_propval ret = {0,}; + int status = get_battery_status(chip); + + if (chip->last_soc > chip->dt.cfg_soc_resume_limit) + return; + + if (status == POWER_SUPPLY_STATUS_UNKNOWN) { + pr_debug("Unable to read battery status\n"); + return; + } + + /* Report recharge to charger for SOC based resume of charging */ + if ((status != POWER_SUPPLY_STATUS_CHARGING) && chip->eoc_reported) { + ret.intval = POWER_SUPPLY_STATUS_CHARGING; + rc = power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &ret); + if (rc < 0) { + pr_err("Unable to set battery property rc=%d\n", rc); + } else { + pr_info("soc dropped below resume_soc soc=%d resume_soc=%d, restart charging\n", + chip->last_soc, + chip->dt.cfg_soc_resume_limit); + chip->eoc_reported = false; + } + } +} + +static void check_eoc_condition(struct qpnp_bms_chip *chip) +{ + int rc; + int status = get_battery_status(chip); + union power_supply_propval ret = {0,}; + + if (status == POWER_SUPPLY_STATUS_UNKNOWN) { + pr_err("Unable to read battery status\n"); + return; + } + + /* + * Check battery status: + * if last_soc is 100 and battery status is still charging + * reset ocv_at_100 and force reporting of eoc to charger. + */ + if ((chip->last_soc == 100) && + (status == POWER_SUPPLY_STATUS_CHARGING)) + chip->ocv_at_100 = -EINVAL; + + /* + * Store the OCV value at 100. If the new ocv is greater than + * ocv_at_100 (battery settles), update ocv_at_100. Else + * if the SOC drops, reset ocv_at_100. + */ + if (chip->ocv_at_100 == -EINVAL) { + if (chip->last_soc == 100) { + if (chip->dt.cfg_report_charger_eoc) { + rc = report_eoc(chip); + if (!rc) { + /* + * update ocv_at_100 only if EOC is + * reported successfully. + */ + chip->ocv_at_100 = chip->last_ocv_uv; + pr_debug("Battery FULL\n"); + } else { + pr_err("Unable to report eoc rc=%d\n", + rc); + chip->ocv_at_100 = -EINVAL; + } + } + if (chip->dt.cfg_use_reported_soc) { + /* begin reported_soc process */ + chip->reported_soc_in_use = true; + chip->charger_removed_since_full = false; + chip->charger_reinserted = false; + chip->reported_soc = 100; + pr_debug("Begin reported_soc process\n"); + } + } + } else { + if (chip->last_ocv_uv >= chip->ocv_at_100) { + pr_debug("new_ocv(%d) > ocv_at_100(%d) maintaining SOC to 100\n", + chip->last_ocv_uv, chip->ocv_at_100); + chip->ocv_at_100 = chip->last_ocv_uv; + chip->last_soc = 100; + } else if (chip->last_soc != 100) { + /* + * Report that the battery is discharging. + * This gets called once when the SOC falls + * below 100. + */ + if (chip->reported_soc_in_use + && chip->reported_soc == 100) { + pr_debug("reported_soc=100, last_soc=%d, do not send DISCHARING status\n", + chip->last_soc); + } else { + ret.intval = POWER_SUPPLY_STATUS_DISCHARGING; + power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &ret); + } + pr_debug("SOC dropped (%d) discarding ocv_at_100\n", + chip->last_soc); + chip->ocv_at_100 = -EINVAL; + } + } +} + +static int report_voltage_based_soc(struct qpnp_bms_chip *chip) +{ + pr_debug("Reported voltage based soc = %d\n", + chip->prev_voltage_based_soc); + return chip->prev_voltage_based_soc; +} + +static int prepare_reported_soc(struct qpnp_bms_chip *chip) +{ + if (chip->charger_removed_since_full == false) { + /* + * charger is not removed since full, + * keep reported_soc as 100 and calculate the delta soc + * between reported_soc and last_soc + */ + chip->reported_soc = 100; + chip->reported_soc_delta = 100 - chip->last_soc; + pr_debug("Keep at reported_soc 100, reported_soc_delta=%d, last_soc=%d\n", + chip->reported_soc_delta, + chip->last_soc); + } else { + /* charger is removed since full */ + if (chip->charger_reinserted) { + /* + * charger reinserted, keep the reported_soc + * until it equals to last_soc. + */ + if (chip->reported_soc == chip->last_soc) { + chip->reported_soc_in_use = false; + chip->reported_soc_high_current = false; + pr_debug("reported_soc equals to last_soc, stop reported_soc process\n"); + } + chip->reported_soc_change_sec = 0; + } + } + pr_debug("Reporting reported_soc=%d, last_soc=%d\n", + chip->reported_soc, chip->last_soc); + return chip->reported_soc; +} + +#define SOC_CATCHUP_SEC_MAX 600 +#define SOC_CATCHUP_SEC_PER_PERCENT 60 +#define MAX_CATCHUP_SOC (SOC_CATCHUP_SEC_MAX / SOC_CATCHUP_SEC_PER_PERCENT) +#define SOC_CHANGE_PER_SEC 5 +static int report_vm_bms_soc(struct qpnp_bms_chip *chip) +{ + int soc, soc_change, batt_temp, rc; + int time_since_last_change_sec = 0, charge_time_sec = 0; + unsigned long last_change_sec; + bool charging; + + soc = chip->calculated_soc; + + last_change_sec = chip->last_soc_change_sec; + calculate_delta_time(&last_change_sec, &time_since_last_change_sec); + + charging = is_battery_charging(chip); + + pr_debug("charging=%d last_soc=%d last_soc_unbound=%d\n", + charging, chip->last_soc, chip->last_soc_unbound); + /* + * account for charge time - limit it to SOC_CATCHUP_SEC to + * avoid overflows when charging continues for extended periods + */ + if (charging && chip->last_soc != -EINVAL) { + if (chip->charge_start_tm_sec == 0 || + (chip->catch_up_time_sec == 0 && + (abs(soc - chip->last_soc) >= MIN_SOC_UUC))) { + /* + * calculating soc for the first time + * after start of chg. Initialize catchup time + */ + if (abs(soc - chip->last_soc) < MAX_CATCHUP_SOC) + chip->catch_up_time_sec = + (soc - chip->last_soc) + * SOC_CATCHUP_SEC_PER_PERCENT; + else + chip->catch_up_time_sec = SOC_CATCHUP_SEC_MAX; + + chip->chg_start_soc = chip->last_soc; + + if (chip->catch_up_time_sec < 0) + chip->catch_up_time_sec = 0; + chip->charge_start_tm_sec = last_change_sec; + + pr_debug("chg_start_soc=%d charge_start_tm_sec=%d catch_up_time_sec=%d\n", + chip->chg_start_soc, chip->charge_start_tm_sec, + chip->catch_up_time_sec); + } + + charge_time_sec = min(SOC_CATCHUP_SEC_MAX, (int)last_change_sec + - chip->charge_start_tm_sec); + + /* end catchup if calculated soc and last soc are same */ + if (chip->last_soc == soc) { + chip->catch_up_time_sec = 0; + chip->chg_start_soc = chip->last_soc; + } + } + + if (chip->last_soc != -EINVAL) { + /* + * last_soc < soc ... if we have not been charging at all + * since the last time this was called, report previous SoC. + * Otherwise, scale and catch up. + */ + rc = get_batt_therm(chip, &batt_temp); + if (rc) + batt_temp = BMS_DEFAULT_TEMP; + + if (chip->last_soc < soc && !charging) + soc = chip->last_soc; + else if (chip->last_soc < soc && soc != 100) + soc = scale_soc_while_chg(chip, charge_time_sec, + chip->catch_up_time_sec, + soc, chip->chg_start_soc); + + /* + * if the battery is close to cutoff or if the batt_temp + * is under the low-temp threshold allow bigger change + */ + if (bms_wake_active(&chip->vbms_lv_wake_source) || + (batt_temp <= chip->dt.cfg_low_temp_threshold)) + soc_change = min((int)abs(chip->last_soc - soc), + time_since_last_change_sec); + else + soc_change = min((int)abs(chip->last_soc - soc), + time_since_last_change_sec + / SOC_CHANGE_PER_SEC); + + if (chip->last_soc_unbound) { + chip->last_soc_unbound = false; + } else { + /* + * if soc have not been unbound by resume, + * only change reported SoC by 1. + */ + soc_change = min(1, soc_change); + } + + if (soc < chip->last_soc && soc != 0) + soc = chip->last_soc - soc_change; + if (soc > chip->last_soc && soc != 100) + soc = chip->last_soc + soc_change; + } + + if (chip->last_soc != soc && !chip->last_soc_unbound) + chip->last_soc_change_sec = last_change_sec; + + /* + * Check/update eoc under following condition: + * if there is change in soc: + * soc != chip->last_soc + * during bootup if soc is 100: + */ + soc = bound_soc(soc); + if ((soc != chip->last_soc) || (soc == 100)) { + chip->last_soc = soc; + check_eoc_condition(chip); + if ((chip->dt.cfg_soc_resume_limit > 0) && !charging) + check_recharge_condition(chip); + } + + pr_debug("last_soc=%d calculated_soc=%d soc=%d time_since_last_change=%d\n", + chip->last_soc, chip->calculated_soc, + soc, time_since_last_change_sec); + + /* + * Backup the actual ocv (last_ocv_uv) and not the + * last_soc-interpolated ocv. This makes sure that + * the BMS algorithm always uses the correct ocv and + * can catch up on the last_soc (across reboots). + * We do not want the algorithm to be based of a wrong + * initial OCV. + */ + + backup_ocv_soc(chip, chip->last_ocv_uv, chip->last_soc); + + if (chip->reported_soc_in_use) + return prepare_reported_soc(chip); + + pr_debug("Reported SOC=%d\n", chip->last_soc); + + return chip->last_soc; +} + +static int report_state_of_charge(struct qpnp_bms_chip *chip) +{ + int soc; + + mutex_lock(&chip->last_soc_mutex); + + if (chip->dt.cfg_use_voltage_soc) + soc = report_voltage_based_soc(chip); + else + soc = report_vm_bms_soc(chip); + + mutex_unlock(&chip->last_soc_mutex); + + return soc; +} + +static void btm_notify_vbat(enum qpnp_tm_state state, void *ctx) +{ + struct qpnp_bms_chip *chip = ctx; + int vbat_uv; + int rc; + + rc = get_battery_voltage(chip, &vbat_uv); + if (rc) { + pr_err("error reading vbat_sns adc channel=%d, rc=%d\n", + VBAT_SNS, rc); + goto out; + } + + pr_debug("vbat is at %d, state is at %d\n", vbat_uv, state); + + if (state == ADC_TM_LOW_STATE) { + pr_debug("low voltage btm notification triggered\n"); + if (vbat_uv <= (chip->vbat_monitor_params.low_thr + + VBATT_ERROR_MARGIN)) { + if (!bms_wake_active(&chip->vbms_lv_wake_source)) + bms_stay_awake(&chip->vbms_lv_wake_source); + + chip->vbat_monitor_params.state_request = + ADC_TM_HIGH_THR_ENABLE; + } else { + pr_debug("faulty btm trigger, discarding\n"); + goto out; + } + } else if (state == ADC_TM_HIGH_STATE) { + pr_debug("high voltage btm notification triggered\n"); + if (vbat_uv > chip->vbat_monitor_params.high_thr) { + chip->vbat_monitor_params.state_request = + ADC_TM_LOW_THR_ENABLE; + if (bms_wake_active(&chip->vbms_lv_wake_source)) + bms_relax(&chip->vbms_lv_wake_source); + } else { + pr_debug("faulty btm trigger, discarding\n"); + goto out; + } + } else { + pr_debug("unknown voltage notification state: %d\n", state); + goto out; + } + + if (chip->bms_psy_registered) + power_supply_changed(chip->bms_psy); + +out: + qpnp_adc_tm_channel_measure(chip->adc_tm_dev, + &chip->vbat_monitor_params); +} + +static int reset_vbat_monitoring(struct qpnp_bms_chip *chip) +{ + int rc; + + chip->vbat_monitor_params.state_request = ADC_TM_HIGH_LOW_THR_DISABLE; + rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev, + &chip->vbat_monitor_params); + if (rc) { + pr_err("tm disable failed: %d\n", rc); + return rc; + } + + if (bms_wake_active(&chip->vbms_lv_wake_source)) + bms_relax(&chip->vbms_lv_wake_source); + + return 0; +} + +static int setup_vbat_monitoring(struct qpnp_bms_chip *chip) +{ + int rc; + + chip->vbat_monitor_params.low_thr = + chip->dt.cfg_low_voltage_threshold; + chip->vbat_monitor_params.high_thr = + chip->dt.cfg_low_voltage_threshold + + VBATT_ERROR_MARGIN; + chip->vbat_monitor_params.state_request = ADC_TM_LOW_THR_ENABLE; + chip->vbat_monitor_params.channel = VBAT_SNS; + chip->vbat_monitor_params.btm_ctx = chip; + chip->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S; + chip->vbat_monitor_params.threshold_notification = &btm_notify_vbat; + pr_debug("set low thr to %d and high to %d\n", + chip->vbat_monitor_params.low_thr, + chip->vbat_monitor_params.high_thr); + + rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev, + &chip->vbat_monitor_params); + if (rc) { + pr_err("adc-tm setup failed: %d\n", rc); + return rc; + } + + pr_debug("vbat monitoring setup complete\n"); + return 0; +} + +static void very_low_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) +{ + if (!bms_wake_active(&chip->vbms_lv_wake_source) + && (vbat_uv <= chip->dt.cfg_low_voltage_threshold)) { + pr_debug("voltage=%d holding low voltage ws\n", vbat_uv); + bms_stay_awake(&chip->vbms_lv_wake_source); + } else if (bms_wake_active(&chip->vbms_lv_wake_source) + && (vbat_uv > chip->dt.cfg_low_voltage_threshold)) { + pr_debug("voltage=%d releasing low voltage ws\n", vbat_uv); + bms_relax(&chip->vbms_lv_wake_source); + } +} + +static void cv_voltage_check(struct qpnp_bms_chip *chip, int vbat_uv) +{ + if (bms_wake_active(&chip->vbms_cv_wake_source)) { + if ((vbat_uv < (chip->dt.cfg_max_voltage_uv - + VBATT_ERROR_MARGIN + CV_DROP_MARGIN)) + && !is_battery_taper_charging(chip)) { + pr_debug("Fell below CV, releasing cv ws\n"); + chip->in_cv_state = false; + bms_relax(&chip->vbms_cv_wake_source); + } else if (!is_battery_charging(chip)) { + pr_debug("charging stopped, releasing cv ws\n"); + chip->in_cv_state = false; + bms_relax(&chip->vbms_cv_wake_source); + } + } else if (!bms_wake_active(&chip->vbms_cv_wake_source) + && is_battery_charging(chip) + && ((vbat_uv > (chip->dt.cfg_max_voltage_uv - + VBATT_ERROR_MARGIN)) + || is_battery_taper_charging(chip))) { + pr_debug("CC_TO_CV voltage=%d holding cv ws\n", vbat_uv); + chip->in_cv_state = true; + bms_stay_awake(&chip->vbms_cv_wake_source); + } +} + +static void low_soc_check(struct qpnp_bms_chip *chip) +{ + int rc; + + if (chip->dt.cfg_low_soc_fifo_length < 1) + return; + + mutex_lock(&chip->state_change_mutex); + + if (chip->calculated_soc <= chip->dt.cfg_low_soc_calc_threshold) { + if (!chip->low_soc_fifo_set) { + pr_debug("soc=%d (low-soc) setting fifo_length to %d\n", + chip->calculated_soc, + chip->dt.cfg_low_soc_fifo_length); + rc = get_fifo_length(chip, S2_STATE, + &chip->s2_fifo_length); + if (rc) { + pr_err("Unable to get_fifo_length rc=%d", rc); + goto low_soc_exit; + } + rc = set_fifo_length(chip, S2_STATE, + chip->dt.cfg_low_soc_fifo_length); + if (rc) { + pr_err("Unable to set_fifo_length rc=%d", rc); + goto low_soc_exit; + } + chip->low_soc_fifo_set = true; + } + } else { + if (chip->low_soc_fifo_set) { + pr_debug("soc=%d setting back fifo_length to %d\n", + chip->calculated_soc, + chip->s2_fifo_length); + rc = set_fifo_length(chip, S2_STATE, + chip->s2_fifo_length); + if (rc) { + pr_err("Unable to set_fifo_length rc=%d", rc); + goto low_soc_exit; + } + chip->low_soc_fifo_set = false; + } + } + +low_soc_exit: + mutex_unlock(&chip->state_change_mutex); +} + +static int calculate_soc_from_voltage(struct qpnp_bms_chip *chip) +{ + int voltage_range_uv, voltage_remaining_uv, voltage_based_soc; + int rc, vbat_uv; + + /* check if we have the averaged fifo data */ + if (chip->voltage_soc_uv) { + vbat_uv = chip->voltage_soc_uv; + } else { + rc = get_battery_voltage(chip, &vbat_uv); + if (rc < 0) { + pr_err("adc vbat failed err = %d\n", rc); + return rc; + } + pr_debug("instant-voltage based voltage-soc\n"); + } + + voltage_range_uv = chip->dt.cfg_max_voltage_uv - + chip->dt.cfg_v_cutoff_uv; + voltage_remaining_uv = vbat_uv - chip->dt.cfg_v_cutoff_uv; + voltage_based_soc = voltage_remaining_uv * 100 / voltage_range_uv; + + voltage_based_soc = clamp(voltage_based_soc, 0, 100); + + if (chip->prev_voltage_based_soc != voltage_based_soc + && chip->bms_psy_registered) { + pr_debug("update bms_psy\n"); + power_supply_changed(chip->bms_psy); + } + chip->prev_voltage_based_soc = voltage_based_soc; + + pr_debug("vbat used = %duv\n", vbat_uv); + pr_debug("Calculated voltage based soc=%d\n", voltage_based_soc); + + if (voltage_based_soc == 100) + if (chip->dt.cfg_report_charger_eoc) + report_eoc(chip); + + return 0; +} + +static void calculate_reported_soc(struct qpnp_bms_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (chip->last_soc < 0) { + pr_debug("last_soc is not ready, return\n"); + return; + } + + if (chip->reported_soc > chip->last_soc) { + /*send DISCHARGING status if the reported_soc drops from 100 */ + if (chip->reported_soc == 100) { + ret.intval = POWER_SUPPLY_STATUS_DISCHARGING; + power_supply_set_property(chip->batt_psy, + POWER_SUPPLY_PROP_STATUS, &ret); + pr_debug("Report discharging status, reported_soc=%d, last_soc=%d\n", + chip->reported_soc, chip->last_soc); + } + /* + * reported_soc_delta is used to prevent + * the big change in last_soc, + * this is not used in high current mode + */ + if (chip->reported_soc_delta > 0) + chip->reported_soc_delta--; + + if (chip->reported_soc_high_current) + chip->reported_soc--; + else + chip->reported_soc = chip->last_soc + + chip->reported_soc_delta; + + pr_debug("New reported_soc=%d, last_soc is=%d\n", + chip->reported_soc, chip->last_soc); + } else { + chip->reported_soc_in_use = false; + chip->reported_soc_high_current = false; + pr_debug("reported_soc equals last_soc,stop reported_soc process\n"); + } + pr_debug("bms power_supply_changed\n"); + power_supply_changed(chip->bms_psy); +} + +static int clamp_soc_based_on_voltage(struct qpnp_bms_chip *chip, int soc) +{ + int rc, vbat_uv; + + rc = get_battery_voltage(chip, &vbat_uv); + if (rc < 0) { + pr_err("adc vbat failed err = %d\n", rc); + return soc; + } + + /* only clamp when discharging */ + if (is_battery_charging(chip)) + return soc; + + if (soc <= 0 && vbat_uv > chip->dt.cfg_v_cutoff_uv) { + pr_debug("clamping soc to 1, vbat (%d) > cutoff (%d)\n", + vbat_uv, chip->dt.cfg_v_cutoff_uv); + return 1; + } + pr_debug("not clamping, using soc = %d, vbat = %d and cutoff = %d\n", + soc, vbat_uv, chip->dt.cfg_v_cutoff_uv); + return soc; +} + +static void battery_voltage_check(struct qpnp_bms_chip *chip) +{ + int rc, vbat_uv = 0; + + rc = get_battery_voltage(chip, &vbat_uv); + if (rc < 0) { + pr_err("Failed to read battery-voltage rc=%d\n", rc); + } else { + very_low_voltage_check(chip, vbat_uv); + cv_voltage_check(chip, vbat_uv); + } +} + +#define UI_SOC_CATCHUP_TIME (60) +static void monitor_soc_work(struct work_struct *work) +{ + struct qpnp_bms_chip *chip = container_of(work, + struct qpnp_bms_chip, + monitor_soc_work.work); + int rc, new_soc = 0, batt_temp; + + bms_stay_awake(&chip->vbms_soc_wake_source); + + calculate_delta_time(&chip->tm_sec, &chip->delta_time_s); + pr_debug("elapsed_time=%d\n", chip->delta_time_s); + + mutex_lock(&chip->last_soc_mutex); + + if (!is_battery_present(chip)) { + /* if battery is not preset report 100% SOC */ + pr_debug("battery gone, reporting 100\n"); + chip->last_soc_invalid = true; + chip->last_soc = -EINVAL; + new_soc = 100; + } else { + battery_voltage_check(chip); + + if (chip->dt.cfg_use_voltage_soc) { + calculate_soc_from_voltage(chip); + } else { + rc = get_batt_therm(chip, &batt_temp); + if (rc < 0) { + pr_err("Unable to read batt temp rc=%d, using default=%d\n", + rc, BMS_DEFAULT_TEMP); + batt_temp = BMS_DEFAULT_TEMP; + } + + if (chip->last_soc_invalid) { + chip->last_soc_invalid = false; + chip->last_soc = -EINVAL; + } + new_soc = lookup_soc_ocv(chip, chip->last_ocv_uv, + batt_temp); + /* clamp soc due to BMS hw/sw immaturities */ + new_soc = clamp_soc_based_on_voltage(chip, new_soc); + + if (chip->calculated_soc != new_soc) { + pr_debug("SOC changed! new_soc=%d prev_soc=%d\n", + new_soc, chip->calculated_soc); + chip->calculated_soc = new_soc; + /* + * To recalculate the catch-up time, clear it + * when SOC changes. + */ + chip->catch_up_time_sec = 0; + + if (chip->calculated_soc == 100) + /* update last_soc immediately */ + report_vm_bms_soc(chip); + + pr_debug("update bms_psy\n"); + power_supply_changed(chip->bms_psy); + } else if (chip->last_soc != chip->calculated_soc) { + pr_debug("update bms_psy\n"); + power_supply_changed(chip->bms_psy); + } else { + report_vm_bms_soc(chip); + } + } + /* low SOC configuration */ + low_soc_check(chip); + } + /* + * schedule the work only if last_soc has not caught up with + * the calculated soc or if we are using voltage based soc + */ + if ((chip->last_soc != chip->calculated_soc) || + chip->dt.cfg_use_voltage_soc) + schedule_delayed_work(&chip->monitor_soc_work, + msecs_to_jiffies(get_calculation_delay_ms(chip))); + + if (chip->reported_soc_in_use && chip->charger_removed_since_full + && !chip->charger_reinserted) { + /* record the elapsed time after last reported_soc change */ + chip->reported_soc_change_sec += chip->delta_time_s; + pr_debug("reported_soc_change_sec=%d\n", + chip->reported_soc_change_sec); + + /* above the catch up time, calculate new reported_soc */ + if (chip->reported_soc_change_sec > UI_SOC_CATCHUP_TIME) { + calculate_reported_soc(chip); + chip->reported_soc_change_sec = 0; + } + } + + mutex_unlock(&chip->last_soc_mutex); + + bms_relax(&chip->vbms_soc_wake_source); +} + +static void voltage_soc_timeout_work(struct work_struct *work) +{ + struct qpnp_bms_chip *chip = container_of(work, + struct qpnp_bms_chip, + voltage_soc_timeout_work.work); + + mutex_lock(&chip->bms_device_mutex); + if (!chip->bms_dev_open) { + pr_warn("BMS device not opened, using voltage based SOC\n"); + chip->dt.cfg_use_voltage_soc = true; + } + mutex_unlock(&chip->bms_device_mutex); +} + +static int get_prop_bms_capacity(struct qpnp_bms_chip *chip) +{ + return report_state_of_charge(chip); +} + +static bool is_hi_power_state_requested(struct qpnp_bms_chip *chip) +{ + + pr_debug("hi_power_state=0x%x\n", chip->hi_power_state); + + if (chip->hi_power_state & VMBMS_IGNORE_ALL_BIT) + return false; + else + return !!chip->hi_power_state; + +} + +static int qpnp_vm_bms_config_power_state(struct qpnp_bms_chip *chip, + int usecase, bool hi_power_enable) +{ + if (usecase < 0) { + pr_err("Invalid power-usecase %x\n", usecase); + return -EINVAL; + } + + if (hi_power_enable) + chip->hi_power_state |= usecase; + else + chip->hi_power_state &= ~usecase; + + pr_debug("hi_power_state=%x usecase=%x hi_power_enable=%d\n", + chip->hi_power_state, usecase, hi_power_enable); + + return 0; +} + +static int get_prop_bms_current_now(struct qpnp_bms_chip *chip) +{ + return chip->current_now; +} + +static int get_current_cc(struct qpnp_bms_chip *chip) +{ + int soc, cc_full; + int64_t current_charge; + + if (chip->batt_data == NULL) + return -EINVAL; + + cc_full = chip->batt_data->fcc; + if (chip->dt.cfg_use_voltage_soc) + soc = chip->prev_voltage_based_soc; + else + soc = chip->last_soc; + + /* + * Full charge capacity is in mAh and soc is in % + * current_charge capacity is defined in uAh + * Hence conversion ((mAh * pct * 1000) / 100) => (mAh * pct * 10) + */ + current_charge = cc_full * soc * 10; + + return current_charge; +} + +static enum power_supply_property bms_power_props[] = { + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_RESISTANCE, + POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE, + POWER_SUPPLY_PROP_RESISTANCE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_VOLTAGE_OCV, + POWER_SUPPLY_PROP_HI_POWER, + POWER_SUPPLY_PROP_LOW_POWER, + POWER_SUPPLY_PROP_BATTERY_TYPE, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_CHARGE_COUNTER, +}; + +static int +qpnp_vm_bms_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + case POWER_SUPPLY_PROP_HI_POWER: + case POWER_SUPPLY_PROP_LOW_POWER: + return 1; + default: + break; + } + + return 0; +} + +static int qpnp_vm_bms_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct qpnp_bms_chip *chip = power_supply_get_drvdata(psy); + int value = 0, rc; + + val->intval = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = get_prop_bms_capacity(chip); + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = chip->battery_status; + break; + case POWER_SUPPLY_PROP_RESISTANCE: + val->intval = get_prop_bms_rbatt(chip); + break; + case POWER_SUPPLY_PROP_RESISTANCE_CAPACITIVE: + if (chip->batt_data->rbatt_capacitive_mohm > 0) + val->intval = chip->batt_data->rbatt_capacitive_mohm; + if (chip->dt.cfg_r_conn_mohm > 0) + val->intval += chip->dt.cfg_r_conn_mohm; + break; + case POWER_SUPPLY_PROP_RESISTANCE_NOW: + rc = get_batt_therm(chip, &value); + if (rc < 0) + value = BMS_DEFAULT_TEMP; + val->intval = get_rbatt(chip, chip->calculated_soc, value); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = get_prop_bms_current_now(chip); + break; + case POWER_SUPPLY_PROP_BATTERY_TYPE: + val->strval = chip->batt_data->battery_type; + break; + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + val->intval = chip->last_ocv_uv; + break; + case POWER_SUPPLY_PROP_TEMP: + rc = get_batt_therm(chip, &value); + if (rc < 0) + value = BMS_DEFAULT_TEMP; + val->intval = value; + break; + case POWER_SUPPLY_PROP_HI_POWER: + val->intval = is_hi_power_state_requested(chip); + break; + case POWER_SUPPLY_PROP_LOW_POWER: + val->intval = !is_hi_power_state_requested(chip); + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + if (chip->dt.cfg_battery_aging_comp) + val->intval = chip->charge_cycles; + else + val->intval = -EINVAL; + break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + val->intval = get_current_cc(chip); + break; + default: + return -EINVAL; + } + return 0; +} + +static int qpnp_vm_bms_power_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + int rc = 0; + struct qpnp_bms_chip *chip = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_CURRENT_NOW: + chip->current_now = val->intval; + pr_debug("IBATT = %d\n", val->intval); + break; + case POWER_SUPPLY_PROP_VOLTAGE_OCV: + cancel_delayed_work_sync(&chip->monitor_soc_work); + chip->last_ocv_uv = val->intval; + pr_debug("OCV = %d\n", val->intval); + schedule_delayed_work(&chip->monitor_soc_work, 0); + break; + case POWER_SUPPLY_PROP_HI_POWER: + rc = qpnp_vm_bms_config_power_state(chip, val->intval, true); + if (rc) + pr_err("Unable to set power-state rc=%d\n", rc); + break; + case POWER_SUPPLY_PROP_LOW_POWER: + rc = qpnp_vm_bms_config_power_state(chip, val->intval, false); + if (rc) + pr_err("Unable to set power-state rc=%d\n", rc); + break; + default: + return -EINVAL; + } + return rc; +} + +static void bms_new_battery_setup(struct qpnp_bms_chip *chip) +{ + int rc; + + mutex_lock(&chip->bms_data_mutex); + + chip->last_soc_invalid = true; + /* + * disable and re-enable the BMS hardware to reset + * the realtime-FIFO data and restart accumulation + */ + rc = qpnp_masked_write_base(chip, chip->base + EN_CTL_REG, + BMS_EN_BIT, 0); + /* delay for the BMS hardware to reset its state */ + msleep(200); + rc |= qpnp_masked_write_base(chip, chip->base + EN_CTL_REG, + BMS_EN_BIT, BMS_EN_BIT); + /* delay for the BMS hardware to re-start */ + msleep(200); + if (rc) + pr_err("Unable to reset BMS rc=%d\n", rc); + + chip->last_ocv_uv = estimate_ocv(chip); + + memset(&chip->bms_data, 0, sizeof(chip->bms_data)); + + /* update the sequence number */ + chip->bms_data.seq_num = chip->seq_num++; + + /* signal the read thread */ + chip->data_ready = 1; + wake_up_interruptible(&chip->bms_wait_q); + + /* hold a wake lock until the read thread is scheduled */ + if (chip->bms_dev_open) + pm_stay_awake(chip->dev); + + mutex_unlock(&chip->bms_data_mutex); + + /* reset aging variables */ + if (chip->dt.cfg_battery_aging_comp) { + chip->charge_cycles = 0; + chip->charge_increase = 0; + rc = backup_charge_cycle(chip); + if (rc) + pr_err("Unable to reset aging data rc=%d\n", rc); + } +} + +static void battery_insertion_check(struct qpnp_bms_chip *chip) +{ + int present = (int)is_battery_present(chip); + + if (chip->battery_present != present) { + pr_debug("shadow_sts=%d status=%d\n", + chip->battery_present, present); + if (chip->battery_present != -EINVAL) { + if (present) { + /* new battery inserted */ + bms_new_battery_setup(chip); + setup_vbat_monitoring(chip); + pr_debug("New battery inserted!\n"); + } else { + /* battery removed */ + reset_vbat_monitoring(chip); + pr_debug("Battery removed\n"); + } + } + chip->battery_present = present; + } +} + +static void battery_status_check(struct qpnp_bms_chip *chip) +{ + int status = get_battery_status(chip); + + if (chip->battery_status != status) { + if (status == POWER_SUPPLY_STATUS_CHARGING) { + pr_debug("charging started\n"); + charging_began(chip); + } else if (chip->battery_status == + POWER_SUPPLY_STATUS_CHARGING) { + pr_debug("charging stopped\n"); + charging_ended(chip); + } + + if (status == POWER_SUPPLY_STATUS_FULL) { + pr_debug("battery full\n"); + chip->battery_full = true; + } else if (chip->battery_status == POWER_SUPPLY_STATUS_FULL) { + pr_debug("battery not-full anymore\n"); + chip->battery_full = false; + } + chip->battery_status = status; + } +} + +#define HIGH_CURRENT_TH 2 +static void reported_soc_check_status(struct qpnp_bms_chip *chip) +{ + u8 present; + + present = is_charger_present(chip); + pr_debug("usb_present=%d\n", present); + + if (!present && !chip->charger_removed_since_full) { + chip->charger_removed_since_full = true; + pr_debug("reported_soc: charger removed since full\n"); + return; + } + if (chip->reported_soc_high_current) { + pr_debug("reported_soc in high current mode, return\n"); + return; + } + if ((chip->reported_soc - chip->last_soc) > + (100 - chip->dt.cfg_soc_resume_limit + + HIGH_CURRENT_TH)) { + chip->reported_soc_high_current = true; + chip->charger_removed_since_full = true; + chip->charger_reinserted = false; + pr_debug("reported_soc enters high current mode\n"); + return; + } + if (present && chip->charger_removed_since_full) { + chip->charger_reinserted = true; + pr_debug("reported_soc: charger reinserted\n"); + } + if (!present && chip->charger_removed_since_full) { + chip->charger_reinserted = false; + pr_debug("reported_soc: charger removed again\n"); + } +} + +static void qpnp_vm_bms_ext_power_changed(struct power_supply *psy) +{ + struct qpnp_bms_chip *chip = power_supply_get_drvdata(psy); + + pr_debug("Triggered!\n"); + battery_status_check(chip); + battery_insertion_check(chip); + + mutex_lock(&chip->last_soc_mutex); + battery_voltage_check(chip); + mutex_unlock(&chip->last_soc_mutex); + + if (chip->reported_soc_in_use) + reported_soc_check_status(chip); +} + + +static void dump_bms_data(const char *func, struct qpnp_bms_chip *chip) +{ + int i; + + pr_debug("%s: fifo_count=%d acc_count=%d seq_num=%d\n", + func, chip->bms_data.num_fifo, + chip->bms_data.acc_count, + chip->bms_data.seq_num); + + for (i = 0; i < chip->bms_data.num_fifo; i++) + pr_debug("fifo=%d fifo_uv=%d sample_interval=%d sample_count=%d\n", + i, chip->bms_data.fifo_uv[i], + chip->bms_data.sample_interval_ms, + chip->bms_data.sample_count); + pr_debug("avg_acc_data=%d\n", chip->bms_data.acc_uv); +} + +static int read_and_populate_fifo_data(struct qpnp_bms_chip *chip) +{ + u8 fifo_count = 0, val = 0; + u8 fifo_data_raw[MAX_FIFO_REGS * 2]; + u16 fifo_data; + int rc, i, j; + int64_t voltage_soc_avg = 0; + + /* read the completed FIFO count */ + rc = qpnp_read_wrapper(chip, &val, chip->base + STATUS2_REG, 1); + if (rc) { + pr_err("Unable to read STATUS2 register rc=%d\n", rc); + return rc; + } + fifo_count = (val & FIFO_CNT_SD_MASK) >> FIFO_CNT_SD_SHIFT; + pr_debug("fifo_count=%d\n", fifo_count); + if (!fifo_count) { + pr_debug("No data in FIFO\n"); + return 0; + } else if (fifo_count > MAX_FIFO_REGS) { + pr_err("Invalid fifo-length %d rejecting data\n", fifo_count); + chip->bms_data.num_fifo = 0; + return 0; + } + + /* read the FIFO data */ + for (i = 0; i < fifo_count * 2; i++) { + rc = qpnp_read_wrapper(chip, &fifo_data_raw[i], + chip->base + FIFO_0_LSB_REG + i, 1); + if (rc) { + pr_err("Unable to read FIFO register(%d) rc=%d\n", + i, rc); + return rc; + } + } + + /* populate the structure */ + chip->bms_data.num_fifo = fifo_count; + + rc = get_sample_interval(chip, chip->current_fsm_state, + &chip->bms_data.sample_interval_ms); + if (rc) { + pr_err("Unable to read state=%d sample_interval rc=%d\n", + chip->current_fsm_state, rc); + return rc; + } + + rc = get_sample_count(chip, chip->current_fsm_state, + &chip->bms_data.sample_count); + if (rc) { + pr_err("Unable to read state=%d sample_count rc=%d\n", + chip->current_fsm_state, rc); + return rc; + } + + for (i = 0, j = 0; i < fifo_count * 2; i = i + 2, j++) { + fifo_data = fifo_data_raw[i] | (fifo_data_raw[i + 1] << 8); + chip->bms_data.fifo_uv[j] = convert_vbatt_raw_to_uv(chip, + fifo_data, 0); + voltage_soc_avg += chip->bms_data.fifo_uv[j]; + } + /* store the fifo average for voltage-based-soc */ + chip->voltage_soc_uv = div_u64(voltage_soc_avg, fifo_count); + + return 0; +} + +static int read_and_populate_acc_data(struct qpnp_bms_chip *chip) +{ + int rc; + u32 acc_data_sd = 0, acc_count_sd = 0, avg_acc_data = 0; + + /* read ACC SD count */ + rc = qpnp_read_wrapper(chip, (u8 *)&acc_count_sd, + chip->base + ACC_CNT_SD_REG, 1); + if (rc) { + pr_err("Unable to read ACC_CNT_SD_REG rc=%d\n", rc); + return rc; + } + if (!acc_count_sd) { + pr_debug("No data in accumulator\n"); + return 0; + } + /* read ACC SD data */ + rc = qpnp_read_wrapper(chip, (u8 *)&acc_data_sd, + chip->base + ACC_DATA0_SD_REG, 3); + if (rc) { + pr_err("Unable to read ACC_DATA0_SD_REG rc=%d\n", rc); + return rc; + } + avg_acc_data = div_u64(acc_data_sd, acc_count_sd); + + chip->bms_data.acc_uv = convert_vbatt_raw_to_uv(chip, + avg_acc_data, 0); + chip->bms_data.acc_count = acc_count_sd; + + rc = get_sample_interval(chip, chip->current_fsm_state, + &chip->bms_data.sample_interval_ms); + if (rc) { + pr_err("Unable to read state=%d sample_interval rc=%d\n", + chip->current_fsm_state, rc); + return rc; + } + + rc = get_sample_count(chip, chip->current_fsm_state, + &chip->bms_data.sample_count); + if (rc) { + pr_err("Unable to read state=%d sample_count rc=%d\n", + chip->current_fsm_state, rc); + return rc; + } + + return 0; +} + +static int clear_fifo_acc_data(struct qpnp_bms_chip *chip) +{ + int rc; + u8 reg = 0; + + reg = FIFO_CNT_SD_CLR_BIT | ACC_DATA_SD_CLR_BIT | ACC_CNT_SD_CLR_BIT; + rc = qpnp_masked_write_base(chip, chip->base + DATA_CTL2_REG, reg, reg); + if (rc) + pr_err("Unable to write DATA_CTL2_REG rc=%d\n", rc); + + return rc; +} + +static irqreturn_t bms_fifo_update_done_irq_handler(int irq, void *_chip) +{ + int rc; + struct qpnp_bms_chip *chip = _chip; + + pr_debug("fifo_update_done triggered\n"); + + mutex_lock(&chip->bms_data_mutex); + + if (chip->suspend_data_valid) { + pr_debug("Suspend data not processed yet\n"); + goto fail_fifo; + } + + rc = calib_vadc(chip); + if (rc) + pr_err("Unable to calibrate vadc rc=%d\n", rc); + + /* clear old data */ + memset(&chip->bms_data, 0, sizeof(chip->bms_data)); + /* + * 1. Read FIFO and populate the bms_data + * 2. Clear FIFO data + * 3. Notify userspace + */ + rc = update_fsm_state(chip); + if (rc) { + pr_err("Unable to read FSM state rc=%d\n", rc); + goto fail_fifo; + } + pr_debug("fsm_state=%d\n", chip->current_fsm_state); + + rc = read_and_populate_fifo_data(chip); + if (rc) { + pr_err("Unable to read FIFO data rc=%d\n", rc); + goto fail_fifo; + } + + rc = clear_fifo_acc_data(chip); + if (rc) + pr_err("Unable to clear FIFO/ACC data rc=%d\n", rc); + + /* update the sequence number */ + chip->bms_data.seq_num = chip->seq_num++; + + dump_bms_data(__func__, chip); + + /* signal the read thread */ + chip->data_ready = 1; + wake_up_interruptible(&chip->bms_wait_q); + + /* hold a wake lock until the read thread is scheduled */ + if (chip->bms_dev_open) + pm_stay_awake(chip->dev); +fail_fifo: + mutex_unlock(&chip->bms_data_mutex); + return IRQ_HANDLED; +} + +static irqreturn_t bms_fsm_state_change_irq_handler(int irq, void *_chip) +{ + int rc; + struct qpnp_bms_chip *chip = _chip; + + pr_debug("fsm_state_changed triggered\n"); + + mutex_lock(&chip->bms_data_mutex); + + if (chip->suspend_data_valid) { + pr_debug("Suspend data not processed yet\n"); + goto fail_state; + } + + rc = calib_vadc(chip); + if (rc) + pr_err("Unable to calibrate vadc rc=%d\n", rc); + + /* clear old data */ + memset(&chip->bms_data, 0, sizeof(chip->bms_data)); + /* + * 1. Read FIFO and ACC_DATA and populate the bms_data + * 2. Clear FIFO & ACC data + * 3. Notify userspace + */ + pr_debug("prev_fsm_state=%d\n", chip->current_fsm_state); + + rc = read_and_populate_fifo_data(chip); + if (rc) { + pr_err("Unable to read FIFO data rc=%d\n", rc); + goto fail_state; + } + + /* read accumulator data */ + rc = read_and_populate_acc_data(chip); + if (rc) { + pr_err("Unable to read ACC_SD data rc=%d\n", rc); + goto fail_state; + } + + rc = update_fsm_state(chip); + if (rc) { + pr_err("Unable to read FSM state rc=%d\n", rc); + goto fail_state; + } + + rc = clear_fifo_acc_data(chip); + if (rc) + pr_err("Unable to clear FIFO/ACC data rc=%d\n", rc); + + /* update the sequence number */ + chip->bms_data.seq_num = chip->seq_num++; + + dump_bms_data(__func__, chip); + + /* signal the read thread */ + chip->data_ready = 1; + wake_up_interruptible(&chip->bms_wait_q); + + /* hold a wake lock until the read thread is scheduled */ + if (chip->bms_dev_open) + pm_stay_awake(chip->dev); +fail_state: + mutex_unlock(&chip->bms_data_mutex); + return IRQ_HANDLED; +} + +static int read_shutdown_ocv_soc(struct qpnp_bms_chip *chip) +{ + u8 stored_soc = 0; + u16 stored_ocv = 0; + int rc; + + rc = qpnp_read_wrapper(chip, (u8 *)&stored_ocv, + chip->base + BMS_OCV_REG, 2); + if (rc) { + pr_err("failed to read addr = %d %d\n", + chip->base + BMS_OCV_REG, rc); + return -EINVAL; + } + + /* if shutdwon ocv is invalid, reject shutdown soc too */ + if (!stored_ocv || (stored_ocv == OCV_INVALID)) { + pr_debug("shutdown OCV %d - invalid\n", stored_ocv); + chip->shutdown_ocv = OCV_INVALID; + chip->shutdown_soc = SOC_INVALID; + return -EINVAL; + } + chip->shutdown_ocv = stored_ocv * 1000; + + /* + * The previous SOC is stored in the first 7 bits of the register as + * (Shutdown SOC + 1). This allows for register reset values of both + * 0x00 and 0xFF. + */ + rc = qpnp_read_wrapper(chip, &stored_soc, chip->base + BMS_SOC_REG, 1); + if (rc) { + pr_err("failed to read addr = %d %d\n", + chip->base + BMS_SOC_REG, rc); + return -EINVAL; + } + + if (!stored_soc || stored_soc == SOC_INVALID) { + chip->shutdown_soc = SOC_INVALID; + chip->shutdown_ocv = OCV_INVALID; + return -EINVAL; + } + chip->shutdown_soc = (stored_soc >> 1) - 1; + + pr_debug("shutdown_ocv=%d shutdown_soc=%d\n", + chip->shutdown_ocv, chip->shutdown_soc); + + return 0; +} + +static int interpolate_current_comp(int die_temp) +{ + int i; + int num_rows = ARRAY_SIZE(temp_curr_comp_lut); + + if (die_temp <= (temp_curr_comp_lut[0].temp_decideg)) + return temp_curr_comp_lut[0].current_ma; + + if (die_temp >= (temp_curr_comp_lut[num_rows - 1].temp_decideg)) + return temp_curr_comp_lut[num_rows - 1].current_ma; + + for (i = 0; i < num_rows - 1; i++) + if (die_temp <= (temp_curr_comp_lut[i].temp_decideg)) + break; + + if (die_temp == (temp_curr_comp_lut[i].temp_decideg)) + return temp_curr_comp_lut[i].current_ma; + + return linear_interpolate( + temp_curr_comp_lut[i - 1].current_ma, + temp_curr_comp_lut[i - 1].temp_decideg, + temp_curr_comp_lut[i].current_ma, + temp_curr_comp_lut[i].temp_decideg, + die_temp); +} + +static void adjust_pon_ocv(struct qpnp_bms_chip *chip, int batt_temp) +{ + int rc, current_ma, rbatt_mohm, die_temp, delta_uv, pc; + struct qpnp_vadc_result result; + + rc = qpnp_vadc_read(chip->vadc_dev, DIE_TEMP, &result); + if (rc) { + pr_err("error reading adc channel=%d, rc=%d\n", DIE_TEMP, rc); + } else { + pc = interpolate_pc(chip->batt_data->pc_temp_ocv_lut, + batt_temp, chip->last_ocv_uv / 1000); + /* + * For pc < 2, use the rbatt of pc = 2. This is to avoid + * the huge rbatt values at pc < 2 which can disrupt the pon_ocv + * calculations. + */ + if (pc < 2) + pc = 2; + rbatt_mohm = get_rbatt(chip, pc, batt_temp); + /* convert die_temp to DECIDEGC */ + die_temp = (int)result.physical / 100; + current_ma = interpolate_current_comp(die_temp); + delta_uv = rbatt_mohm * current_ma; + pr_debug("PON OCV changed from %d to %d pc=%d rbatt=%d current_ma=%d die_temp=%d batt_temp=%d delta_uv=%d\n", + chip->last_ocv_uv, chip->last_ocv_uv + delta_uv, pc, + rbatt_mohm, current_ma, die_temp, batt_temp, delta_uv); + + chip->last_ocv_uv += delta_uv; + } +} + +static int calculate_initial_soc(struct qpnp_bms_chip *chip) +{ + int rc, batt_temp = 0, est_ocv = 0; + + rc = get_batt_therm(chip, &batt_temp); + if (rc < 0) { + pr_err("Unable to read batt temp, using default=%d\n", + BMS_DEFAULT_TEMP); + batt_temp = BMS_DEFAULT_TEMP; + } + + rc = read_and_update_ocv(chip, batt_temp, true); + if (rc) { + pr_err("Unable to read PON OCV rc=%d\n", rc); + return rc; + } + + rc = read_shutdown_ocv_soc(chip); + if (rc < 0 || chip->dt.cfg_ignore_shutdown_soc) + chip->shutdown_soc_invalid = true; + + if (chip->warm_reset) { + /* + * if we have powered on from warm reset - + * Always use shutdown SOC. If shudown SOC is invalid then + * estimate OCV + */ + if (chip->shutdown_soc_invalid) { + pr_debug("Estimate OCV\n"); + est_ocv = estimate_ocv(chip); + if (est_ocv <= 0) { + pr_err("Unable to estimate OCV rc=%d\n", + est_ocv); + return -EINVAL; + } + chip->last_ocv_uv = est_ocv; + chip->calculated_soc = lookup_soc_ocv(chip, est_ocv, + batt_temp); + } else { + chip->last_ocv_uv = chip->shutdown_ocv; + chip->last_soc = chip->shutdown_soc; + chip->calculated_soc = lookup_soc_ocv(chip, + chip->shutdown_ocv, batt_temp); + pr_debug("Using shutdown SOC\n"); + } + } else { + /* + * In PM8916 2.0 PON OCV calculation is delayed due to + * change in the ordering of power-on sequence of LDO6. + * Adjust PON OCV to include current during PON. + */ + if (chip->workaround_flag & WRKARND_PON_OCV_COMP) + adjust_pon_ocv(chip, batt_temp); + + /* !warm_reset use PON OCV only if shutdown SOC is invalid */ + chip->calculated_soc = lookup_soc_ocv(chip, + chip->last_ocv_uv, batt_temp); + if (!chip->shutdown_soc_invalid && + (abs(chip->shutdown_soc - chip->calculated_soc) < + chip->dt.cfg_shutdown_soc_valid_limit)) { + chip->last_ocv_uv = chip->shutdown_ocv; + chip->last_soc = chip->shutdown_soc; + chip->calculated_soc = lookup_soc_ocv(chip, + chip->shutdown_ocv, batt_temp); + pr_debug("Using shutdown SOC\n"); + } else { + chip->shutdown_soc_invalid = true; + pr_debug("Using PON SOC\n"); + } + } + /* store the start-up OCV for voltage-based-soc */ + chip->voltage_soc_uv = chip->last_ocv_uv; + + pr_info("warm_reset=%d est_ocv=%d shutdown_soc_invalid=%d shutdown_ocv=%d shutdown_soc=%d last_soc=%d calculated_soc=%d last_ocv_uv=%d\n", + chip->warm_reset, est_ocv, chip->shutdown_soc_invalid, + chip->shutdown_ocv, chip->shutdown_soc, chip->last_soc, + chip->calculated_soc, chip->last_ocv_uv); + + return 0; +} + +static int calculate_initial_aging_comp(struct qpnp_bms_chip *chip) +{ + int rc; + bool battery_removed = is_battery_replaced_in_offmode(chip); + + if (battery_removed || chip->shutdown_soc_invalid) { + pr_info("Clearing aging data battery_removed=%d shutdown_soc_invalid=%d\n", + battery_removed, chip->shutdown_soc_invalid); + chip->charge_cycles = 0; + chip->charge_increase = 0; + rc = backup_charge_cycle(chip); + if (rc) + pr_err("Unable to reset aging data rc=%d\n", rc); + } else { + rc = read_chgcycle_data_from_backup(chip); + if (rc) + pr_err("Unable to read aging data rc=%d\n", rc); + } + + pr_debug("Initial aging data charge_cycles=%u charge_increase=%u\n", + chip->charge_cycles, chip->charge_increase); + return rc; +} + +static int bms_load_hw_defaults(struct qpnp_bms_chip *chip) +{ + u8 val, bms_en = 0; + u32 interval[2], count[2], fifo[2]; + int rc; + + /* S3 OCV tolerence threshold */ + if (chip->dt.cfg_s3_ocv_tol_uv >= 0 && + chip->dt.cfg_s3_ocv_tol_uv <= MAX_OCV_TOL_THRESHOLD) { + val = chip->dt.cfg_s3_ocv_tol_uv / OCV_TOL_LSB_UV; + rc = qpnp_masked_write_base(chip, + chip->base + S3_OCV_TOL_CTL_REG, 0xFF, val); + if (rc) { + pr_err("Unable to write s3_ocv_tol_threshold rc=%d\n", + rc); + return rc; + } + } + + /* S1 accumulator threshold */ + if (chip->dt.cfg_s1_sample_count >= 1 && + chip->dt.cfg_s1_sample_count <= MAX_SAMPLE_COUNT) { + val = (chip->dt.cfg_s1_sample_count > 1) ? + (ilog2(chip->dt.cfg_s1_sample_count) - 1) : 0; + rc = qpnp_masked_write_base(chip, + chip->base + S1_ACC_CNT_REG, + ACC_CNT_MASK, val); + if (rc) { + pr_err("Unable to write s1 sample count rc=%d\n", rc); + return rc; + } + } + + /* S2 accumulator threshold */ + if (chip->dt.cfg_s2_sample_count >= 1 && + chip->dt.cfg_s2_sample_count <= MAX_SAMPLE_COUNT) { + val = (chip->dt.cfg_s2_sample_count > 1) ? + (ilog2(chip->dt.cfg_s2_sample_count) - 1) : 0; + rc = qpnp_masked_write_base(chip, + chip->base + S2_ACC_CNT_REG, + ACC_CNT_MASK, val); + if (rc) { + pr_err("Unable to write s2 sample count rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.cfg_s1_sample_interval_ms >= 0 && + chip->dt.cfg_s1_sample_interval_ms <= MAX_SAMPLE_INTERVAL) { + val = chip->dt.cfg_s1_sample_interval_ms / 10; + rc = qpnp_write_wrapper(chip, &val, + chip->base + S1_SAMPLE_INTVL_REG, 1); + if (rc) { + pr_err("Unable to write s1 sample inteval rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.cfg_s2_sample_interval_ms >= 0 && + chip->dt.cfg_s2_sample_interval_ms <= MAX_SAMPLE_INTERVAL) { + val = chip->dt.cfg_s2_sample_interval_ms / 10; + rc = qpnp_write_wrapper(chip, &val, + chip->base + S2_SAMPLE_INTVL_REG, 1); + if (rc) { + pr_err("Unable to write s2 sample inteval rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.cfg_s1_fifo_length >= 0 && + chip->dt.cfg_s1_fifo_length <= MAX_FIFO_REGS) { + rc = qpnp_masked_write_base(chip, chip->base + FIFO_LENGTH_REG, + S1_FIFO_LENGTH_MASK, + chip->dt.cfg_s1_fifo_length); + if (rc) { + pr_err("Unable to write s1 fifo length rc=%d\n", rc); + return rc; + } + } + + if (chip->dt.cfg_s2_fifo_length >= 0 && + chip->dt.cfg_s2_fifo_length <= MAX_FIFO_REGS) { + rc = qpnp_masked_write_base(chip, chip->base + + FIFO_LENGTH_REG, S2_FIFO_LENGTH_MASK, + chip->dt.cfg_s2_fifo_length + << S2_FIFO_LENGTH_SHIFT); + if (rc) { + pr_err("Unable to write s2 fifo length rc=%d\n", rc); + return rc; + } + } + + get_sample_interval(chip, S1_STATE, &interval[0]); + get_sample_interval(chip, S2_STATE, &interval[1]); + get_sample_count(chip, S1_STATE, &count[0]); + get_sample_count(chip, S2_STATE, &count[1]); + get_fifo_length(chip, S1_STATE, &fifo[0]); + get_fifo_length(chip, S2_STATE, &fifo[1]); + + /* Force the BMS state to S2 at boot-up */ + rc = force_fsm_state(chip, S2_STATE); + if (rc) { + pr_err("Unable to force S2 state rc=%d\n", rc); + return rc; + } + + rc = qpnp_read_wrapper(chip, &bms_en, chip->base + EN_CTL_REG, 1); + if (rc) { + pr_err("Unable to read BMS_EN state rc=%d\n", rc); + return rc; + } + + rc = update_fsm_state(chip); + if (rc) { + pr_err("Unable to read FSM state rc=%d\n", rc); + return rc; + } + + pr_info("BMS_EN=%d Sample_Interval-S1=[%d]S2=[%d] Sample_Count-S1=[%d]S2=[%d] Fifo_Length-S1=[%d]S2=[%d] FSM_state=%d\n", + !!bms_en, interval[0], interval[1], count[0], + count[1], fifo[0], fifo[1], + chip->current_fsm_state); + + return 0; +} + +static ssize_t vm_bms_read(struct file *file, char __user *buf, size_t count, + loff_t *ppos) +{ + int rc; + struct qpnp_bms_chip *chip = file->private_data; + + if (!chip->data_ready && (file->f_flags & O_NONBLOCK)) { + rc = -EAGAIN; + goto fail_read; + } + + rc = wait_event_interruptible(chip->bms_wait_q, chip->data_ready); + if (rc) { + pr_debug("wait failed! rc=%d\n", rc); + goto fail_read; + } + + if (!chip->data_ready) { + pr_debug("No Data, false wakeup\n"); + rc = -EFAULT; + goto fail_read; + } + + mutex_lock(&chip->bms_data_mutex); + + if (copy_to_user(buf, &chip->bms_data, sizeof(chip->bms_data))) { + pr_err("Failed in copy_to_user\n"); + mutex_unlock(&chip->bms_data_mutex); + rc = -EFAULT; + goto fail_read; + } + pr_debug("Data copied!!\n"); + chip->data_ready = 0; + + mutex_unlock(&chip->bms_data_mutex); + /* wakelock-timeout for userspace to pick up */ + pm_wakeup_event(chip->dev, BMS_READ_TIMEOUT); + + return sizeof(chip->bms_data); + +fail_read: + pm_relax(chip->dev); + return rc; +} + +static int vm_bms_open(struct inode *inode, struct file *file) +{ + struct qpnp_bms_chip *chip = container_of(inode->i_cdev, + struct qpnp_bms_chip, bms_cdev); + + mutex_lock(&chip->bms_device_mutex); + + if (chip->bms_dev_open) { + pr_debug("BMS device already open\n"); + mutex_unlock(&chip->bms_device_mutex); + return -EBUSY; + } + + chip->bms_dev_open = true; + file->private_data = chip; + pr_debug("BMS device opened\n"); + + mutex_unlock(&chip->bms_device_mutex); + + return 0; +} + +static int vm_bms_release(struct inode *inode, struct file *file) +{ + struct qpnp_bms_chip *chip = container_of(inode->i_cdev, + struct qpnp_bms_chip, bms_cdev); + + mutex_lock(&chip->bms_device_mutex); + + chip->bms_dev_open = false; + pm_relax(chip->dev); + pr_debug("BMS device closed\n"); + + mutex_unlock(&chip->bms_device_mutex); + + return 0; +} + +static const struct file_operations bms_fops = { + .owner = THIS_MODULE, + .open = vm_bms_open, + .read = vm_bms_read, + .release = vm_bms_release, +}; + +static void bms_init_defaults(struct qpnp_bms_chip *chip) +{ + chip->data_ready = 0; + chip->last_ocv_raw = OCV_UNINITIALIZED; + chip->battery_status = POWER_SUPPLY_STATUS_UNKNOWN; + chip->battery_present = -EINVAL; + chip->calculated_soc = -EINVAL; + chip->last_soc = -EINVAL; + chip->vbms_lv_wake_source.disabled = 1; + chip->vbms_cv_wake_source.disabled = 1; + chip->vbms_soc_wake_source.disabled = 1; + chip->ocv_at_100 = -EINVAL; + chip->prev_soc_uuc = -EINVAL; + chip->charge_cycles = 0; + chip->start_soc = 0; + chip->end_soc = 0; + chip->charge_increase = 0; +} + +#define REQUEST_IRQ(chip, rc, irq_name) \ +do { \ + rc = devm_request_threaded_irq(chip->dev, \ + chip->irq_name##_irq.irq, NULL, \ + bms_##irq_name##_irq_handler, \ + IRQF_TRIGGER_RISING | IRQF_ONESHOT, \ + #irq_name, chip); \ + if (rc < 0) \ + pr_err("Unable to request " #irq_name " irq: %d\n", rc);\ +} while (0) + +#define FIND_IRQ(chip, pdev, irq_name, rc) \ +do { \ + chip->irq_name##_irq.irq = of_irq_get_byname(child, \ + #irq_name); \ + if (chip->irq_name##_irq.irq < 0) { \ + rc = chip->irq_name##_irq.irq; \ + pr_err("Unable to get " #irq_name " irq rc=%d\n", rc); \ + } \ +} while (0) + +static int bms_request_irqs(struct qpnp_bms_chip *chip) +{ + int rc; + + REQUEST_IRQ(chip, rc, fifo_update_done); + if (rc < 0) + return rc; + + REQUEST_IRQ(chip, rc, fsm_state_change); + if (rc < 0) + return rc; + + /* Disable the state change IRQ */ + disable_bms_irq(&chip->fsm_state_change_irq); + enable_irq_wake(chip->fifo_update_done_irq.irq); + + return 0; +} + +static int bms_find_irqs(struct qpnp_bms_chip *chip, struct device_node *child) +{ + int rc = 0; + + FIND_IRQ(chip, child, fifo_update_done, rc); + if (rc < 0) + return rc; + FIND_IRQ(chip, child, fsm_state_change, rc); + if (rc < 0) + return rc; + + return 0; +} + + +static int64_t read_battery_id(struct qpnp_bms_chip *chip) +{ + int rc; + struct qpnp_vadc_result result; + + rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result); + if (rc) { + pr_err("error reading batt id channel = %d, rc = %d\n", + LR_MUX2_BAT_ID, rc); + return rc; + } + + return result.physical; +} + +static int show_bms_config(struct seq_file *m, void *data) +{ + struct qpnp_bms_chip *chip = m->private; + int s1_sample_interval, s2_sample_interval; + int s1_sample_count, s2_sample_count; + int s1_fifo_length, s2_fifo_length; + + get_sample_interval(chip, S1_STATE, &s1_sample_interval); + get_sample_interval(chip, S2_STATE, &s2_sample_interval); + get_sample_count(chip, S1_STATE, &s1_sample_count); + get_sample_count(chip, S2_STATE, &s2_sample_count); + get_fifo_length(chip, S1_STATE, &s1_fifo_length); + get_fifo_length(chip, S2_STATE, &s2_fifo_length); + + seq_printf(m, "r_conn_mohm\t=\t%d\n" + "v_cutoff_uv\t=\t%d\n" + "max_voltage_uv\t=\t%d\n" + "use_voltage_soc\t=\t%d\n" + "low_soc_calc_threshold\t=\t%d\n" + "low_soc_calculate_soc_ms\t=\t%d\n" + "low_voltage_threshold\t=\t%d\n" + "low_voltage_calculate_soc_ms\t=\t%d\n" + "calculate_soc_ms\t=\t%d\n" + "voltage_soc_timeout_ms\t=\t%d\n" + "ignore_shutdown_soc\t=\t%d\n" + "shutdown_soc_valid_limit\t=\t%d\n" + "force_s3_on_suspend\t=\t%d\n" + "report_charger_eoc\t=\t%d\n" + "aging_compensation\t=\t%d\n" + "use_reported_soc\t=\t%d\n" + "s1_sample_interval_ms\t=\t%d\n" + "s2_sample_interval_ms\t=\t%d\n" + "s1_sample_count\t=\t%d\n" + "s2_sample_count\t=\t%d\n" + "s1_fifo_length\t=\t%d\n" + "s2_fifo_length\t=\t%d\n", + chip->dt.cfg_r_conn_mohm, + chip->dt.cfg_v_cutoff_uv, + chip->dt.cfg_max_voltage_uv, + chip->dt.cfg_use_voltage_soc, + chip->dt.cfg_low_soc_calc_threshold, + chip->dt.cfg_low_soc_calculate_soc_ms, + chip->dt.cfg_low_voltage_threshold, + chip->dt.cfg_low_voltage_calculate_soc_ms, + chip->dt.cfg_calculate_soc_ms, + chip->dt.cfg_voltage_soc_timeout_ms, + chip->dt.cfg_ignore_shutdown_soc, + chip->dt.cfg_shutdown_soc_valid_limit, + chip->dt.cfg_force_s3_on_suspend, + chip->dt.cfg_report_charger_eoc, + chip->dt.cfg_battery_aging_comp, + chip->dt.cfg_use_reported_soc, + s1_sample_interval, + s2_sample_interval, + s1_sample_count, + s2_sample_count, + s1_fifo_length, + s2_fifo_length); + + return 0; +} + +static int bms_config_open(struct inode *inode, struct file *file) +{ + struct qpnp_bms_chip *chip = inode->i_private; + + return single_open(file, show_bms_config, chip); +} + +static const struct file_operations bms_config_debugfs_ops = { + .owner = THIS_MODULE, + .open = bms_config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int show_bms_status(struct seq_file *m, void *data) +{ + struct qpnp_bms_chip *chip = m->private; + + seq_printf(m, "bms_psy_registered\t=\t%d\n" + "bms_dev_open\t=\t%d\n" + "warm_reset\t=\t%d\n" + "battery_status\t=\t%d\n" + "battery_present\t=\t%d\n" + "in_cv_state\t=\t%d\n" + "calculated_soc\t=\t%d\n" + "last_soc\t=\t%d\n" + "last_ocv_uv\t=\t%d\n" + "last_ocv_raw\t=\t%d\n" + "last_soc_unbound\t=\t%d\n" + "current_fsm_state\t=\t%d\n" + "current_now\t=\t%d\n" + "ocv_at_100\t=\t%d\n" + "low_voltage_ws_active\t=\t%d\n" + "cv_ws_active\t=\t%d\n", + chip->bms_psy_registered, + chip->bms_dev_open, + chip->warm_reset, + chip->battery_status, + chip->battery_present, + chip->in_cv_state, + chip->calculated_soc, + chip->last_soc, + chip->last_ocv_uv, + chip->last_ocv_raw, + chip->last_soc_unbound, + chip->current_fsm_state, + chip->current_now, + chip->ocv_at_100, + bms_wake_active(&chip->vbms_lv_wake_source), + bms_wake_active(&chip->vbms_cv_wake_source)); + return 0; +} + +static int bms_status_open(struct inode *inode, struct file *file) +{ + struct qpnp_bms_chip *chip = inode->i_private; + + return single_open(file, show_bms_status, chip); +} + +static const struct file_operations bms_status_debugfs_ops = { + .owner = THIS_MODULE, + .open = bms_status_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int show_bms_data(struct seq_file *m, void *data) +{ + struct qpnp_bms_chip *chip = m->private; + int i; + + mutex_lock(&chip->bms_data_mutex); + + seq_printf(m, "seq_num=%d\n", chip->bms_data.seq_num); + for (i = 0; i < chip->bms_data.num_fifo; i++) + seq_printf(m, "fifo_uv[%d]=%d sample_count=%d interval_ms=%d\n", + i, chip->bms_data.fifo_uv[i], + chip->bms_data.sample_count, + chip->bms_data.sample_interval_ms); + seq_printf(m, "acc_uv=%d sample_count=%d sample_interval=%d\n", + chip->bms_data.acc_uv, chip->bms_data.acc_count, + chip->bms_data.sample_interval_ms); + + mutex_unlock(&chip->bms_data_mutex); + + return 0; +} + +static int bms_data_open(struct inode *inode, struct file *file) +{ + struct qpnp_bms_chip *chip = inode->i_private; + + return single_open(file, show_bms_data, chip); +} + +static const struct file_operations bms_data_debugfs_ops = { + .owner = THIS_MODULE, + .open = bms_data_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int set_battery_data(struct qpnp_bms_chip *chip) +{ + int64_t battery_id; + int rc = 0; + struct bms_battery_data *batt_data; + struct device_node *node; + + battery_id = read_battery_id(chip); + if (battery_id < 0) { + pr_err("cannot read battery id err = %lld\n", battery_id); + return battery_id; + } + node = of_find_node_by_name(chip->pdev->dev.of_node, + "qcom,battery-data"); + if (!node) { + pr_err("No available batterydata\n"); + return -EINVAL; + } + + batt_data = devm_kzalloc(chip->dev, + sizeof(struct bms_battery_data), GFP_KERNEL); + if (!batt_data) + return -EINVAL; + + batt_data->fcc_temp_lut = devm_kzalloc(chip->dev, + sizeof(struct single_row_lut), GFP_KERNEL); + batt_data->pc_temp_ocv_lut = devm_kzalloc(chip->dev, + sizeof(struct pc_temp_ocv_lut), GFP_KERNEL); + batt_data->rbatt_sf_lut = devm_kzalloc(chip->dev, + sizeof(struct sf_lut), GFP_KERNEL); + batt_data->ibat_acc_lut = devm_kzalloc(chip->dev, + sizeof(struct ibat_temp_acc_lut), GFP_KERNEL); + + batt_data->max_voltage_uv = -1; + batt_data->cutoff_uv = -1; + batt_data->iterm_ua = -1; + + /* + * if the alloced luts are 0s, of_batterydata_read_data ignores + * them. + */ + rc = of_batterydata_read_data(node, batt_data, battery_id); + if (rc || !batt_data->pc_temp_ocv_lut + || !batt_data->fcc_temp_lut + || !batt_data->rbatt_sf_lut + || !batt_data->ibat_acc_lut) { + pr_err("battery data load failed\n"); + devm_kfree(chip->dev, batt_data->fcc_temp_lut); + devm_kfree(chip->dev, batt_data->pc_temp_ocv_lut); + devm_kfree(chip->dev, batt_data->rbatt_sf_lut); + devm_kfree(chip->dev, batt_data->ibat_acc_lut); + devm_kfree(chip->dev, batt_data); + return rc; + } + + if (batt_data->pc_temp_ocv_lut == NULL) { + pr_err("temp ocv lut table has not been loaded\n"); + devm_kfree(chip->dev, batt_data->fcc_temp_lut); + devm_kfree(chip->dev, batt_data->pc_temp_ocv_lut); + devm_kfree(chip->dev, batt_data->rbatt_sf_lut); + devm_kfree(chip->dev, batt_data->ibat_acc_lut); + devm_kfree(chip->dev, batt_data); + + return -EINVAL; + } + + /* check if ibat_acc_lut is valid */ + if (!batt_data->ibat_acc_lut->rows) { + pr_info("ibat_acc_lut not present\n"); + devm_kfree(chip->dev, batt_data->ibat_acc_lut); + batt_data->ibat_acc_lut = NULL; + } + + /* Override battery properties if specified in the battery profile */ + if (batt_data->max_voltage_uv >= 0) + chip->dt.cfg_max_voltage_uv = batt_data->max_voltage_uv; + if (batt_data->cutoff_uv >= 0) + chip->dt.cfg_v_cutoff_uv = batt_data->cutoff_uv; + + chip->batt_data = batt_data; + + return 0; +} + +static int parse_pdev_dt_properties(struct qpnp_bms_chip *chip, + struct platform_device *pdev) +{ + struct device_node *child; + int rc; + unsigned int base; + + chip->dev = &(pdev->dev); + chip->pdev = pdev; + + if (of_get_available_child_count(pdev->dev.of_node) == 0) { + pr_err("no child nodes found\n"); + return -ENXIO; + } + + + for_each_available_child_of_node(pdev->dev.of_node, child) { + rc = of_property_read_u32(child, "reg", &base); + if (rc < 0) { + dev_err(&pdev->dev, + "Couldn't find reg in node = %s rc = %d\n", + child->full_name, rc); + return -ENXIO; + } + + pr_debug("Node name = %s\n", child->name); + + if (strcmp("qcom,batt-pres-status", + child->name) == 0) { + chip->batt_pres_addr = base; + continue; + } + + if (strcmp("qcom,qpnp-chg-pres", + child->name) == 0) { + chip->chg_pres_addr = base; + continue; + } + + chip->base = base; + rc = bms_find_irqs(chip, child); + if (rc) { + pr_err("Could not find irqs rc=%d\n", rc); + return rc; + } + } + + if (chip->base == 0) { + dev_err(&pdev->dev, "BMS peripheral was not registered\n"); + return -EINVAL; + } + + pr_debug("bms-base=0x%04x bat-pres-reg=0x%04x qpnp-chg-pres=0x%04x\n", + chip->base, chip->batt_pres_addr, chip->chg_pres_addr); + + return 0; +} + +#define PROP_READ(chip_prop, qpnp_pdev_property, retval) \ +do { \ + if (retval) \ + break; \ + retval = of_property_read_u32(chip->pdev->dev.of_node, \ + "qcom," qpnp_pdev_property, \ + &chip->dt.chip_prop); \ + if (retval) { \ + pr_err("Error reading " #qpnp_pdev_property \ + " property %d\n", retval); \ + } \ +} while (0) + +#define PROP_READ_OPTIONAL(chip_prop, qpnp_pdev_property, retval) \ +do { \ + retval = of_property_read_u32(chip->pdev->dev.of_node, \ + "qcom," qpnp_pdev_property, \ + &chip->dt.chip_prop); \ + if (retval) \ + chip->dt.chip_prop = -EINVAL; \ +} while (0) + +static int parse_bms_dt_properties(struct qpnp_bms_chip *chip) +{ + int rc = 0; + + PROP_READ(cfg_v_cutoff_uv, "v-cutoff-uv", rc); + PROP_READ(cfg_max_voltage_uv, "max-voltage-uv", rc); + PROP_READ(cfg_r_conn_mohm, "r-conn-mohm", rc); + PROP_READ(cfg_shutdown_soc_valid_limit, + "shutdown-soc-valid-limit", rc); + PROP_READ(cfg_low_soc_calc_threshold, + "low-soc-calculate-soc-threshold", rc); + PROP_READ(cfg_low_soc_calculate_soc_ms, + "low-soc-calculate-soc-ms", rc); + PROP_READ(cfg_low_voltage_calculate_soc_ms, + "low-voltage-calculate-soc-ms", rc); + PROP_READ(cfg_calculate_soc_ms, "calculate-soc-ms", rc); + PROP_READ(cfg_low_voltage_threshold, "low-voltage-threshold", rc); + PROP_READ(cfg_voltage_soc_timeout_ms, + "volatge-soc-timeout-ms", rc); + + if (rc) { + pr_err("Missing required properties rc=%d\n", rc); + return rc; + } + + PROP_READ_OPTIONAL(cfg_s1_sample_interval_ms, + "s1-sample-interval-ms", rc); + PROP_READ_OPTIONAL(cfg_s2_sample_interval_ms, + "s2-sample-interval-ms", rc); + PROP_READ_OPTIONAL(cfg_s1_sample_count, "s1-sample-count", rc); + PROP_READ_OPTIONAL(cfg_s2_sample_count, "s2-sample-count", rc); + PROP_READ_OPTIONAL(cfg_s1_fifo_length, "s1-fifo-length", rc); + PROP_READ_OPTIONAL(cfg_s2_fifo_length, "s2-fifo-length", rc); + PROP_READ_OPTIONAL(cfg_s3_ocv_tol_uv, "s3-ocv-tolerence-uv", rc); + PROP_READ_OPTIONAL(cfg_low_soc_fifo_length, + "low-soc-fifo-length", rc); + PROP_READ_OPTIONAL(cfg_soc_resume_limit, "resume-soc", rc); + PROP_READ_OPTIONAL(cfg_low_temp_threshold, + "low-temp-threshold", rc); + if (rc) + chip->dt.cfg_low_temp_threshold = 0; + + PROP_READ_OPTIONAL(cfg_ibat_avg_samples, + "ibat-avg-samples", rc); + if (rc || (chip->dt.cfg_ibat_avg_samples <= 0) || + (chip->dt.cfg_ibat_avg_samples > IAVG_SAMPLES)) + chip->dt.cfg_ibat_avg_samples = IAVG_SAMPLES; + + chip->dt.cfg_ignore_shutdown_soc = of_property_read_bool( + chip->pdev->dev.of_node, "qcom,ignore-shutdown-soc"); + chip->dt.cfg_use_voltage_soc = of_property_read_bool( + chip->pdev->dev.of_node, "qcom,use-voltage-soc"); + chip->dt.cfg_force_s3_on_suspend = of_property_read_bool( + chip->pdev->dev.of_node, "qcom,force-s3-on-suspend"); + chip->dt.cfg_report_charger_eoc = of_property_read_bool( + chip->pdev->dev.of_node, "qcom,report-charger-eoc"); + chip->dt.cfg_disable_bms = of_property_read_bool( + chip->pdev->dev.of_node, "qcom,disable-bms"); + chip->dt.cfg_force_bms_active_on_charger = of_property_read_bool( + chip->pdev->dev.of_node, + "qcom,force-bms-active-on-charger"); + chip->dt.cfg_battery_aging_comp = of_property_read_bool( + chip->pdev->dev.of_node, "qcom,batt-aging-comp"); + chip->dt.cfg_use_reported_soc = of_property_read_bool( + chip->pdev->dev.of_node, "qcom,use-reported-soc"); + pr_debug("v_cutoff_uv=%d, max_v=%d\n", chip->dt.cfg_v_cutoff_uv, + chip->dt.cfg_max_voltage_uv); + pr_debug("r_conn=%d shutdown_soc_valid_limit=%d low_temp_threshold=%d ibat_avg_samples=%d\n", + chip->dt.cfg_r_conn_mohm, + chip->dt.cfg_shutdown_soc_valid_limit, + chip->dt.cfg_low_temp_threshold, + chip->dt.cfg_ibat_avg_samples); + pr_debug("ignore_shutdown_soc=%d, use_voltage_soc=%d low_soc_fifo_length=%d\n", + chip->dt.cfg_ignore_shutdown_soc, + chip->dt.cfg_use_voltage_soc, + chip->dt.cfg_low_soc_fifo_length); + pr_debug("force-s3-on-suspend=%d report-charger-eoc=%d disable-bms=%d disable-suspend-on-usb=%d aging_compensation=%d\n", + chip->dt.cfg_force_s3_on_suspend, + chip->dt.cfg_report_charger_eoc, + chip->dt.cfg_disable_bms, + chip->dt.cfg_force_bms_active_on_charger, + chip->dt.cfg_battery_aging_comp); + pr_debug("use-reported-soc is %d\n", + chip->dt.cfg_use_reported_soc); + + return 0; +} + +static int bms_get_adc(struct qpnp_bms_chip *chip, + struct platform_device *pdev) +{ + int rc = 0; + + chip->vadc_dev = qpnp_get_vadc(&pdev->dev, "bms"); + if (IS_ERR(chip->vadc_dev)) { + rc = PTR_ERR(chip->vadc_dev); + if (rc == -EPROBE_DEFER) + pr_err("vadc not found - defer probe rc=%d\n", rc); + else + pr_err("vadc property missing, rc=%d\n", rc); + + return rc; + } + + chip->adc_tm_dev = qpnp_get_adc_tm(&pdev->dev, "bms"); + if (IS_ERR(chip->adc_tm_dev)) { + rc = PTR_ERR(chip->adc_tm_dev); + if (rc == -EPROBE_DEFER) + pr_err("adc-tm not found - defer probe rc=%d\n", rc); + else + pr_err("adc-tm property missing, rc=%d\n", rc); + } + + return rc; +} + +static int register_bms_char_device(struct qpnp_bms_chip *chip) +{ + int rc; + + rc = alloc_chrdev_region(&chip->dev_no, 0, 1, "vm_bms"); + if (rc) { + pr_err("Unable to allocate chrdev rc=%d\n", rc); + return rc; + } + cdev_init(&chip->bms_cdev, &bms_fops); + rc = cdev_add(&chip->bms_cdev, chip->dev_no, 1); + if (rc) { + pr_err("Unable to add bms_cdev rc=%d\n", rc); + goto unregister_chrdev; + } + + chip->bms_class = class_create(THIS_MODULE, "vm_bms"); + if (IS_ERR_OR_NULL(chip->bms_class)) { + pr_err("Fail to create bms class\n"); + rc = -EINVAL; + goto delete_cdev; + } + chip->bms_device = device_create(chip->bms_class, + NULL, chip->dev_no, + NULL, "vm_bms"); + if (IS_ERR(chip->bms_device)) { + pr_err("Fail to create bms_device device\n"); + rc = -EINVAL; + goto delete_cdev; + } + + return 0; + +delete_cdev: + cdev_del(&chip->bms_cdev); +unregister_chrdev: + unregister_chrdev_region(chip->dev_no, 1); + return rc; +} + +static int qpnp_vm_bms_probe(struct platform_device *pdev) +{ + struct qpnp_bms_chip *chip; + struct device_node *revid_dev_node; + struct power_supply_config bms_psy_cfg; + int rc, vbatt = 0; + + chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); + return -EINVAL; + } + + rc = bms_get_adc(chip, pdev); + if (rc < 0) { + pr_err("Failed to get adc rc=%d\n", rc); + return rc; + } + + revid_dev_node = of_parse_phandle(pdev->dev.of_node, + "qcom,pmic-revid", 0); + if (!revid_dev_node) { + pr_err("Missing qcom,pmic-revid property\n"); + return -EINVAL; + } + + chip->revid_data = get_revid_data(revid_dev_node); + if (IS_ERR(chip->revid_data)) { + pr_err("revid error rc = %ld\n", PTR_ERR(chip->revid_data)); + return -EINVAL; + } + if ((chip->revid_data->pmic_subtype == PM8916_SUBTYPE) && + chip->revid_data->rev4 == PM8916_V2P0_REV4) + chip->workaround_flag |= WRKARND_PON_OCV_COMP; + + rc = qpnp_pon_is_warm_reset(); + if (rc < 0) { + pr_err("Error reading warm reset status rc=%d\n", rc); + return rc; + } + chip->warm_reset = !!rc; + + rc = parse_pdev_dt_properties(chip, pdev); + if (rc) { + pr_err("Error registering pdev resource rc=%d\n", rc); + return rc; + } + + rc = parse_bms_dt_properties(chip); + if (rc) { + pr_err("Unable to read all bms properties, rc = %d\n", rc); + return rc; + } + + if (chip->dt.cfg_disable_bms) { + pr_info("VMBMS disabled (disable-bms = 1)\n"); + rc = qpnp_masked_write_base(chip, chip->base + EN_CTL_REG, + BMS_EN_BIT, 0); + if (rc) + pr_err("Unable to disable VMBMS rc=%d\n", rc); + return -ENODEV; + } + + rc = qpnp_read_wrapper(chip, chip->revision, + chip->base + REVISION1_REG, 2); + if (rc) { + pr_err("Error reading version register rc=%d\n", rc); + return rc; + } + + pr_debug("BMS version: %hhu.%hhu\n", + chip->revision[1], chip->revision[0]); + + dev_set_drvdata(&pdev->dev, chip); + device_init_wakeup(&pdev->dev, 1); + mutex_init(&chip->bms_data_mutex); + mutex_init(&chip->bms_device_mutex); + mutex_init(&chip->last_soc_mutex); + mutex_init(&chip->state_change_mutex); + init_waitqueue_head(&chip->bms_wait_q); + + /* read battery-id and select the battery profile */ + rc = set_battery_data(chip); + if (rc) { + pr_err("Unable to read battery data %d\n", rc); + goto fail_init; + } + + /* set the battery profile */ + rc = config_battery_data(chip->batt_data); + if (rc) { + pr_err("Unable to config battery data %d\n", rc); + goto fail_init; + } + + wakeup_source_init(&chip->vbms_lv_wake_source.source, "vbms_lv_wake"); + wakeup_source_init(&chip->vbms_cv_wake_source.source, "vbms_cv_wake"); + wakeup_source_init(&chip->vbms_soc_wake_source.source, "vbms_soc_wake"); + INIT_DELAYED_WORK(&chip->monitor_soc_work, monitor_soc_work); + INIT_DELAYED_WORK(&chip->voltage_soc_timeout_work, + voltage_soc_timeout_work); + + bms_init_defaults(chip); + bms_load_hw_defaults(chip); + + if (is_battery_present(chip)) { + rc = setup_vbat_monitoring(chip); + if (rc) { + pr_err("fail to configure vbat monitoring rc=%d\n", + rc); + goto fail_setup; + } + } + + rc = bms_request_irqs(chip); + if (rc) { + pr_err("error requesting bms irqs, rc = %d\n", rc); + goto fail_irq; + } + + battery_insertion_check(chip); + battery_status_check(chip); + + /* character device to pass data to the userspace */ + rc = register_bms_char_device(chip); + if (rc) { + pr_err("Unable to regiter '/dev/vm_bms' rc=%d\n", rc); + goto fail_bms_device; + } + + the_chip = chip; + calculate_initial_soc(chip); + if (chip->dt.cfg_battery_aging_comp) { + rc = calculate_initial_aging_comp(chip); + if (rc) + pr_err("Unable to calculate initial aging data rc=%d\n", + rc); + } + + /* setup & register the battery power supply */ + chip->bms_psy_d.name = "bms"; + chip->bms_psy_d.type = POWER_SUPPLY_TYPE_BMS; + chip->bms_psy_d.properties = bms_power_props; + chip->bms_psy_d.num_properties = ARRAY_SIZE(bms_power_props); + chip->bms_psy_d.get_property = qpnp_vm_bms_power_get_property; + chip->bms_psy_d.set_property = qpnp_vm_bms_power_set_property; + chip->bms_psy_d.external_power_changed = qpnp_vm_bms_ext_power_changed; + chip->bms_psy_d.property_is_writeable = + qpnp_vm_bms_property_is_writeable; + + bms_psy_cfg.supplied_to = qpnp_vm_bms_supplicants; + bms_psy_cfg.num_supplicants = ARRAY_SIZE(qpnp_vm_bms_supplicants); + bms_psy_cfg.drv_data = chip; + bms_psy_cfg.of_node = NULL; + + chip->bms_psy = devm_power_supply_register(chip->dev, + &chip->bms_psy_d, + &bms_psy_cfg); + if (IS_ERR(chip->bms_psy)) { + pr_err("power_supply_register bms failed rc = %ld\n", + PTR_ERR(chip->bms_psy)); + goto fail_psy; + } + chip->bms_psy_registered = true; + + rc = get_battery_voltage(chip, &vbatt); + if (rc) { + pr_err("error reading vbat_sns adc channel=%d, rc=%d\n", + VBAT_SNS, rc); + goto fail_get_vtg; + } + + chip->debug_root = debugfs_create_dir("qpnp_vmbms", NULL); + if (!chip->debug_root) + pr_err("Couldn't create debug dir\n"); + + if (chip->debug_root) { + struct dentry *ent; + + ent = debugfs_create_file("bms_data", S_IFREG | 0444, + chip->debug_root, chip, + &bms_data_debugfs_ops); + if (!ent) + pr_err("Couldn't create bms_data debug file\n"); + + ent = debugfs_create_file("bms_config", S_IFREG | 0444, + chip->debug_root, chip, + &bms_config_debugfs_ops); + if (!ent) + pr_err("Couldn't create bms_config debug file\n"); + + ent = debugfs_create_file("bms_status", S_IFREG | 0444, + chip->debug_root, chip, + &bms_status_debugfs_ops); + if (!ent) + pr_err("Couldn't create bms_status debug file\n"); + } + + schedule_delayed_work(&chip->monitor_soc_work, 0); + + /* + * schedule a work to check if the userspace vmbms module + * has registered. Fall-back to voltage-based-soc reporting + * if it has not. + */ + schedule_delayed_work(&chip->voltage_soc_timeout_work, + msecs_to_jiffies(chip->dt.cfg_voltage_soc_timeout_ms)); + + pr_info("probe success: soc=%d vbatt=%d ocv=%d warm_reset=%d\n", + get_prop_bms_capacity(chip), vbatt, + chip->last_ocv_uv, chip->warm_reset); + + return rc; + +fail_get_vtg: + power_supply_unregister(chip->bms_psy); +fail_psy: + device_destroy(chip->bms_class, chip->dev_no); + cdev_del(&chip->bms_cdev); + unregister_chrdev_region(chip->dev_no, 1); +fail_bms_device: + chip->bms_psy_registered = false; +fail_irq: + reset_vbat_monitoring(chip); +fail_setup: + wakeup_source_trash(&chip->vbms_lv_wake_source.source); + wakeup_source_trash(&chip->vbms_cv_wake_source.source); + wakeup_source_trash(&chip->vbms_soc_wake_source.source); +fail_init: + mutex_destroy(&chip->bms_data_mutex); + mutex_destroy(&chip->last_soc_mutex); + mutex_destroy(&chip->state_change_mutex); + mutex_destroy(&chip->bms_device_mutex); + the_chip = NULL; + + return rc; +} + +static int qpnp_vm_bms_remove(struct platform_device *pdev) +{ + struct qpnp_bms_chip *chip = dev_get_drvdata(&pdev->dev); + + cancel_delayed_work_sync(&chip->monitor_soc_work); + debugfs_remove_recursive(chip->debug_root); + device_destroy(chip->bms_class, chip->dev_no); + cdev_del(&chip->bms_cdev); + unregister_chrdev_region(chip->dev_no, 1); + reset_vbat_monitoring(chip); + wakeup_source_trash(&chip->vbms_lv_wake_source.source); + wakeup_source_trash(&chip->vbms_cv_wake_source.source); + wakeup_source_trash(&chip->vbms_soc_wake_source.source); + mutex_destroy(&chip->bms_data_mutex); + mutex_destroy(&chip->last_soc_mutex); + mutex_destroy(&chip->state_change_mutex); + mutex_destroy(&chip->bms_device_mutex); + power_supply_unregister(chip->bms_psy); + dev_set_drvdata(&pdev->dev, NULL); + the_chip = NULL; + + return 0; +} + +static void process_suspend_data(struct qpnp_bms_chip *chip) +{ + int rc; + + mutex_lock(&chip->bms_data_mutex); + + chip->suspend_data_valid = false; + + memset(&chip->bms_data, 0, sizeof(chip->bms_data)); + + rc = read_and_populate_fifo_data(chip); + if (rc) + pr_err("Unable to read FIFO data rc=%d\n", rc); + + rc = read_and_populate_acc_data(chip); + if (rc) + pr_err("Unable to read ACC_SD data rc=%d\n", rc); + + rc = clear_fifo_acc_data(chip); + if (rc) + pr_err("Unable to clear FIFO/ACC data rc=%d\n", rc); + + if (chip->bms_data.num_fifo || chip->bms_data.acc_count) { + pr_debug("suspend data valid\n"); + chip->suspend_data_valid = true; + } + + mutex_unlock(&chip->bms_data_mutex); +} + +static void process_resume_data(struct qpnp_bms_chip *chip) +{ + int rc, batt_temp = 0; + int old_ocv = 0; + bool ocv_updated = false; + + rc = get_batt_therm(chip, &batt_temp); + if (rc < 0) { + pr_err("Unable to read batt temp, using default=%d\n", + BMS_DEFAULT_TEMP); + batt_temp = BMS_DEFAULT_TEMP; + } + + mutex_lock(&chip->bms_data_mutex); + /* + * We can get a h/w OCV update when the sleep_b + * is low, which is possible when APPS is suspended. + * So check for an OCV update only in bms_resume + */ + old_ocv = chip->last_ocv_uv; + rc = read_and_update_ocv(chip, batt_temp, false); + if (rc) + pr_err("Unable to read/upadate OCV rc=%d\n", rc); + + if (old_ocv != chip->last_ocv_uv) { + ocv_updated = true; + /* new OCV, clear suspended data */ + chip->suspend_data_valid = false; + memset(&chip->bms_data, 0, sizeof(chip->bms_data)); + chip->calculated_soc = lookup_soc_ocv(chip, + chip->last_ocv_uv, batt_temp); + pr_debug("OCV in sleep SOC=%d\n", chip->calculated_soc); + chip->last_soc_unbound = true; + chip->voltage_soc_uv = chip->last_ocv_uv; + pr_debug("update bms_psy\n"); + power_supply_changed(chip->bms_psy); + } + + if (ocv_updated || chip->suspend_data_valid) { + /* there is data to be sent */ + pr_debug("ocv_updated=%d suspend_data_valid=%d\n", + ocv_updated, chip->suspend_data_valid); + chip->bms_data.seq_num = chip->seq_num++; + dump_bms_data(__func__, chip); + + chip->data_ready = 1; + wake_up_interruptible(&chip->bms_wait_q); + if (chip->bms_dev_open) + pm_stay_awake(chip->dev); + + } + chip->suspend_data_valid = false; + mutex_unlock(&chip->bms_data_mutex); +} + +static int bms_suspend(struct device *dev) +{ + struct qpnp_bms_chip *chip = dev_get_drvdata(dev); + bool battery_charging = is_battery_charging(chip); + bool hi_power_state = is_hi_power_state_requested(chip); + bool charger_present = is_charger_present(chip); + bool bms_suspend_config; + + /* + * Keep BMS FSM active if 'cfg_force_bms_active_on_charger' property + * is present and charger inserted. This ensures that recharge + * starts once battery SOC falls below resume_soc. + */ + bms_suspend_config = chip->dt.cfg_force_bms_active_on_charger + && charger_present; + + chip->apply_suspend_config = false; + if (!battery_charging && !hi_power_state && !bms_suspend_config) + chip->apply_suspend_config = true; + + pr_debug("battery_charging=%d power_state=%s hi_power_state=0x%x apply_suspend_config=%d bms_suspend_config=%d usb_present=%d\n", + battery_charging, hi_power_state ? "hi" : "low", + chip->hi_power_state, + chip->apply_suspend_config, bms_suspend_config, + charger_present); + + if (chip->apply_suspend_config) { + if (chip->dt.cfg_force_s3_on_suspend) { + disable_bms_irq(&chip->fifo_update_done_irq); + pr_debug("Forcing S3 state\n"); + mutex_lock(&chip->state_change_mutex); + force_fsm_state(chip, S3_STATE); + mutex_unlock(&chip->state_change_mutex); + /* Store accumulated data if any */ + process_suspend_data(chip); + } + } + + cancel_delayed_work_sync(&chip->monitor_soc_work); + + return 0; +} + +static int bms_resume(struct device *dev) +{ + u8 state = 0; + int rc, monitor_soc_delay = 0; + unsigned long tm_now_sec; + struct qpnp_bms_chip *chip = dev_get_drvdata(dev); + + if (chip->apply_suspend_config) { + if (chip->dt.cfg_force_s3_on_suspend) { + /* + * Update the state to S2 only if we are in S3. There is + * a possibility of being in S2 if we resumed on + * a charger insertion + */ + mutex_lock(&chip->state_change_mutex); + rc = get_fsm_state(chip, &state); + if (rc) + pr_err("Unable to get FSM state rc=%d\n", rc); + if (rc || (state == S3_STATE)) { + pr_debug("Unforcing S3 state, setting S2 state\n"); + force_fsm_state(chip, S2_STATE); + } + mutex_unlock(&chip->state_change_mutex); + enable_bms_irq(&chip->fifo_update_done_irq); + /* + * if we were charging while suspended, we will + * be woken up by the fifo done interrupt and no + * additional processing is needed. + */ + process_resume_data(chip); + } + } + + /* Start monitor_soc_work based on when it last executed */ + rc = get_current_time(&tm_now_sec); + if (rc) { + pr_err("Could not read current time: %d\n", rc); + } else { + monitor_soc_delay = get_calculation_delay_ms(chip) - + ((tm_now_sec - chip->tm_sec) * 1000); + monitor_soc_delay = max(0, monitor_soc_delay); + } + pr_debug("monitor_soc_delay_sec=%d tm_now_sec=%ld chip->tm_sec=%ld\n", + monitor_soc_delay / 1000, tm_now_sec, chip->tm_sec); + schedule_delayed_work(&chip->monitor_soc_work, + msecs_to_jiffies(monitor_soc_delay)); + + return 0; +} + +static const struct dev_pm_ops qpnp_vm_bms_pm_ops = { + .suspend = bms_suspend, + .resume = bms_resume, +}; + +static const struct of_device_id qpnp_vm_bms_match_table[] = { + { .compatible = QPNP_VM_BMS_DEV_NAME }, + {} +}; + +static struct platform_driver qpnp_vm_bms_driver = { + .probe = qpnp_vm_bms_probe, + .remove = qpnp_vm_bms_remove, + .driver = { + .name = QPNP_VM_BMS_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = qpnp_vm_bms_match_table, + .pm = &qpnp_vm_bms_pm_ops, + }, +}; +module_platform_driver(qpnp_vm_bms_driver); + +MODULE_DESCRIPTION("QPNP VM-BMS Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" QPNP_VM_BMS_DEV_NAME); diff --git a/include/linux/batterydata-interface.h b/include/linux/batterydata-interface.h new file mode 100644 index 000000000000..4318eb9eac5a --- /dev/null +++ b/include/linux/batterydata-interface.h @@ -0,0 +1,15 @@ +/* Copyright (c) 2014-2015, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +int config_battery_data(struct bms_battery_data *profile); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 75aa98ffb40f..c9248e5ae2d1 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -65,6 +65,7 @@ header-y += auto_fs.h header-y += auxvec.h header-y += ax25.h header-y += b1lli.h +header-y += batterydata-interface.h header-y += baycom.h header-y += bcm933xx_hcs.h header-y += bfs_fs.h @@ -490,6 +491,7 @@ header-y += virtio_rng.h header-y += virtio_scsi.h header-y += virtio_types.h header-y += virtio_vsock.h +header-y += vm_bms.h header-y += vm_sockets.h header-y += vt.h header-y += vtpm_proxy.h diff --git a/include/uapi/linux/batterydata-interface.h b/include/uapi/linux/batterydata-interface.h new file mode 100644 index 000000000000..498f4e0335e6 --- /dev/null +++ b/include/uapi/linux/batterydata-interface.h @@ -0,0 +1,30 @@ +#ifndef __BATTERYDATA_LIB_H__ +#define __BATTERYDATA_LIB_H__ + +#include + +/** + * struct battery_params - Battery profile data to be exchanged. + * @soc: SOC (state of charge) of the battery + * @ocv_uv: OCV (open circuit voltage) of the battery + * @rbatt_sf: RBATT scaling factor + * @batt_temp: Battery temperature in deci-degree. + * @slope: Slope of the OCV-SOC curve. + * @fcc_mah: FCC (full charge capacity) of the battery. + */ +struct battery_params { + int soc; + int ocv_uv; + int rbatt_sf; + int batt_temp; + int slope; + int fcc_mah; +}; + +/* IOCTLs to query battery profile data */ +#define BPIOCXSOC _IOWR('B', 0x01, struct battery_params) /* SOC */ +#define BPIOCXRBATT _IOWR('B', 0x02, struct battery_params) /* RBATT SF */ +#define BPIOCXSLOPE _IOWR('B', 0x03, struct battery_params) /* SLOPE */ +#define BPIOCXFCC _IOWR('B', 0x04, struct battery_params) /* FCC */ + +#endif diff --git a/include/uapi/linux/vm_bms.h b/include/uapi/linux/vm_bms.h new file mode 100644 index 000000000000..364efc848855 --- /dev/null +++ b/include/uapi/linux/vm_bms.h @@ -0,0 +1,34 @@ +#ifndef __VM_BMS_H__ +#define __VM_BMS_H__ + +#define VM_BMS_DEVICE "/dev/vm_bms" +#define MAX_FIFO_REGS 8 + +/** + * struct qpnp_vm_bms_data - vm-bms data (passed to usersapce) + * @data_type: type of data filled up + * @num_fifo: count of valid fifo averages + * @fifo_uv: array of fifo averages in uv + * @sample_interval sample interval of the fifo data in ms + * @sample_count total samples in one fifo + * @acc_uv averaged accumulator value in uv + * @acc_count num of accumulated samples + * @seq_num sequence number of the data + */ +struct qpnp_vm_bms_data { + unsigned int num_fifo; + unsigned int fifo_uv[MAX_FIFO_REGS]; + unsigned int sample_interval_ms; + unsigned int sample_count; + unsigned int acc_uv; + unsigned int acc_count; + unsigned int seq_num; +}; + +enum vmbms_power_usecase { + VMBMS_IGNORE_ALL_BIT = 1, + VMBMS_VOICE_CALL_BIT = (1 << 4), + VMBMS_STATIC_DISPLAY_BIT = (1 << 5), +}; + +#endif /* __VM_BMS_H__ */ -- GitLab From 55e32400e4f2656901771de15b90824f191837f2 Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Thu, 19 Apr 2018 10:35:51 +0530 Subject: [PATCH 1599/1834] power: charger: Add snapshot of qpnp-linear-charger Initial snapshot of qpnp-linear-charger driver is taken from msm-3.18 kernel version @ commit f8b6819d0432d6 ("msm: ipa: Fix to handle NULL pointer dereference") Change spmi driver framework to platform driver. Add support to access spmi registers via register mapping. Also add USB power supply and extcon support to notify usb insertion/removal. Change-Id: I8a6ee04540b99c5abd958a7bcbc77c3e7da4d2e5 Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- .../power/supply/qcom/qpnp-linear-charger.txt | 211 + drivers/power/supply/qcom/Kconfig | 11 + drivers/power/supply/qcom/Makefile | 1 + .../power/supply/qcom/qpnp-linear-charger.c | 3544 +++++++++++++++++ 4 files changed, 3767 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/supply/qcom/qpnp-linear-charger.txt create mode 100644 drivers/power/supply/qcom/qpnp-linear-charger.c diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-linear-charger.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-linear-charger.txt new file mode 100644 index 000000000000..6dccdd3d4748 --- /dev/null +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-linear-charger.txt @@ -0,0 +1,211 @@ +Qualcomm QPNP Linear Charger + +The charger module supports the linear battery charger peripherals on +Qualcomm PMIC chips. + +There are four different peripherals in the charger module. +Each of these peripherals are implemented as subnodes. + +- qcom,chgr: Supports charging control and status reporting +- qcom,bat-if: Battery status reporting such as presence and + temperature reporting. +- qcom,usb-chgpth: USB charge path detection and input current + limiting configuration. +- qcom,chg-misc: Miscellaneous features such as comparator override + features etc. + +Parent node required properties: +- qcom,vddmax-mv: Target voltage of battery in mV. +- qcom,vddsafe-mv: Maximum Vdd voltage in mV. +- qcom,vinmin-mv: Minimum input voltage in mV. +- qcom,ibatsafe-ma: Safety battery current setting + +Parent node optional properties: +- qcom,vbatweak-uv: Weak battery voltage threshold in uV, + above which fast charging can start. + The supported voltage range is from + 3000000uV to 3581250uV with a step + size of 18750000 uV. +- qcom,charging-disabled: Set this property to disable charging + by default. +- qcom,use-default-batt-values: Set this flag to force reporting of + fake battery. +- qcom,warm-bat-decidegc: Warm battery temperature in decidegC. +- qcom,cool-bat-decidegc: Cool battery temperature in decidegC. + Note that if both warm and cool + battery temperatures are set, the + corresponding ibatmax and bat-mv + properties are required to be set. +- qcom,ibatmax-cool-ma: Maximum cool battery charge current. +- qcom,ibatmax-warm-ma: Maximum warm battery charge current. +- qcom,warm-bat-mv: Warm temperature battery target + voltage. +- qcom,cool-bat-mv: Cool temperature battery target + voltage. +- qcom,thermal-mitigation: Array of ibatmax values for different + system thermal mitigation level. +- qcom,tchg-mins: Maximum total software initialized + charge time. +- qcom,bpd-detection: Select a battery presence detection + scheme by specifying either "bpd_thm" + "bpd_id" or "bpd_thm_id". "bpd_thm" + selects the temperature pin, "bpd_id" + uses the id pin for battery presence + detection, "bpd_thm_id" selects both. + If the property is not set, the + temperatue pin will be used. +- qcom,btc-disabled: If flag is set battery hot and cold + monitoring is disabled in hardware. + This monitoring is turned on by + default. +- qcom,batt-hot-percentage: Specify a supported hot threshold + percentage. + Supported thresholds: 25% and 35%. If + none is specified hardware defaults + will be used. +- qcom,batt-cold-percentage: Specify a supported cold threshold + percentage. Supported thresholds: 70% + and 80%. If none is specified + hardwaredefaults will be used. +- qcom,chg-adc_tm Corresponding ADC TM device's phandle + to set recurring measurements and + receive notification for batt_therm. +-qcom,float-charge If specified enable float charging. +- qcom,chg-vadc Corresponding VADC device's phandle. +- qcom,charger-detect-eoc If specified charger hardware will + detect end-of-charge. + If not specified charger driver + depends on BMSfor end-of-charge + detection. +- qcom,disable-vbatdet-based-recharge If specified disable VBATDET irq + and charging can only be resumed + if charger is re-inserted or SOC + falls below resume SOC. + This property should always be used + along with the BMS property: + "qcom,disable-suspend-on-usb". +- qcom,use-external-charger If specified the LBC module will + be disabled and the driver will not + register. It also enables BID for + BPD and disables BTC. Declare this node + only if you are using an external charger + and not the PMIC internal LBC. +- qcom,chgr-led-support There is a current sink device in linear + charger module, it is used to control a + led which can act as a charger led as well + as a general notification led. +- qcom,parallel-charger This is a bool property to indicate the + LBC will operate as a secondary charger + in the parallel mode. If this is enabled + the charging operations will be controlled by + the primary-charger. +- qcom,collapsible-chgr-support If specified the collapsible charger feature + will be supported. LBC will disable VIN_MIN + comparator and use chg_gone interrupt to + detect charger removal. + + +Sub node required structure: +- A qcom,charger node must be a child of an SPMI node that has specified + the spmi-dev-container property. Each subnode reflects + a hardware peripheral which adds a unique set of features + to the collective charging device. For example USB detection + and the battery interface are each separate peripherals and + each should be their own subnode. + +Sub node required properties: +- compatible: Must be "qcom,qpnp-linear-charger". +- reg: Specifies the SPMI address and size for this + peripheral. +- interrupts: Specifies the interrupt associated with the + peripheral. +- interrupt-names: Specifies the interrupt names for the peripheral. + Every available interrupt needs to have an associated + name with it to indentify its purpose. + + The following lists each subnode and their + corresponding required interrupt names: + + qcom,usb-chgpth: + - usbin-valid + + The following interrupts are available: + + qcom,usb-chgpth: + - usbin-valid: Indicates valid USB + connection. + - coarse-det-usb: Coarse detect interrupt + triggers at low voltage on + USB_IN. + - chg-gone: Triggers on VCHG line. + - overtemp: Triggers on over temperature + condition + + qcom,chgr: + - chg-done: Triggers on charge completion. + - chg-failed: Notifies of charge failures. + - fast-chg-on: Notifies of fast charging. + - vbat-det-lo: Triggers on vbat-det-lo + voltage. + +Example: + pm8916-chg: qcom,charger { + spmi-dev-container; + compatible = "qcom,qpnp-linear-charger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,vddmax-mv = <4200>; + qcom,vddsafe-mv = <4200>; + qcom,vinmin-mv = <4200>; + qcom,ibatsafe-ma = <1440>; + qcom,vbatweak-uv = <3200>; + qcom,thermal-mitigation = <1500 700 600 325>; + qcom,cool-bat-decidegc = <100>; + qcom,warm-bat-decidegc = <450>; + qcom,cool-bat-mv = <4100>; + qcom,ibatmax-warm-ma = <360>; + qcom,ibatmax-cool-ma = <360>; + qcom,warm-bat-mv = <4100>; + qcom,batt-hot-percentage = <25>; + qcom,batt-cold-percentage = <85>; + qcom,tchg-mins = <152>; + qcom,resume-soc = <99>; + qcom,btc-disabled = <0>; + qcom,chg-vadc = <&pm8916_vadc>; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = <0x0 0x10 0x7>, + <0x0 0x10 0x6>, + <0x0 0x10 0x5>, + <0x0 0x10 0x0>; + + interrupt-names = "chg-done", + "chg-failed", + "fast-chg-on", + "vbat-det-lo"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x0 0x12 0x1>, + <0x0 0x12 0x0>; + + interrupt-names = "bat-temp-ok", + "batt-pres"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = <0 0x13 0x2>, + <0 0x13 0x1>; + + interrupt-names = "chg-gone", + "usbin-valid"; + }; + + qcom,chg-misc@1600 { + reg = <0x1600 0x100>; + }; + }; diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 15498673682a..4746bec77170 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -113,6 +113,17 @@ config QPNP_VM_BMS readings from the battery to calculate the State of Charge. +config QPNP_LINEAR_CHARGER + tristate "QPNP Linear Charger driver" + depends on MFD_SPMI_PMIC + depends on THERMAL_QPNP_ADC_TM + help + Say Y here to enable the Linear battery charger which supports USB + detection and charging. The driver also offers relevant information + to userspace via the power supply framework. + The power supply framework is used to communicate battery and + usb properties to userspace and other driver consumers like USB. + config QPNP_TYPEC tristate "QPNP Type-C driver" depends on MFD_SPMI_PMIC diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index 52a33f0f8f03..c10697e69086 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_QPNP_TYPEC) += qpnp-typec.o obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o obj-$(CONFIG_SMB1390_CHARGE_PUMP) += smb1390-charger.o pmic-voter.o obj-$(CONFIG_QPNP_VM_BMS) += qpnp-vm-bms.o batterydata-lib.o batterydata-interface.o +obj-$(CONFIG_QPNP_LINEAR_CHARGER) += qpnp-linear-charger.o diff --git a/drivers/power/supply/qcom/qpnp-linear-charger.c b/drivers/power/supply/qcom/qpnp-linear-charger.c new file mode 100644 index 000000000000..aedc77a1d6f3 --- /dev/null +++ b/drivers/power/supply/qcom/qpnp-linear-charger.c @@ -0,0 +1,3544 @@ +/* Copyright (c) 2013-2015, 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#define pr_fmt(fmt) "CHG: %s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CREATE_MASK(NUM_BITS, POS) \ + ((unsigned char) (((1 << (NUM_BITS)) - 1) << (POS))) +#define LBC_MASK(MSB_BIT, LSB_BIT) \ + CREATE_MASK(MSB_BIT - LSB_BIT + 1, LSB_BIT) + +/* Interrupt offsets */ +#define INT_RT_STS_REG 0x10 +#define FAST_CHG_ON_IRQ BIT(5) +#define OVERTEMP_ON_IRQ BIT(4) +#define BAT_TEMP_OK_IRQ BIT(1) +#define BATT_PRES_IRQ BIT(0) + +/* USB CHARGER PATH peripheral register offsets */ +#define USB_IN_VALID_MASK BIT(1) +#define CHG_GONE_BIT BIT(2) +#define USB_SUSP_REG 0x47 +#define USB_SUSPEND_BIT BIT(0) +#define USB_COMP_OVR1_REG 0xEA +#define USBIN_LLIMIT_OK_MASK LBC_MASK(1, 0) +#define USBIN_LLIMIT_OK_NO_OVERRIDE 0x00 +#define USBIN_LLIMIT_OK_OVERRIDE_1 0x03 +#define USB_OVP_TST5_REG 0xE7 +#define CHG_GONE_OK_EN_BIT BIT(2) + +/* CHARGER peripheral register offset */ +#define CHG_OPTION_REG 0x08 +#define CHG_OPTION_MASK BIT(7) +#define CHG_STATUS_REG 0x09 +#define CHG_ON_BIT BIT(0) +#define CHG_VDD_LOOP_BIT BIT(1) +#define VINMIN_LOOP_BIT BIT(3) +#define CHG_VDD_MAX_REG 0x40 +#define CHG_VDD_SAFE_REG 0x41 +#define CHG_IBAT_MAX_REG 0x44 +#define CHG_IBAT_SAFE_REG 0x45 +#define CHG_VIN_MIN_REG 0x47 +#define CHG_CTRL_REG 0x49 +#define CHG_ENABLE BIT(7) +#define CHG_FORCE_BATT_ON BIT(0) +#define CHG_EN_MASK (BIT(7) | BIT(0)) +#define CHG_FAILED_REG 0x4A +#define CHG_FAILED_BIT BIT(7) +#define CHG_VBAT_WEAK_REG 0x52 +#define CHG_IBATTERM_EN_REG 0x5B +#define CHG_USB_ENUM_T_STOP_REG 0x4E +#define CHG_TCHG_MAX_EN_REG 0x60 +#define CHG_TCHG_MAX_EN_BIT BIT(7) +#define CHG_TCHG_MAX_MASK LBC_MASK(6, 0) +#define CHG_TCHG_MAX_REG 0x61 +#define CHG_WDOG_EN_REG 0x65 +#define CHG_PERPH_RESET_CTRL3_REG 0xDA +#define CHG_COMP_OVR1 0xEE +#define CHG_VBAT_DET_OVR_MASK LBC_MASK(1, 0) +#define CHG_TEST_LOOP_REG 0xE5 +#define VIN_MIN_LOOP_DISABLE_BIT BIT(0) +#define OVERRIDE_0 0x2 +#define OVERRIDE_NONE 0x0 + +/* BATTIF peripheral register offset */ +#define BAT_IF_PRES_STATUS_REG 0x08 +#define BATT_PRES_MASK BIT(7) +#define BAT_IF_TEMP_STATUS_REG 0x09 +#define BATT_TEMP_HOT_MASK BIT(6) +#define BATT_TEMP_COLD_MASK LBC_MASK(7, 6) +#define BATT_TEMP_OK_MASK BIT(7) +#define BAT_IF_VREF_BAT_THM_CTRL_REG 0x4A +#define VREF_BATT_THERM_FORCE_ON LBC_MASK(7, 6) +#define VREF_BAT_THM_ENABLED_FSM BIT(7) +#define BAT_IF_BPD_CTRL_REG 0x48 +#define BATT_BPD_CTRL_SEL_MASK LBC_MASK(1, 0) +#define BATT_BPD_OFFMODE_EN BIT(3) +#define BATT_THM_EN BIT(1) +#define BATT_ID_EN BIT(0) +#define BAT_IF_BTC_CTRL 0x49 +#define BTC_COMP_EN_MASK BIT(7) +#define BTC_COLD_MASK BIT(1) +#define BTC_HOT_MASK BIT(0) +#define BTC_COMP_OVERRIDE_REG 0xE5 + +/* MISC peripheral register offset */ +#define MISC_REV2_REG 0x01 +#define MISC_BOOT_DONE_REG 0x42 +#define MISC_BOOT_DONE BIT(7) +#define MISC_TRIM3_REG 0xF3 +#define MISC_TRIM3_VDD_MASK LBC_MASK(5, 4) +#define MISC_TRIM4_REG 0xF4 +#define MISC_TRIM4_VDD_MASK BIT(4) + +#define PERP_SUBTYPE_REG 0x05 +#define SEC_ACCESS 0xD0 + +/* Linear peripheral subtype values */ +#define LBC_CHGR_SUBTYPE 0x15 +#define LBC_BAT_IF_SUBTYPE 0x16 +#define LBC_USB_PTH_SUBTYPE 0x17 +#define LBC_MISC_SUBTYPE 0x18 + +#define QPNP_CHG_I_MAX_MIN_90 90 + +/* Feature flags */ +#define VDD_TRIM_SUPPORTED BIT(0) + +#define QPNP_CHARGER_DEV_NAME "qcom,qpnp-linear-charger" + +/* usb_interrupts */ + +struct qpnp_lbc_irq { + int irq; + unsigned long disabled; + bool is_wake; +}; + +enum { + USBIN_VALID = 0, + USB_OVER_TEMP, + USB_CHG_GONE, + BATT_PRES, + BATT_TEMPOK, + CHG_DONE, + CHG_FAILED, + CHG_FAST_CHG, + CHG_VBAT_DET_LO, + MAX_IRQS, +}; + +enum { + USER = BIT(0), + THERMAL = BIT(1), + CURRENT = BIT(2), + SOC = BIT(3), + PARALLEL = BIT(4), + COLLAPSE = BIT(5), +}; + +enum bpd_type { + BPD_TYPE_BAT_ID, + BPD_TYPE_BAT_THM, + BPD_TYPE_BAT_THM_BAT_ID, +}; + +static const char * const bpd_label[] = { + [BPD_TYPE_BAT_ID] = "bpd_id", + [BPD_TYPE_BAT_THM] = "bpd_thm", + [BPD_TYPE_BAT_THM_BAT_ID] = "bpd_thm_id", +}; + +enum btc_type { + HOT_THD_25_PCT = 25, + HOT_THD_35_PCT = 35, + COLD_THD_70_PCT = 70, + COLD_THD_80_PCT = 80, +}; + +static u8 btc_value[] = { + [HOT_THD_25_PCT] = 0x0, + [HOT_THD_35_PCT] = BIT(0), + [COLD_THD_70_PCT] = 0x0, + [COLD_THD_80_PCT] = BIT(1), +}; + +static inline int get_bpd(const char *name) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(bpd_label); i++) { + if (strcmp(bpd_label[i], name) == 0) + return i; + } + return -EINVAL; +} + +static enum power_supply_property msm_batt_power_props[] = { + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_COOL_TEMP, + POWER_SUPPLY_PROP_WARM_TEMP, + POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, +}; + +static char *pm_batt_supplied_to[] = { + "bms", +}; + +struct vddtrim_map { + int trim_uv; + int trim_val; +}; + +/* + * VDDTRIM is a 3 bit value which is split across two + * register TRIM3(bit 5:4) -> VDDTRIM bit(2:1) + * register TRIM4(bit 4) -> VDDTRIM bit(0) + */ +#define TRIM_CENTER 4 +#define MAX_VDD_EA_TRIM_CFG 8 +#define VDD_TRIM3_MASK LBC_MASK(2, 1) +#define VDD_TRIM3_SHIFT 3 +#define VDD_TRIM4_MASK BIT(0) +#define VDD_TRIM4_SHIFT 4 +#define AVG(VAL1, VAL2) ((VAL1 + VAL2) / 2) + +/* + * VDDTRIM table containing map of trim voltage and + * corresponding trim value. + */ +static struct vddtrim_map vddtrim_map[] = { + {36700, 0x00}, + {28000, 0x01}, + {19800, 0x02}, + {10760, 0x03}, + {0, 0x04}, + {-8500, 0x05}, + {-16800, 0x06}, + {-25440, 0x07}, +}; + +static const unsigned int qpnp_lbc_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + +/* + * struct qpnp_lbc_chip - device information + * @dev: device pointer to access the parent + * @pdev: pdev pointer to access platform information + * @chgr_base: charger peripheral base address + * @bat_if_base: battery interface peripheral base address + * @usb_chgpth_base: USB charge path peripheral base address + * @misc_base: misc peripheral base address + * @bat_is_cool: indicates that battery is cool + * @bat_is_warm: indicates that battery is warm + * @chg_done: indicates that charging is completed + * @usb_present: present status of USB + * @batt_present: present status of battery + * @cfg_charging_disabled: disable drawing current from USB. + * @cfg_use_fake_battery: flag to report default battery properties + * @fastchg_on: indicate charger in fast charge mode + * @cfg_btc_disabled: flag to disable btc (disables hot and cold + * irqs) + * @cfg_max_voltage_mv: the max volts the batt should be charged up to + * @cfg_min_voltage_mv: VIN_MIN configuration + * @cfg_batt_weak_voltage_uv: weak battery voltage threshold + * @cfg_warm_bat_chg_ma: warm battery maximum charge current in mA + * @cfg_cool_bat_chg_ma: cool battery maximum charge current in mA + * @cfg_safe_voltage_mv: safe voltage to which battery can charge + * @cfg_warm_bat_mv: warm temperature battery target voltage + * @cfg_warm_bat_mv: warm temperature battery target voltage + * @cfg_cool_bat_mv: cool temperature battery target voltage + * @cfg_soc_resume_limit: SOC at which battery resumes charging + * @cfg_float_charge: enable float charging + * @charger_disabled: maintain USB path state. + * @cfg_charger_detect_eoc: charger can detect end of charging + * @cfg_disable_vbatdet_based_recharge: keep VBATDET comparator overridden to + * low and VBATDET irq disabled. + * @cfg_collapsible_chgr_support: support collapsible charger + * @cfg_chgr_led_support: support charger led work. + * @cfg_safe_current: battery safety current setting + * @cfg_hot_batt_p: hot battery threshold setting + * @cfg_cold_batt_p: eold battery threshold setting + * @cfg_warm_bat_decidegc: warm battery temperature in degree Celsius + * @cfg_cool_bat_decidegc: cool battery temperature in degree Celsius + * @fake_battery_soc: SOC value to be reported to userspace + * @cfg_tchg_mins: maximum allowed software initiated charge time + * @chg_failed_count: counter to maintained number of times charging + * failed + * @cfg_bpd_detection: battery present detection mechanism selection + * @cfg_thermal_levels: amount of thermal mitigation levels + * @cfg_thermal_mitigation: thermal mitigation level values + * @therm_lvl_sel: thermal mitigation level selection + * @jeita_configure_lock: lock to serialize jeita configuration request + * @hw_access_lock: lock to serialize access to charger registers + * @ibat_change_lock: lock to serialize ibat change requests from + * USB and thermal. + * @irq_lock lock to serialize enabling/disabling of irq + * @supported_feature_flag bitmask for all supported features + * @vddtrim_alarm alarm to schedule trim work at regular + * interval + * @vddtrim_work work to perform actual vddmax trimming + * @init_trim_uv initial trim voltage at bootup + * @delta_vddmax_uv current vddmax trim voltage + * @chg_enable_lock: lock to serialize charging enable/disable for + * SOC based resume charging + * @usb_psy: power supply to export information to + * userspace + * @bms_psy: power supply to export information to + * userspace + * @batt_psy: power supply to export information to + * userspace + */ +struct qpnp_lbc_chip { + struct device *dev; + struct platform_device *pdev; + struct regmap *regmap; + u16 chgr_base; + u16 bat_if_base; + u16 usb_chgpth_base; + u16 misc_base; + bool bat_is_cool; + bool bat_is_warm; + bool chg_done; + bool usb_present; + bool batt_present; + bool cfg_charging_disabled; + bool cfg_btc_disabled; + bool cfg_use_fake_battery; + bool fastchg_on; + bool cfg_use_external_charger; + bool cfg_chgr_led_support; + bool non_collapsible_chgr_detected; + unsigned int cfg_warm_bat_chg_ma; + unsigned int cfg_cool_bat_chg_ma; + unsigned int cfg_safe_voltage_mv; + unsigned int cfg_max_voltage_mv; + unsigned int cfg_min_voltage_mv; + unsigned int cfg_charger_detect_eoc; + unsigned int cfg_disable_vbatdet_based_recharge; + unsigned int cfg_batt_weak_voltage_uv; + unsigned int cfg_collapsible_chgr_support; + unsigned int cfg_warm_bat_mv; + unsigned int cfg_cool_bat_mv; + unsigned int cfg_hot_batt_p; + unsigned int cfg_cold_batt_p; + unsigned int cfg_thermal_levels; + unsigned int therm_lvl_sel; + unsigned int *thermal_mitigation; + unsigned int cfg_safe_current; + unsigned int cfg_tchg_mins; + unsigned int chg_failed_count; + unsigned int supported_feature_flag; + int usb_online; + int cfg_bpd_detection; + int cfg_warm_bat_decidegc; + int cfg_cool_bat_decidegc; + int fake_battery_soc; + int cfg_soc_resume_limit; + int cfg_float_charge; + int charger_disabled; + int prev_max_ma; + int usb_psy_ma; + int delta_vddmax_uv; + int init_trim_uv; + enum power_supply_type usb_supply_type; + struct delayed_work collapsible_detection_work; + + /* parallel-chg params */ + int parallel_charging_enabled; + int lbc_max_chg_current; + int ichg_now; + + struct alarm vddtrim_alarm; + struct work_struct vddtrim_work; + struct qpnp_lbc_irq irqs[MAX_IRQS]; + struct mutex jeita_configure_lock; + struct mutex chg_enable_lock; + spinlock_t ibat_change_lock; + spinlock_t hw_access_lock; + spinlock_t irq_lock; + struct power_supply *usb_psy; + struct power_supply_desc usb_psy_d; + struct power_supply *bms_psy; + struct power_supply *batt_psy; + struct power_supply_desc batt_psy_d; + struct qpnp_adc_tm_btm_param adc_param; + struct qpnp_vadc_chip *vadc_dev; + struct qpnp_adc_tm_chip *adc_tm_dev; + struct led_classdev led_cdev; + struct dentry *debug_root; + + /* parallel-chg params */ + struct power_supply *parallel_psy; + struct power_supply_desc parallel_psy_d; + struct delayed_work parallel_work; + struct extcon_dev *extcon; +}; + +static void qpnp_lbc_enable_irq(struct qpnp_lbc_chip *chip, + struct qpnp_lbc_irq *irq) +{ + unsigned long flags; + + spin_lock_irqsave(&chip->irq_lock, flags); + if (__test_and_clear_bit(0, &irq->disabled)) { + pr_debug("number = %d\n", irq->irq); + enable_irq(irq->irq); + if (irq->is_wake) + enable_irq_wake(irq->irq); + } + spin_unlock_irqrestore(&chip->irq_lock, flags); +} + +static void qpnp_lbc_disable_irq(struct qpnp_lbc_chip *chip, + struct qpnp_lbc_irq *irq) +{ + unsigned long flags; + + spin_lock_irqsave(&chip->irq_lock, flags); + if (!__test_and_set_bit(0, &irq->disabled)) { + pr_debug("number = %d\n", irq->irq); + disable_irq_nosync(irq->irq); + if (irq->is_wake) + disable_irq_wake(irq->irq); + } + spin_unlock_irqrestore(&chip->irq_lock, flags); +} + +static int __qpnp_lbc_read(struct qpnp_lbc_chip *chip, u16 base, + u8 *val, int count) +{ + int rc = 0; + + if (base == 0) { + pr_err("base addr cannot be zero\n"); + return -EINVAL; + } + + rc = regmap_bulk_read(chip->regmap, base, val, count); + if (rc) + pr_err("SPMI read failed base=0x%02x rc=%d\n", base, rc); + + return rc; +} + +static int __qpnp_lbc_write(struct qpnp_lbc_chip *chip, u16 base, + u8 *val, int count) +{ + int rc; + + if (base == 0) { + pr_err("base addr cannot be zero\n"); + return -EINVAL; + } + + rc = regmap_bulk_write(chip->regmap, base, val, count); + if (rc) + pr_err("SPMI write failed base=0x%02x rc=%d\n", base, rc); + + return rc; +} + +static int __qpnp_lbc_secure_write(struct qpnp_lbc_chip *chip, u16 base, + u16 offset, u8 *val, int count) +{ + int rc; + u8 reg_val; + + reg_val = 0xA5; + rc = __qpnp_lbc_write(chip, base + SEC_ACCESS, ®_val, 1); + if (rc) + return rc; + + return __qpnp_lbc_write(chip, base + offset, val, 1); +} + +static int qpnp_lbc_read(struct qpnp_lbc_chip *chip, u16 base, + u8 *val, int count) +{ + int rc = 0; + unsigned long flags; + + if (base == 0) { + pr_err("base addr cannot be zero\n"); + return -EINVAL; + } + + spin_lock_irqsave(&chip->hw_access_lock, flags); + rc = __qpnp_lbc_read(chip, base, val, count); + spin_unlock_irqrestore(&chip->hw_access_lock, flags); + + return rc; +} + +static int qpnp_lbc_write(struct qpnp_lbc_chip *chip, u16 base, + u8 *val, int count) +{ + int rc = 0; + unsigned long flags; + + if (base == 0) { + pr_err("base addr cannot be zero\n"); + return -EINVAL; + } + + spin_lock_irqsave(&chip->hw_access_lock, flags); + rc = __qpnp_lbc_write(chip, base, val, count); + spin_unlock_irqrestore(&chip->hw_access_lock, flags); + + return rc; +} + +static int qpnp_lbc_masked_write(struct qpnp_lbc_chip *chip, u16 base, + u8 mask, u8 val) +{ + int rc; + u8 reg_val; + unsigned long flags; + + spin_lock_irqsave(&chip->hw_access_lock, flags); + rc = __qpnp_lbc_read(chip, base, ®_val, 1); + if (rc) + goto out; + + pr_debug("addr = 0x%x read 0x%x\n", base, reg_val); + + reg_val &= ~mask; + reg_val |= val & mask; + + pr_debug("writing to base=%x val=%x\n", base, reg_val); + + rc = __qpnp_lbc_write(chip, base, ®_val, 1); + +out: + spin_unlock_irqrestore(&chip->hw_access_lock, flags); + return rc; +} + +static int __qpnp_lbc_secure_masked_write(struct qpnp_lbc_chip *chip, u16 base, + u16 offset, u8 mask, u8 val) +{ + int rc; + u8 reg_val, reg_val1; + + rc = __qpnp_lbc_read(chip, base + offset, ®_val, 1); + if (rc) + return rc; + + pr_debug("addr = 0x%x read 0x%x\n", base, reg_val); + + reg_val &= ~mask; + reg_val |= val & mask; + pr_debug("writing to base=%x val=%x\n", base, reg_val); + + reg_val1 = 0xA5; + rc = __qpnp_lbc_write(chip, base + SEC_ACCESS, ®_val1, 1); + if (rc) + return rc; + + rc = __qpnp_lbc_write(chip, base + offset, ®_val, 1); + + return rc; +} + +static int qpnp_lbc_get_trim_voltage(u8 trim_reg) +{ + int i; + + for (i = 0; i < MAX_VDD_EA_TRIM_CFG; i++) + if (trim_reg == vddtrim_map[i].trim_val) + return vddtrim_map[i].trim_uv; + + pr_err("Invalid trim reg reg_val=%x\n", trim_reg); + return -EINVAL; +} + +static u8 qpnp_lbc_get_trim_val(struct qpnp_lbc_chip *chip) +{ + int i, sign; + int delta_uv; + + sign = (chip->delta_vddmax_uv >= 0) ? -1 : 1; + + switch (sign) { + case -1: + for (i = TRIM_CENTER; i >= 0; i--) { + if (vddtrim_map[i].trim_uv > chip->delta_vddmax_uv) { + delta_uv = AVG(vddtrim_map[i].trim_uv, + vddtrim_map[i + 1].trim_uv); + if (chip->delta_vddmax_uv >= delta_uv) + return vddtrim_map[i].trim_val; + else + return vddtrim_map[i + 1].trim_val; + } + } + i = 0; + break; + case 1: + for (i = TRIM_CENTER; i < ARRAY_SIZE(vddtrim_map); i++) { + if (vddtrim_map[i].trim_uv < chip->delta_vddmax_uv) { + delta_uv = AVG(vddtrim_map[i].trim_uv, + vddtrim_map[i - 1].trim_uv); + if (chip->delta_vddmax_uv >= delta_uv) + return vddtrim_map[i - 1].trim_val; + else + return vddtrim_map[i].trim_val; + } + } + i = ARRAY_SIZE(vddtrim_map) - 1; + break; + } + + return vddtrim_map[i].trim_val; +} + +static int qpnp_lbc_is_usb_chg_plugged_in(struct qpnp_lbc_chip *chip) +{ + u8 usbin_valid_rt_sts; + int rc; + + rc = qpnp_lbc_read(chip, chip->usb_chgpth_base + INT_RT_STS_REG, + &usbin_valid_rt_sts, 1); + if (rc) + return rc; + + pr_debug("rt_sts 0x%x\n", usbin_valid_rt_sts); + + return (usbin_valid_rt_sts & USB_IN_VALID_MASK) ? 1 : 0; +} + +static int qpnp_lbc_is_chg_gone(struct qpnp_lbc_chip *chip) +{ + u8 rt_sts; + int rc; + + rc = qpnp_lbc_read(chip, chip->usb_chgpth_base + INT_RT_STS_REG, + &rt_sts, 1); + if (rc) + return rc; + + pr_debug("rt_sts 0x%x\n", rt_sts); + + return (rt_sts & CHG_GONE_BIT) ? 1 : 0; +} + +static int qpnp_lbc_charger_enable(struct qpnp_lbc_chip *chip, int reason, + int enable) +{ + int disabled = chip->charger_disabled; + u8 reg_val; + int rc = 0; + + pr_debug("reason=%d requested_enable=%d disabled_status=%d\n", + reason, enable, disabled); + if (enable) + disabled &= ~reason; + else + disabled |= reason; + + if (!!chip->charger_disabled == !!disabled) + goto skip; + + reg_val = !!disabled ? CHG_FORCE_BATT_ON : CHG_ENABLE; + rc = qpnp_lbc_masked_write(chip, chip->chgr_base + CHG_CTRL_REG, + CHG_EN_MASK, reg_val); + if (rc) { + pr_err("Failed to %s charger\n", + reg_val ? "enable" : "disable"); + return rc; + } +skip: + chip->charger_disabled = disabled; + return rc; +} + +static int qpnp_lbc_is_batt_present(struct qpnp_lbc_chip *chip) +{ + u8 batt_pres_rt_sts; + int rc; + + rc = qpnp_lbc_read(chip, chip->bat_if_base + INT_RT_STS_REG, + &batt_pres_rt_sts, 1); + if (rc) + return rc; + + return (batt_pres_rt_sts & BATT_PRES_IRQ) ? 1 : 0; +} + +static int qpnp_lbc_bat_if_configure_btc(struct qpnp_lbc_chip *chip) +{ + u8 btc_cfg = 0, mask = 0, rc; + + /* Do nothing if battery peripheral not present */ + if (!chip->bat_if_base) + return 0; + + if ((chip->cfg_hot_batt_p == HOT_THD_25_PCT) + || (chip->cfg_hot_batt_p == HOT_THD_35_PCT)) { + btc_cfg |= btc_value[chip->cfg_hot_batt_p]; + mask |= BTC_HOT_MASK; + } + + if ((chip->cfg_cold_batt_p == COLD_THD_70_PCT) || + (chip->cfg_cold_batt_p == COLD_THD_80_PCT)) { + btc_cfg |= btc_value[chip->cfg_cold_batt_p]; + mask |= BTC_COLD_MASK; + } + + mask |= BTC_COMP_EN_MASK; + if (!chip->cfg_btc_disabled) + btc_cfg |= BTC_COMP_EN_MASK; + + pr_debug("BTC configuration mask=%x\n", btc_cfg); + + rc = qpnp_lbc_masked_write(chip, + chip->bat_if_base + BAT_IF_BTC_CTRL, + mask, btc_cfg); + if (rc) + pr_err("Failed to configure BTC\n"); + + return rc; +} + +static int qpnp_chg_collapsible_chgr_config(struct qpnp_lbc_chip *chip, + bool enable) +{ + u8 reg_val; + int rc; + + pr_debug("Configure for %scollapsible charger\n", + enable ? "" : "non-"); + /* + * The flow to enable/disable the collapsible charger configuration: + * Enable: Override USBIN_LLIMIT_OK --> + * Disable VIN_MIN comparator --> + * Enable CHG_GONE comparator + * Disable: Enable VIN_MIN comparator --> + * Enable USBIN_LLIMIT_OK --> + * Disable CHG_GONE comparator + */ + if (enable) { + /* Override USBIN_LLIMIT_OK */ + reg_val = USBIN_LLIMIT_OK_OVERRIDE_1; + rc = __qpnp_lbc_secure_masked_write(chip, + chip->usb_chgpth_base, + USB_COMP_OVR1_REG, + USBIN_LLIMIT_OK_MASK, reg_val); + if (rc) { + pr_err("Failed to override USB_LLIMIT_OK\n"); + return rc; + } + } + + /* Configure VIN_MIN comparator */ + rc = __qpnp_lbc_secure_masked_write(chip, + chip->chgr_base, CHG_TEST_LOOP_REG, + VIN_MIN_LOOP_DISABLE_BIT, + enable ? VIN_MIN_LOOP_DISABLE_BIT : 0); + if (rc) { + pr_err("Failed to %s VIN_MIN comparator\n", + enable ? "disable" : "enable"); + return rc; + } + + if (!enable) { + /* Enable USBIN_LLIMIT_OK */ + reg_val = USBIN_LLIMIT_OK_NO_OVERRIDE; + rc = __qpnp_lbc_secure_masked_write(chip, + chip->usb_chgpth_base, + USB_COMP_OVR1_REG, + USBIN_LLIMIT_OK_MASK, reg_val); + if (rc) { + pr_err("Failed to override USB_LLIMIT_OK\n"); + return rc; + } + } + + /* Configure CHG_GONE comparator */ + reg_val = enable ? CHG_GONE_OK_EN_BIT : 0; + rc = __qpnp_lbc_secure_masked_write(chip, + chip->usb_chgpth_base, USB_OVP_TST5_REG, + CHG_GONE_OK_EN_BIT, reg_val); + if (rc) { + pr_err("Failed to write CHG_GONE comparator\n"); + return rc; + } + + return 0; +} + +#define QPNP_LBC_VBATWEAK_MIN_UV 3000000 +#define QPNP_LBC_VBATWEAK_MAX_UV 3581250 +#define QPNP_LBC_VBATWEAK_STEP_UV 18750 +static int qpnp_lbc_vbatweak_set(struct qpnp_lbc_chip *chip, int voltage) +{ + u8 reg_val; + int rc; + + if (voltage < QPNP_LBC_VBATWEAK_MIN_UV || + voltage > QPNP_LBC_VBATWEAK_MAX_UV) { + rc = -EINVAL; + } else { + reg_val = (voltage - QPNP_LBC_VBATWEAK_MIN_UV) / + QPNP_LBC_VBATWEAK_STEP_UV; + pr_debug("VBAT_WEAK=%d setting %02x\n", + chip->cfg_batt_weak_voltage_uv, reg_val); + rc = qpnp_lbc_write(chip, chip->chgr_base + CHG_VBAT_WEAK_REG, + ®_val, 1); + if (rc) + pr_err("Failed to set VBAT_WEAK\n"); + } + + return rc; +} + +#define QPNP_LBC_VBAT_MIN_MV 4000 +#define QPNP_LBC_VBAT_MAX_MV 4775 +#define QPNP_LBC_VBAT_STEP_MV 25 +static int qpnp_lbc_vddsafe_set(struct qpnp_lbc_chip *chip, int voltage) +{ + u8 reg_val; + int rc; + + if (voltage < QPNP_LBC_VBAT_MIN_MV + || voltage > QPNP_LBC_VBAT_MAX_MV) { + pr_err("Invalid vddsafe voltage mV=%d min=%d max=%d\n", + voltage, QPNP_LBC_VBAT_MIN_MV, + QPNP_LBC_VBAT_MAX_MV); + return -EINVAL; + } + reg_val = (voltage - QPNP_LBC_VBAT_MIN_MV) / QPNP_LBC_VBAT_STEP_MV; + pr_debug("voltage=%d setting %02x\n", voltage, reg_val); + rc = qpnp_lbc_write(chip, chip->chgr_base + CHG_VDD_SAFE_REG, + ®_val, 1); + if (rc) + pr_err("Failed to set VDD_SAFE\n"); + + return rc; +} + +static int qpnp_lbc_vddmax_set(struct qpnp_lbc_chip *chip, int voltage) +{ + u8 reg_val; + int rc, trim_val; + unsigned long flags; + + if (voltage < QPNP_LBC_VBAT_MIN_MV + || voltage > QPNP_LBC_VBAT_MAX_MV) { + pr_err("Invalid vddmax voltage mV=%d min=%d max=%d\n", + voltage, QPNP_LBC_VBAT_MIN_MV, + QPNP_LBC_VBAT_MAX_MV); + return -EINVAL; + } + + spin_lock_irqsave(&chip->hw_access_lock, flags); + reg_val = (voltage - QPNP_LBC_VBAT_MIN_MV) / QPNP_LBC_VBAT_STEP_MV; + pr_debug("voltage=%d setting %02x\n", voltage, reg_val); + rc = __qpnp_lbc_write(chip, chip->chgr_base + CHG_VDD_MAX_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to set VDD_MAX\n"); + goto out; + } + + /* Update trim value */ + if (chip->supported_feature_flag & VDD_TRIM_SUPPORTED) { + trim_val = qpnp_lbc_get_trim_val(chip); + reg_val = (trim_val & VDD_TRIM3_MASK) << VDD_TRIM3_SHIFT; + rc = __qpnp_lbc_secure_masked_write(chip, + chip->misc_base, MISC_TRIM3_REG, + MISC_TRIM3_VDD_MASK, reg_val); + if (rc) { + pr_err("Failed to set MISC_TRIM3_REG\n"); + goto out; + } + + reg_val = (trim_val & VDD_TRIM4_MASK) << VDD_TRIM4_SHIFT; + rc = __qpnp_lbc_secure_masked_write(chip, + chip->misc_base, MISC_TRIM4_REG, + MISC_TRIM4_VDD_MASK, reg_val); + if (rc) { + pr_err("Failed to set MISC_TRIM4_REG\n"); + goto out; + } + + chip->delta_vddmax_uv = qpnp_lbc_get_trim_voltage(trim_val); + if (chip->delta_vddmax_uv == -EINVAL) { + pr_err("Invalid trim voltage=%d\n", + chip->delta_vddmax_uv); + rc = -EINVAL; + goto out; + } + + pr_debug("VDD_MAX delta=%d trim value=%x\n", + chip->delta_vddmax_uv, trim_val); + } + +out: + spin_unlock_irqrestore(&chip->hw_access_lock, flags); + return rc; +} + +static int qpnp_lbc_set_appropriate_vddmax(struct qpnp_lbc_chip *chip) +{ + int rc; + + if (chip->bat_is_cool) + rc = qpnp_lbc_vddmax_set(chip, chip->cfg_cool_bat_mv); + else if (chip->bat_is_warm) + rc = qpnp_lbc_vddmax_set(chip, chip->cfg_warm_bat_mv); + else + rc = qpnp_lbc_vddmax_set(chip, chip->cfg_max_voltage_mv); + if (rc) + pr_err("Failed to set appropriate vddmax\n"); + + return rc; +} + +#define QPNP_LBC_MIN_DELTA_UV 13000 +static void qpnp_lbc_adjust_vddmax(struct qpnp_lbc_chip *chip, int vbat_uv) +{ + int delta_uv, prev_delta_uv, rc; + + prev_delta_uv = chip->delta_vddmax_uv; + delta_uv = (int)(chip->cfg_max_voltage_mv * 1000) - vbat_uv; + + /* + * If delta_uv is positive, apply trim if delta_uv > 13mv + * If delta_uv is negative always apply trim. + */ + if (delta_uv > 0 && delta_uv < QPNP_LBC_MIN_DELTA_UV) { + pr_debug("vbat is not low enough to increase vdd\n"); + return; + } + + pr_debug("vbat=%d current delta_uv=%d prev delta_vddmax_uv=%d\n", + vbat_uv, delta_uv, chip->delta_vddmax_uv); + chip->delta_vddmax_uv = delta_uv + chip->delta_vddmax_uv; + pr_debug("new delta_vddmax_uv %d\n", chip->delta_vddmax_uv); + rc = qpnp_lbc_set_appropriate_vddmax(chip); + if (rc) + chip->delta_vddmax_uv = prev_delta_uv; +} + +#define QPNP_LBC_VINMIN_MIN_MV 4200 +#define QPNP_LBC_VINMIN_MAX_MV 5037 +#define QPNP_LBC_VINMIN_STEP_MV 27 +static int qpnp_lbc_vinmin_set(struct qpnp_lbc_chip *chip, int voltage) +{ + u8 reg_val; + int rc; + + if ((voltage < QPNP_LBC_VINMIN_MIN_MV) + || (voltage > QPNP_LBC_VINMIN_MAX_MV)) { + pr_err("Invalid vinmin voltage mV=%d min=%d max=%d\n", + voltage, QPNP_LBC_VINMIN_MIN_MV, + QPNP_LBC_VINMIN_MAX_MV); + return -EINVAL; + } + + reg_val = (voltage - QPNP_LBC_VINMIN_MIN_MV) / QPNP_LBC_VINMIN_STEP_MV; + pr_debug("VIN_MIN=%d setting %02x\n", voltage, reg_val); + rc = qpnp_lbc_write(chip, chip->chgr_base + CHG_VIN_MIN_REG, + ®_val, 1); + if (rc) + pr_err("Failed to set VIN_MIN\n"); + + return rc; +} + +#define QPNP_LBC_IBATSAFE_MIN_MA 90 +#define QPNP_LBC_IBATSAFE_MAX_MA 1440 +#define QPNP_LBC_I_STEP_MA 90 +static int qpnp_lbc_ibatsafe_set(struct qpnp_lbc_chip *chip, int safe_current) +{ + u8 reg_val; + int rc; + + if (safe_current < QPNP_LBC_IBATSAFE_MIN_MA + || safe_current > QPNP_LBC_IBATSAFE_MAX_MA) { + pr_err("Invalid safecurrent mA=%d min=%d max=%d\n", + safe_current, QPNP_LBC_IBATSAFE_MIN_MA, + QPNP_LBC_IBATSAFE_MAX_MA); + return -EINVAL; + } + + reg_val = (safe_current - QPNP_LBC_IBATSAFE_MIN_MA) + / QPNP_LBC_I_STEP_MA; + pr_debug("Ibate_safe=%d setting %02x\n", safe_current, reg_val); + + rc = qpnp_lbc_write(chip, chip->chgr_base + CHG_IBAT_SAFE_REG, + ®_val, 1); + if (rc) + pr_err("Failed to set IBAT_SAFE\n"); + + return rc; +} + +#define QPNP_LBC_IBATMAX_MIN 90 +#define QPNP_LBC_IBATMAX_MAX 1440 +/* + * Set maximum current limit from charger + * ibat = System current + charging current + */ +static int qpnp_lbc_ibatmax_set(struct qpnp_lbc_chip *chip, int chg_current) +{ + u8 reg_val; + int rc; + + if (chg_current > QPNP_LBC_IBATMAX_MAX) + pr_debug("Invalid max charge current mA=%d max=%d\n", + chg_current, + QPNP_LBC_IBATMAX_MAX); + + chg_current = clamp(chg_current, QPNP_LBC_IBATMAX_MIN, + QPNP_LBC_IBATMAX_MAX); + reg_val = (chg_current - QPNP_LBC_IBATMAX_MIN) / QPNP_LBC_I_STEP_MA; + + rc = qpnp_lbc_write(chip, chip->chgr_base + CHG_IBAT_MAX_REG, + ®_val, 1); + if (rc) + pr_err("Failed to set IBAT_MAX\n"); + else + chip->prev_max_ma = chg_current; + + return rc; +} + +#define QPNP_LBC_TCHG_MIN 4 +#define QPNP_LBC_TCHG_MAX 512 +#define QPNP_LBC_TCHG_STEP 4 +static int qpnp_lbc_tchg_max_set(struct qpnp_lbc_chip *chip, int minutes) +{ + u8 reg_val = 0; + int rc; + + /* Disable timer */ + rc = qpnp_lbc_masked_write(chip, chip->chgr_base + CHG_TCHG_MAX_EN_REG, + CHG_TCHG_MAX_EN_BIT, 0); + if (rc) { + pr_err("Failed to write tchg_max_en\n"); + return rc; + } + + /* If minutes is 0, just disable timer */ + if (!minutes) { + pr_debug("Charger safety timer disabled\n"); + return rc; + } + + minutes = clamp(minutes, QPNP_LBC_TCHG_MIN, QPNP_LBC_TCHG_MAX); + + reg_val = (minutes / QPNP_LBC_TCHG_STEP) - 1; + + pr_debug("TCHG_MAX=%d mins setting %x\n", minutes, reg_val); + rc = qpnp_lbc_masked_write(chip, chip->chgr_base + CHG_TCHG_MAX_REG, + CHG_TCHG_MAX_MASK, reg_val); + if (rc) { + pr_err("Failed to write tchg_max_reg\n"); + return rc; + } + + /* Enable timer */ + rc = qpnp_lbc_masked_write(chip, chip->chgr_base + CHG_TCHG_MAX_EN_REG, + CHG_TCHG_MAX_EN_BIT, CHG_TCHG_MAX_EN_BIT); + if (rc) + pr_err("Failed to write tchg_max_en\n"); + + return rc; +} + +#define LBC_CHGR_LED 0x4D +#define CHGR_LED_ON BIT(0) +#define CHGR_LED_OFF 0x0 +#define CHGR_LED_STAT_MASK LBC_MASK(1, 0) +static void qpnp_lbc_chgr_led_brightness_set(struct led_classdev *cdev, + enum led_brightness value) +{ + struct qpnp_lbc_chip *chip = container_of(cdev, struct qpnp_lbc_chip, + led_cdev); + u8 reg; + int rc; + + if (value > LED_FULL) + value = LED_FULL; + + pr_debug("set the charger led brightness to value=%d\n", value); + reg = (value > LED_OFF) ? CHGR_LED_ON : CHGR_LED_OFF; + + rc = qpnp_lbc_masked_write(chip, chip->chgr_base + LBC_CHGR_LED, + CHGR_LED_STAT_MASK, reg); + if (rc) + pr_err("Failed to write charger led\n"); +} + +static enum +led_brightness qpnp_lbc_chgr_led_brightness_get(struct led_classdev *cdev) +{ + + struct qpnp_lbc_chip *chip = container_of(cdev, struct qpnp_lbc_chip, + led_cdev); + u8 reg_val, chgr_led_sts; + int rc; + + rc = qpnp_lbc_read(chip, chip->chgr_base + LBC_CHGR_LED, + ®_val, 1); + if (rc) { + pr_err("Failed to read charger led\n"); + return rc; + } + + chgr_led_sts = reg_val & CHGR_LED_STAT_MASK; + pr_debug("charger led brightness chgr_led_sts=%d\n", chgr_led_sts); + + return (chgr_led_sts == CHGR_LED_ON) ? LED_FULL : LED_OFF; +} + +static int qpnp_lbc_register_chgr_led(struct qpnp_lbc_chip *chip) +{ + int rc; + + chip->led_cdev.name = "red"; + chip->led_cdev.brightness_set = qpnp_lbc_chgr_led_brightness_set; + chip->led_cdev.brightness_get = qpnp_lbc_chgr_led_brightness_get; + + rc = led_classdev_register(chip->dev, &chip->led_cdev); + if (rc) + pr_err("unable to register charger led, rc=%d\n", rc); + + return rc; +}; + +static int is_vinmin_set(struct qpnp_lbc_chip *chip) +{ + u8 reg; + int rc; + + rc = qpnp_lbc_read(chip, chip->chgr_base + CHG_STATUS_REG, ®, 1); + if (rc) { + pr_err("Unable to read charger status\n"); + return false; + } + pr_debug("chg_status=0x%x\n", reg); + + return !!(reg & VINMIN_LOOP_BIT); + +} + +static int is_battery_charging(struct qpnp_lbc_chip *chip) +{ + u8 reg; + int rc; + + rc = qpnp_lbc_read(chip, chip->chgr_base + CHG_STATUS_REG, ®, 1); + if (rc) { + pr_err("Unable to read charger status\n"); + return false; + } + pr_debug("chg_status=0x%x\n", reg); + + return !!(reg & CHG_ON_BIT); +} + +static int qpnp_lbc_vbatdet_override(struct qpnp_lbc_chip *chip, int ovr_val) +{ + int rc; + u8 reg_val; + unsigned long flags; + + spin_lock_irqsave(&chip->hw_access_lock, flags); + + rc = __qpnp_lbc_read(chip, chip->chgr_base + CHG_COMP_OVR1, + ®_val, 1); + if (rc) + goto out; + + pr_debug("addr = 0x%x read 0x%x\n", chip->chgr_base, reg_val); + + reg_val &= ~CHG_VBAT_DET_OVR_MASK; + reg_val |= ovr_val & CHG_VBAT_DET_OVR_MASK; + + pr_debug("writing to base=%x val=%x\n", chip->chgr_base, reg_val); + + rc = __qpnp_lbc_secure_write(chip, chip->chgr_base, CHG_COMP_OVR1, + ®_val, 1); + +out: + spin_unlock_irqrestore(&chip->hw_access_lock, flags); + return rc; +} + +static int get_prop_battery_voltage_now(struct qpnp_lbc_chip *chip) +{ + int rc = 0; + struct qpnp_vadc_result results; + + rc = qpnp_vadc_read(chip->vadc_dev, VBAT_SNS, &results); + if (rc) { + pr_err("Unable to read vbat rc=%d\n", rc); + return 0; + } + + return results.physical; +} + +static int get_prop_batt_present(struct qpnp_lbc_chip *chip) +{ + u8 reg_val; + int rc; + + rc = qpnp_lbc_read(chip, chip->bat_if_base + BAT_IF_PRES_STATUS_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read battery status read failed\n"); + return 0; + } + + return (reg_val & BATT_PRES_MASK) ? 1 : 0; +} + +static int get_prop_batt_health(struct qpnp_lbc_chip *chip) +{ + u8 reg_val; + int rc; + + rc = qpnp_lbc_read(chip, chip->bat_if_base + BAT_IF_TEMP_STATUS_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read battery health\n"); + return POWER_SUPPLY_HEALTH_UNKNOWN; + } + + if (BATT_TEMP_HOT_MASK & reg_val) + return POWER_SUPPLY_HEALTH_OVERHEAT; + if (!(BATT_TEMP_COLD_MASK & reg_val)) + return POWER_SUPPLY_HEALTH_COLD; + if (chip->bat_is_cool) + return POWER_SUPPLY_HEALTH_COOL; + if (chip->bat_is_warm) + return POWER_SUPPLY_HEALTH_WARM; + + return POWER_SUPPLY_HEALTH_GOOD; +} + +static int get_prop_charge_type(struct qpnp_lbc_chip *chip) +{ + int rc; + u8 reg_val; + + if (!get_prop_batt_present(chip)) + return POWER_SUPPLY_CHARGE_TYPE_NONE; + + rc = qpnp_lbc_read(chip, chip->chgr_base + INT_RT_STS_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read interrupt sts\n"); + return POWER_SUPPLY_CHARGE_TYPE_NONE; + } + + if (reg_val & FAST_CHG_ON_IRQ) + return POWER_SUPPLY_CHARGE_TYPE_FAST; + + return POWER_SUPPLY_CHARGE_TYPE_NONE; +} + +static int get_prop_batt_status(struct qpnp_lbc_chip *chip) +{ + int rc; + u8 reg_val; + + if (qpnp_lbc_is_usb_chg_plugged_in(chip) && chip->chg_done) + return POWER_SUPPLY_STATUS_FULL; + + rc = qpnp_lbc_read(chip, chip->chgr_base + INT_RT_STS_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read interrupt sts\n"); + return POWER_SUPPLY_CHARGE_TYPE_NONE; + } + + if (reg_val & FAST_CHG_ON_IRQ) + return POWER_SUPPLY_STATUS_CHARGING; + + return POWER_SUPPLY_STATUS_DISCHARGING; +} + +static int get_prop_current_now(struct qpnp_lbc_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (chip->bms_psy) { + power_supply_get_property(chip->bms_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &ret); + return ret.intval; + } + + pr_debug("No BMS supply registered return 0\n"); + return 0; +} + +#define DEFAULT_CAPACITY 50 +static int get_prop_capacity(struct qpnp_lbc_chip *chip) +{ + union power_supply_propval ret = {0,}; + int soc; + + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + + if (chip->fake_battery_soc >= 0) + return chip->fake_battery_soc; + + if (chip->cfg_use_fake_battery || !get_prop_batt_present(chip)) + return DEFAULT_CAPACITY; + + if (chip->bms_psy) { + power_supply_get_property(chip->bms_psy, + POWER_SUPPLY_PROP_CAPACITY, &ret); + soc = ret.intval; + if (soc == 0) { + if (!qpnp_lbc_is_usb_chg_plugged_in(chip)) + pr_warn_ratelimited("Batt 0, CHG absent\n"); + } + return soc; + } + pr_debug("No BMS supply registered return %d\n", DEFAULT_CAPACITY); + + /* + * Return default capacity to avoid userspace + * from shutting down unecessarily + */ + return DEFAULT_CAPACITY; +} + +static int get_prop_charge_count(struct qpnp_lbc_chip *chip) +{ + union power_supply_propval ret = {0,}; + + if (!chip->bms_psy) + chip->bms_psy = power_supply_get_by_name("bms"); + + if (chip->bms_psy) { + power_supply_get_property(chip->bms_psy, + POWER_SUPPLY_PROP_CHARGE_COUNTER, &ret); + } else { + pr_debug("No BMS supply registered return 0\n"); + } + + return ret.intval; +} + +#define DEFAULT_TEMP 250 +static int get_prop_batt_temp(struct qpnp_lbc_chip *chip) +{ + int rc = 0; + struct qpnp_vadc_result results; + + if (chip->cfg_use_fake_battery || !get_prop_batt_present(chip)) + return DEFAULT_TEMP; + + rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX1_BATT_THERM, &results); + if (rc) { + pr_debug("Unable to read batt temperature rc=%d\n", rc); + return DEFAULT_TEMP; + } + pr_debug("get_bat_temp %d, %lld\n", results.adc_code, + results.physical); + + return (int)results.physical; +} + +static void qpnp_lbc_set_appropriate_current(struct qpnp_lbc_chip *chip) +{ + unsigned int chg_current = chip->usb_psy_ma; + + if (chip->bat_is_cool && chip->cfg_cool_bat_chg_ma) + chg_current = min(chg_current, chip->cfg_cool_bat_chg_ma); + if (chip->bat_is_warm && chip->cfg_warm_bat_chg_ma) + chg_current = min(chg_current, chip->cfg_warm_bat_chg_ma); + if (chip->therm_lvl_sel != 0 && chip->thermal_mitigation) + chg_current = min(chg_current, + chip->thermal_mitigation[chip->therm_lvl_sel]); + + pr_debug("setting charger current %d mA\n", chg_current); + qpnp_lbc_ibatmax_set(chip, chg_current); +} + +static int qpnp_lbc_system_temp_level_set(struct qpnp_lbc_chip *chip, + int lvl_sel) +{ + int rc = 0; + int prev_therm_lvl; + unsigned long flags; + + if (!chip->thermal_mitigation) { + pr_err("Thermal mitigation not supported\n"); + return -EINVAL; + } + + if (lvl_sel < 0) { + pr_err("Unsupported level selected %d\n", lvl_sel); + return -EINVAL; + } + + if (lvl_sel >= chip->cfg_thermal_levels) { + pr_err("Unsupported level selected %d forcing %d\n", lvl_sel, + chip->cfg_thermal_levels - 1); + lvl_sel = chip->cfg_thermal_levels - 1; + } + + if (lvl_sel == chip->therm_lvl_sel) + return 0; + + spin_lock_irqsave(&chip->ibat_change_lock, flags); + prev_therm_lvl = chip->therm_lvl_sel; + chip->therm_lvl_sel = lvl_sel; + if (chip->therm_lvl_sel == (chip->cfg_thermal_levels - 1)) { + /* Disable charging if highest value selected by */ + rc = qpnp_lbc_charger_enable(chip, THERMAL, 0); + if (rc < 0) + pr_err("Failed to set disable charging\n"); + goto out; + } + + qpnp_lbc_set_appropriate_current(chip); + + if (prev_therm_lvl == chip->cfg_thermal_levels - 1) { + /* + * If previously highest value was selected charging must have + * been disabed. Enable charging. + */ + rc = qpnp_lbc_charger_enable(chip, THERMAL, 1); + if (rc < 0) + pr_err("Failed to enable charging\n"); + } +out: + spin_unlock_irqrestore(&chip->ibat_change_lock, flags); + return rc; +} + +#define MIN_COOL_TEMP -300 +#define MAX_WARM_TEMP 1000 +#define HYSTERISIS_DECIDEGC 20 + +static int qpnp_lbc_configure_jeita(struct qpnp_lbc_chip *chip, + enum power_supply_property psp, int temp_degc) +{ + int rc = 0; + + if ((temp_degc < MIN_COOL_TEMP) || (temp_degc > MAX_WARM_TEMP)) { + pr_err("Invalid temp range=%d min=%d max=%d\n", + temp_degc, MIN_COOL_TEMP, MAX_WARM_TEMP); + return -EINVAL; + } + + mutex_lock(&chip->jeita_configure_lock); + switch (psp) { + case POWER_SUPPLY_PROP_COOL_TEMP: + if (temp_degc >= + (chip->cfg_warm_bat_decidegc - HYSTERISIS_DECIDEGC)) { + pr_err("Can't set cool %d higher than warm %d - hysterisis %d\n", + temp_degc, + chip->cfg_warm_bat_decidegc, + HYSTERISIS_DECIDEGC); + rc = -EINVAL; + goto mutex_unlock; + } + if (chip->bat_is_cool) + chip->adc_param.high_temp = + temp_degc + HYSTERISIS_DECIDEGC; + else if (!chip->bat_is_warm) + chip->adc_param.low_temp = temp_degc; + + chip->cfg_cool_bat_decidegc = temp_degc; + break; + case POWER_SUPPLY_PROP_WARM_TEMP: + if (temp_degc <= + (chip->cfg_cool_bat_decidegc + HYSTERISIS_DECIDEGC)) { + pr_err("Can't set warm %d higher than cool %d + hysterisis %d\n", + temp_degc, + chip->cfg_warm_bat_decidegc, + HYSTERISIS_DECIDEGC); + rc = -EINVAL; + goto mutex_unlock; + } + if (chip->bat_is_warm) + chip->adc_param.low_temp = + temp_degc - HYSTERISIS_DECIDEGC; + else if (!chip->bat_is_cool) + chip->adc_param.high_temp = temp_degc; + + chip->cfg_warm_bat_decidegc = temp_degc; + break; + default: + rc = -EINVAL; + goto mutex_unlock; + } + + if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param)) + pr_err("request ADC error\n"); + +mutex_unlock: + mutex_unlock(&chip->jeita_configure_lock); + return rc; +} + +static int qpnp_batt_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + case POWER_SUPPLY_PROP_CAPACITY: + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_COOL_TEMP: + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + case POWER_SUPPLY_PROP_WARM_TEMP: + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + return 1; + default: + break; + } + + return 0; +} + +/* + * End of charge happens only when BMS reports the battery status as full. For + * charging to end the s/w must put the usb path in suspend. Note that there + * is no battery fet and usb path suspend is the only control to prevent any + * current going in to the battery (and the system) + * Charging can begin only when VBATDET comparator outputs 0. This indicates + * that the battery is a at a lower voltage than 4% of the vddmax value. + * S/W can override this comparator to output a favourable value - this is + * used while resuming charging when the battery hasnt fallen below 4% but + * the SOC has fallen below the resume threshold. + * + * In short, when SOC resume happens: + * a. overide the comparator to output 0 + * b. enable charging + * + * When vbatdet based resume happens: + * a. enable charging + * + * When end of charge happens: + * a. disable the overrides in the comparator + * (may be from a previous soc resume) + * b. disable charging + */ +static int qpnp_batt_power_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct qpnp_lbc_chip *chip = power_supply_get_drvdata(psy); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + mutex_lock(&chip->chg_enable_lock); + switch (val->intval) { + case POWER_SUPPLY_STATUS_FULL: + if (chip->cfg_float_charge) + break; + /* Disable charging */ + rc = qpnp_lbc_charger_enable(chip, SOC, 0); + if (!rc) + chip->chg_done = true; + + /* + * Enable VBAT_DET based charging: + * To enable charging when VBAT falls below VBAT_DET + * and device stays suspended after EOC. + */ + if (!chip->cfg_disable_vbatdet_based_recharge) { + /* No override for VBAT_DET_LO comp */ + rc = qpnp_lbc_vbatdet_override(chip, + OVERRIDE_NONE); + if (rc) + pr_err("Failed to override VBAT_DET rc=%d\n", + rc); + else + qpnp_lbc_enable_irq(chip, + &chip->irqs[CHG_VBAT_DET_LO]); + } + break; + case POWER_SUPPLY_STATUS_CHARGING: + chip->chg_done = false; + pr_debug("resuming charging by bms\n"); + if (!chip->cfg_disable_vbatdet_based_recharge) + qpnp_lbc_vbatdet_override(chip, OVERRIDE_0); + + qpnp_lbc_charger_enable(chip, SOC, 1); + break; + case POWER_SUPPLY_STATUS_DISCHARGING: + chip->chg_done = false; + pr_debug("status = DISCHARGING chg_done = %d\n", + chip->chg_done); + break; + default: + break; + } + mutex_unlock(&chip->chg_enable_lock); + break; + case POWER_SUPPLY_PROP_COOL_TEMP: + rc = qpnp_lbc_configure_jeita(chip, psp, val->intval); + break; + case POWER_SUPPLY_PROP_WARM_TEMP: + rc = qpnp_lbc_configure_jeita(chip, psp, val->intval); + break; + case POWER_SUPPLY_PROP_CAPACITY: + chip->fake_battery_soc = val->intval; + pr_debug("power supply changed batt_psy\n"); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + chip->cfg_charging_disabled = !(val->intval); + rc = qpnp_lbc_charger_enable(chip, USER, + !chip->cfg_charging_disabled); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + qpnp_lbc_vinmin_set(chip, val->intval / 1000); + break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + qpnp_lbc_system_temp_level_set(chip, val->intval); + break; + default: + return -EINVAL; + } + + power_supply_changed(chip->batt_psy); + return rc; +} + +static int qpnp_batt_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct qpnp_lbc_chip *chip = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = get_prop_batt_status(chip); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = get_prop_charge_type(chip); + break; + case POWER_SUPPLY_PROP_HEALTH: + val->intval = get_prop_batt_health(chip); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = get_prop_batt_present(chip); + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = chip->cfg_max_voltage_mv * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = chip->cfg_min_voltage_mv * 1000; + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = get_prop_battery_voltage_now(chip); + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = get_prop_batt_temp(chip); + break; + case POWER_SUPPLY_PROP_COOL_TEMP: + val->intval = chip->cfg_cool_bat_decidegc; + break; + case POWER_SUPPLY_PROP_WARM_TEMP: + val->intval = chip->cfg_warm_bat_decidegc; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = get_prop_capacity(chip); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = get_prop_current_now(chip); + break; + case POWER_SUPPLY_PROP_CHARGE_COUNTER: + val->intval = get_prop_charge_count(chip); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + val->intval = !(chip->cfg_charging_disabled); + break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + val->intval = chip->therm_lvl_sel; + break; + default: + return -EINVAL; + } + + return 0; +} + +#define VINMIN_DELAY msecs_to_jiffies(500) +static void qpnp_lbc_parallel_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct qpnp_lbc_chip *chip = container_of(dwork, + struct qpnp_lbc_chip, parallel_work); + + if (is_vinmin_set(chip)) { + /* vinmin-loop triggered - stop ibat increase */ + pr_debug("vinmin_loop triggered ichg_now=%d\n", chip->ichg_now); + goto exit_work; + } else { + int temp = chip->ichg_now + QPNP_LBC_I_STEP_MA; + + if (temp > chip->lbc_max_chg_current) { + pr_debug("ichg_now=%d beyond max_chg_limit=%d - stopping\n", + temp, chip->lbc_max_chg_current); + goto exit_work; + } + chip->ichg_now = temp; + qpnp_lbc_ibatmax_set(chip, chip->ichg_now); + pr_debug("ichg_now increased to %d\n", chip->ichg_now); + } + + schedule_delayed_work(&chip->parallel_work, VINMIN_DELAY); + + return; + +exit_work: + pm_relax(chip->dev); +} + +static int qpnp_lbc_parallel_charging_config(struct qpnp_lbc_chip *chip, + int enable) +{ + chip->parallel_charging_enabled = !!enable; + + if (enable) { + /* Prevent sleep until charger is configured */ + chip->ichg_now = QPNP_LBC_IBATMAX_MIN; + qpnp_lbc_ibatmax_set(chip, chip->ichg_now); + qpnp_lbc_charger_enable(chip, PARALLEL, 1); + pm_stay_awake(chip->dev); + schedule_delayed_work(&chip->parallel_work, VINMIN_DELAY); + } else { + cancel_delayed_work_sync(&chip->parallel_work); + pm_relax(chip->dev); + /* set minimum charging current and disable charging */ + chip->ichg_now = 0; + chip->lbc_max_chg_current = 0; + qpnp_lbc_ibatmax_set(chip, 0); + qpnp_lbc_charger_enable(chip, PARALLEL, 0); + } + + pr_debug("charging=%d ichg_now=%d max_chg_current=%d\n", + enable, chip->ichg_now, chip->lbc_max_chg_current); + + return 0; +} + +static void qpnp_lbc_set_current(struct qpnp_lbc_chip *chip, int current_ma) +{ + pr_debug("USB present=%d current_ma=%dmA\n", chip->usb_present, + current_ma); + + if (current_ma <= 2 && get_prop_batt_present(chip)) { + qpnp_lbc_charger_enable(chip, CURRENT, 0); + chip->usb_psy_ma = QPNP_CHG_I_MAX_MIN_90; + qpnp_lbc_set_appropriate_current(chip); + } else { + chip->usb_psy_ma = current_ma; + qpnp_lbc_set_appropriate_current(chip); + qpnp_lbc_charger_enable(chip, CURRENT, 1); + } +} + +static enum power_supply_property qpnp_lbc_usb_properties[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_REAL_TYPE, + POWER_SUPPLY_PROP_SDP_CURRENT_MAX, +}; + +static int qpnp_lbc_usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct qpnp_lbc_chip *chip = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = chip->usb_psy_ma * 1000; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = chip->usb_present; + break; + case POWER_SUPPLY_PROP_ONLINE: + if (is_battery_charging(chip)) + val->intval = 1; + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_TYPE: + val->intval = POWER_SUPPLY_TYPE_USB; + if (chip->usb_present && + (chip->usb_supply_type != POWER_SUPPLY_TYPE_UNKNOWN)) + val->intval = chip->usb_supply_type; + break; + case POWER_SUPPLY_PROP_REAL_TYPE: + val->intval = POWER_SUPPLY_TYPE_UNKNOWN; + if (chip->usb_present && + (chip->usb_supply_type != POWER_SUPPLY_TYPE_UNKNOWN)) + val->intval = chip->usb_supply_type; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int qpnp_lbc_usb_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct qpnp_lbc_chip *chip = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + case POWER_SUPPLY_PROP_CURRENT_MAX: + qpnp_lbc_set_current(chip, (val->intval / 1000)); + break; + case POWER_SUPPLY_PROP_TYPE: + case POWER_SUPPLY_PROP_REAL_TYPE: + chip->usb_supply_type = val->intval; + break; + default: + return -EINVAL; + } + + power_supply_changed(psy); + return 0; +} +static int qpnp_lbc_usb_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CURRENT_MAX: + return 1; + default: + break; + } + return 0; +} + +static enum power_supply_property qpnp_lbc_parallel_properties[] = { + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, +}; + +static int qpnp_lbc_parallel_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + int rc = 0; + struct qpnp_lbc_chip *chip = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + qpnp_lbc_parallel_charging_config(chip, !!val->intval); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + chip->lbc_max_chg_current = val->intval / 1000; + pr_debug("lbc_max_current=%d\n", chip->lbc_max_chg_current); + break; + default: + return -EINVAL; + } + + return rc; +} + +static int qpnp_lbc_parallel_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + int rc; + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + rc = 1; + break; + default: + rc = 0; + break; + } + return rc; +} + +static int qpnp_lbc_parallel_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct qpnp_lbc_chip *chip = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + val->intval = chip->parallel_charging_enabled; + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + val->intval = chip->lbc_max_chg_current * 1000; + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = chip->ichg_now * 1000; + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = get_prop_charge_type(chip); + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = get_prop_batt_status(chip); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + val->intval = is_vinmin_set(chip); + break; + default: + return -EINVAL; + } + return 0; +} + + +static void qpnp_lbc_jeita_adc_notification(enum qpnp_tm_state state, void *ctx) +{ + struct qpnp_lbc_chip *chip = ctx; + bool bat_warm = 0, bat_cool = 0; + int temp; + unsigned long flags; + + if (state >= ADC_TM_STATE_NUM) { + pr_err("invalid notification %d\n", state); + return; + } + + temp = get_prop_batt_temp(chip); + + pr_debug("temp = %d state = %s\n", temp, + state == ADC_TM_WARM_STATE ? "warm" : "cool"); + + if (state == ADC_TM_WARM_STATE) { + if (temp >= chip->cfg_warm_bat_decidegc) { + /* Normal to warm */ + bat_warm = true; + bat_cool = false; + chip->adc_param.low_temp = + chip->cfg_warm_bat_decidegc + - HYSTERISIS_DECIDEGC; + chip->adc_param.state_request = + ADC_TM_COOL_THR_ENABLE; + } else if (temp >= + chip->cfg_cool_bat_decidegc + HYSTERISIS_DECIDEGC) { + /* Cool to normal */ + bat_warm = false; + bat_cool = false; + + chip->adc_param.low_temp = + chip->cfg_cool_bat_decidegc; + chip->adc_param.high_temp = + chip->cfg_warm_bat_decidegc; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } + } else { + if (temp <= chip->cfg_cool_bat_decidegc) { + /* Normal to cool */ + bat_warm = false; + bat_cool = true; + chip->adc_param.high_temp = + chip->cfg_cool_bat_decidegc + + HYSTERISIS_DECIDEGC; + chip->adc_param.state_request = + ADC_TM_WARM_THR_ENABLE; + } else if (temp <= (chip->cfg_warm_bat_decidegc - + HYSTERISIS_DECIDEGC)){ + /* Warm to normal */ + bat_warm = false; + bat_cool = false; + + chip->adc_param.low_temp = + chip->cfg_cool_bat_decidegc; + chip->adc_param.high_temp = + chip->cfg_warm_bat_decidegc; + chip->adc_param.state_request = + ADC_TM_HIGH_LOW_THR_ENABLE; + } + } + + if (chip->bat_is_cool ^ bat_cool || chip->bat_is_warm ^ bat_warm) { + spin_lock_irqsave(&chip->ibat_change_lock, flags); + chip->bat_is_cool = bat_cool; + chip->bat_is_warm = bat_warm; + qpnp_lbc_set_appropriate_vddmax(chip); + qpnp_lbc_set_appropriate_current(chip); + spin_unlock_irqrestore(&chip->ibat_change_lock, flags); + } + + pr_debug("warm %d, cool %d, low = %d deciDegC, high = %d deciDegC\n", + chip->bat_is_warm, chip->bat_is_cool, + chip->adc_param.low_temp, chip->adc_param.high_temp); + + if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, &chip->adc_param)) + pr_err("request ADC error\n"); +} + +#define IBAT_TERM_EN_MASK BIT(3) +static int qpnp_lbc_chg_init(struct qpnp_lbc_chip *chip) +{ + int rc; + u8 reg_val; + + qpnp_lbc_vbatweak_set(chip, chip->cfg_batt_weak_voltage_uv); + rc = qpnp_lbc_vinmin_set(chip, chip->cfg_min_voltage_mv); + if (rc) { + pr_err("Failed to set vin_min rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_vddsafe_set(chip, chip->cfg_safe_voltage_mv); + if (rc) { + pr_err("Failed to set vdd_safe rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_vddmax_set(chip, chip->cfg_max_voltage_mv); + if (rc) { + pr_err("Failed to set vdd_safe rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_ibatsafe_set(chip, chip->cfg_safe_current); + if (rc) { + pr_err("Failed to set ibat_safe rc=%d\n", rc); + return rc; + } + + if (of_find_property(chip->dev->of_node, "qcom,tchg-mins", NULL)) { + rc = qpnp_lbc_tchg_max_set(chip, chip->cfg_tchg_mins); + if (rc) { + pr_err("Failed to set tchg_mins rc=%d\n", rc); + return rc; + } + } + + /* + * Override VBAT_DET comparator to enable charging + * irrespective of VBAT above VBAT_DET. + */ + rc = qpnp_lbc_vbatdet_override(chip, OVERRIDE_0); + if (rc) { + pr_err("Failed to override comp rc=%d\n", rc); + return rc; + } + + /* + * Disable iterm comparator of linear charger to disable charger + * detecting end of charge condition based on DT configuration + * and float charge configuration. + */ + if (!chip->cfg_charger_detect_eoc || chip->cfg_float_charge) { + rc = qpnp_lbc_masked_write(chip, + chip->chgr_base + CHG_IBATTERM_EN_REG, + IBAT_TERM_EN_MASK, 0); + if (rc) { + pr_err("Failed to disable EOC comp rc=%d\n", rc); + return rc; + } + } + + /* Disable charger watchdog */ + reg_val = 0; + rc = qpnp_lbc_write(chip, chip->chgr_base + CHG_WDOG_EN_REG, + ®_val, 1); + + return rc; +} + +static int qpnp_lbc_bat_if_init(struct qpnp_lbc_chip *chip) +{ + u8 reg_val; + int rc; + + /* Select battery presence detection */ + switch (chip->cfg_bpd_detection) { + case BPD_TYPE_BAT_THM: + reg_val = BATT_THM_EN; + break; + case BPD_TYPE_BAT_ID: + reg_val = BATT_ID_EN; + break; + case BPD_TYPE_BAT_THM_BAT_ID: + reg_val = BATT_THM_EN | BATT_ID_EN; + break; + default: + reg_val = BATT_THM_EN; + break; + } + + rc = qpnp_lbc_masked_write(chip, + chip->bat_if_base + BAT_IF_BPD_CTRL_REG, + BATT_BPD_CTRL_SEL_MASK, reg_val); + if (rc) { + pr_err("Failed to choose BPD rc=%d\n", rc); + return rc; + } + + /* Force on VREF_BAT_THM */ + reg_val = VREF_BATT_THERM_FORCE_ON; + rc = qpnp_lbc_write(chip, + chip->bat_if_base + BAT_IF_VREF_BAT_THM_CTRL_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to force on VREF_BAT_THM rc=%d\n", rc); + return rc; + } + + return 0; +} + +static int qpnp_lbc_usb_path_init(struct qpnp_lbc_chip *chip) +{ + int rc; + u8 reg_val; + + if (qpnp_lbc_is_usb_chg_plugged_in(chip)) { + reg_val = 0; + rc = qpnp_lbc_write(chip, + chip->usb_chgpth_base + CHG_USB_ENUM_T_STOP_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to write enum stop rc=%d\n", rc); + return -ENXIO; + } + } + + if (chip->cfg_charging_disabled) { + rc = qpnp_lbc_charger_enable(chip, USER, 0); + if (rc) + pr_err("Failed to disable charging rc=%d\n", rc); + + /* + * Disable follow-on-reset if charging is explicitly disabled, + * this forces the charging to be disabled across reset. + * Note: Explicitly disabling charging is only a debug/test + * configuration + */ + reg_val = 0x0; + rc = __qpnp_lbc_secure_write(chip, chip->chgr_base, + CHG_PERPH_RESET_CTRL3_REG, ®_val, 1); + if (rc) + pr_err("Failed to configure PERPH_CTRL3 rc=%d\n", rc); + else + pr_debug("Charger is not following PMIC reset\n"); + } else { + /* + * Enable charging explicitly, + * because not sure the default behavior. + */ + reg_val = CHG_ENABLE; + rc = qpnp_lbc_masked_write(chip, chip->chgr_base + CHG_CTRL_REG, + CHG_EN_MASK, reg_val); + if (rc) + pr_err("Failed to enable charger rc=%d\n", rc); + } + + return rc; +} + +#define LBC_MISC_DIG_VERSION_1 0x01 +static int qpnp_lbc_misc_init(struct qpnp_lbc_chip *chip) +{ + int rc; + u8 reg_val, reg_val1, trim_center; + + /* Check if this LBC MISC version supports VDD trimming */ + rc = qpnp_lbc_read(chip, chip->misc_base + MISC_REV2_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read VDD_EA TRIM3 reg rc=%d\n", rc); + return rc; + } + + if (reg_val >= LBC_MISC_DIG_VERSION_1) { + chip->supported_feature_flag |= VDD_TRIM_SUPPORTED; + /* Read initial VDD trim value */ + rc = qpnp_lbc_read(chip, chip->misc_base + MISC_TRIM3_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read VDD_EA TRIM3 reg rc=%d\n", rc); + return rc; + } + + rc = qpnp_lbc_read(chip, chip->misc_base + MISC_TRIM4_REG, + ®_val1, 1); + if (rc) { + pr_err("Failed to read VDD_EA TRIM3 reg rc=%d\n", rc); + return rc; + } + + trim_center = ((reg_val & MISC_TRIM3_VDD_MASK) + >> VDD_TRIM3_SHIFT) + | ((reg_val1 & MISC_TRIM4_VDD_MASK) + >> VDD_TRIM4_SHIFT); + chip->init_trim_uv = qpnp_lbc_get_trim_voltage(trim_center); + chip->delta_vddmax_uv = chip->init_trim_uv; + pr_debug("Initial trim center %x trim_uv %d\n", + trim_center, chip->init_trim_uv); + } + + pr_debug("Setting BOOT_DONE\n"); + reg_val = MISC_BOOT_DONE; + rc = qpnp_lbc_write(chip, chip->misc_base + MISC_BOOT_DONE_REG, + ®_val, 1); + + return rc; +} + +static int show_lbc_config(struct seq_file *m, void *data) +{ + struct qpnp_lbc_chip *chip = m->private; + + seq_printf(m, "cfg_charging_disabled\t=\t%d\n" + "cfg_btc_disabled\t=\t%d\n" + "cfg_use_fake_battery\t=\t%d\n" + "cfg_use_external_charger\t=\t%d\n" + "cfg_chgr_led_support\t=\t%d\n" + "cfg_warm_bat_chg_ma\t=\t%d\n" + "cfg_cool_bat_chg_ma\t=\t%d\n" + "cfg_safe_voltage_mv\t=\t%d\n" + "cfg_max_voltage_mv\t=\t%d\n" + "cfg_min_voltage_mv\t=\t%d\n" + "cfg_charger_detect_eoc\t=\t%d\n" + "cfg_disable_vbatdet_based_recharge\t=\t%d\n" + "cfg_collapsible_chgr_support\t=\t%d\n" + "cfg_batt_weak_voltage_uv\t=\t%d\n" + "cfg_warm_bat_mv\t=\t%d\n" + "cfg_cool_bat_mv\t=\t%d\n" + "cfg_hot_batt_p\t=\t%d\n" + "cfg_cold_batt_p\t=\t%d\n" + "cfg_thermal_levels\t=\t%d\n" + "cfg_safe_current\t=\t%d\n" + "cfg_tchg_mins\t=\t%d\n" + "cfg_bpd_detection\t=\t%d\n" + "cfg_warm_bat_decidegc\t=\t%d\n" + "cfg_cool_bat_decidegc\t=\t%d\n" + "cfg_soc_resume_limit\t=\t%d\n" + "cfg_float_charge\t=\t%d\n", + chip->cfg_charging_disabled, + chip->cfg_btc_disabled, + chip->cfg_use_fake_battery, + chip->cfg_use_external_charger, + chip->cfg_chgr_led_support, + chip->cfg_warm_bat_chg_ma, + chip->cfg_cool_bat_chg_ma, + chip->cfg_safe_voltage_mv, + chip->cfg_max_voltage_mv, + chip->cfg_min_voltage_mv, + chip->cfg_charger_detect_eoc, + chip->cfg_disable_vbatdet_based_recharge, + chip->cfg_collapsible_chgr_support, + chip->cfg_batt_weak_voltage_uv, + chip->cfg_warm_bat_mv, + chip->cfg_cool_bat_mv, + chip->cfg_hot_batt_p, + chip->cfg_cold_batt_p, + chip->cfg_thermal_levels, + chip->cfg_safe_current, + chip->cfg_tchg_mins, + chip->cfg_bpd_detection, + chip->cfg_warm_bat_decidegc, + chip->cfg_cool_bat_decidegc, + chip->cfg_soc_resume_limit, + chip->cfg_float_charge); + + return 0; +} + +static int qpnp_lbc_config_open(struct inode *inode, struct file *file) +{ + struct qpnp_lbc_chip *chip = inode->i_private; + + return single_open(file, show_lbc_config, chip); +} + +static const struct file_operations qpnp_lbc_config_debugfs_ops = { + .owner = THIS_MODULE, + .open = qpnp_lbc_config_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define OF_PROP_READ(chip, prop, qpnp_dt_property, retval, optional) \ +do { \ + if (retval) \ + break; \ + \ + retval = of_property_read_u32(chip->dev->of_node, \ + "qcom," qpnp_dt_property, \ + &chip->prop); \ + \ + if ((retval == -EINVAL) && optional) \ + retval = 0; \ + else if (retval) \ + pr_err("Error reading " #qpnp_dt_property \ + " property rc = %d\n", rc); \ +} while (0) + +static int qpnp_charger_read_dt_props(struct qpnp_lbc_chip *chip) +{ + int rc = 0; + const char *bpd; + + OF_PROP_READ(chip, cfg_max_voltage_mv, "vddmax-mv", rc, 0); + OF_PROP_READ(chip, cfg_safe_voltage_mv, "vddsafe-mv", rc, 0); + OF_PROP_READ(chip, cfg_min_voltage_mv, "vinmin-mv", rc, 0); + OF_PROP_READ(chip, cfg_safe_current, "ibatsafe-ma", rc, 0); + if (rc) + pr_err("Error reading required property rc=%d\n", rc); + + OF_PROP_READ(chip, cfg_tchg_mins, "tchg-mins", rc, 1); + OF_PROP_READ(chip, cfg_warm_bat_decidegc, "warm-bat-decidegc", rc, 1); + OF_PROP_READ(chip, cfg_cool_bat_decidegc, "cool-bat-decidegc", rc, 1); + OF_PROP_READ(chip, cfg_hot_batt_p, "batt-hot-percentage", rc, 1); + OF_PROP_READ(chip, cfg_cold_batt_p, "batt-cold-percentage", rc, 1); + OF_PROP_READ(chip, cfg_batt_weak_voltage_uv, "vbatweak-uv", rc, 1); + OF_PROP_READ(chip, cfg_soc_resume_limit, "resume-soc", rc, 1); + if (rc) { + pr_err("Error reading optional property rc=%d\n", rc); + return rc; + } + + rc = of_property_read_string(chip->dev->of_node, + "qcom,bpd-detection", &bpd); + if (rc) { + + chip->cfg_bpd_detection = BPD_TYPE_BAT_THM; + rc = 0; + } else { + chip->cfg_bpd_detection = get_bpd(bpd); + if (chip->cfg_bpd_detection < 0) { + pr_err("Failed to determine bpd schema rc=%d\n", rc); + return -EINVAL; + } + } + + /* + * Look up JEITA compliance parameters if cool and warm temp + * provided + */ + if (chip->cfg_cool_bat_decidegc || chip->cfg_warm_bat_decidegc) { + chip->adc_tm_dev = qpnp_get_adc_tm(chip->dev, "chg"); + if (IS_ERR(chip->adc_tm_dev)) { + rc = PTR_ERR(chip->adc_tm_dev); + if (rc != -EPROBE_DEFER) + pr_err("Failed to get adc-tm rc=%d\n", rc); + return rc; + } + + OF_PROP_READ(chip, cfg_warm_bat_chg_ma, "ibatmax-warm-ma", + rc, 1); + OF_PROP_READ(chip, cfg_cool_bat_chg_ma, "ibatmax-cool-ma", + rc, 1); + OF_PROP_READ(chip, cfg_warm_bat_mv, "warm-bat-mv", rc, 1); + OF_PROP_READ(chip, cfg_cool_bat_mv, "cool-bat-mv", rc, 1); + if (rc) { + pr_err("Error reading battery temp prop rc=%d\n", rc); + return rc; + } + } + + /* Get the btc-disabled property */ + chip->cfg_btc_disabled = of_property_read_bool( + chip->dev->of_node, "qcom,btc-disabled"); + + /* Get the charging-disabled property */ + chip->cfg_charging_disabled = + of_property_read_bool(chip->dev->of_node, + "qcom,charging-disabled"); + + /* Get the fake-batt-values property */ + chip->cfg_use_fake_battery = + of_property_read_bool(chip->dev->of_node, + "qcom,use-default-batt-values"); + + /* Get the float charging property */ + chip->cfg_float_charge = + of_property_read_bool(chip->dev->of_node, + "qcom,float-charge"); + + /* Get the charger EOC detect property */ + chip->cfg_charger_detect_eoc = + of_property_read_bool(chip->dev->of_node, + "qcom,charger-detect-eoc"); + + /* Get the vbatdet disable property */ + chip->cfg_disable_vbatdet_based_recharge = + of_property_read_bool(chip->dev->of_node, + "qcom,disable-vbatdet-based-recharge"); + + /* Get the charger led support property */ + chip->cfg_chgr_led_support = + of_property_read_bool(chip->dev->of_node, + "qcom,chgr-led-support"); + + /* Get the collapsible charger support property */ + chip->cfg_collapsible_chgr_support = + of_property_read_bool(chip->dev->of_node, + "qcom,collapsible-chgr-support"); + + /* Disable charging when faking battery values */ + if (chip->cfg_use_fake_battery) + chip->cfg_charging_disabled = true; + + chip->cfg_use_external_charger = of_property_read_bool( + chip->dev->of_node, "qcom,use-external-charger"); + + if (of_find_property(chip->dev->of_node, + "qcom,thermal-mitigation", + &chip->cfg_thermal_levels)) { + chip->thermal_mitigation = devm_kzalloc(chip->dev, + chip->cfg_thermal_levels, + GFP_KERNEL); + + if (chip->thermal_mitigation == NULL) { + pr_err("thermal mitigation kzalloc() failed.\n"); + return -ENOMEM; + } + + chip->cfg_thermal_levels /= sizeof(int); + rc = of_property_read_u32_array(chip->dev->of_node, + "qcom,thermal-mitigation", + chip->thermal_mitigation, + chip->cfg_thermal_levels); + if (rc) { + pr_err("Failed to read threm limits rc = %d\n", rc); + return rc; + } + } + + pr_debug("vddmax-mv=%d, vddsafe-mv=%d, vinmin-mv=%d, ibatsafe-ma=$=%d\n", + chip->cfg_max_voltage_mv, + chip->cfg_safe_voltage_mv, + chip->cfg_min_voltage_mv, + chip->cfg_safe_current); + pr_debug("warm-bat-decidegc=%d, cool-bat-decidegc=%d, batt-hot-percentage=%d, batt-cold-percentage=%d\n", + chip->cfg_warm_bat_decidegc, + chip->cfg_cool_bat_decidegc, + chip->cfg_hot_batt_p, + chip->cfg_cold_batt_p); + pr_debug("tchg-mins=%d, vbatweak-uv=%d, resume-soc=%d\n", + chip->cfg_tchg_mins, + chip->cfg_batt_weak_voltage_uv, + chip->cfg_soc_resume_limit); + pr_debug("bpd-detection=%d, ibatmax-warm-ma=%d, ibatmax-cool-ma=%d, warm-bat-mv=%d, cool-bat-mv=%d\n", + chip->cfg_bpd_detection, + chip->cfg_warm_bat_chg_ma, + chip->cfg_cool_bat_chg_ma, + chip->cfg_warm_bat_mv, + chip->cfg_cool_bat_mv); + pr_debug("btc-disabled=%d, charging-disabled=%d, use-default-batt-values=%d, float-charge=%d\n", + chip->cfg_btc_disabled, + chip->cfg_charging_disabled, + chip->cfg_use_fake_battery, + chip->cfg_float_charge); + pr_debug("charger-detect-eoc=%d, disable-vbatdet-based-recharge=%d, chgr-led-support=%d\n", + chip->cfg_charger_detect_eoc, + chip->cfg_disable_vbatdet_based_recharge, + chip->cfg_chgr_led_support); + pr_debug("collapsible-chg-support=%d, use-external-charger=%d, thermal_levels=%d\n", + chip->cfg_collapsible_chgr_support, + chip->cfg_use_external_charger, + chip->cfg_thermal_levels); + return rc; +} + +#define CHG_REMOVAL_DETECT_DLY_MS 300 +static irqreturn_t qpnp_lbc_chg_gone_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + int chg_gone; + + if (chip->cfg_collapsible_chgr_support) { + chg_gone = qpnp_lbc_is_chg_gone(chip); + pr_debug("chg-gone triggered, rt_sts: %d\n", chg_gone); + if (chg_gone) { + /* + * Disable charger to prevent fastchg irq storming + * if a non-collapsible charger is being used. + */ + pr_debug("disable charging for non-collapsbile charger\n"); + qpnp_lbc_charger_enable(chip, COLLAPSE, 0); + qpnp_lbc_disable_irq(chip, &chip->irqs[USBIN_VALID]); + qpnp_lbc_disable_irq(chip, &chip->irqs[USB_CHG_GONE]); + qpnp_chg_collapsible_chgr_config(chip, 0); + /* + * Check after a delay if the charger is still + * inserted. It decides if a non-collapsible + * charger is being used, or charger has been + * removed. + */ + schedule_delayed_work(&chip->collapsible_detection_work, + msecs_to_jiffies(CHG_REMOVAL_DETECT_DLY_MS)); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t qpnp_lbc_usbin_valid_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + int usb_present; + unsigned long flags; + + usb_present = qpnp_lbc_is_usb_chg_plugged_in(chip); + pr_debug("usbin-valid triggered: %d\n", usb_present); + + if (chip->usb_present ^ usb_present) { + chip->usb_present = usb_present; + if (!usb_present) { + chip->usb_supply_type = POWER_SUPPLY_TYPE_UNKNOWN; + qpnp_lbc_charger_enable(chip, CURRENT, 0); + spin_lock_irqsave(&chip->ibat_change_lock, flags); + chip->usb_psy_ma = QPNP_CHG_I_MAX_MIN_90; + qpnp_lbc_set_appropriate_current(chip); + spin_unlock_irqrestore(&chip->ibat_change_lock, + flags); + if (chip->cfg_collapsible_chgr_support) + chip->non_collapsible_chgr_detected = false; + + if (chip->supported_feature_flag & VDD_TRIM_SUPPORTED) + alarm_try_to_cancel(&chip->vddtrim_alarm); + } else { + /* + * Override VBAT_DET comparator to start charging + * even if VBAT > VBAT_DET. + */ + if (!chip->cfg_disable_vbatdet_based_recharge) + qpnp_lbc_vbatdet_override(chip, OVERRIDE_0); + + /* + * If collapsible charger supported, enable chgr_gone + * irq, and configure for collapsible charger. + */ + if (chip->cfg_collapsible_chgr_support && + !chip->non_collapsible_chgr_detected) { + qpnp_lbc_enable_irq(chip, + &chip->irqs[USB_CHG_GONE]); + qpnp_chg_collapsible_chgr_config(chip, 1); + } + /* + * Enable SOC based charging to make sure + * charging gets enabled on USB insertion + * irrespective of battery SOC above resume_soc. + */ + qpnp_lbc_charger_enable(chip, SOC, 1); + } + + pr_debug("Updating usb_psy PRESENT property\n"); + if (chip->usb_present) + extcon_set_cable_state_(chip->extcon, + EXTCON_USB, true); + else + extcon_set_cable_state_(chip->extcon, + EXTCON_USB, false); + power_supply_changed(chip->usb_psy); + } + + return IRQ_HANDLED; +} + +static int qpnp_lbc_is_batt_temp_ok(struct qpnp_lbc_chip *chip) +{ + u8 reg_val; + int rc; + + rc = qpnp_lbc_read(chip, chip->bat_if_base + INT_RT_STS_REG, + ®_val, 1); + if (rc) { + pr_err("reg read failed: addr=%03X, rc=%d\n", + chip->bat_if_base + INT_RT_STS_REG, rc); + return rc; + } + + return (reg_val & BAT_TEMP_OK_IRQ) ? 1 : 0; +} + +static irqreturn_t qpnp_lbc_batt_temp_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + int batt_temp_good; + + batt_temp_good = qpnp_lbc_is_batt_temp_ok(chip); + pr_debug("batt-temp triggered: %d\n", batt_temp_good); + + pr_debug("power supply changed batt_psy\n"); + power_supply_changed(chip->batt_psy); + return IRQ_HANDLED; +} + +static irqreturn_t qpnp_lbc_batt_pres_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + int batt_present; + + batt_present = qpnp_lbc_is_batt_present(chip); + pr_debug("batt-pres triggered: %d\n", batt_present); + + if (chip->batt_present ^ batt_present) { + chip->batt_present = batt_present; + pr_debug("power supply changed batt_psy\n"); + power_supply_changed(chip->batt_psy); + + if ((chip->cfg_cool_bat_decidegc + || chip->cfg_warm_bat_decidegc) + && batt_present) { + pr_debug("enabling vadc notifications\n"); + if (qpnp_adc_tm_channel_measure(chip->adc_tm_dev, + &chip->adc_param)) + pr_err("request ADC error\n"); + } else if ((chip->cfg_cool_bat_decidegc + || chip->cfg_warm_bat_decidegc) + && !batt_present) { + qpnp_adc_tm_disable_chan_meas(chip->adc_tm_dev, + &chip->adc_param); + pr_debug("disabling vadc notifications\n"); + } + } + return IRQ_HANDLED; +} + +static irqreturn_t qpnp_lbc_chg_failed_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + int rc; + u8 reg_val = CHG_FAILED_BIT; + + pr_debug("chg_failed triggered count=%u\n", ++chip->chg_failed_count); + rc = qpnp_lbc_write(chip, chip->chgr_base + CHG_FAILED_REG, + ®_val, 1); + if (rc) + pr_err("Failed to write chg_fail clear bit rc=%d\n", rc); + + if (chip->bat_if_base) { + pr_debug("power supply changed batt_psy\n"); + power_supply_changed(chip->batt_psy); + } + + return IRQ_HANDLED; +} + +static int qpnp_lbc_is_fastchg_on(struct qpnp_lbc_chip *chip) +{ + u8 reg_val; + int rc; + + rc = qpnp_lbc_read(chip, chip->chgr_base + INT_RT_STS_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read interrupt status rc=%d\n", rc); + return rc; + } + pr_debug("charger status %x\n", reg_val); + return (reg_val & FAST_CHG_ON_IRQ) ? 1 : 0; +} + +#define TRIM_PERIOD_NS (50LL * NSEC_PER_SEC) +static irqreturn_t qpnp_lbc_fastchg_irq_handler(int irq, void *_chip) +{ + ktime_t kt; + struct qpnp_lbc_chip *chip = _chip; + bool fastchg_on = false; + + fastchg_on = qpnp_lbc_is_fastchg_on(chip); + + pr_debug("FAST_CHG IRQ triggered, fastchg_on: %d\n", fastchg_on); + + if (chip->fastchg_on ^ fastchg_on) { + chip->fastchg_on = fastchg_on; + if (fastchg_on) { + mutex_lock(&chip->chg_enable_lock); + chip->chg_done = false; + mutex_unlock(&chip->chg_enable_lock); + /* + * Start alarm timer to periodically calculate + * and update VDD_MAX trim value. + */ + if (chip->supported_feature_flag & + VDD_TRIM_SUPPORTED) { + kt = ns_to_ktime(TRIM_PERIOD_NS); + alarm_start_relative(&chip->vddtrim_alarm, + kt); + } + } + + if (chip->bat_if_base) { + pr_debug("power supply changed batt_psy\n"); + power_supply_changed(chip->batt_psy); + } + } + + return IRQ_HANDLED; +} + +static irqreturn_t qpnp_lbc_chg_done_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + + pr_debug("charging done triggered\n"); + + chip->chg_done = true; + pr_debug("power supply changed batt_psy\n"); + power_supply_changed(chip->batt_psy); + + return IRQ_HANDLED; +} + +static irqreturn_t qpnp_lbc_vbatdet_lo_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + int rc; + + pr_debug("vbatdet-lo triggered\n"); + + /* + * Disable vbatdet irq to prevent interrupt storm when VBAT is + * close to VBAT_DET. + */ + qpnp_lbc_disable_irq(chip, &chip->irqs[CHG_VBAT_DET_LO]); + + /* + * Override VBAT_DET comparator to 0 to fix comparator toggling + * near VBAT_DET threshold. + */ + qpnp_lbc_vbatdet_override(chip, OVERRIDE_0); + + /* + * Battery has fallen below the vbatdet threshold and it is + * time to resume charging. + */ + rc = qpnp_lbc_charger_enable(chip, SOC, 1); + if (rc) + pr_err("Failed to enable charging\n"); + + return IRQ_HANDLED; +} + +static int qpnp_lbc_is_overtemp(struct qpnp_lbc_chip *chip) +{ + u8 reg_val; + int rc; + + rc = qpnp_lbc_read(chip, chip->usb_chgpth_base + INT_RT_STS_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read interrupt status rc=%d\n", rc); + return rc; + } + + pr_debug("OVERTEMP rt status %x\n", reg_val); + return (reg_val & OVERTEMP_ON_IRQ) ? 1 : 0; +} + +static irqreturn_t qpnp_lbc_usb_overtemp_irq_handler(int irq, void *_chip) +{ + struct qpnp_lbc_chip *chip = _chip; + int overtemp = qpnp_lbc_is_overtemp(chip); + + pr_warn_ratelimited("charger %s temperature limit\n", + overtemp ? "exceeds" : "within"); + + return IRQ_HANDLED; +} + +static int qpnp_disable_lbc_charger(struct qpnp_lbc_chip *chip) +{ + int rc; + u8 reg; + + reg = CHG_FORCE_BATT_ON; + rc = qpnp_lbc_masked_write(chip, chip->chgr_base + CHG_CTRL_REG, + CHG_EN_MASK, reg); + /* disable BTC */ + rc |= qpnp_lbc_masked_write(chip, chip->bat_if_base + BAT_IF_BTC_CTRL, + BTC_COMP_EN_MASK, 0); + /* Enable BID and disable THM based BPD */ + reg = BATT_ID_EN | BATT_BPD_OFFMODE_EN; + rc |= qpnp_lbc_write(chip, chip->bat_if_base + BAT_IF_BPD_CTRL_REG, + ®, 1); + return rc; +} + +#define REQUEST_IRQ(chip, idx, rc, irq_name, threaded, flags, wake)\ +do { \ + if (rc) \ + break; \ + if (chip->irqs[idx].irq) { \ + if (threaded) \ + rc = devm_request_threaded_irq(chip->dev, \ + chip->irqs[idx].irq, NULL, \ + qpnp_lbc_##irq_name##_irq_handler, \ + flags, #irq_name, chip); \ + else \ + rc = devm_request_irq(chip->dev, \ + chip->irqs[idx].irq, \ + qpnp_lbc_##irq_name##_irq_handler, \ + flags, #irq_name, chip); \ + if (rc < 0) { \ + pr_err("Unable to request " #irq_name " %d\n", \ + rc); \ + } else { \ + rc = 0; \ + if (wake) { \ + enable_irq_wake(chip->irqs[idx].irq); \ + chip->irqs[idx].is_wake = true; \ + } \ + } \ + } \ +} while (0) + +static inline void get_irq_resource(struct qpnp_lbc_chip *chip, int idx, + const char *name, struct device_node *child) +{ + int rc = 0; + + rc = of_irq_get_byname(child, name); + if (rc < 0) + pr_err("Unable to get irq resource for %s - %d\n", name, rc); + else + chip->irqs[idx].irq = rc; +} + +static int qpnp_lbc_request_irqs(struct qpnp_lbc_chip *chip) +{ + int rc = 0; + + REQUEST_IRQ(chip, CHG_FAILED, rc, chg_failed, 0, + IRQF_TRIGGER_RISING, 1); + + REQUEST_IRQ(chip, CHG_FAST_CHG, rc, fastchg, 1, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, 1); + + REQUEST_IRQ(chip, CHG_DONE, rc, chg_done, 0, + IRQF_TRIGGER_RISING, 0); + + REQUEST_IRQ(chip, CHG_VBAT_DET_LO, rc, vbatdet_lo, 0, + IRQF_TRIGGER_FALLING, 1); + + REQUEST_IRQ(chip, BATT_PRES, rc, batt_pres, 1, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, 1); + + REQUEST_IRQ(chip, BATT_TEMPOK, rc, batt_temp, 0, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 1); + + REQUEST_IRQ(chip, USBIN_VALID, rc, usbin_valid, 1, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 1); + + REQUEST_IRQ(chip, USB_CHG_GONE, rc, chg_gone, 0, + IRQF_TRIGGER_RISING, 1); + + REQUEST_IRQ(chip, USB_OVER_TEMP, rc, usb_overtemp, 0, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, 0); + + return 0; +} + +static int qpnp_lbc_get_irqs(struct qpnp_lbc_chip *chip, u8 subtype, + struct device_node *child) +{ + switch (subtype) { + case LBC_CHGR_SUBTYPE: + get_irq_resource(chip, CHG_FAST_CHG, "fast-chg-on", child); + get_irq_resource(chip, CHG_FAILED, "chg-failed", child); + + if (!chip->cfg_disable_vbatdet_based_recharge) + get_irq_resource(chip, CHG_VBAT_DET_LO, + "vbat-det-lo", child); + if (chip->cfg_charger_detect_eoc) + get_irq_resource(chip, CHG_DONE, "chg-done", child); + break; + + case LBC_BAT_IF_SUBTYPE: + get_irq_resource(chip, BATT_PRES, "batt-pres", child); + get_irq_resource(chip, BATT_TEMPOK, "bat-temp-ok", child); + break; + + case LBC_USB_PTH_SUBTYPE: + get_irq_resource(chip, USBIN_VALID, "usbin-valid", child); + get_irq_resource(chip, USB_OVER_TEMP, "usb-over-temp", child); + get_irq_resource(chip, USB_CHG_GONE, "chg-gone", child); + break; + }; + return 0; +} + +/* Get/Set initial state of charger */ +static void determine_initial_status(struct qpnp_lbc_chip *chip) +{ + chip->usb_present = qpnp_lbc_is_usb_chg_plugged_in(chip); + power_supply_changed(chip->usb_psy); + /* + * Set USB psy online to avoid userspace from shutting down if battery + * capacity is at zero and no chargers online. + */ + if (chip->usb_present) { + if (chip->cfg_collapsible_chgr_support && + !chip->non_collapsible_chgr_detected) { + qpnp_lbc_enable_irq(chip, + &chip->irqs[USB_CHG_GONE]); + qpnp_chg_collapsible_chgr_config(chip, 1); + } + extcon_set_cable_state_(chip->extcon, EXTCON_USB, true); + } else { + extcon_set_cable_state_(chip->extcon, EXTCON_USB, false); + } + power_supply_changed(chip->usb_psy); +} + +static void qpnp_lbc_collapsible_detection_work(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct qpnp_lbc_chip *chip = container_of(dwork, + struct qpnp_lbc_chip, + collapsible_detection_work); + + if (qpnp_lbc_is_usb_chg_plugged_in(chip)) { + chip->non_collapsible_chgr_detected = true; + pr_debug("Non-collapsible charger detected\n"); + } else { + chip->non_collapsible_chgr_detected = false; + pr_debug("Charger removal detected\n"); + } + qpnp_lbc_charger_enable(chip, COLLAPSE, 1); + qpnp_lbc_enable_irq(chip, &chip->irqs[USBIN_VALID]); +} + +#define IBAT_TRIM -300 +static void qpnp_lbc_vddtrim_work_fn(struct work_struct *work) +{ + int rc, vbat_now_uv, ibat_now; + u8 reg_val; + ktime_t kt; + struct qpnp_lbc_chip *chip = container_of(work, struct qpnp_lbc_chip, + vddtrim_work); + + vbat_now_uv = get_prop_battery_voltage_now(chip); + ibat_now = get_prop_current_now(chip) / 1000; + pr_debug("vbat %d ibat %d capacity %d\n", + vbat_now_uv, ibat_now, get_prop_capacity(chip)); + + /* + * Stop trimming under following condition: + * USB removed + * Charging Stopped + */ + if (!qpnp_lbc_is_fastchg_on(chip) || + !qpnp_lbc_is_usb_chg_plugged_in(chip)) { + pr_debug("stop trim charging stopped\n"); + goto exit; + } else { + rc = qpnp_lbc_read(chip, chip->chgr_base + CHG_STATUS_REG, + ®_val, 1); + if (rc) { + pr_err("Failed to read chg status rc=%d\n", rc); + goto out; + } + + /* + * Update VDD trim voltage only if following conditions are + * met: + * If charger is in VDD loop AND + * If ibat is between 0 ma and -300 ma + */ + if ((reg_val & CHG_VDD_LOOP_BIT) && + ((ibat_now < 0) && (ibat_now > IBAT_TRIM))) + qpnp_lbc_adjust_vddmax(chip, vbat_now_uv); + } + +out: + kt = ns_to_ktime(TRIM_PERIOD_NS); + alarm_start_relative(&chip->vddtrim_alarm, kt); +exit: + pm_relax(chip->dev); +} + +static enum alarmtimer_restart vddtrim_callback(struct alarm *alarm, + ktime_t now) +{ + struct qpnp_lbc_chip *chip = container_of(alarm, struct qpnp_lbc_chip, + vddtrim_alarm); + + pm_stay_awake(chip->dev); + schedule_work(&chip->vddtrim_work); + + return ALARMTIMER_NORESTART; +} + +static int qpnp_lbc_parallel_charger_init(struct qpnp_lbc_chip *chip) +{ + u8 reg_val; + int rc; + + rc = qpnp_lbc_vinmin_set(chip, chip->cfg_min_voltage_mv); + if (rc) { + pr_err("Failed to set vin_min rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_vddsafe_set(chip, chip->cfg_max_voltage_mv); + if (rc) { + pr_err("Failed to set vdd_safe rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_vddmax_set(chip, chip->cfg_max_voltage_mv); + if (rc) { + pr_err("Failed to set vdd_max rc=%d\n", rc); + return rc; + } + + /* set the minimum charging current */ + rc = qpnp_lbc_ibatmax_set(chip, 0); + if (rc) { + pr_err("Failed to set IBAT_MAX to 0 rc=%d\n", rc); + return rc; + } + + /* disable charging */ + rc = qpnp_lbc_charger_enable(chip, PARALLEL, 0); + if (rc) { + pr_err("Unable to disable charging rc=%d\n", rc); + return 0; + } + + /* Enable BID and disable THM based BPD */ + reg_val = BATT_ID_EN | BATT_BPD_OFFMODE_EN; + rc = qpnp_lbc_write(chip, chip->bat_if_base + BAT_IF_BPD_CTRL_REG, + ®_val, 1); + if (rc) + pr_err("Failed to override BPD configuration rc=%d\n", rc); + + /* Disable and override BTC */ + reg_val = 0x2A; + rc = __qpnp_lbc_secure_write(chip, chip->bat_if_base, + BTC_COMP_OVERRIDE_REG, ®_val, 1); + if (rc) + pr_err("Failed to disable BTC override rc=%d\n", rc); + + reg_val = 0; + rc = qpnp_lbc_write(chip, + chip->bat_if_base + BAT_IF_BTC_CTRL, ®_val, 1); + if (rc) + pr_err("Failed to disable BTC rc=%d\n", rc); + + /* override VBAT_DET */ + rc = qpnp_lbc_vbatdet_override(chip, OVERRIDE_0); + if (rc) + pr_err("Failed to override VBAT_DET rc=%d\n", rc); + + /* Set BOOT_DONE and ENUM complete */ + reg_val = 0; + rc = qpnp_lbc_write(chip, + chip->usb_chgpth_base + CHG_USB_ENUM_T_STOP_REG, + ®_val, 1); + if (rc) + pr_err("Failed to stop enum-timer rc=%d\n", rc); + + reg_val = MISC_BOOT_DONE; + rc = qpnp_lbc_write(chip, chip->misc_base + MISC_BOOT_DONE_REG, + ®_val, 1); + if (rc) + pr_err("Failed to set boot-done rc=%d\n", rc); + + return rc; +} + +static int qpnp_lbc_parse_resources(struct qpnp_lbc_chip *chip) +{ + u8 subtype; + int rc = 0; + struct platform_device *pdev = chip->pdev; + struct device_node *child; + unsigned int base; + + if (of_get_available_child_count(pdev->dev.of_node) == 0) { + pr_err("no child nodes\n"); + goto fail_charger_enable; + } + + for_each_available_child_of_node(pdev->dev.of_node, child) { + rc = of_property_read_u32(child, "reg", &base); + pr_debug("register address = %#X rc = %d\n", base, rc); + if (rc < 0) { + pr_err("Couldn`t find reg in node = %s rc = %d\n", + child->full_name, rc); + goto fail_charger_enable; + } + + rc = qpnp_lbc_read(chip, base + PERP_SUBTYPE_REG, &subtype, 1); + if (rc) { + pr_err("Peripheral subtype read failed rc=%d\n", rc); + return rc; + } + + switch (subtype) { + case LBC_CHGR_SUBTYPE: + chip->chgr_base = base; + rc = qpnp_lbc_get_irqs(chip, subtype, child); + if (rc) { + pr_err("Failed to get CHGR irqs rc=%d\n", rc); + return rc; + } + break; + case LBC_USB_PTH_SUBTYPE: + chip->usb_chgpth_base = base; + rc = qpnp_lbc_get_irqs(chip, subtype, child); + if (rc) { + pr_err("Failed to get USB_PTH irqs rc=%d\n", + rc); + return rc; + } + break; + case LBC_BAT_IF_SUBTYPE: + chip->bat_if_base = base; + rc = qpnp_lbc_get_irqs(chip, subtype, child); + if (rc) { + pr_err("Failed to get BAT_IF irqs rc=%d\n", rc); + return rc; + } + break; + case LBC_MISC_SUBTYPE: + chip->misc_base = base; + break; + default: + pr_err("Invalid peripheral subtype=0x%x\n", subtype); + rc = -EINVAL; + } + } + + pr_debug("chgr_base=%x usb_chgpth_base=%x bat_if_base=%x misc_base=%x\n", + chip->chgr_base, chip->usb_chgpth_base, + chip->bat_if_base, chip->misc_base); + + return rc; + +fail_charger_enable: + dev_set_drvdata(&pdev->dev, NULL); + return -ENXIO; +} + +static int qpnp_lbc_parallel_probe(struct platform_device *pdev) +{ + int rc = 0; + struct qpnp_lbc_chip *chip; + struct power_supply_config parallel_psy_cfg = {}; + + chip = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_lbc_chip), + GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) { + pr_err("Couldn't get parent's regmap\n"); + return -EINVAL; + } + + chip->dev = &pdev->dev; + chip->pdev = pdev; + dev_set_drvdata(&pdev->dev, chip); + device_init_wakeup(&pdev->dev, 1); + spin_lock_init(&chip->hw_access_lock); + spin_lock_init(&chip->ibat_change_lock); + INIT_DELAYED_WORK(&chip->parallel_work, qpnp_lbc_parallel_work); + + OF_PROP_READ(chip, cfg_max_voltage_mv, "vddmax-mv", rc, 0); + if (rc) + return rc; + OF_PROP_READ(chip, cfg_min_voltage_mv, "vinmin-mv", rc, 0); + if (rc) + return rc; + + rc = qpnp_lbc_parse_resources(chip); + if (rc) { + pr_err("Unable to parse LBC(parallel) resources rc=%d\n", rc); + return rc; + } + + rc = qpnp_lbc_parallel_charger_init(chip); + if (rc) { + pr_err("Unable to initialize LBC(parallel) rc=%d\n", rc); + return rc; + } + + chip->parallel_psy_d.name = "parallel"; + chip->parallel_psy_d.type = POWER_SUPPLY_TYPE_PARALLEL; + chip->parallel_psy_d.get_property = qpnp_lbc_parallel_get_property; + chip->parallel_psy_d.set_property = qpnp_lbc_parallel_set_property; + chip->parallel_psy_d.properties = qpnp_lbc_parallel_properties; + chip->parallel_psy_d.property_is_writeable = + qpnp_lbc_parallel_is_writeable; + chip->parallel_psy_d.num_properties = + ARRAY_SIZE(qpnp_lbc_parallel_properties); + + parallel_psy_cfg.drv_data = chip; + parallel_psy_cfg.num_supplicants = 0; + + chip->parallel_psy = devm_power_supply_register(chip->dev, + &chip->parallel_psy_d, + ¶llel_psy_cfg); + if (IS_ERR(chip->parallel_psy)) { + pr_err("Unable to register LBC parallel_psy rc = %ld\n", + PTR_ERR(chip->parallel_psy)); + return PTR_ERR(chip->parallel_psy); + } + + pr_debug("LBC (parallel) registered successfully!\n"); + + return 0; +} + +static int qpnp_lbc_main_probe(struct platform_device *pdev) +{ + ktime_t kt; + struct qpnp_lbc_chip *chip; + struct power_supply_config batt_psy_cfg = {}; + struct power_supply_config usb_psy_cfg = {}; + int rc = 0; + + chip = devm_kzalloc(&pdev->dev, sizeof(struct qpnp_lbc_chip), + GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!chip->regmap) + return -EINVAL; + + chip->dev = &pdev->dev; + chip->pdev = pdev; + dev_set_drvdata(&pdev->dev, chip); + device_init_wakeup(&pdev->dev, 1); + chip->fake_battery_soc = -EINVAL; + chip->usb_supply_type = POWER_SUPPLY_TYPE_UNKNOWN; + + chip->extcon = devm_extcon_dev_allocate(chip->dev, + qpnp_lbc_extcon_cable); + if (IS_ERR(chip->extcon)) { + pr_err("failed to allocate extcon device\n"); + rc = PTR_ERR(chip->extcon); + return rc; + } + + rc = devm_extcon_dev_register(chip->dev, chip->extcon); + if (rc) { + pr_err("failed to register extcon device\n"); + return rc; + } + + mutex_init(&chip->jeita_configure_lock); + mutex_init(&chip->chg_enable_lock); + spin_lock_init(&chip->hw_access_lock); + spin_lock_init(&chip->ibat_change_lock); + spin_lock_init(&chip->irq_lock); + INIT_WORK(&chip->vddtrim_work, qpnp_lbc_vddtrim_work_fn); + alarm_init(&chip->vddtrim_alarm, ALARM_REALTIME, vddtrim_callback); + INIT_DELAYED_WORK(&chip->collapsible_detection_work, + qpnp_lbc_collapsible_detection_work); + + /* Get all device-tree properties */ + rc = qpnp_charger_read_dt_props(chip); + if (rc) { + pr_err("Failed to read DT properties rc=%d\n", rc); + return rc; + } + + rc = qpnp_lbc_parse_resources(chip); + if (rc) { + pr_err("Unable to parse LBC resources rc=%d\n", rc); + goto fail_chg_enable; + } + + if (chip->cfg_use_external_charger) { + pr_warn("Disabling Linear Charger (e-external-charger = 1)\n"); + rc = qpnp_disable_lbc_charger(chip); + if (rc) + pr_err("Unable to disable charger rc=%d\n", rc); + return -ENODEV; + } + + chip->usb_psy_d.name = "usb"; + chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB; + chip->usb_psy_d.properties = qpnp_lbc_usb_properties; + chip->usb_psy_d.num_properties = ARRAY_SIZE(qpnp_lbc_usb_properties); + chip->usb_psy_d.get_property = qpnp_lbc_usb_get_property; + chip->usb_psy_d.set_property = qpnp_lbc_usb_set_property; + chip->usb_psy_d.property_is_writeable = qpnp_lbc_usb_is_writeable; + + usb_psy_cfg.drv_data = chip; + usb_psy_cfg.num_supplicants = 0; + + chip->usb_psy = devm_power_supply_register(chip->dev, + &chip->usb_psy_d, &usb_psy_cfg); + if (IS_ERR(chip->usb_psy)) { + pr_err("Unable to register usb_psy rc = %ld\n", + PTR_ERR(chip->usb_psy)); + rc = PTR_ERR(chip->usb_psy); + goto fail_chg_enable; + } + + chip->vadc_dev = qpnp_get_vadc(chip->dev, "chg"); + if (IS_ERR(chip->vadc_dev)) { + rc = PTR_ERR(chip->vadc_dev); + if (rc != -EPROBE_DEFER) + pr_err("vadc prop missing rc=%d\n", + rc); + goto fail_chg_enable; + } + + /* Initialize h/w */ + rc = qpnp_lbc_misc_init(chip); + if (rc) { + pr_err("unable to initialize LBC MISC rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_chg_init(chip); + if (rc) { + pr_err("unable to initialize LBC charger rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_bat_if_init(chip); + if (rc) { + pr_err("unable to initialize LBC BAT_IF rc=%d\n", rc); + return rc; + } + rc = qpnp_lbc_usb_path_init(chip); + if (rc) { + pr_err("unable to initialize LBC USB path rc=%d\n", rc); + return rc; + } + + if (chip->cfg_chgr_led_support) { + rc = qpnp_lbc_register_chgr_led(chip); + if (rc) { + pr_err("unable to register charger led rc=%d\n", rc); + return rc; + } + } + + if (chip->bat_if_base) { + chip->batt_present = qpnp_lbc_is_batt_present(chip); + chip->batt_psy_d.name = "battery"; + chip->batt_psy_d.type = POWER_SUPPLY_TYPE_BATTERY; + chip->batt_psy_d.properties = msm_batt_power_props; + chip->batt_psy_d.num_properties = + ARRAY_SIZE(msm_batt_power_props); + chip->batt_psy_d.get_property = qpnp_batt_power_get_property; + chip->batt_psy_d.set_property = qpnp_batt_power_set_property; + chip->batt_psy_d.property_is_writeable = + qpnp_batt_property_is_writeable; + + batt_psy_cfg.drv_data = chip; + batt_psy_cfg.supplied_to = pm_batt_supplied_to; + batt_psy_cfg.num_supplicants = + ARRAY_SIZE(pm_batt_supplied_to); + + chip->batt_psy = devm_power_supply_register(chip->dev, + &chip->batt_psy_d, + &batt_psy_cfg); + if (IS_ERR(chip->batt_psy)) { + pr_err("Unable to register LBC batt_psy rc = %ld\n", + PTR_ERR(chip->batt_psy)); + goto fail_chg_enable; + } + } + + if ((chip->cfg_cool_bat_decidegc || chip->cfg_warm_bat_decidegc) + && chip->bat_if_base) { + chip->adc_param.low_temp = chip->cfg_cool_bat_decidegc; + chip->adc_param.high_temp = chip->cfg_warm_bat_decidegc; + chip->adc_param.timer_interval = ADC_MEAS1_INTERVAL_1S; + chip->adc_param.state_request = ADC_TM_HIGH_LOW_THR_ENABLE; + chip->adc_param.btm_ctx = chip; + chip->adc_param.threshold_notification = + qpnp_lbc_jeita_adc_notification; + chip->adc_param.channel = LR_MUX1_BATT_THERM; + + if (get_prop_batt_present(chip)) { + rc = qpnp_adc_tm_channel_measure(chip->adc_tm_dev, + &chip->adc_param); + if (rc) { + pr_err("request ADC error rc=%d\n", rc); + goto unregister_batt; + } + } + } + + rc = qpnp_lbc_bat_if_configure_btc(chip); + if (rc) { + pr_err("Failed to configure btc rc=%d\n", rc); + goto unregister_batt; + } + + /* Get/Set charger's initial status */ + determine_initial_status(chip); + + rc = qpnp_lbc_request_irqs(chip); + if (rc) { + pr_err("unable to initialize LBC MISC rc=%d\n", rc); + goto unregister_batt; + } + + if (chip->cfg_charging_disabled && !get_prop_batt_present(chip)) + pr_info("Battery absent and charging disabled\n"); + + /* Configure initial alarm for VDD trim */ + if ((chip->supported_feature_flag & VDD_TRIM_SUPPORTED) && + qpnp_lbc_is_fastchg_on(chip)) { + kt = ns_to_ktime(TRIM_PERIOD_NS); + alarm_start_relative(&chip->vddtrim_alarm, kt); + } + + chip->debug_root = debugfs_create_dir("qpnp_lbc", NULL); + if (!chip->debug_root) + pr_err("Couldn't create debug dir\n"); + + if (chip->debug_root) { + struct dentry *ent; + + ent = debugfs_create_file("lbc_config", S_IFREG | 0444, + chip->debug_root, chip, + &qpnp_lbc_config_debugfs_ops); + if (!ent) + pr_err("Couldn't create lbc_config debug file\n"); + } + + pr_debug("Probe chg_dis=%d bpd=%d usb=%d batt_pres=%d batt_volt=%d soc=%d\n", + chip->cfg_charging_disabled, + chip->cfg_bpd_detection, + qpnp_lbc_is_usb_chg_plugged_in(chip), + get_prop_batt_present(chip), + get_prop_battery_voltage_now(chip), + get_prop_capacity(chip)); + + return 0; + +unregister_batt: + if (chip->bat_if_base) + power_supply_unregister(chip->batt_psy); +fail_chg_enable: + power_supply_unregister(chip->usb_psy); + dev_set_drvdata(&pdev->dev, NULL); + return rc; +} + +static int is_parallel_charger(struct platform_device *pdev) +{ + return of_property_read_bool(pdev->dev.of_node, + "qcom,parallel-charger"); +} + +static int qpnp_lbc_probe(struct platform_device *pdev) +{ + if (is_parallel_charger(pdev)) + return qpnp_lbc_parallel_probe(pdev); + else + return qpnp_lbc_main_probe(pdev); +} + + +static int qpnp_lbc_remove(struct platform_device *pdev) +{ + struct qpnp_lbc_chip *chip = dev_get_drvdata(&pdev->dev); + + if (chip->supported_feature_flag & VDD_TRIM_SUPPORTED) { + alarm_cancel(&chip->vddtrim_alarm); + cancel_work_sync(&chip->vddtrim_work); + } + cancel_delayed_work_sync(&chip->collapsible_detection_work); + debugfs_remove_recursive(chip->debug_root); + if (chip->bat_if_base) + power_supply_unregister(chip->batt_psy); + power_supply_unregister(chip->usb_psy); + mutex_destroy(&chip->jeita_configure_lock); + mutex_destroy(&chip->chg_enable_lock); + dev_set_drvdata(&pdev->dev, NULL); + return 0; +} + +static const struct of_device_id qpnp_lbc_match_table[] = { + { .compatible = QPNP_CHARGER_DEV_NAME, }, + {} +}; + +static struct platform_driver qpnp_lbc_driver = { + .probe = qpnp_lbc_probe, + .remove = qpnp_lbc_remove, + .driver = { + .name = QPNP_CHARGER_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = qpnp_lbc_match_table, + }, +}; + +/* + * qpnp_lbc_init() - register platform driver for qpnp-chg + */ +static int __init qpnp_lbc_init(void) +{ + return platform_driver_register(&qpnp_lbc_driver); +} +module_init(qpnp_lbc_init); + +static void __exit qpnp_lbc_exit(void) +{ + platform_driver_unregister(&qpnp_lbc_driver); +} +module_exit(qpnp_lbc_exit); + +MODULE_DESCRIPTION("QPNP Linear charger driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" QPNP_CHARGER_DEV_NAME); -- GitLab From d90fd06ded8b02ccfe7e16580dc060bb829e7a51 Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Thu, 19 Apr 2018 12:13:40 +0530 Subject: [PATCH 1600/1834] ARM: dts: msm: Add vm-bms and linear charger nodes in pm8916 Add qpnp-vm-bms, qpnp-linear-charger node and interrupt align interrupt configurations for pmic 8916. Change-Id: Ia8c259ef1bc46c7325348e87dd84eb1ffc583e1b Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- arch/arm64/boot/dts/qcom/pm8916.dtsi | 115 +++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/pm8916.dtsi b/arch/arm64/boot/dts/qcom/pm8916.dtsi index 7d38151c9efc..af290809edd3 100644 --- a/arch/arm64/boot/dts/qcom/pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8916.dtsi @@ -169,6 +169,121 @@ qcom,pmic-revid = <&pm8916_revid>; }; + pm8916_chg: qcom,charger { + compatible = "qcom,qpnp-linear-charger"; + #address-cells = <1>; + #size-cells = <1>; + + qcom,vddmax-mv = <4200>; + qcom,vddsafe-mv = <4200>; + qcom,vinmin-mv = <4308>; + qcom,ibatsafe-ma = <1440>; + qcom,thermal-mitigation = <1440 720 630 0>; + qcom,cool-bat-decidegc = <100>; + qcom,warm-bat-decidegc = <450>; + qcom,cool-bat-mv = <4100>; + qcom,warm-bat-mv = <4100>; + qcom,ibatmax-warm-ma = <360>; + qcom,ibatmax-cool-ma = <360>; + qcom,batt-hot-percentage = <25>; + qcom,batt-cold-percentage = <80>; + qcom,tchg-mins = <232>; + qcom,resume-soc = <99>; + qcom,chg-vadc = <&pm8916_vadc>; + qcom,chg-adc_tm = <&pm8916_adc_tm>; + + status = "disabled"; + + qcom,chgr@1000 { + reg = <0x1000 0x100>; + interrupts = + <0x0 0x10 0x7 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x6 IRQ_TYPE_EDGE_RISING>, + <0x0 0x10 0x5 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x10 0x0 IRQ_TYPE_EDGE_FALLING>; + interrupt-names = "chg-done", + "chg-failed", + "fast-chg-on", + "vbat-det-lo"; + }; + + qcom,bat-if@1200 { + reg = <0x1200 0x100>; + interrupts = <0x0 0x12 0x1 IRQ_TYPE_EDGE_BOTH>, + <0x0 0x12 0x0 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "bat-temp-ok", + "batt-pres"; + }; + + qcom,usb-chgpth@1300 { + reg = <0x1300 0x100>; + interrupts = + <0 0x13 0x4 IRQ_TYPE_EDGE_BOTH>, + <0 0x13 0x2 IRQ_TYPE_EDGE_RISING>, + <0 0x13 0x1 IRQ_TYPE_EDGE_BOTH>; + interrupt-names = "usb-over-temp", + "chg-gone", + "usbin-valid"; + }; + + qcom,chg-misc@1600 { + reg = <0x1600 0x100>; + }; + }; + + pm8916_bms: qcom,vmbms { + compatible = "qcom,qpnp-vm-bms"; + #address-cells = <1>; + #size-cells = <1>; + status = "disabled"; + + qcom,v-cutoff-uv = <3400000>; + qcom,max-voltage-uv = <4200000>; + qcom,r-conn-mohm = <0>; + qcom,shutdown-soc-valid-limit = <100>; + qcom,low-soc-calculate-soc-threshold = <15>; + qcom,low-voltage-calculate-soc-ms = <1000>; + qcom,low-soc-calculate-soc-ms = <5000>; + qcom,calculate-soc-ms = <20000>; + qcom,volatge-soc-timeout-ms = <60000>; + qcom,low-voltage-threshold = <3450000>; + qcom,s3-ocv-tolerence-uv = <1200>; + qcom,s2-fifo-length = <5>; + qcom,low-soc-fifo-length = <2>; + qcom,bms-vadc = <&pm8916_vadc>; + qcom,bms-adc_tm = <&pm8916_adc_tm>; + qcom,pmic-revid = <&pm8916_revid>; + + qcom,force-s3-on-suspend; + qcom,force-s2-in-charging; + qcom,report-charger-eoc; + + qcom,batt-pres-status@1208 { + reg = <0x1208 0x1>; + }; + + qcom,qpnp-chg-pres@1008 { + reg = <0x1008 0x1>; + }; + + qcom,vm-bms@4000 { + reg = <0x4000 0x100>; + interrupts = <0x0 0x40 0x0 IRQ_TYPE_NONE>, + <0x0 0x40 0x1 IRQ_TYPE_NONE>, + <0x0 0x40 0x2 IRQ_TYPE_NONE>, + <0x0 0x40 0x3 IRQ_TYPE_NONE>, + <0x0 0x40 0x4 IRQ_TYPE_NONE>, + <0x0 0x40 0x5 IRQ_TYPE_NONE>; + + interrupt-names = "leave_cv", + "enter_cv", + "good_ocv", + "ocv_thr", + "fifo_update_done", + "fsm_state_change"; + }; + }; + pm8916_leds: qcom,leds@a100 { compatible = "qcom,leds-qpnp"; reg = <0xa100 0x100>; -- GitLab From ca42345027780928c7ce25b8715163ac8e0a046b Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Thu, 5 Apr 2018 16:43:30 +0530 Subject: [PATCH 1601/1834] power: smb1360: Add snapshot of smb1360 charger Initial snapshot of smb1360 driver is taken from msm-3.18 kernel version @ commit f8b6819d0432d6 ("msm: ipa: Fix to handle NULL pointer dereference") Add PMIC charger and fuel gauge drivers to msm-4.9. The power directory structure has changed in kernel version 4.9. Align smb1360 driver from msm-3.18 kernel with new directory structure. Since USB driver uses the extcon framework for communication, extcon support and USB power supply support is added. Change-Id: Iaef0ef4ac9a48b09dde8bd9067ed0495f20e00d8 Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- .../{ => supply/qcom}/smb1360-charger-fg.txt | 0 drivers/power/supply/qcom/Kconfig | 11 + drivers/power/supply/qcom/Makefile | 1 + .../power/supply/qcom/smb1360-charger-fg.c | 5372 +++++++++++++++++ 4 files changed, 5384 insertions(+) rename Documentation/devicetree/bindings/power/{ => supply/qcom}/smb1360-charger-fg.txt (100%) create mode 100644 drivers/power/supply/qcom/smb1360-charger-fg.c diff --git a/Documentation/devicetree/bindings/power/smb1360-charger-fg.txt b/Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt similarity index 100% rename from Documentation/devicetree/bindings/power/smb1360-charger-fg.txt rename to Documentation/devicetree/bindings/power/supply/qcom/smb1360-charger-fg.txt diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 4746bec77170..1c8f1166a7fa 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -29,6 +29,17 @@ config SMB135X_CHARGER The driver reports the charger status via the power supply framework. A charger status change triggers an IRQ via the device STAT pin. +config SMB1360_CHARGER_FG + tristate "SMB1360 Charger and Fuel Gauge" + depends on I2C + help + Say Y to include support for SMB1360 Charger and Fuel Gauge. + SMB1360 is a single path switching mode charger capable of charging + the battery with 1.5Amps of current. It supports a fuel gauge which + uses voltage and coloumb counting for state of charge reporting. + The driver reports the status via the power supply framework. + A status change triggers an IRQ via the device STAT pin. + config SMB1355_SLAVE_CHARGER tristate "SMB1355 Slave Battery Charger" depends on MFD_I2C_PMIC diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index c10697e69086..da20d9364f46 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_QPNP_FG) += qpnp-fg.o obj-$(CONFIG_QPNP_FG_GEN3) += qpnp-fg-gen3.o fg-memif.o fg-util.o obj-$(CONFIG_QPNP_SMBCHARGER) += qpnp-smbcharger.o pmic-voter.o obj-$(CONFIG_SMB135X_CHARGER) += smb135x-charger.o pmic-voter.o +obj-$(CONFIG_SMB1360_CHARGER_FG) += smb1360-charger-fg.o obj-$(CONFIG_SMB1355_SLAVE_CHARGER) += smb1355-charger.o pmic-voter.o obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o diff --git a/drivers/power/supply/qcom/smb1360-charger-fg.c b/drivers/power/supply/qcom/smb1360-charger-fg.c new file mode 100644 index 000000000000..ed9c6101685a --- /dev/null +++ b/drivers/power/supply/qcom/smb1360-charger-fg.c @@ -0,0 +1,5372 @@ +/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define pr_fmt(fmt) "SMB:%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define _SMB1360_MASK(BITS, POS) \ + ((unsigned char)(((1 << (BITS)) - 1) << (POS))) +#define SMB1360_MASK(LEFT_BIT_POS, RIGHT_BIT_POS) \ + _SMB1360_MASK((LEFT_BIT_POS) - (RIGHT_BIT_POS) + 1, \ + (RIGHT_BIT_POS)) + +/* Charger Registers */ +#define CFG_BATT_CHG_REG 0x00 +#define CHG_ITERM_MASK SMB1360_MASK(2, 0) +#define CHG_ITERM_25MA 0x0 +#define CHG_ITERM_200MA 0x7 +#define RECHG_MV_MASK SMB1360_MASK(6, 5) +#define RECHG_MV_SHIFT 5 +#define OTG_CURRENT_MASK SMB1360_MASK(4, 3) +#define OTG_CURRENT_SHIFT 3 + +#define CFG_BATT_CHG_ICL_REG 0x05 +#define AC_INPUT_ICL_PIN_BIT BIT(7) +#define AC_INPUT_PIN_HIGH_BIT BIT(6) +#define RESET_STATE_USB_500 BIT(5) +#define INPUT_CURR_LIM_MASK SMB1360_MASK(3, 0) +#define INPUT_CURR_LIM_300MA 0x0 + +#define CFG_GLITCH_FLT_REG 0x06 +#define AICL_ENABLED_BIT BIT(0) +#define INPUT_UV_GLITCH_FLT_20MS_BIT BIT(7) + +#define CFG_CHG_MISC_REG 0x7 +#define CHG_EN_BY_PIN_BIT BIT(7) +#define CHG_EN_ACTIVE_LOW_BIT BIT(6) +#define PRE_TO_FAST_REQ_CMD_BIT BIT(5) +#define CFG_BAT_OV_ENDS_CHG_CYC BIT(4) +#define CHG_CURR_TERM_DIS_BIT BIT(3) +#define CFG_AUTO_RECHG_DIS_BIT BIT(2) +#define CFG_CHG_INHIBIT_EN_BIT BIT(0) + +#define CFG_CHG_FUNC_CTRL_REG 0x08 +#define CHG_RECHG_THRESH_FG_SRC_BIT BIT(1) + +#define CFG_STAT_CTRL_REG 0x09 +#define CHG_STAT_IRQ_ONLY_BIT BIT(4) +#define CHG_TEMP_CHG_ERR_BLINK_BIT BIT(3) +#define CHG_STAT_ACTIVE_HIGH_BIT BIT(1) +#define CHG_STAT_DISABLE_BIT BIT(0) + +#define CFG_SFY_TIMER_CTRL_REG 0x0A +#define SAFETY_TIME_DISABLE_BIT BIT(5) +#define SAFETY_TIME_MINUTES_SHIFT 2 +#define SAFETY_TIME_MINUTES_MASK SMB1360_MASK(3, 2) + +#define CFG_BATT_MISSING_REG 0x0D +#define BATT_MISSING_SRC_THERM_BIT BIT(1) + +#define CFG_FG_BATT_CTRL_REG 0x0E +#define CFG_FG_OTP_BACK_UP_ENABLE BIT(7) +#define BATT_ID_ENABLED_BIT BIT(5) +#define CHG_BATT_ID_FAIL BIT(4) +#define BATT_ID_FAIL_SELECT_PROFILE BIT(3) +#define BATT_PROFILE_SELECT_MASK SMB1360_MASK(3, 0) +#define BATT_PROFILEA_MASK 0x0 +#define BATT_PROFILEB_MASK 0xF + +#define IRQ_CFG_REG 0x0F +#define IRQ_BAT_HOT_COLD_HARD_BIT BIT(7) +#define IRQ_BAT_HOT_COLD_SOFT_BIT BIT(6) +#define IRQ_DCIN_UV_BIT BIT(2) +#define IRQ_AICL_DONE_BIT BIT(1) +#define IRQ_INTERNAL_TEMPERATURE_BIT BIT(0) + +#define IRQ2_CFG_REG 0x10 +#define IRQ2_SAFETY_TIMER_BIT BIT(7) +#define IRQ2_CHG_ERR_BIT BIT(6) +#define IRQ2_CHG_PHASE_CHANGE_BIT BIT(4) +#define IRQ2_POWER_OK_BIT BIT(2) +#define IRQ2_BATT_MISSING_BIT BIT(1) +#define IRQ2_VBAT_LOW_BIT BIT(0) + +#define IRQ3_CFG_REG 0x11 +#define IRQ3_FG_ACCESS_OK_BIT BIT(6) +#define IRQ3_SOC_CHANGE_BIT BIT(4) +#define IRQ3_SOC_MIN_BIT BIT(3) +#define IRQ3_SOC_MAX_BIT BIT(2) +#define IRQ3_SOC_EMPTY_BIT BIT(1) +#define IRQ3_SOC_FULL_BIT BIT(0) + +#define CHG_CURRENT_REG 0x13 +#define FASTCHG_CURR_MASK SMB1360_MASK(4, 2) +#define FASTCHG_CURR_SHIFT 2 + +#define CHG_CMP_CFG 0x14 +#define JEITA_COMP_CURR_MASK SMB1360_MASK(3, 0) +#define JEITA_COMP_EN_MASK SMB1360_MASK(7, 4) +#define JEITA_COMP_EN_SHIFT 4 +#define JEITA_COMP_EN_BIT SMB1360_MASK(7, 4) +#define BATT_CHG_FLT_VTG_REG 0x15 +#define VFLOAT_MASK SMB1360_MASK(6, 0) +#define CFG_FVC_REG 0x16 +#define FLT_VTG_COMP_MASK SMB1360_MASK(6, 0) + +#define SHDN_CTRL_REG 0x1A +#define SHDN_CMD_USE_BIT BIT(1) +#define SHDN_CMD_POLARITY_BIT BIT(2) + +#define CURRENT_GAIN_LSB_REG 0x1D +#define CURRENT_GAIN_MSB_REG 0x1E + +/* Command Registers */ +#define CMD_I2C_REG 0x40 +#define ALLOW_VOLATILE_BIT BIT(6) +#define FG_ACCESS_ENABLED_BIT BIT(5) +#define FG_RESET_BIT BIT(4) +#define CYCLE_STRETCH_CLEAR_BIT BIT(3) + +#define CMD_IL_REG 0x41 +#define USB_CTRL_MASK SMB1360_MASK(1, 0) +#define USB_100_BIT 0x01 +#define USB_500_BIT 0x00 +#define USB_AC_BIT 0x02 +#define SHDN_CMD_BIT BIT(7) + +#define CMD_CHG_REG 0x42 +#define CMD_CHG_EN BIT(1) +#define CMD_OTG_EN_BIT BIT(0) + +/* Status Registers */ +#define STATUS_1_REG 0x48 +#define AICL_CURRENT_STATUS_MASK SMB1360_MASK(6, 0) +#define AICL_LIMIT_1500MA 0xF + +#define STATUS_3_REG 0x4B +#define CHG_HOLD_OFF_BIT BIT(3) +#define CHG_TYPE_MASK SMB1360_MASK(2, 1) +#define CHG_TYPE_SHIFT 1 +#define BATT_NOT_CHG_VAL 0x0 +#define BATT_PRE_CHG_VAL 0x1 +#define BATT_FAST_CHG_VAL 0x2 +#define BATT_TAPER_CHG_VAL 0x3 +#define CHG_EN_BIT BIT(0) + +#define STATUS_4_REG 0x4C +#define CYCLE_STRETCH_ACTIVE_BIT BIT(5) + +#define REVISION_CTRL_REG 0x4F +#define DEVICE_REV_MASK SMB1360_MASK(3, 0) + +/* IRQ Status Registers */ +#define IRQ_A_REG 0x50 +#define IRQ_A_HOT_HARD_BIT BIT(6) +#define IRQ_A_COLD_HARD_BIT BIT(4) +#define IRQ_A_HOT_SOFT_BIT BIT(2) +#define IRQ_A_COLD_SOFT_BIT BIT(0) + +#define IRQ_B_REG 0x51 +#define IRQ_B_BATT_TERMINAL_BIT BIT(6) +#define IRQ_B_BATT_MISSING_BIT BIT(4) + +#define IRQ_C_REG 0x52 +#define IRQ_C_CHG_TERM BIT(0) + +#define IRQ_D_REG 0x53 +#define IRQ_E_REG 0x54 +#define IRQ_E_USBIN_UV_BIT BIT(0) + +#define IRQ_F_REG 0x55 + +#define IRQ_G_REG 0x56 + +#define IRQ_H_REG 0x57 +#define IRQ_I_REG 0x58 +#define FG_ACCESS_ALLOWED_BIT BIT(0) +#define BATT_ID_RESULT_BIT SMB1360_MASK(6, 4) +#define BATT_ID_SHIFT 4 + +/* FG registers - IRQ config register */ +#define SOC_MAX_REG 0x24 +#define SOC_MIN_REG 0x25 +#define VTG_EMPTY_REG 0x26 +#define SOC_DELTA_REG 0x28 +#define JEITA_SOFT_COLD_REG 0x29 +#define JEITA_SOFT_HOT_REG 0x2A +#define VTG_MIN_REG 0x2B + +/* FG SHADOW registers */ +#define SHDW_FG_ESR_ACTUAL 0x20 +#define SHDW_FG_BATT_STATUS 0x60 +#define BATTERY_PROFILE_BIT BIT(0) + +#define SHDW_FG_MSYS_SOC 0x61 +#define SHDW_FG_CAPACITY 0x62 +#define SHDW_FG_VTG_NOW 0x69 +#define SHDW_FG_CURR_NOW 0x6B +#define SHDW_FG_BATT_TEMP 0x6D + +#define VOLTAGE_PREDICTED_REG 0x80 +#define CC_TO_SOC_COEFF 0xBA +#define NOMINAL_CAPACITY_REG 0xBC +#define ACTUAL_CAPACITY_REG 0xBE +#define FG_AUTO_RECHARGE_SOC 0xD2 +#define FG_SYS_CUTOFF_V_REG 0xD3 +#define FG_CC_TO_CV_V_REG 0xD5 +#define FG_ITERM_REG 0xD9 +#define FG_THERM_C1_COEFF_REG 0xDB +#define FG_IBATT_STANDBY_REG 0xCF + +#define FG_I2C_CFG_MASK SMB1360_MASK(2, 1) +#define FG_CFG_I2C_ADDR 0x2 +#define FG_PROFILE_A_ADDR 0x4 +#define FG_PROFILE_B_ADDR 0x6 + +/* Constants */ +#define CURRENT_100_MA 100 +#define CURRENT_500_MA 500 +#define MAX_8_BITS 255 +#define JEITA_WORK_MS 3000 + +#define FG_RESET_THRESHOLD_MV 15 +#define SMB1360_REV_1 0x01 + +#define SMB1360_POWERON_DELAY_MS 2000 +#define SMB1360_FG_RESET_DELAY_MS 1500 + +enum { + WRKRND_FG_CONFIG_FAIL = BIT(0), + WRKRND_BATT_DET_FAIL = BIT(1), + WRKRND_USB100_FAIL = BIT(2), + WRKRND_HARD_JEITA = BIT(3), +}; + +enum { + USER = BIT(0), +}; + +enum { + PARALLEL_USER = BIT(0), + PARALLEL_CURRENT = BIT(1), + PARALLEL_JEITA_SOFT = BIT(2), + PARALLEL_JEITA_HARD = BIT(3), + PARALLEL_EOC = BIT(4), +}; + +enum fg_i2c_access_type { + FG_ACCESS_CFG = 0x1, + FG_ACCESS_PROFILE_A = 0x2, + FG_ACCESS_PROFILE_B = 0x3 +}; + +enum { + BATTERY_PROFILE_A, + BATTERY_PROFILE_B, + BATTERY_PROFILE_MAX, +}; + +static int otg_curr_ma[] = {350, 550, 950, 1500}; + +struct otp_backup_pool { + u8 reg_start; + u8 reg_end; + u8 start_now; + u16 alg_bitmap; + bool initialized; + struct mutex lock; +}; + +enum otp_backup_alg { + OTP_BACKUP_NOT_USE = 0, + OTP_BACKUP_FG_USE, + OTP_BACKUP_PROF_A_USE, + OTP_BACKUP_PROF_B_USE, +}; + +struct smb1360_otg_regulator { + struct regulator_desc rdesc; + struct regulator_dev *rdev; +}; + +enum wakeup_src { + WAKEUP_SRC_FG_ACCESS = 0, + WAKEUP_SRC_JEITA_SOFT, + WAKEUP_SRC_PARALLEL, + WAKEUP_SRC_MIN_SOC, + WAKEUP_SRC_EMPTY_SOC, + WAKEUP_SRC_JEITA_HYSTERSIS, + WAKEUP_SRC_MAX, +}; +#define WAKEUP_SRC_MASK (~(~0 << WAKEUP_SRC_MAX)) + +struct smb1360_wakeup_source { + struct wakeup_source source; + unsigned long enabled_bitmap; + spinlock_t ws_lock; +}; + +static const unsigned int smb1360_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + +struct smb1360_chip { + struct i2c_client *client; + struct device *dev; + u8 revision; + u8 soft_hot_rt_stat; + u8 soft_cold_rt_stat; + struct delayed_work jeita_work; + struct delayed_work delayed_init_work; + unsigned short default_i2c_addr; + unsigned short fg_i2c_addr; + bool pulsed_irq; + struct completion fg_mem_access_granted; + + /* wakeup source */ + struct smb1360_wakeup_source smb1360_ws; + + /* configuration data - charger */ + int fake_battery_soc; + bool batt_id_disabled; + bool charging_disabled; + bool recharge_disabled; + bool chg_inhibit_disabled; + bool iterm_disabled; + bool shdn_after_pwroff; + bool config_hard_thresholds; + bool soft_jeita_supported; + bool ov_ends_chg_cycle_disabled; + int iterm_ma; + int vfloat_mv; + int safety_time; + int resume_delta_mv; + u32 default_batt_profile; + unsigned int thermal_levels; + unsigned int therm_lvl_sel; + unsigned int *thermal_mitigation; + int otg_batt_curr_limit; + bool min_icl_usb100; + int cold_bat_decidegc; + int hot_bat_decidegc; + int cool_bat_decidegc; + int warm_bat_decidegc; + int cool_bat_mv; + int warm_bat_mv; + int cool_bat_ma; + int warm_bat_ma; + int soft_cold_thresh; + int soft_hot_thresh; + + /* parallel-chg params */ + int fastchg_current; + int parallel_chg_disable_status; + int max_parallel_chg_current; + bool parallel_charging; + + /* configuration data - fg */ + int soc_max; + int soc_min; + int delta_soc; + int voltage_min_mv; + int voltage_empty_mv; + int batt_capacity_mah; + int cc_soc_coeff; + int v_cutoff_mv; + int fg_iterm_ma; + int fg_ibatt_standby_ma; + int fg_thermistor_c1_coeff; + int fg_cc_to_cv_mv; + int fg_auto_recharge_soc; + bool empty_soc_disabled; + int fg_reset_threshold_mv; + bool fg_reset_at_pon; + bool rsense_10mohm; + bool otg_fet_present; + bool fet_gain_enabled; + int otg_fet_enable_gpio; + + /* status tracking */ + int voltage_now; + int current_now; + int resistance_now; + int temp_now; + int soc_now; + int fcc_mah; + bool usb_present; + bool batt_present; + bool batt_hot; + bool batt_cold; + bool batt_warm; + bool batt_cool; + bool batt_full; + bool resume_completed; + bool irq_waiting; + bool irq_disabled; + bool empty_soc; + bool awake_min_soc; + int workaround_flags; + u8 irq_cfg_mask[3]; + int usb_psy_ma; + int charging_disabled_status; + u32 connected_rid; + u32 profile_rid[BATTERY_PROFILE_MAX]; + + u32 peek_poke_address; + u32 fg_access_type; + u32 fg_peek_poke_address; + int skip_writes; + int skip_reads; + enum power_supply_type usb_supply_type; + struct dentry *debug_root; + + struct qpnp_vadc_chip *vadc_dev; + struct power_supply *parallel_psy; + struct power_supply_desc parallel_psy_d; + struct power_supply *usb_psy; + struct power_supply_desc usb_psy_d; + struct power_supply *batt_psy; + struct power_supply_desc batt_psy_d; + struct smb1360_otg_regulator otg_vreg; + struct mutex irq_complete; + struct mutex charging_disable_lock; + struct mutex current_change_lock; + struct mutex read_write_lock; + struct mutex parallel_chg_lock; + struct work_struct parallel_work; + struct mutex otp_gain_lock; + struct mutex fg_access_request_lock; + struct otp_backup_pool otp_backup; + u8 current_gain_otp_reg; + bool otp_hard_jeita_config; + int otp_cold_bat_decidegc; + int otp_hot_bat_decidegc; + u8 hard_jeita_otp_reg; + struct work_struct jeita_hysteresis_work; + int cold_hysteresis; + int hot_hysteresis; + struct extcon_dev *extcon; +}; + +static int chg_time[] = { + 192, + 384, + 768, + 1536, +}; + +static int input_current_limit[] = { + 300, 400, 450, 500, 600, 700, 800, 850, 900, + 950, 1000, 1100, 1200, 1300, 1400, 1500, +}; + +static int fastchg_current[] = { + 450, 600, 750, 900, 1050, 1200, 1350, 1500, +}; + +static void smb1360_stay_awake(struct smb1360_wakeup_source *source, + enum wakeup_src wk_src) +{ + unsigned long flags; + + spin_lock_irqsave(&source->ws_lock, flags); + + if (!__test_and_set_bit(wk_src, &source->enabled_bitmap)) { + __pm_stay_awake(&source->source); + pr_debug("enabled source %s, wakeup_src %d\n", + source->source.name, wk_src); + } + spin_unlock_irqrestore(&source->ws_lock, flags); +} + +static void smb1360_relax(struct smb1360_wakeup_source *source, + enum wakeup_src wk_src) +{ + unsigned long flags; + + spin_lock_irqsave(&source->ws_lock, flags); + if (__test_and_clear_bit(wk_src, &source->enabled_bitmap) && + !(source->enabled_bitmap & WAKEUP_SRC_MASK)) { + __pm_relax(&source->source); + pr_debug("disabled source %s\n", source->source.name); + } + spin_unlock_irqrestore(&source->ws_lock, flags); + + pr_debug("relax source %s, wakeup_src %d\n", + source->source.name, wk_src); +} + +static void smb1360_wakeup_src_init(struct smb1360_chip *chip) +{ + spin_lock_init(&chip->smb1360_ws.ws_lock); + wakeup_source_init(&chip->smb1360_ws.source, "smb1360"); +} + +static int is_between(int value, int left, int right) +{ + if (left >= right && left >= value && value >= right) + return 1; + if (left <= right && left <= value && value <= right) + return 1; + + return 0; +} + +static int bound(int val, int min, int max) +{ + if (val < min) + return min; + if (val > max) + return max; + + return val; +} + +static int __smb1360_read(struct smb1360_chip *chip, int reg, + u8 *val) +{ + s32 ret; + + ret = i2c_smbus_read_byte_data(chip->client, reg); + if (ret < 0) { + dev_err(chip->dev, + "i2c read fail: can't read from %02x: %d\n", reg, ret); + return ret; + } + *val = ret; + pr_debug("Reading 0x%02x=0x%02x\n", reg, *val); + + return 0; +} + +static int __smb1360_write(struct smb1360_chip *chip, int reg, + u8 val) +{ + s32 ret; + + ret = i2c_smbus_write_byte_data(chip->client, reg, val); + if (ret < 0) { + dev_err(chip->dev, + "i2c write fail: can't write %02x to %02x: %d\n", + val, reg, ret); + return ret; + } + pr_debug("Writing 0x%02x=0x%02x\n", reg, val); + return 0; +} + +static int smb1360_read(struct smb1360_chip *chip, int reg, + u8 *val) +{ + int rc; + + if (chip->skip_reads) { + *val = 0; + return 0; + } + mutex_lock(&chip->read_write_lock); + rc = __smb1360_read(chip, reg, val); + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_write(struct smb1360_chip *chip, int reg, + u8 val) +{ + int rc; + + if (chip->skip_writes) + return 0; + + mutex_lock(&chip->read_write_lock); + rc = __smb1360_write(chip, reg, val); + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_fg_read(struct smb1360_chip *chip, int reg, + u8 *val) +{ + int rc; + + if (chip->skip_reads) { + *val = 0; + return 0; + } + + mutex_lock(&chip->read_write_lock); + chip->client->addr = chip->fg_i2c_addr; + rc = __smb1360_read(chip, reg, val); + chip->client->addr = chip->default_i2c_addr; + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_fg_write(struct smb1360_chip *chip, int reg, + u8 val) +{ + int rc; + + if (chip->skip_writes) + return 0; + + mutex_lock(&chip->read_write_lock); + chip->client->addr = chip->fg_i2c_addr; + rc = __smb1360_write(chip, reg, val); + chip->client->addr = chip->default_i2c_addr; + mutex_unlock(&chip->read_write_lock); + + return rc; +} + +static int smb1360_read_bytes(struct smb1360_chip *chip, int reg, + u8 *val, u8 bytes) +{ + s32 rc; + + if (chip->skip_reads) { + *val = 0; + return 0; + } + + mutex_lock(&chip->read_write_lock); + rc = i2c_smbus_read_i2c_block_data(chip->client, reg, bytes, val); + if (rc < 0) + dev_err(chip->dev, + "i2c read fail: can't read %d bytes from %02x: %d\n", + bytes, reg, rc); + mutex_unlock(&chip->read_write_lock); + + return (rc < 0) ? rc : 0; +} + +static int smb1360_write_bytes(struct smb1360_chip *chip, int reg, + u8 *val, u8 bytes) +{ + s32 rc; + + if (chip->skip_writes) { + *val = 0; + return 0; + } + + mutex_lock(&chip->read_write_lock); + rc = i2c_smbus_write_i2c_block_data(chip->client, reg, bytes, val); + if (rc < 0) + dev_err(chip->dev, + "i2c write fail: can't read %d bytes from %02x: %d\n", + bytes, reg, rc); + mutex_unlock(&chip->read_write_lock); + + return (rc < 0) ? rc : 0; +} + +static int smb1360_masked_write(struct smb1360_chip *chip, int reg, + u8 mask, u8 val) +{ + s32 rc; + u8 temp; + + if (chip->skip_writes || chip->skip_reads) + return 0; + + mutex_lock(&chip->read_write_lock); + rc = __smb1360_read(chip, reg, &temp); + if (rc < 0) { + dev_err(chip->dev, "read failed: reg=%03X, rc=%d\n", reg, rc); + goto out; + } + temp &= ~mask; + temp |= val & mask; + rc = __smb1360_write(chip, reg, temp); + if (rc < 0) { + dev_err(chip->dev, + "write failed: reg=%03X, rc=%d\n", reg, rc); + } +out: + mutex_unlock(&chip->read_write_lock); + return rc; +} + +static int smb1360_select_fg_i2c_address(struct smb1360_chip *chip) +{ + unsigned short addr = chip->default_i2c_addr << 0x1; + + switch (chip->fg_access_type) { + case FG_ACCESS_CFG: + addr = (addr & ~FG_I2C_CFG_MASK) | FG_CFG_I2C_ADDR; + break; + case FG_ACCESS_PROFILE_A: + addr = (addr & ~FG_I2C_CFG_MASK) | FG_PROFILE_A_ADDR; + break; + case FG_ACCESS_PROFILE_B: + addr = (addr & ~FG_I2C_CFG_MASK) | FG_PROFILE_B_ADDR; + break; + default: + pr_err("Invalid FG access type=%d\n", chip->fg_access_type); + return -EINVAL; + } + + chip->fg_i2c_addr = addr >> 0x1; + pr_debug("FG_access_type=%d fg_i2c_addr=%x\n", chip->fg_access_type, + chip->fg_i2c_addr); + + return 0; +} + +#define EXPONENT_MASK 0xF800 +#define MANTISSA_MASK 0x3FF +#define SIGN_MASK 0x400 +#define EXPONENT_SHIFT 11 +#define SIGN_SHIFT 10 +#define MICRO_UNIT 1000000ULL +static int64_t float_decode(u16 reg) +{ + int64_t final_val, exponent_val, mantissa_val; + int exponent, mantissa, n; + bool sign; + + exponent = (reg & EXPONENT_MASK) >> EXPONENT_SHIFT; + mantissa = (reg & MANTISSA_MASK); + sign = !!(reg & SIGN_MASK); + + pr_debug("exponent=%d mantissa=%d sign=%d\n", exponent, mantissa, sign); + + mantissa_val = mantissa * MICRO_UNIT; + + n = exponent - 15; + if (n < 0) + exponent_val = MICRO_UNIT >> -n; + else + exponent_val = MICRO_UNIT << n; + + n = n - 10; + if (n < 0) + mantissa_val >>= -n; + else + mantissa_val <<= n; + + final_val = exponent_val + mantissa_val; + + if (sign) + final_val *= -1; + + return final_val; +} + +#define MAX_MANTISSA (1023 * 1000000ULL) +static unsigned int float_encode(int64_t float_val) +{ + int exponent = 0, sign = 0; + unsigned int final_val = 0; + + if (float_val == 0) + return 0; + + if (float_val < 0) { + sign = 1; + float_val = -float_val; + } + + /* Reduce large mantissa until it fits into 10 bit */ + while (float_val >= MAX_MANTISSA) { + exponent++; + float_val >>= 1; + } + + /* Increase small mantissa to improve precision */ + while (float_val < MAX_MANTISSA && exponent > -25) { + exponent--; + float_val <<= 1; + } + + exponent = exponent + 25; + + /* Convert mantissa from micro-units to units */ + float_val = div_s64((float_val + MICRO_UNIT), (int)MICRO_UNIT); + + if (float_val == 1024) { + exponent--; + float_val <<= 1; + } + + float_val -= 1024; + + /* Ensure that resulting number is within range */ + if (float_val > MANTISSA_MASK) + float_val = MANTISSA_MASK; + + /* Convert to 5 bit exponent, 11 bit mantissa */ + final_val = (float_val & MANTISSA_MASK) | (sign << SIGN_SHIFT) | + ((exponent << EXPONENT_SHIFT) & EXPONENT_MASK); + + return final_val; +} + +/* FG reset could only be done after FG access being granted */ +static int smb1360_force_fg_reset(struct smb1360_chip *chip) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, + FG_RESET_BIT); + if (rc) { + pr_err("Couldn't reset FG rc=%d\n", rc); + return rc; + } + + msleep(SMB1360_FG_RESET_DELAY_MS); + + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_RESET_BIT, 0); + if (rc) + pr_err("Couldn't un-reset FG rc=%d\n", rc); + + return rc; +} + +/* + * Requesting FG access relys on the FG_ACCESS_ALLOWED IRQ. + * This function can only be called after interrupt handler + * being installed successfully. + */ +#define SMB1360_FG_ACCESS_TIMEOUT_MS 5000 +#define SMB1360_FG_ACCESS_RETRY_COUNT 3 +static int smb1360_enable_fg_access(struct smb1360_chip *chip) +{ + int rc = 0; + u8 reg, retry = SMB1360_FG_ACCESS_RETRY_COUNT; + + pr_debug("request FG memory access\n"); + /* + * read the ACCESS_ALLOW status bit firstly to + * check if the access was granted before + */ + mutex_lock(&chip->fg_access_request_lock); + smb1360_stay_awake(&chip->smb1360_ws, WAKEUP_SRC_FG_ACCESS); + rc = smb1360_read(chip, IRQ_I_REG, ®); + if (rc) { + pr_err("Couldn't read IRQ_I_REG, rc=%d\n", rc); + goto bail_i2c; + } else if (reg & FG_ACCESS_ALLOWED_BIT) { + pr_debug("FG access was granted\n"); + goto bail_i2c; + } + + /* request FG access */ + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, + FG_ACCESS_ENABLED_BIT); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + goto bail_i2c; + } + + while (retry--) { + rc = wait_for_completion_interruptible_timeout( + &chip->fg_mem_access_granted, + msecs_to_jiffies(SMB1360_FG_ACCESS_TIMEOUT_MS)); + if (rc <= 0) + pr_debug("FG access timeout, retry: %d\n", retry); + else + break; + } + if (rc == 0) /* timed out */ + rc = -ETIMEDOUT; + else if (rc > 0) /* completed */ + rc = 0; + + /* Clear the FG access bit if request failed */ + if (rc < 0) { + rc = smb1360_masked_write(chip, CMD_I2C_REG, + FG_ACCESS_ENABLED_BIT, 0); + if (rc) + pr_err("Couldn't disable FG access rc=%d\n", rc); + } + +bail_i2c: + smb1360_relax(&chip->smb1360_ws, WAKEUP_SRC_FG_ACCESS); + mutex_unlock(&chip->fg_access_request_lock); + return rc; +} + +static inline bool is_device_suspended(struct smb1360_chip *chip) +{ + return !chip->resume_completed; +} + +static int smb1360_disable_fg_access(struct smb1360_chip *chip) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_I2C_REG, FG_ACCESS_ENABLED_BIT, 0); + if (rc) + pr_err("Couldn't disable FG access rc=%d\n", rc); + + init_completion(&chip->fg_mem_access_granted); + + return rc; +} + +static int smb1360_enable_volatile_writes(struct smb1360_chip *chip) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_I2C_REG, + ALLOW_VOLATILE_BIT, ALLOW_VOLATILE_BIT); + if (rc < 0) + dev_err(chip->dev, + "Couldn't set VOLATILE_W_PERM_BIT rc=%d\n", rc); + + return rc; +} + +static void smb1360_otp_backup_pool_init(struct smb1360_chip *chip) +{ + struct otp_backup_pool *pool = &chip->otp_backup; + + pool->reg_start = 0xE0; + pool->reg_end = 0xEF; + pool->start_now = pool->reg_start; + mutex_init(&pool->lock); +} + +static int smb1360_alloc_otp_backup_register(struct smb1360_chip *chip, + u8 size, int usage) +{ + int rc = 0, i; + u8 inv_pos; + struct otp_backup_pool *pool = &chip->otp_backup; + + if (size % 2) { + pr_err("Must be allocated with pairs\n"); + return -EINVAL; + } + + mutex_lock(&pool->lock); + if (pool->start_now + size > pool->reg_end) { + pr_err("Allocation fail: start = 0x%x, size = %d\n", + pool->start_now, size); + mutex_unlock(&pool->lock); + return -EBUSY; + } + rc = pool->start_now; + inv_pos = pool->reg_end - pool->start_now + 1; + for (i = 0; i < size; i = i + 2) { + inv_pos -= (i ? 2 : 0); + pool->alg_bitmap |= usage << (inv_pos - 2); + } + pr_debug("Allocation success, start = 0x%x, size = %d, alg_bitmap = 0x%x\n", + rc, size, pool->alg_bitmap); + pool->start_now += size; + mutex_unlock(&pool->lock); + + return rc; +} + +#define OTP_BACKUP_WA_ALG_1 0xF0 +#define OTP_BACKUP_WA_ALG_2 0xF1 +static int smb1360_otp_backup_alg_update(struct smb1360_chip *chip) +{ + int rc = 0; + struct otp_backup_pool *pool = &chip->otp_backup; + + mutex_lock(&pool->lock); + rc = smb1360_fg_write(chip, OTP_BACKUP_WA_ALG_1, + (u8)(pool->alg_bitmap >> 8)); + rc |= smb1360_fg_write(chip, OTP_BACKUP_WA_ALG_2, + (u8)(pool->alg_bitmap)); + if (rc) + pr_err("Write FG address F0/F1 failed, rc = %d\n", rc); + mutex_unlock(&pool->lock); + + return rc; +} + +#define TRIM_1C_REG 0x1C +#define CHECK_USB100_GOOD_BIT BIT(6) +static bool is_usb100_broken(struct smb1360_chip *chip) +{ + int rc; + u8 reg; + + rc = smb1360_read(chip, TRIM_1C_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read trim 1C reg rc = %d\n", rc); + return rc; + } + return !!(reg & CHECK_USB100_GOOD_BIT); +} + +static int read_revision(struct smb1360_chip *chip, u8 *revision) +{ + int rc; + + *revision = 0; + rc = smb1360_read(chip, REVISION_CTRL_REG, revision); + if (rc) + dev_err(chip->dev, "Couldn't read REVISION_CTRL_REG rc=%d", rc); + + *revision &= DEVICE_REV_MASK; + + return rc; +} + +#define MIN_FLOAT_MV 3460 +#define MAX_FLOAT_MV 4730 +#define VFLOAT_STEP_MV 10 +static int smb1360_float_voltage_set(struct smb1360_chip *chip, int vfloat_mv) +{ + u8 temp; + + if ((vfloat_mv < MIN_FLOAT_MV) || (vfloat_mv > MAX_FLOAT_MV)) { + dev_err(chip->dev, "bad float voltage mv =%d asked to set\n", + vfloat_mv); + return -EINVAL; + } + + temp = (vfloat_mv - MIN_FLOAT_MV) / VFLOAT_STEP_MV; + + return smb1360_masked_write(chip, BATT_CHG_FLT_VTG_REG, + VFLOAT_MASK, temp); +} + +#define MIN_RECHG_MV 50 +#define MAX_RECHG_MV 300 +static int smb1360_recharge_threshold_set(struct smb1360_chip *chip, + int resume_mv) +{ + u8 temp; + + if ((resume_mv < MIN_RECHG_MV) || (resume_mv > MAX_RECHG_MV)) { + dev_err(chip->dev, "bad rechg_thrsh =%d asked to set\n", + resume_mv); + return -EINVAL; + } + + temp = resume_mv / 100; + + return smb1360_masked_write(chip, CFG_BATT_CHG_REG, + RECHG_MV_MASK, temp << RECHG_MV_SHIFT); +} + +static int __smb1360_charging_disable(struct smb1360_chip *chip, bool disable) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_CHG_REG, + CMD_CHG_EN, disable ? 0 : CMD_CHG_EN); + if (rc < 0) + pr_err("Couldn't set CHG_ENABLE_BIT disable=%d rc = %d\n", + disable, rc); + else + pr_debug("CHG_EN status=%d\n", !disable); + + return rc; +} + +static int smb1360_charging_disable(struct smb1360_chip *chip, int reason, + int disable) +{ + int rc = 0; + int disabled; + + mutex_lock(&chip->charging_disable_lock); + + disabled = chip->charging_disabled_status; + + pr_debug("reason=%d requested_disable=%d disabled_status=%d\n", + reason, disable, disabled); + + if (disable == true) + disabled |= reason; + else + disabled &= ~reason; + + if (disabled) + rc = __smb1360_charging_disable(chip, true); + else + rc = __smb1360_charging_disable(chip, false); + + if (rc) + pr_err("Couldn't disable charging for reason=%d rc=%d\n", + rc, reason); + else + chip->charging_disabled_status = disabled; + + mutex_unlock(&chip->charging_disable_lock); + + return rc; +} + +static int smb1360_soft_jeita_comp_enable(struct smb1360_chip *chip, + bool enable) +{ + int rc = 0; + + rc = smb1360_masked_write(chip, CHG_CMP_CFG, JEITA_COMP_EN_MASK, + enable ? JEITA_COMP_EN_BIT : 0); + if (rc) + pr_err("Couldn't %s JEITA compensation\n", enable ? + "enable" : "disable"); + + return rc; +} + +static enum power_supply_property smb1360_battery_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_CHARGING_ENABLED, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_RESISTANCE, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL, +}; + +static int smb1360_get_prop_batt_present(struct smb1360_chip *chip) +{ + return chip->batt_present; +} + +static int smb1360_get_prop_batt_status(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0, chg_type; + + if (is_device_suspended(chip)) + return POWER_SUPPLY_STATUS_UNKNOWN; + + if (chip->batt_full) + return POWER_SUPPLY_STATUS_FULL; + + rc = smb1360_read(chip, STATUS_3_REG, ®); + if (rc) { + pr_err("Couldn't read STATUS_3_REG rc=%d\n", rc); + return POWER_SUPPLY_STATUS_UNKNOWN; + } + + pr_debug("STATUS_3_REG = %x\n", reg); + + if (reg & CHG_HOLD_OFF_BIT) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + + chg_type = (reg & CHG_TYPE_MASK) >> CHG_TYPE_SHIFT; + + if (chg_type == BATT_NOT_CHG_VAL) + return POWER_SUPPLY_STATUS_DISCHARGING; + else + return POWER_SUPPLY_STATUS_CHARGING; +} + +static int smb1360_get_prop_charge_type(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0; + u8 chg_type; + + if (is_device_suspended(chip)) + return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + + rc = smb1360_read(chip, STATUS_3_REG, ®); + if (rc) { + pr_err("Couldn't read STATUS_3_REG rc=%d\n", rc); + return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN; + } + + chg_type = (reg & CHG_TYPE_MASK) >> CHG_TYPE_SHIFT; + if (chg_type == BATT_NOT_CHG_VAL) + return POWER_SUPPLY_CHARGE_TYPE_NONE; + else if ((chg_type == BATT_FAST_CHG_VAL) || + (chg_type == BATT_TAPER_CHG_VAL)) + return POWER_SUPPLY_CHARGE_TYPE_FAST; + else if (chg_type == BATT_PRE_CHG_VAL) + return POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + + return POWER_SUPPLY_CHARGE_TYPE_NONE; +} + +static int smb1360_get_prop_batt_health(struct smb1360_chip *chip) +{ + union power_supply_propval ret = {0, }; + + if (chip->batt_hot) + ret.intval = POWER_SUPPLY_HEALTH_OVERHEAT; + else if (chip->batt_cold) + ret.intval = POWER_SUPPLY_HEALTH_COLD; + else if (chip->batt_warm) + ret.intval = POWER_SUPPLY_HEALTH_WARM; + else if (chip->batt_cool) + ret.intval = POWER_SUPPLY_HEALTH_COOL; + else + ret.intval = POWER_SUPPLY_HEALTH_GOOD; + + return ret.intval; +} + +static int smb1360_get_prop_batt_capacity(struct smb1360_chip *chip) +{ + u8 reg; + u32 temp = 0; + int rc, soc = 0; + + if (chip->fake_battery_soc >= 0) + return chip->fake_battery_soc; + + if (chip->empty_soc) { + pr_debug("empty_soc\n"); + return 0; + } + + if (is_device_suspended(chip)) + return chip->soc_now; + + rc = smb1360_read(chip, SHDW_FG_MSYS_SOC, ®); + if (rc) { + pr_err("Failed to read FG_MSYS_SOC rc=%d\n", rc); + return rc; + } + soc = (100 * reg) / MAX_8_BITS; + + temp = (100 * reg) % MAX_8_BITS; + if (temp > (MAX_8_BITS / 2)) + soc += 1; + + pr_debug("msys_soc_reg=0x%02x, fg_soc=%d batt_full = %d\n", reg, + soc, chip->batt_full); + + chip->soc_now = (chip->batt_full ? 100 : bound(soc, 0, 100)); + + return chip->soc_now; +} + +static int smb1360_get_prop_chg_full_design(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, fcc_mah = 0; + + if (is_device_suspended(chip)) + return chip->fcc_mah; + + rc = smb1360_read_bytes(chip, SHDW_FG_CAPACITY, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_CAPACITY rc=%d\n", rc); + return rc; + } + fcc_mah = (reg[1] << 8) | reg[0]; + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x fcc_mah=%d\n", + reg[0], reg[1], fcc_mah); + + chip->fcc_mah = fcc_mah * 1000; + + return chip->fcc_mah; +} + +static int smb1360_get_prop_batt_temp(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, temp = 0; + + if (is_device_suspended(chip)) + return chip->temp_now; + + rc = smb1360_read_bytes(chip, SHDW_FG_BATT_TEMP, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_BATT_TEMP rc=%d\n", rc); + return rc; + } + + temp = (reg[1] << 8) | reg[0]; + temp = div_u64(temp * 625, 10000UL); /* temperature in kelvin */ + temp = (temp - 273) * 10; /* temperature in decideg */ + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x temperature=%d\n", + reg[0], reg[1], temp); + + chip->temp_now = temp; + + return chip->temp_now; +} + +static int smb1360_get_prop_voltage_now(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, temp = 0; + + if (is_device_suspended(chip)) + return chip->voltage_now; + + rc = smb1360_read_bytes(chip, SHDW_FG_VTG_NOW, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_VTG_NOW rc=%d\n", rc); + return rc; + } + + temp = (reg[1] << 8) | reg[0]; + temp = div_u64(temp * 5000, 0x7FFF); + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x voltage=%d\n", + reg[0], reg[1], temp * 1000); + + chip->voltage_now = temp * 1000; + + return chip->voltage_now; +} + +static int smb1360_get_prop_batt_resistance(struct smb1360_chip *chip) +{ + u8 reg[2]; + u16 temp; + int rc; + int64_t resistance; + + if (is_device_suspended(chip)) + return chip->resistance_now; + + rc = smb1360_read_bytes(chip, SHDW_FG_ESR_ACTUAL, reg, 2); + if (rc) { + pr_err("Failed to read FG_ESR_ACTUAL rc=%d\n", rc); + return rc; + } + temp = (reg[1] << 8) | reg[0]; + + resistance = float_decode(temp) * 2; + + pr_debug("reg=0x%02x resistance=%lld\n", temp, resistance); + + /* resistance in uohms */ + chip->resistance_now = resistance; + + return chip->resistance_now; +} + +static int smb1360_get_prop_current_now(struct smb1360_chip *chip) +{ + u8 reg[2]; + int rc, temp = 0; + + if (is_device_suspended(chip)) + return chip->current_now; + + rc = smb1360_read_bytes(chip, SHDW_FG_CURR_NOW, reg, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_CURR_NOW rc=%d\n", rc); + return rc; + } + + temp = ((s8)reg[1] << 8) | reg[0]; + temp = div_s64(temp * 2500, 0x7FFF); + + pr_debug("reg[0]=0x%02x reg[1]=0x%02x current=%d\n", + reg[0], reg[1], temp * 1000); + + chip->current_now = temp * 1000; + + return chip->current_now; +} + +static int smb1360_set_minimum_usb_current(struct smb1360_chip *chip) +{ + int rc = 0; + + if (chip->min_icl_usb100) { + pr_debug("USB min current set to 100mA\n"); + /* set input current limit to minimum (300mA) */ + rc = smb1360_masked_write(chip, CFG_BATT_CHG_ICL_REG, + INPUT_CURR_LIM_MASK, + INPUT_CURR_LIM_300MA); + if (rc) + pr_err("Couldn't set ICL mA rc=%d\n", rc); + + if (!(chip->workaround_flags & WRKRND_USB100_FAIL)) + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_100_BIT); + if (rc) + pr_err("Couldn't configure for USB100 rc=%d\n", + rc); + } else { + pr_debug("USB min current set to 500mA\n"); + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_500_BIT); + if (rc) + pr_err("Couldn't configure for USB100 rc=%d\n", + rc); + } + + return rc; +} + +static struct power_supply *get_parallel_psy(struct smb1360_chip *chip) +{ + if (chip->parallel_psy) + return chip->parallel_psy; + chip->parallel_psy = power_supply_get_by_name("usb-parallel"); + if (!chip->parallel_psy) + pr_debug("parallel charger not found\n"); + return chip->parallel_psy; +} + +static int __smb1360_parallel_charger_enable(struct smb1360_chip *chip, + bool enable) +{ + struct power_supply *parallel_psy = get_parallel_psy(chip); + union power_supply_propval pval = {0, }; + + if (!parallel_psy) + return 0; + + pval.intval = (enable ? (chip->max_parallel_chg_current * 1000) : 0); + chip->parallel_psy_d.set_property(parallel_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, &pval); + pval.intval = (enable ? 1 : 0); + chip->parallel_psy_d.set_property(parallel_psy, + POWER_SUPPLY_PROP_CHARGING_ENABLED, &pval); + + pr_debug("Parallel-charger %s max_chg_current=%d\n", + enable ? "enabled" : "disabled", + enable ? (chip->max_parallel_chg_current * 1000) : 0); + + return 0; +} + +static int smb1360_parallel_charger_enable(struct smb1360_chip *chip, + int reason, bool enable) +{ + int disabled, *disabled_status; + + mutex_lock(&chip->parallel_chg_lock); + + disabled = chip->parallel_chg_disable_status; + disabled_status = &chip->parallel_chg_disable_status; + + pr_debug("reason=0x%x requested=%s disabled_status=0x%x\n", + reason, enable ? "enable" : "disable", disabled); + + if (enable == true) + disabled &= ~reason; + else + disabled |= reason; + + if (*disabled_status && !disabled) + __smb1360_parallel_charger_enable(chip, true); + + if (!(*disabled_status) && disabled) + __smb1360_parallel_charger_enable(chip, false); + + *disabled_status = disabled; + + pr_debug("disabled_status = %x\n", *disabled_status); + + mutex_unlock(&chip->parallel_chg_lock); + + return 0; +} + +static void smb1360_parallel_work(struct work_struct *work) +{ + u8 reg; + int rc, i; + struct smb1360_chip *chip = container_of(work, + struct smb1360_chip, parallel_work); + + /* check the AICL settled value */ + rc = smb1360_read(chip, STATUS_1_REG, ®); + if (rc) { + pr_debug("Unable to read AICL status rc=%d\n", rc); + goto exit_work; + } + pr_debug("STATUS_1 (aicl status)=0x%x\n", reg); + if ((reg & AICL_CURRENT_STATUS_MASK) == AICL_LIMIT_1500MA) { + /* Strong Charger - Enable parallel path */ + /* find the new fastchg current */ + chip->fastchg_current += (chip->max_parallel_chg_current / 2); + for (i = 0; i < ARRAY_SIZE(fastchg_current) - 1; i++) { + if (fastchg_current[i] >= chip->fastchg_current) + break; + } + if (i == ARRAY_SIZE(fastchg_current)) + i--; + + rc = smb1360_masked_write(chip, CHG_CURRENT_REG, + FASTCHG_CURR_MASK, i << FASTCHG_CURR_SHIFT); + if (rc) + pr_err("Couldn't set fastchg mA rc=%d\n", rc); + + pr_debug("fast-chg (parallel-mode) current set to = %d\n", + fastchg_current[i]); + + smb1360_parallel_charger_enable(chip, PARALLEL_CURRENT, true); + } else { + /* Weak-charger - Disable parallel path */ + smb1360_parallel_charger_enable(chip, PARALLEL_CURRENT, false); + } + +exit_work: + smb1360_relax(&chip->smb1360_ws, WAKEUP_SRC_PARALLEL); +} + +static int smb1360_set_appropriate_usb_current(struct smb1360_chip *chip) +{ + int rc = 0, i, therm_ma, current_ma; + int path_current = chip->usb_psy_ma; + + /* + * If battery is absent do not modify the current at all, these + * would be some appropriate values set by the bootloader or default + * configuration and since it is the only source of power we should + * not change it + */ + if (!chip->batt_present) { + pr_debug("ignoring current request since battery is absent\n"); + return 0; + } + + if (chip->therm_lvl_sel > 0 + && chip->therm_lvl_sel < (chip->thermal_levels - 1)) + /* + * consider thermal limit only when it is active and not at + * the highest level + */ + therm_ma = chip->thermal_mitigation[chip->therm_lvl_sel]; + else + therm_ma = path_current; + + current_ma = min(therm_ma, path_current); + + if (chip->workaround_flags & WRKRND_HARD_JEITA) { + if (chip->batt_warm) + current_ma = min(current_ma, chip->warm_bat_ma); + else if (chip->batt_cool) + current_ma = min(current_ma, chip->cool_bat_ma); + } + + if (current_ma <= 2) { + /* + * SMB1360 does not support USB suspend - + * so set the current-limit to minimum in suspend. + */ + pr_debug("current_ma=%d <= 2 set USB current to minimum\n", + current_ma); + rc = smb1360_set_minimum_usb_current(chip); + if (rc < 0) + pr_err("Couldn't to set minimum USB current rc = %d\n", + rc); + /* disable parallel charger */ + if (chip->parallel_charging) + smb1360_parallel_charger_enable(chip, + PARALLEL_CURRENT, false); + + return rc; + } + + for (i = ARRAY_SIZE(input_current_limit) - 1; i >= 0; i--) { + if (input_current_limit[i] <= current_ma) + break; + } + if (i < 0) { + pr_debug("Couldn't find ICL mA rc=%d\n", rc); + i = 0; + } + /* set input current limit */ + rc = smb1360_masked_write(chip, CFG_BATT_CHG_ICL_REG, + INPUT_CURR_LIM_MASK, i); + if (rc) + pr_err("Couldn't set ICL mA rc=%d\n", rc); + + pr_debug("ICL set to = %d\n", input_current_limit[i]); + + if ((current_ma <= CURRENT_100_MA) && + ((chip->workaround_flags & WRKRND_USB100_FAIL) || + !chip->min_icl_usb100)) { + pr_debug("usb100 not supported: usb100_wrkrnd=%d min_icl_100=%d\n", + !!(chip->workaround_flags & WRKRND_USB100_FAIL), + chip->min_icl_usb100); + current_ma = CURRENT_500_MA; + } + + if (current_ma <= CURRENT_100_MA) { + /* USB 100 */ + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_100_BIT); + if (rc) + pr_err("Couldn't configure for USB100 rc=%d\n", rc); + pr_debug("Setting USB 100\n"); + } else if (current_ma <= CURRENT_500_MA) { + /* USB 500 */ + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_500_BIT); + if (rc) + pr_err("Couldn't configure for USB500 rc=%d\n", rc); + pr_debug("Setting USB 500\n"); + } else { + /* USB AC */ + if (chip->rsense_10mohm) + current_ma /= 2; + + for (i = ARRAY_SIZE(fastchg_current) - 1; i >= 0; i--) { + if (fastchg_current[i] <= current_ma) + break; + } + if (i < 0) { + pr_debug("Couldn't find fastchg mA rc=%d\n", rc); + i = 0; + } + + chip->fastchg_current = fastchg_current[i]; + + /* set fastchg limit */ + rc = smb1360_masked_write(chip, CHG_CURRENT_REG, + FASTCHG_CURR_MASK, i << FASTCHG_CURR_SHIFT); + if (rc) + pr_err("Couldn't set fastchg mA rc=%d\n", rc); + + /* + * To move to a new (higher) input-current setting, + * first set USB500 and then USBAC. This makes sure + * that the new ICL setting takes affect. + */ + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_500_BIT); + if (rc) + pr_err("Couldn't configure for USB500 rc=%d\n", rc); + + rc = smb1360_masked_write(chip, CMD_IL_REG, + USB_CTRL_MASK, USB_AC_BIT); + if (rc) + pr_err("Couldn't configure for USB AC rc=%d\n", rc); + + pr_debug("fast-chg current set to = %d\n", fastchg_current[i]); + } + + return rc; +} + +static int smb1360_set_jeita_comp_curr(struct smb1360_chip *chip, + int current_ma) +{ + int i; + int rc = 0; + + for (i = ARRAY_SIZE(fastchg_current) - 1; i >= 0; i--) { + if (fastchg_current[i] <= current_ma) + break; + } + if (i < 0) { + pr_debug("Couldn't find fastchg_current %dmA\n", current_ma); + i = 0; + } + + rc = smb1360_masked_write(chip, CHG_CMP_CFG, + JEITA_COMP_CURR_MASK, i); + if (rc) + pr_err("Couldn't configure for Icomp, rc = %d\n", rc); + + return rc; +} + +#define TEMP_THRE_SET(x) ((x + 300) / 10) +#define TEMP_THRE_GET(x) ((x * 10) - 300) +static int smb1360_set_soft_jeita_threshold(struct smb1360_chip *chip, + int cold_threshold, int hot_threshold) +{ + int rc = 0; + + rc = smb1360_write(chip, JEITA_SOFT_COLD_REG, + TEMP_THRE_SET(cold_threshold)); + if (rc) { + pr_err("Couldn't set soft cold threshold, rc = %d\n", rc); + return rc; + } + chip->soft_cold_thresh = cold_threshold; + + rc = smb1360_write(chip, JEITA_SOFT_HOT_REG, + TEMP_THRE_SET(hot_threshold)); + if (rc) { + pr_err("Couldn't set soft hot threshold, rc = %d\n", rc); + return rc; + } + chip->soft_hot_thresh = hot_threshold; + + return rc; +} + +static int smb1360_get_soft_jeita_threshold(struct smb1360_chip *chip, + int *cold_threshold, int *hot_threshold) +{ + int rc = 0; + u8 value; + + rc = smb1360_read(chip, JEITA_SOFT_COLD_REG, &value); + if (rc) { + pr_err("Couldn't get soft cold threshold, rc = %d\n", rc); + return rc; + } + *cold_threshold = TEMP_THRE_GET(value); + + rc = smb1360_read(chip, JEITA_SOFT_HOT_REG, &value); + if (rc) { + pr_err("Couldn't get soft hot threshold, rc = %d\n", rc); + return rc; + } + *hot_threshold = TEMP_THRE_GET(value); + + return rc; +} + +#define OTP_HARD_COLD_REG_ADDR 0x12 +#define OTP_HARD_HOT_REG_ADDR 0x13 +static int smb1360_set_otp_hard_jeita_threshold(struct smb1360_chip *chip, + int cold_threshold, int hot_threshold) +{ + int rc = 0, i; + u8 reg[4] = { 0 }; + u8 otp_reg = 0; + int temp_code; + + if (cold_threshold > chip->cool_bat_decidegc || + chip->cool_bat_decidegc >= chip->warm_bat_decidegc || + chip->warm_bat_decidegc > hot_threshold) { + pr_err("cold:%d, cool:%d, warm:%d, hot:%d should be ordered in size\n", + cold_threshold, chip->cool_bat_decidegc, + chip->warm_bat_decidegc, hot_threshold); + return -EINVAL; + } + pr_debug("cold:%d, cool:%d, warm:%d, hot:%d\n", + cold_threshold, chip->cool_bat_decidegc, + chip->warm_bat_decidegc, hot_threshold); + if (!chip->hard_jeita_otp_reg) { + otp_reg = smb1360_alloc_otp_backup_register(chip, + ARRAY_SIZE(reg), OTP_BACKUP_FG_USE); + if (otp_reg <= 0) { + pr_err("OTP reg allocation failed for hard JEITA\n"); + return otp_reg; + } + + chip->hard_jeita_otp_reg = otp_reg; + } else { + otp_reg = chip->hard_jeita_otp_reg; + } + pr_debug("hard_jeita_otp_reg = 0x%x\n", chip->hard_jeita_otp_reg); + + reg[0] = (u8)OTP_HARD_HOT_REG_ADDR; + temp_code = TEMP_THRE_SET(hot_threshold); + if (temp_code < 0) { + pr_err("hard hot temp encode failed\n"); + return temp_code; + } + reg[1] = (u8)temp_code; + reg[2] = (u8)OTP_HARD_COLD_REG_ADDR; + temp_code = TEMP_THRE_SET(cold_threshold); + if (temp_code < 0) { + pr_err("hard cold temp encode failed\n"); + return temp_code; + } + reg[3] = (u8)temp_code; + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't request FG access rc = %d\n", rc); + return rc; + } + chip->fg_access_type = FG_ACCESS_CFG; + + rc = smb1360_select_fg_i2c_address(chip); + if (rc) { + pr_err("Unable to set FG access I2C address\n"); + goto restore_fg; + } + + for (i = 0; i < ARRAY_SIZE(reg); i++) { + rc = smb1360_fg_write(chip, (otp_reg + i), reg[i]); + if (rc) { + pr_err("Write FG address 0x%x: 0x%x failed, rc = %d\n", + otp_reg + i, reg[i], rc); + goto restore_fg; + } + pr_debug("Write FG addr=0x%x, value=0x%x\n", + otp_reg + i, reg[i]); + } + rc = smb1360_otp_backup_alg_update(chip); + if (rc) { + pr_err("Update OTP backup algorithm failed\n"); + goto restore_fg; + } + + rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, + CFG_FG_OTP_BACK_UP_ENABLE, CFG_FG_OTP_BACK_UP_ENABLE); + if (rc) { + pr_err("Write reg 0x0E failed, rc = %d\n", rc); + goto restore_fg; + } + +restore_fg: + rc = smb1360_disable_fg_access(chip); + if (rc) { + pr_err("Couldn't disable FG access rc = %d\n", rc); + return rc; + } + + return rc; +} + +static int smb1360_hard_jeita_otp_init(struct smb1360_chip *chip) +{ + int rc = 0; + + if (!chip->otp_hard_jeita_config) + return rc; + + rc = smb1360_set_otp_hard_jeita_threshold(chip, + chip->otp_cold_bat_decidegc, chip->otp_hot_bat_decidegc); + if (rc) { + dev_err(chip->dev, + "Couldn't set OTP hard jeita threshold,rc = %d\n", rc); + return rc; + } + + return rc; +} + +static int smb1360_system_temp_level_set(struct smb1360_chip *chip, + int lvl_sel) +{ + int rc = 0; + int prev_therm_lvl; + + if (!chip->thermal_mitigation) { + pr_err("Thermal mitigation not supported\n"); + return -EINVAL; + } + + if (lvl_sel < 0) { + pr_err("Unsupported level selected %d\n", lvl_sel); + return -EINVAL; + } + + if (lvl_sel >= chip->thermal_levels) { + pr_err("Unsupported level selected %d forcing %d\n", lvl_sel, + chip->thermal_levels - 1); + lvl_sel = chip->thermal_levels - 1; + } + + if (lvl_sel == chip->therm_lvl_sel) + return 0; + + mutex_lock(&chip->current_change_lock); + prev_therm_lvl = chip->therm_lvl_sel; + chip->therm_lvl_sel = lvl_sel; + + if (chip->therm_lvl_sel == (chip->thermal_levels - 1)) { + rc = smb1360_set_minimum_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current to minimum rc = %d\n", + rc); + } else { + rc = smb1360_set_appropriate_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current rc = %d\n", rc); + } + + mutex_unlock(&chip->current_change_lock); + return rc; +} + +static enum power_supply_property smb1360_usb_properties[] = { + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_TYPE, + POWER_SUPPLY_PROP_REAL_TYPE, + POWER_SUPPLY_PROP_SDP_CURRENT_MAX, +}; + +static int smb1360_usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + int is_battery_charging = 0; + struct smb1360_chip *chip = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + case POWER_SUPPLY_PROP_CURRENT_MAX: + val->intval = chip->usb_psy_ma * 1000; + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = chip->usb_present; + break; + case POWER_SUPPLY_PROP_ONLINE: + is_battery_charging = smb1360_get_prop_batt_status(chip); + val->intval = chip->usb_present && + (is_battery_charging == POWER_SUPPLY_STATUS_CHARGING); + break; + case POWER_SUPPLY_PROP_REAL_TYPE: + val->intval = POWER_SUPPLY_TYPE_UNKNOWN; + if (chip->usb_present && + (chip->usb_supply_type != POWER_SUPPLY_TYPE_UNKNOWN)) + val->intval = chip->usb_supply_type; + break; + case POWER_SUPPLY_PROP_TYPE: + val->intval = POWER_SUPPLY_TYPE_USB; + if (chip->usb_present && + (chip->usb_supply_type != POWER_SUPPLY_TYPE_UNKNOWN)) + val->intval = chip->usb_supply_type; + break; + default: + return -EINVAL; + } + return 0; +} + +static int smb1360_usb_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct smb1360_chip *chip = power_supply_get_drvdata(psy); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_SDP_CURRENT_MAX: + case POWER_SUPPLY_PROP_CURRENT_MAX: + chip->usb_psy_ma = val->intval / 1000; + rc = smb1360_set_appropriate_usb_current(chip); + break; + case POWER_SUPPLY_PROP_TYPE: + case POWER_SUPPLY_PROP_REAL_TYPE: + chip->usb_supply_type = val->intval; + break; + default: + return -EINVAL; + } + + power_supply_changed(psy); + return 0; +} + +static int smb1360_usb_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_CURRENT_MAX: + return 1; + default: + break; + } + return 0; +} + + +static int smb1360_battery_set_property(struct power_supply *psy, + enum power_supply_property prop, + const union power_supply_propval *val) +{ + struct smb1360_chip *chip = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + smb1360_charging_disable(chip, USER, !val->intval); + if (chip->parallel_charging) + smb1360_parallel_charger_enable(chip, + PARALLEL_USER, val->intval); + power_supply_changed(chip->batt_psy); + power_supply_changed(chip->usb_psy); + break; + case POWER_SUPPLY_PROP_CAPACITY: + chip->fake_battery_soc = val->intval; + pr_info("fake_soc set to %d\n", chip->fake_battery_soc); + power_supply_changed(chip->batt_psy); + break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + smb1360_system_temp_level_set(chip, val->intval); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smb1360_battery_is_writeable(struct power_supply *psy, + enum power_supply_property prop) +{ + int rc; + + switch (prop) { + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + case POWER_SUPPLY_PROP_CAPACITY: + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + rc = 1; + break; + default: + rc = 0; + break; + } + return rc; +} + +static int smb1360_battery_get_property(struct power_supply *psy, + enum power_supply_property prop, + union power_supply_propval *val) +{ + struct smb1360_chip *chip = power_supply_get_drvdata(psy); + + switch (prop) { + case POWER_SUPPLY_PROP_HEALTH: + val->intval = smb1360_get_prop_batt_health(chip); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = smb1360_get_prop_batt_present(chip); + break; + case POWER_SUPPLY_PROP_STATUS: + val->intval = smb1360_get_prop_batt_status(chip); + break; + case POWER_SUPPLY_PROP_CHARGING_ENABLED: + val->intval = !chip->charging_disabled_status; + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = smb1360_get_prop_charge_type(chip); + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = smb1360_get_prop_batt_capacity(chip); + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = smb1360_get_prop_chg_full_design(chip); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + val->intval = smb1360_get_prop_voltage_now(chip); + break; + case POWER_SUPPLY_PROP_CURRENT_NOW: + val->intval = smb1360_get_prop_current_now(chip); + break; + case POWER_SUPPLY_PROP_RESISTANCE: + val->intval = smb1360_get_prop_batt_resistance(chip); + break; + case POWER_SUPPLY_PROP_TEMP: + val->intval = smb1360_get_prop_batt_temp(chip); + break; + case POWER_SUPPLY_PROP_SYSTEM_TEMP_LEVEL: + val->intval = chip->therm_lvl_sel; + break; + default: + return -EINVAL; + } + return 0; +} + +static int hot_hard_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_hot = !!rt_stat; + + if (chip->parallel_charging) { + pr_debug("%s parallel-charging\n", chip->batt_hot ? + "Disable" : "Enable"); + smb1360_parallel_charger_enable(chip, + PARALLEL_JEITA_HARD, !chip->batt_hot); + } + if (chip->hot_hysteresis) { + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_JEITA_HYSTERSIS); + schedule_work(&chip->jeita_hysteresis_work); + } + + return 0; +} + +static int cold_hard_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_cold = !!rt_stat; + + if (chip->parallel_charging) { + pr_debug("%s parallel-charging\n", chip->batt_cold ? + "Disable" : "Enable"); + smb1360_parallel_charger_enable(chip, + PARALLEL_JEITA_HARD, !chip->batt_cold); + } + if (chip->cold_hysteresis) { + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_JEITA_HYSTERSIS); + schedule_work(&chip->jeita_hysteresis_work); + } + + return 0; +} + +static void smb1360_jeita_hysteresis_work(struct work_struct *work) +{ + int rc = 0; + int hard_hot, hard_cold; + struct smb1360_chip *chip = container_of(work, + struct smb1360_chip, jeita_hysteresis_work); + + /* disable hard JEITA IRQ first */ + rc = smb1360_masked_write(chip, IRQ_CFG_REG, + IRQ_BAT_HOT_COLD_HARD_BIT, 0); + if (rc) { + pr_err("disable hard JEITA IRQ failed, rc = %d\n", rc); + goto exit_worker; + } + hard_hot = chip->otp_hot_bat_decidegc; + hard_cold = chip->otp_cold_bat_decidegc; + if (chip->batt_hot) + hard_hot -= chip->hot_hysteresis; + else if (chip->batt_cold) + hard_cold += chip->cold_hysteresis; + + rc = smb1360_set_otp_hard_jeita_threshold(chip, hard_cold, hard_hot); + if (rc) { + pr_err("set hard JEITA threshold failed\n"); + goto exit_worker; + } + pr_debug("hard cold: %d, hard hot: %d reprogramed\n", + hard_cold, hard_hot); + /* enable hard JEITA IRQ at the end */ + rc = smb1360_masked_write(chip, IRQ_CFG_REG, + IRQ_BAT_HOT_COLD_HARD_BIT, IRQ_BAT_HOT_COLD_HARD_BIT); + if (rc) + pr_err("enable hard JEITA IRQ failed\n"); +exit_worker: + smb1360_relax(&chip->smb1360_ws, WAKEUP_SRC_JEITA_HYSTERSIS); +} + +/* + * This worker thread should only be called when WRKRND_HARD_JEITA + * is set. + * It is needed to re-program JEITA soft thresholds, compensate + * target voltage and charging current manually. + * The function is required as JEITA hard thresholds can't be programmed. + */ +static void smb1360_jeita_work_fn(struct work_struct *work) +{ + int temp; + int rc = 0; + struct smb1360_chip *chip = container_of(work, + struct smb1360_chip, jeita_work.work); + + temp = smb1360_get_prop_batt_temp(chip); + + if (temp > chip->hot_bat_decidegc) { + /* battery status is hot, only config thresholds */ + rc = smb1360_set_soft_jeita_threshold(chip, + chip->warm_bat_decidegc, chip->hot_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + } else if (temp > chip->warm_bat_decidegc || + (temp == chip->warm_bat_decidegc && !!chip->soft_hot_rt_stat)) { + /* battery status is warm, do compensation manually */ + chip->batt_warm = true; + chip->batt_cool = false; + rc = smb1360_float_voltage_set(chip, chip->warm_bat_mv); + if (rc) { + dev_err(chip->dev, "Couldn't set float voltage\n"); + goto end; + } + rc = smb1360_set_appropriate_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current\n"); + rc = smb1360_set_soft_jeita_threshold(chip, + chip->warm_bat_decidegc, chip->hot_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + } else if (temp > chip->cool_bat_decidegc || + (temp == chip->cool_bat_decidegc && !chip->soft_cold_rt_stat)) { + /* battery status is good, do the normal charging */ + chip->batt_warm = false; + chip->batt_cool = false; + rc = smb1360_float_voltage_set(chip, chip->vfloat_mv); + if (rc) { + dev_err(chip->dev, "Couldn't set float voltage\n"); + goto end; + } + rc = smb1360_set_appropriate_usb_current(chip); + if (rc) + pr_err("Couldn't set USB current\n"); + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cool_bat_decidegc, chip->warm_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + } else if (temp > chip->cold_bat_decidegc) { + /* battery status is cool, do compensation manually */ + chip->batt_cool = true; + chip->batt_warm = false; + rc = smb1360_float_voltage_set(chip, chip->cool_bat_mv); + if (rc) { + dev_err(chip->dev, "Couldn't set float voltage\n"); + goto end; + } + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cold_bat_decidegc, chip->cool_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + } else { + /* battery status is cold, only config thresholds */ + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cold_bat_decidegc, chip->cool_bat_decidegc); + if (rc) { + dev_err(chip->dev, "Couldn't set jeita threshold\n"); + goto end; + } + } + + pr_debug("warm %d, cool %d, soft_cold_rt_sts %d, soft_hot_rt_sts %d, jeita supported %d, threshold_now %d %d\n", + chip->batt_warm, chip->batt_cool, !!chip->soft_cold_rt_stat, + !!chip->soft_hot_rt_stat, chip->soft_jeita_supported, + chip->soft_cold_thresh, chip->soft_hot_thresh); +end: + smb1360_relax(&chip->smb1360_ws, WAKEUP_SRC_JEITA_SOFT); +} + +static int hot_soft_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + chip->soft_hot_rt_stat = rt_stat; + pr_debug("rt_stat = 0x%02x\n", rt_stat); + if (!chip->config_hard_thresholds) + chip->batt_warm = !!rt_stat; + + if (chip->workaround_flags & WRKRND_HARD_JEITA) { + cancel_delayed_work_sync(&chip->jeita_work); + schedule_delayed_work(&chip->jeita_work, + msecs_to_jiffies(JEITA_WORK_MS)); + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_JEITA_SOFT); + } + + if (chip->parallel_charging) { + pr_debug("%s parallel-charging\n", chip->batt_warm ? + "Disable" : "Enable"); + smb1360_parallel_charger_enable(chip, + PARALLEL_JEITA_SOFT, !chip->batt_warm); + } + return 0; +} + +static int cold_soft_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + chip->soft_cold_rt_stat = rt_stat; + pr_debug("rt_stat = 0x%02x\n", rt_stat); + if (!chip->config_hard_thresholds) + chip->batt_cool = !!rt_stat; + + if (chip->workaround_flags & WRKRND_HARD_JEITA) { + cancel_delayed_work_sync(&chip->jeita_work); + schedule_delayed_work(&chip->jeita_work, + msecs_to_jiffies(JEITA_WORK_MS)); + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_JEITA_SOFT); + } + + if (chip->parallel_charging) { + pr_debug("%s parallel-charging\n", chip->batt_cool ? + "Disable" : "Enable"); + smb1360_parallel_charger_enable(chip, + PARALLEL_JEITA_SOFT, !chip->batt_cool); + } + + return 0; +} + +static int battery_missing_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_present = !rt_stat; + return 0; +} + +static int vbat_low_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("vbat low\n"); + + return 0; +} + +static int chg_hot_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_warn_ratelimited("chg hot\n"); + return 0; +} + +static int chg_term_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_full = !!rt_stat; + + if (chip->parallel_charging) { + pr_debug("%s parallel-charging\n", chip->batt_full ? + "Disable" : "Enable"); + smb1360_parallel_charger_enable(chip, + PARALLEL_EOC, !chip->batt_full); + } + + return 0; +} + +static int chg_fastchg_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + + return 0; +} + +static int usbin_uv_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + bool usb_present = !rt_stat; + + pr_debug("chip->usb_present = %d usb_present = %d\n", + chip->usb_present, usb_present); + if (chip->usb_present && !usb_present) { + /* USB removed */ + chip->usb_present = usb_present; + extcon_set_cable_state_(chip->extcon, EXTCON_USB, false); + chip->usb_supply_type = POWER_SUPPLY_TYPE_UNKNOWN; + } + + if (!chip->usb_present && usb_present) { + /* USB inserted */ + chip->usb_present = usb_present; + extcon_set_cable_state_(chip->extcon, EXTCON_USB, true); + } + power_supply_changed(chip->usb_psy); + + return 0; +} + +static int aicl_done_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + bool aicl_done = !!rt_stat; + + pr_debug("AICL done=%d\n", aicl_done); + + if (chip->parallel_charging && aicl_done) { + cancel_work_sync(&chip->parallel_work); + smb1360_stay_awake(&chip->smb1360_ws, WAKEUP_SRC_PARALLEL); + schedule_work(&chip->parallel_work); + } + + return 0; +} + +static int chg_inhibit_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + /* + * charger is inserted when the battery voltage is high + * so h/w won't start charging just yet. Treat this as + * battery full + */ + pr_debug("rt_stat = 0x%02x\n", rt_stat); + chip->batt_full = !!rt_stat; + return 0; +} + +static int delta_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("SOC changed! - rt_stat = 0x%02x\n", rt_stat); + + return 0; +} + +static int min_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("SOC dropped below min SOC, rt_stat = 0x%02x\n", rt_stat); + + if (chip->awake_min_soc) + rt_stat ? smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_MIN_SOC) : + smb1360_relax(&chip->smb1360_ws, + WAKEUP_SRC_MIN_SOC); + + return 0; +} + +static int empty_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("SOC empty! rt_stat = 0x%02x\n", rt_stat); + + if (!chip->empty_soc_disabled) { + if (rt_stat) { + chip->empty_soc = true; + smb1360_stay_awake(&chip->smb1360_ws, + WAKEUP_SRC_EMPTY_SOC); + pr_warn_ratelimited("SOC is 0\n"); + } else { + chip->empty_soc = false; + smb1360_relax(&chip->smb1360_ws, + WAKEUP_SRC_EMPTY_SOC); + } + } + + return 0; +} + +static int full_soc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + if (rt_stat) + pr_debug("SOC is 100\n"); + + return 0; +} + +static int fg_access_allowed_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("stat=%d\n", !!rt_stat); + + if (rt_stat & FG_ACCESS_ALLOWED_BIT) { + pr_debug("FG access granted\n"); + complete_all(&chip->fg_mem_access_granted); + } + + return 0; +} + +static int batt_id_complete_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + pr_debug("batt_id = %x\n", (rt_stat & BATT_ID_RESULT_BIT) + >> BATT_ID_SHIFT); + + return 0; +} + +static int smb1360_adjust_current_gain(struct smb1360_chip *chip, + int gain_factor) +{ + int i, rc; + int64_t current_gain, new_current_gain; + u16 reg_value1 = 0, reg_value2 = 0; + u8 reg[4] = {0x1D, 0x00, 0x1E, 0x00}; + u8 otp_reg = 0; + + if (!chip->current_gain_otp_reg) { + otp_reg = smb1360_alloc_otp_backup_register(chip, + ARRAY_SIZE(reg), OTP_BACKUP_FG_USE); + if (otp_reg <= 0) { + pr_err("OTP reg allocation fail for adjusting current gain\n"); + return otp_reg; + } + chip->current_gain_otp_reg = otp_reg; + } else { + otp_reg = chip->current_gain_otp_reg; + } + pr_debug("current_gain_otp_reg = 0x%x\n", chip->current_gain_otp_reg); + + if (gain_factor) { + rc = smb1360_fg_read(chip, CURRENT_GAIN_LSB_REG, ®[1]); + if (rc) { + pr_err("Unable to set FG access I2C address rc=%d\n", + rc); + return rc; + } + + rc = smb1360_fg_read(chip, CURRENT_GAIN_MSB_REG, ®[3]); + if (rc) { + pr_err("Unable to set FG access I2C address rc=%d\n", + rc); + return rc; + } + + reg_value1 = (reg[3] << 8) | reg[1]; + current_gain = float_decode(reg_value1); + new_current_gain = MICRO_UNIT + (gain_factor * current_gain); + reg_value2 = float_encode(new_current_gain); + reg[1] = reg_value2 & 0xFF; + reg[3] = (reg_value2 & 0xFF00) >> 8; + pr_debug("current_gain_reg=0x%x current_gain_decoded=%lld new_current_gain_decoded=%lld new_current_gain_reg=0x%x\n", + reg_value1, current_gain, new_current_gain, reg_value2); + + for (i = 0; i < ARRAY_SIZE(reg); i++) { + pr_debug("Writing reg_add=%x value=%x\n", + otp_reg + i, reg[i]); + + rc = smb1360_fg_write(chip, (otp_reg + i), reg[i]); + if (rc) { + pr_err("Write FG address 0x%x failed, rc = %d\n", + otp_reg + i, rc); + return rc; + } + } + rc = smb1360_otp_backup_alg_update(chip); + if (rc) { + pr_err("Update OTP backup algorithm failed\n"); + return rc; + } + } else { + pr_debug("Disabling gain correction\n"); + rc = smb1360_fg_write(chip, 0xF0, 0x00); + if (rc) { + pr_err("Write fg address 0x%x failed, rc = %d\n", + 0xF0, rc); + return rc; + } + } + + return 0; +} + +static int smb1360_otp_gain_config(struct smb1360_chip *chip, int gain_factor) +{ + int rc = 0; + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't request FG access rc = %d\n", rc); + return rc; + } + chip->fg_access_type = FG_ACCESS_CFG; + + rc = smb1360_select_fg_i2c_address(chip); + if (rc) { + pr_err("Unable to set FG access I2C address\n"); + goto restore_fg; + } + + rc = smb1360_adjust_current_gain(chip, gain_factor); + if (rc) { + pr_err("Unable to modify current gain rc=%d\n", rc); + goto restore_fg; + } + + rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, + CFG_FG_OTP_BACK_UP_ENABLE, CFG_FG_OTP_BACK_UP_ENABLE); + if (rc) { + pr_err("Write reg 0x0E failed, rc = %d\n", rc); + goto restore_fg; + } + +restore_fg: + rc = smb1360_disable_fg_access(chip); + if (rc) { + pr_err("Couldn't disable FG access rc = %d\n", rc); + return rc; + } + + return rc; +} + +static int smb1360_otg_disable(struct smb1360_chip *chip) +{ + int rc; + + rc = smb1360_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, 0); + if (rc) { + pr_err("Couldn't disable OTG mode rc=%d\n", rc); + return rc; + } + + mutex_lock(&chip->otp_gain_lock); + /* Disable current gain configuration */ + if (chip->otg_fet_present && chip->fet_gain_enabled) { + /* Disable FET */ + gpio_set_value(chip->otg_fet_enable_gpio, 1); + rc = smb1360_otp_gain_config(chip, 0); + if (rc < 0) + pr_err("Couldn't config OTP gain config rc=%d\n", rc); + else + chip->fet_gain_enabled = false; + } + mutex_unlock(&chip->otp_gain_lock); + + return rc; +} + +static int otg_fail_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + int rc; + + pr_debug("OTG Failed stat=%d\n", rt_stat); + rc = smb1360_otg_disable(chip); + if (rc) + pr_err("Couldn't disable OTG mode rc=%d\n", rc); + + return 0; +} + +static int otg_oc_handler(struct smb1360_chip *chip, u8 rt_stat) +{ + int rc; + + pr_debug("OTG over-current stat=%d\n", rt_stat); + rc = smb1360_otg_disable(chip); + if (rc) + pr_err("Couldn't disable OTG mode rc=%d\n", rc); + + return 0; +} + +struct smb_irq_info { + const char *name; + int (*smb_irq)(struct smb1360_chip *chip, + u8 rt_stat); + int high; + int low; +}; + +struct irq_handler_info { + u8 stat_reg; + u8 val; + u8 prev_val; + struct smb_irq_info irq_info[4]; +}; + +static struct irq_handler_info handlers[] = { + {IRQ_A_REG, 0, 0, + { + { + .name = "cold_soft", + .smb_irq = cold_soft_handler, + }, + { + .name = "hot_soft", + .smb_irq = hot_soft_handler, + }, + { + .name = "cold_hard", + .smb_irq = cold_hard_handler, + }, + { + .name = "hot_hard", + .smb_irq = hot_hard_handler, + }, + }, + }, + {IRQ_B_REG, 0, 0, + { + { + .name = "chg_hot", + .smb_irq = chg_hot_handler, + }, + { + .name = "vbat_low", + .smb_irq = vbat_low_handler, + }, + { + .name = "battery_missing", + .smb_irq = battery_missing_handler, + }, + { + .name = "battery_missing", + .smb_irq = battery_missing_handler, + }, + }, + }, + {IRQ_C_REG, 0, 0, + { + { + .name = "chg_term", + .smb_irq = chg_term_handler, + }, + { + .name = "taper", + }, + { + .name = "recharge", + }, + { + .name = "fast_chg", + .smb_irq = chg_fastchg_handler, + }, + }, + }, + {IRQ_D_REG, 0, 0, + { + { + .name = "prechg_timeout", + }, + { + .name = "safety_timeout", + }, + { + .name = "aicl_done", + .smb_irq = aicl_done_handler, + }, + { + .name = "battery_ov", + }, + }, + }, + {IRQ_E_REG, 0, 0, + { + { + .name = "usbin_uv", + .smb_irq = usbin_uv_handler, + }, + { + .name = "usbin_ov", + }, + { + .name = "unused", + }, + { + .name = "chg_inhibit", + .smb_irq = chg_inhibit_handler, + }, + }, + }, + {IRQ_F_REG, 0, 0, + { + { + .name = "power_ok", + }, + { + .name = "unused", + }, + { + .name = "otg_fail", + .smb_irq = otg_fail_handler, + }, + { + .name = "otg_oc", + .smb_irq = otg_oc_handler, + }, + }, + }, + {IRQ_G_REG, 0, 0, + { + { + .name = "delta_soc", + .smb_irq = delta_soc_handler, + }, + { + .name = "chg_error", + }, + { + .name = "wd_timeout", + }, + { + .name = "unused", + }, + }, + }, + {IRQ_H_REG, 0, 0, + { + { + .name = "min_soc", + .smb_irq = min_soc_handler, + }, + { + .name = "max_soc", + }, + { + .name = "empty_soc", + .smb_irq = empty_soc_handler, + }, + { + .name = "full_soc", + .smb_irq = full_soc_handler, + }, + }, + }, + {IRQ_I_REG, 0, 0, + { + { + .name = "fg_access_allowed", + .smb_irq = fg_access_allowed_handler, + }, + { + .name = "fg_data_recovery", + }, + { + .name = "batt_id_complete", + .smb_irq = batt_id_complete_handler, + }, + }, + }, +}; + +#define IRQ_LATCHED_MASK 0x02 +#define IRQ_STATUS_MASK 0x01 +#define BATT_ID_LATCHED_MASK 0x08 +#define BATT_ID_STATUS_MASK 0x07 +#define BITS_PER_IRQ 2 +static irqreturn_t smb1360_stat_handler(int irq, void *dev_id) +{ + struct smb1360_chip *chip = dev_id; + int i, j; + u8 triggered; + u8 changed; + u8 rt_stat, prev_rt_stat, irq_latched_mask, irq_status_mask; + int rc; + int handler_count = 0; + + mutex_lock(&chip->irq_complete); + chip->irq_waiting = true; + if (!chip->resume_completed) { + dev_dbg(chip->dev, "IRQ triggered before device-resume\n"); + if (!chip->irq_disabled) { + disable_irq_nosync(irq); + chip->irq_disabled = true; + } + mutex_unlock(&chip->irq_complete); + return IRQ_HANDLED; + } + chip->irq_waiting = false; + + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + rc = smb1360_read(chip, handlers[i].stat_reg, + &handlers[i].val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read %d rc = %d\n", + handlers[i].stat_reg, rc); + continue; + } + + for (j = 0; j < ARRAY_SIZE(handlers[i].irq_info); j++) { + if (handlers[i].stat_reg == IRQ_I_REG && j == 2) { + irq_latched_mask = BATT_ID_LATCHED_MASK; + irq_status_mask = BATT_ID_STATUS_MASK; + } else { + irq_latched_mask = IRQ_LATCHED_MASK; + irq_status_mask = IRQ_STATUS_MASK; + } + triggered = handlers[i].val + & (irq_latched_mask << (j * BITS_PER_IRQ)); + rt_stat = handlers[i].val + & (irq_status_mask << (j * BITS_PER_IRQ)); + prev_rt_stat = handlers[i].prev_val + & (irq_status_mask << (j * BITS_PER_IRQ)); + changed = prev_rt_stat ^ rt_stat; + + if (triggered || changed) + rt_stat ? handlers[i].irq_info[j].high++ : + handlers[i].irq_info[j].low++; + + if ((triggered || changed) + && handlers[i].irq_info[j].smb_irq != NULL) { + handler_count++; + rc = handlers[i].irq_info[j].smb_irq(chip, + rt_stat); + if (rc < 0) + dev_err(chip->dev, + "Couldn't handle %d irq for reg 0x%02x rc = %d\n", + j, handlers[i].stat_reg, rc); + } + } + handlers[i].prev_val = handlers[i].val; + } + + pr_debug("handler count = %d\n", handler_count); + if (handler_count) + power_supply_changed(chip->batt_psy); + + mutex_unlock(&chip->irq_complete); + + return IRQ_HANDLED; +} + +static int show_irq_count(struct seq_file *m, void *data) +{ + int i, j, total = 0; + + for (i = 0; i < ARRAY_SIZE(handlers); i++) + for (j = 0; j < 4; j++) { + if (!handlers[i].irq_info[j].name) + continue; + seq_printf(m, "%s=%d\t(high=%d low=%d)\n", + handlers[i].irq_info[j].name, + handlers[i].irq_info[j].high + + handlers[i].irq_info[j].low, + handlers[i].irq_info[j].high, + handlers[i].irq_info[j].low); + total += (handlers[i].irq_info[j].high + + handlers[i].irq_info[j].low); + } + + seq_printf(m, "\n\tTotal = %d\n", total); + + return 0; +} + +static int irq_count_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_irq_count, chip); +} + +static const struct file_operations irq_count_debugfs_ops = { + .owner = THIS_MODULE, + .open = irq_count_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int get_reg(void *data, u64 *val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + rc = smb1360_read(chip, chip->peek_poke_address, &temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read reg %x rc = %d\n", + chip->peek_poke_address, rc); + return -EAGAIN; + } + *val = temp; + return 0; +} + +static int set_reg(void *data, u64 val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + temp = (u8) val; + rc = smb1360_write(chip, chip->peek_poke_address, temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't write 0x%02x to 0x%02x rc= %d\n", + chip->peek_poke_address, temp, rc); + return -EAGAIN; + } + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(poke_poke_debug_ops, get_reg, set_reg, "0x%02llx\n"); + +static int fg_get_reg(void *data, u64 *val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + rc = smb1360_select_fg_i2c_address(chip); + if (rc) { + pr_err("Unable to set FG access I2C address\n"); + return -EINVAL; + } + + rc = smb1360_fg_read(chip, chip->fg_peek_poke_address, &temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't read reg %x rc = %d\n", + chip->fg_peek_poke_address, rc); + return -EAGAIN; + } + *val = temp; + return 0; +} + +static int fg_set_reg(void *data, u64 val) +{ + struct smb1360_chip *chip = data; + int rc; + u8 temp; + + rc = smb1360_select_fg_i2c_address(chip); + if (rc) { + pr_err("Unable to set FG access I2C address\n"); + return -EINVAL; + } + + temp = (u8) val; + rc = smb1360_fg_write(chip, chip->fg_peek_poke_address, temp); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't write 0x%02x to 0x%02x rc= %d\n", + chip->fg_peek_poke_address, temp, rc); + return -EAGAIN; + } + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(fg_poke_poke_debug_ops, fg_get_reg, + fg_set_reg, "0x%02llx\n"); + +#define LAST_CNFG_REG 0x17 +static int show_cnfg_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = 0; addr <= LAST_CNFG_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int cnfg_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_cnfg_regs, chip); +} + +static const struct file_operations cnfg_debugfs_ops = { + .owner = THIS_MODULE, + .open = cnfg_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define FIRST_CMD_REG 0x40 +#define LAST_CMD_REG 0x42 +static int show_cmd_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = FIRST_CMD_REG; addr <= LAST_CMD_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int cmd_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_cmd_regs, chip); +} + +static const struct file_operations cmd_debugfs_ops = { + .owner = THIS_MODULE, + .open = cmd_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define FIRST_STATUS_REG 0x48 +#define LAST_STATUS_REG 0x4B +static int show_status_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = FIRST_STATUS_REG; addr <= LAST_STATUS_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int status_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_status_regs, chip); +} + +static const struct file_operations status_debugfs_ops = { + .owner = THIS_MODULE, + .open = status_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +#define FIRST_IRQ_REG 0x50 +#define LAST_IRQ_REG 0x58 +static int show_irq_stat_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc; + u8 reg; + u8 addr; + + for (addr = FIRST_IRQ_REG; addr <= LAST_IRQ_REG; addr++) { + rc = smb1360_read(chip, addr, ®); + if (!rc) + seq_printf(m, "0x%02x = 0x%02x\n", addr, reg); + } + + return 0; +} + +static int irq_stat_debugfs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_irq_stat_regs, chip); +} + +static const struct file_operations irq_stat_debugfs_ops = { + .owner = THIS_MODULE, + .open = irq_stat_debugfs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int data_8(u8 *reg) +{ + return reg[0]; +} +static int data_16(u8 *reg) +{ + return (reg[1] << 8) | reg[0]; +} +static int data_24(u8 *reg) +{ + return (reg[2] << 16) | (reg[1] << 8) | reg[0]; +} +static int data_28(u8 *reg) +{ + return ((reg[3] & 0xF) << 24) | (reg[2] << 16) | + (reg[1] << 8) | reg[0]; +} +static int data_32(u8 *reg) +{ + return (reg[3] << 24) | (reg[2] << 16) | + (reg[1] << 8) | reg[0]; +} + +struct fg_regs { + int index; + int length; + char *param_name; + int (*calc_func)(u8 *); +}; + +static struct fg_regs fg_scratch_pad[] = { + {0, 2, "v_current_predicted", data_16}, + {2, 2, "v_cutoff_predicted", data_16}, + {4, 2, "v_full_predicted", data_16}, + {6, 2, "ocv_estimate", data_16}, + {8, 2, "rslow_drop", data_16}, + {10, 2, "voltage_old", data_16}, + {12, 2, "current_old", data_16}, + {14, 4, "current_average_full", data_32}, + {18, 2, "temperature", data_16}, + {20, 2, "temp_last_track", data_16}, + {22, 2, "ESR_nominal", data_16}, + {26, 2, "Rslow", data_16}, + {28, 2, "counter_imptr", data_16}, + {30, 2, "counter_pulse", data_16}, + {32, 1, "IRQ_delta_prev", data_8}, + {33, 1, "cap_learning_counter", data_8}, + {34, 4, "Vact_int_error", data_32}, + {38, 3, "SOC_cutoff", data_24}, + {41, 3, "SOC_full", data_24}, + {44, 3, "SOC_auto_rechrge_temp", data_24}, + {47, 3, "Battery_SOC", data_24}, + {50, 4, "CC_SOC", data_28}, + {54, 2, "SOC_filtered", data_16}, + {56, 2, "SOC_Monotonic", data_16}, + {58, 2, "CC_SOC_coeff", data_16}, + {60, 2, "nominal_capacity", data_16}, + {62, 2, "actual_capacity", data_16}, + {68, 1, "temperature_counter", data_8}, + {69, 3, "Vbatt_filtered", data_24}, + {72, 3, "Ibatt_filtered", data_24}, + {75, 2, "Current_CC_shadow", data_16}, + {79, 2, "Ibatt_standby", data_16}, + {82, 1, "Auto_recharge_SOC_threshold", data_8}, + {83, 2, "System_cutoff_voltage", data_16}, + {85, 2, "System_CC_to_CV_voltage", data_16}, + {87, 2, "System_term_current", data_16}, + {89, 2, "System_fake_term_current", data_16}, + {91, 2, "thermistor_c1_coeff", data_16}, +}; + +static struct fg_regs fg_cfg[] = { + {0, 2, "ESR_actual", data_16}, + {4, 1, "IRQ_SOC_max", data_8}, + {5, 1, "IRQ_SOC_min", data_8}, + {6, 1, "IRQ_volt_empty", data_8}, + {7, 1, "Temp_external", data_8}, + {8, 1, "IRQ_delta_threshold", data_8}, + {9, 1, "JIETA_soft_cold", data_8}, + {10, 1, "JIETA_soft_hot", data_8}, + {11, 1, "IRQ_volt_min", data_8}, + {14, 2, "ESR_sys_replace", data_16}, +}; + +static struct fg_regs fg_shdw[] = { + {0, 1, "Latest_battery_info", data_8}, + {1, 1, "Latest_Msys_SOC", data_8}, + {2, 2, "Battery_capacity", data_16}, + {4, 2, "Rslow_drop", data_16}, + {6, 1, "Latest_SOC", data_8}, + {7, 1, "Latest_Cutoff_SOC", data_8}, + {8, 1, "Latest_full_SOC", data_8}, + {9, 2, "Voltage_shadow", data_16}, + {11, 2, "Current_shadow", data_16}, + {13, 2, "Latest_temperature", data_16}, + {15, 1, "Latest_system_sbits", data_8}, +}; + +#define FIRST_FG_CFG_REG 0x20 +#define LAST_FG_CFG_REG 0x2F +#define FIRST_FG_SHDW_REG 0x60 +#define LAST_FG_SHDW_REG 0x6F +#define FG_SCRATCH_PAD_MAX 93 +#define FG_SCRATCH_PAD_BASE_REG 0x80 +#define SMB1360_I2C_READ_LENGTH 32 + +static int smb1360_check_cycle_stretch(struct smb1360_chip *chip) +{ + int rc = 0; + u8 reg; + + rc = smb1360_read(chip, STATUS_4_REG, ®); + if (rc) { + pr_err("Unable to read status regiseter\n"); + } else if (reg & CYCLE_STRETCH_ACTIVE_BIT) { + /* clear cycle stretch */ + rc = smb1360_masked_write(chip, CMD_I2C_REG, + CYCLE_STRETCH_CLEAR_BIT, CYCLE_STRETCH_CLEAR_BIT); + if (rc) + pr_err("Unable to clear cycle stretch\n"); + } + + return rc; +} + +static int show_fg_regs(struct seq_file *m, void *data) +{ + struct smb1360_chip *chip = m->private; + int rc, i, j, rem_length; + u8 reg[FG_SCRATCH_PAD_MAX]; + + rc = smb1360_check_cycle_stretch(chip); + if (rc) + pr_err("Unable to check cycle-stretch\n"); + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't request FG access rc=%d\n", rc); + return rc; + } + + for (i = 0; i < (FG_SCRATCH_PAD_MAX / SMB1360_I2C_READ_LENGTH); i++) { + j = i * SMB1360_I2C_READ_LENGTH; + rc = smb1360_read_bytes(chip, FG_SCRATCH_PAD_BASE_REG + j, + ®[j], SMB1360_I2C_READ_LENGTH); + if (rc) { + pr_err("Couldn't read scratch registers rc=%d\n", rc); + break; + } + } + + j = i * SMB1360_I2C_READ_LENGTH; + rem_length = (FG_SCRATCH_PAD_MAX % SMB1360_I2C_READ_LENGTH); + if (rem_length) { + rc = smb1360_read_bytes(chip, FG_SCRATCH_PAD_BASE_REG + j, + ®[j], rem_length); + if (rc) + pr_err("Couldn't read scratch registers rc=%d\n", rc); + } + + rc = smb1360_disable_fg_access(chip); + if (rc) { + pr_err("Couldn't disable FG access rc=%d\n", rc); + return rc; + } + + rc = smb1360_check_cycle_stretch(chip); + if (rc) + pr_err("Unable to check cycle-stretch\n"); + + + seq_puts(m, "FG scratch-pad registers\n"); + for (i = 0; i < ARRAY_SIZE(fg_scratch_pad); i++) + seq_printf(m, "\t%s = %x\n", fg_scratch_pad[i].param_name, + fg_scratch_pad[i].calc_func(®[fg_scratch_pad[i].index])); + + rem_length = LAST_FG_CFG_REG - FIRST_FG_CFG_REG + 1; + rc = smb1360_read_bytes(chip, FIRST_FG_CFG_REG, + ®[0], rem_length); + if (rc) + pr_err("Couldn't read config registers rc=%d\n", rc); + + seq_puts(m, "FG config registers\n"); + for (i = 0; i < ARRAY_SIZE(fg_cfg); i++) + seq_printf(m, "\t%s = %x\n", fg_cfg[i].param_name, + fg_cfg[i].calc_func(®[fg_cfg[i].index])); + + rem_length = LAST_FG_SHDW_REG - FIRST_FG_SHDW_REG + 1; + rc = smb1360_read_bytes(chip, FIRST_FG_SHDW_REG, + ®[0], rem_length); + if (rc) + pr_err("Couldn't read shadow registers rc=%d\n", rc); + + seq_puts(m, "FG shadow registers\n"); + for (i = 0; i < ARRAY_SIZE(fg_shdw); i++) + seq_printf(m, "\t%s = %x\n", fg_shdw[i].param_name, + fg_shdw[i].calc_func(®[fg_shdw[i].index])); + + return rc; +} + +static int fg_regs_open(struct inode *inode, struct file *file) +{ + struct smb1360_chip *chip = inode->i_private; + + return single_open(file, show_fg_regs, chip); +} + +static const struct file_operations fg_regs_debugfs_ops = { + .owner = THIS_MODULE, + .open = fg_regs_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int smb1360_otg_regulator_enable(struct regulator_dev *rdev) +{ + int rc = 0; + struct smb1360_chip *chip = rdev_get_drvdata(rdev); + + rc = smb1360_masked_write(chip, CMD_CHG_REG, CMD_OTG_EN_BIT, + CMD_OTG_EN_BIT); + if (rc) { + pr_err("Couldn't enable OTG mode rc=%d\n", rc); + return rc; + } + + pr_debug("OTG mode enabled\n"); + /* Enable current gain configuration */ + mutex_lock(&chip->otp_gain_lock); + if (chip->otg_fet_present) { + /* Enable FET */ + gpio_set_value(chip->otg_fet_enable_gpio, 0); + rc = smb1360_otp_gain_config(chip, 3); + if (rc < 0) + pr_err("Couldn't config OTP gain config rc=%d\n", rc); + else + chip->fet_gain_enabled = true; + } + mutex_unlock(&chip->otp_gain_lock); + + return rc; +} + +static int smb1360_otg_regulator_disable(struct regulator_dev *rdev) +{ + int rc = 0; + struct smb1360_chip *chip = rdev_get_drvdata(rdev); + + rc = smb1360_otg_disable(chip); + if (rc) + pr_err("Couldn't disable OTG regulator rc=%d\n", rc); + + pr_debug("OTG mode disabled\n"); + return rc; +} + +static int smb1360_otg_regulator_is_enable(struct regulator_dev *rdev) +{ + u8 reg = 0; + int rc = 0; + struct smb1360_chip *chip = rdev_get_drvdata(rdev); + + rc = smb1360_read(chip, CMD_CHG_REG, ®); + if (rc) { + pr_err("Couldn't read OTG enable bit rc=%d\n", rc); + return rc; + } + + return (reg & CMD_OTG_EN_BIT) ? 1 : 0; +} + +static struct regulator_ops smb1360_otg_reg_ops = { + .enable = smb1360_otg_regulator_enable, + .disable = smb1360_otg_regulator_disable, + .is_enabled = smb1360_otg_regulator_is_enable, +}; + +static int smb1360_regulator_init(struct smb1360_chip *chip) +{ + int rc = 0; + struct regulator_config cfg = {}; + + chip->otg_vreg.rdesc.owner = THIS_MODULE; + chip->otg_vreg.rdesc.type = REGULATOR_VOLTAGE; + chip->otg_vreg.rdesc.ops = &smb1360_otg_reg_ops; + chip->otg_vreg.rdesc.of_match = chip->dev->of_node->name; + chip->otg_vreg.rdesc.name = chip->dev->of_node->name; + + cfg.dev = chip->dev; + cfg.driver_data = chip; + cfg.of_node = chip->dev->of_node; + + chip->otg_vreg.rdev = regulator_register( + &chip->otg_vreg.rdesc, &cfg); + if (IS_ERR(chip->otg_vreg.rdev)) { + rc = PTR_ERR(chip->otg_vreg.rdev); + chip->otg_vreg.rdev = NULL; + if (rc != -EPROBE_DEFER) + dev_err(chip->dev, + "OTG reg failed, rc=%d\n", rc); + } + + return rc; +} + +static int smb1360_check_batt_profile(struct smb1360_chip *chip) +{ + int rc, i, timeout = 50; + u8 reg = 0, loaded_profile, new_profile = 0, bid_mask; + + if (!chip->connected_rid) { + pr_debug("Skip batt-profile loading connected_rid=%d\n", + chip->connected_rid); + return 0; + } + + rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); + if (rc) { + pr_err("Couldn't read FG_BATT_STATUS rc=%d\n", rc); + return rc; + } + + loaded_profile = !!(reg & BATTERY_PROFILE_BIT) ? + BATTERY_PROFILE_B : BATTERY_PROFILE_A; + + pr_debug("fg_batt_status=%x loaded_profile=%d\n", reg, loaded_profile); + + for (i = 0; i < BATTERY_PROFILE_MAX; i++) { + pr_debug("profile=%d profile_rid=%d connected_rid=%d\n", i, + chip->profile_rid[i], + chip->connected_rid); + if (abs(chip->profile_rid[i] - chip->connected_rid) < + (div_u64(chip->connected_rid, 10))) + break; + } + + if (i == BATTERY_PROFILE_MAX) { + pr_err("None of the battery-profiles match the connected-RID\n"); + return 0; + } + + if (i == loaded_profile) { + pr_debug("Loaded Profile-RID == connected-RID\n"); + return 0; + } + + new_profile = (loaded_profile == BATTERY_PROFILE_A) ? + BATTERY_PROFILE_B : BATTERY_PROFILE_A; + bid_mask = (new_profile == BATTERY_PROFILE_A) ? + BATT_PROFILEA_MASK : BATT_PROFILEB_MASK; + pr_info("Loaded Profile-RID != connected-RID, switch-profile old_profile=%d new_profile=%d\n", + loaded_profile, new_profile); + + /* set the BID mask */ + rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, + BATT_PROFILE_SELECT_MASK, bid_mask); + if (rc) { + pr_err("Couldn't reset battery-profile rc=%d\n", rc); + return rc; + } + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("FG access timed-out, rc = %d\n", rc); + return rc; + } + /* delay after handshaking for profile-switch to continue */ + msleep(1500); + + rc = smb1360_force_fg_reset(chip); + if (rc) { + pr_err("Couldn't reset FG rc=%d\n", rc); + goto restore_fg; + } + + rc = smb1360_disable_fg_access(chip); + if (rc) { + pr_err("disable FG access failed, rc = %d\n", rc); + return rc; + } + + timeout = 10; + while (timeout) { + /* delay for profile to change */ + msleep(500); + rc = smb1360_read(chip, SHDW_FG_BATT_STATUS, ®); + if (rc) { + pr_err("Could't read FG_BATT_STATUS rc=%d\n", rc); + return rc; + } + + reg = !!(reg & BATTERY_PROFILE_BIT); + if (reg == new_profile) { + pr_info("New profile=%d loaded\n", new_profile); + break; + } + timeout--; + } + + if (!timeout) { + pr_err("New profile could not be loaded\n"); + return -EBUSY; + } + + return 0; + +restore_fg: + smb1360_disable_fg_access(chip); + return rc; +} + +#define UPDATE_IRQ_STAT(irq_reg, value) \ + handlers[irq_reg - IRQ_A_REG].prev_val = value + +static int determine_initial_status(struct smb1360_chip *chip) +{ + int rc; + u8 reg = 0; + + /* + * It is okay to read the IRQ status as the irq's are + * not registered yet. + */ + chip->batt_present = true; + rc = smb1360_read(chip, IRQ_B_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read IRQ_B_REG rc = %d\n", rc); + return rc; + } + UPDATE_IRQ_STAT(IRQ_B_REG, reg); + + if (reg & IRQ_B_BATT_TERMINAL_BIT || reg & IRQ_B_BATT_MISSING_BIT) + chip->batt_present = false; + + rc = smb1360_read(chip, IRQ_C_REG, ®); + if (rc) { + dev_err(chip->dev, "Couldn't read IRQ_C_REG rc = %d\n", rc); + return rc; + } + UPDATE_IRQ_STAT(IRQ_C_REG, reg); + + if (reg & IRQ_C_CHG_TERM) + chip->batt_full = true; + + rc = smb1360_read(chip, IRQ_A_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read irq A rc = %d\n", rc); + return rc; + } + UPDATE_IRQ_STAT(IRQ_A_REG, reg); + + if (chip->workaround_flags & WRKRND_HARD_JEITA) { + schedule_delayed_work(&chip->jeita_work, 0); + } else { + if (reg & IRQ_A_HOT_HARD_BIT) + chip->batt_hot = true; + if (reg & IRQ_A_COLD_HARD_BIT) + chip->batt_cold = true; + if (!chip->config_hard_thresholds) { + if (reg & IRQ_A_HOT_SOFT_BIT) + chip->batt_warm = true; + if (reg & IRQ_A_COLD_SOFT_BIT) + chip->batt_cool = true; + } + } + + rc = smb1360_read(chip, IRQ_E_REG, ®); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read irq E rc = %d\n", rc); + return rc; + } + UPDATE_IRQ_STAT(IRQ_E_REG, reg); + + /* Check usb charger presence and notify */ + chip->usb_present = (reg & IRQ_E_USBIN_UV_BIT) ? false : true; + /* USB removed */ + if (!chip->usb_present) + extcon_set_cable_state_(chip->extcon, EXTCON_USB, false); + /* USB inserted */ + else + extcon_set_cable_state_(chip->extcon, EXTCON_USB, true); + + power_supply_changed(chip->usb_psy); + return 0; +} + +static int smb1360_fg_config(struct smb1360_chip *chip) +{ + int rc = 0, temp, fcc_mah; + u8 reg = 0, reg2[2]; + + if (chip->fg_reset_at_pon) { + int v_predicted, v_now; + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + return rc; + } + + rc = smb1360_read_bytes(chip, VOLTAGE_PREDICTED_REG, reg2, 2); + if (rc) { + pr_err("Failed to read VOLTAGE_PREDICTED rc=%d\n", rc); + goto disable_fg_reset; + } + v_predicted = (reg2[1] << 8) | reg2[0]; + v_predicted = div_u64(v_predicted * 5000, 0x7FFF); + + rc = smb1360_read_bytes(chip, SHDW_FG_VTG_NOW, reg2, 2); + if (rc) { + pr_err("Failed to read SHDW_FG_VTG_NOW rc=%d\n", rc); + goto disable_fg_reset; + } + v_now = (reg2[1] << 8) | reg2[0]; + v_now = div_u64(v_now * 5000, 0x7FFF); + + pr_debug("v_predicted=%d v_now=%d reset_threshold=%d\n", + v_predicted, v_now, chip->fg_reset_threshold_mv); + + /* + * Reset FG if the predicted voltage is off wrt + * the real-time voltage. + */ + temp = abs(v_predicted - v_now); + if (temp >= chip->fg_reset_threshold_mv) { + pr_info("Resetting FG - v_delta=%d threshold=%d\n", + temp, chip->fg_reset_threshold_mv); + /* delay for the FG access to settle */ + msleep(1500); + rc = smb1360_force_fg_reset(chip); + if (rc) { + pr_err("Couldn't reset FG rc=%d\n", rc); + goto disable_fg_reset; + } + } +disable_fg_reset: + smb1360_disable_fg_access(chip); + } + + /* + * The below IRQ thresholds are not accessible in REV_1 + * of SMB1360. + */ + if (!(chip->workaround_flags & WRKRND_FG_CONFIG_FAIL)) { + if (chip->delta_soc != -EINVAL) { + reg = abs(((chip->delta_soc * MAX_8_BITS) / 100) - 1); + pr_debug("delta_soc=%d reg=%x\n", chip->delta_soc, reg); + rc = smb1360_write(chip, SOC_DELTA_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to SOC_DELTA_REG rc=%d\n", + rc); + return rc; + } + } + + if (chip->soc_min != -EINVAL) { + if (is_between(chip->soc_min, 0, 100)) { + reg = DIV_ROUND_UP(chip->soc_min * MAX_8_BITS, + 100); + pr_debug("soc_min=%d reg=%x\n", + chip->soc_min, reg); + rc = smb1360_write(chip, SOC_MIN_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to SOC_MIN_REG rc=%d\n", + rc); + return rc; + } + } + } + + if (chip->soc_max != -EINVAL) { + if (is_between(chip->soc_max, 0, 100)) { + reg = DIV_ROUND_UP(chip->soc_max * MAX_8_BITS, + 100); + pr_debug("soc_max=%d reg=%x\n", + chip->soc_max, reg); + rc = smb1360_write(chip, SOC_MAX_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to SOC_MAX_REG rc=%d\n", + rc); + return rc; + } + } + } + + if (chip->voltage_min_mv != -EINVAL) { + temp = (chip->voltage_min_mv - 2500) * MAX_8_BITS; + reg = DIV_ROUND_UP(temp, 2500); + pr_debug("voltage_min=%d reg=%x\n", + chip->voltage_min_mv, reg); + rc = smb1360_write(chip, VTG_MIN_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to VTG_MIN_REG rc=%d\n", + rc); + return rc; + } + } + + if (chip->voltage_empty_mv != -EINVAL) { + temp = (chip->voltage_empty_mv - 2500) * MAX_8_BITS; + reg = DIV_ROUND_UP(temp, 2500); + pr_debug("voltage_empty=%d reg=%x\n", + chip->voltage_empty_mv, reg); + rc = smb1360_write(chip, VTG_EMPTY_REG, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to VTG_EMPTY_REG rc=%d\n", + rc); + return rc; + } + } + } + + /* scratch-pad register config */ + if (chip->batt_capacity_mah != -EINVAL + || chip->v_cutoff_mv != -EINVAL + || chip->fg_iterm_ma != -EINVAL + || chip->fg_ibatt_standby_ma != -EINVAL + || chip->fg_thermistor_c1_coeff != -EINVAL + || chip->fg_cc_to_cv_mv != -EINVAL + || chip->fg_auto_recharge_soc != -EINVAL) { + + rc = smb1360_enable_fg_access(chip); + if (rc) { + pr_err("Couldn't enable FG access rc=%d\n", rc); + return rc; + } + + /* Update battery capacity */ + if (chip->batt_capacity_mah != -EINVAL) { + rc = smb1360_read_bytes(chip, ACTUAL_CAPACITY_REG, + reg2, 2); + if (rc) { + pr_err("Failed to read ACTUAL CAPACITY rc=%d\n", + rc); + goto disable_fg; + } + fcc_mah = (reg2[1] << 8) | reg2[0]; + if (fcc_mah == chip->batt_capacity_mah) { + pr_debug("battery capacity correct\n"); + } else { + /* Update the battery capacity */ + reg2[1] = + (chip->batt_capacity_mah & 0xFF00) >> 8; + reg2[0] = (chip->batt_capacity_mah & 0xFF); + rc = smb1360_write_bytes(chip, + ACTUAL_CAPACITY_REG, reg2, 2); + if (rc) { + pr_err("Couldn't write batt-capacity rc=%d\n", + rc); + goto disable_fg; + } + rc = smb1360_write_bytes(chip, + NOMINAL_CAPACITY_REG, reg2, 2); + if (rc) { + pr_err("Couldn't write batt-capacity rc=%d\n", + rc); + goto disable_fg; + } + + /* Update CC to SOC COEFF */ + if (chip->cc_soc_coeff != -EINVAL) { + reg2[1] = + (chip->cc_soc_coeff & 0xFF00) >> 8; + reg2[0] = (chip->cc_soc_coeff & 0xFF); + rc = smb1360_write_bytes(chip, + CC_TO_SOC_COEFF, reg2, 2); + if (rc) { + pr_err("Couldn't write cc_soc_coeff rc=%d\n", + rc); + goto disable_fg; + } + } + } + } + + /* Update cutoff voltage for SOC = 0 */ + if (chip->v_cutoff_mv != -EINVAL) { + temp = (u16) div_u64(chip->v_cutoff_mv * 0x7FFF, 5000); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_SYS_CUTOFF_V_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write cutoff_mv rc=%d\n", rc); + goto disable_fg; + } + } + + /* + * Update FG iterm for SOC = 100, this value is always assumed + * to be -ve + */ + if (chip->fg_iterm_ma != -EINVAL) { + int iterm = chip->fg_iterm_ma * -1; + + temp = (s16) div_s64(iterm * 0x7FFF, 2500); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_ITERM_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write fg_iterm rc=%d\n", rc); + goto disable_fg; + } + } + + /* + * Update FG iterm standby for SOC = 0, this value is always + * assumed to be +ve + */ + if (chip->fg_ibatt_standby_ma != -EINVAL) { + int iterm = chip->fg_ibatt_standby_ma; + + temp = (u16) div_u64(iterm * 0x7FFF, 2500); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_IBATT_STANDBY_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write fg_iterm rc=%d\n", rc); + goto disable_fg; + } + } + + /* Update CC_to_CV voltage threshold */ + if (chip->fg_cc_to_cv_mv != -EINVAL) { + temp = (u16) div_u64(chip->fg_cc_to_cv_mv * 0x7FFF, + 5000); + reg2[1] = (temp & 0xFF00) >> 8; + reg2[0] = temp & 0xFF; + rc = smb1360_write_bytes(chip, FG_CC_TO_CV_V_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write cc_to_cv_mv rc=%d\n", + rc); + goto disable_fg; + } + } + + /* Update the thermistor c1 coefficient */ + if (chip->fg_thermistor_c1_coeff != -EINVAL) { + reg2[1] = (chip->fg_thermistor_c1_coeff & 0xFF00) >> 8; + reg2[0] = (chip->fg_thermistor_c1_coeff & 0xFF); + rc = smb1360_write_bytes(chip, FG_THERM_C1_COEFF_REG, + reg2, 2); + if (rc) { + pr_err("Couldn't write thermistor_c1_coeff rc=%d\n", + rc); + goto disable_fg; + } + } + + /* Update SoC based resume charging threshold */ + if (chip->fg_auto_recharge_soc != -EINVAL) { + rc = smb1360_masked_write(chip, CFG_CHG_FUNC_CTRL_REG, + CHG_RECHG_THRESH_FG_SRC_BIT, + CHG_RECHG_THRESH_FG_SRC_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't write to CFG_CHG_FUNC_CTRL_REG rc=%d\n", + rc); + goto disable_fg; + } + + reg = DIV_ROUND_UP(chip->fg_auto_recharge_soc * + MAX_8_BITS, 100); + pr_debug("fg_auto_recharge_soc=%d reg=%x\n", + chip->fg_auto_recharge_soc, reg); + rc = smb1360_write(chip, FG_AUTO_RECHARGE_SOC, reg); + if (rc) { + dev_err(chip->dev, "Couldn't write to FG_AUTO_RECHARGE_SOC rc=%d\n", + rc); + goto disable_fg; + } + } + +disable_fg: + /* disable FG access */ + smb1360_disable_fg_access(chip); + } + + return rc; +} + +static void smb1360_check_feature_support(struct smb1360_chip *chip) +{ + + if (is_usb100_broken(chip)) { + pr_debug("USB100 is not supported\n"); + chip->workaround_flags |= WRKRND_USB100_FAIL; + } + + /* + * FG Configuration + * + * The REV_1 of the chip does not allow access to + * FG config registers (20-2FH). Set the workaround flag. + * Also, the battery detection does not work when the DCIN is absent, + * add a workaround flag for it. + */ + if (chip->revision == SMB1360_REV_1) { + pr_debug("FG config and Battery detection is not supported\n"); + chip->workaround_flags |= + WRKRND_FG_CONFIG_FAIL | WRKRND_BATT_DET_FAIL; + } +} + +static int smb1360_enable(struct smb1360_chip *chip, bool enable) +{ + int rc = 0; + u8 val = 0, shdn_cmd_polar; + + rc = smb1360_read(chip, SHDN_CTRL_REG, &val); + if (rc < 0) { + dev_err(chip->dev, "Couldn't read 0x1A reg rc = %d\n", rc); + return rc; + } + + /* Ignore if a CMD based shutdown is not enabled */ + if (!(val & SHDN_CMD_USE_BIT)) { + pr_debug("SMB not configured for CMD based shutdown\n"); + return 0; + } + + shdn_cmd_polar = !!(val & SHDN_CMD_POLARITY_BIT); + val = (shdn_cmd_polar ^ enable) ? SHDN_CMD_BIT : 0; + + pr_debug("enable=%d shdn_polarity=%d value=%d\n", enable, + shdn_cmd_polar, val); + + rc = smb1360_masked_write(chip, CMD_IL_REG, SHDN_CMD_BIT, val); + if (rc < 0) + pr_err("Couldn't shutdown smb1360 rc = %d\n", rc); + + return rc; +} + +static inline int smb1360_poweroff(struct smb1360_chip *chip) +{ + pr_debug("power off smb1360\n"); + return smb1360_enable(chip, false); +} + +static inline int smb1360_poweron(struct smb1360_chip *chip) +{ + pr_debug("power on smb1360\n"); + return smb1360_enable(chip, true); +} + +static int smb1360_jeita_init(struct smb1360_chip *chip) +{ + int rc = 0; + int temp; + + if (chip->config_hard_thresholds) { + if (chip->soft_jeita_supported) { + chip->workaround_flags |= WRKRND_HARD_JEITA; + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cool_bat_decidegc, chip->warm_bat_decidegc); + if (rc) { + dev_err(chip->dev, + "Couldn't set jeita threshold\n"); + return rc; + } + } else { + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cold_bat_decidegc, chip->hot_bat_decidegc); + if (rc) { + dev_err(chip->dev, + "Couldn't set jeita threshold\n"); + return rc; + } + } + } else { + if (chip->soft_jeita_supported) { + temp = min(chip->warm_bat_ma, chip->cool_bat_ma); + rc = smb1360_set_jeita_comp_curr(chip, temp); + if (rc) { + dev_err(chip->dev, "Couldn't set comp current\n"); + return rc; + } + + temp = (chip->vfloat_mv - chip->warm_bat_mv) / 10; + rc = smb1360_masked_write(chip, CFG_FVC_REG, + FLT_VTG_COMP_MASK, temp); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set VFLT compensation = %d", + rc); + return rc; + } + + rc = smb1360_set_soft_jeita_threshold(chip, + chip->cool_bat_decidegc, chip->warm_bat_decidegc); + if (rc) { + dev_err(chip->dev, + "Couldn't set jeita threshold\n"); + return rc; + } + + rc = smb1360_soft_jeita_comp_enable(chip, true); + if (rc) { + dev_err(chip->dev, "Couldn't enable jeita\n"); + return rc; + } + } + } + + return rc; +} + +static int smb1360_otp_gain_init(struct smb1360_chip *chip) +{ + int rc = 0, gain_factor; + bool otp_gain_config = false; + + if (chip->rsense_10mohm) { + gain_factor = 2; + otp_gain_config = true; + } + + mutex_lock(&chip->otp_gain_lock); + if (chip->otg_fet_present) { + /* + * Reset current gain to the default value if OTG + * is not enabled + */ + if (!chip->fet_gain_enabled) { + otp_gain_config = true; + gain_factor = 0; + } + } + + if (otp_gain_config) { + rc = smb1360_otp_gain_config(chip, gain_factor); + if (rc < 0) + pr_err("Couldn't config OTP gain rc=%d\n", rc); + } + mutex_unlock(&chip->otp_gain_lock); + + return rc; +} + +static int smb1360_hw_init(struct smb1360_chip *chip) +{ + int rc; + int i; + u8 reg, mask; + + smb1360_check_feature_support(chip); + + rc = smb1360_enable_volatile_writes(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't configure for volatile rc = %d\n", + rc); + return rc; + } + + /* Bring SMB1360 out of shutdown, if it was enabled by default */ + rc = smb1360_poweron(chip); + if (rc < 0) { + pr_err("smb1360 power on failed\n"); + return rc; + } + + /* + * A 2 seconds delay is mandatory after bringing the chip out + * of shutdown. This guarantees that FG is in a proper state. + */ + schedule_delayed_work(&chip->delayed_init_work, + msecs_to_jiffies(SMB1360_POWERON_DELAY_MS)); + + /* + * set chg en by cmd register, set chg en by writing bit 1, + * enable auto pre to fast + */ + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CHG_EN_BY_PIN_BIT + | CHG_EN_ACTIVE_LOW_BIT + | PRE_TO_FAST_REQ_CMD_BIT, + 0); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_CHG_MISC_REG rc=%d\n", rc); + return rc; + } + + /* USB/AC pin settings */ + rc = smb1360_masked_write(chip, CFG_BATT_CHG_ICL_REG, + AC_INPUT_ICL_PIN_BIT + | AC_INPUT_PIN_HIGH_BIT + | RESET_STATE_USB_500, + AC_INPUT_PIN_HIGH_BIT + | RESET_STATE_USB_500); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_BATT_CHG_ICL_REG rc=%d\n", + rc); + return rc; + } + + /* AICL enable and set input-uv glitch flt to 20ms*/ + reg = AICL_ENABLED_BIT | INPUT_UV_GLITCH_FLT_20MS_BIT; + rc = smb1360_masked_write(chip, CFG_GLITCH_FLT_REG, reg, reg); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set CFG_GLITCH_FLT_REG rc=%d\n", + rc); + return rc; + } + + /* set the float voltage */ + if (chip->vfloat_mv != -EINVAL) { + rc = smb1360_float_voltage_set(chip, chip->vfloat_mv); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set float voltage rc = %d\n", rc); + return rc; + } + } + + /* set iterm */ + if (chip->iterm_ma != -EINVAL) { + if (chip->iterm_disabled) { + dev_err(chip->dev, "Error: Both iterm_disabled and iterm_ma set\n"); + return -EINVAL; + } + + if (chip->rsense_10mohm) + chip->iterm_ma /= 2; + + if (chip->iterm_ma < 25) + reg = CHG_ITERM_25MA; + else if (chip->iterm_ma > 200) + reg = CHG_ITERM_200MA; + else + reg = DIV_ROUND_UP(chip->iterm_ma, 25) - 1; + + rc = smb1360_masked_write(chip, CFG_BATT_CHG_REG, + CHG_ITERM_MASK, reg); + if (rc) { + dev_err(chip->dev, "Couldn't set iterm rc = %d\n", rc); + return rc; + } + + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CHG_CURR_TERM_DIS_BIT, 0); + if (rc) { + dev_err(chip->dev, + "Couldn't enable iterm rc = %d\n", rc); + return rc; + } + } else if (chip->iterm_disabled) { + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CHG_CURR_TERM_DIS_BIT, + CHG_CURR_TERM_DIS_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set iterm rc = %d\n", + rc); + return rc; + } + } + + /* set the safety time voltage */ + if (chip->safety_time != -EINVAL) { + if (chip->safety_time == 0) { + /* safety timer disabled */ + rc = smb1360_masked_write(chip, CFG_SFY_TIMER_CTRL_REG, + SAFETY_TIME_DISABLE_BIT, SAFETY_TIME_DISABLE_BIT); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't disable safety timer rc = %d\n", + rc); + return rc; + } + } else { + for (i = 0; i < ARRAY_SIZE(chg_time); i++) { + if (chip->safety_time <= chg_time[i]) { + reg = i << SAFETY_TIME_MINUTES_SHIFT; + break; + } + } + rc = smb1360_masked_write(chip, CFG_SFY_TIMER_CTRL_REG, + SAFETY_TIME_DISABLE_BIT | SAFETY_TIME_MINUTES_MASK, + reg); + if (rc < 0) { + dev_err(chip->dev, + "Couldn't set safety timer rc = %d\n", rc); + return rc; + } + } + } + + /* configure resume threshold, auto recharge and charge inhibit */ + if (chip->resume_delta_mv != -EINVAL) { + if (chip->recharge_disabled && chip->chg_inhibit_disabled) { + dev_err(chip->dev, + "Error: Both recharge_disabled and recharge_mv set\n"); + return -EINVAL; + } + rc = smb1360_recharge_threshold_set(chip, + chip->resume_delta_mv); + if (rc) { + dev_err(chip->dev, + "Couldn't set rechg thresh rc = %d\n", rc); + return rc; + } + } + + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CFG_AUTO_RECHG_DIS_BIT, + chip->recharge_disabled ? + CFG_AUTO_RECHG_DIS_BIT : 0); + if (rc) { + dev_err(chip->dev, "Couldn't set rechg-cfg rc = %d\n", rc); + return rc; + } + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CFG_CHG_INHIBIT_EN_BIT, + chip->chg_inhibit_disabled ? + 0 : CFG_CHG_INHIBIT_EN_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set chg_inhibit rc = %d\n", rc); + return rc; + } + + rc = smb1360_masked_write(chip, CFG_CHG_MISC_REG, + CFG_BAT_OV_ENDS_CHG_CYC, + chip->ov_ends_chg_cycle_disabled ? + 0 : CFG_BAT_OV_ENDS_CHG_CYC); + if (rc) { + dev_err(chip->dev, "Couldn't set bat_ov_ends_charge rc = %d\n" + , rc); + return rc; + } + + /* battery missing detection */ + rc = smb1360_masked_write(chip, CFG_BATT_MISSING_REG, + BATT_MISSING_SRC_THERM_BIT, + BATT_MISSING_SRC_THERM_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set batt_missing config = %d\n", + rc); + return rc; + } + + rc = smb1360_jeita_init(chip); + if (rc < 0) { + dev_err(chip->dev, "Couldn't init jeita, rc = %d\n", rc); + return rc; + } + + /* interrupt enabling - active low */ + if (chip->client->irq) { + mask = CHG_STAT_IRQ_ONLY_BIT + | CHG_STAT_ACTIVE_HIGH_BIT + | CHG_STAT_DISABLE_BIT + | CHG_TEMP_CHG_ERR_BLINK_BIT; + + if (!chip->pulsed_irq) + reg = CHG_STAT_IRQ_ONLY_BIT; + else + reg = CHG_TEMP_CHG_ERR_BLINK_BIT; + rc = smb1360_masked_write(chip, CFG_STAT_CTRL_REG, mask, reg); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set irq config rc = %d\n", + rc); + return rc; + } + + /* enabling only interesting interrupts */ + rc = smb1360_write(chip, IRQ_CFG_REG, + IRQ_BAT_HOT_COLD_HARD_BIT + | IRQ_BAT_HOT_COLD_SOFT_BIT + | IRQ_INTERNAL_TEMPERATURE_BIT + | IRQ_DCIN_UV_BIT + | IRQ_AICL_DONE_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set irq1 config rc = %d\n", + rc); + return rc; + } + + rc = smb1360_write(chip, IRQ2_CFG_REG, + IRQ2_SAFETY_TIMER_BIT + | IRQ2_CHG_ERR_BIT + | IRQ2_CHG_PHASE_CHANGE_BIT + | IRQ2_POWER_OK_BIT + | IRQ2_BATT_MISSING_BIT + | IRQ2_VBAT_LOW_BIT); + if (rc) { + dev_err(chip->dev, "Couldn't set irq2 config rc = %d\n", + rc); + return rc; + } + + rc = smb1360_write(chip, IRQ3_CFG_REG, + IRQ3_FG_ACCESS_OK_BIT + | IRQ3_SOC_CHANGE_BIT + | IRQ3_SOC_MIN_BIT + | IRQ3_SOC_MAX_BIT + | IRQ3_SOC_EMPTY_BIT + | IRQ3_SOC_FULL_BIT); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set irq3 enable rc = %d\n", + rc); + return rc; + } + } + + /* batt-id configuration */ + if (chip->batt_id_disabled) { + mask = BATT_ID_ENABLED_BIT | CHG_BATT_ID_FAIL; + reg = CHG_BATT_ID_FAIL; + rc = smb1360_masked_write(chip, CFG_FG_BATT_CTRL_REG, + mask, reg); + if (rc < 0) { + dev_err(chip->dev, "Couldn't set batt_id_reg rc = %d\n", + rc); + return rc; + } + } + + /* USB OTG current limit configuration */ + if (chip->otg_batt_curr_limit != -EINVAL) { + for (i = 0; i < ARRAY_SIZE(otg_curr_ma); i++) { + if (otg_curr_ma[i] >= chip->otg_batt_curr_limit) + break; + } + + if (i == ARRAY_SIZE(otg_curr_ma)) + i = i - 1; + + rc = smb1360_masked_write(chip, CFG_BATT_CHG_REG, + OTG_CURRENT_MASK, + i << OTG_CURRENT_SHIFT); + if (rc) + pr_err("Couldn't set OTG current limit, rc = %d\n", rc); + } + + rc = smb1360_charging_disable(chip, USER, !!chip->charging_disabled); + if (rc) + dev_err(chip->dev, "Couldn't '%s' charging rc = %d\n", + chip->charging_disabled ? "disable" : "enable", rc); + + if (chip->parallel_charging) { + rc = smb1360_parallel_charger_enable(chip, PARALLEL_USER, + !chip->charging_disabled); + if (rc) + dev_err(chip->dev, "Couldn't '%s' parallel-charging rc = %d\n", + chip->charging_disabled ? "disable" : "enable", rc); + } + + return rc; +} + +static int smb1360_delayed_hw_init(struct smb1360_chip *chip) +{ + int rc; + + pr_debug("delayed hw init start!\n"); + + if (chip->otp_hard_jeita_config) { + rc = smb1360_hard_jeita_otp_init(chip); + if (rc) { + pr_err("Unable to change the OTP hard jeita, rc=%d\n", + rc); + return rc; + } + } + rc = smb1360_check_batt_profile(chip); + if (rc) { + pr_err("Unable to modify battery profile, rc=%d\n", rc); + return rc; + } + + rc = smb1360_otp_gain_init(chip); + if (rc) { + pr_err("Unable to config otp gain, rc=%d\n", rc); + return rc; + } + + rc = smb1360_fg_config(chip); + if (rc) { + pr_err("Couldn't configure FG rc=%d\n", rc); + return rc; + } + + rc = smb1360_check_cycle_stretch(chip); + if (rc) { + pr_err("Unable to check cycle-stretch\n"); + return rc; + } + + pr_debug("delayed hw init complete!\n"); + return rc; +} + +static void smb1360_delayed_init_work_fn(struct work_struct *work) +{ + int rc = 0; + struct smb1360_chip *chip = container_of(work, struct smb1360_chip, + delayed_init_work.work); + + rc = smb1360_delayed_hw_init(chip); + + if (!rc) { + /* + * If the delayed hw init successfully, update battery + * power_supply to make sure the correct SoC reported + * timely. + */ + power_supply_changed(chip->batt_psy); + } else if (rc == -ETIMEDOUT) { + /* + * If the delayed hw init failed causing by waiting for + * FG access timed-out, force a FG reset and queue the + * worker again to retry the initialization. + */ + pr_debug("delayed hw init timed-out, retry!"); + rc = smb1360_force_fg_reset(chip); + if (rc) { + pr_err("couldn't reset FG, rc = %d\n", rc); + return; + } + schedule_delayed_work(&chip->delayed_init_work, 0); + } else { + pr_err("delayed hw init failed, rc=%d\n", rc); + } +} + +static int smb_parse_batt_id(struct smb1360_chip *chip) +{ + int rc = 0, rpull = 0, vref = 0; + int64_t denom, batt_id_uv; + struct device_node *node = chip->dev->of_node; + struct qpnp_vadc_result result; + + chip->vadc_dev = qpnp_get_vadc(chip->dev, "smb1360"); + if (IS_ERR(chip->vadc_dev)) { + rc = PTR_ERR(chip->vadc_dev); + if (rc == -EPROBE_DEFER) + pr_err("vadc not found - defer rc=%d\n", rc); + else + pr_err("vadc property missing, rc=%d\n", rc); + + return rc; + } + + rc = of_property_read_u32(node, "qcom,profile-a-rid-kohm", + &chip->profile_rid[0]); + if (rc < 0) { + pr_err("Couldn't read profile-a-rid-kohm rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,profile-b-rid-kohm", + &chip->profile_rid[1]); + if (rc < 0) { + pr_err("Couldn't read profile-b-rid-kohm rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,batt-id-vref-uv", &vref); + if (rc < 0) { + pr_err("Couldn't read batt-id-vref-uv rc=%d\n", rc); + return rc; + } + + rc = of_property_read_u32(node, "qcom,batt-id-rpullup-kohm", &rpull); + if (rc < 0) { + pr_err("Couldn't read batt-id-rpullup-kohm rc=%d\n", rc); + return rc; + } + + /* read battery ID */ + rc = qpnp_vadc_read(chip->vadc_dev, LR_MUX2_BAT_ID, &result); + if (rc) { + pr_err("error reading batt id channel = %d, rc = %d\n", + LR_MUX2_BAT_ID, rc); + return rc; + } + batt_id_uv = result.physical; + + if (batt_id_uv == 0) { + /* vadc not correct or batt id line grounded, report 0 kohms */ + pr_err("batt_id_uv = 0, batt-id grounded using same profile\n"); + return 0; + } + + denom = div64_s64(vref * 1000000LL, batt_id_uv) - 1000000LL; + if (denom == 0) { + /* batt id connector might be open, return 0 kohms */ + return 0; + } + chip->connected_rid = div64_s64(rpull * 1000000LL + denom/2, denom); + + pr_debug("batt_id_voltage = %lld, connected_rid = %d\n", + batt_id_uv, chip->connected_rid); + + return 0; +} + +/* + * Note the below: + * 1. if both qcom,soft-jeita-supported and qcom,config-hard-thresholds + * are not defined, SMB continues with default OTP configuration. + * 2. if both are enabled, the hard thresholds are modified. + * 3. if only qcom,config-hard-thresholds is defined, the soft JEITA is disabled + * 4. if only qcom,soft-jeita-supported is defined, the soft JEITA thresholds + * are modified. + */ +static int smb1360_parse_jeita_params(struct smb1360_chip *chip) +{ + int rc = 0; + struct device_node *node = chip->dev->of_node; + int temp[2]; + + if (of_property_read_bool(node, "qcom,config-hard-thresholds")) { + rc = of_property_read_u32(node, + "qcom,cold-bat-decidegc", &chip->cold_bat_decidegc); + if (rc) { + pr_err("cold_bat_decidegc property error, rc = %d\n", + rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, + "qcom,hot-bat-decidegc", &chip->hot_bat_decidegc); + if (rc) { + pr_err("hot_bat_decidegc property error, rc = %d\n", + rc); + return -EINVAL; + } + + chip->config_hard_thresholds = true; + pr_debug("config_hard_thresholds = %d, cold_bat_decidegc = %d, hot_bat_decidegc = %d\n", + chip->config_hard_thresholds, chip->cold_bat_decidegc, + chip->hot_bat_decidegc); + } else if (of_property_read_bool(node, "qcom,otp-hard-jeita-config")) { + rc = of_property_read_u32(node, "qcom,otp-cold-bat-decidegc", + &chip->otp_cold_bat_decidegc); + if (rc) { + pr_err("otp-cold-bat-decidegc property error, rc = %d\n", + rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,otp-hot-bat-decidegc", + &chip->otp_hot_bat_decidegc); + + if (rc) { + pr_err("otp-hot-bat-decidegc property error, rc = %d\n", + rc); + return -EINVAL; + } + + chip->otp_hard_jeita_config = true; + rc = of_property_read_u32_array(node, + "qcom,otp-hard-jeita-hysteresis", temp, 2); + if (rc) { + if (rc != -EINVAL) { + pr_err("read otp-hard-jeita-hysteresis failed, rc = %d\n", + rc); + return rc; + } + } else { + chip->cold_hysteresis = temp[0]; + chip->hot_hysteresis = temp[1]; + } + + pr_debug("otp_hard_jeita_config = %d, otp_cold_bat_decidegc = %d\n" + "otp_hot_bat_decidegc = %d, cold_hysteresis = %d\n" + "hot_hysteresis = %d\n", + chip->otp_hard_jeita_config, + chip->otp_cold_bat_decidegc, + chip->otp_hot_bat_decidegc, chip->cold_hysteresis, + chip->hot_hysteresis); + } + + if (of_property_read_bool(node, "qcom,soft-jeita-supported")) { + rc = of_property_read_u32(node, "qcom,warm-bat-decidegc", + &chip->warm_bat_decidegc); + if (rc) { + pr_err("warm_bat_decidegc property error, rc = %d\n", + rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,cool-bat-decidegc", + &chip->cool_bat_decidegc); + if (rc) { + pr_err("cool_bat_decidegc property error, rc = %d\n", + rc); + return -EINVAL; + } + rc = of_property_read_u32(node, "qcom,cool-bat-mv", + &chip->cool_bat_mv); + if (rc) { + pr_err("cool_bat_mv property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,warm-bat-mv", + &chip->warm_bat_mv); + if (rc) { + pr_err("warm_bat_mv property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,cool-bat-ma", + &chip->cool_bat_ma); + if (rc) { + pr_err("cool_bat_ma property error, rc = %d\n", rc); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,warm-bat-ma", + &chip->warm_bat_ma); + + if (rc) { + pr_err("warm_bat_ma property error, rc = %d\n", rc); + return -EINVAL; + } + + chip->soft_jeita_supported = true; + } else { + /* + * If no soft JEITA configuration required from devicetree, + * read the default soft JEITA setting for hard JEITA + * configuration sanity check. + */ + rc = smb1360_get_soft_jeita_threshold(chip, + &chip->cool_bat_decidegc, + &chip->warm_bat_decidegc); + if (rc) { + pr_err("get default soft JEITA threshold failed, rc=%d\n", + rc); + return rc; + } + } + + pr_debug("soft-jeita-enabled = %d, warm-bat-decidegc = %d, cool-bat-decidegc = %d, cool-bat-mv = %d, warm-bat-mv = %d, cool-bat-ma = %d, warm-bat-ma = %d\n", + chip->soft_jeita_supported, chip->warm_bat_decidegc, + chip->cool_bat_decidegc, chip->cool_bat_mv, chip->warm_bat_mv, + chip->cool_bat_ma, chip->warm_bat_ma); + + return rc; +} + +#define MAX_PARALLEL_CURRENT 540 +static int smb1360_parse_parallel_charging_params(struct smb1360_chip *chip) +{ + struct device_node *node = chip->dev->of_node; + + if (of_property_read_bool(node, "qcom,parallel-charging-enabled")) { + + if (!chip->rsense_10mohm) { + pr_err("10mohm-rsense configuration not enabled - parallel-charging disabled\n"); + return 0; + } + chip->parallel_charging = true; + chip->max_parallel_chg_current = MAX_PARALLEL_CURRENT; + of_property_read_u32(node, "qcom,max-parallel-current-ma", + &chip->max_parallel_chg_current); + + pr_debug("Max parallel charger current = %dma\n", + chip->max_parallel_chg_current); + + /* mark the parallel-charger as disabled */ + chip->parallel_chg_disable_status |= PARALLEL_CURRENT; + } + + return 0; +} + +static int smb_parse_dt(struct smb1360_chip *chip) +{ + int rc; + struct device_node *node = chip->dev->of_node; + + if (!node) { + dev_err(chip->dev, "device tree info. missing\n"); + return -EINVAL; + } + + chip->rsense_10mohm = of_property_read_bool(node, "qcom,rsense-10mhom"); + + if (of_property_read_bool(node, "qcom,batt-profile-select")) { + rc = smb_parse_batt_id(chip); + if (rc < 0) { + if (rc != -EPROBE_DEFER) + pr_err("Unable to parse batt-id rc=%d\n", rc); + return rc; + } + } + + chip->otg_fet_present = of_property_read_bool(node, + "qcom,otg-fet-present"); + if (chip->otg_fet_present) { + chip->otg_fet_enable_gpio = of_get_named_gpio(node, + "qcom,otg-fet-enable-gpio", 0); + if (!gpio_is_valid(chip->otg_fet_enable_gpio)) { + if (chip->otg_fet_enable_gpio != -EPROBE_DEFER) + pr_err("Unable to get OTG FET enable gpio=%d\n", + chip->otg_fet_enable_gpio); + return chip->otg_fet_enable_gpio; + } + /* Configure OTG FET control gpio */ + rc = devm_gpio_request_one(chip->dev, + chip->otg_fet_enable_gpio, + GPIOF_OPEN_DRAIN | GPIOF_INIT_HIGH, + "smb1360_otg_fet_gpio"); + if (rc) { + pr_err("Unable to request gpio rc=%d\n", rc); + return rc; + } + } + + chip->pulsed_irq = of_property_read_bool(node, "qcom,stat-pulsed-irq"); + + rc = of_property_read_u32(node, "qcom,float-voltage-mv", + &chip->vfloat_mv); + if (rc < 0) + chip->vfloat_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,charging-timeout", + &chip->safety_time); + if (rc < 0) + chip->safety_time = -EINVAL; + + if (!rc && (chip->safety_time > chg_time[ARRAY_SIZE(chg_time) - 1])) { + dev_err(chip->dev, "Bad charging-timeout %d\n", + chip->safety_time); + return -EINVAL; + } + + rc = of_property_read_u32(node, "qcom,recharge-thresh-mv", + &chip->resume_delta_mv); + if (rc < 0) + chip->resume_delta_mv = -EINVAL; + + chip->recharge_disabled = of_property_read_bool(node, + "qcom,recharge-disabled"); + + rc = of_property_read_u32(node, "qcom,iterm-ma", &chip->iterm_ma); + if (rc < 0) + chip->iterm_ma = -EINVAL; + + chip->iterm_disabled = of_property_read_bool(node, + "qcom,iterm-disabled"); + + chip->chg_inhibit_disabled = of_property_read_bool(node, + "qcom,chg-inhibit-disabled"); + + chip->charging_disabled = of_property_read_bool(node, + "qcom,charging-disabled"); + + chip->batt_id_disabled = of_property_read_bool(node, + "qcom,batt-id-disabled"); + + chip->shdn_after_pwroff = of_property_read_bool(node, + "qcom,shdn-after-pwroff"); + + chip->min_icl_usb100 = of_property_read_bool(node, + "qcom,min-icl-100ma"); + + chip->ov_ends_chg_cycle_disabled = of_property_read_bool(node, + "qcom,disable-ov-ends-chg-cycle"); + + rc = smb1360_parse_parallel_charging_params(chip); + if (rc) { + pr_err("Couldn't parse parallel charginng params rc=%d\n", rc); + return rc; + } + + if (of_find_property(node, "qcom,thermal-mitigation", + &chip->thermal_levels)) { + chip->thermal_mitigation = devm_kzalloc(chip->dev, + chip->thermal_levels, + GFP_KERNEL); + + if (chip->thermal_mitigation == NULL) { + pr_err("thermal mitigation kzalloc() failed.\n"); + return -ENOMEM; + } + + chip->thermal_levels /= sizeof(int); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation", + chip->thermal_mitigation, chip->thermal_levels); + if (rc) { + pr_err("Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + rc = smb1360_parse_jeita_params(chip); + if (rc < 0) { + pr_err("Couldn't parse jeita params, rc = %d\n", rc); + return rc; + } + + /* fg params */ + chip->empty_soc_disabled = of_property_read_bool(node, + "qcom,empty-soc-disabled"); + + rc = of_property_read_u32(node, "qcom,fg-delta-soc", &chip->delta_soc); + if (rc < 0) + chip->delta_soc = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-soc-max", &chip->soc_max); + if (rc < 0) + chip->soc_max = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-soc-min", &chip->soc_min); + if (rc < 0) + chip->soc_min = -EINVAL; + + chip->awake_min_soc = of_property_read_bool(node, + "qcom,awake-min-soc"); + + rc = of_property_read_u32(node, "qcom,fg-voltage-min-mv", + &chip->voltage_min_mv); + if (rc < 0) + chip->voltage_min_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-voltage-empty-mv", + &chip->voltage_empty_mv); + if (rc < 0) + chip->voltage_empty_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-batt-capacity-mah", + &chip->batt_capacity_mah); + if (rc < 0) + chip->batt_capacity_mah = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-cc-soc-coeff", + &chip->cc_soc_coeff); + if (rc < 0) + chip->cc_soc_coeff = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-cutoff-voltage-mv", + &chip->v_cutoff_mv); + if (rc < 0) + chip->v_cutoff_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-iterm-ma", + &chip->fg_iterm_ma); + if (rc < 0) + chip->fg_iterm_ma = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-ibatt-standby-ma", + &chip->fg_ibatt_standby_ma); + if (rc < 0) + chip->fg_ibatt_standby_ma = -EINVAL; + + rc = of_property_read_u32(node, "qcom,thermistor-c1-coeff", + &chip->fg_thermistor_c1_coeff); + if (rc < 0) + chip->fg_thermistor_c1_coeff = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-cc-to-cv-mv", + &chip->fg_cc_to_cv_mv); + if (rc < 0) + chip->fg_cc_to_cv_mv = -EINVAL; + + rc = of_property_read_u32(node, "qcom,otg-batt-curr-limit", + &chip->otg_batt_curr_limit); + if (rc < 0) + chip->otg_batt_curr_limit = -EINVAL; + + rc = of_property_read_u32(node, "qcom,fg-auto-recharge-soc", + &chip->fg_auto_recharge_soc); + if (rc < 0) + chip->fg_auto_recharge_soc = -EINVAL; + + if (of_property_read_bool(node, "qcom,fg-reset-at-pon")) { + chip->fg_reset_at_pon = true; + rc = of_property_read_u32(node, "qcom,fg-reset-thresold-mv", + &chip->fg_reset_threshold_mv); + if (rc) { + pr_debug("FG reset voltage threshold not specified using 50mV\n"); + chip->fg_reset_threshold_mv = FG_RESET_THRESHOLD_MV; + } + } + + return 0; +} + +static int smb1360_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + u8 reg; + int rc; + struct smb1360_chip *chip; + struct power_supply_config batt_psy_cfg = {}; + struct power_supply_config usb_psy_cfg = {}; + + chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->resume_completed = true; + chip->client = client; + chip->dev = &client->dev; + chip->fake_battery_soc = -EINVAL; + chip->usb_supply_type = POWER_SUPPLY_TYPE_UNKNOWN; + + chip->extcon = devm_extcon_dev_allocate(chip->dev, + smb1360_extcon_cable); + if (IS_ERR(chip->extcon)) { + pr_err("failed to allocate extcon device\n"); + rc = PTR_ERR(chip->extcon); + return rc; + } + + rc = devm_extcon_dev_register(chip->dev, chip->extcon); + if (rc) { + pr_err("failed to register extcon device\n"); + return rc; + } + + mutex_init(&chip->read_write_lock); + mutex_init(&chip->parallel_chg_lock); + mutex_init(&chip->otp_gain_lock); + mutex_init(&chip->fg_access_request_lock); + mutex_init(&chip->irq_complete); + mutex_init(&chip->charging_disable_lock); + mutex_init(&chip->current_change_lock); + + INIT_DELAYED_WORK(&chip->jeita_work, smb1360_jeita_work_fn); + INIT_DELAYED_WORK(&chip->delayed_init_work, + smb1360_delayed_init_work_fn); + init_completion(&chip->fg_mem_access_granted); + smb1360_wakeup_src_init(chip); + + chip->usb_psy_d.name = "usb"; + chip->usb_psy_d.type = POWER_SUPPLY_TYPE_USB; + chip->usb_psy_d.get_property = smb1360_usb_get_property; + chip->usb_psy_d.set_property = smb1360_usb_set_property; + chip->usb_psy_d.properties = smb1360_usb_properties; + chip->usb_psy_d.num_properties = ARRAY_SIZE(smb1360_usb_properties); + chip->usb_psy_d.property_is_writeable = smb1360_usb_is_writeable; + + usb_psy_cfg.drv_data = chip; + usb_psy_cfg.num_supplicants = 0; + + chip->usb_psy = devm_power_supply_register(chip->dev, + &chip->usb_psy_d, &usb_psy_cfg); + if (IS_ERR(chip->usb_psy)) { + dev_err(chip->dev, "Unable to register usb_psy rc = %ld\n", + PTR_ERR(chip->usb_psy)); + rc = PTR_ERR(chip->usb_psy); + return rc; + } + + /* probe the device to check if its actually connected */ + rc = smb1360_read(chip, CFG_BATT_CHG_REG, ®); + if (rc) { + pr_err("Failed to detect SMB1360, device may be absent\n"); + goto destroy_mutex; + } + + rc = read_revision(chip, &chip->revision); + if (rc) + dev_err(chip->dev, "Couldn't read revision rc = %d\n", rc); + + rc = smb_parse_dt(chip); + if (rc < 0) { + dev_err(&client->dev, "Unable to parse DT nodes\n"); + goto destroy_mutex; + } + + device_init_wakeup(chip->dev, 1); + i2c_set_clientdata(client, chip); + chip->default_i2c_addr = client->addr; + INIT_WORK(&chip->parallel_work, smb1360_parallel_work); + if (chip->cold_hysteresis || chip->hot_hysteresis) + INIT_WORK(&chip->jeita_hysteresis_work, + smb1360_jeita_hysteresis_work); + + pr_debug("default_i2c_addr=%x\n", chip->default_i2c_addr); + smb1360_otp_backup_pool_init(chip); + rc = smb1360_hw_init(chip); + if (rc < 0) { + dev_err(&client->dev, + "Unable to initialize hardware rc = %d\n", rc); + goto destroy_mutex; + } + + rc = smb1360_regulator_init(chip); + if (rc) { + dev_err(&client->dev, + "Couldn't initialize smb1360 ragulator rc=%d\n", rc); + goto fail_hw_init; + } + + rc = determine_initial_status(chip); + if (rc < 0) { + dev_err(&client->dev, + "Unable to determine init status rc = %d\n", rc); + goto fail_hw_init; + } + + chip->batt_psy_d.name = "battery"; + chip->batt_psy_d.type = POWER_SUPPLY_TYPE_BATTERY; + chip->batt_psy_d.get_property = smb1360_battery_get_property; + chip->batt_psy_d.set_property = smb1360_battery_set_property; + chip->batt_psy_d.properties = smb1360_battery_properties; + chip->batt_psy_d.num_properties = + ARRAY_SIZE(smb1360_battery_properties); + chip->batt_psy_d.property_is_writeable = smb1360_battery_is_writeable; + + batt_psy_cfg.drv_data = chip; + batt_psy_cfg.num_supplicants = 0; + + chip->batt_psy = devm_power_supply_register(chip->dev, + &chip->batt_psy_d, &batt_psy_cfg); + if (IS_ERR(chip->batt_psy)) { + dev_err(&client->dev, "Unable to register batt_psy rc = %ld\n", + PTR_ERR(chip->batt_psy)); + goto unregister_batt_psy; + } + + /* STAT irq configuration */ + if (client->irq) { + rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, + smb1360_stat_handler, IRQF_ONESHOT, + "smb1360_stat_irq", chip); + if (rc < 0) { + dev_err(&client->dev, + "request_irq for irq=%d failed rc = %d\n", + client->irq, rc); + goto unregister_batt_psy; + } + enable_irq_wake(client->irq); + } + + chip->debug_root = debugfs_create_dir("smb1360", NULL); + if (!chip->debug_root) + dev_err(chip->dev, "Couldn't create debug dir\n"); + + if (chip->debug_root) { + struct dentry *ent; + + ent = debugfs_create_file("config_registers", S_IFREG | 0444, + chip->debug_root, chip, + &cnfg_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create cnfg debug file rc = %d\n", + rc); + + ent = debugfs_create_file("status_registers", S_IFREG | 0444, + chip->debug_root, chip, + &status_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create status debug file rc = %d\n", + rc); + + ent = debugfs_create_file("irq_status", S_IFREG | 0444, + chip->debug_root, chip, + &irq_stat_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create irq_stat debug file rc = %d\n", + rc); + + ent = debugfs_create_file("cmd_registers", S_IFREG | 0444, + chip->debug_root, chip, + &cmd_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create cmd debug file rc = %d\n", + rc); + + ent = debugfs_create_file("fg_regs", + S_IFREG | 0444, chip->debug_root, chip, + &fg_regs_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create fg_scratch_pad debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("address", S_IFREG | 0644, + chip->debug_root, + &(chip->peek_poke_address)); + if (!ent) + dev_err(chip->dev, + "Couldn't create address debug file rc = %d\n", + rc); + + ent = debugfs_create_file("data", S_IFREG | 0644, + chip->debug_root, chip, + &poke_poke_debug_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("fg_address", + S_IFREG | 0644, + chip->debug_root, + &(chip->fg_peek_poke_address)); + if (!ent) + dev_err(chip->dev, + "Couldn't create address debug file rc = %d\n", + rc); + + ent = debugfs_create_file("fg_data", + S_IFREG | 0644, + chip->debug_root, chip, + &fg_poke_poke_debug_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("fg_access_type", + S_IFREG | 0644, + chip->debug_root, + &(chip->fg_access_type)); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("skip_writes", + S_IFREG | 0644, + chip->debug_root, + &(chip->skip_writes)); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_x32("skip_reads", + S_IFREG | 0644, + chip->debug_root, + &(chip->skip_reads)); + if (!ent) + dev_err(chip->dev, + "Couldn't create data debug file rc = %d\n", + rc); + + ent = debugfs_create_file("irq_count", S_IFREG | 0444, + chip->debug_root, chip, + &irq_count_debugfs_ops); + if (!ent) + dev_err(chip->dev, + "Couldn't create count debug file rc = %d\n", + rc); + } + + dev_info(chip->dev, "SMB1360 revision=0x%x probe success! batt=%d usb=%d soc=%d\n", + chip->revision, + smb1360_get_prop_batt_present(chip), + chip->usb_present, + smb1360_get_prop_batt_capacity(chip)); + + return 0; + +unregister_batt_psy: + power_supply_unregister(chip->batt_psy); +fail_hw_init: + regulator_unregister(chip->otg_vreg.rdev); +destroy_mutex: + power_supply_unregister(chip->usb_psy); + wakeup_source_trash(&chip->smb1360_ws.source); + mutex_destroy(&chip->read_write_lock); + mutex_destroy(&chip->parallel_chg_lock); + mutex_destroy(&chip->otp_gain_lock); + mutex_destroy(&chip->fg_access_request_lock); + mutex_destroy(&chip->irq_complete); + mutex_destroy(&chip->charging_disable_lock); + mutex_destroy(&chip->current_change_lock); + return rc; +} + +static int smb1360_remove(struct i2c_client *client) +{ + struct smb1360_chip *chip = i2c_get_clientdata(client); + + regulator_unregister(chip->otg_vreg.rdev); + power_supply_unregister(chip->usb_psy); + power_supply_unregister(chip->batt_psy); + wakeup_source_trash(&chip->smb1360_ws.source); + mutex_destroy(&chip->charging_disable_lock); + mutex_destroy(&chip->current_change_lock); + mutex_destroy(&chip->read_write_lock); + mutex_destroy(&chip->parallel_chg_lock); + mutex_destroy(&chip->irq_complete); + mutex_destroy(&chip->otp_gain_lock); + mutex_destroy(&chip->fg_access_request_lock); + debugfs_remove_recursive(chip->debug_root); + + return 0; +} + +static int smb1360_suspend(struct device *dev) +{ + int i, rc; + struct i2c_client *client = to_i2c_client(dev); + struct smb1360_chip *chip = i2c_get_clientdata(client); + + /* Save the current IRQ config */ + for (i = 0; i < 3; i++) { + rc = smb1360_read(chip, IRQ_CFG_REG + i, + &chip->irq_cfg_mask[i]); + if (rc) + pr_err("Couldn't save irq cfg regs rc=%d\n", rc); + } + + /* enable only important IRQs */ + rc = smb1360_write(chip, IRQ_CFG_REG, IRQ_DCIN_UV_BIT + | IRQ_AICL_DONE_BIT + | IRQ_BAT_HOT_COLD_SOFT_BIT + | IRQ_BAT_HOT_COLD_HARD_BIT); + if (rc < 0) + pr_err("Couldn't set irq_cfg rc=%d\n", rc); + + rc = smb1360_write(chip, IRQ2_CFG_REG, IRQ2_BATT_MISSING_BIT + | IRQ2_VBAT_LOW_BIT + | IRQ2_POWER_OK_BIT); + if (rc < 0) + pr_err("Couldn't set irq2_cfg rc=%d\n", rc); + + rc = smb1360_write(chip, IRQ3_CFG_REG, IRQ3_SOC_FULL_BIT + | IRQ3_SOC_MIN_BIT + | IRQ3_SOC_EMPTY_BIT); + if (rc < 0) + pr_err("Couldn't set irq3_cfg rc=%d\n", rc); + + mutex_lock(&chip->irq_complete); + chip->resume_completed = false; + mutex_unlock(&chip->irq_complete); + + return 0; +} + +static int smb1360_suspend_noirq(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct smb1360_chip *chip = i2c_get_clientdata(client); + + if (chip->irq_waiting) { + pr_err_ratelimited("Aborting suspend, an interrupt was detected while suspending\n"); + return -EBUSY; + } + return 0; +} + +static int smb1360_resume(struct device *dev) +{ + int i, rc; + struct i2c_client *client = to_i2c_client(dev); + struct smb1360_chip *chip = i2c_get_clientdata(client); + + /* Restore the IRQ config */ + for (i = 0; i < 3; i++) { + rc = smb1360_write(chip, IRQ_CFG_REG + i, + chip->irq_cfg_mask[i]); + if (rc) + pr_err("Couldn't restore irq cfg regs rc=%d\n", rc); + } + + mutex_lock(&chip->irq_complete); + chip->resume_completed = true; + if (chip->irq_waiting) { + chip->irq_disabled = false; + enable_irq(client->irq); + mutex_unlock(&chip->irq_complete); + smb1360_stat_handler(client->irq, chip); + } else { + mutex_unlock(&chip->irq_complete); + } + + power_supply_changed(chip->batt_psy); + + return 0; +} + +static void smb1360_shutdown(struct i2c_client *client) +{ + int rc; + struct smb1360_chip *chip = i2c_get_clientdata(client); + + rc = smb1360_otg_disable(chip); + if (rc) + pr_err("Couldn't disable OTG mode rc=%d\n", rc); + + if (chip->shdn_after_pwroff) { + rc = smb1360_poweroff(chip); + if (rc) + pr_err("Couldn't shutdown smb1360, rc = %d\n", rc); + pr_info("smb1360 power off\n"); + } +} + +static const struct dev_pm_ops smb1360_pm_ops = { + .resume = smb1360_resume, + .suspend_noirq = smb1360_suspend_noirq, + .suspend = smb1360_suspend, +}; + +static const struct of_device_id smb1360_match_table[] = { + { .compatible = "qcom,smb1360-chg-fg",}, + { }, +}; + +static const struct i2c_device_id smb1360_id[] = { + {"smb1360-chg-fg", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, smb1360_id); + +static struct i2c_driver smb1360_driver = { + .driver = { + .name = "smb1360-chg-fg", + .owner = THIS_MODULE, + .of_match_table = smb1360_match_table, + .pm = &smb1360_pm_ops, + }, + .probe = smb1360_probe, + .remove = smb1360_remove, + .shutdown = smb1360_shutdown, + .id_table = smb1360_id, +}; + +module_i2c_driver(smb1360_driver); + +MODULE_DESCRIPTION("SMB1360 Charger and Fuel Gauge"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("i2c:smb1360-chg-fg"); -- GitLab From 8524efc62cdb3964e13c9f15c701ba4d515fe8f0 Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Fri, 6 Apr 2018 15:37:34 +0530 Subject: [PATCH 1602/1834] ARM: dts: msm: Add extcon support in smb1360 driver Add extcon support in smb1360 device tree for apq8009 based wcd9326 ioe refernce board. Change-Id: Ia6189a323e8d35ab5e67b35b32a7eda27965d6c6 Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts index 9efd8083b01b..a0a9c5457a00 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-mtp-wcd9326-refboard.dts @@ -268,6 +268,7 @@ }; &i2c_4 { + status= "okay"; smb1360_otg_supply: smb1360-chg-fg@14 { compatible = "qcom,smb1360-chg-fg"; reg = <0x14>; @@ -283,15 +284,12 @@ qcom,recharge-thresh-mv = <100>; qcom,thermal-mitigation = <1500 700 600 0>; regulator-name = "smb1360_otg_vreg"; + status= "okay"; }; }; &usb_otg { - interrupts = <0 134 0>, <0 140 0>; - interrupt-names = "core_irq", "async_irq"; - - qcom,hsusb-otg-mode = <3>; - vbus_otg-supply = <&vbus_otg_supply>; + extcon = <&smb1360_otg_supply>; }; &mdss_fb0 { -- GitLab From 85430b99650f80792c135a94ba977c888dc17da5 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 16 Apr 2018 18:58:35 +0530 Subject: [PATCH 1603/1834] platform: qpnp-vibrator: Add support for qpnp-vibrator Initial snapshot of leds-qpnp-vibrator driver is taken from msm-3.18 kernel version @ commit f8b6819d0432d6 ("msm: ipa: Fix to handle NULL pointer dereference") The existing driver supports timed_output which is now obsolete, modify it to support the control interface via the LED class framework. The usage is as below - For example, to enable vibrator for 10 sec $ echo 10000 > /sys/class/leds/vibrator/duration $ echo 1 > /sys/class/leds/vibrator/activate Change-Id: Id9f165256472f5137260129c9ff39c0cd19943ed Signed-off-by: Anindya Sundar Gayen Signed-off-by: Sundara Vinayagam --- drivers/leds/Kconfig | 10 + drivers/leds/Makefile | 1 + drivers/leds/leds-qpnp-vibrator.c | 526 ++++++++++++++++++++++++++++++ 3 files changed, 537 insertions(+) create mode 100644 drivers/leds/leds-qpnp-vibrator.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 787bda3549db..f931a2cdf214 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -723,6 +723,16 @@ config LEDS_QPNP_VIBRATOR_LDO peripheral found on Qualcomm Technologies, Inc. QPNP PMICs. The vibrator-ldo peripheral is capable of driving ERM vibrators. +config LEDS_QPNP_VIBRATOR + tristate "Vibrator support for QPNP PMIC" + depends on LEDS_CLASS && MFD_SPMI_PMIC + help + This option enables device driver support for the vibrator + on the Qualcomm technologies Inc's QPNP PMICs. The vibrator + is connected on the VIB_DRV_N line and can be controlled + manually or by the DTEST lines.It uses the android timed-output + framework. + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index e9eaa50d0b61..31d29f0e26c7 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_LEDS_QPNP_FLASH_V2) += leds-qpnp-flash-v2.o leds-qpnp-flash-common. obj-$(CONFIG_LEDS_QPNP_WLED) += leds-qpnp-wled.o obj-$(CONFIG_LEDS_QPNP_HAPTICS) += leds-qpnp-haptics.o obj-$(CONFIG_LEDS_QPNP_VIBRATOR_LDO) += leds-qpnp-vibrator-ldo.o +obj-$(CONFIG_LEDS_QPNP_VIBRATOR) += leds-qpnp-vibrator.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-qpnp-vibrator.c b/drivers/leds/leds-qpnp-vibrator.c new file mode 100644 index 000000000000..cc2615daf1c1 --- /dev/null +++ b/drivers/leds/leds-qpnp-vibrator.c @@ -0,0 +1,526 @@ +/* Copyright (c) 2013-2015, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QPNP_VIB_VTG_CTL(base) (base + 0x41) +#define QPNP_VIB_EN_CTL(base) (base + 0x46) + +#define QPNP_VIB_MAX_LEVEL 31 +#define QPNP_VIB_MIN_LEVEL 12 + +#define QPNP_VIB_DEFAULT_TIMEOUT 15000 +#define QPNP_VIB_DEFAULT_VTG_LVL 3100 + +#define QPNP_VIB_EN BIT(7) +#define QPNP_VIB_VTG_SET_MASK 0x1F +#define QPNP_VIB_LOGIC_SHIFT 4 + +enum qpnp_vib_mode { + QPNP_VIB_MANUAL, + QPNP_VIB_DTEST1, + QPNP_VIB_DTEST2, + QPNP_VIB_DTEST3, +}; + +struct qpnp_pwm_info { + struct pwm_device *pwm_dev; + u32 pwm_channel; + u32 duty_us; + u32 period_us; +}; + +struct qpnp_vib { + struct platform_device *pdev; + struct regmap *regmap; + struct hrtimer vib_timer; + struct led_classdev cdev; + struct work_struct work; + struct qpnp_pwm_info pwm_info; + enum qpnp_vib_mode mode; + + u8 reg_vtg_ctl; + u8 reg_en_ctl; + u8 active_low; + u16 base; + int state; + int vtg_level; + int timeout; + u32 vib_play_ms; + struct mutex lock; +}; + +static int qpnp_vib_read_u8(struct qpnp_vib *vib, u8 *data, u16 reg) +{ + int rc; + + rc = regmap_read(vib->regmap, reg, (unsigned int *)data); + if (rc < 0) + dev_err(&vib->pdev->dev, + "Error reading address: %X - ret %X\n", reg, rc); + + return rc; +} + +static int qpnp_vib_write_u8(struct qpnp_vib *vib, u8 *data, u16 reg) +{ + int rc; + + rc = regmap_write(vib->regmap, reg, (unsigned int)*data); + if (rc < 0) + dev_err(&vib->pdev->dev, + "Error writing address: %X - ret %X\n", reg, rc); + + return rc; +} + +static int qpnp_vibrator_config(struct qpnp_vib *vib) +{ + u8 reg = 0; + int rc; + + /* Configure the VTG CTL regiser */ + rc = qpnp_vib_read_u8(vib, ®, QPNP_VIB_VTG_CTL(vib->base)); + if (rc < 0) + return rc; + reg &= ~QPNP_VIB_VTG_SET_MASK; + reg |= (vib->vtg_level & QPNP_VIB_VTG_SET_MASK); + rc = qpnp_vib_write_u8(vib, ®, QPNP_VIB_VTG_CTL(vib->base)); + if (rc) + return rc; + vib->reg_vtg_ctl = reg; + + /* Configure the VIB ENABLE regiser */ + rc = qpnp_vib_read_u8(vib, ®, QPNP_VIB_EN_CTL(vib->base)); + if (rc < 0) + return rc; + reg |= (!!vib->active_low) << QPNP_VIB_LOGIC_SHIFT; + if (vib->mode != QPNP_VIB_MANUAL) { + vib->pwm_info.pwm_dev = pwm_request(vib->pwm_info.pwm_channel, + "qpnp-vib"); + if (IS_ERR_OR_NULL(vib->pwm_info.pwm_dev)) { + dev_err(&vib->pdev->dev, "vib pwm request failed\n"); + return -ENODEV; + } + + rc = pwm_config(vib->pwm_info.pwm_dev, vib->pwm_info.duty_us, + vib->pwm_info.period_us); + if (rc < 0) { + dev_err(&vib->pdev->dev, "vib pwm config failed\n"); + pwm_free(vib->pwm_info.pwm_dev); + return -ENODEV; + } + + reg |= BIT(vib->mode - 1); + } + + rc = qpnp_vib_write_u8(vib, ®, QPNP_VIB_EN_CTL(vib->base)); + if (rc < 0) + return rc; + vib->reg_en_ctl = reg; + + return rc; +} + +static int qpnp_vib_set(struct qpnp_vib *vib, int on) +{ + int rc; + u8 val; + + if (on) { + if (vib->mode != QPNP_VIB_MANUAL) { + pwm_enable(vib->pwm_info.pwm_dev); + } else { + val = vib->reg_en_ctl; + val |= QPNP_VIB_EN; + rc = qpnp_vib_write_u8(vib, &val, + QPNP_VIB_EN_CTL(vib->base)); + if (rc < 0) + return rc; + vib->reg_en_ctl = val; + } + } else { + if (vib->mode != QPNP_VIB_MANUAL) { + pwm_disable(vib->pwm_info.pwm_dev); + } else { + val = vib->reg_en_ctl; + val &= ~QPNP_VIB_EN; + rc = qpnp_vib_write_u8(vib, &val, + QPNP_VIB_EN_CTL(vib->base)); + if (rc < 0) + return rc; + vib->reg_en_ctl = val; + } + } + + return 0; +} + +static void qpnp_vib_update(struct work_struct *work) +{ + struct qpnp_vib *vib = container_of(work, struct qpnp_vib, + work); + qpnp_vib_set(vib, vib->state); +} + +static enum hrtimer_restart qpnp_vib_timer_func(struct hrtimer *timer) +{ + struct qpnp_vib *vib = container_of(timer, struct qpnp_vib, + vib_timer); + + vib->state = 0; + schedule_work(&vib->work); + + return HRTIMER_NORESTART; +} + +#ifdef CONFIG_PM +static int qpnp_vibrator_suspend(struct device *dev) +{ + struct qpnp_vib *vib = dev_get_drvdata(dev); + + hrtimer_cancel(&vib->vib_timer); + cancel_work_sync(&vib->work); + /* turn-off vibrator */ + qpnp_vib_set(vib, 0); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(qpnp_vibrator_pm_ops, qpnp_vibrator_suspend, NULL); + +static int qpnp_vib_parse_dt(struct qpnp_vib *vib) +{ + struct platform_device *pdev = vib->pdev; + struct device_node *node = pdev->dev.of_node; + const char *mode; + u32 temp_val; + int rc; + + vib->timeout = QPNP_VIB_DEFAULT_TIMEOUT; + + rc = of_property_read_u32(node, "reg", &temp_val); + if (rc < 0) { + dev_err(&pdev->dev, + "Couldn't find reg in node = %s rc = %d\n", + node->full_name, rc); + return rc; + } + vib->base = temp_val; + + rc = of_property_read_u32(node, + "qcom,vib-timeout-ms", &temp_val); + if (!rc) { + vib->timeout = temp_val; + } else if (rc != -EINVAL) { + dev_err(&pdev->dev, "Unable to read vib timeout\n"); + return rc; + } + + vib->vtg_level = QPNP_VIB_DEFAULT_VTG_LVL; + rc = of_property_read_u32(node, + "qcom,vib-vtg-level-mV", &temp_val); + if (!rc) { + vib->vtg_level = temp_val; + } else if (rc != -EINVAL) { + dev_err(&pdev->dev, "Unable to read vtg level\n"); + return rc; + } + + vib->vtg_level /= 100; + if (vib->vtg_level < QPNP_VIB_MIN_LEVEL) + vib->vtg_level = QPNP_VIB_MIN_LEVEL; + else if (vib->vtg_level > QPNP_VIB_MAX_LEVEL) + vib->vtg_level = QPNP_VIB_MAX_LEVEL; + + vib->mode = QPNP_VIB_MANUAL; + rc = of_property_read_string(node, "qcom,mode", &mode); + if (!rc) { + if (strcmp(mode, "manual") == 0) { + vib->mode = QPNP_VIB_MANUAL; + } else if (strcmp(mode, "dtest1") == 0) { + vib->mode = QPNP_VIB_DTEST1; + } else if (strcmp(mode, "dtest2") == 0) { + vib->mode = QPNP_VIB_DTEST2; + } else if (strcmp(mode, "dtest3") == 0) { + vib->mode = QPNP_VIB_DTEST3; + } else { + dev_err(&pdev->dev, "Invalid mode\n"); + return -EINVAL; + } + } else if (rc != -EINVAL) { + dev_err(&pdev->dev, "Unable to read mode\n"); + return rc; + } + + if (vib->mode != QPNP_VIB_MANUAL) { + rc = of_property_read_u32(node, + "qcom,pwm-channel", &temp_val); + if (!rc) + vib->pwm_info.pwm_channel = temp_val; + else + return rc; + + rc = of_property_read_u32(node, + "qcom,period-us", &temp_val); + if (!rc) + vib->pwm_info.period_us = temp_val; + else + return rc; + + rc = of_property_read_u32(node, + "qcom,duty-us", &temp_val); + if (!rc) + vib->pwm_info.duty_us = temp_val; + else + return rc; + } + + vib->active_low = of_property_read_bool(node, + "qcom,active-low"); + + return 0; +} + +static ssize_t qpnp_vib_get_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct qpnp_vib *chip = container_of(cdev, struct qpnp_vib, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", !!chip->reg_en_ctl); +} + +static ssize_t qpnp_vib_get_duration(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct qpnp_vib *vib = container_of(cdev, struct qpnp_vib, cdev); + ktime_t time_rem; + s64 time_us = 0; + + if (hrtimer_active(&vib->vib_timer)) { + time_rem = hrtimer_get_remaining(&vib->vib_timer); + time_us = ktime_to_us(time_rem); + } + + return snprintf(buf, PAGE_SIZE, "%lld\n", div_s64(time_us, 1000)); +} + + +static ssize_t qpnp_vib_set_duration(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct qpnp_vib *vib = container_of(cdev, struct qpnp_vib, cdev); + u32 value; + int rc; + + rc = kstrtouint(buf, 0, &value); + if (rc < 0) + return rc; + + /* setting 0 on duration is NOP for now */ + if (value <= 0) + return count; + + if (value > vib->timeout) + value = vib->timeout; + + mutex_lock(&vib->lock); + vib->vib_play_ms = value; + mutex_unlock(&vib->lock); + return count; +} + +static ssize_t qpnp_vib_get_activate(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct qpnp_vib *vib = container_of(cdev, struct qpnp_vib, cdev); + + return snprintf(buf, PAGE_SIZE, "%d\n", vib->state); +} + +static ssize_t qpnp_vib_set_activate(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct qpnp_vib *vib = container_of(cdev, struct qpnp_vib, cdev); + u32 value; + int rc; + + rc = kstrtouint(buf, 0, &value); + if (rc < 0) + return rc; + + if (value != 0 && value != 1) + return count; + + vib->state = value; + pr_debug("state = %d, time = %ums\n", vib->state, + vib->vib_play_ms); + mutex_lock(&vib->lock); + if (vib->state) { + hrtimer_cancel(&vib->vib_timer); + hrtimer_start(&vib->vib_timer, + ktime_set(vib->vib_play_ms / 1000, + (vib->vib_play_ms % 1000) * 1000000), + HRTIMER_MODE_REL); + } + vib->vib_play_ms = 0; + mutex_unlock(&vib->lock); + schedule_work(&vib->work); + + return count; +} + +static struct device_attribute qpnp_vib_attrs[] = { + __ATTR(state, 0444, qpnp_vib_get_state, NULL), + __ATTR(duration, 0664, qpnp_vib_get_duration, qpnp_vib_set_duration), + __ATTR(activate, 0664, qpnp_vib_get_activate, qpnp_vib_set_activate), +}; + +/* Dummy functions for brightness */ +static +enum led_brightness qpnp_brightness_get(struct led_classdev *cdev) +{ + return 0; +} + +static void qpnp_brightness_set(struct led_classdev *cdev, + enum led_brightness level) +{ + +} + +static int qpnp_vibrator_probe(struct platform_device *pdev) +{ + struct qpnp_vib *vib; + int rc; + int i; + + vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); + if (!vib) + return -ENOMEM; + + vib->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!vib->regmap) { + dev_err(&pdev->dev, "Couldn't get parent's regmap\n"); + return -EINVAL; + } + + vib->pdev = pdev; + + rc = qpnp_vib_parse_dt(vib); + if (rc) { + dev_err(&pdev->dev, "DT parsing failed\n"); + return rc; + } + + rc = qpnp_vibrator_config(vib); + if (rc) { + dev_err(&pdev->dev, "vib config failed\n"); + return rc; + } + + mutex_init(&vib->lock); + INIT_WORK(&vib->work, qpnp_vib_update); + + hrtimer_init(&vib->vib_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + vib->vib_timer.function = qpnp_vib_timer_func; + + vib->cdev.name = "vibrator"; + vib->cdev.brightness_get = qpnp_brightness_get; + vib->cdev.brightness_set = qpnp_brightness_set; + vib->cdev.max_brightness = 100; + rc = devm_led_classdev_register(&pdev->dev, &vib->cdev); + if (rc < 0) { + dev_err(&pdev->dev, "Error in registering led class device, rc=%d\n", + rc); + goto led_reg_fail; + } + + /* Enabling sysfs entries */ + for (i = 0; i < ARRAY_SIZE(qpnp_vib_attrs); i++) { + rc = sysfs_create_file(&vib->cdev.dev->kobj, + &qpnp_vib_attrs[i].attr); + if (rc < 0) { + dev_err(&pdev->dev, "Error in creating sysfs file, rc=%d\n", + rc); + goto sysfs_fail; + } + } + + dev_set_drvdata(&pdev->dev, vib); + return rc; + +sysfs_fail: + dev_set_drvdata(&pdev->dev, NULL); +led_reg_fail: + hrtimer_cancel(&vib->vib_timer); + cancel_work_sync(&vib->work); + mutex_destroy(&vib->lock); + return -EINVAL; +} + +static int qpnp_vibrator_remove(struct platform_device *pdev) +{ + struct qpnp_vib *vib = dev_get_drvdata(&pdev->dev); + int i; + +/* Removing sysfs entries */ + for (i = 0; i < ARRAY_SIZE(qpnp_vib_attrs); i++) + sysfs_remove_file(&vib->cdev.dev->kobj, + &qpnp_vib_attrs[i].attr); + + dev_set_drvdata(&pdev->dev, NULL); + hrtimer_cancel(&vib->vib_timer); + cancel_work_sync(&vib->work); + mutex_destroy(&vib->lock); + return 0; +} + +static const struct of_device_id spmi_match_table[] = { + { .compatible = "qcom,qpnp-vibrator", + }, + {} +}; + +static struct platform_driver qpnp_vibrator_driver = { + .driver = { + .name = "qcom,qpnp-vibrator", + .of_match_table = spmi_match_table, + .pm = &qpnp_vibrator_pm_ops, + }, + .probe = qpnp_vibrator_probe, + .remove = qpnp_vibrator_remove, +}; + +module_platform_driver(qpnp_vibrator_driver); + +MODULE_DESCRIPTION("qpnp vibrator driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 259d7628b859639a7ef347dfc75fbc96788b0946 Mon Sep 17 00:00:00 2001 From: Anindya Sundar Gayen Date: Mon, 23 Apr 2018 16:40:56 +0530 Subject: [PATCH 1604/1834] ARM: defconfig: Add initial config files for APQ8009 Initial snapshot of msm8909_defconfig is taken from msm-4.9 kernel version @ commit 42dd3842913785 ("ARM: defconfig: Add the initial config files for MSM8908W") Add regular and perf defconfig for APQ8009. Change-Id: I705f4639ca7c5e8f2161f107d19e8b64d4783c59 Signed-off-by: Anindya Sundar Gayen Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909-perf_defconfig | 482 ++++++++++++++++++++++ arch/arm/configs/msm8909_defconfig | 507 ++++++++++++++++++++++++ 2 files changed, 989 insertions(+) create mode 100644 arch/arm/configs/msm8909-perf_defconfig create mode 100644 arch/arm/configs/msm8909_defconfig diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig new file mode 100644 index 000000000000..44343dfde3f6 --- /dev/null +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -0,0 +1,482 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_BZIP2 is not set +# CONFIG_RD_LZMA is not set +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +# CONFIG_MEMBARRIER is not set +CONFIG_EMBEDDED=y +# CONFIG_COMPAT_BRK is not set +CONFIG_PROFILING=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_ARCH_MMAP_RND_BITS=16 +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8909=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8909=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_QCOM_RPM=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QCOM_RPM=y +CONFIG_REGULATOR_QCOM_SPMI=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_FB=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_DWC3=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_SYNC_FILE=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_PM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_TRACER_PKT=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_PWM=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_WARN=2048 +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +# CONFIG_DEBUG_PREEMPT is not set +# CONFIG_FTRACE is not set +CONFIG_LKDTM=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y +# CONFIG_ARM_UNWIND is not set +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y +CONFIG_XZ_DEC=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig new file mode 100644 index 000000000000..c075657198b1 --- /dev/null +++ b/arch/arm/configs/msm8909_defconfig @@ -0,0 +1,507 @@ +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_DELAY_ACCT=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_DEBUG=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +CONFIG_PROFILING=y +CONFIG_OPROFILE=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8909=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_HIGHMEM=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +CONFIG_PM_DEBUG=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CT_PROTO_DCCP=y +CONFIG_NF_CT_PROTO_SCTP=y +CONFIG_NF_CT_PROTO_UDPLITE=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QTAGUID=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_L2TP=y +CONFIG_L2TP_DEBUGFS=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_DNS_RESOLVER=y +CONFIG_RMNET_DATA=y +CONFIG_RMNET_DATA_FC=y +CONFIG_RMNET_DATA_DEBUG_PKT=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_IPC_ROUTER=y +CONFIG_IPC_ROUTER_SECURITY=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_DMA_CMA=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_LOGGING=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_SCSI_UFSHCD_CMD_LOGGING=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_DEBUG=y +CONFIG_DM_CRYPT=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_NETDEVICES=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +CONFIG_INPUT_JOYSTICK=y +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_HS=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_MSM_V2=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8909=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_QCOM_RPM=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QCOM_RPM=y +CONFIG_REGULATOR_QCOM_SPMI=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_FB=y +CONFIG_FB_VIRTUAL=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_A4TECH=y +CONFIG_HID_APPLE=y +CONFIG_HID_BELKIN=y +CONFIG_HID_CHERRY=y +CONFIG_HID_CHICONY=y +CONFIG_HID_CYPRESS=y +CONFIG_HID_ELECOM=y +CONFIG_HID_EZKEY=y +CONFIG_HID_KENSINGTON=y +CONFIG_HID_LOGITECH=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MONTEREY=y +CONFIG_HID_MULTITOUCH=y +CONFIG_USB_DWC3=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_QUSB_PHY=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DEBUG_FILES=y +CONFIG_USB_GADGET_DEBUG_FS=y +CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_MMC=y +CONFIG_MMC_PERF_PROFILING=y +CONFIG_MMC_RING_BUFFER=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_TEST=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_SYNC_FILE=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_REVID=y +CONFIG_USB_BAM=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_PM=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_MSM_CORE_HANG_DETECT=y +CONFIG_MSM_GLADIATOR_HANG_DETECT=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_GLINK=y +CONFIG_MSM_GLINK_LOOPBACK_SERVER=y +CONFIG_MSM_GLINK_SMEM_NATIVE_XPRT=y +CONFIG_MSM_GLINK_SPI_XPRT=y +CONFIG_TRACER_PKT=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_IPC_ROUTER_SMD_XPRT=y +CONFIG_MSM_IPC_ROUTER_GLINK_XPRT=y +CONFIG_MSM_QMI_INTERFACE=y +CONFIG_MSM_GLINK_PKT=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_PWM=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_WARN=2048 +CONFIG_PAGE_OWNER=y +CONFIG_PAGE_OWNER_ENABLE_DEFAULT=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_PAGEALLOC=y +CONFIG_SLUB_DEBUG_PANIC_ON=y +CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_FREE=y +CONFIG_DEBUG_OBJECTS_TIMERS=y +CONFIG_DEBUG_OBJECTS_WORK=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_DEBUG_OBJECTS_PERCPU_COUNTER=y +CONFIG_SLUB_DEBUG_ON=y +CONFIG_DEBUG_KMEMLEAK=y +CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=4000 +CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_DEBUG_MEMORY_INIT=y +CONFIG_LOCKUP_DETECTOR=y +# CONFIG_DETECT_HUNG_TASK is not set +CONFIG_WQ_WATCHDOG=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_PANIC_ON_SCHED_BUG=y +CONFIG_PANIC_ON_RT_THROTTLING=y +CONFIG_SCHEDSTATS=y +CONFIG_SCHED_STACK_END_CHECK=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_MUTEXES=y +CONFIG_DEBUG_ATOMIC_SLEEP=y +CONFIG_DEBUG_LIST=y +CONFIG_FAULT_INJECTION=y +CONFIG_FAIL_PAGE_ALLOC=y +CONFIG_FAULT_INJECTION_DEBUG_FS=y +CONFIG_FAULT_INJECTION_STACKTRACE_FILTER=y +CONFIG_IPC_LOGGING=y +CONFIG_QCOM_RTB=y +CONFIG_QCOM_RTB_SEPARATE_CPUS=y +CONFIG_FUNCTION_TRACER=y +CONFIG_IRQSOFF_TRACER=y +CONFIG_PREEMPT_TRACER=y +CONFIG_BLK_DEV_IO_TRACE=y +CONFIG_CPU_FREQ_SWITCH_PROFILER=y +CONFIG_LKDTM=y +CONFIG_MEMTEST=y +CONFIG_PANIC_ON_DATA_CORRUPTION=y +CONFIG_DEBUG_USER=y +CONFIG_PID_IN_CONTEXTIDR=y +CONFIG_DEBUG_SET_MODULE_RONX=y +CONFIG_CORESIGHT=y +CONFIG_CORESIGHT_REMOTE_ETM=y +CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 +CONFIG_CORESIGHT_STM=y +CONFIG_CORESIGHT_TPDA=y +CONFIG_CORESIGHT_TPDM=y +CONFIG_CORESIGHT_CTI=y +CONFIG_CORESIGHT_EVENT=y +CONFIG_CORESIGHT_HWEVENT=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_LSM_MMAP_MIN_ADDR=4096 +CONFIG_HARDENED_USERCOPY=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_SECURITY_APPARMOR=y +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_CRYPTO_CTR=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_OTA_CRYPTO=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y +CONFIG_QMI_ENCDEC=y -- GitLab From 39917b014a2d3ebd6c875767089145ab42e3c7bf Mon Sep 17 00:00:00 2001 From: Anindya Sundar Gayen Date: Tue, 24 Apr 2018 16:29:47 +0530 Subject: [PATCH 1605/1834] ARM: defconfig: Add support for PM8916 components Add support for vibrator, adb, rtc, pwm, linear charger, vmbms, qpnp-regulator. Change-Id: Ifb1e51036c64f63d6f7f63d7e370cf847d1fde0f Signed-off-by: Anindya Sundar Gayen Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909-perf_defconfig | 17 +++++++++++++++++ arch/arm/configs/msm8909_defconfig | 17 +++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 44343dfde3f6..6f3cee42936d 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -290,6 +290,9 @@ CONFIG_POWER_RESET=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB1360_CHARGER_FG=y +CONFIG_QPNP_VM_BMS=y +CONFIG_QPNP_LINEAR_CHARGER=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y CONFIG_THERMAL_QPNP=y @@ -307,6 +310,7 @@ CONFIG_REGULATOR_QCOM_SPMI=y CONFIG_REGULATOR_CPR=y CONFIG_REGULATOR_MEM_ACC=y CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP=y CONFIG_REGULATOR_RPM_SMD=y CONFIG_REGULATOR_SPM=y CONFIG_REGULATOR_STUB=y @@ -348,6 +352,13 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CI13XXX_MSM=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_RING_BUFFER=y @@ -359,6 +370,11 @@ CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_VIBRATOR=y +CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y @@ -408,6 +424,7 @@ CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_PWM=y +CONFIG_PWM_QPNP=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index c075657198b1..f57e45dbbd6f 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -285,6 +285,9 @@ CONFIG_POWER_RESET=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_SUPPLY=y +CONFIG_SMB1360_CHARGER_FG=y +CONFIG_QPNP_VM_BMS=y +CONFIG_QPNP_LINEAR_CHARGER=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y CONFIG_THERMAL_QPNP=y @@ -302,6 +305,7 @@ CONFIG_REGULATOR_QCOM_SPMI=y CONFIG_REGULATOR_CPR=y CONFIG_REGULATOR_MEM_ACC=y CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP=y CONFIG_REGULATOR_RPM_SMD=y CONFIG_REGULATOR_SPM=y CONFIG_REGULATOR_STUB=y @@ -343,6 +347,13 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y CONFIG_USB_GADGET_VBUS_DRAW=500 +CONFIG_USB_CI13XXX_MSM=y +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_SERIAL=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_RING_BUFFER=y @@ -354,6 +365,11 @@ CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_VIBRATOR=y +CONFIG_LEDS_TRIGGERS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_QPNP=y CONFIG_DMADEVICES=y @@ -403,6 +419,7 @@ CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_PWM=y +CONFIG_PWM_QPNP=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y -- GitLab From 3c04a67ccabf45ce1640b516773032a4cdabb488 Mon Sep 17 00:00:00 2001 From: Jitendra Sharma Date: Tue, 1 May 2018 12:05:52 +0530 Subject: [PATCH 1606/1834] soc: qcom: Reset string table index for each dump collection request Section name should be placed in String table. Currently, we used static version for string table index to update subsequent section names. Due to this string table index keeps on increasing during every new dump(subsystem restart) request. This ultimately will result in buffer overflow, leading to Redzone overwritten. Hence, as a fix, now reset, this string table index once dump capture is complete. Change-Id: Ibc2446ae4011db5291044eacdc1a1119597d862a Signed-off-by: Jitendra Sharma --- drivers/soc/qcom/ramdump.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/soc/qcom/ramdump.c b/drivers/soc/qcom/ramdump.c index 7758c64fb9ab..789eee75e0cb 100644 --- a/drivers/soc/qcom/ramdump.c +++ b/drivers/soc/qcom/ramdump.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -455,19 +455,19 @@ static int _do_ramdump(void *handle, struct ramdump_segment *segments, } static inline unsigned int set_section_name(const char *name, - struct elfhdr *ehdr) + struct elfhdr *ehdr, + int *strtable_idx) { char *strtab = elf_str_table(ehdr); - static int strtable_idx = 1; int idx, ret = 0; - idx = strtable_idx; + idx = *strtable_idx; if ((strtab == NULL) || (name == NULL)) return 0; ret = idx; idx += strlcpy((strtab + idx), name, MAX_NAME_LENGTH); - strtable_idx = idx + 1; + *strtable_idx = idx + 1; return ret; } @@ -480,6 +480,7 @@ static int _do_minidump(void *handle, struct ramdump_segment *segments, struct elfhdr *ehdr; struct elf_shdr *shdr; unsigned long offset, strtbl_off; + int strtable_idx = 1; if (!rd_dev->consumer_present) { pr_err("Ramdump(%s): No consumers. Aborting..\n", rd_dev->name); @@ -519,13 +520,14 @@ static int _do_minidump(void *handle, struct ramdump_segment *segments, shdr->sh_size = MAX_STRTBL_SIZE; shdr->sh_entsize = 0; shdr->sh_flags = 0; - shdr->sh_name = set_section_name("STR_TBL", ehdr); + shdr->sh_name = set_section_name("STR_TBL", ehdr, &strtable_idx); shdr++; for (i = 0; i < nsegments; i++, shdr++) { /* Update elf header */ shdr->sh_type = SHT_PROGBITS; - shdr->sh_name = set_section_name(segments[i].name, ehdr); + shdr->sh_name = set_section_name(segments[i].name, ehdr, + &strtable_idx); shdr->sh_addr = (elf_addr_t)segments[i].address; shdr->sh_size = segments[i].size; shdr->sh_flags = SHF_WRITE; -- GitLab From 26b053beb418a2ffd74ed12a404acc9b13ef7339 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Wed, 2 May 2018 19:50:42 +0530 Subject: [PATCH 1607/1834] usb: ehci-hcd: Fix ehci shutdown unclocked register access ehci shutdown callback can access registers with the clocks turned off if the USB controller is in low power mode. Check HCD_FLAG_HW_ACCESSIBLE flag before accessing any register. Change-Id: Iafc9a5057aa196131b3aa7a2f659b9f8f052ec7f Signed-off-by: Ajay Agarwal --- drivers/usb/host/ehci-hcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 142fe5139ca3..e79ac2a45e59 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -377,6 +377,9 @@ static void ehci_shutdown(struct usb_hcd *hcd) if (!ehci->sbrn) return; + if (!HCD_HW_ACCESSIBLE(hcd)) + return; + spin_lock_irq(&ehci->lock); ehci->shutdown = true; ehci->rh_state = EHCI_RH_STOPPING; -- GitLab From 261feedf5a8d7208a4b9621af8033074fa4214e6 Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Thu, 9 Nov 2017 12:41:45 -0800 Subject: [PATCH 1608/1834] msm: wlan: Add support for UNI-III ETSI sub-band Per the EU STD. ETSI EN 300 440, sub-band 5725-5875 is allowed in EU at reduced power of 25 mW. Add the sub-band to the EU countries that support this sub-band. Change-Id: I0a43e99c4357527f607110faecddd9d0fd444fc6 Signed-off-by: Amar Singhal CRs-Fixed: 2141740 --- net/wireless/db.txt | 334 ++++++-------------------------------------- 1 file changed, 46 insertions(+), 288 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index eb4cc00e38e0..5b625fce8662 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -40,6 +40,7 @@ country AL: DFS-ETSI (5150 - 5250 @ 80), (23), AUTO-BW (5250 - 5350 @ 80), (23), DFS, AUTO-BW (5470 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country AM: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -51,6 +52,7 @@ country AN: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country AR: (2402 - 2482 @ 40), (36) @@ -74,15 +76,7 @@ country AT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -112,6 +106,7 @@ country BA: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country BB: DFS-FCC (2402 - 2482 @ 40), (20) @@ -128,15 +123,7 @@ country BE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -152,15 +139,7 @@ country BG: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -250,15 +229,7 @@ country CH: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -312,15 +283,7 @@ country CY: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -331,15 +294,7 @@ country CZ: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -354,15 +309,7 @@ country DE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -371,15 +318,7 @@ country DK: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -415,15 +354,7 @@ country EE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -437,15 +368,7 @@ country ES: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -460,15 +383,7 @@ country FI: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -484,15 +399,7 @@ country FR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -501,15 +408,7 @@ country GB: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -530,6 +429,7 @@ country GF: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country GH: DFS-FCC (2402 - 2482 @ 40), (20) @@ -561,15 +461,7 @@ country GR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -614,15 +506,7 @@ country HR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -638,15 +522,7 @@ country HU: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -660,15 +536,7 @@ country IE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -695,15 +563,7 @@ country IS: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -712,15 +572,7 @@ country IT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -811,15 +663,7 @@ country LI: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -841,15 +685,7 @@ country LT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -858,15 +694,7 @@ country LU: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -875,15 +703,7 @@ country LV: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -899,18 +719,21 @@ country MC: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country MD: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country ME: DFS-ETSI (2402 - 2482 @ 40), (20) (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country MF: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -930,6 +753,7 @@ country MK: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country MN: DFS-FCC (2402 - 2482 @ 40), (20) @@ -957,6 +781,7 @@ country MQ: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country MR: DFS-ETSI (2402 - 2482 @ 40), (20) @@ -969,15 +794,7 @@ country MT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1044,15 +861,7 @@ country NL: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1061,15 +870,7 @@ country NO: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1111,6 +912,7 @@ country PF: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country PG: DFS-FCC (2402 - 2482 @ 40), (20) @@ -1137,15 +939,7 @@ country PL: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1154,6 +948,7 @@ country PM: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country PR: DFS-FCC (2402 - 2472 @ 40), (30) @@ -1174,15 +969,7 @@ country PT: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1220,15 +1007,7 @@ country RO: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1239,6 +1018,7 @@ country RS: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1268,15 +1048,7 @@ country SE: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1294,15 +1066,7 @@ country SI: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1311,15 +1075,7 @@ country SK: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS - # 5.9ghz band - # reference: http://www.etsi.org/deliver/etsi_en/302500_302599/302571/01.02.00_20/en_302571v010200a.pdf - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) + (5725 - 5875 @ 80), (14) # 60 gHz band channels 1-4, ref: Etsi En 302 567 (57000 - 66000 @ 2160), (40) @@ -1379,6 +1135,7 @@ country TR: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country TT: (2402 - 2482 @ 40), (20) @@ -1465,6 +1222,7 @@ country VC: DFS-ETSI (5170 - 5250 @ 80), (23), AUTO-BW (5250 - 5330 @ 80), (23), DFS, AUTO-BW (5490 - 5710 @ 160), (30), DFS + (5725 - 5875 @ 80), (14) country VE: DFS-FCC (2402 - 2482 @ 40), (20) -- GitLab From 271fe36540e1df82e8ecb250db520283f573d870 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Tue, 1 May 2018 10:44:20 -0700 Subject: [PATCH 1609/1834] msm: ipa4: MHI register update Update test_client_1 to be MHI instead of non-MHI. Change-Id: I473bf968096720217f427b3c90236608631e321b Crs-fixed: 2234199 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 80155f9e2060..d6d6d0d33ecf 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1363,7 +1363,7 @@ static const struct ipa_ep_configuration ipa3_ep_mapping IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, QMB_MASTER_SELECT_DDR, {0, 8, 8, 16, IPA_EE_AP } }, - [IPA_4_0][IPA_CLIENT_TEST1_PROD] = { + [IPA_4_0_MHI][IPA_CLIENT_TEST1_PROD] = { true, IPA_v4_0_GROUP_UL_DL, true, IPA_DPS_HPS_SEQ_TYPE_2ND_PKT_PROCESS_PASS_NO_DEC_UCP, -- GitLab From c513a319bbc5e44bda10d8fc00d18566575aff62 Mon Sep 17 00:00:00 2001 From: Dennis Cagle Date: Fri, 27 Apr 2018 16:49:18 -0700 Subject: [PATCH 1610/1834] defconfig: Enable SELinux on sdxpoorwills Enable SELinux feature on sdxpoorwills Change-Id: I98e53356c119b596d15dd5f54983688c7642b9a9 Signed-off-by: Dennis Cagle --- arch/arm/configs/sdxpoorwills-perf_defconfig | 9 +++++++++ arch/arm/configs/sdxpoorwills_defconfig | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index e3c1c1aa817b..b2927cea690e 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -1,3 +1,4 @@ +CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y @@ -60,6 +61,7 @@ CONFIG_IPV6_PIMSM_V2=y CONFIG_NETFILTER=y CONFIG_NETFILTER_DEBUG=y CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_TIMEOUT=y CONFIG_NF_CONNTRACK_TIMESTAMP=y @@ -77,6 +79,7 @@ CONFIG_NF_CT_NETLINK=y CONFIG_NF_CT_NETLINK_TIMEOUT=y CONFIG_NF_CT_NETLINK_HELPER=y CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -84,6 +87,7 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y @@ -115,6 +119,7 @@ CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_ECN=y CONFIG_IP_NF_TARGET_TTL=y CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y @@ -407,6 +412,10 @@ CONFIG_CORESIGHT_TPDM=y CONFIG_CORESIGHT_CTI=y CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_HWEVENT=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_AVC_STATS is not set CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index 7a54d68b2fb1..7e7e2dbdfcbf 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -1,3 +1,4 @@ +CONFIG_AUDIT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IKCONFIG=y @@ -62,6 +63,7 @@ CONFIG_IPV6_PIMSM_V2=y CONFIG_NETFILTER=y CONFIG_NETFILTER_DEBUG=y CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y CONFIG_NF_CONNTRACK_EVENTS=y CONFIG_NF_CONNTRACK_TIMEOUT=y CONFIG_NF_CONNTRACK_TIMESTAMP=y @@ -79,6 +81,7 @@ CONFIG_NF_CT_NETLINK=y CONFIG_NF_CT_NETLINK_TIMEOUT=y CONFIG_NF_CT_NETLINK_HELPER=y CONFIG_NETFILTER_NETLINK_GLUE_CT=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y @@ -86,6 +89,7 @@ CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y CONFIG_NETFILTER_XT_TARGET_NOTRACK=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y CONFIG_NETFILTER_XT_MATCH_CONNLABEL=y @@ -117,6 +121,7 @@ CONFIG_IP_NF_MANGLE=y CONFIG_IP_NF_TARGET_ECN=y CONFIG_IP_NF_TARGET_TTL=y CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y @@ -434,6 +439,10 @@ CONFIG_CORESIGHT_EVENT=y CONFIG_CORESIGHT_TGU=y CONFIG_CORESIGHT_HWEVENT=y CONFIG_CORESIGHT_DUMMY=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +# CONFIG_SECURITY_SELINUX_AVC_STATS is not set CONFIG_CRYPTO_CMAC=y CONFIG_CRYPTO_SHA256=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y -- GitLab From 1d377732fd9a1698ac5a702b5f21cc264bc88823 Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Mon, 15 Jan 2018 17:16:03 -0800 Subject: [PATCH 1611/1834] msm: wlan: Remove DSRC channels for US DSRC channels are not required when SRD channels are enabled. Therefore remove them. Signed-off-by: Amar Singhal Change-Id: I1b2937c45d43d31c5689c7c4d134fcfb9a265b0e CRs-Fixed: 2174850 --- net/wireless/db.txt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/net/wireless/db.txt b/net/wireless/db.txt index 5b625fce8662..30cc249bb98e 100644 --- a/net/wireless/db.txt +++ b/net/wireless/db.txt @@ -1187,18 +1187,6 @@ country US: DFS-FCC (5250 - 5330 @ 80), (24), DFS, AUTO-BW (5490 - 5730 @ 160), (24), DFS (5735 - 5835 @ 80), (30) - # 5.9ghz band - # reference: https://apps.fcc.gov/edocs_public/attachmatch/FCC-03-324A1.pdf - (5842 - 5863 @ 5), (30) - (5850 - 5870 @ 10), (30) - (5860 - 5880 @ 10), (30) - (5865 - 5885 @ 20), (30) - (5870 - 5890 @ 10), (30) - (5880 - 5900 @ 10), (30) - (5890 - 5910 @ 10), (30) - (5895 - 5915 @ 20), (30) - (5900 - 5920 @ 10), (30) - (5910 - 5930 @ 10), (30) # 60g band # reference: http://cfr.regstoday.com/47cfr15.aspx#47_CFR_15p255 # channels 1,2,3,4,5,6 EIRP=40dBm(43dBm peak) -- GitLab From 922b035a6480973e18cd3ded9e9bebbd8e76ed36 Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Thu, 19 Apr 2018 14:03:29 -0700 Subject: [PATCH 1612/1834] cnss2: Use general name "wlan" as subsystem name Use "wlan" as subsystem name instead of a specific device ID when register to SSR framework. Change-Id: I68ddf13b209ac470fe444958fcdcc50937b3b1c5 Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/main.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 914275867075..4c4c761ae6d3 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -1799,20 +1799,7 @@ int cnss_register_subsys(struct cnss_plat_data *plat_priv) subsys_info = &plat_priv->subsys_info; - switch (plat_priv->device_id) { - case QCA6174_DEVICE_ID: - subsys_info->subsys_desc.name = "AR6320"; - break; - case QCA6290_EMULATION_DEVICE_ID: - case QCA6290_DEVICE_ID: - subsys_info->subsys_desc.name = "QCA6290"; - break; - default: - cnss_pr_err("Unknown device ID: 0x%lx\n", plat_priv->device_id); - ret = -ENODEV; - goto out; - } - + subsys_info->subsys_desc.name = "wlan"; subsys_info->subsys_desc.owner = THIS_MODULE; subsys_info->subsys_desc.powerup = cnss_subsys_powerup; subsys_info->subsys_desc.shutdown = cnss_subsys_shutdown; -- GitLab From 4e0bb6705061bc42b75bfec5d14d2792d7e55a68 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Wed, 2 May 2018 15:26:58 -0700 Subject: [PATCH 1613/1834] power: qpnp-fg-gen3: Fix incorrect calculations 'Commit 6364691deb82 ("power: qpnp-fg-gen3: Fix fuel-gen3 compilation issues")' tried fixing 32 bit compilation issues by replacing do_div() with div64_s64. However, it broke the calculations done previously by not storing the quotient back. Fix it. Also, since these calculations are made on unsigned integers, replace div64_s64() with div64_u64(). CRs-Fixed: 2235300 Change-Id: I257d8b96eeb7cec35540359b02160996ef99d1a7 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen3.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 440bf74bd26c..7ba0ce5bc489 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -1417,16 +1417,16 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) QNOVO_CL_SKEW_DECIPCT, chip->cl.final_cc_uah); chip->cl.final_cc_uah = chip->cl.final_cc_uah * (1000 + QNOVO_CL_SKEW_DECIPCT); - div64_s64(chip->cl.final_cc_uah, 1000); + chip->cl.final_cc_uah = div64_u64(chip->cl.final_cc_uah, 1000); } max_inc_val = chip->cl.learned_cc_uah * (1000 + chip->dt.cl_max_cap_inc); - div64_s64(max_inc_val, 1000); + max_inc_val = div64_u64(max_inc_val, 1000); min_dec_val = chip->cl.learned_cc_uah * (1000 - chip->dt.cl_max_cap_dec); - div64_s64(min_dec_val, 1000); + min_dec_val = div64_u64(min_dec_val, 1000); old_cap = chip->cl.learned_cc_uah; if (chip->cl.final_cc_uah > max_inc_val) @@ -1440,7 +1440,7 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) if (chip->dt.cl_max_cap_limit) { max_inc_val = (int64_t)chip->cl.nom_cap_uah * (1000 + chip->dt.cl_max_cap_limit); - div64_s64(max_inc_val, 1000); + max_inc_val = div64_u64(max_inc_val, 1000); if (chip->cl.final_cc_uah > max_inc_val) { fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes above max limit %lld\n", chip->cl.final_cc_uah, max_inc_val); @@ -1451,7 +1451,7 @@ static void fg_cap_learning_post_process(struct fg_chip *chip) if (chip->dt.cl_min_cap_limit) { min_dec_val = (int64_t)chip->cl.nom_cap_uah * (1000 - chip->dt.cl_min_cap_limit); - div64_s64(min_dec_val, 1000); + min_dec_val = div64_u64(min_dec_val, 1000); if (chip->cl.final_cc_uah < min_dec_val) { fg_dbg(chip, FG_CAP_LEARN, "learning capacity %lld goes below min limit %lld\n", chip->cl.final_cc_uah, min_dec_val); @@ -1955,7 +1955,7 @@ static int fg_rconn_config(struct fg_chip *chip) } val *= scaling_factor; - div64_s64(val, 1000); + val = div64_u64(val, 1000); rc = fg_sram_write(chip, ESR_RSLOW_CHG_WORD, ESR_RSLOW_CHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT); if (rc < 0) { @@ -1972,7 +1972,7 @@ static int fg_rconn_config(struct fg_chip *chip) } val *= scaling_factor; - div64_s64(val, 1000); + val = div64_u64(val, 1000); rc = fg_sram_write(chip, ESR_RSLOW_DISCHG_WORD, ESR_RSLOW_DISCHG_OFFSET, (u8 *)&val, 1, FG_IMA_DEFAULT); if (rc < 0) { -- GitLab From d92b246d50e57f1ebc1f503ed2b2c2ab581b0ccf Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 27 Apr 2018 14:30:37 -0700 Subject: [PATCH 1614/1834] power: qpnp-fg-gen3: Restore recharge SOC only when not in JEITA Currently, recharge SOC is adjusted (lowered) based on the SOC where charging terminates. It is restored back to the original threshold when the charge termination condition goes away. This works fine in most cases. However there are certain conditions where the charger fluctuates between fast and taper regions along with the charge termination status. Handle this by checking if battery is out of JEITA as well before restoring back the original recharge SOC threshold. CRs-Fixed: 2213369 Change-Id: Ic64151ddbbff09c26d6ebfcd3e6d4e70e0be8c9d Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-fg-gen3.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index 7ba0ce5bc489..eaf138c99f2c 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -2080,12 +2080,21 @@ static int fg_set_recharge_soc(struct fg_chip *chip, int recharge_soc) static int fg_adjust_recharge_soc(struct fg_chip *chip) { + union power_supply_propval prop = {0, }; int rc, msoc, recharge_soc, new_recharge_soc = 0; bool recharge_soc_status; if (!chip->dt.auto_recharge_soc) return 0; + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_HEALTH, + &prop); + if (rc < 0) { + pr_err("Error in getting battery health, rc=%d\n", rc); + return rc; + } + chip->health = prop.intval; + recharge_soc = chip->dt.recharge_soc_thr; recharge_soc_status = chip->recharge_soc_adjusted; /* @@ -2116,6 +2125,9 @@ static int fg_adjust_recharge_soc(struct fg_chip *chip) if (!chip->recharge_soc_adjusted) return 0; + if (chip->health != POWER_SUPPLY_HEALTH_GOOD) + return 0; + /* Restore the default value */ new_recharge_soc = recharge_soc; chip->recharge_soc_adjusted = false; -- GitLab From 1d9260577b9502d44a6f578a2ea47da6dcaba904 Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Fri, 27 Apr 2018 15:21:09 +0530 Subject: [PATCH 1615/1834] sched: add tracing support for bias to waker and prev cpu Update task_util trace event to trace biased to waker and prev cpu. Change-Id: I12bb1a6b93eb8dd15f0ecc5f14904b2fd4655fda Signed-off-by: Lingutla Chandrasekhar --- include/trace/events/sched.h | 10 ++++++---- kernel/sched/fair.c | 27 ++++++++++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h index e06df4da01ef..b355ebfd7697 100644 --- a/include/trace/events/sched.h +++ b/include/trace/events/sched.h @@ -713,10 +713,10 @@ TRACE_EVENT(sched_energy_diff, TRACE_EVENT(sched_task_util, TP_PROTO(struct task_struct *p, int next_cpu, int backup_cpu, - int target_cpu, bool sync, bool need_idle, + int target_cpu, bool sync, bool need_idle, int fastpath, bool placement_boost, int rtg_cpu, u64 start_t), - TP_ARGS(p, next_cpu, backup_cpu, target_cpu, sync, need_idle, + TP_ARGS(p, next_cpu, backup_cpu, target_cpu, sync, need_idle, fastpath, placement_boost, rtg_cpu, start_t), TP_STRUCT__entry( @@ -729,6 +729,7 @@ TRACE_EVENT(sched_task_util, __field(int, target_cpu ) __field(bool, sync ) __field(bool, need_idle ) + __field(int, fastpath ) __field(bool, placement_boost ) __field(int, rtg_cpu ) __field(u64, latency ) @@ -744,13 +745,14 @@ TRACE_EVENT(sched_task_util, __entry->target_cpu = target_cpu; __entry->sync = sync; __entry->need_idle = need_idle; + __entry->fastpath = fastpath; __entry->placement_boost = placement_boost; __entry->rtg_cpu = rtg_cpu; __entry->latency = (sched_clock() - start_t); ), - TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d next_cpu=%d backup_cpu=%d target_cpu=%d sync=%d need_idle=%d placement_boost=%d rtg_cpu=%d latency=%llu", - __entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, __entry->next_cpu, __entry->backup_cpu, __entry->target_cpu, __entry->sync, __entry->need_idle, __entry->placement_boost, __entry->rtg_cpu, __entry->latency) + TP_printk("pid=%d comm=%s util=%lu prev_cpu=%d next_cpu=%d backup_cpu=%d target_cpu=%d sync=%d need_idle=%d fastpath=%d placement_boost=%d rtg_cpu=%d latency=%llu", + __entry->pid, __entry->comm, __entry->util, __entry->prev_cpu, __entry->next_cpu, __entry->backup_cpu, __entry->target_cpu, __entry->sync, __entry->need_idle, __entry->fastpath, __entry->placement_boost, __entry->rtg_cpu, __entry->latency) ); #endif diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 04ba6d02736d..112aeaa8dab8 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -7357,6 +7357,12 @@ static inline struct cpumask *find_rtg_target(struct task_struct *p) } #endif +enum fastpaths { + NONE = 0, + SYNC_WAKEUP, + PREV_CPU_BIAS, +}; + static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync) { bool boosted, prefer_idle; @@ -7367,6 +7373,7 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync struct cpumask *rtg_target = find_rtg_target(p); struct find_best_target_env fbt_env; u64 start_t = 0; + int fastpath = 0; if (trace_sched_task_util_enabled()) start_t = sched_clock(); @@ -7403,12 +7410,17 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync if (bias_to_waker_cpu(p, cpu, rtg_target)) { schedstat_inc(p->se.statistics.nr_wakeups_secb_sync); schedstat_inc(this_rq()->eas_stats.secb_sync); - return cpu; + target_cpu = cpu; + fastpath = SYNC_WAKEUP; + goto out; } } - if (bias_to_prev_cpu(p, rtg_target)) - return prev_cpu; + if (bias_to_prev_cpu(p, rtg_target)) { + target_cpu = prev_cpu; + fastpath = PREV_CPU_BIAS; + goto out; + } rcu_read_lock(); @@ -7495,11 +7507,12 @@ static int select_energy_cpu_brute(struct task_struct *p, int prev_cpu, int sync schedstat_inc(this_rq()->eas_stats.secb_count); unlock: - trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync, - fbt_env.need_idle, fbt_env.placement_boost, - rtg_target ? cpumask_first(rtg_target) : -1, - start_t); rcu_read_unlock(); +out: + trace_sched_task_util(p, next_cpu, backup_cpu, target_cpu, sync, + fbt_env.need_idle, fastpath, + fbt_env.placement_boost, rtg_target ? + cpumask_first(rtg_target) : -1, start_t); return target_cpu; } -- GitLab From 9f23b6334a70a05bb9fb016009249ac099b4a62f Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Thu, 3 May 2018 10:40:10 +0300 Subject: [PATCH 1616/1834] msm: ipa3: Fix QMB configuration for IPA test pipes IPA test pipes which are used for unit-tests has wrong QMB configuration. It needs to be DDR QMB and not PCIE QMB which is used for MHI data path. Change-Id: I7600916835f4d38ae379e5f81212f9717ba1c7e7 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 80155f9e2060..9361d0d77407 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1279,31 +1279,31 @@ static const struct ipa_ep_configuration ipa3_ep_mapping true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 11, 6, 9, 9, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST1_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 11, 6, 9, 9, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST2_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 12, 2, 5, 5, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST3_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 19, 12, 9, 9, IPA_EE_AP } }, [IPA_4_0][IPA_CLIENT_TEST4_CONS] = { true, IPA_v4_0_GROUP_UL_DL, false, IPA_DPS_HPS_SEQ_TYPE_INVALID, - QMB_MASTER_SELECT_PCIE, + QMB_MASTER_SELECT_DDR, { 21, 14, 9, 9, IPA_EE_AP } }, /* Dummy consumer (pipe 31) is used in L2TP rt rule */ [IPA_4_0][IPA_CLIENT_DUMMY_CONS] = { -- GitLab From 4d1681c8b8440629814481678aa2e05e2a66549b Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Thu, 3 May 2018 13:59:31 +0530 Subject: [PATCH 1617/1834] ARM: dts: msm: Update energy costs for new frequency on SDM845V2 Add energy cost for new frequency of Gold CPU on SDM845V2, which is used in task placement by energy aware scheduler. Change-Id: I1f0cb4f3ce354c2102d937e9b07cc93c9d829a2f Signed-off-by: Lingutla Chandrasekhar --- arch/arm64/boot/dts/qcom/sdm845-v2.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi index 575cf124a803..ba76273d507e 100644 --- a/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm845-v2.dtsi @@ -469,6 +469,7 @@ 2764800 30000 2784000 35000 2803200 40000 + 2841600 50000 >; idle-cost-data = < 100 80 60 40 @@ -535,6 +536,7 @@ 2764800 160 2784000 165 2803200 170 + 2841600 180 >; idle-cost-data = < 4 3 2 1 -- GitLab From d30be38a975983193b7c29f7988dc3558a86f9d7 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Mon, 23 Apr 2018 13:22:33 +0530 Subject: [PATCH 1618/1834] defconfig: Remove debug configurations for perf build Enable FTRACE support and remove debug config flags for perf build on msm8909w. Change-Id: Ie5729e3a9a504bd0aaff66bafd8740f8d190886b Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909w-perf_defconfig | 49 ++++++------------------ 1 file changed, 11 insertions(+), 38 deletions(-) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 0e3a3ec7feff..9b5574004872 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -4,10 +4,6 @@ CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y @@ -49,10 +45,10 @@ CONFIG_SMP=y CONFIG_SCHED_MC=y CONFIG_PREEMPT=y CONFIG_AEABI=y -CONFIG_HIGHMEM=y CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y @@ -108,14 +104,12 @@ CONFIG_NF_CT_NETLINK=y CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y CONFIG_NETFILTER_XT_TARGET_CONNMARK=y CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_CT=y CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y -CONFIG_NETFILTER_XT_TARGET_LOG=y CONFIG_NETFILTER_XT_TARGET_MARK=y CONFIG_NETFILTER_XT_TARGET_NFLOG=y CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y -CONFIG_NETFILTER_XT_TARGET_NOTRACK=y -CONFIG_NETFILTER_XT_TARGET_TEE=y CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y @@ -125,7 +119,6 @@ CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y CONFIG_NETFILTER_XT_MATCH_DSCP=y -CONFIG_NETFILTER_XT_MATCH_ESP=y CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y CONFIG_NETFILTER_XT_MATCH_HELPER=y CONFIG_NETFILTER_XT_MATCH_IPRANGE=y @@ -146,6 +139,8 @@ CONFIG_NETFILTER_XT_MATCH_STRING=y CONFIG_NETFILTER_XT_MATCH_TIME=y CONFIG_NETFILTER_XT_MATCH_U32=y CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_DUP_IPV4=y +CONFIG_NF_LOG_IPV4=y CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_AH=y CONFIG_IP_NF_MATCH_ECN=y @@ -164,6 +159,8 @@ CONFIG_IP_NF_ARPTABLES=y CONFIG_IP_NF_ARPFILTER=y CONFIG_IP_NF_ARP_MANGLE=y CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_DUP_IPV6=y +CONFIG_NF_LOG_IPV6=y CONFIG_IP6_NF_IPTABLES=y CONFIG_IP6_NF_MATCH_RPFILTER=y CONFIG_IP6_NF_FILTER=y @@ -216,7 +213,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y -CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y @@ -229,11 +225,9 @@ CONFIG_SCSI_SCAN_ASYNC=y CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y -CONFIG_SCSI_UFS_QCOM_ICE=y CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_UEVENT=y CONFIG_DM_VERITY=y @@ -257,7 +251,6 @@ CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y -CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26=y CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26=y @@ -346,11 +339,7 @@ CONFIG_HID_MAGICMOUSE=y CONFIG_HID_MICROSOFT=y CONFIG_HID_MONTEREY=y CONFIG_HID_MULTITOUCH=y -CONFIG_USB_DWC3=y -CONFIG_NOP_USB_XCEIV=y CONFIG_DUAL_ROLE_USB_INTF=y -CONFIG_USB_MSM_SSPHY_QMP=y -CONFIG_MSM_QUSB_PHY=y CONFIG_USB_GADGET=y CONFIG_USB_GADGET_DEBUG_FILES=y CONFIG_USB_GADGET_DEBUG_FS=y @@ -365,8 +354,6 @@ CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_EEM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y -CONFIG_USB_CONFIGFS_F_MTP=y -CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_F_ACC=y CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y CONFIG_USB_CONFIGFS_UEVENT=y @@ -374,7 +361,6 @@ CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y CONFIG_USB_CONFIGFS_F_CCID=y -CONFIG_USB_CONFIGFS_F_GSI=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y CONFIG_MMC_RING_BUFFER=y @@ -382,7 +368,6 @@ CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -444,7 +429,6 @@ CONFIG_MSM_PIL=y CONFIG_MSM_PIL_SSR_GENERIC=y CONFIG_MSM_PIL_MSS_QDSP6V5=y CONFIG_MSM_EVENT_TIMER=y -CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_MSM_BAM_DMUX=y CONFIG_MSM_GLINK_BGCOM_XPRT=y @@ -464,17 +448,15 @@ CONFIG_PWM=y CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y +CONFIG_STM=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y CONFIG_FUSE_FS=y -CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_ECRYPT_FS=y @@ -496,21 +478,12 @@ CONFIG_PANIC_ON_RT_THROTTLING=y CONFIG_SCHEDSTATS=y CONFIG_SCHED_STACK_END_CHECK=y # CONFIG_DEBUG_PREEMPT is not set -# CONFIG_FTRACE is not set +CONFIG_IPC_LOGGING=y CONFIG_LKDTM=y CONFIG_PANIC_ON_DATA_CORRUPTION=y # CONFIG_ARM_UNWIND is not set CONFIG_PID_IN_CONTEXTIDR=y CONFIG_DEBUG_SET_MODULE_RONX=y -CONFIG_CORESIGHT=y -CONFIG_CORESIGHT_REMOTE_ETM=y -CONFIG_CORESIGHT_REMOTE_ETM_DEFAULT_ENABLE=0 -CONFIG_CORESIGHT_STM=y -CONFIG_CORESIGHT_TPDA=y -CONFIG_CORESIGHT_TPDM=y -CONFIG_CORESIGHT_CTI=y -CONFIG_CORESIGHT_EVENT=y -CONFIG_CORESIGHT_HWEVENT=y CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y CONFIG_SECURITY=y CONFIG_SECURITYFS=y @@ -519,13 +492,13 @@ CONFIG_LSM_MMAP_MIN_ADDR=4096 CONFIG_HARDENED_USERCOPY=y CONFIG_SECURITY_SELINUX=y CONFIG_SECURITY_SMACK=y -CONFIG_CRYPTO_CTR=y -CONFIG_CRYPTO_XTS=y CONFIG_CRYPTO_XCBC=y CONFIG_CRYPTO_MD4=y CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y CONFIG_ARM_CRYPTO=y -- GitLab From d9a9f34f6ad7a9731456e713ef458ef9b4e31896 Mon Sep 17 00:00:00 2001 From: Manapragada Sai Date: Fri, 20 Apr 2018 19:58:20 +0530 Subject: [PATCH 1619/1834] defconfig: msm: Config Cleanup on SDM450 - 2 Disabling few extra configs seen on 4.9 compared to 3.18 kernel, after disaussing with different teams Change-Id: Iaab906482225b2fdac312302868960b530927fee Signed-off-by: Manapragada Sai --- arch/arm/configs/msm8953-perf_defconfig | 15 +++++---------- arch/arm/configs/msm8953_defconfig | 15 +++++---------- arch/arm64/configs/msm8953-perf_defconfig | 15 +++++---------- arch/arm64/configs/msm8953_defconfig | 15 +++++---------- 4 files changed, 20 insertions(+), 40 deletions(-) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index bfa6cc7d078a..2ba24d9f84b1 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -17,7 +17,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -222,6 +221,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -240,7 +241,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -252,10 +252,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -339,7 +337,6 @@ CONFIG_PINCTRL_MSM8953=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y @@ -409,7 +406,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_RADIO_IRIS=y @@ -422,7 +418,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -489,11 +485,12 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -592,8 +589,6 @@ CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index b7dc23ddeeec..829901843a3f 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -18,7 +18,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -227,6 +226,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -245,7 +246,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -257,10 +257,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -346,7 +344,6 @@ CONFIG_PINCTRL_MSM8953=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y @@ -416,7 +413,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_RADIO_IRIS=y @@ -430,7 +426,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -497,12 +493,13 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -608,8 +605,6 @@ CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index 46b34b30c470..83c10ec14f7c 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -18,7 +18,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -223,6 +222,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -241,7 +242,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -253,10 +253,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -338,7 +336,6 @@ CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_SYSCON=y @@ -411,7 +408,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y @@ -425,7 +421,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -492,11 +488,12 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -598,8 +595,6 @@ CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index dc58fc369cd9..dbfafdd48964 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -19,7 +19,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -229,6 +228,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -247,7 +248,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -259,10 +259,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -347,7 +345,6 @@ CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_SYSCON=y @@ -420,7 +417,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y @@ -435,7 +431,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -502,12 +498,13 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -619,8 +616,6 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y -- GitLab From 93c50b8f8e67b1e747f1687286cf27fce67a5bdf Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 23 Apr 2018 14:35:28 +0530 Subject: [PATCH 1620/1834] msm: kgsl: Add multiple fuses based speed bin Add multiple fuses based speed bin. This enables support for different GPU Fmax frequencies based on speed bin value. Change-Id: I9799111c2ccdafee405a4612c342e809720eb612 Signed-off-by: Sunil Khatri --- .../devicetree/bindings/gpu/adreno.txt | 13 +++++ drivers/gpu/msm/adreno.c | 53 +++++++++++++++++++ drivers/gpu/msm/adreno.h | 1 + drivers/gpu/msm/adreno_a5xx.c | 24 ++++++++- 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/gpu/adreno.txt b/Documentation/devicetree/bindings/gpu/adreno.txt index 4fb47d6f90fe..a4e9ba7b057f 100644 --- a/Documentation/devicetree/bindings/gpu/adreno.txt +++ b/Documentation/devicetree/bindings/gpu/adreno.txt @@ -127,6 +127,19 @@ Optional Properties: mask - mask for the relevant bits in the efuse register. shift - number of bits to right shift to get the speed bin value. + +- qcom,gpu-speed-bin-vectors: + GPU speed bin vectors property is the series of all the vectors + in format specified below. Values from individual fuses are read, + masked and shifted to form a value. At the end all fuse values + are ordered together to form final speed bin value. + + + < .. .. .. > + offset - offset of the efuse register from the base. + mask - mask for the relevant bits in the efuse register. + shift - number of bits to right shift. + - qcom,gpu-disable-fuse: GPU disable fuse offset - offset of the efuse register from the base. diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index cb916ae82bfe..8661c0a6fbb0 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -279,6 +279,59 @@ int adreno_efuse_read_u32(struct adreno_device *adreno_dev, unsigned int offset, return 0; } +void adreno_efuse_speed_bin_array(struct adreno_device *adreno_dev) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + int ret, count, i = 0; + unsigned int val, vector_size = 3; + unsigned int *bin_vector; + + /* + * Here count is no of 32 bit elements in the + * speed-bin-vector array. If there are two fuses + * i.e If no of fuses are 2 then no of elements will be + * 2 * 3 = 6(elements of 32 bit each). + */ + count = of_property_count_u32_elems(device->pdev->dev.of_node, + "qcom,gpu-speed-bin-vectors"); + if (count <= 0) + return; + + bin_vector = kmalloc(sizeof(count * sizeof(unsigned int)), + GFP_KERNEL); + if (bin_vector == NULL) { + KGSL_DRV_ERR(device, + "Unable to allocate memory for speed-bin vector\n"); + return; + } + + if (of_property_read_u32_array(device->pdev-> + dev.of_node, "qcom,gpu-speed-bin-vectors", + bin_vector, count)) { + KGSL_DRV_ERR(device, + "Speed-bin-vectors is invalid\n"); + kfree(bin_vector); + return; + } + + /* + * Final value of adreno_dev->speed_bin is the value formed by + * OR'ing the values read from all the fuses. + */ + while (i < count) { + ret = adreno_efuse_read_u32(adreno_dev, bin_vector[i], &val); + + if (ret < 0) + break; + + adreno_dev->speed_bin |= (val & bin_vector[i+1]) + >> bin_vector[i+2]; + i += vector_size; + } + + kfree(bin_vector); +} + static int _get_counter(struct adreno_device *adreno_dev, int group, int countable, unsigned int *lo, unsigned int *hi) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 686ed34d629e..e4f34c99915a 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1130,6 +1130,7 @@ int adreno_efuse_map(struct adreno_device *adreno_dev); int adreno_efuse_read_u32(struct adreno_device *adreno_dev, unsigned int offset, unsigned int *val); void adreno_efuse_unmap(struct adreno_device *adreno_dev); +void adreno_efuse_speed_bin_array(struct adreno_device *adreno_dev); bool adreno_is_cx_dbgc_register(struct kgsl_device *device, unsigned int offset); diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index d37753e24e4a..27cb8f46077b 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -122,14 +122,34 @@ static void a530_efuse_speed_bin(struct adreno_device *adreno_dev) adreno_dev->speed_bin = (val & speed_bin[1]) >> speed_bin[2]; } +static void a5xx_efuse_speed_bin(struct adreno_device *adreno_dev) +{ + unsigned int val; + unsigned int speed_bin[3]; + struct kgsl_device *device = &adreno_dev->dev; + + if (of_get_property(device->pdev->dev.of_node, + "qcom,gpu-speed-bin-vectors", NULL)) { + adreno_efuse_speed_bin_array(adreno_dev); + return; + } + + if (!of_property_read_u32_array(device->pdev->dev.of_node, + "qcom,gpu-speed-bin", speed_bin, 3)) { + adreno_efuse_read_u32(adreno_dev, speed_bin[0], &val); + adreno_dev->speed_bin = (val & speed_bin[1]) >> speed_bin[2]; + return; + } +} + static const struct { int (*check)(struct adreno_device *adreno_dev); void (*func)(struct adreno_device *adreno_dev); } a5xx_efuse_funcs[] = { { adreno_is_a530, a530_efuse_leakage }, { adreno_is_a530, a530_efuse_speed_bin }, - { adreno_is_a504, a530_efuse_speed_bin }, - { adreno_is_a505, a530_efuse_speed_bin }, + { adreno_is_a504, a5xx_efuse_speed_bin }, + { adreno_is_a505, a5xx_efuse_speed_bin }, { adreno_is_a512, a530_efuse_speed_bin }, { adreno_is_a508, a530_efuse_speed_bin }, }; -- GitLab From 338858cce7a651923a5451f6c55d914af85e5ca9 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Fri, 20 Apr 2018 11:55:38 +0530 Subject: [PATCH 1621/1834] ARM: dts: msm: Add adc phandle in charger node for PMI632 Add ADC phandle in charger device node, this is used by charger driver to read USBIN voltage and current. Change-Id: I33653ca32eeb6a4c5a8d4191edece613193f7ee5 Signed-off-by: Ashay Jaiswal --- arch/arm64/boot/dts/qcom/pmi632.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index b8f8b6834b74..4f4677de3327 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -305,6 +305,7 @@ qcom,pmic-revid = <&pmi632_revid>; dpdm-supply = <&qusb_phy>; qcom,auto-recharge-soc = <98>; + qcom,chg-vadc = <&pmi632_vadc>; qcom,thermal-mitigation = <3000000 2500000 2000000 1500000 -- GitLab From ca899953d89c3f968d23adb02a1e3444c3eb3133 Mon Sep 17 00:00:00 2001 From: Vijay Viswanath Date: Tue, 10 Apr 2018 13:01:16 +0530 Subject: [PATCH 1622/1834] mmc: core: hibernation support for mmc cards eMMC is the storage device for hibernation image. As such it needs to be working when hibernation image is created and written. Also for loading hibernation image after reboot, eMMC driver needs to be probed and running. During reboot, kernel comes up and does its own eMMC probe and sets speed for eMMC. A late system call then checks for hibernation image. If there is a hibernation image, the current kernel will stay only temporarily. Once the hibernation image is found and loaded, the temporary kernel suspends the eMMC device and then gives control to kernel in hibernation image. The hibernation image then restores the eMMC device based on the eMMC driver state saved just before creating hibernation image. This gives rise to a possible missmatch between the HW state of eMMC (Specifically the bus speed) when temporary kernel suspends it and the state driver restores after hibernation restore. So a synchornization has been done by making the eMMC run in max speed during: 1. Just before hibernation image is created (So the driver state in hibernation image will be for max speed mode). 2. After reboot, just before temporary kernel loads image and suspends (so the mmc driver in temporary kernel will put the eMMC in suspend while HW state is in highest speed mode. This ensures that the HW state, mmc_resume post the hibernation expects, will be same as the HW state actually present in the eMMC at the point of hibernation restore. This also ensures we save the hibernation image in max performance and we restore the hibernation image also in max performance. Change-Id: Ia9deceacade97ac89e4f25b40ce074d75bbb2bbc Signed-off-by: Vijay Viswanath --- drivers/mmc/core/core.c | 10 ++++-- drivers/mmc/core/mmc.c | 69 ++++++++++++++++++++++++++++++++++++++++ include/linux/mmc/core.h | 2 ++ include/linux/mmc/host.h | 1 + 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 289f3bc79e78..abafb22700ee 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -4702,9 +4702,11 @@ static int mmc_pm_notify(struct notifier_block *notify_block, int err = 0; switch (mode) { + case PM_RESTORE_PREPARE: case PM_HIBERNATION_PREPARE: + if (host->bus_ops && host->bus_ops->pre_hibernate) + host->bus_ops->pre_hibernate(host); case PM_SUSPEND_PREPARE: - case PM_RESTORE_PREPARE: spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 1; spin_unlock_irqrestore(&host->lock, flags); @@ -4728,9 +4730,11 @@ static int mmc_pm_notify(struct notifier_block *notify_block, host->pm_flags = 0; break; - case PM_POST_SUSPEND: - case PM_POST_HIBERNATION: case PM_POST_RESTORE: + case PM_POST_HIBERNATION: + if (host->bus_ops && host->bus_ops->post_hibernate) + host->bus_ops->post_hibernate(host); + case PM_POST_SUSPEND: spin_lock_irqsave(&host->lock, flags); host->rescan_disable = 0; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index ff4f84fdab38..99165f7ac961 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -3058,6 +3058,73 @@ static int mmc_shutdown(struct mmc_host *host) return 0; } +static int mmc_pre_hibernate(struct mmc_host *host) +{ + int ret = 0; + + mmc_get_card(host->card); + host->cached_caps2 = host->caps2; + + /* + * Increase usage_count of card and host device till + * hibernation is over. This will ensure they will not runtime suspend. + */ + pm_runtime_get_noresume(mmc_dev(host)); + pm_runtime_get_noresume(&host->card->dev); + + if (!mmc_can_scale_clk(host)) + goto out; + /* + * Suspend clock scaling and mask host capability so that + * we will run in max frequency during: + * 1. Hibernation preparation and image creation + * 2. After finding hibernation image during reboot + * 3. Once hibernation image is loaded and till hibernation + * restore is complete. + */ + if (host->clk_scaling.enable) + mmc_suspend_clk_scaling(host); + host->caps2 &= ~MMC_CAP2_CLK_SCALE; + host->clk_scaling.state = MMC_LOAD_HIGH; + ret = mmc_clk_update_freq(host, host->card->clk_scaling_highest, + host->clk_scaling.state); + if (ret) + pr_err("%s: %s: Setting clk frequency to max failed: %d\n", + mmc_hostname(host), __func__, ret); +out: + mmc_host_clk_hold(host); + mmc_put_card(host->card); + return ret; +} + +static int mmc_post_hibernate(struct mmc_host *host) +{ + int ret = 0; + + mmc_get_card(host->card); + if (!(host->cached_caps2 & MMC_CAP2_CLK_SCALE)) + goto enable_pm; + /* Enable the clock scaling and set the host capability */ + host->caps2 |= MMC_CAP2_CLK_SCALE; + if (!host->clk_scaling.enable) + ret = mmc_resume_clk_scaling(host); + if (ret) + pr_err("%s: %s: Resuming clk scaling failed: %d\n", + mmc_hostname(host), __func__, ret); +enable_pm: + /* + * Reduce usage count of card and host device so that they may + * runtime suspend. + */ + pm_runtime_put_noidle(&host->card->dev); + pm_runtime_put_noidle(mmc_dev(host)); + + mmc_host_clk_release(host); + + mmc_put_card(host->card); + return ret; +} + static const struct mmc_bus_ops mmc_ops = { .remove = mmc_remove, .detect = mmc_detect, @@ -3069,6 +3136,8 @@ static const struct mmc_bus_ops mmc_ops = { .change_bus_speed = mmc_change_bus_speed, .reset = mmc_reset, .shutdown = mmc_shutdown, + .pre_hibernate = mmc_pre_hibernate, + .post_hibernate = mmc_post_hibernate }; /* diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h index c5a4a259577a..48b7281a5e25 100644 --- a/include/linux/mmc/core.h +++ b/include/linux/mmc/core.h @@ -138,6 +138,8 @@ struct mmc_bus_ops { int (*shutdown)(struct mmc_host *); int (*reset)(struct mmc_host *); int (*change_bus_speed)(struct mmc_host *, unsigned long *); + int (*pre_hibernate)(struct mmc_host *); + int (*post_hibernate)(struct mmc_host *); }; struct mmc_card; diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 089c18b33978..afb179bdefc7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -454,6 +454,7 @@ struct mmc_host { #define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */ u32 caps2; /* More host capabilities */ + u32 cached_caps2; #define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */ #define MMC_CAP2_FULL_PWR_CYCLE (1 << 2) /* Can do full power cycle */ -- GitLab From 10dea61accc570b60fc0933b09f8f4d3f26839f6 Mon Sep 17 00:00:00 2001 From: Josh Kirsch Date: Wed, 2 May 2018 19:23:19 -0700 Subject: [PATCH 1623/1834] ARM: dts: msm: Add audio apr device for SDX24 Add device node for audio apr device for SDX24 target. This device is added to represent APR module. Change-Id: I6b43df4a3eb08dbc478bd7a1381068614279e112 Signed-off-by: Josh Kirsch --- arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi b/arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi index 0fd3b3473c61..6a3210ca0ca0 100644 --- a/arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi +++ b/arch/arm/boot/dts/qcom/sdx-audio-lpass.dtsi @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -69,6 +69,10 @@ compatible = "qcom,msm-pcm-hostless"; }; + audio_apr: qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + }; + host_pcm: qcom,msm-voice-host-pcm { compatible = "qcom,msm-voice-host-pcm"; }; -- GitLab From 623bcec96ba9ea861f36b98e05b9e6e3f179f3be Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Fri, 16 Mar 2018 14:36:21 -0700 Subject: [PATCH 1624/1834] defconfig: Enable cellular hints in regulatory cfg80211 The user-space may send regulatory hint that has cellular sub-type enabled. To process such events, enable CONFIG_CFG80211_REG_CELLULAR_HINTS. Signed-off-by: Amar Singhal Change-Id: I19056eebb69aaf52cf0075374f31b090ec8be512 CRs-Fixed: 2201959 --- arch/arm64/configs/msm8953-perf_defconfig | 2 ++ arch/arm64/configs/msm8953_defconfig | 2 ++ arch/arm64/configs/sdm670-perf_defconfig | 2 ++ arch/arm64/configs/sdm670_defconfig | 2 ++ arch/arm64/configs/sdm845-perf_defconfig | 2 ++ arch/arm64/configs/sdm845_defconfig | 2 ++ 6 files changed, 12 insertions(+) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index 46b34b30c470..0a0f7f7c41d1 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -225,6 +225,8 @@ CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index dc58fc369cd9..4e076f30ebca 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -231,6 +231,8 @@ CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index f82678ed7691..9b1dd4b21a64 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -229,6 +229,8 @@ CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index ee3418bd8c5f..d7d89aeb9e80 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -237,6 +237,8 @@ CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index f5dc2a8f4043..20ae1a967632 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -228,6 +228,8 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_RFKILL=y CONFIG_NFC_NQ=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index 8dc560d8d0ea..edab022cf943 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -233,6 +233,8 @@ CONFIG_SOCKEV_NLMCAST=y CONFIG_BT=y CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y CONFIG_CFG80211_INTERNAL_REGDB=y # CONFIG_CFG80211_CRDA_SUPPORT is not set CONFIG_RFKILL=y -- GitLab From 49d80b2aaec535cf15ecbecef563be454deee46b Mon Sep 17 00:00:00 2001 From: Amit Shekhar Date: Thu, 3 May 2018 10:26:34 -0700 Subject: [PATCH 1625/1834] msm: vidc: Fix buffer size calculation Fix buffer size calculation for NV12, NV21 and UBWC color format to accommodate last row buffers for any frame whose size is not a multiple of 512x512. Change-Id: I97c7e01b10cfce90203c3babcdeb6513d0003d34 Signed-off-by: Amit Shekhar --- include/uapi/media/msm_media_info.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/uapi/media/msm_media_info.h b/include/uapi/media/msm_media_info.h index 4f12e5c534c8..3fd0c8849a4e 100644 --- a/include/uapi/media/msm_media_info.h +++ b/include/uapi/media/msm_media_info.h @@ -1229,6 +1229,7 @@ static inline unsigned int VENUS_BUFFER_SIZE( { const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height); unsigned int uv_alignment = 0, size = 0; + unsigned int w_alignment = 512; unsigned int y_plane, uv_plane, y_stride, uv_stride, y_sclines, uv_sclines; unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0; @@ -1252,6 +1253,17 @@ static inline unsigned int VENUS_BUFFER_SIZE( switch (color_fmt) { case COLOR_FMT_NV21: case COLOR_FMT_NV12: + uv_alignment = 4096; + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + uv_alignment; + size = y_plane + uv_plane + + MSM_MEDIA_MAX(extra_size, 8 * y_stride); + size = MSM_MEDIA_ALIGN(size, 4096); + + /* Additional size to cover last row of non-aligned frame */ + size += MSM_MEDIA_ALIGN(width, w_alignment) * w_alignment; + size = MSM_MEDIA_ALIGN(size, 4096); + break; case COLOR_FMT_P010: uv_alignment = 4096; y_plane = y_stride * y_sclines; @@ -1288,6 +1300,10 @@ static inline unsigned int VENUS_BUFFER_SIZE( uv_meta_plane)*2 + MSM_MEDIA_MAX(extra_size + 8192, 48 * y_stride); size = MSM_MEDIA_ALIGN(size, 4096); + + /* Additional size to cover last row of non-aligned frame */ + size += MSM_MEDIA_ALIGN(width, w_alignment) * w_alignment; + size = MSM_MEDIA_ALIGN(size, 4096); break; case COLOR_FMT_NV12_BPP10_UBWC: y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); -- GitLab From 3136b28ed40b09abba3384d20bd6f5be1a4b3b86 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Fri, 4 May 2018 10:55:15 +0530 Subject: [PATCH 1626/1834] drm/msm/sde: Correct vblank ref count in case of failures If register IRQ fails, correct vblank ref counts so that IRQ registration can be tried again. Change-Id: I4bc0864f182da6ef1a8f1ab5e36892d8201b1195 Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c index 862a8b36a428..3fd45cbf43a9 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c @@ -645,11 +645,17 @@ static int sde_encoder_phys_vid_control_vblank_irq( SDE_EVT32(DRMID(phys_enc->parent), enable, atomic_read(&phys_enc->vblank_refcount)); - if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) + if (enable && atomic_inc_return(&phys_enc->vblank_refcount) == 1) { ret = sde_encoder_helper_register_irq(phys_enc, INTR_IDX_VSYNC); - else if (!enable && atomic_dec_return(&phys_enc->vblank_refcount) == 0) + if (ret) + atomic_dec_return(&phys_enc->vblank_refcount); + } else if (!enable && + atomic_dec_return(&phys_enc->vblank_refcount) == 0) { ret = sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_VSYNC); + if (ret) + atomic_inc_return(&phys_enc->vblank_refcount); + } end: if (ret) { -- GitLab From b7e5ea36deea7c43c519c872cd1a9fa65dd263ce Mon Sep 17 00:00:00 2001 From: Rajshekar Eashwarappa Date: Thu, 26 Apr 2018 16:44:53 +0530 Subject: [PATCH 1627/1834] ARM: dts: msm: Add snapshot of 8917 video driver dtsi This is snapshot of the video driver dtsi as of msm-3.18 commit 637fceaee159 ("ARM: dts: msm: Prevent L2PC from occurring when Venus is active on 8917") Change-Id: I9eab513bd365f0e983dfab8841d1b2399c5b30dc Signed-off-by: Rajshekar Eashwarappa Signed-off-by: Vasantha Balla --- arch/arm64/boot/dts/qcom/msm8917-vidc.dtsi | 167 +++++++++++++++++++++ arch/arm64/boot/dts/qcom/msm8917.dtsi | 1 + 2 files changed, 168 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8917-vidc.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8917-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8917-vidc.dtsi new file mode 100644 index 000000000000..c3a93af20094 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-vidc.dtsi @@ -0,0 +1,167 @@ +/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,vidc@1d00000 { + compatible = "qcom,msm-vidc"; + reg = <0x01d00000 0xff000>; + interrupts = <0 44 0>; + qcom,hfi-version = "3xx"; + venus-supply = <&gdsc_venus>; + venus-core0-supply = <&gdsc_venus_core0>; + clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>, + <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>, + <&clock_gcc clk_gcc_venus0_ahb_clk>, + <&clock_gcc clk_gcc_venus0_axi_clk>; + clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x0>; + qcom,sw-power-collapse; + qcom,slave-side-cp; + qcom,dcvs-tbl = + <108000 108000 244800 0x00000004>, /* Encoder */ + <108000 108000 244800 0x0c000000>; /* Decoder */ + qcom,dcvs-limit = + <8160 30>, /* Encoder */ + <8160 30>; /* Decoder */ + qcom,hfi = "venus"; + qcom,reg-presets = <0xe0020 0x05555556>, + <0xe0024 0x05555556>, + <0x80124 0x00000003>; + qcom,qdss-presets = <0x826000 0x1000>, + <0x827000 0x1000>, + <0x822000 0x1000>, + <0x803000 0x1000>, + <0x9180000 0x1000>, + <0x9181000 0x1000>; + qcom,max-hw-load = <352800>; /* 1080p@30 + 720p@30 */ + qcom,pm-qos-latency-us = <651>; + qcom,firmware-name = "venus"; + qcom,allowed-clock-rates = <360000000 329140000 + 308570000 270000000 200000000>; + qcom,clock-freq-tbl { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,cycles-per-mb = <2470>; + qcom,low-power-mode-factor = <32768>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xf3ffffff>; + qcom,cycles-per-mb = <788>; + }; + qcom,profile-hevcdec { + qcom,codec-mask = <0x0c000000>; + qcom,cycles-per-mb = <1015>; + }; + }; + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_iommu 0x800 0x00>, + <&apps_iommu 0x807 0x00>, + <&apps_iommu 0x808 0x27>, + <&apps_iommu 0x811 0x20>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x5dc00000 0x7f000000 + 0xdcc00000 0x1000000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_iommu 0x900 0x00>, + <&apps_iommu 0x90a 0x04>, + <&apps_iommu 0x909 0x22>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x12c00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_iommu 0x90c 0x20>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_iommu 0x940 0x00>, + <&apps_iommu 0x907 0x08>, + <&apps_iommu 0x908 0x20>, + <&apps_iommu 0x90d 0x20>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "venus-ddr-gov"; + qcom,bus-range-kbps = <1000 917000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + }; + + venus-ddr-gov { + compatible = "qcom,msm-vidc,governor,table"; + name = "venus-ddr-gov"; + status = "ok"; + qcom,bus-freq-table { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,load-busfreq-tbl = + <244800 841000>, /* 1080p30E */ + <216000 740000>, /* 720p60E */ + <194400 680000>, /* FWVGA120E */ + <144000 496000>, /* VGA120E */ + <108000 370000>, /* 720p30E */ + <97200 340000>, /* FWVGA60E */ + <48600 170000>, /* FWVGA30E */ + <72000 248000>, /* VGA60E */ + <36000 124000>, /* VGA30E */ + <18000 70000>, /* QVGA60E */ + <9000 35000>, /* QVGA30E */ + <0 0>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xffffffff>; + qcom,load-busfreq-tbl = + <244800 605000>, /* 1080p30D */ + <216000 540000>, /* 720p60D */ + <194400 484000>, /* FWVGA120D */ + <144000 360000>, /* VGA120D */ + <108000 270000>, /* 720p30D */ + <97200 242000>, /* FWVGA60D */ + <48600 121000>, /* FWVGA30D */ + <72000 180000>, /* VGA60D */ + <36000 90000>, /* VGA30D */ + <18000 45000>, /* HVGA30D */ + <0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi index 78410b322893..dbdd9d9dd7d5 100644 --- a/arch/arm64/boot/dts/qcom/msm8917.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi @@ -166,6 +166,7 @@ #include "msm8917-mdss-pll.dtsi" #include "msm-arm-smmu-8917.dtsi" #include "msm8917-gpu.dtsi" +#include "msm8917-vidc.dtsi" &soc { #address-cells = <1>; -- GitLab From a8ef5bccd02ab456e8b5b8d4ca716dbcabb3137c Mon Sep 17 00:00:00 2001 From: Udaya Bhaskara Reddy Mallavarapu Date: Thu, 3 May 2018 15:53:40 +0530 Subject: [PATCH 1628/1834] arm64: configs: Enable dvb demux compilation for 8953 Enable dvb-core, mpq adapter and mpq dvb demux software plugin compilation for 8953. Change-Id: Ied39474b8b95ee19265ae3c1fab02b68868718dc Signed-off-by: Udaya Bhaskara Reddy Mallavarapu --- arch/arm64/configs/msm8953-perf_defconfig | 4 ++++ arch/arm64/configs/msm8953_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm64/configs/msm8953-perf_defconfig b/arch/arm64/configs/msm8953-perf_defconfig index 46b34b30c470..b42625d3a330 100644 --- a/arch/arm64/configs/msm8953-perf_defconfig +++ b/arch/arm64/configs/msm8953-perf_defconfig @@ -381,6 +381,7 @@ CONFIG_REGULATOR_SPM=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y @@ -415,6 +416,9 @@ CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_SW=y CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_QCOM_KGSL=y diff --git a/arch/arm64/configs/msm8953_defconfig b/arch/arm64/configs/msm8953_defconfig index dc58fc369cd9..cab30c61498d 100644 --- a/arch/arm64/configs/msm8953_defconfig +++ b/arch/arm64/configs/msm8953_defconfig @@ -390,6 +390,7 @@ CONFIG_REGULATOR_SPM=y CONFIG_REGULATOR_STUB=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y @@ -424,6 +425,9 @@ CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y +CONFIG_DVB_MPQ=m +CONFIG_DVB_MPQ_DEMUX=m +CONFIG_DVB_MPQ_SW=y CONFIG_RADIO_IRIS=y CONFIG_RADIO_IRIS_TRANSPORT=y CONFIG_QCOM_KGSL=y -- GitLab From 5e8e365b17067e67fbedf0857c42854c75244228 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Fri, 20 Apr 2018 17:54:00 +0530 Subject: [PATCH 1629/1834] usb: gadget: qdss: Add support for qdss fs descriptor handling Currently f_qdss driver not supported in full-speed mode. This results in Chapter 9 USB2 CV Other Speed Configuration Test failures with qdss composition. Hence added full speed descriptors support in qdss driver. Change-Id: I1ca4b2f1aba1479661f89497cfd5c5f25369fa8e Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_qdss.c | 62 ++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index d1c37410184d..bedaf2e215cd 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -1,7 +1,7 @@ /* * f_qdss.c -- QDSS function Driver * - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -117,6 +117,39 @@ static struct usb_ss_ep_comp_descriptor qdss_ctrl_out_ep_comp_desc = { .wBytesPerInterval = 0, }; +/* Full speed support */ +static struct usb_endpoint_descriptor qdss_fs_data_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), +}; + +static struct usb_endpoint_descriptor qdss_fs_ctrl_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), +}; + +static struct usb_endpoint_descriptor qdss_fs_ctrl_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(64), +}; + +static struct usb_descriptor_header *qdss_fs_desc[] = { + (struct usb_descriptor_header *) &qdss_data_intf_desc, + (struct usb_descriptor_header *) &qdss_fs_data_desc, + (struct usb_descriptor_header *) &qdss_ctrl_intf_desc, + (struct usb_descriptor_header *) &qdss_fs_ctrl_in_desc, + (struct usb_descriptor_header *) &qdss_fs_ctrl_out_desc, + NULL, +}; static struct usb_descriptor_header *qdss_hs_desc[] = { (struct usb_descriptor_header *) &qdss_data_intf_desc, (struct usb_descriptor_header *) &qdss_hs_data_desc, @@ -138,6 +171,11 @@ static struct usb_descriptor_header *qdss_ss_desc[] = { NULL, }; +static struct usb_descriptor_header *qdss_fs_data_only_desc[] = { + (struct usb_descriptor_header *) &qdss_data_intf_desc, + (struct usb_descriptor_header *) &qdss_fs_data_desc, + NULL, +}; static struct usb_descriptor_header *qdss_hs_data_only_desc[] = { (struct usb_descriptor_header *) &qdss_data_intf_desc, (struct usb_descriptor_header *) &qdss_hs_data_desc, @@ -367,6 +405,9 @@ static void clear_desc(struct usb_gadget *gadget, struct usb_function *f) if (gadget_is_dualspeed(gadget) && f->hs_descriptors) usb_free_descriptors(f->hs_descriptors); + + if (f->fs_descriptors) + usb_free_descriptors(f->fs_descriptors); } static int qdss_bind(struct usb_configuration *c, struct usb_function *f) @@ -378,11 +419,6 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) pr_debug("qdss_bind\n"); - if (!gadget_is_dualspeed(gadget) && !gadget_is_superspeed(gadget)) { - pr_err("qdss_bind: full-speed is not supported\n"); - return -ENOTSUPP; - } - /* Allocate data I/F */ iface = usb_interface_id(c, f); if (iface < 0) { @@ -447,6 +483,18 @@ static int qdss_bind(struct usb_configuration *c, struct usb_function *f) ep->driver_data = qdss; } + /*update fs descriptors*/ + qdss_fs_data_desc.bEndpointAddress = + qdss_ss_data_desc.bEndpointAddress; + if (qdss->debug_inface_enabled) { + qdss_fs_ctrl_in_desc.bEndpointAddress = + qdss_ss_ctrl_in_desc.bEndpointAddress; + qdss_fs_ctrl_out_desc.bEndpointAddress = + qdss_ss_ctrl_out_desc.bEndpointAddress; + f->fs_descriptors = usb_copy_descriptors(qdss_fs_desc); + } else + f->fs_descriptors = usb_copy_descriptors( + qdss_fs_data_only_desc); /*update descriptors*/ qdss_hs_data_desc.bEndpointAddress = qdss_ss_data_desc.bEndpointAddress; @@ -1144,7 +1192,7 @@ static struct usb_function *qdss_alloc(struct usb_function_instance *fi) struct f_qdss *usb_qdss = opts->usb_qdss; usb_qdss->port.function.name = "usb_qdss"; - usb_qdss->port.function.fs_descriptors = qdss_hs_desc; + usb_qdss->port.function.fs_descriptors = qdss_fs_desc; usb_qdss->port.function.hs_descriptors = qdss_hs_desc; usb_qdss->port.function.strings = qdss_strings; usb_qdss->port.function.bind = qdss_bind; -- GitLab From 68ad9cba05d7fab7c2b4176b6cd97d7a6a4cfaa1 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Mon, 23 Apr 2018 13:41:14 -0700 Subject: [PATCH 1630/1834] diag: Add new Diag IDs Update to latest diag IDs Change-Id: I57a25f570484f2cd8255275015ca2c70294a78fb Signed-off-by: Sreelakshmi Gownipalli --- include/linux/diagchar.h | 52 ++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 95fe2397315f..3c7ec2264935 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -146,10 +146,10 @@ * a new RANGE of SSIDs to the msg_mask_tbl. */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0x0B3F +#define APPS_EVENT_LAST_ID 0x0C5A #define MSG_SSID_0 0 -#define MSG_SSID_0_LAST 121 +#define MSG_SSID_0_LAST 125 #define MSG_SSID_1 500 #define MSG_SSID_1_LAST 506 #define MSG_SSID_2 1000 @@ -161,11 +161,11 @@ #define MSG_SSID_5 4000 #define MSG_SSID_5_LAST 4010 #define MSG_SSID_6 4500 -#define MSG_SSID_6_LAST 4583 +#define MSG_SSID_6_LAST 4584 #define MSG_SSID_7 4600 -#define MSG_SSID_7_LAST 4615 +#define MSG_SSID_7_LAST 4616 #define MSG_SSID_8 5000 -#define MSG_SSID_8_LAST 5033 +#define MSG_SSID_8_LAST 5034 #define MSG_SSID_9 5500 #define MSG_SSID_9_LAST 5516 #define MSG_SSID_10 6000 @@ -265,7 +265,7 @@ static const uint32_t msg_bld_masks_0[] = { MSG_MASK_9 | MSG_MASK_10, MSG_LVL_MED, MSG_LVL_LOW, - MSG_LVL_LOW, + MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_LOW, MSG_LVL_LOW, @@ -319,7 +319,7 @@ static const uint32_t msg_bld_masks_0[] = { MSG_LVL_FATAL, MSG_LVL_MED, MSG_LVL_HIGH, - MSG_LVL_LOW, + MSG_LVL_MED, MSG_LVL_HIGH, MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | MSG_LVL_FATAL, @@ -497,6 +497,7 @@ static const uint32_t msg_bld_masks_6[] = { MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, + MSG_LVL_LOW, MSG_LVL_LOW }; @@ -516,7 +517,9 @@ static const uint32_t msg_bld_masks_7[] = { MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, - MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | MSG_LVL_FATAL + MSG_LVL_LOW | MSG_LVL_MED | MSG_LVL_HIGH | MSG_LVL_ERROR | + MSG_LVL_FATAL, + MSG_LVL_LOW }; static const uint32_t msg_bld_masks_8[] = { @@ -536,9 +539,6 @@ static const uint32_t msg_bld_masks_8[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, @@ -553,6 +553,10 @@ static const uint32_t msg_bld_masks_8[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_HIGH, MSG_LVL_HIGH }; @@ -655,14 +659,14 @@ static const uint32_t msg_bld_masks_10[] = { MSG_LVL_MED, MSG_LVL_MED, MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, - MSG_LVL_LOW, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, + MSG_LVL_MED, MSG_LVL_MED }; @@ -812,7 +816,9 @@ static const uint32_t msg_bld_masks_19[] = { }; static const uint32_t msg_bld_masks_20[] = { - MSG_LVL_LOW, + MSG_LVL_LOW | MSG_MASK_5 | MSG_MASK_6 | MSG_MASK_7 | + MSG_MASK_8 | MSG_MASK_9 | MSG_MASK_10 | MSG_MASK_11 | + MSG_MASK_12, MSG_LVL_LOW, MSG_LVL_LOW, MSG_LVL_LOW, @@ -890,7 +896,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1A11, /* EQUIP ID 1 */ + 0x1C68, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ @@ -900,7 +906,7 @@ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 8 */ 0x0, /* EQUIP ID 9 */ 0xA38A, /* EQUIP ID 10 */ - 0xB201, /* EQUIP ID 11 */ + 0xB9FF, /* EQUIP ID 11 */ 0x0, /* EQUIP ID 12 */ 0xD1FF, /* EQUIP ID 13 */ 0x0, /* EQUIP ID 14 */ -- GitLab From 81cef8ad77f770f92de2453374477800d0167780 Mon Sep 17 00:00:00 2001 From: Chandana Kishori Chiluveru Date: Tue, 24 Apr 2018 10:30:32 +0530 Subject: [PATCH 1631/1834] usb: gadget: qdss: Fix runtime PM usage count for multiple set_alt In some scenarios such as USBCV tests, multiple set_alt could be issued with same interface setting. In that case, driver get the usage count in set_alt but do not put it. This causes a mismatch of usage count and DWC3 LPM does not work anymore. Fix this by adding check in qdss_set_alt to ignore multiple set_alts. Change-Id: I232456c3f99b0cfaa61eb1c044bdd86013c930fa Signed-off-by: Chandana Kishori Chiluveru --- drivers/usb/gadget/function/f_qdss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_qdss.c b/drivers/usb/gadget/function/f_qdss.c index bedaf2e215cd..0ce2c4078248 100644 --- a/drivers/usb/gadget/function/f_qdss.c +++ b/drivers/usb/gadget/function/f_qdss.c @@ -698,7 +698,7 @@ static int qdss_set_alt(struct usb_function *f, unsigned int intf, goto fail1; } - if (intf == qdss->data_iface_id) { + if (intf == qdss->data_iface_id && !qdss->data_enabled) { /* Increment usage count on connect */ usb_gadget_autopm_get_async(qdss->gadget); -- GitLab From 400731059ba4fb82744d658633e8ecde9efde1fc Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 23 Apr 2018 15:29:55 +0530 Subject: [PATCH 1632/1834] ARM: dts: msm: Add GPU clock support for SDM439/SDM429 Add GPU clock support for SDM439 and SDM429 and its variants. Different variants of SDM439 are supported with speed bins. Also update the DDR bandwidth table for new DDR clock plan. Change-Id: I6c9fc5457ef515bc4ba57c4a9d720d32858987be Signed-off-by: Sunil Khatri --- arch/arm64/boot/dts/qcom/sdm439.dtsi | 234 +++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 74d97a6ae5e3..85b28f49c2b2 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -325,3 +325,237 @@ /delete-property/ qcom,platform-regulator-settings; /delete-property/ qcom,platform-lane-config; }; + +/* GPU Overrides*/ +&gpubw { + /delete-property/qcom,bw-tbl; + qcom,bw-tbl = + < 0 >, /* off */ + < 769 >, /* 1. DDR:100.80 MHz BIMC: 50.40 MHz */ + < 1611 >, /* 2. DDR:211.20 MHz BIMC: 105.60 MHz */ + < 2273 >, /* 3. DDR:297.60 MHz BIMC: 148.80 MHz */ + < 2929 >, /* 4. DDR:384.00 MHz BIMC: 192.00 MHz */ + < 4248 >, /* 5. DDR:556.80 MHz BIMC: 278.40 MHz */ + < 5346 >, /* 6. DDR:662.40 MHz BIMC: 331.20 MHz */ + < 5712 >, /* 7. DDR:748.80 MHz BIMC: 374.40 MHz */ + < 6150 >, /* 8. DDR:796.80 MHz BIMC: 398.40 MHz */ + < 7105 >; /* 9. DDR:931.20 MHz BIMC: 465.60 MHz */ +}; + +&msm_gpu { + /delete-property/qcom,msm-bus,num-cases; + qcom,msm-bus,num-cases = <10>; + /delete-property/qcom,msm-bus,vectors-KBps; + qcom,msm-bus,vectors-KBps = + <26 512 0 0>, /* off */ + <26 512 0 806400>, /* 1. 100.80 MHz */ + <26 512 0 1689600>, /* 2. 211.20 MHz */ + <26 512 0 2380800>, /* 3. 297.60 MHz */ + <26 512 0 3072000>, /* 4. 384.00 MHz */ + <26 512 0 4454400>, /* 5. 556.80 MHz */ + <26 512 0 5299200>, /* 6. 662.40 MHz */ + <26 512 0 5990400>, /* 7. 748.80 MHz */ + <26 512 0 6374400>, /* 8. 796.80 MHz */ + <26 512 0 7449600>; /* 9. 931.20 MHz */ + + qcom,gpu-speed-bin-vectors = + <0x6004 0x00c00000 22>, + <0x6008 0x00000600 7>; + + /delete-node/qcom,gpu-pwrlevels; + qcom,gpu-pwrlevel-bins { + #address-cells = <1>; + #size-cells = <0>; + + compatible="qcom,gpu-pwrlevel-bins"; + + qcom,gpu-pwrlevels-0 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <0>; + + qcom,initial-pwrlevel = <3>; + + /* TURBO */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <650000000>; + qcom,bus-freq = <9>; + qcom,bus-min = <9>; + qcom,bus-max = <9>; + }; + + /* NOM+ */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <560000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <6>; + qcom,bus-max = <8>; + }; + + /* SVS+ */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@5 { + reg = <5>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-1 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <4>; + + qcom,initial-pwrlevel = <2>; + + /* NOM+ */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <560000000>; + qcom,bus-freq = <8>; + qcom,bus-min = <7>; + qcom,bus-max = <9>; + }; + + /* NOM */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <6>; + qcom,bus-max = <8>; + }; + + /* SVS+ */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@4 { + reg = <4>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-2 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <5>; + + qcom,initial-pwrlevel = <1>; + + /* NOM */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <510000000>; + qcom,bus-freq = <7>; + qcom,bus-min = <6>; + qcom,bus-max = <8>; + }; + + /* SVS+ */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <400000000>; + qcom,bus-freq = <5>; + qcom,bus-min = <4>; + qcom,bus-max = <7>; + }; + + /* SVS */ + qcom,gpu-pwrlevel@2 { + reg = <2>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <3>; + qcom,bus-max = <5>; + }; + + /* XO */ + qcom,gpu-pwrlevel@3 { + reg = <3>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + + qcom,gpu-pwrlevels-3 { + #address-cells = <1>; + #size-cells = <0>; + + qcom,speed-bin = <10>; + + qcom,initial-pwrlevel = <0>; + + /* SVS */ + qcom,gpu-pwrlevel@0 { + reg = <0>; + qcom,gpu-freq = <320000000>; + qcom,bus-freq = <4>; + qcom,bus-min = <4>; + qcom,bus-max = <8>; + }; + + /* XO */ + qcom,gpu-pwrlevel@1 { + reg = <1>; + qcom,gpu-freq = <19200000>; + qcom,bus-freq = <0>; + qcom,bus-min = <0>; + qcom,bus-max = <0>; + }; + }; + }; +}; -- GitLab From 3543bfc26a357dbcf2460461a2b6f7c3787779fe Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Tue, 10 Apr 2018 11:39:05 -0700 Subject: [PATCH 1633/1834] msm: ipa: add support for HW stats to QMI Populate new fields in the QMI message to send information regarding HW stats location in SRAM. Change-Id: Idaae117081fad6a5cf797eefd5399aa9a4cc35f9 Acked-by: Ady Abraham Signed-off-by: Mohammed Javid Signed-off-by: Skylar Chang --- .../platform/msm/ipa/ipa_v3/ipa_qmi_service.c | 14 ++++ .../msm/ipa/ipa_v3/ipa_qmi_service_v01.c | 83 ++++++++++++++++++- include/uapi/linux/ipa_qmi_service_v01.h | 41 ++++++++- 3 files changed, 135 insertions(+), 3 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 821abe285fb0..3aa8a01f75af 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -531,6 +531,20 @@ static int ipa3_qmi_init_modem_send_sync_msg(void) req.v6_hash_filter_tbl_start_addr = IPA_MEM_PART(v6_flt_hash_ofst) + smem_restr_bytes; + req.hw_stats_quota_base_addr_valid = true; + req.hw_stats_quota_base_addr = + IPA_MEM_PART(stats_quota_ofst) + smem_restr_bytes; + + req.hw_stats_quota_size_valid = true; + req.hw_stats_quota_size = IPA_MEM_PART(stats_quota_size); + + req.hw_drop_stats_base_addr_valid = true; + req.hw_drop_stats_base_addr = + IPA_MEM_PART(stats_drop_ofst) + smem_restr_bytes; + + req.hw_drop_stats_table_size_valid = true; + req.hw_drop_stats_table_size = IPA_MEM_PART(stats_drop_size); + if (!ipa3_uc_loaded_check()) { /* First time boot */ req.is_ssr_bootup_valid = false; req.is_ssr_bootup = 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c index 703acd7d1398..aa56311bc0c6 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1093,11 +1093,92 @@ struct elem_info ipa3_init_modem_driver_req_msg_data_v01_ei[] = { struct ipa_init_modem_driver_req_msg_v01, v6_hash_filter_tbl_start_addr), }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x1F, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_base_addr_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x1F, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_base_addr), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x20, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x20, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_stats_quota_size), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x21, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_base_addr_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x21, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_base_addr), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(uint8_t), + .is_array = NO_ARRAY, + .tlv_type = 0x22, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_table_size_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(uint32_t), + .is_array = NO_ARRAY, + .tlv_type = 0x22, + .offset = offsetof( + struct ipa_init_modem_driver_req_msg_v01, + hw_drop_stats_table_size), + }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, .tlv_type = QMI_COMMON_TLV_TYPE, }, + }; struct elem_info ipa3_init_modem_driver_resp_msg_data_v01_ei[] = { diff --git a/include/uapi/linux/ipa_qmi_service_v01.h b/include/uapi/linux/ipa_qmi_service_v01.h index 1917c0dd2699..72efc86015cb 100644 --- a/include/uapi/linux/ipa_qmi_service_v01.h +++ b/include/uapi/linux/ipa_qmi_service_v01.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -54,6 +54,11 @@ #define QMI_IPA_MAX_CLIENT_DST_PIPES_V01 8 #define QMI_IPA_MAX_UL_FIREWALL_RULES_V01 64 +/* + * Indicates presence of newly added member to support HW stats. + */ +#define IPA_QMI_SUPPORTS_STATS + #define IPA_INT_MAX ((int)(~0U>>1)) #define IPA_INT_MIN (-IPA_INT_MAX - 1) @@ -314,6 +319,38 @@ struct ipa_init_modem_driver_req_msg_v01 { * table in IPAv3 onwards. Denotes the offset from the start of * the IPA shared memory. */ + + /* Optional + * Modem HW Stats Quota Base address + * Must be set to true if hw_stats_quota_base_addr + * is being passed + */ + uint8_t hw_stats_quota_base_addr_valid; + uint32_t hw_stats_quota_base_addr; + + /* Optional + * Modem HW Stats Quota Size + * Must be set to true if hw_stats_quota_size + * is being passed + */ + uint8_t hw_stats_quota_size_valid; + uint32_t hw_stats_quota_size; + + /* Optional + * Modem HW Drop Stats Table Start Address + * Must be set to true if hw_drop_stats_base_addr + * is being passed + */ + uint8_t hw_drop_stats_base_addr_valid; + uint32_t hw_drop_stats_base_addr; + + /* Optional + * Modem HW Drop Stats Table size + * Must be set to true if hw_drop_stats_table_size + * is being passed + */ + uint8_t hw_drop_stats_table_size_valid; + uint32_t hw_drop_stats_table_size; }; /* Message */ /* Response Message; Requests the modem IPA driver about initialization */ @@ -1951,7 +1988,7 @@ struct ipa_configure_ul_firewall_rules_ind_msg_v01 { #define QMI_IPA_INSTALL_UL_FIREWALL_RULES_IND_V01 0x003A /* add for max length*/ -#define QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01 134 +#define QMI_IPA_INIT_MODEM_DRIVER_REQ_MAX_MSG_LEN_V01 162 #define QMI_IPA_INIT_MODEM_DRIVER_RESP_MAX_MSG_LEN_V01 25 #define QMI_IPA_INDICATION_REGISTER_REQ_MAX_MSG_LEN_V01 8 #define QMI_IPA_INDICATION_REGISTER_RESP_MAX_MSG_LEN_V01 7 -- GitLab From 132ce1865a8877affa09c2bda3ce3f23bf25f1af Mon Sep 17 00:00:00 2001 From: Madhukar Sandi Date: Fri, 4 May 2018 17:18:14 +0530 Subject: [PATCH 1634/1834] ARM: dts: msm: disable thermal node for initial bring up Initial 8x09 som bring up, we are disabling thermal node, once complete test and review done we will integrate again. Change-Id: Id1ac7f9e715035697d3b04055bc0ac1ea8b592b0 Signed-off-by: Madhukar Sandi --- arch/arm64/boot/dts/qcom/8909-pm8916.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi b/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi index af56793e27b6..3247d0d1e07a 100644 --- a/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi +++ b/arch/arm64/boot/dts/qcom/8909-pm8916.dtsi @@ -296,7 +296,6 @@ qcom,scale-function = <2>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@32 { @@ -308,7 +307,6 @@ qcom,scale-function = <4>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; chan@3c { @@ -320,7 +318,6 @@ qcom,scale-function = <4>; qcom,hw-settle-time = <2>; qcom,fast-avg-setup = <0>; - qcom,vadc-thermal-node; }; }; -- GitLab From 433dac59e1f904517a19b33c165dbe76b518c005 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 4 May 2018 12:05:44 +0530 Subject: [PATCH 1635/1834] defconfig: Enable MFD_SYSCON for access via regmap This is required for driver to be able to access the system registers via regmap. Change-Id: Ia890210e80ba7da83b8d591965031ad272af0cc7 Signed-off-by: Taniya Das --- arch/arm/configs/sdxpoorwills-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index 646b52de491f..04affb10ef92 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -258,6 +258,7 @@ CONFIG_QTI_QMI_COOLING_DEVICE=y CONFIG_REGULATOR_COOLING_DEVICE=y CONFIG_MFD_I2C_PMIC=y CONFIG_MFD_SPMI_PMIC=y +CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_REGULATOR_QPNP=y -- GitLab From ba688c4a8bb16fc07a14535c7b7af173a92bf919 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Wed, 2 May 2018 15:40:10 -0700 Subject: [PATCH 1636/1834] msm: pcie: clear Request Exit L1 bit when enabling L1 via debugfs When enabling L1 via debugfs commands, the request exit L1 bit needs to be cleared so the link can enter L1. Change-Id: I41b6d3b856473bebc1337eb467763a6f66914e41 Signed-off-by: Tony Truong --- drivers/pci/host/pci-msm.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index b67a94d133e3..cec5a96cc615 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -1457,6 +1457,10 @@ static void msm_pcie_sel_debug_testcase(struct msm_pcie_dev_t *dev, pci_walk_bus(bus, &msm_pcie_config_l1_enable, dev); + /* enable l1 mode, clear bit 5 (REQ_NOT_ENTR_L1) */ + msm_pcie_write_mask(dev->parf + + PCIE20_PARF_PM_CTRL, BIT(5), 0); + msm_pcie_config_l1_enable(dev->dev, dev); } break; -- GitLab From acd7fb85f74337c0a951f7e8d35e055fb69d89d6 Mon Sep 17 00:00:00 2001 From: Arulpandiyan Vadivel Date: Thu, 19 Apr 2018 12:38:34 +0530 Subject: [PATCH 1637/1834] ARM: dts: msm: enable linear charger in dragon board Enable linear charger, vm-bms drivers and add extcon support in usb_otg node for apq8009 based dragon board. Change-Id: I141580802ad57b242045cc2d196eb19404045400 Signed-off-by: Arulpandiyan Vadivel Signed-off-by: Sundara Vinayagam --- arch/arm64/boot/dts/qcom/apq8009-dragon.dts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts index 1446c9c8b3a5..85b35b4de960 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts @@ -73,11 +73,12 @@ }; &usb_otg { - interrupts = <0 134 0>,<0 140 0>,<0 136 0>; - interrupt-names = "core_irq", "async_irq", "phy_irq"; + interrupts = <0 134 0>,<0 140 0>,<0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; qcom,hsusb-otg-mode = <3>; - qcom,switch-vbus-w-id; + qcom,switch-vbus-w-id; vbus_otg-supply = <&vph_pwr_vreg>; + extcon = <&pm8916_chg>; }; &external_image_mem { @@ -111,3 +112,11 @@ status= "disabled"; }; }; + +&pm8916_chg { + status = "ok"; +}; + +&pm8916_bms { + status = "ok"; +}; -- GitLab From c8d4864d98186e8e743c89398b4faa9f61f689a3 Mon Sep 17 00:00:00 2001 From: Carter Cooper Date: Fri, 18 Aug 2017 10:39:57 -0600 Subject: [PATCH 1638/1834] msm: kgsl: Add handler for GPC interrupt on A6xx GPU Add the interrupt handler to cause a snapshot when the GPC interrupt is received for A6xx. Change-Id: I6eabde0f2bdfc3997bf380055246c2cbdada7cdf Signed-off-by: Carter Cooper Signed-off-by: Harshdeep Dhatt Signed-off-by: Rajesh Kemisetti --- drivers/gpu/msm/adreno_a5xx.c | 8 ++++---- drivers/gpu/msm/adreno_a6xx.c | 25 ++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index d37753e24e4a..776a700cfbce 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -3291,11 +3291,11 @@ static void a5xx_gpmu_int_callback(struct adreno_device *adreno_dev, int bit) } /* - * a5x_gpc_err_int_callback() - Isr for GPC error interrupts + * a5xx_gpc_err_int_callback() - Isr for GPC error interrupts * @adreno_dev: Pointer to device * @bit: Interrupt bit */ -void a5x_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) +static void a5xx_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -3305,7 +3305,7 @@ void a5x_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) * with help of register dump. */ - KGSL_DRV_CRIT(device, "RBBM: GPC error\n"); + KGSL_DRV_CRIT_RATELIMIT(device, "RBBM: GPC error\n"); adreno_irqctrl(adreno_dev, 0); /* Trigger a fault in the dispatcher - this will effect a restart */ @@ -3343,7 +3343,7 @@ static struct adreno_irq_funcs a5xx_irq_funcs[32] = { ADRENO_IRQ_CALLBACK(a5xx_err_callback), /* 6 - RBBM_ATB_ASYNC_OVERFLOW */ ADRENO_IRQ_CALLBACK(a5xx_err_callback), - ADRENO_IRQ_CALLBACK(a5x_gpc_err_int_callback), /* 7 - GPC_ERR */ + ADRENO_IRQ_CALLBACK(a5xx_gpc_err_int_callback), /* 7 - GPC_ERR */ ADRENO_IRQ_CALLBACK(a5xx_preempt_callback),/* 8 - CP_SW */ ADRENO_IRQ_CALLBACK(a5xx_cp_hw_err_callback), /* 9 - CP_HW_ERROR */ /* 10 - CP_CCU_FLUSH_DEPTH_TS */ diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 7fd11d9366ca..88c97b8e71d9 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2639,6 +2639,29 @@ static void a6xx_cp_callback(struct adreno_device *adreno_dev, int bit) adreno_dispatcher_schedule(device); } +/* + * a6xx_gpc_err_int_callback() - Isr for GPC error interrupts + * @adreno_dev: Pointer to device + * @bit: Interrupt bit + */ +static void a6xx_gpc_err_int_callback(struct adreno_device *adreno_dev, int bit) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + + /* + * GPC error is typically the result of mistake SW programming. + * Force GPU fault for this interrupt so that we can debug it + * with help of register dump. + */ + + KGSL_DRV_CRIT_RATELIMIT(device, "RBBM: GPC error\n"); + adreno_irqctrl(adreno_dev, 0); + + /* Trigger a fault in the dispatcher - this will effect a restart */ + adreno_set_gpu_fault(adreno_dev, ADRENO_SOFT_FAULT); + adreno_dispatcher_schedule(device); +} + #define A6XX_INT_MASK \ ((1 << A6XX_INT_CP_AHB_ERROR) | \ (1 << A6XX_INT_ATB_ASYNCFIFO_OVERFLOW) | \ @@ -2663,7 +2686,7 @@ static struct adreno_irq_funcs a6xx_irq_funcs[32] = { ADRENO_IRQ_CALLBACK(NULL), /* 5 - UNUSED */ /* 6 - RBBM_ATB_ASYNC_OVERFLOW */ ADRENO_IRQ_CALLBACK(a6xx_err_callback), - ADRENO_IRQ_CALLBACK(NULL), /* 7 - GPC_ERR */ + ADRENO_IRQ_CALLBACK(a6xx_gpc_err_int_callback), /* 7 - GPC_ERR */ ADRENO_IRQ_CALLBACK(a6xx_preemption_callback),/* 8 - CP_SW */ ADRENO_IRQ_CALLBACK(a6xx_cp_hw_err_callback), /* 9 - CP_HW_ERROR */ ADRENO_IRQ_CALLBACK(NULL), /* 10 - CP_CCU_FLUSH_DEPTH_TS */ -- GitLab From 564ede4112f4ad30a7004f386dc204bcf14b69f9 Mon Sep 17 00:00:00 2001 From: Rajesh Kemisetti Date: Wed, 2 May 2018 15:32:38 +0530 Subject: [PATCH 1639/1834] msm: kgsl: Try again if GPU zap shader loading fails Sometimes GPU Zap shader loading might fail with -EAGAIN. Try to load again in such conditions to see if it succeeds. Change-Id: Icd8e582c36f8f19ff765ed65c2ff68fe6bb007bf Signed-off-by: Rajesh Kemisetti --- drivers/gpu/msm/adreno.h | 3 +++ drivers/gpu/msm/adreno_a5xx.c | 26 ++++++++++++++++++-------- drivers/gpu/msm/adreno_a6xx.c | 26 +++++++++++++++++--------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 686ed34d629e..16da714edc76 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -174,6 +174,9 @@ /* Number of times to try hard reset */ #define NUM_TIMES_RESET_RETRY 5 +/* Number of times to try loading of zap shader */ +#define ZAP_RETRY_MAX 5 + /* Number of times to poll the AHB fence in ISR */ #define FENCE_RETRY_MAX 100 diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index d37753e24e4a..4697464e4644 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2191,6 +2191,7 @@ static int a5xx_microcode_load(struct adreno_device *adreno_dev) struct adreno_firmware *pm4_fw = ADRENO_FW(adreno_dev, ADRENO_FW_PM4); struct adreno_firmware *pfp_fw = ADRENO_FW(adreno_dev, ADRENO_FW_PFP); uint64_t gpuaddr; + int ret = 0, zap_retry = 0; gpuaddr = pm4_fw->memdesc.gpuaddr; kgsl_regwrite(device, A5XX_CP_PM4_INSTR_BASE_LO, @@ -2211,7 +2212,6 @@ static int a5xx_microcode_load(struct adreno_device *adreno_dev) */ if (adreno_dev->zap_loaded && !(ADRENO_FEATURE(adreno_dev, ADRENO_CPZ_RETENTION))) { - int ret; struct scm_desc desc = {0}; desc.args[0] = 0; @@ -2228,15 +2228,25 @@ static int a5xx_microcode_load(struct adreno_device *adreno_dev) /* Load the zap shader firmware through PIL if its available */ if (adreno_dev->gpucore->zap_name && !adreno_dev->zap_loaded) { - ptr = subsystem_get(adreno_dev->gpucore->zap_name); - - /* Return error if the zap shader cannot be loaded */ - if (IS_ERR_OR_NULL(ptr)) - return (ptr == NULL) ? -ENODEV : PTR_ERR(ptr); - adreno_dev->zap_loaded = 1; + /* + * subsystem_get() may return -EAGAIN in case system is busy + * and unable to load the firmware. So keep trying since this + * is not a fatal error. + */ + do { + ret = 0; + ptr = subsystem_get(adreno_dev->gpucore->zap_name); + + /* Return error if the zap shader cannot be loaded */ + if (IS_ERR_OR_NULL(ptr)) { + ret = (ptr == NULL) ? -ENODEV : PTR_ERR(ptr); + ptr = NULL; + } else + adreno_dev->zap_loaded = 1; + } while ((ret == -EAGAIN) && (zap_retry++ < ZAP_RETRY_MAX)); } - return 0; + return ret; } static int _me_init_ucode_workarounds(struct adreno_device *adreno_dev) diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 7fd11d9366ca..6f33e2cf0652 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -845,7 +845,7 @@ static int a6xx_microcode_load(struct adreno_device *adreno_dev) struct adreno_firmware *fw = ADRENO_FW(adreno_dev, ADRENO_FW_SQE); uint64_t gpuaddr; void *zap; - int ret = 0; + int ret = 0, zap_retry = 0; gpuaddr = fw->memdesc.gpuaddr; kgsl_regwrite(device, A6XX_CP_SQE_INSTR_BASE_LO, @@ -855,14 +855,22 @@ static int a6xx_microcode_load(struct adreno_device *adreno_dev) /* Load the zap shader firmware through PIL if its available */ if (adreno_dev->gpucore->zap_name && !adreno_dev->zap_loaded) { - zap = subsystem_get(adreno_dev->gpucore->zap_name); - - /* Return error if the zap shader cannot be loaded */ - if (IS_ERR_OR_NULL(zap)) { - ret = (zap == NULL) ? -ENODEV : PTR_ERR(zap); - zap = NULL; - } else - adreno_dev->zap_loaded = 1; + /* + * subsystem_get() may return -EAGAIN in case system is busy + * and unable to load the firmware. So keep trying since this + * is not a fatal error. + */ + do { + ret = 0; + zap = subsystem_get(adreno_dev->gpucore->zap_name); + + /* Return error if the zap shader cannot be loaded */ + if (IS_ERR_OR_NULL(zap)) { + ret = (zap == NULL) ? -ENODEV : PTR_ERR(zap); + zap = NULL; + } else + adreno_dev->zap_loaded = 1; + } while ((ret == -EAGAIN) && (zap_retry++ < ZAP_RETRY_MAX)); } return ret; -- GitLab From c822ad53b12be5fe1db2650e8de64ee8cd8d73d7 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Wed, 2 May 2018 17:53:32 -0700 Subject: [PATCH 1640/1834] Documentation: Add doc for smmu EMAC support in sdxpoorwills Add DT bindings documentation for EMAC smmu support. Change-Id: I37fea9e7bb898dcb3395975ed19fd86ed96ff2eb CRs-Fixed: 2236527 Acked-by: Nisha Menon Signed-off-by: Sunil Paidimarri --- .../bindings/net/qcom,emac-dwc-eqos.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Documentation/devicetree/bindings/net/qcom,emac-dwc-eqos.txt b/Documentation/devicetree/bindings/net/qcom,emac-dwc-eqos.txt index eff3d82e2124..6f0cbfed5d08 100644 --- a/Documentation/devicetree/bindings/net/qcom,emac-dwc-eqos.txt +++ b/Documentation/devicetree/bindings/net/qcom,emac-dwc-eqos.txt @@ -10,6 +10,7 @@ emac_hw node: - reg: Offset and length of the register regions for the mac and io-macro - interrupts: Interrupt number used by this controller - io-macro-info: Internal io-macro-info +- emac_emb_smmu: Internal emac smmu node Optional: - qcom,msm-bus,name: String representing the client-name @@ -20,16 +21,25 @@ Optional: in KBps, instantaneous bandwidth in KBps qcom,bus-vector-names: specifies string IDs for the corresponding bus vectors in the same order as qcom,msm-bus,vectors-KBps property. +- qcom,arm-smmu: Boolean, if present enables EMAC SMMU support in sdxpoorwills. Internal io-macro-info: - io-macro-bypass-mode: <0 or 1> internal or external delay configuration - io-interface: PHY interface used +Internal emac_emb_smmu: +- compatible: Should be "qcom,emac-smmu-embedded". +- qcom,smmu-s1-bypass: Boolean, if present S1 bypass is enabled. +- iommus: Includes the <&smmu_phandle stream_id size> pair for each context + bank. +- qcom,iova-mapping: of the smmu context bank. + Example: soc { emac_hw: qcom,emac@00020000 { compatible = "qcom,emac-dwc-eqos"; + qcom,arm-smmu; reg = <0x20000 0x10000>, <0x36000 0x100>; reg-names = "emac-base", "rgmii-base"; @@ -57,5 +67,12 @@ soc { io-macro-bypass-mode = <0>; io-interface = "rgmii"; }; + + emac_emb_smmu: emac_emb_smmu { + compatible = "qcom,emac-smmu-embedded"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x220 0xf>; + qcom,iova-mapping = <0x80000000 0x40000000>; + }; }; } -- GitLab From e49ab9939e6cb8ddf4694418d372a75f07e01e56 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Wed, 14 Mar 2018 09:09:28 -0700 Subject: [PATCH 1641/1834] ARM: dts: msm: Add SMMU support for EMAC in sdxpoorwills Add emac smmu entry to enable smmu support in emac for sdxpoorwills. Change-Id: I70a1e3423414f1d578ab1c0bf1032c58546255ba CRs-Fixed: 2224619 Acked-by: Nisha Menon Signed-off-by: Sunil Paidimarri --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index d0f484cdee16..ec5b61e1d334 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1237,6 +1237,7 @@ &soc { emac_hw: qcom,emac@00020000 { compatible = "qcom,emac-dwc-eqos"; + qcom,arm-smmu; reg = <0x20000 0x10000>, <0x36000 0x100>, <0x3900000 0x300000>; @@ -1277,6 +1278,13 @@ io-macro-bypass-mode = <0>; io-interface = "rgmii"; }; + + emac_emb_smmu: emac_emb_smmu { + compatible = "qcom,emac-smmu-embedded"; + qcom,smmu-s1-bypass; + iommus = <&apps_smmu 0x220 0xf>; + qcom,iova-mapping = <0x80000000 0x40000000>; + }; }; ess-instance { -- GitLab From d7c1dc673dab2eacb163de206d87a839f70e4402 Mon Sep 17 00:00:00 2001 From: Madhukar Sandi Date: Fri, 27 Apr 2018 12:21:17 +0530 Subject: [PATCH 1642/1834] ARM: dts: msm: Override firmware android fstab node for apq8009 Since system is mounted as root partition by kernel itself, an early mount of system is not required. then, delete system from fstab node by overriding. Also, override vendor's fsmgr_flags with a/b flags. Change-Id: I0453770ec4f514a3015201936a29f48263384ca7 Signed-off-by: Madhukar Sandi --- arch/arm64/boot/dts/qcom/apq8009-dragon.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts index 85b35b4de960..6b3aea071ea6 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts @@ -113,6 +113,19 @@ }; }; +&firmware { + android { + compatible = "android,firmware"; + fstab { + compatible = "android,fstab"; + vendor_fstab: vendor { + fsmgr_flags = "wait,slotselect"; + }; + /delete-node/ system; + }; + }; +}; + &pm8916_chg { status = "ok"; }; -- GitLab From d09bc698d866055bfa314375c0162781fbd2f210 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 2 May 2018 10:54:28 +0530 Subject: [PATCH 1643/1834] thermal: qpnp-adc-tm: Update adc_tm register offsets for PMIC5 Few adc_tm registers have different offsets on PMIC5 compared to PMIC4. Update logic to account for PMIC5 registers. Change-Id: Icd55ceb9d358facc2e815541effe35a3e43b486c Signed-off-by: Jishnu Prakash --- .../bindings/hwmon/qpnp-adc-voltage.txt | 1 + .../bindings/thermal/qpnp-adc-tm.txt | 1 + drivers/hwmon/qpnp-adc-common.c | 6 ++ drivers/hwmon/qpnp-adc-voltage.c | 6 +- drivers/thermal/qpnp-adc-tm.c | 72 ++++++++++++++----- include/linux/qpnp/qpnp-adc.h | 2 + 6 files changed, 67 insertions(+), 21 deletions(-) diff --git a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt index d9d3470ceff7..432c482e0b9c 100644 --- a/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt +++ b/Documentation/devicetree/bindings/hwmon/qpnp-adc-voltage.txt @@ -10,6 +10,7 @@ VADC node Required properties: - compatible : should be "qcom,qpnp-vadc" for Voltage ADC device driver and "qcom,qpnp-vadc-hc" for VADC_HC voltage ADC device driver. + should include "qcom,qpnp-adc-hc-pm5" for PMIC5. - reg : offset and length of the PMIC Aribter register map. - address-cells : Must be one. - size-cells : Must be zero. diff --git a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt index 97b71a738fc0..d3f765ca4624 100644 --- a/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt +++ b/Documentation/devicetree/bindings/thermal/qpnp-adc-tm.txt @@ -13,6 +13,7 @@ VADC_TM node Required properties: - compatible : should be "qcom,qpnp-adc-tm-hc" for thermal ADC driver using refreshed BTM peripheral. + should include "qcom,qpnp-adc-tm-hc-pm5" for PMIC5. - reg : offset and length of the PMIC Aribter register map. - address-cells : Must be one. - size-cells : Must be zero. diff --git a/drivers/hwmon/qpnp-adc-common.c b/drivers/hwmon/qpnp-adc-common.c index f396c7695e44..b900f76b9b55 100644 --- a/drivers/hwmon/qpnp-adc-common.c +++ b/drivers/hwmon/qpnp-adc-common.c @@ -2495,6 +2495,12 @@ int32_t qpnp_adc_get_devicetree_data(struct platform_device *pdev, } } + if (of_device_is_compatible(node, "qcom,qpnp-adc-hc-pm5") || + of_device_is_compatible(node, "qcom,qpnp-adc-tm-hc-pm5")) + adc_prop->is_pmic_5 = true; + else + adc_prop->is_pmic_5 = false; + for_each_child_of_node(node, child) { int channel_num, scaling = 0, post_scaling = 0; int fast_avg_setup, calib_type = 0, rc, hw_settle_time = 0; diff --git a/drivers/hwmon/qpnp-adc-voltage.c b/drivers/hwmon/qpnp-adc-voltage.c index ed5222eb8f3d..7e6af659a649 100644 --- a/drivers/hwmon/qpnp-adc-voltage.c +++ b/drivers/hwmon/qpnp-adc-voltage.c @@ -35,8 +35,6 @@ #include #include -#define QPNP_VADC_HC_VREF_CODE 0x4000 - /* QPNP VADC register definition */ #define QPNP_VADC_REVISION1 0x0 #define QPNP_VADC_REVISION2 0x1 @@ -508,7 +506,7 @@ int32_t qpnp_vadc_hc_read(struct qpnp_vadc_chip *vadc, goto fail_unlock; } - if (vadc->adc->adc_prop->full_scale_code == QPNP_VADC_HC_VREF_CODE) { + if (!vadc->adc->adc_prop->is_pmic_5) { if (!vadc->vadc_init_calib) { rc = qpnp_vadc_calib_device(vadc); if (rc) { @@ -2595,6 +2593,8 @@ static const struct of_device_id qpnp_vadc_match_table[] = { }, { .compatible = "qcom,qpnp-vadc-hc", }, + { .compatible = "qcom,qpnp-adc-hc-pm5", + }, {} }; diff --git a/drivers/thermal/qpnp-adc-tm.c b/drivers/thermal/qpnp-adc-tm.c index 5c0022e2a2e9..5d345cceb702 100644 --- a/drivers/thermal/qpnp-adc-tm.c +++ b/drivers/thermal/qpnp-adc-tm.c @@ -191,6 +191,8 @@ #define QPNP_BTM_MEAS_INTERVAL_CTL 0x50 #define QPNP_BTM_MEAS_INTERVAL_CTL2 0x51 +#define QPNP_BTM_MEAS_INTERVAL_CTL_PM5 0x44 +#define QPNP_BTM_MEAS_INTERVAL_CTL2_PM5 0x45 #define QPNP_ADC_TM_MEAS_INTERVAL_TIME_SHIFT 0x3 #define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_SHIFT 0x4 #define QPNP_ADC_TM_MEAS_INTERVAL_CTL2_MASK 0xf0 @@ -742,6 +744,7 @@ static int32_t qpnp_adc_tm_timer_interval_select( bool chan_found = false; u8 meas_interval_timer2 = 0, timer_interval_store = 0; uint32_t btm_chan_idx = 0; + bool is_pmic_5 = chip->adc->adc_prop->is_pmic_5; while (i < chip->max_channels_available) { if (chip->sensor[i].btm_channel_num == btm_chan) { @@ -763,10 +766,18 @@ static int32_t qpnp_adc_tm_timer_interval_select( rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MEAS_INTERVAL_CTL, chip->sensor[chan_idx].meas_interval, 1); - else - rc = qpnp_adc_tm_write_reg(chip, - QPNP_BTM_MEAS_INTERVAL_CTL, - chip->sensor[chan_idx].meas_interval, 1); + else { + if (!is_pmic_5) + rc = qpnp_adc_tm_write_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL, + chip->sensor[chan_idx].meas_interval, + 1); + else + rc = qpnp_adc_tm_write_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL_PM5, + chip->sensor[chan_idx].meas_interval, + 1); + } if (rc < 0) { pr_err("timer1 configure failed\n"); return rc; @@ -778,10 +789,16 @@ static int32_t qpnp_adc_tm_timer_interval_select( rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MEAS_INTERVAL_CTL2, &meas_interval_timer2, 1); - else - rc = qpnp_adc_tm_read_reg(chip, + else { + if (!is_pmic_5) + rc = qpnp_adc_tm_read_reg(chip, QPNP_BTM_MEAS_INTERVAL_CTL2, &meas_interval_timer2, 1); + else + rc = qpnp_adc_tm_read_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL2_PM5, + &meas_interval_timer2, 1); + } if (rc < 0) { pr_err("timer2 configure read failed\n"); return rc; @@ -794,10 +811,16 @@ static int32_t qpnp_adc_tm_timer_interval_select( rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MEAS_INTERVAL_CTL2, meas_interval_timer2, 1); - else - rc = qpnp_adc_tm_write_reg(chip, - QPNP_BTM_MEAS_INTERVAL_CTL2, - meas_interval_timer2, 1); + else { + if (!is_pmic_5) + rc = qpnp_adc_tm_write_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL2, + meas_interval_timer2, 1); + else + rc = qpnp_adc_tm_write_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL2_PM5, + meas_interval_timer2, 1); + } if (rc < 0) { pr_err("timer2 configure failed\n"); return rc; @@ -808,10 +831,16 @@ static int32_t qpnp_adc_tm_timer_interval_select( rc = qpnp_adc_tm_read_reg(chip, QPNP_ADC_TM_MEAS_INTERVAL_CTL2, &meas_interval_timer2, 1); - else - rc = qpnp_adc_tm_read_reg(chip, - QPNP_BTM_MEAS_INTERVAL_CTL2, - &meas_interval_timer2, 1); + else { + if (!is_pmic_5) + rc = qpnp_adc_tm_read_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL2, + &meas_interval_timer2, 1); + else + rc = qpnp_adc_tm_read_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL2_PM5, + &meas_interval_timer2, 1); + } if (rc < 0) { pr_err("timer3 read failed\n"); return rc; @@ -823,10 +852,16 @@ static int32_t qpnp_adc_tm_timer_interval_select( rc = qpnp_adc_tm_write_reg(chip, QPNP_ADC_TM_MEAS_INTERVAL_CTL2, meas_interval_timer2, 1); - else - rc = qpnp_adc_tm_write_reg(chip, - QPNP_BTM_MEAS_INTERVAL_CTL2, - meas_interval_timer2, 1); + else { + if (!is_pmic_5) + rc = qpnp_adc_tm_write_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL2, + meas_interval_timer2, 1); + else + rc = qpnp_adc_tm_write_reg(chip, + QPNP_BTM_MEAS_INTERVAL_CTL2_PM5, + meas_interval_timer2, 1); + } if (rc < 0) { pr_err("timer3 configure failed\n"); return rc; @@ -2997,6 +3032,7 @@ static int qpnp_adc_tm_initial_setup(struct qpnp_adc_tm_chip *chip) static const struct of_device_id qpnp_adc_tm_match_table[] = { { .compatible = "qcom,qpnp-adc-tm" }, { .compatible = "qcom,qpnp-adc-tm-hc" }, + { .compatible = "qcom,qpnp-adc-tm-hc-pm5" }, {} }; diff --git a/include/linux/qpnp/qpnp-adc.h b/include/linux/qpnp/qpnp-adc.h index 031573dd8be3..48fe2e981b0c 100644 --- a/include/linux/qpnp/qpnp-adc.h +++ b/include/linux/qpnp/qpnp-adc.h @@ -1065,12 +1065,14 @@ struct qpnp_vadc_scaling_ratio { * @full_scale_code: Full scale value with intrinsic offset removed. * @biploar: Polarity for QPNP ADC. * @adc_hc: Represents using HC variant of the ADC controller. + * @is_pmic_5: To check if PMIC5 is used. */ struct qpnp_adc_properties { uint32_t adc_vdd_reference; uint32_t full_scale_code; bool bipolar; bool adc_hc; + bool is_pmic_5; }; /** -- GitLab From 77497c0467512528adad19b773124588fbbce363 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Wed, 28 Jun 2017 18:31:35 +0530 Subject: [PATCH 1644/1834] msm: mdss: fix the pixel clock calculation for fb modes In the current implementation, if panel is configured in split mode and supports multiple resolutions, then the pixel clock calculation for the supported modes does not take split mode into consideration. This causes issues when recovery or charger application try to configure display. So fix the same by recalculating the pixel clock with taking care of proper width in case of split mode panel. Change-Id: Ie6b50bcd67d3e283610f8b04ac0a974b3527e552 Signed-off-by: Sandeep Panda --- drivers/video/fbdev/msm/mdss_fb.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 27299d1075e8..7ca94df76c87 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1161,11 +1161,24 @@ static int mdss_fb_init_panel_modes(struct msm_fb_data_type *mfd, if (pdata->next) { spt = mdss_panel_get_timing_by_name(pdata->next, modedb[i].name); - if (!IS_ERR_OR_NULL(spt)) + /* for split config, recalculate xres and pixel clock */ + if (!IS_ERR_OR_NULL(spt)) { + unsigned long pclk, h_total, v_total; modedb[i].xres += spt->xres; - else + h_total = modedb[i].xres + + modedb[i].left_margin + + modedb[i].right_margin + + modedb[i].hsync_len; + v_total = modedb[i].yres + + modedb[i].lower_margin + + modedb[i].upper_margin + + modedb[i].vsync_len; + pclk = h_total * v_total * modedb[i].refresh; + modedb[i].pixclock = KHZ2PICOS(pclk / 1000); + } else { pr_debug("no matching split config for %s\n", modedb[i].name); + } /* * if no panel timing found for current, need to -- GitLab From a413b2bd2ce75ea7c15fb8e060e35c163e436eee Mon Sep 17 00:00:00 2001 From: Ashish Garg Date: Tue, 23 May 2017 14:45:55 +0530 Subject: [PATCH 1645/1834] msm: mdss: ensure clocks are on till pixel transfer is completed When pixel transfer is going on, there is a race condition during which pixel clock can get turned off due to early clock gating before CMD_MDP interrupt is triggered which can cause interrupt storm. This change ensures CMD_MDP interrupt is received before turning off clocks. Change-Id: I33b664334912584170c12733329051b067c3f1da Signed-off-by: Ashish Garg --- drivers/video/fbdev/msm/mdss_dsi_host.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 7d737b539817..26252ce338b5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -161,7 +161,14 @@ void mdss_dsi_clk_req(struct mdss_dsi_ctrl_pdata *ctrl, MDSS_XLOG(ctrl->ndx, enable, ctrl->mdp_busy, current->pid, client); - if (enable == 0) { + /* + * ensure that before going into ecg or turning + * off the clocks, cmd_mdp_busy is not true. During a + * race condition, clocks are turned off and so the + * isr for cmd_mdp_busy does not get cleared in hw. + */ + if (enable == MDSS_DSI_CLK_OFF || + enable == MDSS_DSI_CLK_EARLY_GATE) { /* need wait before disable */ mutex_lock(&ctrl->cmd_mutex); mdss_dsi_cmd_mdp_busy(ctrl); -- GitLab From 088c7c7429fca7ad06ad05778111baaec8142a1a Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Thu, 13 Apr 2017 13:11:40 +0530 Subject: [PATCH 1646/1834] msm: mdss: avoid fake ack and overflow errors during ESD In the current implementation DSI driver is masking the fake ACK and overflow errors that might occur during if BTA mechanism is used to check ESD. But if register read mechanism is used to check ESD, then also embedded BTA will be triggered and fake ACK and overflow errors might be reported. Mask the same for register based ESD check also. Change-Id: If1ee0a7cc0171b96a3b7298aa5201372c6eb8139 Signed-off-by: Sandeep Panda --- drivers/video/fbdev/msm/mdss_dsi_host.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 7d737b539817..85e84895fffd 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -2974,7 +2974,10 @@ bool mdss_dsi_ack_err_status(struct mdss_dsi_ctrl_pdata *ctrl) * warning message is ignored. */ if (ctrl->panel_data.panel_info.esd_check_enabled && - (ctrl->status_mode == ESD_BTA) && (status & 0x1008000)) + ((ctrl->status_mode == ESD_BTA) || + (ctrl->status_mode == ESD_REG) || + (ctrl->status_mode == ESD_REG_NT35596)) && + (status & 0x1008000)) return false; pr_err("%s: status=%x\n", __func__, status); @@ -3205,8 +3208,10 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) * cleared. */ if (ctrl->panel_data.panel_info.esd_check_enabled && - (ctrl->status_mode == ESD_BTA) && - (ctrl->panel_mode == DSI_VIDEO_MODE)) { + ((ctrl->status_mode == ESD_BTA) || + (ctrl->status_mode == ESD_REG) || + (ctrl->status_mode == ESD_REG_NT35596)) && + (ctrl->panel_mode == DSI_VIDEO_MODE)) { isr &= ~DSI_INTR_ERROR; /* clear only overflow */ mdss_dsi_set_reg(ctrl, 0x0c, 0x44440000, 0x44440000); -- GitLab From 9883b5084350f718786479235a5cd80693dca8b3 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Fri, 19 May 2017 15:54:16 +0530 Subject: [PATCH 1647/1834] msm: mdss: do not print error in case sync_trigger is enabled In case sync trigger is enabled, then DCS commands are only sent for both the DSI controller when transfer call for the second DSI controller happens. So in that case do not print error log for the first controller if DCS command is not sent. Change-Id: I5c302f55f15735970cd5f6c8d0b31c55b447433f Signed-off-by: Sandeep Panda --- drivers/video/fbdev/msm/mdss_dsi_host.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 7d737b539817..064b2c234703 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -1155,6 +1155,8 @@ static int mdss_dsi_read_status(struct mdss_dsi_ctrl_pdata *ctrl) rc = mdss_dsi_cmdlist_put(ctrl, &cmdreq); if (rc <= 0) { + if (!mdss_dsi_sync_wait_enable(ctrl) || + mdss_dsi_sync_wait_trigger(ctrl)) pr_err("%s: get status: fail\n", __func__); return rc; } -- GitLab From cbaf6442a2dd0db45427c3c5a2cb3b96f77cf4ec Mon Sep 17 00:00:00 2001 From: Rashi Bindra Date: Mon, 15 May 2017 12:10:40 +0530 Subject: [PATCH 1648/1834] msm: mdss: Read status value from master controller Read the panel status from master controller when sync wait broadcast is enabled for the panel. Change-Id: I57ddac718738f3a6749d1deddae93b25e7f77261 Signed-off-by: Rashi Bindra --- drivers/video/fbdev/msm/mdss_dsi_host.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 7d737b539817..4fa373600479 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -2186,6 +2186,7 @@ static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl, bool ack_error = false; char reg[16]; int repeated_bytes = 0; + struct mdss_dsi_ctrl_pdata *mctrl = mdss_dsi_get_other_ctrl(ctrl); lp = (u32 *)rp->data; temp = (u32 *)reg; @@ -2246,7 +2247,11 @@ static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl, off += ((cnt - 1) * 4); for (i = 0; i < cnt; i++) { - data = (u32)MIPI_INP((ctrl->ctrl_base) + off); + if (mdss_dsi_sync_wait_trigger(ctrl)) + data = (u32)MIPI_INP((mctrl->ctrl_base) + off); + else + data = (u32)MIPI_INP((ctrl->ctrl_base) + off); + /* to network byte order */ if (!repeated_bytes) *lp++ = ntohl(data); -- GitLab From de193409a52717727132e818dcda31c1555f9e58 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Fri, 27 Apr 2018 12:14:50 +0530 Subject: [PATCH 1649/1834] power: fg-alg: add min_start_soc to begin the capacity learning Currently, capacity learning begins based on SOC threshold and battery temperature. Since the SOC threshold to begin cannot be qualified in certain low battery conditions, add another minimum SOC threshold for a better qualification. CRs-Fixed: 2225348 Change-Id: If916c0a04cec785dc25f3c70d0ea1643d598f479 Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/fg-alg.c | 12 +++++++----- drivers/power/supply/qcom/fg-alg.h | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c index 3d74f7e4452c..f1ce5b3057d7 100644 --- a/drivers/power/supply/qcom/fg-alg.c +++ b/drivers/power/supply/qcom/fg-alg.c @@ -327,13 +327,15 @@ static int cap_learning_process_full_data(struct cap_learning *cl) */ static int cap_learning_begin(struct cap_learning *cl, u32 batt_soc) { - int rc, cc_soc_sw, batt_soc_msb; + int rc, cc_soc_sw, batt_soc_msb, batt_soc_pct; batt_soc_msb = batt_soc >> 24; - if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) > - cl->dt.start_soc) { - pr_debug("Battery SOC %d is high!, not starting\n", - batt_soc_msb); + batt_soc_pct = DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW); + + if (batt_soc_pct > cl->dt.max_start_soc || + batt_soc_pct < cl->dt.min_start_soc) { + pr_debug("Battery SOC %d is high/low, not starting\n", + batt_soc_pct); return -EINVAL; } diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h index ff5becee881b..0853ad9c32b7 100644 --- a/drivers/power/supply/qcom/fg-alg.h +++ b/drivers/power/supply/qcom/fg-alg.h @@ -29,7 +29,8 @@ struct cycle_counter { }; struct cl_params { - int start_soc; + int min_start_soc; + int max_start_soc; int max_temp; int min_temp; int max_cap_inc; -- GitLab From fd9ffeeccdc78d121025cf98e18afc5b2197b602 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Sun, 6 May 2018 18:10:48 +0300 Subject: [PATCH 1650/1834] msm: ipa3: fix debugfs creation order IPA unit-test module is initialized by IPA ready callback. The ready callback is called before creating IPA debugfs root folder in which IPA unit-test module depends on. Change-Id: Id3e867cd074730a3006e124d1074bedef081920a Signed-off-by: Ghanim Fodi --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index af926fb9498f..9eb3c352d832 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -4718,12 +4718,12 @@ static int ipa3_post_init(const struct ipa3_plat_drv_res *resource_p, ipa3_ctx->ipa_initialization_complete = true; mutex_unlock(&ipa3_ctx->lock); + ipa3_debugfs_init(); + ipa3_trigger_ipa_ready_cbs(); complete_all(&ipa3_ctx->init_completion_obj); pr_info("IPA driver initialization was successful.\n"); - ipa3_debugfs_init(); - return 0; fail_teth_bridge_driver_init: -- GitLab From 25b3bf8835610befbbeb8582591162aabdc3c882 Mon Sep 17 00:00:00 2001 From: Shadab Naseem Date: Fri, 4 May 2018 14:32:44 +0530 Subject: [PATCH 1651/1834] defconfig: msm: Enable msm serial for sdxpoorwills perf Enable msm serial driver for sdxpoorwills perf build for uart shell to work. Change-Id: Ibaadc63c7d66f6a56aa36104f666963528b9c68c Signed-off-by: Shadab Naseem --- arch/arm/configs/sdxpoorwills-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index e3c1c1aa817b..aaed1a290061 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -217,6 +217,7 @@ CONFIG_INPUT_UINPUT=y CONFIG_INPUT_GPIO=m CONFIG_SERIO_LIBPS2=y # CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_HS=y CONFIG_DIAG_CHAR=y CONFIG_HW_RANDOM=y -- GitLab From d58d6879449606f67ec727d96a5dafd044130073 Mon Sep 17 00:00:00 2001 From: Vaishnavi Kommaraju Date: Thu, 26 Apr 2018 20:33:18 +0530 Subject: [PATCH 1652/1834] ARM: dts: msm: Update audio related device nodes for SDM439 CDP Update drive strengths as per HW requirement to 16mA to fix recording issue on SDM439 CDP platform. Also, add property to detect headset on SDM439 platforms. Change-Id: Icb7492c7c94761326e5a4149f34ab04b5dac6999 Signed-off-by: Vaishnavi Kommaraju --- arch/arm64/boot/dts/qcom/sdm439-audio.dtsi | 1 + arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi | 24 ++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi index f6751d2445aa..dba56a4ab8d3 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi @@ -15,6 +15,7 @@ int_codec: sound { qcom,model = "sdm439-snd-card-mtp"; qcom,msm-hs-micbias-type = "internal"; + qcom,msm-micbias2-ext-cap; asoc-codec = <&stub_codec>, <&msm_digital_codec>, <&pmic_analog_codec>; diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi index 08745cdfeca7..fd66f4b2e858 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-cdp.dtsi @@ -150,6 +150,30 @@ }; }; +&cdc_pdm_lines_2_act { + mux { + pins = "gpio70", "gpio71", "gpio72"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio70", "gpio71", "gpio72"; + drive-strength = <16>; + }; +}; + +&cdc_pdm_lines_act { + mux { + pins = "gpio69", "gpio73", "gpio74"; + function = "cdc_pdm0"; + }; + + config { + pins = "gpio69", "gpio73", "gpio74"; + drive-strength = <16>; + }; +}; + &pm8953_pwm { status = "ok"; }; -- GitLab From 0f97e35b65b70a1d9a46ab32b819bbcb011428f1 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Mon, 7 May 2018 11:05:55 +0530 Subject: [PATCH 1653/1834] msm: kgsl: Correct GPU busy counter overflow detection Correct overflow detection check to return true only if previous value of register ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI is less than current value. Also, update the counter variable to current counter value incase where abnormal counter value is observed to make sure next GPU busy sample is correct. Change-Id: If2d504791123eedf1dca3bdc85ff0166c1e8ae13 Signed-off-by: Deepak Kumar --- drivers/gpu/msm/adreno.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 8b88aadfc2f6..8c7c8369bd2e 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -1805,7 +1805,7 @@ static inline bool is_power_counter_overflow(struct adreno_device *adreno_dev, return ret; } adreno_readreg(adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_HI, &val); - if (val != *perfctr_pwr_hi) { + if (val > *perfctr_pwr_hi) { *perfctr_pwr_hi = val; ret = true; } @@ -1820,14 +1820,17 @@ static inline unsigned int counter_delta(struct kgsl_device *device, unsigned int ret = 0; bool overflow = true; static unsigned int perfctr_pwr_hi; + unsigned int prev_perfctr_pwr_hi = 0; /* Read the value */ kgsl_regread(device, reg, &val); if (adreno_is_a5xx(adreno_dev) && reg == adreno_getreg - (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO)) + (adreno_dev, ADRENO_REG_RBBM_PERFCTR_RBBM_0_LO)) { + prev_perfctr_pwr_hi = perfctr_pwr_hi; overflow = is_power_counter_overflow(adreno_dev, reg, *counter, &perfctr_pwr_hi); + } /* Return 0 for the first read */ if (*counter != 0) { @@ -1840,9 +1843,12 @@ static inline unsigned int counter_delta(struct kgsl_device *device, * Since KGSL got abnormal value from the counter, * We will drop the value from being accumulated. */ - pr_warn_once("KGSL: Abnormal value :0x%x (0x%x) from perf counter : 0x%x\n", - val, *counter, reg); - return 0; + KGSL_DRV_ERR_RATELIMIT(device, + "Abnormal value:0x%llx (0x%llx) from perf counter : 0x%x\n", + val | ((uint64_t)perfctr_pwr_hi << 32), + *counter | + ((uint64_t)prev_perfctr_pwr_hi << 32), + reg); } } -- GitLab From 6f3c18f3837bf3f2cd62e5b45aee3b9699016424 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Mon, 7 May 2018 12:23:24 +0300 Subject: [PATCH 1654/1834] wil6210: initialize PN in the vring descriptor It is seen that with cache-coherency enabled, PN is sometimes not being flushed/written. As a temporary workaround add initialization of the PN to avoid reading invalid value. Change-Id: I9e4389b26ea4e2637c1fdb15b8db6f39d0d55ee1 Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/txrx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index dcec343864aa..d0fecd9f8a4c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -323,6 +323,8 @@ static int wil_vring_alloc_skb(struct wil6210_priv *wil, struct vring *vring, return -ENOMEM; } + d->mac.pn_15_0 = 0; + d->mac.pn_47_16 = 0; d->dma.d0 = RX_DMA_D0_CMD_DMA_RT | RX_DMA_D0_CMD_DMA_IT; wil_desc_addr_set(&d->dma.addr, pa); /* ip_length don't care */ -- GitLab From cbf64ca904b18b2d7a86126de43966bf9df1a949 Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Mon, 7 May 2018 14:53:21 +0530 Subject: [PATCH 1655/1834] defconfig: Enable F2FS for 8917 Enable F2FS related config options for MSM8917. Change-Id: I4553d5f18673fcdbb7969c25931822cf4172fdd6 Signed-off-by: Swetha Chikkaboraiah --- arch/arm/configs/msm8937-perf_defconfig | 2 ++ arch/arm/configs/msm8937_defconfig | 2 ++ arch/arm64/configs/msm8937-perf_defconfig | 2 ++ arch/arm64/configs/msm8937_defconfig | 2 ++ 4 files changed, 8 insertions(+) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 5a6de0f4f422..6fdaac8b9a82 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -581,6 +581,8 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 858b506ba37a..085006895c5b 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -597,6 +597,8 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 4c6b6a1b39b4..291eba4465a1 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -589,6 +589,8 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index 11bd200bdd36..94f5e126762b 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -607,6 +607,8 @@ CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y CONFIG_QUOTA=y CONFIG_QUOTA_NETLINK_INTERFACE=y CONFIG_QFMT_V2=y -- GitLab From 3830a9597d30f3afe102c4d481a892381b8f1748 Mon Sep 17 00:00:00 2001 From: Sachin Mohan Gadag Date: Fri, 4 May 2018 19:24:58 +0530 Subject: [PATCH 1656/1834] ARM: dts: msm: Add external codec support for apq8053 IOT Add external codec support and disable internal codec support for apq8053 IOT target, because IOT apq8053 target supports external codec. CRs-fixed: 1072203 Change-Id: I9e5b0af18a971ffba6f311c33707b720f588ca75 Signed-off-by: Sachin Mohan Gadag --- arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts | 60 ++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts index 8f7e3261e3b1..9f0edda5e3ed 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-iot-mtp.dts @@ -26,3 +26,63 @@ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; }; +&int_codec { + status = "disabled"; +}; + +&wsa881x_i2c_f { + status = "disabled"; +}; + +&wsa881x_i2c_45 { + status = "disabled"; +}; + +&cdc_pri_mi2s_gpios { + status = "disabled"; +}; + +&wsa881x_analog_vi_gpio { + status = "disabled"; +}; + +&wsa881x_analog_clk_gpio { + status = "disabled"; +}; + +&wsa881x_analog_reset_gpio { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&slim_msm { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; + +&wcd9335 { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + qcom,model = "msm8953-tasha-snd-card"; + status = "okay"; +}; -- GitLab From fe450a7dc06a59441d2874ee7e3e7fbdca68ff4a Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Fri, 4 May 2018 10:51:15 +0530 Subject: [PATCH 1657/1834] ARM: dts: msm: Add label for PMIC5 In driver code, some register offsets are different for PMIC5. Add label to identify PMIC5 to select correct register offsets. Change-Id: I5a1aa6101f7ef27b2b77398dc03296cf0ec0336c Signed-off-by: Jishnu Prakash --- arch/arm64/boot/dts/qcom/pmi632.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index 48bda6121c05..80480f14b7e3 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -35,7 +35,8 @@ }; pmi632_vadc: vadc@3100 { - compatible = "qcom,qpnp-vadc-hc"; + compatible = "qcom,qpnp-vadc-hc", + "qcom,qpnp-adc-hc-pm5"; reg = <0x3100 0x100>; #address-cells = <1>; #size-cells = <0>; @@ -252,7 +253,8 @@ }; pmi632_adc_tm: vadc@3500 { - compatible = "qcom,qpnp-adc-tm-hc"; + compatible = "qcom,qpnp-adc-tm-hc", + "qcom,qpnp-adc-tm-hc-pm5"; reg = <0x3500 0x100>; #address-cells = <1>; #size-cells = <0>; -- GitLab From 21358bd7a0680e3f4785dff95d884001b2f005e0 Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Mon, 18 Jul 2016 12:54:23 +0530 Subject: [PATCH 1658/1834] msm: mdss: fix mdss errors on 32-bit compilation Changes made to fix mdss compilation errors on 32-bit mode Change-Id: Ic28f6f36781154ff0c28f4636ade8523d753ab6a Signed-off-by: Raviteja Tamatam --- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 344d6efc2f37..a4b3be04f259 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -571,11 +571,12 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe, u32 fps, u32 v_total) { u32 active_line_cycle, backfill_cycle, total_cycle; - u32 ver_dwnscale; + u64 ver_dwnscale; u32 active_line; u32 backfill_line; - ver_dwnscale = (src_h << PHASE_STEP_SHIFT) / dst.h; + ver_dwnscale = src_h << PHASE_STEP_SHIFT; + do_div(ver_dwnscale, dst.h); if (ver_dwnscale > (MDSS_MDP_QSEED3_VER_DOWNSCALE_LIM << PHASE_STEP_SHIFT)) { @@ -599,7 +600,7 @@ static u32 __calc_qseed3_mdp_clk_rate(struct mdss_mdp_pipe *pipe, total_cycle = active_line_cycle + backfill_cycle; pr_debug("line: active=%d backfill=%d vds=%d\n", - active_line, backfill_line, ver_dwnscale); + active_line, backfill_line, (u32)ver_dwnscale); pr_debug("cycle: total=%d active=%d backfill=%d\n", total_cycle, active_line_cycle, backfill_cycle); -- GitLab From 5f494b2bbe46e4a1f3781fb749a31c42d27ac5e8 Mon Sep 17 00:00:00 2001 From: Alan Kwong Date: Fri, 12 Aug 2016 19:15:25 -0400 Subject: [PATCH 1659/1834] msm: mdss: shutoff axi memory and periphery when axi clk is off Because of CBCR update, mdss driver needs to control mdss axi clock state of memory core and periphery control when branch clock is off. Since mdss does not have retention requirement for axi, both memory core and periphery control can be turned off to conserve power when mdss axi clock is off. CRs-Fixed: 1044375 Change-Id: Ia609549304be97cdaeff0f30ff0ca8ad5e22af75 Signed-off-by: Alan Kwong --- drivers/video/fbdev/msm/mdss_mdp.c | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index e472e7fb5568..a6d43a6cd57b 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1455,6 +1455,35 @@ static int mdss_mdp_idle_pc_restore(void) return rc; } +/** + * mdss_mdp_retention_init() - initialize retention setting + * @mdata: pointer to the global mdss data structure. + */ +static int mdss_mdp_retention_init(struct mdss_data_type *mdata) +{ + struct clk *mdss_axi_clk = mdss_mdp_get_clk(MDSS_CLK_AXI); + int rc; + + if (!mdss_axi_clk) { + pr_err("failed to get AXI clock\n"); + return -EINVAL; + } + + rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_MEM); + if (rc) { + pr_err("failed to set AXI no memory retention %d\n", rc); + return rc; + } + + rc = clk_set_flags(mdss_axi_clk, CLKFLAG_NORETAIN_PERIPH); + if (rc) { + pr_err("failed to set AXI no periphery retention %d\n", rc); + return rc; + } + + return rc; +} + /** * mdss_bus_bandwidth_ctrl() -- place bus bandwidth request * @enable: value of enable or disable @@ -2695,6 +2724,12 @@ static int mdss_mdp_probe(struct platform_device *pdev) goto probe_done; } + rc = mdss_mdp_retention_init(mdata); + if (rc) { + pr_err("unable to initialize mdss mdp retention\n"); + goto probe_done; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT_MS); if (mdata->idle_pc_enabled) pm_runtime_use_autosuspend(&pdev->dev); -- GitLab From 07bef04243800b120fe923778064b9929334783c Mon Sep 17 00:00:00 2001 From: Ingrid Gallardo Date: Thu, 18 Aug 2016 19:38:13 -0700 Subject: [PATCH 1660/1834] msm: mdss: increase mdp hw recovery timeout In some cases, display driver times out waiting for the mdp hw recovery to complete, causing the device to panic; however in some cases hw is able to successfuly complete the recovery after some more time. This change increases the timeout, so driver waits more time for the hw to complete the recovery sequence. CRs-Fixed: 1055875 Change-Id: I31909c45a4fec921da322658ec84d387d0f182ac Signed-off-by: Ingrid Gallardo --- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index a4b3be04f259..368848de0c29 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4341,9 +4341,11 @@ void mdss_mdp_check_ctl_reset_status(struct mdss_mdp_ctl *ctl) return; pr_debug("hw ctl reset is set for ctl:%d\n", ctl->num); - status = mdss_mdp_poll_ctl_reset_status(ctl, 5); + /* poll for at least ~1 frame */ + status = mdss_mdp_poll_ctl_reset_status(ctl, 320); if (status) { - pr_err("hw recovery is not complete for ctl:%d\n", ctl->num); + pr_err("hw recovery is not complete for ctl:%d status:0x%x\n", + ctl->num, status); MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt", "dbg_bus", "vbif_dbg_bus", "panic"); } -- GitLab From c3daa1500777cfd00171a650aee2b5ff77334772 Mon Sep 17 00:00:00 2001 From: Benjamin Chan Date: Wed, 17 Aug 2016 10:16:50 -0400 Subject: [PATCH 1661/1834] msm: mdss: Correct command mode MISR CRC reg offset and blockid msmcobalt has a different command mode MISR CRC register offset. Correct the offset for the MISR control and signature registers, and correct the block_id by lookup the INTF number from CTL. CRs-Fixed: 1049910 Change-Id: If4fb44d217ed84067a0732334523ddb1e435e4e7 Signed-off-by: Benjamin Chan --- drivers/video/fbdev/msm/mdss_debug.c | 40 ++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c index f38d40c8aa18..ef2df7f612eb 100644 --- a/drivers/video/fbdev/msm/mdss_debug.c +++ b/drivers/video/fbdev/msm/mdss_debug.c @@ -1377,6 +1377,38 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id, } } else { if (block_id <= DISPLAY_MISR_HDMI) { + /* + * In Dual LM single display configuration, + * the interface number (i.e. block_id) + * might not be the one given from ISR. + * We should always check with the actual + * intf_num from ctl. + */ + struct msm_fb_data_type *mfd = NULL; + + /* + * ISR pass in NULL ctl, so we need to get it + * from the mdata. + */ + if (!ctl && mdata->mixer_intf) + ctl = mdata->mixer_intf->ctl; + if (ctl) + mfd = ctl->mfd; + if (mfd && is_dual_lm_single_display(mfd)) { + switch (ctl->intf_num) { + case MDSS_MDP_INTF1: + block_id = DISPLAY_MISR_DSI0; + break; + case MDSS_MDP_INTF2: + block_id = DISPLAY_MISR_DSI1; + break; + default: + pr_err("Unmatch INTF for Dual LM single display configuration, INTF:%d\n", + ctl->intf_num); + return NULL; + } + } + intf_base = (char *)mdss_mdp_get_intf_base_addr( mdata, block_id); @@ -1390,11 +1422,15 @@ static inline struct mdss_mdp_misr_map *mdss_misr_get_map(u32 block_id, /* * extra offset required for - * cmd misr in 8996 + * cmd misr in 8996 and mdss3.x */ if (IS_MDSS_MAJOR_MINOR_SAME( mdata->mdp_rev, - MDSS_MDP_HW_REV_107)) { + MDSS_MDP_HW_REV_107) || + (mdata->mdp_rev == + MDSS_MDP_HW_REV_300) || + (mdata->mdp_rev == + MDSS_MDP_HW_REV_301)) { ctrl_reg += 0x8; value_reg += 0x8; } -- GitLab From 7f87b6d3e860591de4800e050e79a510f72abcdc Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Mon, 12 Sep 2016 11:10:30 -0700 Subject: [PATCH 1662/1834] msm: mdss: wait for kickoff before executing mode switch changes Currently, as soon as the mode switch for video-cmd mode request kicks in, few software structures are changed immediately. This might cause issues when the previous kickoff is in progress with the kernel thread. Add wait for kickoff before executing mode switch to avoid such issues. Change-Id: I2646d00d64416523da9c936715e9af9a2b258eeb Signed-off-by: Veera Sundaram Sankaran --- drivers/video/fbdev/msm/mdss_fb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 27299d1075e8..79a2495a2bfb 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -4730,6 +4730,9 @@ static int mdss_fb_mode_switch(struct msm_fb_data_type *mfd, u32 mode) if (!mfd || !mfd->panel_info) return -EINVAL; + /* make sure that we are idle while switching */ + mdss_fb_wait_for_kickoff(mfd); + pinfo = mfd->panel_info; if (pinfo->mipi.dms_mode == DYNAMIC_MODE_SWITCH_SUSPEND_RESUME) { ret = mdss_fb_blanking_mode_switch(mfd, mode); -- GitLab From b7ce654575c9ab3655a2a2cac5590a294f9412ee Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Mon, 7 May 2018 16:59:53 +0530 Subject: [PATCH 1663/1834] USB: pd: Fix compilation issues for 32 bit support Compilation errors are seen from policy_engine.c driver, when try to compile for 32 bit support. Hence fix those errors for 32 bit support getting compiled successfully. Change-Id: Id891d5ebcfbb85c1515c2aa60b192264b7a20db0 Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/pd/policy_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index 56b2a6d5623b..a387bb09bfe4 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -942,7 +942,7 @@ static struct rx_msg *pd_ext_msg_received(struct usbpd *pd, u16 header, u8 *buf, /* check against received length to avoid overrun */ if (bytes_to_copy > len - sizeof(ext_hdr)) { - usbpd_warn(&pd->dev, "not enough bytes in chunk, expected:%u received:%lu\n", + usbpd_warn(&pd->dev, "not enough bytes in chunk, expected:%u received:%zu\n", bytes_to_copy, len - sizeof(ext_hdr)); bytes_to_copy = len - sizeof(ext_hdr); } -- GitLab From 9efa44793ef532623ae5275fb69205de80c4c471 Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Mon, 7 May 2018 19:09:36 +0530 Subject: [PATCH 1664/1834] mm: vmpressure: fix dual calls to global vmpressure vmpressure function is invoked multiple time from shrink_node, once for each memcg and then for the entire subtree. But global vmpressure calculation is performed for each of these calls resulting in window period ending fast. This is not a problem when CONFIG_MEMCG is enabled, as global vmpressure is not used in that case. With !CONFIG_MEMCG global vmpressure is called twice. Fix this. Change-Id: I9262790dbe38880e56917b2214c2da59a342ce66 Signed-off-by: Vinayak Menon --- mm/vmpressure.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmpressure.c b/mm/vmpressure.c index 1306f326620d..e468da694b47 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -423,7 +423,7 @@ static void vmpressure_global(gfp_t gfp, unsigned long scanned, void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree, unsigned long scanned, unsigned long reclaimed) { - if (!memcg) + if (!memcg && tree) vmpressure_global(gfp, scanned, reclaimed); if (IS_ENABLED(CONFIG_MEMCG)) -- GitLab From 1467f2a4c6437a530d447c3b9c32e3a466afc5e2 Mon Sep 17 00:00:00 2001 From: Anindya Sundar Gayen Date: Fri, 4 May 2018 17:37:23 +0530 Subject: [PATCH 1665/1834] defconfig: Enable MPM support for APQ8009 Enable MPM interrupt controller support. Change-Id: I582c5a7c39ec8888614e769461b7b9624ea77051 Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909-perf_defconfig | 1 + arch/arm/configs/msm8909_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 6f3cee42936d..aee8104be698 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -425,6 +425,7 @@ CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_PWM=y CONFIG_PWM_QPNP=y +CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index f57e45dbbd6f..b82c3fd0ea16 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -420,6 +420,7 @@ CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_PWM=y CONFIG_PWM_QPNP=y +CONFIG_QTI_MPM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y -- GitLab From 9eee1933854ed3372859285d4bdef72f80030b02 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Wed, 25 Apr 2018 11:25:42 +0530 Subject: [PATCH 1666/1834] drm/msm/sde: enable backlight in ESD recovery case In case of ESD recovery display disable/enable happens without the knowledge of backlight framework. So backlight does not change during this period. This causes issues where panel used DCS backlight update method where backlight is lost during ESD trigger and it is not set again after recovery is complete. This change fixes the issue by calling backlight update API during ESD recovery display enable/disable case. Change-Id: I157120688603dd0558b773bbf41996b6d7373d94 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_drm.c | 7 +++++- drivers/gpu/drm/msm/sde/sde_connector.c | 30 +++++++++++++++++++++-- drivers/gpu/drm/msm/sde/sde_connector.h | 10 +++++++- 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c index 5b4786596d33..6b5bfb4a5cb1 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_drm.c @@ -186,6 +186,7 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) { int rc = 0; struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); + struct dsi_display *display; if (!bridge) { pr_err("Invalid params\n"); @@ -197,11 +198,15 @@ static void dsi_bridge_enable(struct drm_bridge *bridge) pr_debug("[%d] seamless enable\n", c_bridge->id); return; } + display = c_bridge->display; - rc = dsi_display_post_enable(c_bridge->display); + rc = dsi_display_post_enable(display); if (rc) pr_err("[%d] DSI display post enabled failed, rc=%d\n", c_bridge->id, rc); + + if (display && display->drm_conn) + sde_connector_helper_bridge_enable(display->drm_conn); } static void dsi_bridge_disable(struct drm_bridge *bridge) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index d2f8d12cdaa6..f1c1d6342fe1 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -623,6 +623,7 @@ int sde_connector_pre_kickoff(struct drm_connector *connector) void sde_connector_helper_bridge_disable(struct drm_connector *connector) { int rc; + struct sde_connector *c_conn = NULL; if (!connector) return; @@ -633,6 +634,31 @@ void sde_connector_helper_bridge_disable(struct drm_connector *connector) connector->base.id, rc); SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR); } + + c_conn = to_sde_connector(connector); + if (c_conn->panel_dead) { + c_conn->bl_device->props.power = FB_BLANK_POWERDOWN; + c_conn->bl_device->props.state |= BL_CORE_FBBLANK; + backlight_update_status(c_conn->bl_device); + } +} + +void sde_connector_helper_bridge_enable(struct drm_connector *connector) +{ + struct sde_connector *c_conn = NULL; + + if (!connector) + return; + + c_conn = to_sde_connector(connector); + + /* Special handling for ESD recovery case */ + if (c_conn->panel_dead) { + c_conn->bl_device->props.power = FB_BLANK_UNBLANK; + c_conn->bl_device->props.state &= ~BL_CORE_FBBLANK; + backlight_update_status(c_conn->bl_device); + c_conn->panel_dead = false; + } } int sde_connector_clk_ctrl(struct drm_connector *connector, bool enable) @@ -1734,15 +1760,15 @@ sde_connector_best_encoder(struct drm_connector *connector) static void _sde_connector_report_panel_dead(struct sde_connector *conn) { struct drm_event event; - bool panel_dead = true; if (!conn) return; + conn->panel_dead = true; event.type = DRM_EVENT_PANEL_DEAD; event.length = sizeof(bool); msm_mode_object_event_notify(&conn->base.base, - conn->base.dev, &event, (u8 *)&panel_dead); + conn->base.dev, &event, (u8 *)&conn->panel_dead); sde_encoder_display_failure_notification(conn->encoder); SDE_EVT32(SDE_EVTLOG_ERROR); SDE_ERROR("esd check failed report PANEL_DEAD conn_id: %d enc_id: %d\n", diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index c6f348ec80ef..0c2445487788 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -324,6 +324,8 @@ struct sde_connector_evt { * @status_work: work object to perform status checks * @force_panel_dead: variable to trigger forced ESD recovery * @esd_status_interval: variable to change ESD check interval in millisec + * @panel_dead: Flag to indicate if panel has gone bad + * @esd_status_check: Flag to indicate if ESD thread is scheduled or not * @bl_scale_dirty: Flag to indicate PP BL scale value(s) is changed * @bl_scale: BL scale value for ABA feature * @bl_scale_ad: BL scale value for AD feature @@ -365,7 +367,7 @@ struct sde_connector { struct delayed_work status_work; u32 force_panel_dead; u32 esd_status_interval; - + bool panel_dead; bool esd_status_check; bool bl_scale_dirty; @@ -762,6 +764,12 @@ void sde_conn_timeline_status(struct drm_connector *conn); */ void sde_connector_helper_bridge_disable(struct drm_connector *connector); +/** + * sde_connector_helper_bridge_enable - helper function for drm bridge enable + * @connector: Pointer to DRM connector object + */ +void sde_connector_helper_bridge_enable(struct drm_connector *connector); + /** * sde_connector_get_panel_vfp - helper to get panel vfp * @connector: pointer to drm connector -- GitLab From f20db7285b64b3729cb181248cc62a4d0b04ded7 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Fri, 4 May 2018 10:56:59 +0530 Subject: [PATCH 1667/1834] drm/msm/dsi-staging: update ESD thread disable sequence Currently to synchronize ESD check and DSI disable, ESD thread acquires display mutex before the check starts. But this is causing performance issues when atomic check also tries to acquire the display mutex and blocks on ESD thread if the later has already acquired it. Fix this race condition by removing display mutex lock from ESD thread and instead synchronize ESD check and DSI disable by always ensuring that ESD check has been stopped before DSI disable sequence kicks in. Change-Id: I5a0b44a7cbf01648303eb85c7a08a6a62c1ef94e Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 19 +++++++------------ drivers/gpu/drm/msm/sde/sde_connector.c | 3 +++ drivers/gpu/drm/msm/sde/sde_encoder.c | 5 ----- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index adcec15ee219..5c34b8e7c91f 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -559,9 +559,6 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, if (dsi_ctrl_validate_host_state(ctrl->ctrl)) return 1; - /* acquire panel_lock to make sure no commands are in progress */ - dsi_panel_acquire_panel_lock(panel); - config = &(panel->esd_config); lenp = config->status_valid_params ?: config->status_cmds_rlen; count = config->status_cmd.count; @@ -580,7 +577,7 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, flags); if (rc <= 0) { pr_err("rx cmd transfer failed rc=%d\n", rc); - goto error; + return rc; } memcpy(config->return_buf + start, @@ -588,9 +585,6 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl, start += lenp[i]; } -error: - /* release panel_lock */ - dsi_panel_release_panel_lock(panel); return rc; } @@ -709,15 +703,16 @@ int dsi_display_check_status(void *display, bool te_check_override) u32 status_mode; int rc = 0x1; - if (dsi_display == NULL) + if (!dsi_display || !dsi_display->panel) return -EINVAL; - mutex_lock(&dsi_display->display_lock); - panel = dsi_display->panel; + + dsi_panel_acquire_panel_lock(panel); + if (!panel->panel_initialized) { pr_debug("Panel not initialized\n"); - mutex_unlock(&dsi_display->display_lock); + dsi_panel_release_panel_lock(panel); return rc; } @@ -742,7 +737,7 @@ int dsi_display_check_status(void *display, bool te_check_override) dsi_display_clk_ctrl(dsi_display->dsi_clk_handle, DSI_ALL_CLKS, DSI_CLK_OFF); - mutex_unlock(&dsi_display->display_lock); + dsi_panel_release_panel_lock(panel); return rc; } diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index f1c1d6342fe1..15b5465e70f4 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -635,6 +635,9 @@ void sde_connector_helper_bridge_disable(struct drm_connector *connector) SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR); } + /* Disable ESD thread */ + sde_connector_schedule_status_work(connector, false); + c_conn = to_sde_connector(connector); if (c_conn->panel_dead) { c_conn->bl_device->props.power = FB_BLANK_POWERDOWN; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index bea66931f967..d5bb17e06f3d 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -2648,7 +2648,6 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) struct sde_encoder_virt *sde_enc = NULL; struct msm_drm_private *priv; struct sde_kms *sde_kms; - struct drm_connector *drm_conn = NULL; enum sde_intf_mode intf_mode; int i = 0; @@ -2677,10 +2676,6 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc) SDE_EVT32(DRMID(drm_enc)); - /* Disable ESD thread */ - drm_conn = sde_enc->cur_master->connector; - sde_connector_schedule_status_work(drm_conn, false); - /* wait for idle */ sde_encoder_wait_for_event(drm_enc, MSM_ENC_TX_COMPLETE); -- GitLab From e55cd14c02c4ffdace5756123a50ff0f80bf2083 Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Tue, 8 May 2018 00:05:01 +0530 Subject: [PATCH 1668/1834] drm/msm/sde: avoid dead lock in missing TE recovery sequence In the current implementation if there is no TE coming from display panel, then ESD recovery kicks in to reset display HW. In the ESD recovery path driver puts vote for HW resources by queuing a work in the commit thread, to avoid unclocked access to SDE registers and then waits for work to finish. But if the recovery process is triggered by commit thread itself, then it will lead to deadlock. Hence avoid this scenario by checking for thread id before putting the vote. Change-Id: Ia03d95d929215ef4f23f6de11ebabeef5f66d9e3 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/sde/sde_encoder.c | 12 ++++++++---- drivers/gpu/drm/msm/sde/sde_encoder.h | 4 ---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index bea66931f967..15bd7c353351 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -4858,10 +4858,14 @@ int sde_encoder_display_failure_notification(struct drm_encoder *enc) SDE_EVT32_VERBOSE(DRMID(enc)); disp_thread = &priv->disp_thread[sde_enc->crtc->index]; - - kthread_queue_work(&disp_thread->worker, - &sde_enc->esd_trigger_work); - kthread_flush_work(&sde_enc->esd_trigger_work); + if (current->tgid == disp_thread->thread->tgid) { + sde_encoder_resource_control(&sde_enc->base, + SDE_ENC_RC_EVENT_KICKOFF); + } else { + kthread_queue_work(&disp_thread->worker, + &sde_enc->esd_trigger_work); + kthread_flush_work(&sde_enc->esd_trigger_work); + } /** * panel may stop generating te signal (vsync) during esd failure. rsc * hardware may hang without vsync. Avoid rsc hang by generating the diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 0e8e9dd2b8e3..8225dcd23e57 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -242,10 +242,6 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder); * esd timeout or other display failure notification. This event flows from * dsi, sde_connector to sde_encoder. * - * This api must not be called from crtc_commit (display) thread because it - * requests the flush work on same thread. It is called from esd check thread - * based on current design. - * * TODO: manage the event at sde_kms level for forward processing. * @drm_enc: Pointer to drm encoder structure * @Return: true if successful in updating the encoder structure -- GitLab From 163afb24f779581f0d13014cf84d235d58f9a0a2 Mon Sep 17 00:00:00 2001 From: Liangliang Lu Date: Tue, 8 May 2018 11:21:22 +0800 Subject: [PATCH 1669/1834] ARM: dts: msm: Add fpc re-drive support for SDM632 QRD In the cases that have FPC cable between main board and sub-board, USB connector located on sub-board, add re-drive chipset on sub-board to make sure the signal of rx/tx for super-speed is good enough. Change-Id: Icbfc2387f461e90dd13ae43d8256984ce8759fe6 Signed-off-by: Liangliang Lu --- arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi index 09077c424423..cefc0783a1c1 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632-qrd.dtsi @@ -12,3 +12,9 @@ */ #include "sdm450-qrd-sku4.dtsi" + +&ssphy { + fpc-redrive-supply = <&pm8953_l6>; + qcom,redrive-voltage-level = <0 1800000 1900000>; + qcom,redrive-load = <105000>; +}; -- GitLab From b4a235f54823c89727976c2eaa4a6bf699a979a4 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Thu, 22 Mar 2018 14:28:31 -0700 Subject: [PATCH 1670/1834] diag: Protect memory allocation in diagfwd_mhi_read_work_fn Protect the memory allocation with mhi channel lock in diagfwd_read_work_fn() to avoid race condition while freeing up the memory. Change-Id: I3c06da2bdf649c7ef67864ce68d5cca1d91eff8e Signed-off-by: Sreelakshmi Gownipalli Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diagfwd_mhi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/char/diag/diagfwd_mhi.c b/drivers/char/diag/diagfwd_mhi.c index f8c3fdeb505c..6f418681c8ff 100644 --- a/drivers/char/diag/diagfwd_mhi.c +++ b/drivers/char/diag/diagfwd_mhi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -434,9 +434,10 @@ static void mhi_read_work_fn(struct work_struct *work) do { if (!(atomic_read(&(read_ch->opened)))) break; - + spin_lock_irqsave(&read_ch->lock, flags); buf = diagmem_alloc(driver, DIAG_MDM_BUF_SIZE, mhi_info->mempool); + spin_unlock_irqrestore(&read_ch->lock, flags); if (!buf) break; @@ -743,4 +744,3 @@ void diag_mhi_exit(void) diagmem_exit(driver, mhi_info->mempool); } } - -- GitLab From c20b1ed348d782dd54edfd5cb83a1492407203eb Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Thu, 3 May 2018 11:41:28 +0530 Subject: [PATCH 1671/1834] ARM: dts: msm: Add wcnss node for msm8917 Add wcnss device tree node to enable wlan driver. Add base memory address, clock, gpio, pin control and voltage regulators entry required for wlan. Change-Id: Ie180ac8e750a10d4a42cc7c2a35c21d52f249190 Signed-off-by: Anurag Chouhan --- arch/arm64/boot/dts/qcom/msm8917.dtsi | 80 +++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi index dbdd9d9dd7d5..36db486b8de8 100644 --- a/arch/arm64/boot/dts/qcom/msm8917.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi @@ -1423,6 +1423,86 @@ status = "disabled"; }; + qcom,wcnss-wlan@a000000 { + compatible = "qcom,wcnss_wlan"; + reg = <0xa000000 0x280000>, + <0xb011008 0x4>, + <0xa21b000 0x3000>, + <0x3204000 0x100>, + <0x3200800 0x200>, + <0xa100400 0x200>, + <0xa205050 0x200>, + <0xa219000 0x20>, + <0xa080488 0x8>, + <0xa080fb0 0x8>, + <0xa08040c 0x8>, + <0xa0120a8 0x8>, + <0xa012448 0x8>, + <0xa080c00 0x1>; + + reg-names = "wcnss_mmio", "wcnss_fiq", + "pronto_phy_base", "riva_phy_base", + "riva_ccu_base", "pronto_a2xb_base", + "pronto_ccpu_base", "pronto_saw2_base", + "wlan_tx_phy_aborts","wlan_brdg_err_source", + "wlan_tx_status", "alarms_txctl", + "alarms_tactl", "pronto_mcu_base"; + + interrupts = <0 145 0 0 146 0>; + interrupt-names = "wcnss_wlantx_irq", "wcnss_wlanrx_irq"; + + qcom,pronto-vddmx-supply = <&pm8937_l3_level_ao>; + qcom,pronto-vddcx-supply = <&pm8937_s2_level>; + qcom,pronto-vddpx-supply = <&pm8937_l5>; + qcom,iris-vddxo-supply = <&pm8937_l7>; + qcom,iris-vddrfa-supply = <&pm8937_l19>; + qcom,iris-vddpa-supply = <&pm8937_l9>; + qcom,iris-vdddig-supply = <&pm8937_l5>; + + qcom,iris-vddxo-voltage-level = <1800000 0 1800000>; + qcom,iris-vddrfa-voltage-level = <1300000 0 1300000>; + qcom,iris-vddpa-voltage-level = <3300000 0 3300000>; + qcom,iris-vdddig-voltage-level = <1800000 0 1800000>; + + qcom,vddmx-voltage-level = ; + qcom,vddcx-voltage-level = ; + qcom,vddpx-voltage-level = <1800000 0 1800000>; + + qcom,iris-vddxo-current = <10000>; + qcom,iris-vddrfa-current = <100000>; + qcom,iris-vddpa-current = <515000>; + qcom,iris-vdddig-current = <10000>; + + qcom,pronto-vddmx-current = <0>; + qcom,pronto-vddcx-current = <0>; + qcom,pronto-vddpx-current = <0>; + + pinctrl-names = "wcnss_default", "wcnss_sleep", + "wcnss_gpio_default"; + pinctrl-0 = <&wcnss_default>; + pinctrl-1 = <&wcnss_sleep>; + pinctrl-2 = <&wcnss_gpio_default>; + + gpios = <&tlmm 76 0>, <&tlmm 77 0>, <&tlmm 78 0>, + <&tlmm 79 0>, <&tlmm 80 0>; + + clocks = <&clock_gcc clk_xo_wlan_clk>, + <&clock_gcc clk_rf_clk2>, + <&clock_debug clk_gcc_debug_mux_8937>, + <&clock_gcc clk_wcnss_m_clk>; + + clock-names = "xo", "rf_clk", "measure", "wcnss_debug"; + + qcom,has-autodetect-xo; + qcom,is-pronto-v3; + qcom,has-pronto-hw; + qcom,has-vsys-adc-channel; + qcom,wcnss-adc_tm = <&pm8937_adc_tm>; + }; }; #include "pm8937-rpm-regulator.dtsi" -- GitLab From e28f2aed7a12d675defb247e1863d2363feebffa Mon Sep 17 00:00:00 2001 From: Neeraj Soni Date: Mon, 30 Apr 2018 11:13:17 +0530 Subject: [PATCH 1672/1834] crypto:msm: fix compilation issue for crypto APIs New APIs introduced as part of new FDE design can not be referenced if driver config flag is not defined. Provide a dummy reference to handle this case. Change-Id: I7cfacd34ffca8cb156e3b12b6f29586950bf1ad8 Signed-off-by: Neeraj Soni --- include/crypto/ice.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/crypto/ice.h b/include/crypto/ice.h index b02a4403a302..133041ea9ec8 100644 --- a/include/crypto/ice.h +++ b/include/crypto/ice.h @@ -53,16 +53,22 @@ typedef void (*ice_error_cb)(void *, u32 error); struct qcom_ice_variant_ops *qcom_ice_get_variant_ops(struct device_node *node); struct platform_device *qcom_ice_get_pdevice(struct device_node *node); -void qcom_ice_set_fde_flag(int flag); -int qcom_ice_set_fde_conf(sector_t strt, sector_t size, int idx, int mode); #ifdef CONFIG_CRYPTO_DEV_QCOM_ICE int qcom_ice_setup_ice_hw(const char *storage_type, int enable); +void qcom_ice_set_fde_flag(int flag); +int qcom_ice_set_fde_conf(sector_t strt, sector_t size, int idx, int mode); #else static inline int qcom_ice_setup_ice_hw(const char *storage_type, int enable) { return 0; } +static inline void qcom_ice_set_fde_flag(int flag) {} +static inline int qcom_ice_set_fde_conf(sector_t strt, sector_t size, int idx, + int mode) +{ + return 0; +} #endif struct qcom_ice_variant_ops { -- GitLab From 727927b88f832da7a007b0968cacae094fcab928 Mon Sep 17 00:00:00 2001 From: Odelu Kukatla Date: Mon, 23 Apr 2018 22:28:35 +0530 Subject: [PATCH 1673/1834] ARM: dts: msm: Populate OPP table for GFX clock on MSM8937/SDM439 For GPU thermal mitigation, there is need to populate OPP table for gfx3d clock source so add support for the same. Change-Id: I72d33260c96ffe738ec8b0d5f25acbe818ac2e8c Signed-off-by: Odelu Kukatla --- arch/arm64/boot/dts/qcom/msm8937.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi index 9ef154a29024..d22101fe41e6 100644 --- a/arch/arm64/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi @@ -423,6 +423,7 @@ <0x00a6018 0x00004>; reg-names = "cc_base", "apcs_c1_base", "apcs_c0_base", "efuse"; + qcom,gfx3d_clk_src-opp-store-vcorner = <&msm_gpu>; vdd_dig-supply = <&pm8937_s2_level>; vdd_sr2_dig-supply = <&pm8937_s2_level_ao>; vdd_sr2_pll-supply = <&pm8937_l7_ao>; -- GitLab From e57aa240cda4362f885c02dcde8842713db95512 Mon Sep 17 00:00:00 2001 From: Tony Truong Date: Fri, 20 Jan 2017 17:25:58 -0800 Subject: [PATCH 1674/1834] msm: pcie: change PCIe to suspend after suspend_noirq Some PCIe clients support suspend_noirq and need the PCIe link to be up. Change PCIe to have its power down sequence after clients suspend_noirq. Change-Id: I32063f6adf795f8a49cd7d9fe340403ffaf6fd94 Signed-off-by: Tony Truong --- drivers/pci/host/pci-msm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index cec5a96cc615..cc681366d2db 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -6301,7 +6301,7 @@ static int msm_pcie_pm_suspend(struct pci_dev *dev, return ret; } -static void msm_pcie_fixup_suspend(struct pci_dev *dev) +static void msm_pcie_fixup_suspend_late(struct pci_dev *dev) { int ret; struct msm_pcie_dev_t *pcie_dev = PCIE_BUS_PRIV_DATA(dev->bus); @@ -6334,8 +6334,8 @@ static void msm_pcie_fixup_suspend(struct pci_dev *dev) mutex_unlock(&pcie_dev->recovery_lock); } -DECLARE_PCI_FIXUP_SUSPEND(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID, - msm_pcie_fixup_suspend); +DECLARE_PCI_FIXUP_SUSPEND_LATE(PCIE_VENDOR_ID_QCOM, PCI_ANY_ID, + msm_pcie_fixup_suspend_late); /* Resume the PCIe link */ static int msm_pcie_pm_resume(struct pci_dev *dev, -- GitLab From 3e0fd3ebf8ba17717f7c8feef0fd6c0ca4fde875 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Thu, 12 Apr 2018 18:00:07 +0530 Subject: [PATCH 1675/1834] msm: kgsl: Do not invoke loading of GPU ZAP shader Do not invoke GPU ZAP shader loading if secure context is not enabled on a target. Change-Id: I6509e5c37ae45f1486da6af7f60da055c5f080c2 Signed-off-by: Sunil Khatri --- drivers/gpu/msm/adreno_a5xx.c | 7 +++++++ drivers/gpu/msm/adreno_a6xx.c | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/gpu/msm/adreno_a5xx.c b/drivers/gpu/msm/adreno_a5xx.c index 7ddb6febcac5..876b7c96a551 100644 --- a/drivers/gpu/msm/adreno_a5xx.c +++ b/drivers/gpu/msm/adreno_a5xx.c @@ -2225,6 +2225,13 @@ static int a5xx_microcode_load(struct adreno_device *adreno_dev) kgsl_regwrite(device, A5XX_CP_PFP_INSTR_BASE_HI, upper_32_bits(gpuaddr)); + /* + * Do not invoke to load zap shader if MMU does + * not support secure mode. + */ + if (!device->mmu.secured) + return 0; + /* * Resume call to write the zap shader base address into the * appropriate register, diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index f2c18b742565..37330cb0a501 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -853,6 +853,13 @@ static int a6xx_microcode_load(struct adreno_device *adreno_dev) kgsl_regwrite(device, A6XX_CP_SQE_INSTR_BASE_HI, upper_32_bits(gpuaddr)); + /* + * Do not invoke to load zap shader if MMU does + * not support secure mode. + */ + if (!device->mmu.secured) + return 0; + /* Load the zap shader firmware through PIL if its available */ if (adreno_dev->gpucore->zap_name && !adreno_dev->zap_loaded) { /* -- GitLab From cae88843be24de972c6be6224153243cbd4e2695 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Wed, 21 Mar 2018 17:08:28 -0700 Subject: [PATCH 1676/1834] drm/msm/sde: Add property for AD vsync count On command mode panel, vsync notification will triggered for each TE, not actual vsync commit. This change adds an AD property to track vsync event count for AD, so that AD feature can converge with the correct display commit count. Change-Id: I6c87ce989203f8bb121723465c661e2b2f27c179 Signed-off-by: Ping Li --- drivers/gpu/drm/msm/sde/sde_ad4.h | 1 + .../gpu/drm/msm/sde/sde_color_processing.c | 71 ++++++++++++++++++- .../gpu/drm/msm/sde/sde_color_processing.h | 9 ++- drivers/gpu/drm/msm/sde/sde_crtc.c | 1 + drivers/gpu/drm/msm/sde/sde_crtc.h | 2 + drivers/gpu/drm/msm/sde/sde_hw_ad4.c | 34 +++++++++ 6 files changed, 116 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_ad4.h b/drivers/gpu/drm/msm/sde/sde_ad4.h index bf08360e9862..b254d7dc981e 100644 --- a/drivers/gpu/drm/msm/sde/sde_ad4.h +++ b/drivers/gpu/drm/msm/sde/sde_ad4.h @@ -52,6 +52,7 @@ enum ad_property { AD_IPC_SUSPEND, AD_IPC_RESUME, AD_IPC_RESET, + AD_VSYNC_UPDATE, AD_PROPMAX, }; diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.c b/drivers/gpu/drm/msm/sde/sde_color_processing.c index 0f55b198ce99..47ff02431851 100644 --- a/drivers/gpu/drm/msm/sde/sde_color_processing.c +++ b/drivers/gpu/drm/msm/sde/sde_color_processing.c @@ -88,6 +88,7 @@ static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc, enum ad_property ad_prop); static void sde_cp_notify_hist_event(struct drm_crtc *crtc_drm, void *arg); +static void sde_cp_update_ad_vsync_prop(struct sde_crtc *sde_crtc, u32 val); #define setup_dspp_prop_install_funcs(func) \ do { \ @@ -138,6 +139,7 @@ enum { SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS, SDE_CP_CRTC_DSPP_AD_BACKLIGHT, SDE_CP_CRTC_DSPP_AD_STRENGTH, + SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT, SDE_CP_CRTC_DSPP_MAX, /* DSPP features end */ @@ -407,6 +409,7 @@ void sde_cp_crtc_init(struct drm_crtc *crtc) if (IS_ERR(sde_crtc->hist_blob)) sde_crtc->hist_blob = NULL; + sde_crtc->ad_vsync_count = 0; mutex_init(&sde_crtc->crtc_cp_lock); INIT_LIST_HEAD(&sde_crtc->active_list); INIT_LIST_HEAD(&sde_crtc->dirty_list); @@ -789,6 +792,9 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, ad_cfg.prop = AD_MODE; ad_cfg.hw_cfg = &hw_cfg; hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + sde_crtc->ad_vsync_count = 0; + sde_cp_update_ad_vsync_prop(sde_crtc, + sde_crtc->ad_vsync_count); break; case SDE_CP_CRTC_DSPP_AD_INIT: if (!hw_dspp || !hw_dspp->ops.setup_ad) { @@ -798,6 +804,9 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, ad_cfg.prop = AD_INIT; ad_cfg.hw_cfg = &hw_cfg; hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + sde_crtc->ad_vsync_count = 0; + sde_cp_update_ad_vsync_prop(sde_crtc, + sde_crtc->ad_vsync_count); break; case SDE_CP_CRTC_DSPP_AD_CFG: if (!hw_dspp || !hw_dspp->ops.setup_ad) { @@ -807,6 +816,9 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, ad_cfg.prop = AD_CFG; ad_cfg.hw_cfg = &hw_cfg; hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + sde_crtc->ad_vsync_count = 0; + sde_cp_update_ad_vsync_prop(sde_crtc, + sde_crtc->ad_vsync_count); break; case SDE_CP_CRTC_DSPP_AD_INPUT: if (!hw_dspp || !hw_dspp->ops.setup_ad) { @@ -816,6 +828,9 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, ad_cfg.prop = AD_INPUT; ad_cfg.hw_cfg = &hw_cfg; hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + sde_crtc->ad_vsync_count = 0; + sde_cp_update_ad_vsync_prop(sde_crtc, + sde_crtc->ad_vsync_count); break; case SDE_CP_CRTC_DSPP_AD_ASSERTIVENESS: if (!hw_dspp || !hw_dspp->ops.setup_ad) { @@ -825,6 +840,9 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, ad_cfg.prop = AD_ASSERTIVE; ad_cfg.hw_cfg = &hw_cfg; hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + sde_crtc->ad_vsync_count = 0; + sde_cp_update_ad_vsync_prop(sde_crtc, + sde_crtc->ad_vsync_count); break; case SDE_CP_CRTC_DSPP_AD_BACKLIGHT: if (!hw_dspp || !hw_dspp->ops.setup_ad) { @@ -834,6 +852,9 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, ad_cfg.prop = AD_BACKLIGHT; ad_cfg.hw_cfg = &hw_cfg; hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + sde_crtc->ad_vsync_count = 0; + sde_cp_update_ad_vsync_prop(sde_crtc, + sde_crtc->ad_vsync_count); break; case SDE_CP_CRTC_DSPP_AD_STRENGTH: if (!hw_dspp || !hw_dspp->ops.setup_ad) { @@ -843,6 +864,9 @@ static void sde_cp_crtc_setfeature(struct sde_cp_node *prop_node, ad_cfg.prop = AD_STRENGTH; ad_cfg.hw_cfg = &hw_cfg; hw_dspp->ops.setup_ad(hw_dspp, &ad_cfg); + sde_crtc->ad_vsync_count = 0; + sde_cp_update_ad_vsync_prop(sde_crtc, + sde_crtc->ad_vsync_count); break; default: ret = -EINVAL; @@ -924,10 +948,15 @@ void sde_cp_crtc_apply_properties(struct drm_crtc *crtc) DRM_DEBUG_DRIVER("Dirty list is empty\n"); goto exit; } - sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET); set_dspp_flush = true; } + if (!list_empty(&sde_crtc->ad_active)) { + sde_cp_ad_set_prop(sde_crtc, AD_IPC_RESET); + sde_cp_ad_set_prop(sde_crtc, AD_VSYNC_UPDATE); + sde_cp_update_ad_vsync_prop(sde_crtc, sde_crtc->ad_vsync_count); + } + list_for_each_entry_safe(prop_node, n, &sde_crtc->dirty_list, dirty_list) { sde_dspp_feature = crtc_feature_map[prop_node->feature]; @@ -1449,6 +1478,9 @@ static void dspp_ad_install_property(struct drm_crtc *crtc) "SDE_DSPP_AD_V4_BACKLIGHT", SDE_CP_CRTC_DSPP_AD_BACKLIGHT, 0, (BIT(16) - 1), 0); + sde_cp_crtc_install_range_property(crtc, + "SDE_DSPP_AD_V4_VSYNC_COUNT", + SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT, 0, U32_MAX, 0); break; default: DRM_ERROR("version %d not supported\n", version); @@ -1867,6 +1899,11 @@ static void sde_cp_ad_set_prop(struct sde_crtc *sde_crtc, hw_cfg.displayh = num_mixers * hw_lm->cfg.out_width; hw_cfg.displayv = hw_lm->cfg.out_height; hw_cfg.mixer_info = hw_lm; + + if (ad_prop == AD_VSYNC_UPDATE) { + hw_cfg.payload = &sde_crtc->ad_vsync_count; + hw_cfg.len = sizeof(sde_crtc->ad_vsync_count); + } ad_cfg.prop = ad_prop; ad_cfg.hw_cfg = &hw_cfg; ret = hw_dspp->ops.validate_ad(hw_dspp, (u32 *)&ad_prop); @@ -2118,3 +2155,35 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en, exit: return ret; } + +void sde_cp_update_ad_vsync_count(struct drm_crtc *crtc, u32 val) +{ + struct sde_crtc *sde_crtc; + + if (!crtc) { + DRM_ERROR("invalid crtc %pK\n", crtc); + return; + } + + sde_crtc = to_sde_crtc(crtc); + if (!sde_crtc) { + DRM_ERROR("invalid sde_crtc %pK\n", sde_crtc); + return; + } + + sde_crtc->ad_vsync_count = val; + sde_cp_update_ad_vsync_prop(sde_crtc, val); +} + +static void sde_cp_update_ad_vsync_prop(struct sde_crtc *sde_crtc, u32 val) +{ + struct sde_cp_node *prop_node = NULL; + + list_for_each_entry(prop_node, &sde_crtc->feature_list, feature_list) { + if (prop_node->feature == SDE_CP_CRTC_DSPP_AD_VSYNC_COUNT) { + prop_node->prop_val = val; + pr_debug("AD vsync count updated to %d\n", val); + return; + } + } +} diff --git a/drivers/gpu/drm/msm/sde/sde_color_processing.h b/drivers/gpu/drm/msm/sde/sde_color_processing.h index 7eb173852611..620db26775a9 100644 --- a/drivers/gpu/drm/msm/sde/sde_color_processing.h +++ b/drivers/gpu/drm/msm/sde/sde_color_processing.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -146,4 +146,11 @@ void sde_cp_crtc_post_ipc(struct drm_crtc *crtc); */ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en, struct sde_irq_callback *hist_irq); + +/** + * sde_cp_update_ad_vsync_count: Api to update AD vsync count + * @crtc: Pointer to crtc. + * @val: vsync count value + */ +void sde_cp_update_ad_vsync_count(struct drm_crtc *crtc, u32 val); #endif /*_SDE_COLOR_PROCESSING_H */ diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 7daab2acf8a6..e09dbadedc72 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -4125,6 +4125,7 @@ static void sde_crtc_disable(struct drm_crtc *crtc) event.type = DRM_EVENT_CRTC_POWER; event.length = sizeof(u32); sde_cp_crtc_suspend(crtc); + sde_cp_update_ad_vsync_count(crtc, 0); power_on = 0; msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 64f38211631d..116af84d7667 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -155,6 +155,7 @@ struct sde_crtc_event { * @dirty_list : list of color processing features are dirty * @ad_dirty: list containing ad properties that are dirty * @ad_active: list containing ad properties that are active + * @ad_vsync_count : count of vblank since last reset for AD * @crtc_lock : crtc lock around create, destroy and access. * @frame_pending : Whether or not an update is pending * @frame_events : static allocation of in-flight frame events @@ -224,6 +225,7 @@ struct sde_crtc { struct list_head ad_dirty; struct list_head ad_active; struct list_head user_event_list; + u32 ad_vsync_count; struct mutex crtc_lock; struct mutex crtc_cp_lock; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c index 66445da368fc..e60defd2c35b 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ad4.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_ad4.c @@ -109,6 +109,9 @@ static int ad4_ipc_reset_setup_ipcr(struct sde_hw_dspp *dspp, static int ad4_cfg_ipc_reset(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg); +static int ad4_vsync_update(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg); + static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_idle][AD_MODE] = ad4_mode_setup_common, [ad4_state_idle][AD_INIT] = ad4_init_setup_idle, @@ -121,6 +124,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_idle][AD_IPC_SUSPEND] = ad4_no_op_setup, [ad4_state_idle][AD_IPC_RESUME] = ad4_no_op_setup, [ad4_state_idle][AD_IPC_RESET] = ad4_no_op_setup, + [ad4_state_idle][AD_VSYNC_UPDATE] = ad4_no_op_setup, [ad4_state_startup][AD_MODE] = ad4_mode_setup_common, [ad4_state_startup][AD_INIT] = ad4_init_setup, @@ -133,6 +137,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_startup][AD_STRENGTH] = ad4_no_op_setup, [ad4_state_startup][AD_IPC_RESUME] = ad4_no_op_setup, [ad4_state_startup][AD_IPC_RESET] = ad4_ipc_reset_setup_startup, + [ad4_state_startup][AD_VSYNC_UPDATE] = ad4_vsync_update, [ad4_state_run][AD_MODE] = ad4_mode_setup_common, [ad4_state_run][AD_INIT] = ad4_init_setup_run, @@ -145,6 +150,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_run][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_run, [ad4_state_run][AD_IPC_RESUME] = ad4_no_op_setup, [ad4_state_run][AD_IPC_RESET] = ad4_setup_debug, + [ad4_state_run][AD_VSYNC_UPDATE] = ad4_vsync_update, [ad4_state_ipcs][AD_MODE] = ad4_no_op_setup, [ad4_state_ipcs][AD_INIT] = ad4_no_op_setup, @@ -157,6 +163,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_ipcs][AD_IPC_SUSPEND] = ad4_no_op_setup, [ad4_state_ipcs][AD_IPC_RESUME] = ad4_ipc_resume_setup_ipcs, [ad4_state_ipcs][AD_IPC_RESET] = ad4_no_op_setup, + [ad4_state_ipcs][AD_VSYNC_UPDATE] = ad4_no_op_setup, [ad4_state_ipcr][AD_MODE] = ad4_mode_setup_common, [ad4_state_ipcr][AD_INIT] = ad4_init_setup_ipcr, @@ -169,6 +176,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_ipcr][AD_IPC_SUSPEND] = ad4_ipc_suspend_setup_ipcr, [ad4_state_ipcr][AD_IPC_RESUME] = ad4_no_op_setup, [ad4_state_ipcr][AD_IPC_RESET] = ad4_ipc_reset_setup_ipcr, + [ad4_state_ipcr][AD_VSYNC_UPDATE] = ad4_no_op_setup, [ad4_state_manual][AD_MODE] = ad4_mode_setup_common, [ad4_state_manual][AD_INIT] = ad4_init_setup, @@ -181,6 +189,7 @@ static ad4_prop_setup prop_set_func[ad4_state_max][AD_PROPMAX] = { [ad4_state_manual][AD_IPC_SUSPEND] = ad4_no_op_setup, [ad4_state_manual][AD_IPC_RESUME] = ad4_no_op_setup, [ad4_state_manual][AD_IPC_RESET] = ad4_setup_debug_manual, + [ad4_state_manual][AD_VSYNC_UPDATE] = ad4_no_op_setup, }; struct ad4_info { @@ -201,6 +210,7 @@ struct ad4_info { u32 irdx_control_0; u32 tf_ctrl; u32 vc_control_0; + u32 frame_pushes; }; static struct ad4_info info[DSPP_MAX] = { @@ -905,6 +915,8 @@ static int ad4_cfg_setup(struct sde_hw_dspp *dspp, struct sde_ad_hw_cfg *cfg) val = (ad_cfg->cfg_param_046 & (BIT(16) - 1)); SDE_REG_WRITE(&dspp->hw, dspp->cap->sblk->ad.base + blk_offset, val); + info[dspp->idx].frame_pushes = ad_cfg->cfg_param_047; + return 0; } @@ -1546,3 +1558,25 @@ static int ad4_strength_setup_idle(struct sde_hw_dspp *dspp, ad4_mode_setup(dspp, info[dspp->idx].mode); return 0; } + +static int ad4_vsync_update(struct sde_hw_dspp *dspp, + struct sde_ad_hw_cfg *cfg) +{ + u32 *count; + struct sde_hw_mixer *hw_lm; + + if (cfg->hw_cfg->len != sizeof(u32) || !cfg->hw_cfg->payload) { + DRM_ERROR("invalid sz param exp %zd given %d cfg %pK\n", + sizeof(u32), cfg->hw_cfg->len, cfg->hw_cfg->payload); + return -EINVAL; + } + + count = (u32 *)(cfg->hw_cfg->payload); + hw_lm = cfg->hw_cfg->mixer_info; + + if (hw_lm && !hw_lm->cfg.right_mixer && + (*count < info[dspp->idx].frame_pushes)) + (*count)++; + + return 0; +} -- GitLab From 2176725108faf85041745d7babf034a72b89826d Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 8 May 2018 15:01:26 +0530 Subject: [PATCH 1677/1834] sched/fair: Consider task affinity while skipping a sched group When placement boost is active, the CPUs in the highest capacity sched group are only considered for task placement. The find_best_target()->skip_sg() skips lower capacity sched groups. This is a problem for the tasks whose affinity allows them to run only on lower capacity sched group. Change-Id: I935ff3dc3daa98c636885312216a68323aac3ce1 Signed-off-by: Pavankumar Kondeti --- kernel/sched/fair.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 04ba6d02736d..65e728c40d5e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -6871,6 +6871,13 @@ static inline bool skip_sg(struct task_struct *p, struct sched_group *sg, if (!sg->group_weight) return true; + /* + * Don't skip a group if a task affinity allows it + * to run only on that group. + */ + if (cpumask_subset(tsk_cpus_allowed(p), sched_group_cpus(sg))) + return false; + if (!task_fits_max(p, fcpu)) return true; -- GitLab From 606a7a92398f716dd9d3aae2653c29175d3b9bc4 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Fri, 4 May 2018 14:35:11 +0530 Subject: [PATCH 1678/1834] diag: Add new WLAN_RSN event id The patch adds new WLAN_RSN_INFO event as latest ID. Change-Id: Ic76506632ea0aa61c79c52824556b6aaeb0b04e6 Signed-off-by: Manoj Prabhu B --- include/linux/diagchar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index 3c7ec2264935..a3d9563e7f4e 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -146,7 +146,7 @@ * a new RANGE of SSIDs to the msg_mask_tbl. */ #define MSG_MASK_TBL_CNT 26 -#define APPS_EVENT_LAST_ID 0x0C5A +#define APPS_EVENT_LAST_ID 0x0C5B #define MSG_SSID_0 0 #define MSG_SSID_0_LAST 125 -- GitLab From 037708a14300e63231df333fa8184c94e6632d28 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Wed, 18 Apr 2018 14:53:24 +0530 Subject: [PATCH 1679/1834] regulator: cpr4-apss: Update voltage corner configuration for sdm632 Gold and Silver clusters contain dedicated 3 fuse corners for each of them and also a common LowSVS fuse corner. Update the voltage corner configuration defined for sdm632 as per new fusing scheme. CRs-Fixed: 2233570 Change-Id: Ida3e23e940c45174cc3136a2c589473d6cdb8ccb Signed-off-by: Tirupathi Reddy --- .../arm64/boot/dts/qcom/sdm632-regulator.dtsi | 191 ++++++++++++++++-- arch/arm64/boot/dts/qcom/sdm632.dtsi | 36 ++-- drivers/regulator/cpr4-apss-regulator.c | 32 +-- 3 files changed, 217 insertions(+), 42 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi index b5373a22c5d2..a7580e07fd76 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi @@ -143,10 +143,10 @@ regulator-min-microvolt = <1>; regulator-max-microvolt = <7>; - qcom,cpr-fuse-corners = <5>; + qcom,cpr-fuse-corners = <4>; qcom,cpr-fuse-combos = <64>; qcom,cpr-corners = <7>; - qcom,cpr-corner-fmax-map = <1 2 3 4 7>; + qcom,cpr-corner-fmax-map = <1 3 4 7>; qcom,cpr-voltage-ceiling = <720000 790000 865000 865000 920000 @@ -170,8 +170,6 @@ 1970 1880 2110 2010 2510 4900 4370 4780>, <3600 3600 3830 2430 2520 2700 1790 1760 1970 1880 2110 2010 2510 4900 4370 4780>, - <3600 3600 3830 2430 2520 2700 1790 1760 - 1970 1880 2110 2010 2510 4900 4370 4780>, <3600 3600 3830 2430 2520 2700 1790 1760 1970 1880 2110 2010 2510 4900 4370 4780>; @@ -191,36 +189,203 @@ apc1_perfcl_vreg: regulator { regulator-name = "apc1_perfcl_corner"; regulator-min-microvolt = <1>; - regulator-max-microvolt = <5>; + regulator-max-microvolt = <7>; - qcom,cpr-fuse-corners = <3>; + qcom,cpr-fuse-corners = <4>; qcom,cpr-fuse-combos = <64>; - qcom,cpr-corners = <5>; - qcom,cpr-corner-fmax-map = <1 2 5>; + qcom,cpr-corners = <7>; + qcom,cpr-corner-fmax-map = <1 3 4 7>; qcom,cpr-voltage-ceiling = - <865000 865000 920000 990000 1065000>; + <720000 790000 865000 865000 920000 + 990000 1065000>; qcom,cpr-voltage-floor = - <500000 500000 500000 500000 500000>; + <500000 500000 500000 500000 500000 + 500000 500000>; - qcom,mem-acc-voltage = <2 2 2 2 3>; + qcom,mem-acc-voltage = <1 1 2 2 2 2 3>; qcom,corner-frequencies = - <1094400000 1401600000 1555200000 - 1804800000 2016000000>; + <633600000 902400000 1094400000 + 1401600000 1555200000 1804800000 + 2016000000>; qcom,cpr-ro-scaling-factor = <3600 3600 3830 2430 2520 2700 1790 1760 1970 1880 2110 2010 2510 4900 4370 4780>, <3600 3600 3830 2430 2520 2700 1790 1760 1970 1880 2110 2010 2510 4900 4370 4780>, + <3600 3600 3830 2430 2520 2700 1790 1760 + 1970 1880 2110 2010 2510 4900 4370 4780>, <3600 3600 3830 2430 2520 2700 1790 1760 1970 1880 2110 2010 2510 4900 4370 4780>; qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; + + qcom,cpr-open-loop-voltage-fuse-adjustment = + /* Speed bin 0; CPR rev 0..7 */ + < 30000 0 0 0>, + < 30000 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 1; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 2; CPR rev 0..7 */ + < 30000 0 0 0>, + < 30000 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 3; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 4; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 5; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 6; CPR rev 0..7 */ + < 30000 0 0 0>, + < 30000 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 7; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>; + + qcom,cpr-closed-loop-voltage-fuse-adjustment = + /* Speed bin 0; CPR rev 0..7 */ + < 30000 0 0 0>, + < 30000 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 1; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 2; CPR rev 0..7 */ + < 30000 0 0 0>, + < 30000 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 3; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 4; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 5; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 6; CPR rev 0..7 */ + < 30000 0 0 0>, + < 30000 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + + /* Speed bin 7; CPR rev 0..7 */ + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>, + < 0 0 0 0>; }; }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi index 69cb36fd8cb8..b54e8315528c 100644 --- a/arch/arm64/boot/dts/qcom/sdm632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -824,10 +824,12 @@ < 1804800000 7>; qcom,speed0-bin-v0-c1 = < 0 0>, - < 1094400000 1>, - < 1401600000 2>, - < 1555200000 3>, - < 1804800000 4>; + < 633600000 1>, + < 902400000 2>, + < 1094400000 3>, + < 1401600000 4>, + < 1555200000 5>, + < 1804800000 6>; qcom,speed0-bin-v0-cci = < 0 0>, < 307200000 1>, @@ -848,10 +850,12 @@ < 1804800000 7>; qcom,speed6-bin-v0-c1 = < 0 0>, - < 1094400000 1>, - < 1401600000 2>, - < 1555200000 3>, - < 1804800000 4>; + < 633600000 1>, + < 902400000 2>, + < 1094400000 3>, + < 1401600000 4>, + < 1555200000 5>, + < 1804800000 6>; qcom,speed6-bin-v0-cci = < 0 0>, < 307200000 1>, @@ -872,11 +876,13 @@ < 1804800000 7>; qcom,speed2-bin-v0-c1 = < 0 0>, - < 1094400000 1>, - < 1401600000 2>, - < 1555200000 3>, - < 1804800000 4>, - < 2016000000 5>; + < 633600000 1>, + < 902400000 2>, + < 1094400000 3>, + < 1401600000 4>, + < 1555200000 5>, + < 1804800000 6>, + < 2016000000 7>; qcom,speed2-bin-v0-cci = < 0 0>, < 307200000 1>, @@ -914,6 +920,8 @@ < 1804800 >; qcom,cpufreq-table-4 = + < 633600 >, + < 902400 >, < 1094400 >, < 1401600 >, < 1555200 >, @@ -961,6 +969,8 @@ < 1536000 768000>, /* NOM+ */ < 1670400 787200>; /* TURBO */ cpu-to-dev-map-4 = + < 633600 307200>, /* SVS */ + < 902400 403200>, < 1094400 499200>, /* SVS */ < 1401600 691200>, /* NOM */ < 1555200 768000>, /* NOM+ */ diff --git a/drivers/regulator/cpr4-apss-regulator.c b/drivers/regulator/cpr4-apss-regulator.c index d5a0e33078d4..725fc585cabe 100644 --- a/drivers/regulator/cpr4-apss-regulator.c +++ b/drivers/regulator/cpr4-apss-regulator.c @@ -36,8 +36,8 @@ #include "cpr3-regulator.h" #define MSM8953_APSS_FUSE_CORNERS 4 -#define SDM632_POWER_APSS_FUSE_CORNERS 5 -#define SDM632_PERF_APSS_FUSE_CORNERS 3 +#define SDM632_POWER_APSS_FUSE_CORNERS 4 +#define SDM632_PERF_APSS_FUSE_CORNERS 4 /** * struct cpr4_apss_fuses - APSS specific fuse data @@ -103,27 +103,27 @@ static const char * const cpr4_msm8953_apss_fuse_corner_name[] = { enum cpr4_sdm632_power_apss_fuse_corner { CPR4_SDM632_POWER_APSS_FUSE_CORNER_LOWSVS = 0, - CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS = 1, - CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1 = 2, - CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM = 3, - CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1 = 4, + CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1 = 1, + CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM = 2, + CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1 = 3, }; static const char * const cpr4_sdm632_power_apss_fuse_corner_name[] = { [CPR4_SDM632_POWER_APSS_FUSE_CORNER_LOWSVS] = "LowSVS", - [CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS] = "SVS", [CPR4_SDM632_POWER_APSS_FUSE_CORNER_SVS_L1] = "SVS_L1", [CPR4_SDM632_POWER_APSS_FUSE_CORNER_NOM] = "NOM", [CPR4_SDM632_POWER_APSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1", }; enum cpr4_sdm632_perf_apss_fuse_corner { - CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1 = 0, - CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM = 1, - CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1 = 2, + CPR4_SDM632_PERF_APSS_FUSE_CORNER_LOWSVS = 0, + CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1 = 1, + CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM = 2, + CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1 = 3, }; static const char * const cpr4_sdm632_perf_apss_fuse_corner_name[] = { + [CPR4_SDM632_PERF_APSS_FUSE_CORNER_LOWSVS] = "LowSVS", [CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1] = "SVS_L1", [CPR4_SDM632_PERF_APSS_FUSE_CORNER_NOM] = "NOM", [CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1] = "TURBO_L1", @@ -229,12 +229,12 @@ static const struct cpr3_fuse_param sdm632_apss_ro_sel_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = { [CPR4_APSS_POWER_CLUSTER_ID] = { {{73, 28, 31}, {} }, - {{73, 24, 27}, {} }, {{73, 20, 23}, {} }, {{73, 16, 19}, {} }, {{73, 12, 15}, {} }, }, [CPR4_APSS_PERF_CLUSTER_ID] = { + {{73, 28, 31}, {} }, {{73, 8, 11}, {} }, {{73, 4, 7}, {} }, {{73, 0, 3}, {} }, @@ -245,12 +245,12 @@ static const struct cpr3_fuse_param sdm632_apss_init_voltage_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = { [CPR4_APSS_POWER_CLUSTER_ID] = { {{74, 18, 23}, {} }, - {{74, 12, 17}, {} }, {{71, 24, 29}, {} }, {{74, 6, 11}, {} }, {{74, 0, 5}, {} }, }, [CPR4_APSS_PERF_CLUSTER_ID] = { + {{74, 18, 23}, {} }, {{71, 18, 23}, {} }, {{71, 12, 17}, {} }, {{71, 6, 11}, {} }, @@ -261,12 +261,12 @@ static const struct cpr3_fuse_param sdm632_apss_target_quot_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = { [CPR4_APSS_POWER_CLUSTER_ID] = { {{75, 44, 55}, {} }, - {{75, 32, 43}, {} }, {{72, 44, 55}, {} }, {{75, 20, 31}, {} }, {{75, 8, 19}, {} }, }, [CPR4_APSS_PERF_CLUSTER_ID] = { + {{75, 44, 55}, {} }, {{72, 32, 43}, {} }, {{72, 20, 31}, {} }, {{72, 8, 19}, {} }, @@ -277,13 +277,13 @@ static const struct cpr3_fuse_param sdm632_apss_quot_offset_param[2][SDM632_POWER_APSS_FUSE_CORNERS][2] = { [CPR4_APSS_POWER_CLUSTER_ID] = { {{} }, - {{74, 39, 45}, {} }, {{71, 46, 52}, {} }, {{74, 32, 38}, {} }, {{74, 24, 30}, {} }, }, [CPR4_APSS_PERF_CLUSTER_ID] = { {{} }, + {{74, 39, 45}, {} }, {{71, 39, 45}, {} }, {{71, 32, 38}, {} }, }, @@ -322,12 +322,12 @@ static const int sdm632_apss_fuse_ref_volt[2][SDM632_POWER_APSS_FUSE_CORNERS] = { [CPR4_APSS_POWER_CLUSTER_ID] = { 645000, - 720000, 790000, 865000, 1065000, }, [CPR4_APSS_PERF_CLUSTER_ID] = { + 645000, 790000, 865000, 1065000, @@ -1025,7 +1025,7 @@ static int cpr4_apss_calculate_target_quotients(struct cpr3_regulator *vreg) } else { corner_name = cpr4_sdm632_perf_apss_fuse_corner_name; lowest_fuse_corner = - CPR4_SDM632_PERF_APSS_FUSE_CORNER_SVS_L1; + CPR4_SDM632_PERF_APSS_FUSE_CORNER_LOWSVS; highest_fuse_corner = CPR4_SDM632_PERF_APSS_FUSE_CORNER_TURBO_L1; } -- GitLab From 25c24c1dd349e073f30cbd1d47e0ff4485199e1b Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Tue, 8 May 2018 16:27:06 +0530 Subject: [PATCH 1680/1834] ARM: dts: msm: disable home key for SDM632 RCM device Disable home key for SDM632 RCM device, as there is no such module on the device. Change-Id: I7a0902047177dff3ba928136cdd2accda1106c8c Signed-off-by: Shantanu Jain --- arch/arm64/boot/dts/qcom/sdm632-rcm.dts | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm632-rcm.dts b/arch/arm64/boot/dts/qcom/sdm632-rcm.dts index 68f0ea0ca3e5..fe7ab38edd9e 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-rcm.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-rcm.dts @@ -24,3 +24,32 @@ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; }; +&soc { + gpio_keys { + /delete-node/home; + }; +}; + +&tlmm { + tlmm_gpio_key { + gpio_key_active: gpio_key_active { + mux { + pins = "gpio85", "gpio86", "gpio87"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87"; + }; + }; + + gpio_key_suspend: gpio_key_suspend { + mux { + pins = "gpio85", "gpio86", "gpio87"; + }; + + config { + pins = "gpio85", "gpio86", "gpio87"; + }; + }; + }; +}; -- GitLab From 83f2d490ca93c98d7964183c0a39fa6e25fd3e21 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Mon, 7 May 2018 12:19:17 +0530 Subject: [PATCH 1681/1834] drivers: cpuidle: lpm-levels: Update failure print Remove unused goto statement and update failure print. Change-Id: Ie85dc1c5f42c6434961bc3787c09012c406b3f75 Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index 9ae640da4df8..9694225f8ea8 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -1783,12 +1783,10 @@ static int __init lpm_levels_module_init(void) #endif rc = platform_driver_register(&lpm_driver); - if (rc) { - pr_info("Error registering %s\n", lpm_driver.driver.name); - goto fail; - } + if (rc) + pr_info("Error registering %s rc=%d\n", lpm_driver.driver.name, + rc); -fail: return rc; } late_initcall(lpm_levels_module_init); -- GitLab From 8e12d2b95e4fe540d3980c021d4e922a30f25838 Mon Sep 17 00:00:00 2001 From: Manapragada Sai Date: Tue, 8 May 2018 18:11:02 +0530 Subject: [PATCH 1682/1834] defconfig: msm: Continued Config cleanup on SDM439 Disabling few extra configs seen on 4.9 kernel compared to 3.18 kernel. Change-Id: I55da4fe2b51e300d552b25176576ed6cb3661749 Signed-off-by: Manapragada Sai --- arch/arm/configs/msm8937-perf_defconfig | 15 +++++---------- arch/arm/configs/msm8937_defconfig | 15 +++++---------- arch/arm64/configs/msm8937-perf_defconfig | 15 +++++---------- arch/arm64/configs/msm8937_defconfig | 15 +++++---------- 4 files changed, 20 insertions(+), 40 deletions(-) diff --git a/arch/arm/configs/msm8937-perf_defconfig b/arch/arm/configs/msm8937-perf_defconfig index 5a6de0f4f422..ee0446712c46 100644 --- a/arch/arm/configs/msm8937-perf_defconfig +++ b/arch/arm/configs/msm8937-perf_defconfig @@ -17,7 +17,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -223,6 +222,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -241,7 +242,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -253,10 +253,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -339,7 +337,6 @@ CONFIG_PINCTRL_MSM8917=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y @@ -409,7 +406,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_RADIO_IRIS=y @@ -422,7 +418,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -483,11 +479,12 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -588,8 +585,6 @@ CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y diff --git a/arch/arm/configs/msm8937_defconfig b/arch/arm/configs/msm8937_defconfig index 858b506ba37a..dceb155c8066 100644 --- a/arch/arm/configs/msm8937_defconfig +++ b/arch/arm/configs/msm8937_defconfig @@ -18,7 +18,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -228,6 +227,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -246,7 +247,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -258,10 +258,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -346,7 +344,6 @@ CONFIG_PINCTRL_MSM8917=y CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y @@ -416,7 +413,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_RADIO_IRIS=y @@ -430,7 +426,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -491,12 +487,13 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -604,8 +601,6 @@ CONFIG_FUSE_FS=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 4c6b6a1b39b4..41ab5e2486ac 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -18,7 +18,6 @@ CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -224,6 +223,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -242,7 +243,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -254,10 +254,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -341,7 +339,6 @@ CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_SYSCON=y @@ -414,7 +411,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y @@ -428,7 +424,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -489,11 +485,12 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -596,8 +593,6 @@ CONFIG_FUSE_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index 11bd200bdd36..69ff1522b6ab 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -19,7 +19,6 @@ CONFIG_IKCONFIG_PROC=y CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 CONFIG_CGROUP_DEBUG=y CONFIG_CGROUP_FREEZER=y -CONFIG_CPUSETS=y CONFIG_CGROUP_CPUACCT=y CONFIG_CGROUP_SCHEDTUNE=y CONFIG_RT_GROUP_SCHED=y @@ -230,6 +229,8 @@ CONFIG_RMNET_DATA=y CONFIG_RMNET_DATA_FC=y CONFIG_RMNET_DATA_DEBUG_PKT=y CONFIG_BT=y +# CONFIG_BT_BREDR is not set +# CONFIG_BT_LE is not set CONFIG_MSM_BT_POWER=y CONFIG_CFG80211=y CONFIG_CFG80211_INTERNAL_REGDB=y @@ -248,7 +249,6 @@ CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y CONFIG_UID_SYS_STATS=y -CONFIG_MEMORY_STATE_TIME=y CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y CONFIG_CHR_DEV_SG=y @@ -260,10 +260,8 @@ CONFIG_SCSI_UFSHCD=y CONFIG_SCSI_UFSHCD_PLATFORM=y CONFIG_SCSI_UFS_QCOM=y CONFIG_SCSI_UFS_QCOM_ICE=y -CONFIG_SCSI_UFSHCD_CMD_LOGGING=y CONFIG_MD=y CONFIG_BLK_DEV_DM=y -CONFIG_DM_DEBUG=y CONFIG_DM_CRYPT=y CONFIG_DM_REQ_CRYPT=y CONFIG_DM_UEVENT=y @@ -349,7 +347,6 @@ CONFIG_PINCTRL_QCOM_SPMI_PMIC=y CONFIG_GPIOLIB=y CONFIG_GPIO_SYSFS=y CONFIG_GPIO_QPNP_PIN=y -CONFIG_GPIO_QPNP_PIN_DEBUG=y CONFIG_POWER_RESET_QCOM=y CONFIG_QCOM_DLOAD_MODE=y CONFIG_POWER_RESET_SYSCON=y @@ -422,7 +419,6 @@ CONFIG_OV12830=y CONFIG_MSM_V4L2_VIDEO_OVERLAY_DEVICE=y CONFIG_MSMB_JPEG=y CONFIG_MSM_FD=y -CONFIG_MSM_JPEGDMA=y CONFIG_MSM_VIDC_3X_V4L2=y CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_MSM_SDE_ROTATOR=y @@ -437,7 +433,7 @@ CONFIG_FB_MSM_MDSS_WRITEBACK=y CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CLASS_DEVICE is not set CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_DYNAMIC_MINORS=y @@ -498,12 +494,13 @@ CONFIG_USB_CONFIGFS_F_CCID=y CONFIG_USB_CONFIGFS_F_QDSS=y CONFIG_MMC=y CONFIG_MMC_PERF_PROFILING=y +# CONFIG_PWRSEQ_EMMC is not set +# CONFIG_PWRSEQ_SIMPLE is not set CONFIG_MMC_RING_BUFFER=y CONFIG_MMC_PARANOID_SD_INIT=y CONFIG_MMC_CLKGATE=y CONFIG_MMC_BLOCK_MINORS=32 CONFIG_MMC_BLOCK_DEFERRED_RESUME=y -CONFIG_MMC_TEST=y CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_PLTFM=y CONFIG_MMC_SDHCI_MSM=y @@ -615,8 +612,6 @@ CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y CONFIG_TMPFS_POSIX_ACL=y -CONFIG_ECRYPT_FS=y -CONFIG_ECRYPT_FS_MESSAGING=y CONFIG_SDCARD_FS=y # CONFIG_NETWORK_FILESYSTEMS is not set CONFIG_NLS_CODEPAGE_437=y -- GitLab From a6e3f5193288465a90e66a56b085558218bc842b Mon Sep 17 00:00:00 2001 From: Zhen Kong Date: Fri, 20 Jan 2017 12:22:23 -0800 Subject: [PATCH 1683/1834] qseecom: release memory when failed to get fw size release app list entry when __qseecom_get_fw_size() returns error. Change-Id: I82406c39a2def87395811f442f39b57201766091 Signed-off-by: Zhen Kong --- drivers/misc/qseecom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index c0143db8ca9d..2b31ed3f981d 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -4510,6 +4510,7 @@ int qseecom_start_app(struct qseecom_handle **handle, strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE); if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) { ret = -EIO; + kfree(entry); goto exit_entry_free; } entry->app_arch = app_arch; -- GitLab From 3ee2e1201874d0c2e4f8edd0b6fdf6ff199a1ff1 Mon Sep 17 00:00:00 2001 From: Sunil Khatri Date: Mon, 2 Apr 2018 12:43:53 +0530 Subject: [PATCH 1684/1834] msm: kgsl: Enable GPU CPZ for A505/A504 Add GPU properties in A505/A504 GPU list to enable CPZ. For secure content rendering GPU content protection needs to be enabled. Change-Id: I14d9645db52b3f6be371760025ce2d10ec20b8e7 Signed-off-by: Sunil Khatri --- drivers/gpu/msm/adreno-gpulist.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno-gpulist.h b/drivers/gpu/msm/adreno-gpulist.h index f7e9eb338913..614b1c7697ef 100644 --- a/drivers/gpu/msm/adreno-gpulist.h +++ b/drivers/gpu/msm/adreno-gpulist.h @@ -207,9 +207,11 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .major = 0, .minor = 4, .patchid = ANY_ID, - .features = ADRENO_PREEMPTION | ADRENO_64BIT, + .features = ADRENO_PREEMPTION | ADRENO_64BIT | + ADRENO_CONTENT_PROTECTION | ADRENO_CPZ_RETENTION, .pm4fw_name = "a530_pm4.fw", .pfpfw_name = "a530_pfp.fw", + .zap_name = "a506_zap", .gpudev = &adreno_a5xx_gpudev, .gmem_size = (SZ_128K + SZ_8K), .num_protected_regs = 0x20, @@ -221,9 +223,11 @@ static const struct adreno_gpu_core adreno_gpulist[] = { .major = 0, .minor = 5, .patchid = ANY_ID, - .features = ADRENO_PREEMPTION | ADRENO_64BIT, + .features = ADRENO_PREEMPTION | ADRENO_64BIT | + ADRENO_CONTENT_PROTECTION | ADRENO_CPZ_RETENTION, .pm4fw_name = "a530_pm4.fw", .pfpfw_name = "a530_pfp.fw", + .zap_name = "a506_zap", .gpudev = &adreno_a5xx_gpudev, .gmem_size = (SZ_128K + SZ_8K), .num_protected_regs = 0x20, -- GitLab From 464d6c0144b64ee186179a4eef6f77998a0631ec Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Tue, 8 May 2018 11:46:03 -0700 Subject: [PATCH 1685/1834] ARM: dts: msm: Enable SMMU S1 for IPA on sdxpoorwills Take out the s1-bypass flag from IPA dtsi entries to enable SMMU for IPA memory. Change-Id: I8d7e1c8053ec58e93c502ef19bd9fb5f71fcb377 Crs-fixed: 2228863 Signed-off-by: Michael Adisumarta --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index ec5b61e1d334..9a5abe2bacb3 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1039,7 +1039,6 @@ ipa_smmu_ap: ipa_smmu_ap { compatible = "qcom,ipa-smmu-ap-cb"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x5E0 0x0>; qcom,iova-mapping = <0x20000000 0x40000000>; qcom,additional-mapping = @@ -1050,7 +1049,6 @@ ipa_smmu_wlan: ipa_smmu_wlan { compatible = "qcom,ipa-smmu-wlan-cb"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x5E1 0x0>; qcom,additional-mapping = /* ipa-uc ram */ @@ -1059,7 +1057,6 @@ ipa_smmu_uc: ipa_smmu_uc { compatible = "qcom,ipa-smmu-uc-cb"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x5E2 0x0>; qcom,iova-mapping = <0x40000000 0x20000000>; }; -- GitLab From 677363c05ad45878efb1842e6c1f252eebd415c6 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 7 May 2018 12:14:38 -0700 Subject: [PATCH 1686/1834] ARM: dts: msm: Enable SMMU S1 for EMAC on sdxpoorwills Remove the S1 bypass flag to enable SMMU mapping in EMAC for all the memory allocations. Change-Id: I07f3927b82ab807905c79d6ee872873cf5e63b63 CRs-Fixed: 2237497 Acked-by: Nisha Menon Signed-off-by: Sunil Paidimarri --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 9a5abe2bacb3..7911896ebc30 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1278,7 +1278,6 @@ emac_emb_smmu: emac_emb_smmu { compatible = "qcom,emac-smmu-embedded"; - qcom,smmu-s1-bypass; iommus = <&apps_smmu 0x220 0xf>; qcom,iova-mapping = <0x80000000 0x40000000>; }; -- GitLab From fa43dbfe83a4d14d4f3014a8c73410e276cd6403 Mon Sep 17 00:00:00 2001 From: Jingbiao Lu Date: Wed, 9 May 2018 10:07:33 +0800 Subject: [PATCH 1687/1834] ARM: qcom: add board config support for sda429 and sda439 Add board config support for sda429 and sda439. Change-Id: I44733203397199147e1893a325775d51d289b65a Signed-off-by: Jingbiao Lu --- arch/arm/mach-qcom/board-sdm429.c | 1 + arch/arm/mach-qcom/board-sdm439.c | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/mach-qcom/board-sdm429.c b/arch/arm/mach-qcom/board-sdm429.c index c648eafcc685..6bdf0f4eb957 100644 --- a/arch/arm/mach-qcom/board-sdm429.c +++ b/arch/arm/mach-qcom/board-sdm429.c @@ -17,6 +17,7 @@ static const char *sdm429_dt_match[] __initconst = { "qcom,sdm429", + "qcom,sda429", NULL }; diff --git a/arch/arm/mach-qcom/board-sdm439.c b/arch/arm/mach-qcom/board-sdm439.c index 312f3a5c5bc3..7b9aa0fa8676 100644 --- a/arch/arm/mach-qcom/board-sdm439.c +++ b/arch/arm/mach-qcom/board-sdm439.c @@ -17,6 +17,7 @@ static const char *sdm439_dt_match[] __initconst = { "qcom,sdm439", + "qcom,sda439", NULL }; -- GitLab From 0d5834ff6c0311265a1d37461ff815b5743fa5a9 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Thu, 3 May 2018 17:16:57 +0800 Subject: [PATCH 1688/1834] ARM: dts: msm: Correct dump size of rpmh for sdxpoorwills The original dump size of rpmh is unable to allocated. Correct the size of rpmh to make SDI be able to dump rpmh. CRs-Fixed: 2238517 Change-Id: I10ce6144b85047a583497b0d18fca4c102de5788 Signed-off-by: Mao Jinlong --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index ec5b61e1d334..963d5cb02eaf 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -809,7 +809,7 @@ memory-region = <&dump_mem>; rpmh_dump { - qcom,dump-size = <0x2000000>; + qcom,dump-size = <0x300000>; qcom,dump-id = <0xec>; }; -- GitLab From ff64a11f42ddf419aa883df8ea84d9e5bc6793cd Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Tue, 28 Nov 2017 22:20:16 +0530 Subject: [PATCH 1689/1834] msm: vidc: Select UBWC statistic parameters appropriately If initial values for min_CR and min_CF are set to 0 then while finding the minimum value in the list it will always compare with 0 and output min_CR as 0. Change-Id: I73a21e723a0f7111eb959439808a7d7ad46ad937 Signed-off-by: Vikash Garodia Signed-off-by: Prateek Shrivastava --- drivers/media/platform/msm/vidc/msm_vidc_clocks.c | 12 ++++++++---- drivers/media/platform/msm/vidc/msm_vidc_common.c | 8 ++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c index 4a0aa581bd3c..6ae030f8ef27 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_clocks.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_clocks.c @@ -114,14 +114,18 @@ static int fill_dynamic_stats(struct msm_vidc_inst *inst, { struct recon_buf *binfo, *nextb; struct vidc_input_cr_data *temp, *next; - u32 min_cf = 0, max_cf = 0; - u32 min_input_cr = 0, max_input_cr = 0, min_cr = 0, max_cr = 0; + u32 max_cr = 0, max_cf = 0, max_input_cr = 0; + u32 min_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO; + u32 min_input_cr = MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO; + u32 min_cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR; mutex_lock(&inst->reconbufs.lock); list_for_each_entry_safe(binfo, nextb, &inst->reconbufs.list, list) { - min_cr = min(min_cr, binfo->CR); + if (binfo->CR) + min_cr = min(min_cr, binfo->CR); + if (binfo->CF) + min_cf = min(min_cf, binfo->CF); max_cr = max(max_cr, binfo->CR); - min_cf = min(min_cf, binfo->CF); max_cf = max(max_cf, binfo->CF); } mutex_unlock(&inst->reconbufs.lock); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index b3926101ced1..f9bc79c87790 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -2035,6 +2035,7 @@ static void handle_session_flush(enum hal_command_response cmd, void *data) struct msm_vidc_cb_cmd_done *response = data; struct msm_vidc_inst *inst; struct v4l2_event flush_event = {0}; + struct recon_buf *binfo; u32 *ptr = NULL; enum hal_flush flush_type; int rc; @@ -2089,6 +2090,13 @@ static void handle_session_flush(enum hal_command_response cmd, void *data) goto exit; } + mutex_lock(&inst->reconbufs.lock); + list_for_each_entry(binfo, &inst->reconbufs.list, list) { + binfo->CR = 0; + binfo->CF = 0; + } + mutex_unlock(&inst->reconbufs.lock); + dprintk(VIDC_DBG, "Notify flush complete, flush_type: %x\n", flush_type); v4l2_event_queue_fh(&inst->event_handler, &flush_event); -- GitLab From 7fa1540f0b638894967504ddac8e7099896839c9 Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 8 May 2018 12:15:08 +0530 Subject: [PATCH 1690/1834] sched/walt: Fix stale window start marker passed to the schedutil With commit d8c5bfcc07ee ("sched: Make sure window start passed to schedutil is consistent"), the rq->load_reported_window is presented to the governor as the window_start marker. The rq->load_reported_window is updated when load is reported to governor only during a window rollover. So it should be consistent with the current window start mark. But for a just hotplugged in CPU, the rq->load_reported_window is not updated until the next window rollover. If the load is reported for any other reason before the next window rollover, the window start marker passed to the schedutil would be stale and leads to a BUG_ON() in schedutil. The recent window start marker is cached in WALT in walt_irq_work_lastq_ws. Use this instead of load_reported_window to fix this problem. The rq->window_start is cached in rq->load_reported_window to filter the utilization updates in the same window. This is not needed since utilization updates are not sent when SCHED_CPUFREQ_WALT flag is not set. So kill the load_reported_window maintenance. Change-Id: Idaefcb0b9cecb15ea436ac7a66cb6da81e3852a1 Signed-off-by: Pavankumar Kondeti --- kernel/sched/sched.h | 19 +++---------------- kernel/sched/walt.c | 2 +- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index f27ab13d40ce..61aa3c78e8d1 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -798,7 +798,6 @@ struct rq { int cstate, wakeup_latency, wakeup_energy; u64 window_start; s64 cum_window_start; - u64 load_reported_window; unsigned long walt_flags; u64 cur_irqload; @@ -1862,6 +1861,8 @@ cpu_util_freq_pelt(int cpu) } #ifdef CONFIG_SCHED_WALT +extern atomic64_t walt_irq_work_lastq_ws; + static inline unsigned long cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) { @@ -1898,7 +1899,7 @@ cpu_util_freq_walt(int cpu, struct sched_walt_cpu_load *walt_load) walt_load->prev_window_util = util; walt_load->nl = nl; walt_load->pl = pl; - walt_load->ws = rq->load_reported_window; + walt_load->ws = atomic64_read(&walt_irq_work_lastq_ws); } return (util >= capacity) ? capacity : util; @@ -2268,22 +2269,8 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) struct update_util_data *data; #ifdef CONFIG_SCHED_WALT - unsigned int exception_flags = SCHED_CPUFREQ_INTERCLUSTER_MIG | - SCHED_CPUFREQ_PL | SCHED_CPUFREQ_EARLY_DET | - SCHED_CPUFREQ_FORCE_UPDATE; - - /* - * Skip if we've already reported, but not if this is an inter-cluster - * migration. Also only allow WALT update sites. - */ if (!(flags & SCHED_CPUFREQ_WALT)) return; - if (!sched_disable_window_stats && - (rq->load_reported_window == rq->window_start) && - !(flags & exception_flags)) - return; - if (!(flags & exception_flags)) - rq->load_reported_window = rq->window_start; #endif data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data, diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index a9fb3678fdb1..c8f6e00419be 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -44,7 +44,7 @@ const char *migrate_type_names[] = {"GROUP_TO_RQ", "RQ_TO_GROUP", static struct cpu_cycle_counter_cb cpu_cycle_counter_cb; static bool use_cycle_counter; DEFINE_MUTEX(cluster_lock); -static atomic64_t walt_irq_work_lastq_ws; +atomic64_t walt_irq_work_lastq_ws; static struct irq_work walt_cpufreq_irq_work; static struct irq_work walt_migration_irq_work; -- GitLab From a791d522e899abc15bae1db9a8cf8928eeebb355 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Tue, 10 Apr 2018 18:20:42 +0530 Subject: [PATCH 1691/1834] power: qpnp-qg: add support for capacity learning and cycle counter Capacity learning and cycle counter algorithms are supported through fg-alg.c. Add the necessary initialization and callback functions to qg driver to support those algorithms. CRs-Fixed: 2225348 Change-Id: I8457da50607fc8fdbecf191bfe574d99bb2e50b4 Signed-off-by: Vamshi Krishna B V --- .../bindings/power/supply/qcom/qpnp-qg.txt | 71 +++ drivers/power/supply/qcom/Makefile | 2 +- .../power/supply/qcom/qg-battery-profile.c | 21 + .../power/supply/qcom/qg-battery-profile.h | 1 + drivers/power/supply/qcom/qg-core.h | 13 + drivers/power/supply/qcom/qg-defs.h | 3 + drivers/power/supply/qcom/qg-reg.h | 2 + drivers/power/supply/qcom/qg-sdam.c | 47 ++ drivers/power/supply/qcom/qg-sdam.h | 2 + drivers/power/supply/qcom/qg-soc.c | 26 +- drivers/power/supply/qcom/qpnp-qg.c | 403 +++++++++++++++++- include/uapi/linux/qg.h | 7 +- 12 files changed, 591 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt index efa67f526547..afeb65dc86d0 100644 --- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt +++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt @@ -191,6 +191,77 @@ First Level Node - QGAUGE device temperature specific configuration as applied. If not specified, the default value is 0 degree centigrade. +- qcom,cl-disable + Usage: optional + Value type: + Definition: A boolean property to disable the battery capacity + learning when charging. + +- qcom,cl-feedback-on + Usage: optional + Value type: + Definition: A boolean property to feedback the learned capacity into + the capacity lerning algorithm. This has to be used only if the + property "qcom,cl-disable" is not specified. + +- qcom,cl-max-start-soc + Usage: optional + Value type: + Definition: Battery SOC has to be below or equal to this value at the + start of a charge cycle to start the capacity learning. + If this is not specified, then the default value used + will be 15. Unit is in percentage. + +- qcom,cl-min-start-soc + Usage: optional + Value type: + Definition: Battery SOC has to be above or equal to this value at the + start of a charge cycle to start the capacity learning. + If this is not specified, then the default value used + will be 10. Unit is in percentage. + +- qcom,cl-min-temp + Usage: optional + Value type: + Definition: Lower limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 150 (15 C). Unit is in decidegC. + +- qcom,cl-max-temp + Usage: optional + Value type: + Definition: Upper limit of battery temperature to start the capacity + learning. If this is not specified, then the default value + used will be 500 (50 C). Unit is in decidegC. + +- qcom,cl-max-increment + Usage: optional + Value type: + Definition: Maximum capacity increment allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 5 (0.5%). Unit is in decipercentage. + +- qcom,cl-max-decrement + Usage: optional + Value type: + Definition: Maximum capacity decrement allowed per capacity learning + cycle. If this is not specified, then the default value + used will be 100 (10%). Unit is in decipercentage. + +- qcom,cl-min-limit + Usage: optional + Value type: + Definition: Minimum limit that the capacity cannot go below in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + +- qcom,cl-max-limit + Usage: optional + Value type: + Definition: Maximum limit that the capacity cannot go above in a + capacity learning cycle. If this is not specified, then + the default value is 0. Unit is in decipercentage. + ========================================================== Second Level Nodes - Peripherals managed by QGAUGE driver ========================================================== diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index de76a5bdeacf..d345cc3757ca 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_SMB1355_SLAVE_CHARGER) += smb1355-charger.o pmic-voter.o obj-$(CONFIG_SMB1351_USB_CHARGER) += smb1351-charger.o pmic-voter.o battery.o obj-$(CONFIG_QPNP_SMB2) += step-chg-jeita.o battery.o qpnp-smb2.o smb-lib.o pmic-voter.o storm-watch.o obj-$(CONFIG_SMB138X_CHARGER) += step-chg-jeita.o smb138x-charger.o smb-lib.o pmic-voter.o storm-watch.o battery.o -obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o +obj-$(CONFIG_QPNP_QG) += qpnp-qg.o pmic-voter.o qg-util.o qg-soc.o qg-sdam.o qg-battery-profile.o qg-profile-lib.o fg-alg.o obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o obj-$(CONFIG_QPNP_TYPEC) += qpnp-typec.o obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o diff --git a/drivers/power/supply/qcom/qg-battery-profile.c b/drivers/power/supply/qcom/qg-battery-profile.c index 441c759a384a..36edd76c642a 100644 --- a/drivers/power/supply/qcom/qg-battery-profile.c +++ b/drivers/power/supply/qcom/qg-battery-profile.c @@ -22,6 +22,7 @@ #include #include #include +#include "qg-battery-profile.h" #include "qg-profile-lib.h" #include "qg-defs.h" @@ -410,6 +411,26 @@ int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging) return 0; } +int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging) +{ + u8 table_index = charging ? TABLE_FCC1 : TABLE_FCC2; + u32 fcc_mah; + + if (!the_battery || !the_battery->profile) { + pr_err("Battery profile not loaded\n"); + return -ENODEV; + } + + fcc_mah = interpolate_single_row_lut( + &the_battery->profile[table_index], + batt_temp, DEGC_SCALE); + fcc_mah = CAP(QG_MIN_FCC_MAH, QG_MAX_FCC_MAH, fcc_mah); + + *nom_cap_uah = fcc_mah * 1000; + + return 0; +} + int qg_batterydata_init(struct device_node *profile_node) { int rc = 0; diff --git a/drivers/power/supply/qcom/qg-battery-profile.h b/drivers/power/supply/qcom/qg-battery-profile.h index 143a4f239cfb..1b0627776ff0 100644 --- a/drivers/power/supply/qcom/qg-battery-profile.h +++ b/drivers/power/supply/qcom/qg-battery-profile.h @@ -15,5 +15,6 @@ int qg_batterydata_init(struct device_node *node); void qg_batterydata_exit(void); int lookup_soc_ocv(u32 *soc, u32 ocv_uv, int batt_temp, bool charging); +int qg_get_nominal_capacity(u32 *nom_cap_uah, int batt_temp, bool charging); #endif /* __QG_BATTERY_PROFILE_H__ */ diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 6e44f335f884..05ca4529e6c6 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -12,6 +12,9 @@ #ifndef __QG_CORE_H__ #define __QG_CORE_H__ +#include +#include "fg-alg.h" + struct qg_batt_props { const char *batt_type_str; int float_volt_uv; @@ -49,6 +52,8 @@ struct qg_dt { int cold_temp_threshold; bool hold_soc_while_full; bool linearize_soc; + bool cl_disable; + bool cl_feedback_on; }; struct qpnp_qg { @@ -109,12 +114,19 @@ struct qpnp_qg { int maint_soc; int msoc; int pon_soc; + int batt_soc; + int cc_soc; struct alarm alarm_timer; u32 sdam_data[SDAM_MAX]; /* DT */ struct qg_dt dt; struct qg_batt_props bp; + /* capacity learning */ + struct cap_learning *cl; + /* charge counter */ + struct cycle_counter *counter; + char counter_buf[BUCKET_COUNT * 8]; }; enum ocv_type { @@ -135,6 +147,7 @@ enum debug_mask { QG_DEBUG_PM = BIT(7), QG_DEBUG_BUS_READ = BIT(8), QG_DEBUG_BUS_WRITE = BIT(9), + QG_DEBUG_ALG_CL = BIT(10), }; enum qg_irq { diff --git a/drivers/power/supply/qcom/qg-defs.h b/drivers/power/supply/qcom/qg-defs.h index 6ae9aa2c0cab..2061208ad55c 100644 --- a/drivers/power/supply/qcom/qg-defs.h +++ b/drivers/power/supply/qcom/qg-defs.h @@ -47,4 +47,7 @@ #define CAP(min, max, value) \ ((min > value) ? min : ((value > max) ? max : value)) +#define QG_SOC_FULL 10000 +#define BATT_SOC_32BIT GENMASK(31, 0) + #endif /* __QG_DEFS_H__ */ diff --git a/drivers/power/supply/qcom/qg-reg.h b/drivers/power/supply/qcom/qg-reg.h index 96533d4dad43..66f9be11a7df 100644 --- a/drivers/power/supply/qcom/qg-reg.h +++ b/drivers/power/supply/qcom/qg-reg.h @@ -87,6 +87,8 @@ #define QG_SDAM_OCV_OFFSET 0x4C #define QG_SDAM_IBAT_OFFSET 0x50 #define QG_SDAM_TIME_OFFSET 0x54 +#define QG_SDAM_CYCLE_COUNT_OFFSET 0x58 +#define QG_SDAM_LEARNED_CAPACITY_OFFSET 0x68 #define QG_SDAM_PON_OCV_OFFSET 0x7C #endif diff --git a/drivers/power/supply/qcom/qg-sdam.c b/drivers/power/supply/qcom/qg-sdam.c index 54eed16fa2c2..7bc4afac1b44 100644 --- a/drivers/power/supply/qcom/qg-sdam.c +++ b/drivers/power/supply/qcom/qg-sdam.c @@ -130,6 +130,53 @@ int qg_sdam_read(u8 param, u32 *data) return rc; } +int qg_sdam_multibyte_write(u32 offset, u8 *data, u32 length) +{ + int rc, i; + struct qg_sdam *chip = the_chip; + + if (!chip) { + pr_err("Invalid sdam-chip pointer\n"); + return -EINVAL; + } + + offset = chip->sdam_base + offset; + rc = regmap_bulk_write(chip->regmap, offset, data, (size_t)length); + if (rc < 0) { + pr_err("Failed to write offset=%0x4x value=%d\n", + offset, *data); + } else { + for (i = 0; i < length; i++) + pr_debug("QG SDAM write offset=%0x4x value=%d\n", + offset++, data[i]); + } + + return rc; +} + +int qg_sdam_multibyte_read(u32 offset, u8 *data, u32 length) +{ + int rc, i; + struct qg_sdam *chip = the_chip; + + if (!chip) { + pr_err("Invalid sdam-chip pointer\n"); + return -EINVAL; + } + + offset = chip->sdam_base + offset; + rc = regmap_raw_read(chip->regmap, offset, (u8 *)data, (size_t)length); + if (rc < 0) { + pr_err("Failed to read offset=%0x4x\n", offset); + } else { + for (i = 0; i < length; i++) + pr_debug("QG SDAM read offset=%0x4x value=%d\n", + offset++, data[i]); + } + + return rc; +} + int qg_sdam_read_all(u32 *sdam_data) { int i, rc; diff --git a/drivers/power/supply/qcom/qg-sdam.h b/drivers/power/supply/qcom/qg-sdam.h index 51af04c7b493..10e684f8ec40 100644 --- a/drivers/power/supply/qcom/qg-sdam.h +++ b/drivers/power/supply/qcom/qg-sdam.h @@ -37,5 +37,7 @@ int qg_sdam_write(u8 param, u32 data); int qg_sdam_read(u8 param, u32 *data); int qg_sdam_write_all(u32 *sdam_data); int qg_sdam_read_all(u32 *sdam_data); +int qg_sdam_multibyte_write(u32 offset, u8 *sdam_data, u32 length); +int qg_sdam_multibyte_read(u32 offset, u8 *sdam_data, u32 length); #endif diff --git a/drivers/power/supply/qcom/qg-soc.c b/drivers/power/supply/qcom/qg-soc.c index c4d504354554..af8b158b7c95 100644 --- a/drivers/power/supply/qcom/qg-soc.c +++ b/drivers/power/supply/qcom/qg-soc.c @@ -13,9 +13,11 @@ #define pr_fmt(fmt) "QG-K: %s: " fmt, __func__ #include +#include #include #include #include +#include "fg-alg.h" #include "qg-sdam.h" #include "qg-core.h" #include "qg-reg.h" @@ -98,11 +100,12 @@ static bool is_scaling_required(struct qpnp_qg *chip) static void update_msoc(struct qpnp_qg *chip) { - int rc; + int rc = 0, batt_temp = 0, batt_soc_32bit = 0; + bool usb_present = is_usb_present(chip); if (chip->catch_up_soc > chip->msoc) { /* SOC increased */ - if (is_usb_present(chip)) /* Increment if USB is present */ + if (usb_present) /* Increment if USB is present */ chip->msoc += chip->dt.delta_soc; } else if (chip->catch_up_soc < chip->msoc) { /* SOC dropped */ @@ -130,6 +133,25 @@ static void update_msoc(struct qpnp_qg *chip) if (rc < 0) pr_err("Failed to update SDAM with MSOC rc=%d\n", rc); + if (!chip->dt.cl_disable && chip->cl->active) { + rc = qg_get_battery_temp(chip, &batt_temp); + if (rc < 0) { + pr_err("Failed to read BATT_TEMP rc=%d\n", rc); + } else { + batt_soc_32bit = div64_u64( + chip->batt_soc * BATT_SOC_32BIT, + QG_SOC_FULL); + cap_learning_update(chip->cl, batt_temp, batt_soc_32bit, + chip->charge_status, chip->charge_done, + usb_present, false); + } + } + + cycle_count_update(chip->counter, + DIV_ROUND_CLOSEST(chip->msoc * 255, 100), + chip->charge_status, chip->charge_done, + usb_present); + qg_dbg(chip, QG_DEBUG_SOC, "SOC scale: Update maint_soc=%d msoc=%d catch_up_soc=%d delta_soc=%d\n", chip->maint_soc, chip->msoc, diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index f7a6b7ab36c0..09705ade7b30 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,7 @@ #include #include #include +#include "fg-alg.h" #include "qg-sdam.h" #include "qg-core.h" #include "qg-reg.h" @@ -641,6 +643,12 @@ static void process_udata_work(struct work_struct *work) struct qpnp_qg, udata_work); int rc; + if (chip->udata.param[QG_CC_SOC].valid) + chip->cc_soc = chip->udata.param[QG_CC_SOC].data; + + if (chip->udata.param[QG_BATT_SOC].valid) + chip->batt_soc = chip->udata.param[QG_BATT_SOC].data; + if (chip->udata.param[QG_SOC].valid) { qg_dbg(chip, QG_DEBUG_SOC, "udata SOC=%d last SOC=%d\n", chip->udata.param[QG_SOC].data, chip->catch_up_soc); @@ -946,6 +954,127 @@ static int qg_good_ocv_irq_disable_cb(struct votable *votable, void *data, return 0; } +/* ALG callback functions below */ + +static int qg_get_learned_capacity(void *data, int64_t *learned_cap_uah) +{ + struct qpnp_qg *chip = data; + int16_t cc_mah; + int rc; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -EPERM; + + rc = qg_sdam_multibyte_read(QG_SDAM_LEARNED_CAPACITY_OFFSET, + (u8 *)&cc_mah, 2); + if (rc < 0) { + pr_err("Error in reading learned_capacity, rc=%d\n", rc); + return rc; + } + *learned_cap_uah = cc_mah * 1000; + + qg_dbg(chip, QG_DEBUG_ALG_CL, "Retrieved learned capacity %llduah\n", + *learned_cap_uah); + return 0; +} + +static int qg_store_learned_capacity(void *data, int64_t learned_cap_uah) +{ + struct qpnp_qg *chip = data; + int16_t cc_mah; + int rc; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !learned_cap_uah) + return -EPERM; + + cc_mah = div64_s64(learned_cap_uah, 1000); + rc = qg_sdam_multibyte_write(QG_SDAM_LEARNED_CAPACITY_OFFSET, + (u8 *)&cc_mah, 2); + if (rc < 0) { + pr_err("Error in writing learned_capacity, rc=%d\n", rc); + return rc; + } + + qg_dbg(chip, QG_DEBUG_ALG_CL, "Stored learned capacity %llduah\n", + learned_cap_uah); + return 0; +} + +static int qg_get_cc_soc(void *data, int *cc_soc) +{ + struct qpnp_qg *chip = data; + + if (!chip) + return -ENODEV; + + if (chip->cc_soc == INT_MIN) + return -EINVAL; + + *cc_soc = chip->cc_soc; + + return 0; +} + +static int qg_restore_cycle_count(void *data, u16 *buf, int length) +{ + struct qpnp_qg *chip = data; + int id, rc = 0; + u8 tmp[2]; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -EPERM; + + if (!buf || length > BUCKET_COUNT) + return -EINVAL; + + for (id = 0; id < length; id++) { + rc = qg_sdam_multibyte_read( + QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2), + (u8 *)tmp, 2); + if (rc < 0) { + pr_err("failed to read bucket %d rc=%d\n", id, rc); + return rc; + } + *buf++ = tmp[0] | tmp[1] << 8; + } + + return rc; +} + +static int qg_store_cycle_count(void *data, u16 *buf, int id, int length) +{ + struct qpnp_qg *chip = data; + int rc = 0; + + if (!chip) + return -ENODEV; + + if (chip->battery_missing || !chip->profile_loaded) + return -EPERM; + + if (!buf || length > BUCKET_COUNT * 2 || id < 0 || + id > BUCKET_COUNT - 1 || + (((id * 2) + length) > BUCKET_COUNT * 2)) + return -EINVAL; + + rc = qg_sdam_multibyte_write( + QG_SDAM_CYCLE_COUNT_OFFSET + (id * 2), + (u8 *)buf, length); + if (rc < 0) + pr_err("failed to write bucket %d rc=%d\n", id, rc); + + return rc; +} + #define DEFAULT_BATT_TYPE "Unknown Battery" #define MISSING_BATT_TYPE "Missing Battery" #define DEBUG_BATT_TYPE "Debug Board" @@ -1042,10 +1171,62 @@ static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc) return 0; } +static const char *qg_get_cycle_counts(struct qpnp_qg *chip) +{ + int i, rc, len = 0; + char *buf; + + buf = chip->counter_buf; + for (i = 1; i <= BUCKET_COUNT; i++) { + chip->counter->id = i; + rc = get_cycle_count(chip->counter); + if (rc < 0) { + pr_err("Couldn't get cycle count rc=%d\n", rc); + return NULL; + } + + if (sizeof(chip->counter_buf) - len < 8) { + pr_err("Invalid length %d\n", len); + return NULL; + } + + len += snprintf(buf+len, 8, "%d ", rc); + } + + buf[len] = '\0'; + return buf; +} + static int qg_psy_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *pval) { + struct qpnp_qg *chip = power_supply_get_drvdata(psy); + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (chip->dt.cl_disable) { + pr_warn("Capacity learning disabled!\n"); + return 0; + } + if (chip->cl->active) { + pr_warn("Capacity learning active!\n"); + return 0; + } + if (pval->intval <= 0 || pval->intval > chip->cl->nom_cap_uah) { + pr_err("charge_full is out of bounds\n"); + return -EINVAL; + } + mutex_lock(&chip->cl->lock); + rc = qg_store_learned_capacity(chip, pval->intval); + if (!rc) + chip->cl->learned_cap_uah = pval->intval; + mutex_unlock(&chip->cl->lock); + break; + default: + break; + } return 0; } @@ -1055,6 +1236,7 @@ static int qg_psy_get_property(struct power_supply *psy, { struct qpnp_qg *chip = power_supply_get_drvdata(psy); int rc = 0; + int64_t temp = 0; pval->intval = 0; @@ -1106,6 +1288,22 @@ static int qg_psy_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: pval->intval = chip->charge_counter_uah; break; + case POWER_SUPPLY_PROP_CHARGE_FULL: + if (!chip->dt.cl_disable && chip->dt.cl_feedback_on) + rc = qg_get_learned_capacity(chip, &temp); + else + rc = qg_get_nominal_capacity((int *)&temp, 250, true); + if (!rc) + pval->intval = (int)temp; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + rc = qg_get_nominal_capacity((int *)&temp, 250, true); + if (!rc) + pval->intval = (int)temp; + break; + case POWER_SUPPLY_PROP_CYCLE_COUNTS: + pval->strval = qg_get_cycle_counts(chip); + break; default: pr_debug("Unsupported property %d\n", psp); break; @@ -1117,6 +1315,12 @@ static int qg_psy_get_property(struct power_supply *psy, static int qg_property_is_writeable(struct power_supply *psy, enum power_supply_property psp) { + switch (psp) { + case POWER_SUPPLY_PROP_CHARGE_FULL: + return 1; + default: + break; + } return 0; } @@ -1136,6 +1340,9 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_BATT_FULL_CURRENT, POWER_SUPPLY_PROP_BATT_PROFILE_VERSION, + POWER_SUPPLY_PROP_CYCLE_COUNTS, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, }; static const struct power_supply_desc qg_psy_desc = { @@ -1262,7 +1469,7 @@ static void qg_status_change_work(struct work_struct *work) struct qpnp_qg *chip = container_of(work, struct qpnp_qg, qg_status_change_work); union power_supply_propval prop = {0, }; - int rc = 0; + int rc = 0, batt_temp = 0, batt_soc_32b = 0; if (!is_batt_available(chip)) { pr_debug("batt-psy not available\n"); @@ -1294,6 +1501,24 @@ static void qg_status_change_work(struct work_struct *work) if (rc < 0) pr_err("Failed to update usb status, rc=%d\n", rc); + cycle_count_update(chip->counter, + DIV_ROUND_CLOSEST(chip->msoc * 255, 100), + chip->charge_status, chip->charge_done, + chip->usb_present); + + if (!chip->dt.cl_disable) { + rc = qg_get_battery_temp(chip, &batt_temp); + if (rc < 0) { + pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc); + } else { + batt_soc_32b = div64_u64( + chip->batt_soc * BATT_SOC_32BIT, + QG_SOC_FULL); + cap_learning_update(chip->cl, batt_temp, batt_soc_32b, + chip->charge_status, chip->charge_done, + chip->usb_present, false); + } + } rc = qg_charge_full_update(chip); if (rc < 0) pr_err("Failed in charge_full_update, rc=%d\n", rc); @@ -2069,6 +2294,64 @@ static int qg_request_irqs(struct qpnp_qg *chip) return 0; } +static int qg_alg_init(struct qpnp_qg *chip) +{ + struct cycle_counter *counter; + struct cap_learning *cl; + struct device_node *node = chip->dev->of_node; + int rc; + + counter = devm_kzalloc(chip->dev, sizeof(*counter), GFP_KERNEL); + if (!counter) + return -ENOMEM; + + counter->restore_count = qg_restore_cycle_count; + counter->store_count = qg_store_cycle_count; + counter->data = chip; + + rc = cycle_count_init(counter); + if (rc < 0) { + dev_err(chip->dev, "Error in initializing cycle counter, rc:%d\n", + rc); + counter->data = NULL; + devm_kfree(chip->dev, counter); + return rc; + } + + chip->counter = counter; + + chip->dt.cl_disable = of_property_read_bool(node, + "qcom,cl-disable"); + + /*Return if capacity learning is disabled*/ + if (chip->dt.cl_disable) + return 0; + + cl = devm_kzalloc(chip->dev, sizeof(*cl), GFP_KERNEL); + if (!cl) + return -ENOMEM; + + cl->cc_soc_max = QG_SOC_FULL; + cl->get_cc_soc = qg_get_cc_soc; + cl->get_learned_capacity = qg_get_learned_capacity; + cl->store_learned_capacity = qg_store_learned_capacity; + cl->data = chip; + + rc = cap_learning_init(cl); + if (rc < 0) { + dev_err(chip->dev, "Error in initializing capacity learning, rc:%d\n", + rc); + counter->data = NULL; + cl->data = NULL; + devm_kfree(chip->dev, counter); + devm_kfree(chip->dev, cl); + return rc; + } + + chip->cl = cl; + return 0; +} + #define DEFAULT_VBATT_EMPTY_MV 3200 #define DEFAULT_VBATT_EMPTY_COLD_MV 3000 #define DEFAULT_VBATT_CUTOFF_MV 3400 @@ -2082,6 +2365,14 @@ static int qg_request_irqs(struct qpnp_qg *chip) #define DEFAULT_DELTA_SOC 1 #define DEFAULT_SHUTDOWN_SOC_SECS 360 #define DEFAULT_COLD_TEMP_THRESHOLD 0 +#define DEFAULT_CL_MIN_START_SOC 10 +#define DEFAULT_CL_MAX_START_SOC 15 +#define DEFAULT_CL_MIN_TEMP_DECIDEGC 150 +#define DEFAULT_CL_MAX_TEMP_DECIDEGC 500 +#define DEFAULT_CL_MAX_INC_DECIPERC 5 +#define DEFAULT_CL_MAX_DEC_DECIPERC 100 +#define DEFAULT_CL_MIN_LIM_DECIPERC 0 +#define DEFAULT_CL_MAX_LIM_DECIPERC 0 static int qg_parse_dt(struct qpnp_qg *chip) { int rc = 0; @@ -2275,6 +2566,65 @@ static int qg_parse_dt(struct qpnp_qg *chip) else chip->dt.rbat_conn_mohm = temp; + /* Capacity learning params*/ + if (!chip->dt.cl_disable) { + chip->dt.cl_feedback_on = of_property_read_bool(node, + "qcom,cl-feedback-on"); + + rc = of_property_read_u32(node, "qcom,cl-min-start-soc", &temp); + if (rc < 0) + chip->cl->dt.min_start_soc = DEFAULT_CL_MIN_START_SOC; + else + chip->cl->dt.min_start_soc = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-start-soc", &temp); + if (rc < 0) + chip->cl->dt.max_start_soc = DEFAULT_CL_MAX_START_SOC; + else + chip->cl->dt.max_start_soc = temp; + + rc = of_property_read_u32(node, "qcom,cl-min-temp", &temp); + if (rc < 0) + chip->cl->dt.min_temp = DEFAULT_CL_MIN_TEMP_DECIDEGC; + else + chip->cl->dt.min_temp = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-temp", &temp); + if (rc < 0) + chip->cl->dt.max_temp = DEFAULT_CL_MAX_TEMP_DECIDEGC; + else + chip->cl->dt.max_temp = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-increment", &temp); + if (rc < 0) + chip->cl->dt.max_cap_inc = DEFAULT_CL_MAX_INC_DECIPERC; + else + chip->cl->dt.max_cap_inc = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-decrement", &temp); + if (rc < 0) + chip->cl->dt.max_cap_dec = DEFAULT_CL_MAX_DEC_DECIPERC; + else + chip->cl->dt.max_cap_dec = temp; + + rc = of_property_read_u32(node, "qcom,cl-min-limit", &temp); + if (rc < 0) + chip->cl->dt.min_cap_limit = + DEFAULT_CL_MIN_LIM_DECIPERC; + else + chip->cl->dt.min_cap_limit = temp; + + rc = of_property_read_u32(node, "qcom,cl-max-limit", &temp); + if (rc < 0) + chip->cl->dt.max_cap_limit = + DEFAULT_CL_MAX_LIM_DECIPERC; + else + chip->cl->dt.max_cap_limit = temp; + + qg_dbg(chip, QG_DEBUG_PON, "DT: cl_min_start_soc=%d cl_max_start_soc=%d cl_min_temp=%d cl_max_temp=%d\n", + chip->cl->dt.min_start_soc, chip->cl->dt.max_start_soc, + chip->cl->dt.min_temp, chip->cl->dt.max_temp); + } qg_dbg(chip, QG_DEBUG_PON, "DT: vbatt_empty_mv=%dmV vbatt_low_mv=%dmV delta_soc=%d\n", chip->dt.vbatt_empty_mv, chip->dt.vbatt_low_mv, chip->dt.delta_soc); @@ -2464,7 +2814,7 @@ static const struct dev_pm_ops qpnp_qg_pm_ops = { static int qpnp_qg_probe(struct platform_device *pdev) { - int rc = 0, soc = 0; + int rc = 0, soc = 0, nom_cap_uah; struct qpnp_qg *chip; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); @@ -2497,6 +2847,14 @@ static int qpnp_qg_probe(struct platform_device *pdev) mutex_init(&chip->data_lock); init_waitqueue_head(&chip->qg_wait_q); chip->maint_soc = -EINVAL; + chip->batt_soc = INT_MIN; + chip->cc_soc = INT_MIN; + + rc = qg_alg_init(chip); + if (rc < 0) { + pr_err("Error in alg_init, rc:%d\n", rc); + return rc; + } rc = qg_parse_dt(chip); if (rc < 0) { @@ -2534,6 +2892,30 @@ static int qpnp_qg_probe(struct platform_device *pdev) return rc; } + if (chip->profile_loaded) { + if (!chip->dt.cl_disable) { + /* + * Use FCC @ 25 C and charge-profile for + * Nominal Capacity + */ + rc = qg_get_nominal_capacity(&nom_cap_uah, 250, true); + if (!rc) { + rc = cap_learning_post_profile_init(chip->cl, + nom_cap_uah); + if (rc < 0) { + pr_err("Error in cap_learning_post_profile_init rc=%d\n", + rc); + return rc; + } + } + } + rc = restore_cycle_count(chip->counter); + if (rc < 0) { + pr_err("Error in restoring cycle_count, rc=%d\n", rc); + return rc; + } + } + rc = qg_determine_pon_soc(chip); if (rc < 0) { pr_err("Failed to determine initial state, rc=%d\n", rc); @@ -2627,6 +3009,22 @@ static int qpnp_qg_remove(struct platform_device *pdev) return 0; } +static void qpnp_qg_shutdown(struct platform_device *pdev) +{ + struct qpnp_qg *chip = platform_get_drvdata(pdev); + + if (!is_usb_present(chip) || !chip->profile_loaded) + return; + /* + * Charging status doesn't matter when the device shuts down and we + * have to treat this as charge done. Hence pass charge_done as true. + */ + cycle_count_update(chip->counter, + DIV_ROUND_CLOSEST(chip->msoc * 255, 100), + POWER_SUPPLY_STATUS_NOT_CHARGING, + true, chip->usb_present); +} + static const struct of_device_id match_table[] = { { .compatible = "qcom,qpnp-qg", }, { }, @@ -2641,6 +3039,7 @@ static struct platform_driver qpnp_qg_driver = { }, .probe = qpnp_qg_probe, .remove = qpnp_qg_remove, + .shutdown = qpnp_qg_shutdown, }; module_platform_driver(qpnp_qg_driver); diff --git a/include/uapi/linux/qg.h b/include/uapi/linux/qg.h index 54488ff79c81..2c7b49af873d 100644 --- a/include/uapi/linux/qg.h +++ b/include/uapi/linux/qg.h @@ -12,8 +12,8 @@ enum qg { QG_ESR, QG_CHARGE_COUNTER, QG_FIFO_TIME_DELTA, - QG_RESERVED_1, - QG_RESERVED_2, + QG_BATT_SOC, + QG_CC_SOC, QG_RESERVED_3, QG_RESERVED_4, QG_RESERVED_5, @@ -25,6 +25,9 @@ enum qg { QG_MAX, }; +#define QG_BATT_SOC QG_BATT_SOC +#define QG_CC_SOC QG_CC_SOC + struct fifo_data { unsigned int v; unsigned int i; -- GitLab From 256be6b2c229a6a0443500dad18c366e51ca351e Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 8 May 2018 15:45:03 +0530 Subject: [PATCH 1692/1834] sched: Remove unnecessary calls to cpufreq_update_util() The cpufreq update util calls after update_task_ravg() are no longer needed. This is taken care in WALT when a window is rolled over. Besides these calls were ineffectual since SCHED_CPUFREQ_WALT wasn't passed in the flag parameter. Change-Id: I28ac40b33662584ec9f8fff116e66a6f33a8d010 Signed-off-by: Pavankumar Kondeti --- kernel/sched/core.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 467801c7922c..93c00e99a06d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2174,7 +2174,6 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) wallclock = ktime_get_ns(); update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_WAKE, wallclock, 0); - cpufreq_update_util(rq, 0); raw_spin_unlock(&rq->lock); rcu_read_lock(); @@ -2263,7 +2262,6 @@ static void try_to_wake_up_local(struct task_struct *p, struct pin_cookie cookie update_task_ravg(rq->curr, rq, TASK_UPDATE, wallclock, 0); update_task_ravg(p, rq, TASK_WAKE, wallclock, 0); - cpufreq_update_util(rq, 0); ttwu_activate(rq, p, ENQUEUE_WAKEUP); note_task_waking(p, wallclock); } @@ -3636,7 +3634,6 @@ static void __sched notrace __schedule(bool preempt) update_task_ravg(prev, rq, PUT_PREV_TASK, wallclock, 0); update_task_ravg(next, rq, PICK_NEXT_TASK, wallclock, 0); - cpufreq_update_util(rq, 0); rq->nr_switches++; rq->curr = next; ++*switch_count; @@ -3645,7 +3642,6 @@ static void __sched notrace __schedule(bool preempt) rq = context_switch(rq, prev, next, cookie); /* unlocks the rq */ } else { update_task_ravg(prev, rq, TASK_UPDATE, wallclock, 0); - cpufreq_update_util(rq, 0); lockdep_unpin_lock(&rq->lock, cookie); raw_spin_unlock_irq(&rq->lock); } -- GitLab From 7984a52b37595d6d808831c7c94ad6083b69fa45 Mon Sep 17 00:00:00 2001 From: Tiequan Luo Date: Mon, 7 May 2018 11:22:27 +0800 Subject: [PATCH 1693/1834] ARM: dts: msm: Add support for apq8009 robot-som variant Add support for apq8009-robot with pm8916 on AUDIO KIT carrier board for 1GB variant. Change-Id: Ifb4ee4c767f38608b649edb88bd731c5a2aaddaa Signed-off-by: Tiequan Luo --- arch/arm64/boot/dts/qcom/Makefile | 1 + .../dts/qcom/apq8009-robot-som-refboard.dts | 102 ++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 31d4b0d5bc0f..f47106eefe00 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -422,6 +422,7 @@ dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \ apq8009w-bg-wtp-v2.dtb \ apq8009w-bg-alpha.dtb \ apq8009-mtp-wcd9326-refboard.dtb \ + apq8009-robot-som-refboard.dtb \ apq8009-dragon.dtb dtb-$(CONFIG_ARCH_SDM450) += sdm450-rcm.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts new file mode 100644 index 000000000000..c9808dc4e571 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8909-mtp.dtsi" +#include "8909-pm8916.dtsi" +#include "msm8909-pm8916-mtp.dtsi" +#include "apq8009-audio-external_codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8009 Robot SOM refboard"; + compatible = "qcom,apq8009-mtp", "qcom,apq8009", "qcom,mtp"; + qcom,msm-id = <265 2>; + qcom,board-id = <8 0x15>; +}; + +&soc { + ext-codec { + qcom,msm-mbhc-hphl-swh = <0>; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + }; + + sound-9335 { + status = "disabled"; + }; + + i2c@78b8000 { + wcd9xxx_codec@d { + status = "disabled"; + }; + }; + + vph_pwr_vreg: vph_pwr_vreg { + compatible = "regulator-fixed"; + status = "ok"; + regulator-name = "vph_pwr"; + regulator-always-on; + }; + + mdss_mdp: qcom,mdss_mdp@1a00000 { + status = "disabled"; + }; +}; + +&sdhc_2 { + status = "disabled"; +}; + +&usb_otg { + interrupts = <0 134 0>,<0 140 0>,<0 136 0>; + interrupt-names = "core_irq", "async_irq", "phy_irq"; + qcom,hsusb-otg-mode = <3>; + qcom,switch-vbus-w-id; + vbus_otg-supply = <&vph_pwr_vreg>; + extcon = <&pm8916_chg>; +}; + +&external_image_mem { + reg = <0x0 0x87a00000 0x0 0x0600000>; +}; + +&modem_adsp_mem { + reg = <0x0 0x88000000 0x0 0x01e00000>; +}; + +&peripheral_mem { + reg = <0x0 0x89e00000 0x0 0x0700000>; +}; + +&pm8916_chg { + status = "ok"; +}; + +&pm8916_bms { + status = "ok"; +}; -- GitLab From 6b649f5b31ad30a9b99f96a19ca7440c811795f4 Mon Sep 17 00:00:00 2001 From: Tim Jiang Date: Tue, 8 May 2018 13:52:17 +0800 Subject: [PATCH 1694/1834] ARM: dts: msm: Enable QCA9379 bluetooth device for apq8009 Enable blsp1_uart2_hs which provide communication between QCA9379 BT and HOST. BT enable is controlled through msm gpio 47. So, add device node for it. Change-Id: I8d59e96e14167baaaf6310c24500e552d2c1d00c Signed-off-by: Tim Jiang --- arch/arm64/boot/dts/qcom/apq8009-dragon.dts | 9 +++++++++ arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts index 6b3aea071ea6..12a4363c3115 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-dragon.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-dragon.dts @@ -66,6 +66,11 @@ mdss_mdp: qcom,mdss_mdp@1a00000 { status = "disabled"; }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; }; &sdhc_2 { @@ -133,3 +138,7 @@ &pm8916_bms { status = "ok"; }; + +&blsp1_uart2_hs { + status = "ok"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts index c9808dc4e571..72486b208141 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts @@ -66,6 +66,11 @@ mdss_mdp: qcom,mdss_mdp@1a00000 { status = "disabled"; }; + + bluetooth: bt_qca9379 { + compatible = "qca,qca9379"; + qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ + }; }; &sdhc_2 { @@ -100,3 +105,7 @@ &pm8916_bms { status = "ok"; }; + +&blsp1_uart2_hs { + status = "ok"; +}; -- GitLab From 157a69bf6136ea79c4fee856efea8fd6d209cb14 Mon Sep 17 00:00:00 2001 From: Xiaojun Sang Date: Wed, 9 May 2018 17:10:33 +0800 Subject: [PATCH 1695/1834] ARM: dts: msm: Remove quin i2s GPIO on SDM439 QRD GPIOs 85-88 are no longer assigned for SDM 439 QRD. Hence remove GPIO configuration for quin i2s device. Change-Id: Ibc5b260e93c0040e64aa898696085b1c6909b136 Signed-off-by: Xiaojun Sang --- arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index 18714ce1568c..85b8e5507126 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -51,6 +51,11 @@ qcom,msm-mbhc-hphl-swh = <1>; qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-hs-micbias-type = "external"; + /delete-property/ qcom,quin-mi2s-gpios; +}; + +&cdc_quin_mi2s_gpios { + status = "disabled"; }; &wsa881x_i2c_f { -- GitLab From 09166f4fad3503f43fcff3d78dbfa8629ef49331 Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Mon, 30 Apr 2018 22:38:56 +0530 Subject: [PATCH 1696/1834] ARM: kernel: smp: Clear Pending IPI flag after handling Clear per cpu pending IPI interrupt flag after handing. Change-Id: I1c69212110314d86c5013b6ec990eabe353d779a Signed-off-by: Raghavendra Kakarla --- arch/arm/kernel/smp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index ab509d6cc6ca..a03a99ae7ac6 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -672,6 +672,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs) if ((unsigned)ipinr < NR_IPI) trace_ipi_exit_rcuidle(ipi_types[ipinr]); + + per_cpu(pending_ipi, cpu) = false; set_irq_regs(old_regs); } -- GitLab From ae2b028a2a4e464fd0ad2790365e6e9c4f416e9c Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Wed, 9 May 2018 15:39:39 +0530 Subject: [PATCH 1697/1834] drm/msm/dsi-staging: add support to wait post dsi command rx Some display panel have the requirement of waiting for certain duration before dsi host can read back the response from panel, to a DCS read command. This change adds the support to store the delay required in dsi message structure it self. Change-Id: I82f53d811f82195eb900e4594b01c6e0f23fed53 Signed-off-by: Sandeep Panda --- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 9 +++------ drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 2 +- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 4 +++- include/drm/drm_mipi_dsi.h | 2 ++ 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index c7c640f51a49..667a3b8c39b2 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -1338,9 +1338,6 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, u32 dlen, diff, rlen = msg->rx_len; unsigned char *buff; char cmd; - struct dsi_cmd_desc *of_cmd; - - of_cmd = container_of(msg, struct dsi_cmd_desc, msg); if (msg->rx_len <= 2) { short_resp = true; @@ -1378,9 +1375,9 @@ static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl, * wait before reading rdbk_data register, if any delay is * required after sending the read command. */ - if (of_cmd && of_cmd->post_wait_ms) - usleep_range(of_cmd->post_wait_ms * 1000, - ((of_cmd->post_wait_ms * 1000) + 10)); + if (msg->wait_ms) + usleep_range(msg->wait_ms * 1000, + ((msg->wait_ms * 1000) + 10)); dlen = dsi_ctrl->hw.ops.get_cmd_read_data(&dsi_ctrl->hw, buff, total_bytes_read, diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index adcec15ee219..71c651a2a5a6 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -758,7 +758,7 @@ static int dsi_display_cmd_prepare(const char *cmd_buf, u32 cmd_buf_len, cmd->msg.channel = cmd_buf[2]; cmd->msg.flags = cmd_buf[3]; cmd->msg.ctrl = 0; - cmd->post_wait_ms = cmd_buf[4]; + cmd->post_wait_ms = cmd->msg.wait_ms = cmd_buf[4]; cmd->msg.tx_len = ((cmd_buf[5] << 8) | (cmd_buf[6])); if (cmd->msg.tx_len > payload_len) { diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 79df63152ac4..8949d706dc25 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1536,7 +1536,7 @@ static int dsi_panel_create_cmd_packets(const char *data, cmd[i].msg.channel = data[2]; cmd[i].msg.flags |= (data[3] == 1 ? MIPI_DSI_MSG_REQ_ACK : 0); cmd[i].msg.ctrl = 0; - cmd[i].post_wait_ms = data[4]; + cmd[i].post_wait_ms = cmd[i].msg.wait_ms = data[4]; cmd[i].msg.tx_len = ((data[5] << 8) | (data[6])); size = cmd[i].msg.tx_len * sizeof(u8); @@ -3511,6 +3511,7 @@ static int dsi_panel_roi_prepare_dcs_cmds(struct dsi_panel_cmd_set *set, set->cmds[0].msg.tx_buf = caset; set->cmds[0].msg.rx_len = 0; set->cmds[0].msg.rx_buf = 0; + set->cmds[0].msg.wait_ms = 0; set->cmds[0].last_command = 0; set->cmds[0].post_wait_ms = 0; @@ -3522,6 +3523,7 @@ static int dsi_panel_roi_prepare_dcs_cmds(struct dsi_panel_cmd_set *set, set->cmds[1].msg.tx_buf = paset; set->cmds[1].msg.rx_len = 0; set->cmds[1].msg.rx_buf = 0; + set->cmds[1].msg.wait_ms = 0; set->cmds[1].last_command = 1; set->cmds[1].post_wait_ms = 0; diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 3c2024d8e6f5..328f232f33ee 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -32,6 +32,7 @@ struct mipi_dsi_device; * @type: payload data type * @flags: flags controlling this message transmission * @ctrl: ctrl index to transmit on + * @wait_ms: duration in ms to wait after message transmission * @tx_len: length of @tx_buf * @tx_buf: data to be written * @rx_len: length of @rx_buf @@ -42,6 +43,7 @@ struct mipi_dsi_msg { u8 type; u16 flags; u32 ctrl; + u32 wait_ms; size_t tx_len; const void *tx_buf; -- GitLab From ee679cb66d6f3f3071d8b5b950971d5420a43e9b Mon Sep 17 00:00:00 2001 From: Vatsal Bucha Date: Thu, 3 May 2018 19:29:30 +0530 Subject: [PATCH 1698/1834] perf_defconfig: sdm670: Enable compilation of regmap irq for sdm670 REGMAP IRQ is used in SDM670 AQT codec. Enable compilation so as to resolve any unknown symbol errors. CRs-Fixed: 2235767 Change-Id: Ic81da840cd7c26dab3473c4da0c3e1df639c8355 Signed-off-by: Vatsal Bucha --- arch/arm64/configs/sdm670-perf_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 93f76211efe8..a411a887439c 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -238,6 +238,7 @@ CONFIG_NFC_NQ=y CONFIG_IPC_ROUTER=y CONFIG_IPC_ROUTER_SECURITY=y CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_AQT_REGMAP=y CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y CONFIG_DMA_CMA=y CONFIG_ZRAM=y -- GitLab From 4455d289812b48100896214065d487a529443e08 Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 27 Apr 2018 11:01:20 +0530 Subject: [PATCH 1699/1834] clk: qcom: Retrieve pre_div from freq_tbl for shared RCG There could be cases where a simultaneous clk_disable and clk_set_rate on the same rcg could result in a wrong recalc rate. So for shared rcgs get the pre_div value based on the current frequency from the frequency table. Change-Id: Ia5730e43965b2d0ba19da05fca47825514f98865 Signed-off-by: Taniya Das --- drivers/clk/qcom/clk-rcg2.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 35bcf5aec326..00989a8cca5e 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -246,12 +246,14 @@ static unsigned long clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_rcg2 *rcg = to_clk_rcg2(hw); + const struct freq_tbl *f_curr; u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask; if (rcg->flags & DFS_ENABLE_RCG) return rcg->current_freq; - if (rcg->enable_safe_config && !clk_hw_is_prepared(hw)) { + if (rcg->enable_safe_config && (!clk_hw_is_prepared(hw) + || !clk_hw_is_enabled(hw))) { if (!rcg->current_freq) rcg->current_freq = cxo_f.freq; return rcg->current_freq; @@ -271,9 +273,17 @@ clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) mode >>= CFG_MODE_SHIFT; } - mask = BIT(rcg->hid_width) - 1; - hid_div = cfg >> CFG_SRC_DIV_SHIFT; - hid_div &= mask; + if (rcg->enable_safe_config) { + f_curr = qcom_find_freq(rcg->freq_tbl, rcg->current_freq); + if (!f_curr) + return -EINVAL; + + hid_div = f_curr->pre_div; + } else { + mask = BIT(rcg->hid_width) - 1; + hid_div = cfg >> CFG_SRC_DIV_SHIFT; + hid_div &= mask; + } return clk_rcg2_calc_rate(parent_rate, m, n, mode, hid_div); } -- GitLab From 59df5b4a31841cdf847a3a949278ef2352b07b5f Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Wed, 2 May 2018 09:47:04 +0530 Subject: [PATCH 1700/1834] defconfig: Disable config EXT2_FS and EXT3_FS for sdm845 This change disable the unspported fs configs. Change-Id: Ieec98a724ff801df02d3c8b7ba96075b8bf2449e Signed-off-by: Ankit Jain --- arch/arm64/configs/sdm845-perf_defconfig | 4 +--- arch/arm64/configs/sdm845_defconfig | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm64/configs/sdm845-perf_defconfig b/arch/arm64/configs/sdm845-perf_defconfig index 55f45ae0b3b5..a1fd1dc9eaf7 100644 --- a/arch/arm64/configs/sdm845-perf_defconfig +++ b/arch/arm64/configs/sdm845-perf_defconfig @@ -568,9 +568,7 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_F2FS_FS=y diff --git a/arch/arm64/configs/sdm845_defconfig b/arch/arm64/configs/sdm845_defconfig index b890deede1b9..04608cdb2067 100644 --- a/arch/arm64/configs/sdm845_defconfig +++ b/arch/arm64/configs/sdm845_defconfig @@ -589,9 +589,7 @@ CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y CONFIG_SENSORS_SSC=y CONFIG_MSM_TZ_LOG=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT3_FS=y +CONFIG_EXT4_FS=y CONFIG_EXT4_FS_SECURITY=y CONFIG_EXT4_ENCRYPTION=y CONFIG_F2FS_FS=y -- GitLab From 5fd7bfc4922e92102fc11b202c5eba68c19c2c30 Mon Sep 17 00:00:00 2001 From: Animesh Kishore Date: Wed, 9 May 2018 17:54:16 +0530 Subject: [PATCH 1701/1834] fbdev: msm: Fix systrace markers Trace event for systrace annotations should be tracing_mark_write. Change-Id: I24d1995c9b9b6cd16690b18e2f5c5f0ee1d64111 Signed-off-by: Animesh Kishore --- drivers/video/fbdev/msm/mdss_debug.h | 4 ++-- drivers/video/fbdev/msm/mdss_mdp_trace.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_debug.h b/drivers/video/fbdev/msm/mdss_debug.h index 0d482c033d0f..828d326faf7d 100644 --- a/drivers/video/fbdev/msm/mdss_debug.h +++ b/drivers/video/fbdev/msm/mdss_debug.h @@ -78,8 +78,8 @@ struct vbif_debug_bus { #define MDSS_XLOG_IOMMU(...) mdss_xlog(__func__, __LINE__, MDSS_XLOG_IOMMU, \ ##__VA_ARGS__, DATA_LIMITER) -#define ATRACE_END(name) trace_mdss_mark_write(current->tgid, name, 0) -#define ATRACE_BEGIN(name) trace_mdss_mark_write(current->tgid, name, 1) +#define ATRACE_END(name) trace_tracing_mark_write(current->tgid, name, 0) +#define ATRACE_BEGIN(name) trace_tracing_mark_write(current->tgid, name, 1) #define ATRACE_FUNC() ATRACE_BEGIN(__func__) #define ATRACE_INT(name, value) \ diff --git a/drivers/video/fbdev/msm/mdss_mdp_trace.h b/drivers/video/fbdev/msm/mdss_mdp_trace.h index f8a6baf79dd7..c100e9cc8c18 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_trace.h +++ b/drivers/video/fbdev/msm/mdss_mdp_trace.h @@ -376,7 +376,7 @@ TRACE_EVENT(mdp_cmd_wait_pingpong, __entry->kickoff_cnt) ); -TRACE_EVENT(mdss_mark_write, +TRACE_EVENT(tracing_mark_write, TP_PROTO(int pid, const char *name, bool trace_begin), TP_ARGS(pid, name, trace_begin), TP_STRUCT__entry( -- GitLab From cc3789e19860db2bad1d5dce5a8ac77590b3a80b Mon Sep 17 00:00:00 2001 From: Vishnuvardhan Prodduturi Date: Wed, 9 May 2018 17:58:00 +0530 Subject: [PATCH 1702/1834] msm: mdss: fix calls to usleep_range function in mdss driver usleep_range is getting called with wrong arguments which in turn is causing the process to go to infinite sleep. This patch fixes all such instances. Change-Id: I1db734fa43db399e3a7b61a08af3477d258d080f Signed-off-by: Vishnuvardhan Prodduturi --- drivers/video/fbdev/msm/dsi_host_v2.c | 4 ++-- drivers/video/fbdev/msm/mdss_dsi_host.c | 4 ++-- drivers/video/fbdev/msm/mdss_dsi_panel.c | 4 ++-- drivers/video/fbdev/msm/mdss_io_util.c | 24 ++++++++++++------------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/video/fbdev/msm/dsi_host_v2.c b/drivers/video/fbdev/msm/dsi_host_v2.c index 33775eca7c71..2cca4691b93f 100644 --- a/drivers/video/fbdev/msm/dsi_host_v2.c +++ b/drivers/video/fbdev/msm/dsi_host_v2.c @@ -753,8 +753,8 @@ static int msm_dsi_cmds_tx(struct mdss_dsi_ctrl_pdata *ctrl, } if (dchdr->wait) - usleep_range(dchdr->wait * 1000, - dchdr->wait * 1000); + usleep_range((dchdr->wait * 1000), + (dchdr->wait * 1000) + 10); mdss_dsi_buf_init(tp); len = 0; diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 7d737b539817..8b19b72af9b5 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -1689,8 +1689,8 @@ static int mdss_dsi_cmds2buf_tx(struct mdss_dsi_ctrl_pdata *ctrl, __func__, cm->payload[0], len); if (!wait || dchdr->wait > VSYNC_PERIOD) - usleep_range(dchdr->wait * 1000, - dchdr->wait * 1000); + usleep_range((dchdr->wait * 1000), + (dchdr->wait * 1000) + 10); mdss_dsi_buf_init(tp); len = 0; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 1688503c72a3..157acf3700ce 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -443,8 +443,8 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) gpio_set_value((ctrl_pdata->rst_gpio), pdata->panel_info.rst_seq[i]); if (pdata->panel_info.rst_seq[++i]) - usleep_range(pinfo->rst_seq[i] * 1000, - pinfo->rst_seq[i] * 1000); + usleep_range((pinfo->rst_seq[i] * 1000), + (pinfo->rst_seq[i] * 1000) + 10); } if (gpio_is_valid(ctrl_pdata->bklt_en_gpio)) { diff --git a/drivers/video/fbdev/msm/mdss_io_util.c b/drivers/video/fbdev/msm/mdss_io_util.c index 311779347e08..2f70ad37e227 100644 --- a/drivers/video/fbdev/msm/mdss_io_util.c +++ b/drivers/video/fbdev/msm/mdss_io_util.c @@ -275,8 +275,8 @@ int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable) } need_sleep = !regulator_is_enabled(in_vreg[i].vreg); if (in_vreg[i].pre_on_sleep && need_sleep) - usleep_range(in_vreg[i].pre_on_sleep * 1000, - in_vreg[i].pre_on_sleep * 1000); + usleep_range((in_vreg[i].pre_on_sleep * 1000), + (in_vreg[i].pre_on_sleep * 1000) + 10); rc = regulator_set_load(in_vreg[i].vreg, in_vreg[i].load[DSS_REG_MODE_ENABLE]); if (rc < 0) { @@ -287,8 +287,8 @@ int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable) } rc = regulator_enable(in_vreg[i].vreg); if (in_vreg[i].post_on_sleep && need_sleep) - usleep_range(in_vreg[i].post_on_sleep * 1000, - in_vreg[i].post_on_sleep * 1000); + usleep_range((in_vreg[i].post_on_sleep * 1000), + (in_vreg[i].post_on_sleep * 1000) + 10); if (rc < 0) { DEV_ERR("%pS->%s: %s enable failed\n", __builtin_return_address(0), __func__, @@ -299,8 +299,8 @@ int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable) } else { for (i = num_vreg-1; i >= 0; i--) { if (in_vreg[i].pre_off_sleep) - usleep_range(in_vreg[i].pre_off_sleep * 1000, - in_vreg[i].pre_off_sleep * 1000); + usleep_range((in_vreg[i].pre_off_sleep * 1000), + (in_vreg[i].pre_off_sleep * 1000) + 10); regulator_set_load(in_vreg[i].vreg, in_vreg[i].load[DSS_REG_MODE_DISABLE]); @@ -308,8 +308,8 @@ int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable) regulator_disable(in_vreg[i].vreg); if (in_vreg[i].post_off_sleep) - usleep_range(in_vreg[i].post_off_sleep * 1000, - in_vreg[i].post_off_sleep * 1000); + usleep_range((in_vreg[i].post_off_sleep * 1000), + (in_vreg[i].post_off_sleep * 1000) + 10); } } return rc; @@ -321,14 +321,14 @@ int msm_mdss_enable_vreg(struct mdss_vreg *in_vreg, int num_vreg, int enable) vreg_set_opt_mode_fail: for (i--; i >= 0; i--) { if (in_vreg[i].pre_off_sleep) - usleep_range(in_vreg[i].pre_off_sleep * 1000, - in_vreg[i].pre_off_sleep * 1000); + usleep_range((in_vreg[i].pre_off_sleep * 1000), + (in_vreg[i].pre_off_sleep * 1000) + 10); regulator_set_load(in_vreg[i].vreg, in_vreg[i].load[DSS_REG_MODE_DISABLE]); regulator_disable(in_vreg[i].vreg); if (in_vreg[i].post_off_sleep) - usleep_range(in_vreg[i].post_off_sleep * 1000, - in_vreg[i].post_off_sleep * 1000); + usleep_range((in_vreg[i].post_off_sleep * 1000), + (in_vreg[i].post_off_sleep * 1000) + 10); } return rc; -- GitLab From 1d73857127cd7c1546601498b791576db2967b14 Mon Sep 17 00:00:00 2001 From: Ashwanth Goli Date: Wed, 9 May 2018 19:57:01 +0530 Subject: [PATCH 1703/1834] ipv6: remove min MTU check for ipsec tunnels With 749439bfac ipsec dst's that report a MTU less than IPV6_MIN_MTU are broken even for packets that are smaller than IPV6_MIN_MTU. According to rfc2473#section-7.1 if the original IPv6 packet is equal or smaller than the IPv6 minimum link MTU, the tunnel entry-point node encapsulates the original packet, and subsequently fragments the resulting IPv6 tunnel packet into IPv6 fragments that do not exceed the Path MTU to the tunnel exit-point. This patch drops the MTU check for ipsec tunnel destinations. Change-Id: I36152ec99a955e20ded707fd7269ba11b94a9cfc Signed-off-by: Ashwanth Goli --- net/ipv6/ip6_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 55ca65c7d5e5..7e24ced552b2 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1276,7 +1276,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, if (np->frag_size) mtu = np->frag_size; } - if (mtu < IPV6_MIN_MTU) + if (!(rt->dst.flags & DST_XFRM_TUNNEL) && mtu < IPV6_MIN_MTU) return -EINVAL; cork->base.fragsize = mtu; if (dst_allfrag(rt->dst.path)) -- GitLab From 5e42986c8a88550f9cadea0837a3728c5b684edd Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Wed, 28 Feb 2018 15:21:42 +0530 Subject: [PATCH 1704/1834] diag: Update Peripheral boot logging mask based on tool status The patch updates logging mask to peripheral only when mask update is received from the tool during peripheral boot up. Change-Id: I74c88102e79560ee1b9cfecad9536c225fec4f57 Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_masks.c | 14 +++++++++++--- drivers/char/diag/diagchar.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/char/diag/diag_masks.c b/drivers/char/diag/diag_masks.c index b7d56a99684d..c20dd2e12160 100644 --- a/drivers/char/diag/diag_masks.c +++ b/drivers/char/diag/diag_masks.c @@ -2189,9 +2189,12 @@ void diag_send_updates_peripheral(uint8_t peripheral) if (driver->time_sync_enabled) diag_send_time_sync_update(peripheral); mutex_lock(&driver->md_session_lock); - diag_send_msg_mask_update(peripheral, ALL_SSID, ALL_SSID); - diag_send_log_mask_update(peripheral, ALL_EQUIP_ID); - diag_send_event_mask_update(peripheral); + if (driver->set_mask_cmd) { + diag_send_msg_mask_update(peripheral, + ALL_SSID, ALL_SSID); + diag_send_log_mask_update(peripheral, ALL_EQUIP_ID); + diag_send_event_mask_update(peripheral); + } mutex_unlock(&driver->md_session_lock); diag_send_real_time_update(peripheral, driver->real_time_mode[DIAG_LOCAL_PROC]); @@ -2228,6 +2231,7 @@ int diag_process_apps_masks(unsigned char *buf, int len, int pid) break; case DIAG_CMD_OP_SET_LOG_MASK: hdlr = diag_cmd_set_log_mask; + driver->set_mask_cmd = 1; break; case DIAG_CMD_OP_GET_LOG_MASK: hdlr = diag_cmd_get_log_mask; @@ -2247,17 +2251,21 @@ int diag_process_apps_masks(unsigned char *buf, int len, int pid) break; case DIAG_CMD_OP_SET_MSG_MASK: hdlr = diag_cmd_set_msg_mask; + driver->set_mask_cmd = 1; break; case DIAG_CMD_OP_SET_ALL_MSG_MASK: hdlr = diag_cmd_set_all_msg_mask; + driver->set_mask_cmd = 1; break; } } else if (*buf == DIAG_CMD_GET_EVENT_MASK) { hdlr = diag_cmd_get_event_mask; } else if (*buf == DIAG_CMD_SET_EVENT_MASK) { hdlr = diag_cmd_update_event_mask; + driver->set_mask_cmd = 1; } else if (*buf == DIAG_CMD_EVENT_TOGGLE) { hdlr = diag_cmd_toggle_events; + driver->set_mask_cmd = 1; } if (hdlr) diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index fc1877674058..9bbfb82fec13 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -673,6 +673,7 @@ struct diagchar_dev { struct diag_mask_info *log_mask; struct diag_mask_info *event_mask; struct diag_mask_info *build_time_mask; + uint8_t set_mask_cmd; uint8_t msg_mask_tbl_count; uint8_t bt_msg_mask_tbl_count; uint16_t event_mask_size; -- GitLab From 435bad322c53191ec22e9bbcb1758d287a1b8b8f Mon Sep 17 00:00:00 2001 From: Venkateswara Rao Tadikonda Date: Wed, 9 May 2018 16:21:34 +0530 Subject: [PATCH 1705/1834] msm: kgsl: Update GPU idleness check when RB is empty GPU is considered to be idle when ring buffer is idle in current design. But ring buffer empty will not alone determine GPU idleness. RBBM status also should be checked along with ring buffer status to determine GPU idleness. Change-Id: I165edfb7f10144612525f240817fd77ac5da6efb Signed-off-by: Venkateswara Rao Tadikonda --- drivers/gpu/msm/adreno_dispatch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index b8c282db189a..a634d9871992 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -208,8 +208,8 @@ static inline bool _isidle(struct adreno_device *adreno_dev) if (!kgsl_state_is_awake(KGSL_DEVICE(adreno_dev))) goto ret; - if (adreno_rb_empty(adreno_dev->cur_rb)) - goto ret; + if (!adreno_rb_empty(adreno_dev->cur_rb)) + return false; /* only check rbbm status to determine if GPU is idle */ adreno_readreg(adreno_dev, ADRENO_REG_RBBM_STATUS, ®_rbbm_status); -- GitLab From 1616269d26d2604e4f01e3d150273420037896a0 Mon Sep 17 00:00:00 2001 From: Ping Li Date: Tue, 8 May 2018 14:13:46 -0700 Subject: [PATCH 1706/1834] drm/msm/sde: Update dither programming for dual-pipe merge modes For DUALPIPE_DSCMERGE, DUALPIPE_3DMERGE and DUALPIPE_3DMERGE_DSC topologies, dither needs to be programmed on all ping-pong buffers used in dual pipe case. Change-Id: I9894a722a52e1b3182cc402db3796a173a07a3c2 Signed-off-by: Ping Li --- drivers/gpu/drm/msm/sde/sde_encoder.c | 30 +++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index bea66931f967..589fa6803ec5 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -80,6 +80,11 @@ /* Maximum number of VSYNC wait attempts for RSC state transition */ #define MAX_RSC_WAIT 5 +#define TOPOLOGY_DUALPIPE_MERGE_MODE(x) \ + (((x) == SDE_RM_TOPOLOGY_DUALPIPE_DSCMERGE) || \ + ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE) || \ + ((x) == SDE_RM_TOPOLOGY_DUALPIPE_3DMERGE_DSC)) + /** * enum sde_enc_rc_events - events for resource control state machine * @SDE_ENC_RC_EVENT_KICKOFF: @@ -3402,13 +3407,14 @@ void sde_encoder_trigger_kickoff_pending(struct drm_encoder *drm_enc) static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) { void *dither_cfg; - int ret = 0, rc; + int ret = 0, rc, i = 0; size_t len = 0; enum sde_rm_topology_name topology; struct drm_encoder *drm_enc; struct msm_mode_info mode_info; struct msm_display_dsc_info *dsc = NULL; struct sde_encoder_virt *sde_enc; + struct sde_hw_pingpong *hw_pp; if (!phys || !phys->connector || !phys->hw_pp || !phys->hw_pp->ops.setup_dither || !phys->parent) @@ -3431,12 +3437,24 @@ static void _sde_encoder_setup_dither(struct sde_encoder_phys *phys) /* disable dither for 10 bpp or 10bpc dsc config */ if (dsc->bpp == 10 || dsc->bpc == 10) { phys->hw_pp->ops.setup_dither(phys->hw_pp, NULL, 0); + return; + } + + ret = sde_connector_get_dither_cfg(phys->connector, + phys->connector->state, &dither_cfg, &len); + if (ret) + return; + + if (TOPOLOGY_DUALPIPE_MERGE_MODE(topology)) { + for (i = 0; i < MAX_CHANNELS_PER_ENC; i++) { + hw_pp = sde_enc->hw_pp[i]; + if (hw_pp) { + phys->hw_pp->ops.setup_dither(hw_pp, dither_cfg, + len); + } + } } else { - ret = sde_connector_get_dither_cfg(phys->connector, - phys->connector->state, &dither_cfg, &len); - if (!ret) - phys->hw_pp->ops.setup_dither(phys->hw_pp, - dither_cfg, len); + phys->hw_pp->ops.setup_dither(phys->hw_pp, dither_cfg, len); } } -- GitLab From f9fc5990360a1d1dee1cd9920b4b57769ab977d7 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 23 Apr 2018 16:52:28 -0700 Subject: [PATCH 1707/1834] ARM: dts: msm: Enable iommu hibernation support for 8953-iot-mtp This platform supports iommu hibernation. Change-Id: I92f657e5f23f27ecefe6cfbd41ca03d07c0db122 Signed-off-by: Patrick Daly --- arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts index 39c76cc4da52..c3d4cc585fc4 100644 --- a/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts +++ b/arch/arm64/boot/dts/qcom/msm8953-iot-mtp.dts @@ -25,3 +25,18 @@ qcom,pmic-id = <0x010016 0x010011 0x0 0x0>; }; +&kgsl_smmu { + qcom,hibernation-support; + qcom,static-ns-cbs = <0>; + /delete-property/ qcom,skip-init; +}; + +&apps_iommu { + qcom,hibernation-support; + qcom,static-ns-cbs = + <15 16 17 18 19>, + <20 21 22 23 24 25 26 27 28 29 30>, + <31>; + + /delete-property/ qcom,skip-init; +}; -- GitLab From cb40b67227ce6dfc2e34e0d9014af2a69b42cbc8 Mon Sep 17 00:00:00 2001 From: Vijay kumar Tumati Date: Thu, 3 May 2018 14:12:06 +0530 Subject: [PATCH 1708/1834] msm: camera: Configure camera csiphy mux select Program mux register based on the mode that csiphy is used in. Change-Id: I4106044ddad5e071dea648516b85500ef102d8da Signed-off-by: Vijay kumar Tumati --- .../msm/camera_v2/sensor/csiphy/msm_csiphy.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c index 72586fa214c3..6fc8e1e87af2 100644 --- a/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c +++ b/drivers/media/platform/msm/camera_v2/sensor/csiphy/msm_csiphy.c @@ -293,10 +293,18 @@ static int msm_csiphy_snps_lane_config( void __iomem *csiphybase; enum snps_csiphy_mode mode = INVALID_MODE; uint32_t value, num_tries, num_lanes, offset; + uint32_t clk_mux_reg = 0; csiphybase = csiphy_dev->base; + if (csiphy_dev->clk_mux_base != NULL) + clk_mux_reg = msm_camera_io_r(csiphy_dev->clk_mux_base); + else { + pr_err("%s: invalid clk_mux_base\n", __func__); + return -EINVAL; + } + /* lane mask usage - * BIT LANE + * BIT LANE * 0(LSB) PHY A data 0 * 1 PHY A data 1 * 2 PHY B data 0 @@ -318,6 +326,9 @@ static int msm_csiphy_snps_lane_config( return -EINVAL; } csiphy_dev->snps_state = CONFIGURED_AGGREGATE_MODE; + clk_mux_reg &= ~0xff; + clk_mux_reg |= csiphy_params->csid_core << 4; + clk_mux_reg |= (uint32_t)csiphy_params->csid_core; } else if (lane_mask == LANE_MASK_PHY_A) { /* PHY A */ /* 2 lane config */ num_lanes = 2; @@ -333,6 +344,8 @@ static int msm_csiphy_snps_lane_config( pr_err("%s: invalid request\n", __func__); return -EINVAL; } + clk_mux_reg &= ~0xf; + clk_mux_reg |= (uint32_t)csiphy_params->csid_core; } else if (lane_mask == LANE_MASK_PHY_B) { /* PHY B */ /* 2 lane config */ num_lanes = 2; @@ -348,11 +361,17 @@ static int msm_csiphy_snps_lane_config( pr_err("%s: invalid request\n", __func__); return -EINVAL; } + clk_mux_reg &= ~0xf0; + clk_mux_reg |= csiphy_params->csid_core << 4; } else { /* None of available configurations */ pr_err("%s: invalid configuration requested\n", __func__); return -EINVAL; } + msm_camera_io_w(clk_mux_reg, csiphy_dev->clk_mux_base); + /* ensure write is done */ + mb(); + if (mode == AGGREGATE_MODE || mode == TWO_LANE_PHY_A) { ret = msm_csiphy_snps_2_lane_config(csiphy_dev, csiphy_params, TWO_LANE_PHY_A, num_lanes); -- GitLab From 2e6a64e8877af90ffcb7ed8940569bfb10b2611a Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Thu, 10 May 2018 11:07:52 +0530 Subject: [PATCH 1709/1834] ARM: dts: msm: Enable APC CPR closed-loop for sdm439 Enable APC CPR closed-loop operation and also apply static voltage adjustments as per the sdm439 voltage plan. Change-Id: I760e1a0051105ba460d620ca42d4acd4b68d7669 Signed-off-by: Tirupathi Reddy --- arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi index f325925cdfa3..a8b8291013de 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi @@ -468,5 +468,19 @@ qcom,cpr-quot-adjust-scaling-factor-max = <0 1400 1400>; qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>; qcom,cpr-scaled-init-voltage-as-ceiling; + + qcom,cpr-fuse-version-map = + /* */ + <(-1) (-1) ( 0) (-1) (-1) (-1)>, + <(-1) (-1) (-1) (-1) (-1) (-1)>; + + qcom,cpr-quotient-adjustment = + <66 77 66>, /* SVSP_30mV, NOM_35mV, TUR_30mV */ + <0 0 0>; + + qcom,cpr-voltage-ceiling-override = + <(-1) (-1) 795000 795000 835000 910000 910000>; + + qcom,cpr-enable; }; }; -- GitLab From fbc04ba69d13fddb93b1dd096ea3e762b6141e46 Mon Sep 17 00:00:00 2001 From: Vaishnavi Kommaraju Date: Fri, 16 Mar 2018 18:54:00 +0530 Subject: [PATCH 1710/1834] ARM: dts: msm: External codec audio changes for sdm632 Audio changes to support external codec on sdm632. Add new dbu3 fixed regulator for sdm632 buck supply. Change-Id: I8de8343e63d5b40e462d0c8fc8cadc8ef72ad502 Signed-off-by: Vaishnavi Kommaraju --- .../boot/dts/qcom/sdm632-ext-audio-mtp.dtsi | 105 ++++++++++++++++++ .../dts/qcom/sdm632-ext-codec-mtp-s4.dtsi | 1 + .../arm64/boot/dts/qcom/sdm632-regulator.dtsi | 7 ++ 3 files changed, 113 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi new file mode 100644 index 000000000000..b34e3d8db2ab --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm632-ext-audio-mtp.dtsi @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&int_codec { + status = "disabled"; +}; + +&pmic_analog_codec { + status = "disabled"; +}; + +&wsa881x_i2c_f { + status = "disabled"; +}; + +&wsa881x_i2c_45 { + status = "disabled"; +}; + +&cdc_pri_mi2s_gpios { + status = "disabled"; +}; + +&wsa881x_analog_vi_gpio { + status = "disabled"; +}; + +&wsa881x_analog_clk_gpio { + status = "disabled"; +}; + +&wsa881x_analog_reset_gpio { + status = "disabled"; +}; + +&cdc_comp_gpios { + status = "disabled"; +}; + +&slim_msm { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; + +&wcd9335 { + status = "okay"; + + dc-vdd-buck-supply = <&dbu3>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&dbu3>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <150000>; + + cdc-vdd-tx-h-supply = <&dbu3>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&dbu3>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vdd-px-supply = <&dbu3>; + qcom,cdc-vdd-px-voltage = <1800000 1800000>; + qcom,cdc-vdd-px-current = <10000>; +}; + +&cdc_us_euro_sw { + status = "okay"; +}; + +&cdc_quin_mi2s_gpios { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + qcom,model = "msm8953-tasha-snd-card"; + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi index d8326ff5d7c4..fd1eb3dd9b5e 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4.dtsi @@ -12,4 +12,5 @@ */ #include "sdm450-pmi632-mtp-s3.dtsi" +#include "sdm632-ext-audio-mtp.dtsi" diff --git a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi index a7580e07fd76..93ccc07f51b7 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi @@ -432,4 +432,11 @@ mem-acc-supply = <&gfx_mem_acc>; qcom,mem-acc-corner-map = <1 1 1 2 2 2 2>; }; + + dbu3: dbu3 { + compatible = "regulator-fixed"; + regulator-name = "dbu3"; + startup-delay-us = <0>; + enable-active-high; + }; }; -- GitLab From 407046b378f13e14055d3f4b9a6fb98e3b289443 Mon Sep 17 00:00:00 2001 From: Ghanim Fodi Date: Wed, 9 May 2018 17:37:23 +0300 Subject: [PATCH 1711/1834] msm: gsi: add support for prefetch escape buffer only GSI 2.0 supports escape buffers only configuration for GSI prefetch. Add this capability and expose it to the client drivers. Change-Id: Id2525fbd62e2b366be809d4866ef324c785a1716 Signed-off-by: Ghanim Fodi --- drivers/platform/msm/gsi/gsi.c | 4 ++++ drivers/platform/msm/gsi/gsi_reg.h | 4 +++- include/linux/msm_gsi.h | 8 +++++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index dc445a0c07f6..e729c563ce19 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1572,6 +1572,10 @@ static void gsi_program_chan_ctx(struct gsi_chan_props *props, unsigned int ee, GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK) | ((props->use_db_eng << GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT) & GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK)); + if (gsi_ctx->per.ver >= GSI_VER_2_0) + val |= ((props->prefetch_mode << + GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT) + & GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK); gsi_writel(val, gsi_ctx->base + GSI_EE_n_GSI_CH_k_QOS_OFFS(props->ch_id, ee)); } diff --git a/drivers/platform/msm/gsi/gsi_reg.h b/drivers/platform/msm/gsi/gsi_reg.h index 7817613ed9f1..add38767877d 100644 --- a/drivers/platform/msm/gsi/gsi_reg.h +++ b/drivers/platform/msm/gsi/gsi_reg.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1124,6 +1124,8 @@ #define GSI_EE_n_GSI_CH_k_QOS_RMSK 0x303 #define GSI_EE_n_GSI_CH_k_QOS_MAXk 30 #define GSI_EE_n_GSI_CH_k_QOS_MAXn 3 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_BMSK 0x400 +#define GSI_EE_n_GSI_CH_k_QOS_USE_ESCAPE_BUF_ONLY_SHFT 0xa #define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_BMSK 0x200 #define GSI_EE_n_GSI_CH_k_QOS_USE_DB_ENG_SHFT 0x9 #define GSI_EE_n_GSI_CH_k_QOS_MAX_PREFETCH_BMSK 0x100 diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index 6e0b439fcdc8..81e7e7527960 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -219,6 +219,11 @@ enum gsi_max_prefetch { GSI_TWO_PREFETCH_SEG = 0x1 }; +enum gsi_prefetch_mode { + GSI_USE_PREFETCH_BUFS = 0x0, + GSI_ESCAPE_BUF_ONLY = 0x1 +}; + enum gsi_chan_evt { GSI_CHAN_EVT_INVALID = 0x0, GSI_CHAN_EVT_SUCCESS = 0x1, @@ -357,6 +362,7 @@ struct gsi_chan_props { enum gsi_chan_use_db_eng use_db_eng; enum gsi_max_prefetch max_prefetch; uint8_t low_weight; + enum gsi_prefetch_mode prefetch_mode; void (*xfer_cb)(struct gsi_chan_xfer_notify *notify); void (*err_cb)(struct gsi_chan_err_notify *notify); void *chan_user_data; -- GitLab From 04c48a9479f568413bf82e37328f7c7f62b602d2 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Thu, 10 May 2018 14:15:45 +0530 Subject: [PATCH 1712/1834] thermal: tsens: Apply scaling to temp read from sensor Thresholds are specified in degrees C, and sensor temperatures are in milli-degrees C. Scale the sensor temperature to degrees C before comparing to the threshold value to check if threshold has been breached. Change-Id: Id2435b9e3d19d7777769ccd412ce8943dec0d1b6 Signed-off-by: Jishnu Prakash --- drivers/thermal/tsens1xxx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/tsens1xxx.c b/drivers/thermal/tsens1xxx.c index d63fcd1e74d2..19e2b5a91b5c 100644 --- a/drivers/thermal/tsens1xxx.c +++ b/drivers/thermal/tsens1xxx.c @@ -517,8 +517,8 @@ static irqreturn_t tsens_irq_thread(int irq, void *data) th_temp = code_to_degc((threshold & TSENS_UPPER_THRESHOLD_MASK) >> TSENS_UPPER_THRESHOLD_SHIFT, - tm->sensor); - if (th_temp > temp) { + (tm->sensor + i)); + if (th_temp > (temp/TSENS_SCALE_MILLIDEG)) { pr_debug("Re-arm high threshold\n"); rc = tsens_tz_activate_trip_type( &tm->sensor[i], @@ -539,8 +539,8 @@ static irqreturn_t tsens_irq_thread(int irq, void *data) tm->tsens_tm_addr + addr_offset)); th_temp = code_to_degc((threshold & TSENS_LOWER_THRESHOLD_MASK), - tm->sensor); - if (th_temp < temp) { + (tm->sensor + i)); + if (th_temp < (temp/TSENS_SCALE_MILLIDEG)) { pr_debug("Re-arm Low threshold\n"); rc = tsens_tz_activate_trip_type( &tm->sensor[i], -- GitLab From cf0babd01a21a2c9fe5d2d56b2f6344e352734ef Mon Sep 17 00:00:00 2001 From: Pavankumar Kondeti Date: Tue, 8 May 2018 14:12:50 +0530 Subject: [PATCH 1713/1834] sched/fair: Fix task placement issue under sched boost conditions When placement boost is active for a task on a big little system, task_fits_max() should return false for any CPU that does not belong to the highest capacity cluster. This is done to limit the CPU search only to the highest capacity cluster. However when highest capacity cluster's cpufreq policy max is trimmed, the task_fits_max() is returning false for all clusters. Due to this the task is placed on the previous CPU which is resulting in suboptimal performance. The problem lies in update_cpu_capacity() where cpu_orig_capacity and max_cpu_capacity.val are updated. These two quantities are out of sync when cpufreq policy max is trimmed. Make cpu_orig_capacity reflect the trimmed policy max and update max_cpu_capacity.val to the highest cpu_orig_capacity among all CPUs. Change-Id: Ib7ebdf2e7dfb5ec4d018dc76325d5dba8b26ad01 Signed-off-by: Pavankumar Kondeti --- kernel/sched/fair.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 65e728c40d5e..f9705b7355a8 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -8797,13 +8797,12 @@ static void update_cpu_capacity(struct sched_domain *sd, int cpu) int max_cap_cpu; unsigned long flags; - capacity = min(capacity, thermal_cap(cpu)); - - cpu_rq(cpu)->cpu_capacity_orig = capacity; - capacity *= arch_scale_max_freq_capacity(sd, cpu); capacity >>= SCHED_CAPACITY_SHIFT; + capacity = min(capacity, thermal_cap(cpu)); + cpu_rq(cpu)->cpu_capacity_orig = capacity; + mcc = &cpu_rq(cpu)->rd->max_cpu_capacity; raw_spin_lock_irqsave(&mcc->lock, flags); -- GitLab From d458eed2b13d66f555a25f1b347a3acf4f3b3aed Mon Sep 17 00:00:00 2001 From: Sriharsha Allenki Date: Thu, 10 May 2018 15:20:21 +0530 Subject: [PATCH 1714/1834] defconfig: Enable Microchip USB to ethernet adapter drivers for QCS605 Enable CONFIG_USB_LAN78XX to support host mode USB to ethernet Micropchip ethernet adapters. Change-Id: I3f83b5e1d770a2c8eddda657c25f0fec207fc01d Signed-off-by: Sriharsha Allenki --- arch/arm64/configs/sdm670-perf_defconfig | 1 + arch/arm64/configs/sdm670_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/sdm670-perf_defconfig b/arch/arm64/configs/sdm670-perf_defconfig index 93f76211efe8..686dad8c2be9 100644 --- a/arch/arm64/configs/sdm670-perf_defconfig +++ b/arch/arm64/configs/sdm670-perf_defconfig @@ -286,6 +286,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_LAN78XX=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y diff --git a/arch/arm64/configs/sdm670_defconfig b/arch/arm64/configs/sdm670_defconfig index 3e8d8650a479..e295330a8fa1 100644 --- a/arch/arm64/configs/sdm670_defconfig +++ b/arch/arm64/configs/sdm670_defconfig @@ -293,6 +293,7 @@ CONFIG_PPPOLAC=y CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_LAN78XX=y CONFIG_USB_USBNET=y CONFIG_WCNSS_MEM_PRE_ALLOC=y CONFIG_CLD_LL_CORE=y -- GitLab From 2a5317b34884e8c73896faf220a08369c4a456de Mon Sep 17 00:00:00 2001 From: Raghavendra Kakarla Date: Thu, 12 Apr 2018 17:06:13 +0530 Subject: [PATCH 1715/1834] ARM: dts: msm: Add LPM prediction parameters for sdm670 Add LPM prediction parameters which are use by the lpm prediction algorithm to predict next cpu low power mode. Change-Id: I3aa49b3e493197f2dcf6108e87b872740bfcaa78 Signed-off-by: Raghavendra Kakarla --- arch/arm64/boot/dts/qcom/sdm670-pm.dtsi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi index bdcd039c145f..8ed821affe94 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-pm.dtsi @@ -134,7 +134,9 @@ #size-cells = <0>; qcom,psci-mode-shift = <0>; qcom,psci-mode-mask = <0xf>; - qcom,disable-prediction; + qcom,ref-stddev = <100>; + qcom,tmr-add = <100>; + qcom,ref-premature-cnt = <3>; qcom,cpu = <&CPU6 &CPU7>; qcom,pm-cpu-level@0 { /* C1 */ -- GitLab From f978605c817b81d17aa716af12aca3b26e42fbc8 Mon Sep 17 00:00:00 2001 From: Atul Raut Date: Sun, 29 Jan 2017 21:20:05 -0800 Subject: [PATCH 1716/1834] arm/arm64: fix build when !CONFIG_DMA_CMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit if !CONFIG_DMA_CMA throws error implicit declaration of function ‘dma_contiguous_early_fixup’ in routine drivers/base/dma-removed.c:removed_dma_setup which has no dependency over CONFIG_DMA_CMA. Fix by removing dependency of CONFIG_DMA_CMA flag for function dma_contiguous_early_fixup Change-Id: Ife6d0399b7ae61d1781212a1ae7525378fb920fc Signed-off-by: Atul Raut [vinmenon@codeaurora.org: fix copyright, commit subject] Signed-off-by: Vinayak Menon --- arch/arm/include/asm/dma-contiguous.h | 15 +++++++++++++-- arch/arm64/include/asm/dma-contiguous.h | 5 +---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/dma-contiguous.h b/arch/arm/include/asm/dma-contiguous.h index 4f8e9e5514b1..2dbb8c668e61 100644 --- a/arch/arm/include/asm/dma-contiguous.h +++ b/arch/arm/include/asm/dma-contiguous.h @@ -1,14 +1,25 @@ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + #ifndef ASMARM_DMA_CONTIGUOUS_H #define ASMARM_DMA_CONTIGUOUS_H #ifdef __KERNEL__ -#ifdef CONFIG_DMA_CMA #include void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size); -#endif #endif #endif diff --git a/arch/arm64/include/asm/dma-contiguous.h b/arch/arm64/include/asm/dma-contiguous.h index f7e2c32ff928..50f70a8aac94 100644 --- a/arch/arm64/include/asm/dma-contiguous.h +++ b/arch/arm64/include/asm/dma-contiguous.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013,2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013,2017-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,7 +15,6 @@ #define _ASM_DMA_CONTIGUOUS_H #ifdef __KERNEL__ -#ifdef CONFIG_DMA_CMA #include @@ -23,5 +22,3 @@ void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size); #endif #endif - -#endif -- GitLab From a3e1503e693b451e0887f824bd621135b816fe1e Mon Sep 17 00:00:00 2001 From: Yue Ma Date: Thu, 15 Feb 2018 15:56:12 -0800 Subject: [PATCH 1717/1834] cnss2: Support unified QMI sequence Unified QMI sequence creates a common sequence that can be used by firmware and host driver among various devices. It will help reduce maintenance effort and enhance scalability. Add the support for it to CNSS2 driver. Change-Id: Ia8b20f185bd9ecc4b7866aa2df62318b981e93f5 Signed-off-by: Yue Ma --- drivers/net/wireless/cnss2/main.c | 1 + drivers/net/wireless/cnss2/main.h | 5 +- drivers/net/wireless/cnss2/pci.c | 83 +-- drivers/net/wireless/cnss2/qmi.c | 129 +++-- .../cnss2/wlan_firmware_service_v01.c | 544 +++++++++++++++--- .../cnss2/wlan_firmware_service_v01.h | 107 +++- 6 files changed, 699 insertions(+), 170 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index 4c4c761ae6d3..e4efb98aec57 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -1675,6 +1675,7 @@ static int cnss_cold_boot_cal_start_hdlr(struct cnss_plat_data *plat_priv) static int cnss_cold_boot_cal_done_hdlr(struct cnss_plat_data *plat_priv) { + plat_priv->cal_done = true; cnss_wlfw_wlan_mode_send_sync(plat_priv, QMI_WLFW_OFF_V01); cnss_shutdown(plat_priv); clear_bit(CNSS_COLD_BOOT_CAL, &plat_priv->driver_state); diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index c11b2061d93c..b62c01446945 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -107,6 +107,7 @@ struct cnss_fw_mem { void *va; phys_addr_t pa; bool valid; + u32 type; }; enum cnss_fw_dump_type { @@ -198,7 +199,8 @@ struct cnss_plat_data { struct wlfw_rf_board_info_s_v01 board_info; struct wlfw_soc_info_s_v01 soc_info; struct wlfw_fw_version_info_s_v01 fw_version_info; - struct cnss_fw_mem fw_mem; + u32 fw_mem_seg_len; + struct cnss_fw_mem fw_mem[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; struct cnss_fw_mem m3_mem; struct cnss_pin_connect_result pin_result; struct dentry *root_dentry; @@ -210,6 +212,7 @@ struct cnss_plat_data { u32 diag_reg_read_mem_type; u32 diag_reg_read_len; u8 *diag_reg_read_buf; + bool cal_done; }; void *cnss_bus_dev_to_bus_priv(struct device *dev); diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index 9d1fbf9a5e88..4726750a371d 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -732,18 +732,21 @@ int cnss_pm_request_resume(struct cnss_pci_data *pci_priv) int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; - struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem; - - if (!fw_mem->va && fw_mem->size) { - fw_mem->va = dma_alloc_coherent(&pci_priv->pci_dev->dev, - fw_mem->size, &fw_mem->pa, - GFP_KERNEL); - if (!fw_mem->va) { - cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx\n", - fw_mem->size); - fw_mem->size = 0; - - return -ENOMEM; + struct cnss_fw_mem *fw_mem = plat_priv->fw_mem; + int i; + + for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { + if (!fw_mem[i].va && fw_mem[i].size) { + fw_mem[i].va = + dma_alloc_coherent(&pci_priv->pci_dev->dev, + fw_mem[i].size, + &fw_mem[i].pa, GFP_KERNEL); + if (!fw_mem[i].va) { + cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n", + fw_mem[i].size, fw_mem[i].type); + + return -ENOMEM; + } } } @@ -753,17 +756,25 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv) static void cnss_pci_free_fw_mem(struct cnss_pci_data *pci_priv) { struct cnss_plat_data *plat_priv = pci_priv->plat_priv; - struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem; - - if (fw_mem->va && fw_mem->size) { - cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n", - fw_mem->va, &fw_mem->pa, fw_mem->size); - dma_free_coherent(&pci_priv->pci_dev->dev, fw_mem->size, - fw_mem->va, fw_mem->pa); - fw_mem->va = NULL; - fw_mem->pa = 0; - fw_mem->size = 0; + struct cnss_fw_mem *fw_mem = plat_priv->fw_mem; + int i; + + for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { + if (fw_mem[i].va && fw_mem[i].size) { + cnss_pr_dbg("Freeing memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n", + fw_mem[i].va, &fw_mem[i].pa, + fw_mem[i].size, fw_mem[i].type); + dma_free_coherent(&pci_priv->pci_dev->dev, + fw_mem[i].size, fw_mem[i].va, + fw_mem[i].pa); + fw_mem[i].va = NULL; + fw_mem[i].pa = 0; + fw_mem[i].size = 0; + fw_mem[i].type = 0; + } } + + plat_priv->fw_mem_seg_len = 0; } int cnss_pci_load_m3(struct cnss_pci_data *pci_priv) @@ -1107,7 +1118,7 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic) struct cnss_dump_seg *dump_seg = plat_priv->ramdump_info_v2.dump_data_vaddr; struct image_info *fw_image, *rddm_image; - struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem; + struct cnss_fw_mem *fw_mem = plat_priv->fw_mem; int ret, i; ret = mhi_download_rddm_img(pci_priv->mhi_ctrl, in_panic); @@ -1152,18 +1163,20 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic) dump_data->nentries += rddm_image->entries; - if (fw_mem->pa && fw_mem->va && fw_mem->size) { - cnss_pr_dbg("Collect remote heap dump segment, nentries 1\n"); - - dump_seg->address = fw_mem->pa; - dump_seg->v_address = fw_mem->va; - dump_seg->size = fw_mem->size; - dump_seg->type = CNSS_FW_REMOTE_HEAP; - cnss_pr_dbg("seg-0: address 0x%lx, v_address %pK, size 0x%lx\n", - dump_seg->address, dump_seg->v_address, - dump_seg->size); - dump_seg++; - dump_data->nentries++; + cnss_pr_dbg("Collect remote heap dump segment\n"); + + for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { + if (fw_mem[i].type == QMI_WLFW_MEM_TYPE_DDR_V01) { + dump_seg->address = fw_mem[i].pa; + dump_seg->v_address = fw_mem[i].va; + dump_seg->size = fw_mem[i].size; + dump_seg->type = CNSS_FW_REMOTE_HEAP; + cnss_pr_dbg("seg-%d: address 0x%lx, v_address %pK, size 0x%lx\n", + i, dump_seg->address, dump_seg->v_address, + dump_seg->size); + dump_seg++; + dump_data->nentries++; + } } if (dump_data->nentries > 0) diff --git a/drivers/net/wireless/cnss2/qmi.c b/drivers/net/wireless/cnss2/qmi.c index f4344aee54ee..b8777c18d252 100644 --- a/drivers/net/wireless/cnss2/qmi.c +++ b/drivers/net/wireless/cnss2/qmi.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -159,10 +159,9 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv) memset(&req, 0, sizeof(req)); memset(&resp, 0, sizeof(resp)); - req.daemon_support_valid = 1; - req.daemon_support = daemon_support; - - cnss_pr_dbg("daemon_support is %d\n", req.daemon_support); + req.num_clients_valid = 1; + req.num_clients = daemon_support ? 2 : 1; + cnss_pr_dbg("Number of clients is %d\n", req.num_clients); req.wake_msi = cnss_get_wake_msi(plat_priv); if (req.wake_msi) { @@ -170,6 +169,19 @@ static int cnss_wlfw_host_cap_send_sync(struct cnss_plat_data *plat_priv) req.wake_msi_valid = 1; } + req.bdf_support_valid = 1; + req.bdf_support = 1; + + req.m3_support_valid = 1; + req.m3_support = 1; + + req.m3_cache_support_valid = 1; + req.m3_cache_support = 1; + + req.cal_done_valid = 1; + req.cal_done = plat_priv->cal_done; + cnss_pr_dbg("Calibration done is %d\n", plat_priv->cal_done); + req_desc.max_msg_len = WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN; req_desc.msg_id = QMI_WLFW_HOST_CAP_REQ_V01; req_desc.ei_array = wlfw_host_cap_req_msg_v01_ei; @@ -221,8 +233,8 @@ static int cnss_wlfw_ind_register_send_sync(struct cnss_plat_data *plat_priv) req.request_mem_enable = 1; req.fw_mem_ready_enable_valid = 1; req.fw_mem_ready_enable = 1; - req.cold_boot_cal_done_enable_valid = 1; - req.cold_boot_cal_done_enable = 1; + req.fw_init_done_enable_valid = 1; + req.fw_init_done_enable = 1; req.pin_connect_result_enable_valid = 1; req.pin_connect_result_enable = 1; @@ -260,27 +272,48 @@ static int cnss_wlfw_request_mem_ind_hdlr(struct cnss_plat_data *plat_priv, void *msg, unsigned int msg_len) { struct msg_desc ind_desc; - struct wlfw_request_mem_ind_msg_v01 ind_msg; - struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem; - int ret = 0; + struct wlfw_request_mem_ind_msg_v01 *ind_msg; + int ret = 0, i; + + ind_msg = kzalloc(sizeof(*ind_msg), GFP_KERNEL); + if (!ind_msg) + return -ENOMEM; ind_desc.msg_id = QMI_WLFW_REQUEST_MEM_IND_V01; ind_desc.max_msg_len = WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN; ind_desc.ei_array = wlfw_request_mem_ind_msg_v01_ei; - ret = qmi_kernel_decode(&ind_desc, &ind_msg, msg, msg_len); + ret = qmi_kernel_decode(&ind_desc, ind_msg, msg, msg_len); if (ret < 0) { cnss_pr_err("Failed to decode request memory indication, msg_len: %u, err = %d\n", ret, msg_len); - return ret; + goto out; } - fw_mem->size = ind_msg.size; + if (ind_msg->mem_seg_len == 0 || + ind_msg->mem_seg_len > QMI_WLFW_MAX_NUM_MEM_SEG_V01) { + cnss_pr_err("Invalid memory segment length: %u\n", + ind_msg->mem_seg_len); + ret = -EINVAL; + goto out; + } + + cnss_pr_dbg("FW memory segment count is %u\n", ind_msg->mem_seg_len); + plat_priv->fw_mem_seg_len = ind_msg->mem_seg_len; + for (i = 0; i < plat_priv->fw_mem_seg_len; i++) { + plat_priv->fw_mem[i].type = ind_msg->mem_seg[i].type; + plat_priv->fw_mem[i].size = ind_msg->mem_seg[i].size; + } cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_REQUEST_MEM, 0, NULL); + kfree(ind_msg); return 0; + +out: + kfree(ind_msg); + return ret; } static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv, @@ -317,29 +350,46 @@ static int cnss_qmi_pin_result_ind_hdlr(struct cnss_plat_data *plat_priv, int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv) { - struct wlfw_respond_mem_req_msg_v01 req; - struct wlfw_respond_mem_resp_msg_v01 resp; + struct wlfw_respond_mem_req_msg_v01 *req; + struct wlfw_respond_mem_resp_msg_v01 *resp; struct msg_desc req_desc, resp_desc; - struct cnss_fw_mem *fw_mem = &plat_priv->fw_mem; - int ret = 0; + struct cnss_fw_mem *fw_mem = plat_priv->fw_mem; + int ret = 0, i; cnss_pr_dbg("Sending respond memory message, state: 0x%lx\n", plat_priv->driver_state); - if (!fw_mem->pa || !fw_mem->size) { - cnss_pr_err("Memory for FW is not available!\n"); - ret = -ENOMEM; - goto out; - } + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + resp = kzalloc(sizeof(*resp), GFP_KERNEL); + if (!resp) + return -ENOMEM; - cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx\n", - fw_mem->va, &fw_mem->pa, fw_mem->size); + req->mem_seg_len = plat_priv->fw_mem_seg_len; + for (i = 0; i < req->mem_seg_len; i++) { + if (!fw_mem[i].pa || !fw_mem[i].size) { + if (fw_mem[i].type == 0) { + cnss_pr_err("Invalid memory for FW type, segment = %d\n", + i); + ret = -EINVAL; + goto out; + } + cnss_pr_err("Memory for FW is not available for type: %u\n", + fw_mem[i].type); + ret = -ENOMEM; + goto out; + } - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); + cnss_pr_dbg("Memory for FW, va: 0x%pK, pa: %pa, size: 0x%zx, type: %u\n", + fw_mem[i].va, &fw_mem[i].pa, + fw_mem[i].size, fw_mem[i].type); - req.addr = fw_mem->pa; - req.size = fw_mem->size; + req->mem_seg[i].addr = fw_mem[i].pa; + req->mem_seg[i].size = fw_mem[i].size; + req->mem_seg[i].type = fw_mem[i].type; + } req_desc.max_msg_len = WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN; req_desc.msg_id = QMI_WLFW_RESPOND_MEM_REQ_V01; @@ -349,8 +399,8 @@ int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv) resp_desc.msg_id = QMI_WLFW_RESPOND_MEM_RESP_V01; resp_desc.ei_array = wlfw_respond_mem_resp_msg_v01_ei; - ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, &req, - sizeof(req), &resp_desc, &resp, sizeof(resp), + ret = qmi_send_req_wait(plat_priv->qmi_wlfw_clnt, &req_desc, req, + sizeof(*req), &resp_desc, resp, sizeof(*resp), QMI_WLFW_TIMEOUT_MS); if (ret < 0) { cnss_pr_err("Failed to send respond memory request, err = %d\n", @@ -358,16 +408,21 @@ int cnss_wlfw_respond_mem_send_sync(struct cnss_plat_data *plat_priv) goto out; } - if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { cnss_pr_err("Respond memory request failed, result: %d, err: %d\n", - resp.resp.result, resp.resp.error); - ret = resp.resp.result; + resp->resp.result, resp->resp.error); + ret = resp->resp.result; goto out; } + kfree(req); + kfree(resp); return 0; + out: CNSS_ASSERT(0); + kfree(req); + kfree(resp); return ret; } @@ -908,12 +963,12 @@ static void cnss_wlfw_clnt_ind(struct qmi_handle *handle, CNSS_DRIVER_EVENT_FW_MEM_READY, 0, NULL); break; - case QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01: + case QMI_WLFW_FW_READY_IND_V01: cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_COLD_BOOT_CAL_DONE, 0, NULL); break; - case QMI_WLFW_FW_READY_IND_V01: + case QMI_WLFW_FW_INIT_DONE_IND_V01: cnss_driver_event_post(plat_priv, CNSS_DRIVER_EVENT_FW_READY, 0, NULL); @@ -974,11 +1029,11 @@ int cnss_wlfw_server_arrive(struct cnss_plat_data *plat_priv) cnss_pr_info("QMI WLFW service connected, state: 0x%lx\n", plat_priv->driver_state); - ret = cnss_wlfw_host_cap_send_sync(plat_priv); + ret = cnss_wlfw_ind_register_send_sync(plat_priv); if (ret < 0) goto out; - ret = cnss_wlfw_ind_register_send_sync(plat_priv); + ret = cnss_wlfw_host_cap_send_sync(plat_priv); if (ret < 0) goto out; diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c index 7d6a771bc0d5..bbf707b869bd 100644 --- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c +++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -62,7 +62,7 @@ static struct elem_info wlfw_ce_tgt_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -97,7 +97,7 @@ static struct elem_info wlfw_ce_svc_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -123,7 +123,7 @@ static struct elem_info wlfw_shadow_reg_cfg_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -140,7 +140,7 @@ static struct elem_info wlfw_shadow_reg_v2_cfg_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -175,7 +175,131 @@ static struct elem_info wlfw_memory_region_info_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_mem_cfg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + offset), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + size), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_cfg_s_v01, + secure_flag), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_mem_seg_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + size), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_mem_type_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + type), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + mem_cfg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_CFG_V01, + .elem_size = sizeof(struct wlfw_mem_cfg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_s_v01, + mem_cfg), + .ei_array = wlfw_mem_cfg_s_v01_ei, + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct elem_info wlfw_mem_seg_resp_s_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + size), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wlfw_mem_type_enum_v01), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + type), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wlfw_mem_seg_resp_s_v01, + restore), + }, + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -201,7 +325,7 @@ static struct elem_info wlfw_rf_chip_info_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -218,7 +342,7 @@ static struct elem_info wlfw_rf_board_info_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -235,7 +359,7 @@ static struct elem_info wlfw_soc_info_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -261,7 +385,7 @@ static struct elem_info wlfw_fw_version_info_s_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -418,7 +542,7 @@ struct elem_info wlfw_ind_register_req_msg_v01_ei[] = { .is_array = NO_ARRAY, .tlv_type = 0x18, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - cold_boot_cal_done_enable_valid), + fw_init_done_enable_valid), }, { .data_type = QMI_UNSIGNED_1_BYTE, @@ -427,7 +551,7 @@ struct elem_info wlfw_ind_register_req_msg_v01_ei[] = { .is_array = NO_ARRAY, .tlv_type = 0x18, .offset = offsetof(struct wlfw_ind_register_req_msg_v01, - cold_boot_cal_done_enable), + fw_init_done_enable), }, { .data_type = QMI_OPT_FLAG, @@ -447,10 +571,46 @@ struct elem_info wlfw_ind_register_req_msg_v01_ei[] = { .offset = offsetof(struct wlfw_ind_register_req_msg_v01, rejuvenate_enable), }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + xo_cal_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + xo_cal_enable), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + cal_done_enable_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct wlfw_ind_register_req_msg_v01, + cal_done_enable), + }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -489,7 +649,7 @@ struct elem_info wlfw_ind_register_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -497,7 +657,7 @@ struct elem_info wlfw_fw_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -505,7 +665,7 @@ struct elem_info wlfw_msa_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -573,7 +733,7 @@ struct elem_info wlfw_pin_connect_result_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -608,7 +768,7 @@ struct elem_info wlfw_wlan_mode_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -626,7 +786,7 @@ struct elem_info wlfw_wlan_mode_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -764,7 +924,7 @@ struct elem_info wlfw_wlan_cfg_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -782,7 +942,7 @@ struct elem_info wlfw_wlan_cfg_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -790,7 +950,7 @@ struct elem_info wlfw_cap_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -920,7 +1080,7 @@ struct elem_info wlfw_cap_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1054,7 +1214,7 @@ struct elem_info wlfw_bdf_download_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1073,7 +1233,7 @@ struct elem_info wlfw_bdf_download_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1117,7 +1277,7 @@ struct elem_info wlfw_cal_report_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1135,7 +1295,7 @@ struct elem_info wlfw_cal_report_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1153,7 +1313,7 @@ struct elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1269,7 +1429,7 @@ struct elem_info wlfw_cal_download_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1288,7 +1448,7 @@ struct elem_info wlfw_cal_download_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1316,7 +1476,7 @@ struct elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1342,7 +1502,7 @@ struct elem_info wlfw_cal_update_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1459,7 +1619,7 @@ struct elem_info wlfw_cal_update_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1485,7 +1645,7 @@ struct elem_info wlfw_msa_info_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1522,7 +1682,7 @@ struct elem_info wlfw_msa_info_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1530,7 +1690,7 @@ struct elem_info wlfw_msa_ready_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1548,7 +1708,7 @@ struct elem_info wlfw_msa_ready_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1574,7 +1734,7 @@ struct elem_info wlfw_ini_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1592,7 +1752,7 @@ struct elem_info wlfw_ini_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1627,7 +1787,7 @@ struct elem_info wlfw_athdiag_read_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1676,7 +1836,7 @@ struct elem_info wlfw_athdiag_read_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1724,7 +1884,7 @@ struct elem_info wlfw_athdiag_write_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1743,7 +1903,7 @@ struct elem_info wlfw_athdiag_write_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1760,7 +1920,7 @@ struct elem_info wlfw_vbatt_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1778,7 +1938,7 @@ struct elem_info wlfw_vbatt_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1804,7 +1964,7 @@ struct elem_info wlfw_mac_addr_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1822,7 +1982,7 @@ struct elem_info wlfw_mac_addr_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1834,16 +1994,16 @@ struct elem_info wlfw_host_cap_req_msg_v01_ei[] = { .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, - daemon_support_valid), + num_clients_valid), }, { - .data_type = QMI_UNSIGNED_1_BYTE, + .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, - .elem_size = sizeof(u8), + .elem_size = sizeof(u32), .is_array = NO_ARRAY, .tlv_type = 0x10, .offset = offsetof(struct wlfw_host_cap_req_msg_v01, - daemon_support), + num_clients), }, { .data_type = QMI_OPT_FLAG, @@ -1863,10 +2023,217 @@ struct elem_info wlfw_host_cap_req_msg_v01_ei[] = { .offset = offsetof(struct wlfw_host_cap_req_msg_v01, wake_msi), }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + gpios_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + gpios_len), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = QMI_WLFW_MAX_NUM_GPIO_V01, + .elem_size = sizeof(u32), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + gpios), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + nm_modem_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x13, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + nm_modem), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x14, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_cache_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x15, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + bdf_cache_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x16, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_cache_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x17, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + m3_cache_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_filesys_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x18, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_filesys_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_cache_support_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x19, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_cache_support), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_done_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1A, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + cal_done), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_bucket_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .is_array = NO_ARRAY, + .tlv_type = 0x1B, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_bucket), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_cfg_mode_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .is_array = NO_ARRAY, + .tlv_type = 0x1C, + .offset = offsetof(struct wlfw_host_cap_req_msg_v01, + mem_cfg_mode), + }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1884,50 +2251,61 @@ struct elem_info wlfw_host_cap_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; struct elem_info wlfw_request_mem_ind_msg_v01_ei[] = { { - .data_type = QMI_UNSIGNED_4_BYTE, + .data_type = QMI_DATA_LEN, .elem_len = 1, - .elem_size = sizeof(u32), + .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, - size), + mem_seg_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, + .elem_size = sizeof(struct wlfw_mem_seg_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wlfw_request_mem_ind_msg_v01, + mem_seg), + .ei_array = wlfw_mem_seg_s_v01_ei, }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; struct elem_info wlfw_respond_mem_req_msg_v01_ei[] = { { - .data_type = QMI_UNSIGNED_8_BYTE, + .data_type = QMI_DATA_LEN, .elem_len = 1, - .elem_size = sizeof(u64), + .elem_size = sizeof(u8), .is_array = NO_ARRAY, .tlv_type = 0x01, .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, - addr), + mem_seg_len), }, { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(u32), - .is_array = NO_ARRAY, - .tlv_type = 0x02, + .data_type = QMI_STRUCT, + .elem_len = QMI_WLFW_MAX_NUM_MEM_SEG_V01, + .elem_size = sizeof(struct wlfw_mem_seg_resp_s_v01), + .is_array = VAR_LEN_ARRAY, + .tlv_type = 0x01, .offset = offsetof(struct wlfw_respond_mem_req_msg_v01, - size), + mem_seg), + .ei_array = wlfw_mem_seg_resp_s_v01_ei, }, { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1945,7 +2323,7 @@ struct elem_info wlfw_respond_mem_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -1953,15 +2331,15 @@ struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; -struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[] = { +struct elem_info wlfw_fw_init_done_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2041,7 +2419,7 @@ struct elem_info wlfw_rejuvenate_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2049,7 +2427,7 @@ struct elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2068,7 +2446,7 @@ struct elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2096,7 +2474,7 @@ struct elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2155,7 +2533,7 @@ struct elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2181,7 +2559,7 @@ struct elem_info wlfw_m3_info_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2199,7 +2577,7 @@ struct elem_info wlfw_m3_info_resp_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; @@ -2216,6 +2594,14 @@ struct elem_info wlfw_xo_cal_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .is_array = NO_ARRAY, - .is_array = QMI_COMMON_TLV_TYPE, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct elem_info wlfw_cal_done_ind_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .is_array = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, }, }; diff --git a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h index 9b56eb0c02fb..00a873d11d14 100644 --- a/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h +++ b/drivers/net/wireless/cnss2/wlan_firmware_service_v01.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,10 +23,12 @@ #define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025 #define QMI_WLFW_FW_MEM_READY_IND_V01 0x0037 #define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A +#define QMI_WLFW_CAL_DONE_IND_V01 0x003E #define QMI_WLFW_HOST_CAP_REQ_V01 0x0034 #define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B #define QMI_WLFW_M3_INFO_REQ_V01 0x003C #define QMI_WLFW_CAP_REQ_V01 0x0024 +#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038 #define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026 #define QMI_WLFW_M3_INFO_RESP_V01 0x003C #define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029 @@ -42,7 +44,6 @@ #define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022 #define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020 #define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023 -#define QMI_WLFW_COLD_BOOT_CAL_DONE_IND_V01 0x0038 #define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035 #define QMI_WLFW_REJUVENATE_IND_V01 0x0039 #define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B @@ -72,13 +73,16 @@ #define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020 #define QMI_WLFW_MAX_NUM_MEMORY_REGIONS_V01 2 +#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 32 #define QMI_WLFW_MAX_NUM_CAL_V01 5 #define QMI_WLFW_MAX_DATA_SIZE_V01 6144 #define QMI_WLFW_FUNCTION_NAME_LEN_V01 128 #define QMI_WLFW_MAX_NUM_CE_V01 12 #define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32 #define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144 +#define QMI_WLFW_MAX_NUM_GPIO_V01 32 #define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128 +#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2 #define QMI_WLFW_MAX_STR_LEN_V01 16 #define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24 #define QMI_WLFW_MAC_ADDR_SIZE_V01 6 @@ -117,6 +121,17 @@ enum wlfw_pipedir_enum_v01 { WLFW_PIPEDIR_ENUM_MAX_VAL_V01 = INT_MAX, }; +enum wlfw_mem_type_enum_v01 { + WLFW_MEM_TYPE_ENUM_MIN_VAL_V01 = INT_MIN, + QMI_WLFW_MEM_TYPE_MSA_V01 = 0, + QMI_WLFW_MEM_TYPE_DDR_V01 = 1, + QMI_WLFW_MEM_BDF_V01 = 2, + QMI_WLFW_MEM_M3_V01 = 3, + QMI_WLFW_MEM_CAL_V01 = 4, + QMI_WLFW_MEM_DPD_V01 = 5, + WLFW_MEM_TYPE_ENUM_MAX_VAL_V01 = INT_MAX, +}; + #define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00) #define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01) #define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02) @@ -128,6 +143,7 @@ enum wlfw_pipedir_enum_v01 { #define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL) #define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL) #define QMI_WLFW_FW_MEM_READY_V01 ((u64)0x08ULL) +#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL) #define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL) @@ -160,6 +176,26 @@ struct wlfw_memory_region_info_s_v01 { u8 secure_flag; }; +struct wlfw_mem_cfg_s_v01 { + u64 offset; + u32 size; + u8 secure_flag; +}; + +struct wlfw_mem_seg_s_v01 { + u32 size; + enum wlfw_mem_type_enum_v01 type; + u32 mem_cfg_len; + struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01]; +}; + +struct wlfw_mem_seg_resp_s_v01 { + u64 addr; + u32 size; + enum wlfw_mem_type_enum_v01 type; + u8 restore; +}; + struct wlfw_rf_chip_info_s_v01 { u32 chip_id; u32 chip_family; @@ -195,13 +231,17 @@ struct wlfw_ind_register_req_msg_v01 { u8 request_mem_enable; u8 fw_mem_ready_enable_valid; u8 fw_mem_ready_enable; - u8 cold_boot_cal_done_enable_valid; - u8 cold_boot_cal_done_enable; + u8 fw_init_done_enable_valid; + u8 fw_init_done_enable; u8 rejuvenate_enable_valid; u32 rejuvenate_enable; + u8 xo_cal_enable_valid; + u8 xo_cal_enable; + u8 cal_done_enable_valid; + u8 cal_done_enable; }; -#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 46 +#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 54 extern struct elem_info wlfw_ind_register_req_msg_v01_ei[]; struct wlfw_ind_register_resp_msg_v01 { @@ -533,13 +573,36 @@ struct wlfw_mac_addr_resp_msg_v01 { extern struct elem_info wlfw_mac_addr_resp_msg_v01_ei[]; struct wlfw_host_cap_req_msg_v01 { - u8 daemon_support_valid; - u8 daemon_support; + u8 num_clients_valid; + u32 num_clients; u8 wake_msi_valid; u32 wake_msi; -}; - -#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 11 + u8 gpios_valid; + u32 gpios_len; + u32 gpios[QMI_WLFW_MAX_NUM_GPIO_V01]; + u8 nm_modem_valid; + u8 nm_modem; + u8 bdf_support_valid; + u8 bdf_support; + u8 bdf_cache_support_valid; + u8 bdf_cache_support; + u8 m3_support_valid; + u8 m3_support; + u8 m3_cache_support_valid; + u8 m3_cache_support; + u8 cal_filesys_support_valid; + u8 cal_filesys_support; + u8 cal_cache_support_valid; + u8 cal_cache_support; + u8 cal_done_valid; + u8 cal_done; + u8 mem_bucket_valid; + u32 mem_bucket; + u8 mem_cfg_mode_valid; + u8 mem_cfg_mode; +}; + +#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189 extern struct elem_info wlfw_host_cap_req_msg_v01_ei[]; struct wlfw_host_cap_resp_msg_v01 { @@ -550,18 +613,19 @@ struct wlfw_host_cap_resp_msg_v01 { extern struct elem_info wlfw_host_cap_resp_msg_v01_ei[]; struct wlfw_request_mem_ind_msg_v01 { - u32 size; + u32 mem_seg_len; + struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; }; -#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 7 +#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 1124 extern struct elem_info wlfw_request_mem_ind_msg_v01_ei[]; struct wlfw_respond_mem_req_msg_v01 { - u64 addr; - u32 size; + u32 mem_seg_len; + struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01]; }; -#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 18 +#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 548 extern struct elem_info wlfw_respond_mem_req_msg_v01_ei[]; struct wlfw_respond_mem_resp_msg_v01 { @@ -578,12 +642,12 @@ struct wlfw_fw_mem_ready_ind_msg_v01 { #define WLFW_FW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0 extern struct elem_info wlfw_fw_mem_ready_ind_msg_v01_ei[]; -struct wlfw_cold_boot_cal_done_ind_msg_v01 { +struct wlfw_fw_init_done_ind_msg_v01 { char placeholder; }; -#define WLFW_COLD_BOOT_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0 -extern struct elem_info wlfw_cold_boot_cal_done_ind_msg_v01_ei[]; +#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_fw_init_done_ind_msg_v01_ei[]; struct wlfw_rejuvenate_ind_msg_v01 { u8 cause_for_rejuvenation_valid; @@ -654,4 +718,11 @@ struct wlfw_xo_cal_ind_msg_v01 { #define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4 extern struct elem_info wlfw_xo_cal_ind_msg_v01_ei[]; +struct wlfw_cal_done_ind_msg_v01 { + char placeholder; +}; + +#define WLFW_CAL_DONE_IND_MSG_V01_MAX_MSG_LEN 0 +extern struct elem_info wlfw_cal_done_ind_msg_v01_ei[]; + #endif -- GitLab From 14bd88ac0d431e3afd6f5f57eb27f66ff26ce819 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Thu, 10 May 2018 15:40:42 -0600 Subject: [PATCH 1718/1834] ARM: dts: msm: enable QMP debugfs support for sdxpoorwills Add device bindings for QMP debug client for sdxpoorwills target. Change-Id: I87757616f3735a5b02511a1327bfdd4b10c83756 Signed-off-by: Lina Iyer --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index d0f484cdee16..b8d021433923 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1078,6 +1078,12 @@ #mbox-cells = <1>; }; + aop-msg-client { + compatible = "qcom,debugfs-qmp-client"; + mboxes = <&qmp_aop 0>; + mbox-names = "aop"; + }; + vbus_detect: qcom,pmd-vbus-det { compatible = "qcom,pmd-vbus-det"; interrupt-parent = <&spmi_bus>; -- GitLab From 26398b919a849bb53f632b9876a7a3e2fa44f70b Mon Sep 17 00:00:00 2001 From: Lei Chen Date: Tue, 8 May 2018 14:47:56 +0800 Subject: [PATCH 1719/1834] ARM: dts: msm: add support for hx8399c HD+ panel for SDM429 QRD Add the dtsi nodes to enable hx8399c HD+ video mode on SDM429 QRD target. Change-Id: I2d2dbd12ac3788bb09dab112550e2d269062d307 Signed-off-by: Lei Chen --- arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi | 4 ++++ arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi index 7116662f29c6..dde9c5616cc2 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429-qrd.dtsi @@ -12,3 +12,7 @@ */ #include "sdm439-qrd.dtsi" + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_hx8399c_hd_vid>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi index 18714ce1568c..bfe7bfa0a958 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd.dtsi @@ -297,3 +297,13 @@ qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; }; + +&dsi_hx8399c_hd_vid { + /delete-property/ qcom,mdss-dsi-panel-timings; + qcom,mdss-dsi-panel-timings-phy-12nm = [08 06 0a 02 00 04 02 08]; + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_pwm"; + qcom,mdss-dsi-bl-pmic-pwm-frequency = <100>; + qcom,mdss-dsi-bl-pmic-bank-select = <0>; + qcom,mdss-dsi-pwm-gpio = <&pm8953_gpios 8 0>; +}; -- GitLab From a60e56f369f0288197000dac504e1789cb776c8c Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Wed, 9 May 2018 21:09:38 +0530 Subject: [PATCH 1720/1834] ARM: dts: msm: Add platform-enable-gpio for msm8909w Use platform-enable-gpio to control buffer connected on panel reset line. Change-Id: I97b5c2f8fa31d98ee370561a2fffaec71a4ae8d4 Signed-off-by: Arun kumar --- arch/arm64/boot/dts/qcom/8909w-pm660.dtsi | 25 +++++++++++++++++++ .../arm64/boot/dts/qcom/apq8009w-bg-alpha.dts | 1 + .../boot/dts/qcom/apq8009w-bg-wtp-v2.dts | 1 + .../boot/dts/qcom/msm8909w-bg-wtp-v2.dts | 1 + 4 files changed, 28 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi index 394740610c8d..c8330bd689d6 100644 --- a/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi +++ b/arch/arm64/boot/dts/qcom/8909w-pm660.dtsi @@ -79,6 +79,31 @@ }; }; +&msm_gpio { + /delete-node/ mpu6050_int_pin; + /delete-node/ apds99xx_int_pin; + /delete-node/ ak8963_int_pin; + + pmx_mdss { + mdss_dsi_active: mdss_dsi_active { + mux { + pins = "gpio25", "gpio37", "gpio59"; + }; + config { + pins = "gpio25", "gpio37", "gpio59"; + }; + }; + mdss_dsi_suspend: mdss_dsi_suspend { + mux { + pins = "gpio25", "gpio37", "gpio59"; + }; + config { + pins = "gpio25", "gpio37", "gpio59"; + }; + }; + }; +}; + &i2c_3 { qcom,actuator@0 { /delete-property/ cam_vaf-supply; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts index 89e1b761576f..1fe7b1551da3 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-alpha.dts @@ -300,4 +300,5 @@ &mdss_dsi0 { qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>; + qcom,platform-enable-gpio = <&msm_gpio 59 0>; }; diff --git a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts index 9fb662603175..81136703dd47 100644 --- a/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/apq8009w-bg-wtp-v2.dts @@ -317,4 +317,5 @@ &mdss_dsi0 { qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>; + qcom,platform-enable-gpio = <&msm_gpio 59 0>; }; diff --git a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts index 8149eb2f76e0..9dd80f085c4e 100644 --- a/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts +++ b/arch/arm64/boot/dts/qcom/msm8909w-bg-wtp-v2.dts @@ -320,4 +320,5 @@ &mdss_dsi0 { qcom,dsi-pref-prim-pan = <&dsi_auo_390p_cmd>; qcom,platform-bklight-en-gpio = <&msm_gpio 52 0>; + qcom,platform-enable-gpio = <&msm_gpio 59 0>; }; -- GitLab From 886ddda03cf09768111b6b81d912bf8331bd9f48 Mon Sep 17 00:00:00 2001 From: Pratham Pratap Date: Thu, 19 Apr 2018 12:26:48 +0530 Subject: [PATCH 1721/1834] usb: dwc3: replace %p with %pK Format specifier %p can leak kernel addresses while not valuing the kptr_restrict system settings. When kptr_restrict is set to (1), kernel pointers printed using the %pK format specifier will be replaced with 0's. Debugging Note : &pK prints only Zeros as address. If you need actual address information, write 0 to kptr_restrict. echo 0 > /proc/sys/kernel/kptr_restrict Change-Id: I1a5300d035dfb6366cb8d2740a5890bdb3e4a618 Signed-off-by: Pratham Pratap --- drivers/usb/dwc3/gadget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 73caa97884a3..f0e4d5e05b68 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1307,7 +1307,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) if (req->request.status == -EINPROGRESS) { ret = -EBUSY; - dev_err_ratelimited(dwc->dev, "%s: %p request already in queue", + dev_err_ratelimited(dwc->dev, "%s: %pK request already in queue", dep->name, req); return ret; } -- GitLab From 9785eb64dbd7ac926540450978fe56295420e74e Mon Sep 17 00:00:00 2001 From: bings Date: Wed, 9 May 2018 13:31:19 +0800 Subject: [PATCH 1722/1834] ARM: defconfig: Add support for naples sdio for msm8909 Enable naples sdio config to msm8909-perf_defconfig, msm8909_defconfig. Change-Id: Ia432d7b2a441d6d5d340ad6086930a6f1d604e3e CRs-Fixed: 2239334 Signed-off-by: bings --- arch/arm/configs/msm8909-perf_defconfig | 5 ++++- arch/arm/configs/msm8909_defconfig | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/msm8909-perf_defconfig b/arch/arm/configs/msm8909-perf_defconfig index 6f3cee42936d..faa252d1d845 100644 --- a/arch/arm/configs/msm8909-perf_defconfig +++ b/arch/arm/configs/msm8909-perf_defconfig @@ -259,7 +259,9 @@ CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_WCNSS_MEM_PRE_ALLOC=y -CONFIG_CLD_LL_CORE=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y CONFIG_INPUT_JOYSTICK=y @@ -423,6 +425,7 @@ CONFIG_MSM_PIL=y CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_CNSS_CRYPTO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ANDROID=y diff --git a/arch/arm/configs/msm8909_defconfig b/arch/arm/configs/msm8909_defconfig index f57e45dbbd6f..0fd9d9b515a9 100644 --- a/arch/arm/configs/msm8909_defconfig +++ b/arch/arm/configs/msm8909_defconfig @@ -253,7 +253,9 @@ CONFIG_PPPOPNS=y CONFIG_PPP_ASYNC=y CONFIG_PPP_SYNC_TTY=y CONFIG_WCNSS_MEM_PRE_ALLOC=y -CONFIG_CLD_LL_CORE=y +CONFIG_CNSS=y +CONFIG_CNSS_SDIO=y +CONFIG_CLD_HL_SDIO_CORE=y CONFIG_INPUT_EVDEV=y CONFIG_KEYBOARD_GPIO=y CONFIG_INPUT_JOYSTICK=y @@ -418,6 +420,7 @@ CONFIG_MSM_PIL=y CONFIG_MSM_EVENT_TIMER=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_CNSS_CRYPTO=y CONFIG_PWM=y CONFIG_PWM_QPNP=y CONFIG_ANDROID=y -- GitLab From 883dc407a196997fc12b7416ab97a7d62c62431c Mon Sep 17 00:00:00 2001 From: Kiran Gunda Date: Fri, 11 May 2018 14:28:39 +0530 Subject: [PATCH 1723/1834] ARM: dts: msm: Program the SOC disable threshold for PMI632 Program the SOC based disable threshold to disable the flash if the battery SOC is less than the disable threshold value. This is to avoid effecting the other critical PMIC features at low battery SOC. Change-Id: Ibc4beff74dbbe0b7fedc9043eadcc8fe9411cb74 Signed-off-by: Kiran Gunda --- arch/arm64/boot/dts/qcom/pmi632.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/pmi632.dtsi b/arch/arm64/boot/dts/qcom/pmi632.dtsi index 80480f14b7e3..40290d00537b 100644 --- a/arch/arm64/boot/dts/qcom/pmi632.dtsi +++ b/arch/arm64/boot/dts/qcom/pmi632.dtsi @@ -480,6 +480,7 @@ "ilim1-s1", "ilim2-s2", "vreg-ok"; + qcom,flash-disable-soc = <10>; }; smb5_vbus: qcom,smb5-vbus { -- GitLab From 304b0e56505bbfff6b8be2422d6551ddbdb30b8c Mon Sep 17 00:00:00 2001 From: Maria Yu Date: Fri, 11 May 2018 17:33:20 +0800 Subject: [PATCH 1724/1834] defconfig: msm: remove HARDEN_BRANCH_PREDICTOR config for msm8937 HARDEN_BRANCH_PREDICTOR is not needed for msm8937 platforms, so remove the config. Change-Id: I5dcaa65fede64142c6d2eba9c67979bfb7c8a4c9 Signed-off-by: Maria Yu --- arch/arm64/configs/msm8937-perf_defconfig | 1 - arch/arm64/configs/msm8937_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 4c6b6a1b39b4..9988b6478122 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -68,7 +68,6 @@ CONFIG_CMA=y CONFIG_ZSMALLOC=y CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y -CONFIG_HARDEN_BRANCH_PREDICTOR=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index 11bd200bdd36..ce96e828af22 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -71,7 +71,6 @@ CONFIG_CMA_DEBUGFS=y CONFIG_ZSMALLOC=y CONFIG_PROCESS_RECLAIM=y CONFIG_SECCOMP=y -CONFIG_HARDEN_BRANCH_PREDICTOR=y CONFIG_ARMV8_DEPRECATED=y CONFIG_SWP_EMULATION=y CONFIG_CP15_BARRIER_EMULATION=y -- GitLab From 162db220782ff9d52bec51a05827b36b4a8056e8 Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Wed, 9 May 2018 17:28:40 +0530 Subject: [PATCH 1725/1834] msm: mdss: avoid sending panel off command during TWM entry Provide sysfs node to indicate TWM entry and do not send panel off command when TWM entry is initiated. Change-Id: I23b2f378ec7810dc6052c2927435bec8aab1b785 Signed-off-by: Arun kumar --- drivers/video/fbdev/msm/mdp3.c | 33 ++++++++++++++++++++++ drivers/video/fbdev/msm/mdp3.h | 2 +- drivers/video/fbdev/msm/mdp3_ctrl.c | 20 ++++++++++--- drivers/video/fbdev/msm/mdp3_ppp.c | 8 ++++++ drivers/video/fbdev/msm/mdss_dsi.c | 3 +- drivers/video/fbdev/msm/mdss_fb.c | 15 ++++++++-- drivers/video/fbdev/msm/mdss_fb.h | 1 + drivers/video/fbdev/msm/mdss_mdp_overlay.c | 1 + drivers/video/fbdev/msm/mdss_qpic.c | 1 + 9 files changed, 75 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/msm/mdp3.c b/drivers/video/fbdev/msm/mdp3.c index 591c240dc6ff..c9db88e07706 100644 --- a/drivers/video/fbdev/msm/mdp3.c +++ b/drivers/video/fbdev/msm/mdp3.c @@ -2111,9 +2111,41 @@ static ssize_t mdp3_show_smart_blit(struct device *dev, static DEVICE_ATTR(smart_blit, 0664, mdp3_show_smart_blit, mdp3_store_smart_blit); +static ssize_t mdp3_store_twm(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + u32 data = -1; + ssize_t rc = 0; + + rc = kstrtoint(buf, 10, &data); + if (rc) { + pr_err("kstrtoint failed. rc=%d\n", rc); + return rc; + } + mdp3_res->twm_en = data ? true : false; + pr_err("TWM : %s\n", (mdp3_res->twm_en) ? + "ENABLED" : "DISABLED"); + return len; +} + +static ssize_t mdp3_show_twm(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret = 0; + + pr_err("TWM : %s\n", (mdp3_res->twm_en) ? + "ENABLED" : "DISABLED"); + ret = snprintf(buf, PAGE_SIZE, "%d\n", mdp3_res->twm_en); + return ret; +} + +static DEVICE_ATTR(twm_enable, 0664, + mdp3_show_twm, mdp3_store_twm); + static struct attribute *mdp3_fs_attrs[] = { &dev_attr_caps.attr, &dev_attr_smart_blit.attr, + &dev_attr_twm_enable.attr, NULL }; @@ -2378,6 +2410,7 @@ static int mdp3_probe(struct platform_device *pdev) mdp3_dynamic_clock_gating_ctrl; mdp3_res->mdss_util->panel_intf_type = mdp3_panel_intf_type; mdp3_res->mdss_util->panel_intf_status = mdp3_panel_get_intf_status; + mdp3_res->twm_en = false; if (mdp3_res->mdss_util->param_check(mdss_mdp3_panel)) { mdp3_res->mdss_util->display_disabled = true; diff --git a/drivers/video/fbdev/msm/mdp3.h b/drivers/video/fbdev/msm/mdp3.h index 6fb39a73649d..7132dee09e15 100644 --- a/drivers/video/fbdev/msm/mdp3.h +++ b/drivers/video/fbdev/msm/mdp3.h @@ -208,7 +208,7 @@ struct mdp3_hw_resource { bool solid_fill_vote_en; struct list_head reg_bus_clist; struct mutex reg_bus_lock; - + bool twm_en; u32 max_bw; u8 ppp_formats[BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)]; diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 589f2df1842f..1b0028b598df 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -983,6 +983,11 @@ static int mdp3_ctrl_on(struct msm_fb_data_type *mfd) return rc; } +static bool mdp3_is_twm_en(void) +{ + return mdp3_res->twm_en; +} + static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) { int rc = 0; @@ -1025,8 +1030,10 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) pr_debug("fb%d is off already", mfd->index); goto off_error; } - if (panel && panel->set_backlight) + if (panel && panel->set_backlight) { + if (!mdp3_is_twm_en()) panel->set_backlight(panel, 0); + } } /* @@ -1065,9 +1072,13 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) mdp3_irq_deregister(); } - if (panel->event_handler) - rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, - (void *) (long int)mfd->panel_power_state); + if (panel->event_handler) { + if (mdp3_is_twm_en()) + pr_info("TWM Enabled skip MDSS_EVENT_PANEL_OFF\n"); + else + rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, + (void *) (long int)mfd->panel_power_state); + } if (rc) pr_err("EVENT_PANEL_OFF error (%d)\n", rc); @@ -2870,6 +2881,7 @@ int mdp3_ctrl_init(struct msm_fb_data_type *mfd) mdp3_interface->configure_panel = mdp3_update_panel_info; mdp3_interface->input_event_handler = NULL; mdp3_interface->signal_retire_fence = NULL; + mdp3_interface->is_twm_en = mdp3_is_twm_en; mdp3_session = kzalloc(sizeof(struct mdp3_session_data), GFP_KERNEL); if (!mdp3_session) diff --git a/drivers/video/fbdev/msm/mdp3_ppp.c b/drivers/video/fbdev/msm/mdp3_ppp.c index 9253a69f927b..6095073cd1a2 100644 --- a/drivers/video/fbdev/msm/mdp3_ppp.c +++ b/drivers/video/fbdev/msm/mdp3_ppp.c @@ -196,12 +196,20 @@ int mdp3_ppp_verify_res(struct mdp_blit_req *req) if (((req->src_rect.x + req->src_rect.w) > req->src.width) || ((req->src_rect.y + req->src_rect.h) > req->src.height)) { + pr_err("%s: src roi (x=%d,y=%d,w=%d, h=%d) WxH(%dx%d)\n", + __func__, req->src_rect.x, req->src_rect.y, + req->src_rect.w, req->src_rect.h, req->src.width, + req->src.height); pr_err("%s: src roi larger than boundary\n", __func__); return -EINVAL; } if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) || ((req->dst_rect.y + req->dst_rect.h) > req->dst.height)) { + pr_err("%s: dst roi (x=%d,y=%d,w=%d, h=%d) WxH(%dx%d)\n", + __func__, req->dst_rect.x, req->dst_rect.y, + req->dst_rect.w, req->dst_rect.h, req->dst.width, + req->dst.height); pr_err("%s: dst roi larger than boundary\n", __func__); return -EINVAL; } diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index d8e74dab4251..a49d5fa3d0ba 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -1704,7 +1704,8 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata, int power_state) ATRACE_BEGIN("dsi_panel_off"); ret = ctrl_pdata->off(pdata); if (ret) { - pr_err("%s: Panel OFF failed\n", __func__); + pr_err("%s: Panel OFF failed\n", + __func__); goto error; } ATRACE_END("dsi_panel_off"); diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index 27299d1075e8..968d11d082b8 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -1653,6 +1653,7 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl) u32 temp = bkl_lvl; bool ad_bl_notify_needed = false; bool bl_notify_needed = false; + bool twm_en = false; if ((((mdss_fb_is_power_off(mfd) && mfd->dcm_state != DCM_ENTER) || !mfd->allow_bl_update) && !IS_CALIB_MODE_BL(mfd)) || @@ -1687,9 +1688,17 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl) if (mfd->bl_level != bkl_lvl) bl_notify_needed = true; pr_debug("backlight sent to panel :%d\n", temp); - pdata->set_backlight(pdata, temp); - mfd->bl_level = bkl_lvl; - mfd->bl_level_scaled = temp; + + if (mfd->mdp.is_twm_en) + twm_en = mfd->mdp.is_twm_en(); + + if (twm_en) { + pr_info("TWM Enabled skip backlight update\n"); + } else { + pdata->set_backlight(pdata, temp); + mfd->bl_level = bkl_lvl; + mfd->bl_level_scaled = temp; + } } if (ad_bl_notify_needed) mdss_fb_bl_update_notify(mfd, diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index c85f033cff85..5f2baef3f058 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -236,6 +236,7 @@ struct msm_mdp_interface { int (*pp_release_fnc)(struct msm_fb_data_type *mfd); void (*signal_retire_fence)(struct msm_fb_data_type *mfd, int retire_cnt); + bool (*is_twm_en)(void); void *private1; }; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 80708aa627f4..672b634c7155 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -6603,6 +6603,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) mdp5_interface->configure_panel = mdss_mdp_update_panel_info; mdp5_interface->input_event_handler = mdss_mdp_input_event_handler; mdp5_interface->signal_retire_fence = mdss_mdp_signal_retire_fence; + mdp5_interface->is_twm_en = NULL; if (mfd->panel_info->type == WRITEBACK_PANEL) { mdp5_interface->atomic_validate = diff --git a/drivers/video/fbdev/msm/mdss_qpic.c b/drivers/video/fbdev/msm/mdss_qpic.c index aa8d783f972e..2f170cce32f1 100644 --- a/drivers/video/fbdev/msm/mdss_qpic.c +++ b/drivers/video/fbdev/msm/mdss_qpic.c @@ -231,6 +231,7 @@ int mdss_qpic_overlay_init(struct msm_fb_data_type *mfd) qpic_interface->dma_fnc = mdss_qpic_pan_display; qpic_interface->ioctl_handler = NULL; qpic_interface->kickoff_fnc = NULL; + qpic_interface->is_twm_en = NULL; return 0; } -- GitLab From ec570b7f9c7f83ebb3e4c19e3b134e9261e71d09 Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Wed, 9 May 2018 20:23:38 +0530 Subject: [PATCH 1726/1834] msm: mdss: use platform-enable-gpio on msm8909w BG Use platform-enable-gpio to control buffer connected on panel reset gpio. This helps in avoiding panel reset during TWM entry. Change-Id: I6a0706c593202ab62acf332690d3255acbfd49f8 Signed-off-by: Arun kumar --- drivers/video/fbdev/msm/mdp3_ctrl.c | 20 +++++++++++++++++--- drivers/video/fbdev/msm/mdss_dsi.c | 1 + drivers/video/fbdev/msm/mdss_dsi_panel.c | 3 +++ drivers/video/fbdev/msm/mdss_panel.h | 1 + 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 1b0028b598df..1b68bb9642ac 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -1073,11 +1073,25 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) } if (panel->event_handler) { - if (mdp3_is_twm_en()) - pr_info("TWM Enabled skip MDSS_EVENT_PANEL_OFF\n"); - else + if (mdp3_is_twm_en()) { + pr_info("TWM active skip panel off, disable disp_en\n"); + if (gpio_is_valid(panel->panel_en_gpio)) { + rc = gpio_direction_output( + panel->panel_en_gpio, 1); + if (rc) { + pr_err("%s:set dir for gpio(%d) FAIL\n", + __func__, panel->panel_en_gpio); + } else { + gpio_set_value((panel->panel_en_gpio), 0); + usleep_range(100, 110); + pr_debug("%s:set disp_en_gpio_%d Low\n", + __func__, panel->panel_en_gpio); + } + } + } else { rc = panel->event_handler(panel, MDSS_EVENT_PANEL_OFF, (void *) (long int)mfd->panel_power_state); + } } if (rc) pr_err("EVENT_PANEL_OFF error (%d)\n", rc); diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index a49d5fa3d0ba..8d3e490de049 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -4070,6 +4070,7 @@ static int mdss_dsi_parse_gpio_params(struct platform_device *ctrl_pdev, if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) pr_debug("%s:%d, Disp_en gpio not specified\n", __func__, __LINE__); + pdata->panel_en_gpio = ctrl_pdata->disp_en_gpio; } ctrl_pdata->disp_te_gpio = of_get_named_gpio(ctrl_pdev->dev.of_node, diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index 1688503c72a3..7bb6618c4103 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -427,6 +427,8 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) __func__); goto exit; } + gpio_set_value((ctrl_pdata->disp_en_gpio), 1); + usleep_range(100, 110); } if (pdata->panel_info.rst_seq_len) { @@ -497,6 +499,7 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) } if (gpio_is_valid(ctrl_pdata->disp_en_gpio)) { gpio_set_value((ctrl_pdata->disp_en_gpio), 0); + usleep_range(100, 110); gpio_free(ctrl_pdata->disp_en_gpio); } gpio_set_value((ctrl_pdata->rst_gpio), 0); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index a3f9349eb722..c9e7e619679c 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -821,6 +821,7 @@ struct mdss_panel_data { struct mdss_panel_data *next; int panel_te_gpio; + int panel_en_gpio; struct completion te_done; }; -- GitLab From aa11bb25a4544f3defd7a2700be045561ca331b6 Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Wed, 9 May 2018 16:05:42 +0530 Subject: [PATCH 1727/1834] msm: mdss: do not send blank event to interface in TWM entry Sending MDSS_EVENT_BLANK turns off the panel. For TWM entry to be successful do not send blank event. Change-Id: I432049a2a44833f425bc64d5844442a234652c25 Signed-off-by: Arun kumar --- drivers/video/fbdev/msm/mdp3_ctrl.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/video/fbdev/msm/mdp3_ctrl.c b/drivers/video/fbdev/msm/mdp3_ctrl.c index 1b0028b598df..c8ac31f8d79f 100644 --- a/drivers/video/fbdev/msm/mdp3_ctrl.c +++ b/drivers/video/fbdev/msm/mdp3_ctrl.c @@ -1041,12 +1041,13 @@ static int mdp3_ctrl_off(struct msm_fb_data_type *mfd) * events need to be sent to the interface so that the * panel can be configured in low power mode */ - if (panel->event_handler) - rc = panel->event_handler(panel, MDSS_EVENT_BLANK, - (void *) (long int)mfd->panel_power_state); - if (rc) - pr_err("EVENT_BLANK error (%d)\n", rc); - + if (!mdp3_is_twm_en()) { + if (panel->event_handler) + rc = panel->event_handler(panel, MDSS_EVENT_BLANK, + (void *) (long int)mfd->panel_power_state); + if (rc) + pr_err("EVENT_BLANK error (%d)\n", rc); + } if (intf_stopped) { if (!mdp3_session->clk_on) mdp3_ctrl_clk_enable(mfd, 1); -- GitLab From b9950c18804bcbc8bf347d13283b02be4b6b4f35 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Thu, 10 May 2018 18:27:53 +0530 Subject: [PATCH 1728/1834] ARM: dts: msm: Update sound node entries for MSM8917 QRD SKU5 Add headset specific entries for MSM8917 QRD SKU5 target. Change-Id: I694eaa3929fc0e163c7f88cc1fa6e6dbc94cc685 Signed-off-by: Soumya Managoli --- arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi index f897b5941023..fae258d07bf9 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-qrd.dtsi @@ -78,6 +78,12 @@ }; &soc { + int_codec: sound { + status = "okay"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-hs-micbias-type = "internal"; + }; + gpio_keys { compatible = "gpio-keys"; input-name = "gpio-keys"; -- GitLab From 66112e5e4a1c7c44098c633778c6ea428b1cf5d8 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Thu, 10 May 2018 16:56:36 +0530 Subject: [PATCH 1729/1834] ARM: dts: msm: properly configure camera key for SDM670 Configure the camera-snapshot as GPIO_ACTIVE_LOW and camera-focus as GPIO_ACTIVE_HIGH as per the schematics. Change-Id: Ie757f65acfb8f632a897af6be84331bbaebcff0a Signed-off-by: Shantanu Jain --- arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi | 6 +++--- arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi index bd88087d94fe..da4d27da8d66 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-cdp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -143,7 +143,7 @@ cam_snapshot { label = "cam_snapshot"; - gpios = <&tlmm 91 0>; + gpios = <&tlmm 91 GPIO_ACTIVE_LOW>; linux,input-type = <1>; linux,code = <766>; gpio-key,wakeup; @@ -153,7 +153,7 @@ cam_focus { label = "cam_focus"; - gpios = <&tlmm 92 0>; + gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>; linux,input-type = <1>; linux,code = <528>; gpio-key,wakeup; diff --git a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi index cc5512790cf6..7764837cb7db 100644 --- a/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm670-mtp.dtsi @@ -202,7 +202,7 @@ cam_snapshot { label = "cam_snapshot"; - gpios = <&tlmm 91 0>; + gpios = <&tlmm 91 GPIO_ACTIVE_LOW>; linux,input-type = <1>; linux,code = <766>; gpio-key,wakeup; @@ -212,7 +212,7 @@ cam_focus { label = "cam_focus"; - gpios = <&tlmm 92 0>; + gpios = <&tlmm 92 GPIO_ACTIVE_HIGH>; linux,input-type = <1>; linux,code = <528>; gpio-key,wakeup; -- GitLab From 71a9ef40cbda3daac703f554340939a693614ff1 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Mon, 26 Mar 2018 19:07:41 -0700 Subject: [PATCH 1730/1834] power: smb5: Fix TypeC settings for PR_SWAP During TypeC PR_SWAP, SW is selected as source to control CC_COUT. CC orientation needs to be fixed in the middle of swap, so when there is a momentary disconnect, PD PHY can know which CC to communicate on. Add force CC_OUT support by SW override. Also, PMIC5, the new generation of PMICs, requires VSafe0V check bypass in order to get from AttachWait.SRC to Attached.SRC state to become source during PR_SWAP. Change-Id: I54ac5c21fc4b08cec47b9094e74c6ec0a5fc5179 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/smb5-lib.c | 48 ++++++++++++++++++++++++---- drivers/power/supply/qcom/smb5-reg.h | 2 ++ 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 87561867e23f..5345674a8786 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -3109,7 +3109,7 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) /* enable DRP */ rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, - TYPEC_POWER_ROLE_CMD_MASK, 0); + TYPEC_POWER_ROLE_CMD_MASK, 0); if (rc < 0) smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); @@ -3426,19 +3426,55 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, const union power_supply_propval *val) { int rc; + u8 stat = 0, orientation; chg->pr_swap_in_progress = val->intval; - /* - * call the cc changed irq to handle real removals while - * PR_SWAP was in progress - */ - smblib_usb_typec_change(chg); rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG, REDUCE_TCCDEBOUNCE_TO_2MS_BIT, val->intval ? REDUCE_TCCDEBOUNCE_TO_2MS_BIT : 0); if (rc < 0) smblib_err(chg, "Couldn't set tCC debounce rc=%d\n", rc); + + rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, + BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT, + val->intval ? BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT : 0); + if (rc < 0) + smblib_err(chg, "Couldn't set exit state cfg rc=%d\n", rc); + + if (chg->pr_swap_in_progress) { + rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", + rc); + } + + orientation = + stat & CC_ORIENTATION_BIT ? TYPEC_CCOUT_VALUE_BIT : 0; + rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, + TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT + | TYPEC_CCOUT_VALUE_BIT, + TYPEC_CCOUT_SRC_BIT | TYPEC_CCOUT_BUFFER_EN_BIT + | orientation); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", + rc); + } + } else { + rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, + TYPEC_CCOUT_SRC_BIT, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_CCOUT_CONTROL_REG rc=%d\n", + rc); + } + + /* enable DRP */ + rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, + TYPEC_POWER_ROLE_CMD_MASK, 0); + if (rc < 0) + smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); + } + return 0; } diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index e199087c907b..4d399aad9510 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -287,10 +287,12 @@ enum { #define VCONN_EN_SRC_BIT BIT(0) #define TYPE_C_CCOUT_CONTROL_REG (TYPEC_BASE + 0x48) +#define TYPEC_CCOUT_BUFFER_EN_BIT BIT(2) #define TYPEC_CCOUT_VALUE_BIT BIT(1) #define TYPEC_CCOUT_SRC_BIT BIT(0) #define TYPE_C_EXIT_STATE_CFG_REG (TYPEC_BASE + 0x50) +#define BYPASS_VSAFE0V_DURING_ROLE_SWAP_BIT BIT(3) #define EXIT_SNK_BASED_ON_CC_BIT BIT(0) #define TYPE_C_INTERRUPT_EN_CFG_1_REG (TYPEC_BASE + 0x5E) -- GitLab From 6afaea252128fa03cc4481bca36b45fb5404478c Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Mon, 26 Mar 2018 19:11:07 -0700 Subject: [PATCH 1731/1834] power: smb5: update USB source detection sequence Currently, USB/TypeC source detection takes place in the following order: APSD runs first for BC 1.2 and HVDCP2, followed by PD; if PD fails, APSD is rerun for HVDCP3 authentication. However, this has a big shortcoming, APSD rerun needs to be carefully designed to avoid PD conflicts, which increases code complexity, and makes it hard to maintain and add new changes. To simplify, a new APSD/PD flow is introduced to replace it: go PD first, followed by APSD rerun for BC1.2, HVDCP2 and then HVDCP3. For PD, if USB cable is plugged at boot up, run PD irrespective of cable type (legacy or regular), otherwise, skip PD in case of legacy cable detected. Change-Id: I2816a88c32e57bb167d9d325db306602fb4f0b64 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-smb5.c | 85 +++--- drivers/power/supply/qcom/smb5-lib.c | 397 ++++++++++---------------- drivers/power/supply/qcom/smb5-lib.h | 28 +- drivers/power/supply/qcom/smb5-reg.h | 5 + 4 files changed, 215 insertions(+), 300 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index d3aaf264a075..5264254ce8dd 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -177,6 +177,11 @@ module_param_named( debug_mask, __debug_mask, int, 0600 ); +static int __pd_disabled; +module_param_named( + pd_disabled, __pd_disabled, int, 0600 +); + static int __weak_chg_icl_ua = 500000; module_param_named( weak_chg_icl_ua, __weak_chg_icl_ua, int, 0600 @@ -434,7 +439,6 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_MODE, POWER_SUPPLY_PROP_TYPEC_POWER_ROLE, POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, - POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, @@ -515,9 +519,6 @@ static int smb5_usb_get_prop(struct power_supply *psy, else rc = smblib_get_prop_typec_cc_orientation(chg, val); break; - case POWER_SUPPLY_PROP_PD_ALLOWED: - rc = smblib_get_prop_pd_allowed(chg, val); - break; case POWER_SUPPLY_PROP_PD_ACTIVE: val->intval = chg->pd_active; break; @@ -605,12 +606,6 @@ static int smb5_usb_set_prop(struct power_supply *psy, struct smb_charger *chg = &chip->chg; int rc = 0; - mutex_lock(&chg->lock); - if (!chg->typec_present) { - rc = -EINVAL; - goto unlock; - } - switch (psp) { case POWER_SUPPLY_PROP_PD_CURRENT_MAX: rc = smblib_set_prop_pd_current_max(chg, val); @@ -652,8 +647,6 @@ static int smb5_usb_set_prop(struct power_supply *psy, break; } -unlock: - mutex_unlock(&chg->lock); return rc; } @@ -1425,6 +1418,15 @@ static int smb5_configure_typec(struct smb_charger *chg) { int rc; + /* disable apsd */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, + 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); + return rc; + } + rc = smblib_write(chg, TYPE_C_INTERRUPT_EN_CFG_1_REG, TYPEC_CCOUT_DETACH_INT_EN_BIT | TYPEC_CCOUT_ATTACH_INT_EN_BIT); @@ -1459,14 +1461,6 @@ static int smb5_configure_micro_usb(struct smb_charger *chg) { int rc; - /* configure micro USB mode */ - rc = smblib_masked_write(chg, TYPEC_U_USB_CFG_REG, - EN_MICRO_USB_MODE_BIT, EN_MICRO_USB_MODE_BIT); - if (rc < 0) { - dev_err(chg->dev, "Couldn't enable micro USB mode rc=%d\n", rc); - return rc; - } - rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, MICRO_USB_STATE_CHANGE_INT_EN_BIT, MICRO_USB_STATE_CHANGE_INT_EN_BIT); @@ -1500,7 +1494,6 @@ static int smb5_init_hw(struct smb5 *chip) &chg->default_icl_ua); /* Use SW based VBUS control, disable HW autonomous mode */ - /* TODO: auth can be enabled through vote based on APSD flow */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, HVDCP_AUTH_ALG_EN_CFG_BIT | HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT, HVDCP_AUTH_ALG_EN_CFG_BIT); @@ -1537,10 +1530,22 @@ static int smb5_init_hw(struct smb5 *chip) type = !!(val & EN_MICRO_USB_MODE_BIT); } - chg->connector_type = type ? POWER_SUPPLY_CONNECTOR_MICRO_USB - : POWER_SUPPLY_CONNECTOR_TYPEC; pr_debug("Connector type=%s\n", type ? "Micro USB" : "TypeC"); + if (type) { + chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; + smblib_rerun_apsd_if_required(chg); + rc = smb5_configure_micro_usb(chg); + } else { + chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC; + rc = smb5_configure_typec(chg); + } + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc); + return rc; + } + /* * PMI632 based hw init: * - Initialize flash module for PMI632 @@ -1548,8 +1553,6 @@ static int smb5_init_hw(struct smb5 *chip) if (chg->smb_version == PMI632_SUBTYPE) schgm_flash_init(chg); - smblib_rerun_apsd_if_required(chg); - /* vote 0mA on usb_icl for non battery platforms */ vote(chg->usb_icl_votable, DEFAULT_VOTER, chip->dt.no_battery, 0); @@ -1565,12 +1568,6 @@ static int smb5_init_hw(struct smb5 *chip) vote(chg->fv_votable, BATT_PROFILE_VOTER, chg->batt_profile_fv_uv > 0, chg->batt_profile_fv_uv); - vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, - true, 0); - vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, - true, 0); - vote(chg->pd_disallowed_votable_indirect, MICRO_USB_VOTER, - chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB, 0); /* Some h/w limit maximum supported ICL */ vote(chg->usb_icl_votable, HW_LIMIT_VOTER, @@ -1594,16 +1591,6 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } - if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) - rc = smb5_configure_micro_usb(chg); - else - rc = smb5_configure_typec(chg); - if (rc < 0) { - dev_err(chg->dev, - "Couldn't configure TypeC/micro-USB mode rc=%d\n", rc); - return rc; - } - /* configure VBUS for software control */ rc = smblib_masked_write(chg, DCDC_OTG_CFG_REG, OTG_EN_SRC_CFG_BIT, 0); if (rc < 0) { @@ -1812,11 +1799,21 @@ static int smb5_determine_initial_status(struct smb5 *chip) { struct smb_irq_data irq_data = {chip, "determine-initial-status"}; struct smb_charger *chg = &chip->chg; + union power_supply_propval val; + int rc; + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + pr_err("Couldn't get usb present rc=%d\n", rc); + return rc; + } + chg->early_usb_attach = val.intval; if (chg->bms_psy) smblib_suspend_on_debug_battery(chg); usb_plugin_irq_handler(0, &irq_data); + typec_attach_detach_irq_handler(0, &irq_data); typec_state_change_irq_handler(0, &irq_data); usb_source_change_irq_handler(0, &irq_data); chg_state_change_irq_handler(0, &irq_data); @@ -2008,6 +2005,7 @@ static struct smb_irq_info smb5_irqs[] = { }, [TYPEC_ATTACH_DETACH_IRQ] = { .name = "typec-attach-detach", + .handler = typec_attach_detach_irq_handler, }, [TYPEC_LEGACY_CABLE_DETECT_IRQ] = { .name = "typec-legacy-cable-detect", @@ -2303,6 +2301,7 @@ static int smb5_probe(struct platform_device *pdev) chg = &chip->chg; chg->dev = &pdev->dev; chg->debug_mask = &__debug_mask; + chg->pd_disabled = &__pd_disabled; chg->weak_chg_icl_ua = &__weak_chg_icl_ua; chg->mode = PARALLEL_MASTER; chg->irq_info = smb5_irqs; @@ -2452,6 +2451,10 @@ static int smb5_remove(struct platform_device *pdev) struct smb5 *chip = platform_get_drvdata(pdev); struct smb_charger *chg = &chip->chg; + /* force enable APSD */ + smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + BC1P2_SRC_DETECT_BIT, BC1P2_SRC_DETECT_BIT); + smb5_free_interrupts(chg); smblib_deinit(chg); platform_set_drvdata(pdev, NULL); diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 5345674a8786..1c93bf6e17b8 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -663,10 +663,6 @@ static void smblib_uusb_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); - rc = smblib_request_dpdm(chg, false); - if (rc < 0) - smblib_err(chg, "Couldn't to disable DPDM rc=%d\n", rc); - if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; if (data) { @@ -954,18 +950,6 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, (bool)suspend); } -static int smblib_pd_disallowed_votable_indirect_callback( - struct votable *votable, void *data, int disallowed, const char *client) -{ - struct smb_charger *chg = data; - int rc; - - rc = vote(chg->pd_allowed_votable, PD_DISALLOWED_INDIRECT_VOTER, - !disallowed, 0); - - return rc; -} - static int smblib_awake_vote_callback(struct votable *votable, void *data, int awake, const char *client) { @@ -1989,13 +1973,6 @@ int smblib_get_prop_typec_power_role(struct smb_charger *chg, return rc; } -int smblib_get_prop_pd_allowed(struct smb_charger *chg, - union power_supply_propval *val) -{ - val->intval = get_effective_result(chg->pd_allowed_votable); - return 0; -} - int smblib_get_prop_input_current_settled(struct smb_charger *chg, union power_supply_propval *val) { @@ -2039,13 +2016,7 @@ int smblib_get_prop_pd_in_hard_reset(struct smb_charger *chg, int smblib_get_pe_start(struct smb_charger *chg, union power_supply_propval *val) { - /* - * hvdcp timeout voter is the last one to allow pd. Use its vote - * to indicate start of pe engine - */ - val->intval - = !get_client_vote_locked(chg->pd_disallowed_votable_indirect, - APSD_VOTER); + val->intval = chg->ok_to_pd; return 0; } @@ -2298,14 +2269,14 @@ int smblib_set_prop_pd_voltage_max(struct smb_charger *chg, return rc; } -static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) +int smblib_set_prop_pd_active(struct smb_charger *chg, + const union power_supply_propval *val) { int rc = 0; - chg->pd_active = pd_active; + chg->pd_active = val->intval; if (chg->pd_active) { - vote(chg->pd_allowed_votable, PD_VOTER, true, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, true, 0); /* @@ -2313,24 +2284,24 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) * It is guaranteed that pd_active is set prior to * pd_current_max */ - rc = vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); - if (rc < 0) - smblib_err(chg, "Couldn't vote for USB ICL rc=%d\n", - rc); - - /* clear USB ICL vote for DCP_VOTER */ - rc = vote(chg->usb_icl_votable, DCP_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, "Couldn't un-vote DCP from USB ICL rc=%d\n", - rc); - - /* remove USB_PSY_VOTER */ - rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); - if (rc < 0) - smblib_err(chg, "Couldn't unvote USB_PSY rc=%d\n", rc); + vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); } else { - vote(chg->pd_allowed_votable, PD_VOTER, true, 0); + vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); + + /* PD hard resets failed, rerun apsd */ + if (chg->ok_to_pd) { + chg->ok_to_pd = false; + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't disable APSD rc=%d\n", rc); + return rc; + } + smblib_rerun_apsd(chg); + } } smblib_update_usb_type(chg); @@ -2338,15 +2309,6 @@ static int __smblib_set_prop_pd_active(struct smb_charger *chg, bool pd_active) return rc; } -int smblib_set_prop_pd_active(struct smb_charger *chg, - const union power_supply_propval *val) -{ - if (!get_effective_result(chg->pd_allowed_votable)) - return -EINVAL; - - return __smblib_set_prop_pd_active(chg, val->intval); -} - int smblib_set_prop_ship_mode(struct smb_charger *chg, const union power_supply_propval *val) { @@ -2657,11 +2619,7 @@ irqreturn_t icl_change_irq_handler(int irq, void *data) static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising) { - if (vbus_rising) { - /* use the typec flag even though its not typec */ - chg->typec_present = 1; - } else { - chg->typec_present = 0; + if (!vbus_rising) { smblib_update_usb_type(chg); smblib_notify_device_mode(chg, false); smblib_uusb_removal(chg); @@ -2764,12 +2722,10 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data) struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; - mutex_lock(&chg->lock); if (chg->pd_hard_reset) smblib_usb_plugin_hard_reset_locked(chg); else smblib_usb_plugin_locked(chg); - mutex_unlock(&chg->lock); return IRQ_HANDLED; } @@ -2858,8 +2814,6 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (!rising) return; - vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); - if (chg->mode == PARALLEL_MASTER) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, true, 0); @@ -2872,33 +2826,19 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, bool rising, bool qc_charger) { - const struct apsd_result *apsd_result = smblib_get_apsd_result(chg); - - /* Hold off PD only until hvdcp 2.0 detection timeout */ if (rising) { /* enable HDC and ICL irq for QC2/3 charger */ if (qc_charger) vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0); else - vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, - false, 0); - /* * HVDCP detection timeout done * If adapter is not QC2.0/QC3.0 - it is a plain old DCP. + * enforce DCP ICL if specified */ - if (!qc_charger && (apsd_result->bit & DCP_CHARGER_BIT)) - /* enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); - - /* - * if pd is not allowed, then set pd_active = false right here, - * so that it starts the hvdcp engine - */ - if (!get_effective_result(chg->pd_allowed_votable)) - __smblib_set_prop_pd_active(chg, 0); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__, @@ -2926,19 +2866,11 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: case FLOAT_CHARGER_BIT: - /* if not DCP then no hvdcp timeout happens. Enable pd here */ - vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, - false, 0); if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) || chg->use_extcon) smblib_notify_device_mode(chg, true); break; case OCP_CHARGER_BIT: - vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); - /* if not DCP then no hvdcp timeout happens, Enable pd here. */ - vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, - false, 0); - break; case DCP_CHARGER_BIT: vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); break; @@ -2957,6 +2889,14 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) int rc = 0; u8 stat; + /* + * Prepared to run PD or PD is active. At this moment, APSD is disabled, + * but there still can be irq on apsd_done from previously unfinished + * APSD run, skip it. + */ + if (chg->ok_to_pd) + return IRQ_HANDLED; + rc = smblib_read(chg, APSD_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read APSD_STATUS rc=%d\n", rc); @@ -3011,32 +2951,68 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) static void typec_sink_insertion(struct smb_charger *chg) { - /* when a sink is inserted we should not wait on hvdcp timeout to - * enable pd - */ - vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, false, 0); + vote(chg->usb_icl_votable, OTG_VOTER, true, 0); + if (chg->use_extcon) { smblib_notify_usb_host(chg, true); chg->otg_present = true; } + + if (!chg->pr_swap_in_progress) + chg->ok_to_pd = !(*chg->pd_disabled) || chg->early_usb_attach; +} + +static void typec_src_insertion(struct smb_charger *chg) +{ + int rc = 0; + u8 stat; + + if (chg->pr_swap_in_progress) + return; + + rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", + rc); + return; + } + + chg->typec_legacy = stat & TYPEC_LEGACY_CABLE_STATUS_BIT; + chg->ok_to_pd = !(chg->typec_legacy || *chg->pd_disabled) + || chg->early_usb_attach; + if (!chg->ok_to_pd) { + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't disable APSD rc=%d\n", rc); + return; + } + smblib_rerun_apsd(chg); + } } static void typec_sink_removal(struct smb_charger *chg) { - smblib_set_charge_param(chg, &chg->param.freq_switcher, - chg->chg_freq.freq_above_otg_threshold); - chg->boost_current_ua = 0; + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); } -static void smblib_handle_typec_removal(struct smb_charger *chg) +static void typec_src_removal(struct smb_charger *chg) { int rc; struct smb_irq_data *data; struct storm_watch *wdata; - rc = smblib_request_dpdm(chg, false); + /* disable apsd */ + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, + 0); if (rc < 0) - smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + smblib_err(chg, + "Couldn't disable APSD rc=%d\n", rc); + + smblib_update_usb_type(chg); if (chg->wa_flags & BOOST_BACK_WA) { data = chg->irq_info[SWITCHER_POWER_OK_IRQ].irq_data; @@ -3062,11 +3038,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->usb_icl_votable, CTM_VOTER, false, 0); vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0); - /* reset power delivery voters */ - vote(chg->pd_allowed_votable, PD_VOTER, false, 0); - vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, true, 0); - vote(chg->pd_disallowed_votable_indirect, APSD_VOTER, true, 0); - /* reset usb irq voters */ vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, QC_VOTER, false, 0); @@ -3078,14 +3049,10 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); - chg->vconn_attempts = 0; - chg->otg_attempts = 0; chg->pulse_cnt = 0; chg->usb_icl_delta_ua = 0; chg->voltage_min_uv = MICRO_5V; chg->voltage_max_uv = MICRO_5V; - chg->pd_active = 0; - chg->pd_hard_reset = 0; /* write back the default FLOAT charger configuration */ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, @@ -3094,12 +3061,6 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't write float charger options rc=%d\n", rc); - /* reset back to 103mS tCC debounce */ - rc = smblib_masked_write(chg, TYPE_C_DEBOUNCE_OPTION_REG, - REDUCE_TCCDEBOUNCE_TO_2MS_BIT, 0); - if (rc < 0) - smblib_err(chg, "Couldn't set 120mS tCC debounce rc=%d\n", rc); - /* reconfigure allowed voltage for HVDCP */ rc = smblib_set_adapter_allowance(chg, USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V); @@ -3107,58 +3068,15 @@ static void smblib_handle_typec_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n", rc); - /* enable DRP */ - rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, - TYPEC_POWER_ROLE_CMD_MASK, 0); - if (rc < 0) - smblib_err(chg, "Couldn't enable DRP rc=%d\n", rc); - - /* HW controlled CC_OUT */ - rc = smblib_masked_write(chg, TYPE_C_CCOUT_CONTROL_REG, - TYPEC_CCOUT_SRC_BIT, 0); - if (rc < 0) - smblib_err(chg, "Couldn't enable HW cc_out rc=%d\n", rc); - - /* clear exit sink based on cc */ - rc = smblib_masked_write(chg, TYPE_C_EXIT_STATE_CFG_REG, - EXIT_SNK_BASED_ON_CC_BIT, 0); - if (rc < 0) - smblib_err(chg, "Couldn't clear exit_sink_based_on_cc rc=%d\n", - rc); - - typec_sink_removal(chg); - smblib_update_usb_type(chg); - if (chg->use_extcon) { if (chg->otg_present) smblib_notify_usb_host(chg, false); else smblib_notify_device_mode(chg, false); } - chg->otg_present = false; -} - -static void smblib_handle_typec_insertion(struct smb_charger *chg) -{ - int rc; - u8 stat; - - vote(chg->pd_disallowed_votable_indirect, CC_DETACHED_VOTER, false, 0); - - rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); - return; - } - if (stat & SNK_SRC_MODE_BIT) { - typec_sink_insertion(chg); - } else { - rc = smblib_request_dpdm(chg, true); - if (rc < 0) - smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); - typec_sink_removal(chg); - } + chg->otg_present = false; + chg->typec_legacy = false; } static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) @@ -3200,66 +3118,6 @@ static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua); } -static void smblib_handle_typec_cc_state_change(struct smb_charger *chg) -{ - u8 stat; - int typec_mode, rc; - - if (chg->pr_swap_in_progress) - return; - - typec_mode = smblib_get_prop_typec_mode(chg); - if (chg->typec_present && (typec_mode != chg->typec_mode)) - smblib_handle_rp_change(chg, typec_mode); - - chg->typec_mode = typec_mode; - - if (!chg->typec_present && chg->typec_mode != POWER_SUPPLY_TYPEC_NONE) { - chg->typec_present = true; - smblib_dbg(chg, PR_MISC, "TypeC %s insertion\n", - smblib_typec_mode_name[chg->typec_mode]); - smblib_handle_typec_insertion(chg); - } else if (chg->typec_present && - chg->typec_mode == POWER_SUPPLY_TYPEC_NONE) { - chg->typec_present = false; - smblib_dbg(chg, PR_MISC, "TypeC removal\n"); - smblib_handle_typec_removal(chg); - } - - rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); - return; - } - /* suspend usb if sink */ - if ((stat & SNK_SRC_MODE_BIT) && chg->typec_present) - vote(chg->usb_icl_votable, OTG_VOTER, true, 0); - else - vote(chg->usb_icl_votable, OTG_VOTER, false, 0); - - smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", - smblib_typec_mode_name[chg->typec_mode]); -} - -static void smblib_usb_typec_change(struct smb_charger *chg) -{ - int rc; - u8 stat; - - smblib_handle_typec_cc_state_change(chg); - - rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); - if (rc < 0) { - smblib_err(chg, "Couldn't read TYPE_C_STATUS_4 rc=%d\n", rc); - return; - } - - if (stat & TYPEC_VBUS_ERROR_STATUS_BIT) - smblib_dbg(chg, PR_INTERRUPT, "IRQ: vbus-error\n"); - - power_supply_changed(chg->usb_psy); -} - irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; @@ -3281,17 +3139,81 @@ irqreturn_t typec_state_change_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; + int typec_mode; - if ((chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) - || chg->pr_swap_in_progress) { + if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) { smblib_dbg(chg, PR_INTERRUPT, - "Ignoring since pr_swap_in_progress\n"); + "Ignoring for micro USB\n"); return IRQ_HANDLED; } - mutex_lock(&chg->lock); - smblib_usb_typec_change(chg); - mutex_unlock(&chg->lock); + typec_mode = smblib_get_prop_typec_mode(chg); + if (chg->sink_src_mode != UNATTACHED_MODE + && (typec_mode != chg->typec_mode)) + smblib_handle_rp_change(chg, typec_mode); + chg->typec_mode = typec_mode; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: cc-state-change; Type-C %s detected\n", + smblib_typec_mode_name[chg->typec_mode]); + + power_supply_changed(chg->usb_psy); + + return IRQ_HANDLED; +} + +irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + u8 stat; + int rc; + + smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); + + rc = smblib_read(chg, TYPE_C_STATE_MACHINE_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATE_MACHINE_STATUS_REG rc=%d\n", + rc); + return IRQ_HANDLED; + } + + if (stat & TYPEC_ATTACH_DETACH_STATE_BIT) { + rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n", + rc); + return IRQ_HANDLED; + } + + if (stat & SNK_SRC_MODE_BIT) { + chg->sink_src_mode = SRC_MODE; + typec_sink_insertion(chg); + } else { + chg->sink_src_mode = SINK_MODE; + typec_src_insertion(chg); + } + + } else { + switch (chg->sink_src_mode) { + case SRC_MODE: + typec_sink_removal(chg); + break; + case SINK_MODE: + typec_src_removal(chg); + break; + default: + break; + } + + if (!chg->pr_swap_in_progress) { + chg->ok_to_pd = false; + chg->sink_src_mode = UNATTACHED_MODE; + chg->early_usb_attach = false; + } + } + + power_supply_changed(chg->usb_psy); + return IRQ_HANDLED; } @@ -3717,23 +3639,6 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } - chg->pd_disallowed_votable_indirect - = create_votable("PD_DISALLOWED_INDIRECT", VOTE_SET_ANY, - smblib_pd_disallowed_votable_indirect_callback, chg); - if (IS_ERR(chg->pd_disallowed_votable_indirect)) { - rc = PTR_ERR(chg->pd_disallowed_votable_indirect); - chg->pd_disallowed_votable_indirect = NULL; - return rc; - } - - chg->pd_allowed_votable = create_votable("PD_ALLOWED", - VOTE_SET_ANY, NULL, NULL); - if (IS_ERR(chg->pd_allowed_votable)) { - rc = PTR_ERR(chg->pd_allowed_votable); - chg->pd_allowed_votable = NULL; - return rc; - } - chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY, smblib_awake_vote_callback, chg); @@ -3771,10 +3676,6 @@ static void smblib_destroy_votables(struct smb_charger *chg) destroy_votable(chg->dc_suspend_votable); if (chg->usb_icl_votable) destroy_votable(chg->usb_icl_votable); - if (chg->pd_disallowed_votable_indirect) - destroy_votable(chg->pd_disallowed_votable_indirect); - if (chg->pd_allowed_votable) - destroy_votable(chg->pd_allowed_votable); if (chg->awake_votable) destroy_votable(chg->awake_votable); if (chg->chg_disable_votable) @@ -3786,7 +3687,6 @@ int smblib_init(struct smb_charger *chg) int rc = 0; mutex_init(&chg->lock); - mutex_init(&chg->otg_oc_lock); INIT_WORK(&chg->bms_update_work, bms_update_work); INIT_WORK(&chg->pl_update_work, pl_update_work); INIT_WORK(&chg->jeita_update_work, jeita_update_work); @@ -3799,6 +3699,7 @@ int smblib_init(struct smb_charger *chg) chg->fake_input_current_limited = -EINVAL; chg->fake_batt_status = -EINVAL; chg->jeita_configured = false; + chg->sink_src_mode = UNATTACHED_MODE; switch (chg->mode) { case PARALLEL_MASTER: diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 5d6d3a64a8f6..96bd550d44dd 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -80,6 +80,12 @@ enum smb_mode { NUM_MODES, }; +enum sink_src_mode { + SINK_MODE, + SRC_MODE, + UNATTACHED_MODE, +}; + enum { BOOST_BACK_WA = BIT(0), }; @@ -259,6 +265,7 @@ struct smb_charger { struct smb_params param; struct smb_iio iio; int *debug_mask; + int *pd_disabled; enum smb_mode mode; struct smb_chg_freq chg_freq; int smb_version; @@ -269,7 +276,6 @@ struct smb_charger { /* locks */ struct mutex lock; struct mutex ps_change_lock; - struct mutex otg_oc_lock; /* power supplies */ struct power_supply *batt_psy; @@ -296,8 +302,6 @@ struct smb_charger { struct votable *fcc_votable; struct votable *fv_votable; struct votable *usb_icl_votable; - struct votable *pd_disallowed_votable_indirect; - struct votable *pd_allowed_votable; struct votable *awake_votable; struct votable *pl_disable_votable; struct votable *chg_disable_votable; @@ -315,10 +319,17 @@ struct smb_charger { struct delayed_work uusb_otg_work; struct delayed_work bb_removal_work; - /* cached status */ + /* pd */ int voltage_min_uv; int voltage_max_uv; int pd_active; + bool pd_hard_reset; + bool pr_swap_in_progress; + bool early_usb_attach; + bool ok_to_pd; + bool typec_legacy; + + /* cached status */ bool system_suspend_supported; int boost_threshold_ua; int system_temp_level; @@ -334,15 +345,10 @@ struct smb_charger { int connector_type; bool otg_en; bool suspend_input_on_debug_batt; - int otg_attempts; - int vconn_attempts; int default_icl_ua; int otg_cl_ua; bool uusb_apsd_rerun_done; - bool pd_hard_reset; - bool typec_present; int fake_input_current_limited; - bool pr_swap_in_progress; int typec_mode; int usb_icl_change_irq_enabled; u32 jeita_status; @@ -352,6 +358,7 @@ struct smb_charger { int hw_max_icl_ua; int auto_recharge_soc; bool jeita_configured; + enum sink_src_mode sink_src_mode; /* workaround flag */ u32 wa_flags; @@ -420,6 +427,7 @@ irqreturn_t usb_plugin_irq_handler(int irq, void *data); irqreturn_t usb_source_change_irq_handler(int irq, void *data); irqreturn_t icl_change_irq_handler(int irq, void *data); irqreturn_t typec_state_change_irq_handler(int irq, void *data); +irqreturn_t typec_attach_detach_irq_handler(int irq, void *data); irqreturn_t dc_plugin_irq_handler(int irq, void *data); irqreturn_t high_duty_cycle_irq_handler(int irq, void *data); irqreturn_t switcher_power_ok_irq_handler(int irq, void *data); @@ -485,8 +493,6 @@ int smblib_get_prop_typec_cc_orientation(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_typec_power_role(struct smb_charger *chg, union power_supply_propval *val); -int smblib_get_prop_pd_allowed(struct smb_charger *chg, - union power_supply_propval *val); int smblib_get_prop_input_current_settled(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_input_voltage_settled(struct smb_charger *chg, diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 4d399aad9510..7a886b0113f4 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -215,6 +215,7 @@ enum { #define HVDCP_AUTH_ALG_EN_CFG_BIT BIT(6) #define HVDCP_AUTONOMOUS_MODE_EN_CFG_BIT BIT(5) #define BC1P2_SRC_DETECT_BIT BIT(3) +#define HVDCP_EN_BIT BIT(2) #define USBIN_OPTIONS_2_CFG_REG (USBIN_BASE + 0x63) #define FLOAT_OPTIONS_MASK GENMASK(2, 0) @@ -262,6 +263,9 @@ enum { #define SRC_RA_OPEN_BIT BIT(1) #define AUDIO_ACCESS_RA_RA_BIT BIT(0) +#define TYPE_C_STATE_MACHINE_STATUS_REG (TYPEC_BASE + 0x09) +#define TYPEC_ATTACH_DETACH_STATE_BIT BIT(5) + #define TYPE_C_MISC_STATUS_REG (TYPEC_BASE + 0x0B) #define SNK_SRC_MODE_BIT BIT(6) #define TYPEC_VBUS_ERROR_STATUS_BIT BIT(4) @@ -269,6 +273,7 @@ enum { #define CC_ATTACHED_BIT BIT(0) #define LEGACY_CABLE_STATUS_REG (TYPEC_BASE + 0x0D) +#define TYPEC_LEGACY_CABLE_STATUS_BIT BIT(1) #define TYPEC_NONCOMP_LEGACY_CABLE_STATUS_BIT BIT(0) #define TYPEC_U_USB_STATUS_REG (TYPEC_BASE + 0x0F) -- GitLab From f7b89907c2cd1529a3bf5b66b44ec8e8706ba753 Mon Sep 17 00:00:00 2001 From: Harry Yang Date: Tue, 13 Mar 2018 22:37:53 -0700 Subject: [PATCH 1732/1834] power: smb5: Rearrange USB ICL SW configuration SW configures USB ICL by updating ICL_MAX to override APSD results. As APSD/PD flow has been re-organized by running APSD after PD, SW ICL configuration process has to be updated accordingly. Following is the order of power source precedence along with ICL_MAX set by SW. 1. USB PD: set by USB PD driver 2. HVDCP (Quick Charge 2.0/3.0): 3A 3. USB Type-C Rp-high: 3A; Rp-medium: 1.5A 4. USB Legacy/Type-C Rp-std: follow USB BC 1.2 CRs-Fixed: 2215965 Change-Id: Ibd1cd3d531c3132f3cfadad68f6bb10453c702f2 Signed-off-by: Harry Yang --- drivers/power/supply/qcom/qpnp-smb5.c | 20 ++- drivers/power/supply/qcom/smb5-lib.c | 194 ++++++++++++++++++-------- drivers/power/supply/qcom/smb5-lib.h | 4 +- drivers/power/supply/qcom/smb5-reg.h | 2 + 4 files changed, 156 insertions(+), 64 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 5264254ce8dd..462e55fb57b1 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -52,6 +52,13 @@ static struct smb_params smb5_pmi632_params = { .max_u = 3000000, .step_u = 50000, }, + .icl_max_stat = { + .name = "dcdc icl max status", + .reg = ICL_MAX_STATUS_REG, + .min_u = 0, + .max_u = 3000000, + .step_u = 50000, + }, .icl_stat = { .name = "input current limit status", .reg = AICL_ICL_STATUS_REG, @@ -90,7 +97,7 @@ static struct smb_params smb5_pmi632_params = { }, }; -static struct smb_params smb5_pmi855_params = { +static struct smb_params smb5_pm855b_params = { .fcc = { .name = "fast charge current", .reg = CHGR_FAST_CHARGE_CURRENT_CFG_REG, @@ -112,8 +119,15 @@ static struct smb_params smb5_pmi855_params = { .max_u = 5000000, .step_u = 50000, }, + .icl_max_stat = { + .name = "dcdc icl max status", + .reg = ICL_MAX_STATUS_REG, + .min_u = 0, + .max_u = 5000000, + .step_u = 50000, + }, .icl_stat = { - .name = "input current limit status", + .name = "aicl icl status", .reg = AICL_ICL_STATUS_REG, .min_u = 0, .max_u = 5000000, @@ -221,7 +235,7 @@ static int smb5_chg_config_init(struct smb5 *chip) switch (pmic_rev_id->pmic_subtype) { case PM855B_SUBTYPE: chip->chg.smb_version = PM855B_SUBTYPE; - chg->param = smb5_pmi855_params; + chg->param = smb5_pm855b_params; chg->name = "pm855b_charger"; break; case PMI632_SUBTYPE: diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 1c93bf6e17b8..9d7bb8326352 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -39,6 +39,10 @@ __func__, ##__VA_ARGS__); \ } while (0) +#define typec_rp_med_high(chg, typec_mode) \ + ((typec_mode == POWER_SUPPLY_TYPEC_SOURCE_MEDIUM \ + || typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) \ + && !chg->typec_legacy) int smblib_read(struct smb_charger *chg, u16 addr, u8 *val) { @@ -654,7 +658,7 @@ int smblib_mapping_cc_delta_from_field_value(struct smb_chg_param *param, return 0; } -#define USBIN_100MA 100000 +#define SDP_100_MA 100000 static void smblib_uusb_removal(struct smb_charger *chg) { int rc; @@ -679,6 +683,7 @@ static void smblib_uusb_removal(struct smb_charger *chg) /* reset both usbin current and voltage votes */ vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); /* reconfigure allowed voltage for HVDCP */ @@ -701,8 +706,6 @@ static void smblib_uusb_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't write float charger options rc=%d\n", rc); - /* leave the ICL configured to 100mA for next insertion */ - vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA); /* clear USB ICL vote for USB_PSY_VOTER */ rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); if (rc < 0) @@ -768,6 +771,7 @@ static int smblib_get_pulse_cnt(struct smb_charger *chg, int *count) } #define USBIN_25MA 25000 +#define USBIN_100MA 100000 #define USBIN_150MA 150000 #define USBIN_500MA 500000 #define USBIN_900MA 900000 @@ -881,6 +885,10 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) set_mode: rc = smblib_masked_write(chg, USBIN_ICL_OPTIONS_REG, USBIN_MODE_CHG_BIT, hc_mode ? USBIN_MODE_CHG_BIT : 0); + if (rc < 0) { + smblib_err(chg, "Couldn't set USBIN_ICL_OPTIONS rc=%d\n", rc); + goto out; + } /* unsuspend after configuring current and override */ rc = smblib_set_usb_suspend(chg, false); @@ -921,7 +929,8 @@ int smblib_get_icl_current(struct smb_charger *chg, int *icl_ua) return INT_MAX; /* override is set */ - rc = smblib_get_charge_param(chg, &chg->param.usb_icl, icl_ua); + rc = smblib_get_charge_param(chg, &chg->param.icl_max_stat, + icl_ua); if (rc < 0) { smblib_err(chg, "Couldn't get HC ICL rc=%d\n", rc); return rc; @@ -2103,24 +2112,40 @@ static int smblib_handle_usb_current(struct smb_charger *chg, if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) { if (usb_current == -ETIMEDOUT) { - /* - * Valid FLOAT charger, report the current based - * of Rp - */ + if ((chg->float_cfg & FLOAT_OPTIONS_MASK) + == FORCE_FLOAT_SDP_CFG_BIT) { + /* + * Confiugure USB500 mode if Float charger is + * configured for SDP. + */ + rc = set_sdp_current(chg, USBIN_500MA); + if (rc < 0) + smblib_err(chg, + "Couldn't set SDP ICL rc=%d\n", + rc); + + return rc; + } + if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) { + /* + * Valid FLOAT charger, report the current + * based of Rp. + */ typec_mode = smblib_get_prop_typec_mode(chg); rp_ua = get_rp_based_dcp_current(chg, typec_mode); rc = vote(chg->usb_icl_votable, - DYNAMIC_RP_VOTER, true, rp_ua); - if (rc < 0) { - pr_err("Couldn't vote ICL DYNAMIC_RP_VOTER rc=%d\n", - rc); + SW_ICL_MAX_VOTER, true, rp_ua); + if (rc < 0) + return rc; + } else { + rc = vote(chg->usb_icl_votable, + SW_ICL_MAX_VOTER, true, DCP_CURRENT_UA); + if (rc < 0) return rc; - } } - /* No specific handling required for micro-USB */ } else { /* * FLOAT charger detected as SDP by USB driver, @@ -2129,12 +2154,13 @@ static int smblib_handle_usb_current(struct smb_charger *chg, */ chg->real_charger_type = POWER_SUPPLY_TYPE_USB; rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, - true, usb_current); - if (rc < 0) { - pr_err("Couldn't vote ICL USB_PSY_VOTER rc=%d\n", - rc); + true, usb_current); + if (rc < 0) + return rc; + rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, + false, 0); + if (rc < 0) return rc; - } } } else { rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, @@ -2144,12 +2170,12 @@ static int smblib_handle_usb_current(struct smb_charger *chg, return rc; } - } + rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); + if (rc < 0) { + pr_err("Couldn't remove SW_ICL_MAX vote rc=%d\n", rc); + return rc; + } - rc = vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); - if (rc < 0) { - pr_err("Couldn't unvote ICL DEFAULT_100MA_VOTER rc=%d\n", rc); - return rc; } return 0; @@ -2285,7 +2311,9 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, * pd_current_max */ vote(chg->usb_icl_votable, PD_VOTER, true, USBIN_500MA); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); } else { + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); @@ -2828,17 +2856,16 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, { if (rising) { - /* enable HDC and ICL irq for QC2/3 charger */ - if (qc_charger) + if (qc_charger) { + /* enable HDC and ICL irq for QC2/3 charger */ vote(chg->usb_irq_enable_votable, QC_VOTER, true, 0); - else - /* - * HVDCP detection timeout done - * If adapter is not QC2.0/QC3.0 - it is a plain old DCP. - * enforce DCP ICL if specified - */ + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CURRENT_UA); + } else { + /* A plain DCP, enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, chg->dcp_icl_ua != -EINVAL, chg->dcp_icl_ua); + } } smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s %s\n", __func__, @@ -2853,6 +2880,69 @@ static void smblib_handle_hvdcp_detect_done(struct smb_charger *chg, rising ? "rising" : "falling"); } +static void update_sw_icl_max(struct smb_charger *chg, int pst) +{ + int typec_mode; + int rp_ua; + + /* while PD is active it should have complete ICL control */ + if (chg->pd_active) + return; + + /* + * HVDCP 2/3, handled separately + * For UNKNOWN(input not present) return without updating ICL + */ + if (pst == POWER_SUPPLY_TYPE_USB_HVDCP + || pst == POWER_SUPPLY_TYPE_USB_HVDCP_3 + || pst == POWER_SUPPLY_TYPE_UNKNOWN) + return; + + /* TypeC rp med or high, use rp value */ + typec_mode = smblib_get_prop_typec_mode(chg); + if (typec_rp_med_high(chg, typec_mode)) { + rp_ua = get_rp_based_dcp_current(chg, typec_mode); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); + return; + } + + /* rp-std or legacy, USB BC 1.2 */ + switch (pst) { + case POWER_SUPPLY_TYPE_USB: + /* + * USB_PSY will vote to increase the current to 500/900mA once + * enumeration is done. + */ + if (!is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, true, + SDP_100_MA); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); + break; + case POWER_SUPPLY_TYPE_USB_CDP: + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + CDP_CURRENT_UA); + break; + case POWER_SUPPLY_TYPE_USB_DCP: + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + DCP_CURRENT_UA); + break; + case POWER_SUPPLY_TYPE_USB_FLOAT: + /* + * limit ICL to 100mA, the USB driver will enumerate to check + * if this is a SDP and appropriately set the current + */ + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + SDP_100_MA); + break; + default: + smblib_err(chg, "Unknown APSD %d; forcing 500mA\n", pst); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + SDP_CURRENT_UA); + break; + } +} + static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { const struct apsd_result *apsd_result; @@ -2862,6 +2952,8 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) apsd_result = smblib_update_usb_type(chg); + update_sw_icl_max(chg, apsd_result->pst); + switch (apsd_result->bit) { case SDP_CHARGER_BIT: case CDP_CHARGER_BIT: @@ -2872,7 +2964,6 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) break; case OCP_CHARGER_BIT: case DCP_CHARGER_BIT: - vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, false, 0); break; default: break; @@ -3028,7 +3119,7 @@ static void typec_src_removal(struct smb_charger *chg) cancel_delayed_work_sync(&chg->pl_enable_work); /* reset input current limit voters */ - vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER, true, USBIN_100MA); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chg->usb_icl_votable, PD_VOTER, false, 0); vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, DCP_VOTER, false, 0); @@ -3036,7 +3127,6 @@ static void typec_src_removal(struct smb_charger *chg) vote(chg->usb_icl_votable, SW_QC3_VOTER, false, 0); vote(chg->usb_icl_votable, OTG_VOTER, false, 0); vote(chg->usb_icl_votable, CTM_VOTER, false, 0); - vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, false, 0); /* reset usb irq voters */ vote(chg->usb_irq_enable_votable, PD_VOTER, false, 0); @@ -3081,41 +3171,27 @@ static void typec_src_removal(struct smb_charger *chg) static void smblib_handle_rp_change(struct smb_charger *chg, int typec_mode) { - int rp_ua; const struct apsd_result *apsd = smblib_get_apsd_result(chg); - if ((apsd->pst != POWER_SUPPLY_TYPE_USB_DCP) - && (apsd->pst != POWER_SUPPLY_TYPE_USB_FLOAT)) - return; - - /* - * if APSD indicates FLOAT and the USB stack had detected SDP, - * do not respond to Rp changes as we do not confirm that its - * a legacy cable - */ - if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB) - return; /* * We want the ICL vote @ 100mA for a FLOAT charger * until the detection by the USB stack is complete. * Ignore the Rp changes unless there is a - * pre-existing valid vote. + * pre-existing valid vote or FLOAT is configured for + * SDP current. */ - if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT && - (get_client_vote(chg->usb_icl_votable, DEFAULT_100MA_VOTER) - <= USBIN_100MA)) + if (apsd->pst == POWER_SUPPLY_TYPE_USB_FLOAT) { + if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER) + <= USBIN_100MA + || (chg->float_cfg & FLOAT_OPTIONS_MASK) + == FORCE_FLOAT_SDP_CFG_BIT) return; + } + + update_sw_icl_max(chg, apsd->pst); - /* - * handle Rp change for DCP/FLOAT/OCP. - * Update the current only if the Rp is different from - * the last Rp value. - */ smblib_dbg(chg, PR_MISC, "CC change old_mode=%d new_mode=%d\n", chg->typec_mode, typec_mode); - - rp_ua = get_rp_based_dcp_current(chg, typec_mode); - vote(chg->usb_icl_votable, DYNAMIC_RP_VOTER, true, rp_ua); } irqreturn_t typec_or_rid_detection_change_irq_handler(int irq, void *data) diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 96bd550d44dd..7e2558cc48b8 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -56,6 +56,7 @@ enum print_reason { #define CTM_VOTER "CTM_VOTER" #define SW_QC3_VOTER "SW_QC3_VOTER" #define AICL_RERUN_VOTER "AICL_RERUN_VOTER" +#define SW_ICL_MAX_VOTER "SW_ICL_MAX_VOTER" #define QNOVO_VOTER "QNOVO_VOTER" #define BATT_PROFILE_VOTER "BATT_PROFILE_VOTER" #define OTG_DELAY_VOTER "OTG_DELAY_VOTER" @@ -65,8 +66,6 @@ enum print_reason { #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define WBC_VOTER "WBC_VOTER" #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" -#define DYNAMIC_RP_VOTER "DYNAMIC_RP_VOTER" -#define DEFAULT_100MA_VOTER "DEFAULT_100MA_VOTER" #define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define BOOST_BACK_STORM_COUNT 3 @@ -234,6 +233,7 @@ struct smb_params { struct smb_chg_param fcc; struct smb_chg_param fv; struct smb_chg_param usb_icl; + struct smb_chg_param icl_max_stat; struct smb_chg_param icl_stat; struct smb_chg_param otg_cl; struct smb_chg_param jeita_cc_comp_hot; diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 7a886b0113f4..4fdf866eae98 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -105,6 +105,8 @@ enum { /******************************** * DCDC Peripheral Registers * ********************************/ +#define ICL_MAX_STATUS_REG (DCDC_BASE + 0x06) + #define AICL_ICL_STATUS_REG (DCDC_BASE + 0x08) #define AICL_STATUS_REG (DCDC_BASE + 0x0A) -- GitLab From 5eb8a78c0c4904984b4151ec5a54e8b95a02b2ac Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 10 May 2018 18:12:53 -0700 Subject: [PATCH 1733/1834] power: qpnp-smbcharger: Fix error path Properly clean up voteables on error. Change-Id: I3fb7fe93956effe3144c79ba5e00ddea3ca02b35 Signed-off-by: Patrick Daly --- drivers/power/supply/qcom/qpnp-smbcharger.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/power/supply/qcom/qpnp-smbcharger.c b/drivers/power/supply/qcom/qpnp-smbcharger.c index 9b5c25fbffd5..3bb48104db08 100644 --- a/drivers/power/supply/qcom/qpnp-smbcharger.c +++ b/drivers/power/supply/qcom/qpnp-smbcharger.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2016 The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -8488,6 +8488,8 @@ static int smbchg_probe(struct platform_device *pdev) out: handle_usb_removal(chip); votables_cleanup: + if (chip->hvdcp_enable_votable) + destroy_votable(chip->hvdcp_enable_votable); if (chip->aicl_deglitch_short_votable) destroy_votable(chip->aicl_deglitch_short_votable); if (chip->hw_aicl_rerun_enable_indirect_votable) -- GitLab From 7de08dba85b8a465c996d4eb8ff4f554f9c6f934 Mon Sep 17 00:00:00 2001 From: Ji Xu Date: Thu, 3 May 2018 15:25:34 +0800 Subject: [PATCH 1734/1834] iio: Add new driver for icm20602 Support new IMU device of icm20602 based on I2C interface. Icm20602 can provide accelerator or gyro and temperature data through I2C 400 Kbps or SPI 10 Mbps interface. It can also share the data to userspace based on the water level configured by the userspace. Change-Id: Ibac2ce1be517eccbf1b548d88b33372637300dee Signed-off-by: xuji --- .../bindings/iio/imu/invn-icm20602.txt | 28 + drivers/iio/imu/Kconfig | 1 + drivers/iio/imu/Makefile | 1 + drivers/iio/imu/inv_icm20602/Kconfig | 14 + drivers/iio/imu/inv_icm20602/Makefile | 6 + .../iio/imu/inv_icm20602/inv_icm20602_bsp.c | 932 +++++++++++++++++ .../iio/imu/inv_icm20602/inv_icm20602_bsp.h | 978 ++++++++++++++++++ .../iio/imu/inv_icm20602/inv_icm20602_core.c | 547 ++++++++++ .../iio/imu/inv_icm20602/inv_icm20602_iio.h | 282 +++++ .../iio/imu/inv_icm20602/inv_icm20602_ring.c | 131 +++ .../imu/inv_icm20602/inv_icm20602_trigger.c | 83 ++ 11 files changed, 3003 insertions(+) create mode 100644 Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt create mode 100644 drivers/iio/imu/inv_icm20602/Kconfig create mode 100644 drivers/iio/imu/inv_icm20602/Makefile create mode 100644 drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c create mode 100644 drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h create mode 100644 drivers/iio/imu/inv_icm20602/inv_icm20602_core.c create mode 100644 drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h create mode 100644 drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c create mode 100644 drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c diff --git a/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt new file mode 100644 index 000000000000..27c304ef517e --- /dev/null +++ b/Documentation/devicetree/bindings/iio/imu/invn-icm20602.txt @@ -0,0 +1,28 @@ +The ICM20602 sensor is 6-axis gyroscope+accelerometer combo +device which is made by InvenSense Inc. + +Required properties: + + - compatible : Should be "invensense,icm20602". + - reg : the I2C address which depends on the AD0 pin. + - interrupt-parent : should be the phandle for the interrupt controller + - interrupts : interrupt mapping for GPIO IRQ + +Optional properties: + - invensense,icm20602-gpio: the irq gpio. This is not used if + using SMD to trigger. this is needed only if using the + device IRQ to trigger. Only using SMD to trigger can + support 8K sample rate. + +Example: + icm20602-i2c@068 { + compatible = "invensense,icm20602"; + reg = <0x68>; + interrupt-parent = <&msm_gpio>; + interrupts = <13 0>; + invensense,icm20602-gpio = <&msm_gpio 13 0x0>; + pinctrl-names = "imu_active","imu_suspend"; + pinctrl-0 = <&imu_int_active>; + pinctrl-1 = <&imu_int_suspend>; + status = "okay"; + }; diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig index 1f1ad41ef881..0a8b76326d79 100644 --- a/drivers/iio/imu/Kconfig +++ b/drivers/iio/imu/Kconfig @@ -39,6 +39,7 @@ config KMX61 be called kmx61. source "drivers/iio/imu/inv_mpu6050/Kconfig" +source "drivers/iio/imu/inv_icm20602/Kconfig" endmenu diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile index c71bcd30dc38..fab6a5e2c733 100644 --- a/drivers/iio/imu/Makefile +++ b/drivers/iio/imu/Makefile @@ -15,5 +15,6 @@ obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o obj-y += bmi160/ obj-y += inv_mpu6050/ +obj-y += inv_icm20602/ obj-$(CONFIG_KMX61) += kmx61.o diff --git a/drivers/iio/imu/inv_icm20602/Kconfig b/drivers/iio/imu/inv_icm20602/Kconfig new file mode 100644 index 000000000000..fa8868915fba --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/Kconfig @@ -0,0 +1,14 @@ +# +# inv-icm20602 drivers for Invensense MPU devices and combos +# +config INV_ICM20602_IIO + tristate "Invensense ICM20602 devices" + depends on I2C && SYSFS + select IIO_BUFFER + select IIO_BUFFER_CB + select IIO_TRIGGERED_BUFFER + help + This driver supports the Invensense ICM20602 devices. + It is a gyroscope/accelerometer combo device. + This driver can be built as a module. The module will be called + inv-icm20602. diff --git a/drivers/iio/imu/inv_icm20602/Makefile b/drivers/iio/imu/inv_icm20602/Makefile new file mode 100644 index 000000000000..d60c10ac178e --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for Invensense icm20602 device. +# + +obj-$(CONFIG_INV_ICM20602_IIO) += inv-icm20602.o +inv-icm20602-objs := inv_icm20602_core.o inv_icm20602_ring.o inv_icm20602_trigger.o inv_icm20602_bsp.o diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c new file mode 100644 index 000000000000..bfff285457c5 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.c @@ -0,0 +1,932 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_icm20602_bsp.h" +#include "inv_icm20602_iio.h" + +#define icm20602_init_reg_addr(head, tail, reg_map) { \ + enum inv_icm20602_reg_addr i;\ + for (i = head; i <= tail; i++) {\ + reg_map->address = i;\ + reg_map->reg_u.reg = 0x0;\ + reg_map++;\ + } \ +} + +#define icm20602_write_reg_simple(st, register) \ + icm20602_write_reg(st, \ + register.address, \ + register.reg_u.reg) + +static struct inv_icm20602_reg_map reg_set_20602; + +int icm20602_init_reg_map(void) +{ + struct struct_XG_OFFS_TC_H *reg_map = &(reg_set_20602.XG_OFFS_TC_H); + + icm20602_init_reg_addr(ADDR_XG_OFFS_TC_H, + ADDR_XG_OFFS_TC_L, reg_map); + + icm20602_init_reg_addr(ADDR_YG_OFFS_TC_H, + ADDR_YG_OFFS_TC_L, reg_map); + + icm20602_init_reg_addr(ADDR_ZG_OFFS_TC_H, + ADDR_ZG_OFFS_TC_L, reg_map); + + icm20602_init_reg_addr(ADDR_SELF_TEST_X_ACCEL, + ADDR_SELF_TEST_Z_ACCEL, reg_map); + + icm20602_init_reg_addr(ADDR_XG_OFFS_USRH, + ADDR_LP_MODE_CFG, reg_map); + + icm20602_init_reg_addr(ADDR_ACCEL_WOM_X_THR, + ADDR_FIFO_EN, reg_map); + + icm20602_init_reg_addr(ADDR_FSYNC_INT, + ADDR_GYRO_ZOUT_L, reg_map); + + icm20602_init_reg_addr(ADDR_SELF_TEST_X_GYRO, + ADDR_SELF_TEST_Z_GYRO, reg_map); + + icm20602_init_reg_addr(ADDR_FIFO_WM_TH1, + ADDR_FIFO_WM_TH2, reg_map); + + icm20602_init_reg_addr(ADDR_SIGNAL_PATH_RESET, + ADDR_PWR_MGMT_2, reg_map); + + icm20602_init_reg_addr(ADDR_I2C_IF, + ADDR_I2C_IF, reg_map); + + icm20602_init_reg_addr(ADDR_FIFO_COUNTH, + ADDR_XA_OFFSET_L, reg_map); + + icm20602_init_reg_addr(ADDR_YA_OFFSET_H, + ADDR_YA_OFFSET_L, reg_map); + + icm20602_init_reg_addr(ADDR_ZA_OFFSET_H, + ADDR_ZA_OFFSET_L, reg_map); + + return MPU_SUCCESS; +} + +#define W_FLG 0 +#define R_FLG 1 +int icm20602_bulk_read(struct inv_icm20602_state *st, + int reg, char *buf, int size) +{ + int result = MPU_SUCCESS; + char tx_buf[2] = {0x0, 0x0}; + int tmp_size = size; + int tmp_buf = buf; + struct i2c_msg msg[2]; + + if (!st || !buf) + return -MPU_FAIL; + + if (st->interface == ICM20602_SPI) { + tx_buf[0] = ICM20602_READ_REG(reg); + result = spi_write_then_read(st->spi, &tx_buf[0], + 1, tmp_buf, size); + if (result) { + pr_err("mpu read reg %u failed, rc %d\n", + reg, result); + result = -MPU_READ_FAIL; + } + } else { + result = size; + while (tmp_size > 0) { +#ifdef ICM20602_I2C_SMBUS + result += i2c_smbus_read_i2c_block_data(st->client, + reg, (tmp_size < 32)?tmp_size:32, tmp_buf); + tmp_size -= 32; + tmp_buf += tmp_size; +#else + tx_buf[0] = reg; + msg[0].addr = st->client->addr; + msg[0].flags = W_FLG; + msg[0].len = 1; + msg[0].buf = tx_buf; + + msg[1].addr = st->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = (tmp_size < 32)?tmp_size:32; + msg[1].buf = tmp_buf; + i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg)); + tmp_size -= 32; + tmp_buf += tmp_size; +#endif + } + } + + return result; +} + +static int icm20602_write_reg(struct inv_icm20602_state *st, + uint8_t reg, uint8_t val) +{ + int result = MPU_SUCCESS; + char txbuf[2] = {0x0, 0x0}; + struct i2c_msg msg[1]; + + if (st->interface == ICM20602_SPI) { + txbuf[0] = ICM20602_WRITE_REG(reg); + txbuf[1] = val; + result = spi_write_then_read(st->spi, &txbuf[0], 2, NULL, 0); + if (result) { + pr_err("mpu write reg %u failed, rc %d\n", + reg, val); + result = -MPU_READ_FAIL; + } + } else if (st->interface == ICM20602_I2C) { +#ifdef ICM20602_I2C_SMBUS + result = i2c_smbus_write_i2c_block_data(st->client, + reg, 1, &val); +#else + txbuf[0] = reg; + txbuf[1] = val; + msg[0].addr = st->client->addr; + msg[0].flags = I2C_M_IGNORE_NAK; + msg[0].len = 2; + msg[0].buf = txbuf; + + i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg)); +#endif + } + + return result; +} + +static int icm20602_read_reg(struct inv_icm20602_state *st, + uint8_t reg, uint8_t *val) +{ + int result = MPU_SUCCESS; + char txbuf[1] = {0x0}; + char rxbuf[1] = {0x0}; + struct i2c_msg msg[2]; + + if (st->interface == ICM20602_SPI) { + txbuf[0] = ICM20602_READ_REG(reg); + result = spi_write_then_read(st->spi, + &txbuf[0], 1, rxbuf, 1); + if (result) { + pr_err("mpu read reg %u failed, rc %d\n", + reg, result); + result = -MPU_READ_FAIL; + } + } else if (st->interface == ICM20602_I2C) { +#ifdef ICM20602_I2C_SMBUS + result = i2c_smbus_read_i2c_block_data(st->client, + reg, 1, rxbuf); + if (result != 1) { + pr_err("mpu read reg %u failed, rc %d\n", + reg, result); + result = -MPU_READ_FAIL; + } +#else + txbuf[0] = reg; + msg[0].addr = st->client->addr; + msg[0].flags = W_FLG; + msg[0].len = 1; + msg[0].buf = txbuf; + + msg[1].addr = st->client->addr; + msg[1].flags = I2C_M_RD; + msg[1].len = 1; + msg[1].buf = rxbuf; + + i2c_transfer(st->client->adapter, msg, ARRAY_SIZE(msg)); +#endif + } + *val = rxbuf[0]; + + return result; +} + +#define combine_8_to_16(upper, lower) ((upper << 8) | lower) + +int icm20602_read_raw(struct inv_icm20602_state *st, + struct struct_icm20602_real_data *real_data, uint32_t type) +{ + struct struct_icm20602_raw_data raw_data; + + if (type & ACCEL != 0) { + icm20602_read_reg(st, + reg_set_20602.ACCEL_XOUT_H.address, + &raw_data.ACCEL_XOUT_H); + icm20602_read_reg(st, + reg_set_20602.ACCEL_XOUT_L.address, + &raw_data.ACCEL_XOUT_L); + real_data->ACCEL_XOUT = + combine_8_to_16(raw_data.ACCEL_XOUT_H, + raw_data.ACCEL_XOUT_L); + + icm20602_read_reg(st, + reg_set_20602.ACCEL_YOUT_H.address, + &raw_data.ACCEL_YOUT_H); + icm20602_read_reg(st, + reg_set_20602.ACCEL_YOUT_L.address, + &raw_data.ACCEL_YOUT_L); + real_data->ACCEL_YOUT = + combine_8_to_16(raw_data.ACCEL_YOUT_H, + raw_data.ACCEL_YOUT_L); + + icm20602_read_reg(st, + reg_set_20602.ACCEL_ZOUT_H.address, + &raw_data.ACCEL_ZOUT_H); + icm20602_read_reg(st, + reg_set_20602.ACCEL_ZOUT_L.address, + &raw_data.ACCEL_ZOUT_L); + real_data->ACCEL_ZOUT = + combine_8_to_16(raw_data.ACCEL_ZOUT_H, + raw_data.ACCEL_ZOUT_L); + } + + if (type & GYRO != 0) { + icm20602_read_reg(st, + reg_set_20602.GYRO_XOUT_H.address, + &raw_data.GYRO_XOUT_H); + icm20602_read_reg(st, + reg_set_20602.GYRO_XOUT_L.address, + &raw_data.GYRO_XOUT_L); + real_data->GYRO_XOUT = + combine_8_to_16(raw_data.GYRO_XOUT_H, + raw_data.GYRO_XOUT_L); + + icm20602_read_reg(st, + reg_set_20602.GYRO_YOUT_H.address, + &raw_data.GYRO_YOUT_H); + icm20602_read_reg(st, + reg_set_20602.GYRO_YOUT_L.address, + &raw_data.GYRO_YOUT_L); + real_data->GYRO_YOUT = + combine_8_to_16(raw_data.GYRO_YOUT_H, + raw_data.GYRO_YOUT_L); + + icm20602_read_reg(st, + reg_set_20602.GYRO_ZOUT_H.address, + &raw_data.GYRO_ZOUT_H); + icm20602_read_reg(st, + reg_set_20602.GYRO_ZOUT_L.address, + &raw_data.GYRO_ZOUT_L); + real_data->GYRO_ZOUT = + combine_8_to_16(raw_data.GYRO_ZOUT_H, + raw_data.GYRO_ZOUT_L); + } + + return MPU_SUCCESS; +} + +int icm20602_read_fifo(struct inv_icm20602_state *st, + void *buf, const int size) +{ + return icm20602_bulk_read(st, + reg_set_20602.FIFO_R_W.address, buf, size); +} + +int icm20602_start_fifo(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + + config = st->config; + + /* enable fifo */ + if (config->fifo_enabled) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x1; + if (icm20602_write_reg_simple(st, + reg_set_20602.USER_CTRL)) { + pr_err("icm20602 start fifo failed\n"); + return -MPU_FAIL; + } + + /* enable interrupt, need to test */ + reg_set_20602.INT_ENABLE.reg_u.REG.FIFO_OFLOW_EN = 0x1; + reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0; + if (icm20602_write_reg_simple(st, + reg_set_20602.INT_ENABLE)) { + pr_err("icm20602 set FIFO_OFLOW_EN failed\n"); + return -MPU_FAIL; + } + } + + return MPU_SUCCESS; +} + +static int icm20602_stop_fifo(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + + config = st->config; + /* disable fifo */ + if (config->fifo_enabled) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_EN = 0x0; + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1; + if (icm20602_write_reg_simple(st, + reg_set_20602.USER_CTRL)) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + pr_err("icm20602 stop fifo failed\n"); + return -MPU_FAIL; + } + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + } + + return MPU_SUCCESS; +} + +static int icm20602_config_waterlevel(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + uint8_t val = 0; + + config = st->config; + if (config->fifo_enabled != true) + return MPU_SUCCESS; + /* config waterlevel as the fps need */ + config->fifo_waterlevel = (config->user_fps_in_ms / + (1000 / config->gyro_accel_sample_rate)) + *ICM20602_PACKAGE_SIZE; + + if (config->fifo_waterlevel > 1023 || + config->fifo_waterlevel/50 > + (1023-config->fifo_waterlevel)/ICM20602_PACKAGE_SIZE) { + pr_err("set fifo_waterlevel failed %d\n", + config->fifo_waterlevel); + return MPU_FAIL; + } + reg_set_20602.FIFO_WM_TH1.reg_u.reg = + (config->fifo_waterlevel & 0xff00) >> 8; + reg_set_20602.FIFO_WM_TH2.reg_u.reg = + (config->fifo_waterlevel & 0x00ff); + + icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH1); + icm20602_write_reg_simple(st, reg_set_20602.FIFO_WM_TH2); + icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH1.address, &val); + icm20602_read_reg(st, reg_set_20602.FIFO_WM_TH2.address, &val); + + return MPU_SUCCESS; +} + +static int icm20602_read_ST_code(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + int result = 0; + + config = st->config; + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_ACCEL.address, + &(config->acc_self_test.X)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_ACCEL.address, + &(config->acc_self_test.Y)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_ACCEL.address, + &(config->acc_self_test.Z)); + + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_X_GYRO.address, + &(config->gyro_self_test.X)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Y_GYRO.address, + &(config->gyro_self_test.Y)); + result |= icm20602_read_reg(st, reg_set_20602.SELF_TEST_Z_GYRO.address, + &(config->gyro_self_test.Z)); + + return result; +} + +static int icm20602_set_self_test(struct inv_icm20602_state *st) +{ + uint8_t raw_data[6] = {0, 0, 0, 0, 0, 0}; + uint8_t selfTest[6]; + float factory_trim[6]; + int result = 0; + int ii; + + reg_set_20602.SMPLRT_DIV.reg_u.REG.SMPLRT_DIV = 0; + result |= icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV); + + reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = INV_ICM20602_GYRO_LFP_92HZ; + result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG); + + reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0; + reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = ICM20602_GYRO_FSR_250DPS; + result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG); + + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = ICM20602_ACCLFP_99; + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0X0; + result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG2); + + reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = ICM20602_ACC_FSR_2G; + result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG); + + //icm20602_read_ST_code(st); + + return 0; +} + +static int icm20602_do_test_acc(struct inv_icm20602_state *st, + struct X_Y_Z *acc, struct X_Y_Z *acc_st) +{ + struct struct_icm20602_real_data *real_data = + kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC); + struct icm20602_user_config *config = st->config; + int i, j; + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, ACCEL); + acc->X += real_data->ACCEL_XOUT; + acc->Y += real_data->ACCEL_YOUT; + acc->Z += real_data->ACCEL_ZOUT; + usleep_range(1000, 1001); + } + acc->X /= SELFTEST_COUNT; + acc->X *= ST_PRECISION; + + acc->Y /= SELFTEST_COUNT; + acc->Y *= ST_PRECISION; + + acc->Z /= SELFTEST_COUNT; + acc->Z *= ST_PRECISION; + + reg_set_20602.ACCEL_CONFIG.reg_u.REG.XG_ST = 0x1; + reg_set_20602.ACCEL_CONFIG.reg_u.REG.YG_ST = 0x1; + reg_set_20602.ACCEL_CONFIG.reg_u.REG.ZG_ST = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG); + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, ACCEL); + acc_st->X += real_data->ACCEL_XOUT; + acc_st->Y += real_data->ACCEL_YOUT; + acc_st->Z += real_data->ACCEL_ZOUT; + usleep_range(1000, 1001); + } + acc_st->X /= SELFTEST_COUNT; + acc_st->X *= ST_PRECISION; + + acc_st->Y /= SELFTEST_COUNT; + acc_st->Y *= ST_PRECISION; + + acc_st->Z /= SELFTEST_COUNT; + acc_st->Z *= ST_PRECISION; + + return MPU_SUCCESS; +} + +static int icm20602_do_test_gyro(struct inv_icm20602_state *st, + struct X_Y_Z *gyro, struct X_Y_Z *gyro_st) +{ + struct struct_icm20602_real_data *real_data = + kmalloc(sizeof(struct inv_icm20602_state), GFP_ATOMIC); + int i, j; + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, GYRO); + gyro->X += real_data->GYRO_XOUT; + gyro->Y += real_data->GYRO_YOUT; + gyro->Z += real_data->GYRO_ZOUT; + usleep_range(1000, 1001); + } + gyro->X /= SELFTEST_COUNT; + gyro->X *= ST_PRECISION; + + gyro->Y /= SELFTEST_COUNT; + gyro->Y *= ST_PRECISION; + + gyro->Z /= SELFTEST_COUNT; + gyro->Z *= ST_PRECISION; + + reg_set_20602.GYRO_CONFIG.reg_u.REG.XG_ST = 0x1; + reg_set_20602.GYRO_CONFIG.reg_u.REG.YG_ST = 0x1; + reg_set_20602.GYRO_CONFIG.reg_u.REG.ZG_ST = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG); + + for (i = 0; i < SELFTEST_COUNT; i++) { + icm20602_read_raw(st, real_data, ACCEL); + gyro_st->X += real_data->GYRO_XOUT; + gyro_st->Y += real_data->GYRO_YOUT; + gyro_st->Z += real_data->GYRO_ZOUT; + usleep_range(1000, 1001); + } + gyro_st->X /= SELFTEST_COUNT; + gyro_st->X *= ST_PRECISION; + + gyro_st->Y /= SELFTEST_COUNT; + gyro_st->Y *= ST_PRECISION; + + gyro_st->Z /= SELFTEST_COUNT; + gyro_st->Z *= ST_PRECISION; + + return MPU_SUCCESS; +} + +static bool icm20602_check_acc_selftest(struct inv_icm20602_state *st, + struct X_Y_Z *acc, struct X_Y_Z *acc_st) +{ + struct X_Y_Z acc_ST_code, st_otp, st_shift_cust; + bool otp_value_zero = false, test_result = true; + + acc_ST_code.X = st->config->acc_self_test.X; + acc_ST_code.Y = st->config->acc_self_test.Y; + acc_ST_code.Z = st->config->acc_self_test.Z; + + st_otp.X = (st_otp.X != 0) ? mpu_st_tb[acc_ST_code.X - 1] : 0; + st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[acc_ST_code.Y - 1] : 0; + st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[acc_ST_code.Z - 1] : 0; + + if (st_otp.X & st_otp.Y & st_otp.Z == 0) + otp_value_zero = true; + + st_shift_cust.X = acc_st->X - acc->X; + st_shift_cust.Y = acc_st->X - acc->Y; + st_shift_cust.Z = acc_st->X - acc->Z; + if (!otp_value_zero) { + if ( + st_shift_cust.X < + (st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) || + st_shift_cust.Y < + (st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) || + st_shift_cust.Z < + (st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MIN / 100) || + + st_shift_cust.X > + (st_otp.X * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) || + st_shift_cust.Y > + (st_otp.Y * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) || + st_shift_cust.Z > + (st_otp.Z * ST_PRECISION * ACC_ST_SHIFT_MAX / 100) + ) { + test_result = false; + } + } else { + if ( + abs(st_shift_cust.X) < + (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Y) < + (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Z) < + (ACC_ST_AL_MIN * 16384 / 1000 * ST_PRECISION) || + + abs(st_shift_cust.X) > + (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Y) > + (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) || + abs(st_shift_cust.Z) > + (ACC_ST_AL_MAX * 16384 / 1000 * ST_PRECISION) + ) { + test_result = false; + } + } + + return test_result; +} + +static int icm20602_check_gyro_selftest(struct inv_icm20602_state *st, + struct X_Y_Z *gyro, struct X_Y_Z *gyro_st) +{ + struct X_Y_Z gyro_ST_code, st_otp, st_shift_cust; + bool otp_value_zero = false, test_result = true; + + gyro_ST_code.X = st->config->gyro_self_test.X; + gyro_ST_code.Y = st->config->gyro_self_test.Y; + gyro_ST_code.Z = st->config->gyro_self_test.Z; + + st_otp.X = (st_otp.X != 0) ? mpu_st_tb[gyro_ST_code.X - 1] : 0; + st_otp.Y = (st_otp.Y != 0) ? mpu_st_tb[gyro_ST_code.Y - 1] : 0; + st_otp.Z = (st_otp.Z != 0) ? mpu_st_tb[gyro_ST_code.Z - 1] : 0; + + if (st_otp.X & st_otp.Y & st_otp.Z == 0) + otp_value_zero = true; + + st_shift_cust.X = gyro_st->X - gyro->X; + st_shift_cust.Y = gyro_st->X - gyro->Y; + st_shift_cust.Z = gyro_st->X - gyro->Z; + if (!otp_value_zero) { + if ( + st_shift_cust.X < + (st_otp.X * ST_PRECISION * GYRO_ST_SHIFT / 100) || + st_shift_cust.Y < + (st_otp.Y * ST_PRECISION * GYRO_ST_SHIFT / 100) || + st_shift_cust.Z < + (st_otp.Z * ST_PRECISION * GYRO_ST_SHIFT / 100) + ) { + test_result = false; + } + } else { + if ( + abs(st_shift_cust.X) < + (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) || + abs(st_shift_cust.Y) < + (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) || + abs(st_shift_cust.Z) < + (GYRO_ST_AL * 32768 / 250 * ST_PRECISION) + ) { + test_result = false; + } + } + + if (test_result == true) { + /* Self Test Pass/Fail Criteria C */ + if ( + abs(st_shift_cust.X) > + GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION || + abs(st_shift_cust.Y) > + GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION || + abs(st_shift_cust.Z) > + GYRO_OFFSET_MAX * 32768 / 250 * ST_PRECISION + ) { + test_result = false; + } + } + + return test_result; +} + +bool icm20602_self_test(struct inv_icm20602_state *st) +{ + struct X_Y_Z acc, acc_st; + struct X_Y_Z gyro, gyro_st; + bool test_result = true; + + icm20602_set_self_test(st); + icm20602_do_test_acc(st, &acc, &acc_st); + icm20602_do_test_gyro(st, &gyro, &gyro_st); + test_result = icm20602_check_acc_selftest(st, &acc, &acc_st); + test_result = icm20602_check_gyro_selftest(st, &gyro, &gyro_st); + + return test_result; +} + +static int icm20602_config_fifo(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + + config = st->config; + if (config->fifo_enabled != true) + return MPU_SUCCESS; + + /* + * Set CONFIG.USER_SET_BIT = 0, No reason as datasheet said + */ + reg_set_20602.CONFIG.reg_u.REG.USER_SET_BIT = 0x0; + /* + * Set CONFIG.FIFO_MODE = 1, + * i.e. when FIFO is full, additional writes will + * not be written to FIFO + */ + reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1; + if (icm20602_write_reg_simple(st, reg_set_20602.CONFIG)) + return -MPU_FAIL; + + /* reset fifo */ + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1; + if (icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL)) { + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + return -MPU_FAIL; + } + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + + /* Enable FIFO on specified sensors */ + reg_set_20602.FIFO_EN.reg_u.REG.GYRO_FIFO_EN = 0x1; + reg_set_20602.FIFO_EN.reg_u.REG.ACCEL_FIFO_EN = 0x1; + if (icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN)) + return -MPU_FAIL; + + if (icm20602_config_waterlevel(st)) + return -MPU_FAIL; + + if (icm20602_start_fifo(st)) + return -MPU_FAIL; + + return MPU_SUCCESS; +} + +static int icm20602_initialize_gyro(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = NULL; + int result = MPU_SUCCESS; + int sample_rate; + uint8_t fchoice_b; + + if (st == NULL) + return -MPU_FAIL; + + /* + * ICM20602 supports gyro sampling rate up to 32KHz + * when fchoice_b != 0x00 + * In our driver, we supports up to 8KHz + * thus always set fchoice_b to 0x00; + */ + config = st->config; + /* + * SAPLRT_DIV in ICM20602_REG_SMPLRT_DIV is only used for 1kHz internal + * sampling, i.e. fchoice_b in ICM20602_REG_GYRO_CONFIG is 00 + * and 0 < dlpf_cfg in ICM20602_REG_CONFIG < 7 + * SAMPLE_RATE=Internal_Sample_Rate / (1 + SMPLRT_DIV) + */ + if (config->gyro_accel_sample_rate <= ICM20602_SAMPLE_RATE_1000HZ) + reg_set_20602.SMPLRT_DIV.reg_u.reg = + ICM20602_INTERNAL_SAMPLE_RATE_HZ / + config->gyro_accel_sample_rate - 1; + + result = icm20602_write_reg_simple(st, reg_set_20602.SMPLRT_DIV); + + /* Set gyro&temperature(combine) LPF */ + reg_set_20602.CONFIG.reg_u.REG.DLFP_CFG = config->gyro_lpf; + result |= icm20602_write_reg_simple(st, reg_set_20602.CONFIG); + + /* Set gyro full scale range */ + reg_set_20602.GYRO_CONFIG.reg_u.REG.FCHOICE_B = 0x0; + reg_set_20602.GYRO_CONFIG.reg_u.REG.FS_SEL = config->gyro_fsr; + result |= icm20602_write_reg_simple(st, reg_set_20602.GYRO_CONFIG); + + /* Set Accel full scale range */ + reg_set_20602.ACCEL_CONFIG.reg_u.REG.ACCEL_FS_SEL = config->acc_fsr; + result |= icm20602_write_reg_simple(st, reg_set_20602.ACCEL_CONFIG); + + /* + * Set accel LPF + * Support accel sample rate up to 1KHz + * thus set accel_fchoice_b to 0x00 + * The actual accel sample rate is 1KHz/(1+SMPLRT_DIV) + */ + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.ACCEL_FCHOICE_B = 0x0; + reg_set_20602.ACCEL_CONFIG2.reg_u.REG.A_DLPF_CFG = config->acc_lpf; + result |= icm20602_write_reg_simple(st, + reg_set_20602.ACCEL_CONFIG2); + + if (result) { + pr_err("icm20602 init gyro and accel failed\n"); + return -MPU_FAIL; + } + + return result; +} + +int icm20602_set_power_itg(struct inv_icm20602_state *st, bool power_on) +{ + int result = MPU_SUCCESS; + + if (power_on) { + reg_set_20602.PWR_MGMT_1.reg_u.reg = 0; + result = icm20602_write_reg_simple(st, + reg_set_20602.PWR_MGMT_1); + } else { + reg_set_20602.PWR_MGMT_1.reg_u.REG.SLEEP = 0x1; + result = icm20602_write_reg_simple(st, + reg_set_20602.PWR_MGMT_1); + } + if (result) { + pr_err("set power failed power %d err %d\n", + power_on, result); + return result; + } + + if (power_on) + msleep(30); + + return result; +} + +int icm20602_init_device(struct inv_icm20602_state *st) +{ + int result = MPU_SUCCESS; + struct icm20602_user_config *config = NULL; + int package_count; + + config = st->config; + if (st == NULL || st->config == NULL) { + pr_err("icm20602 validate config failed\n"); + return -MPU_FAIL; + } + + /* turn on gyro and accel */ + reg_set_20602.PWR_MGMT_2.reg_u.reg = 0x0; + result |= icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2); + msleep(30); + + /* disable INT */ + reg_set_20602.INT_ENABLE.reg_u.reg = 0x0; + result |= icm20602_write_reg_simple(st, reg_set_20602.INT_ENABLE); + + /* disbale FIFO */ + reg_set_20602.FIFO_EN.reg_u.reg = 0x0; + result |= icm20602_write_reg_simple(st, reg_set_20602.FIFO_EN); + + /* reset FIFO */ + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x1; + result |= icm20602_write_reg_simple(st, reg_set_20602.USER_CTRL); + reg_set_20602.USER_CTRL.reg_u.REG.FIFO_RST = 0x0; + msleep(30); + + /* init gyro and accel */ + if (icm20602_initialize_gyro(st)) { + pr_err("icm20602 init device failed\n"); + return -MPU_FAIL; + } + + /* if FIFO enable, config FIFO */ + if (config->fifo_enabled) { + if (icm20602_config_fifo(st)) { + pr_err("icm20602 init config fifo failed\n"); + return -MPU_FAIL; + } + } else { + /* enable interrupt */ + reg_set_20602.INT_ENABLE.reg_u.REG.DATA_RDY_INT_EN = 0x0; + if (icm20602_write_reg_simple(st, + reg_set_20602.INT_ENABLE)) { + pr_err("icm20602 set raw rdy failed\n"); + return -MPU_FAIL; + } + } + + /* buffer malloc */ + package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE; + + st->buf = kzalloc(sizeof(config->fifo_waterlevel * 2), GFP_ATOMIC); + if (!st->buf) + return -ENOMEM; + + st->data_push = kcalloc(package_count, + sizeof(struct struct_icm20602_data), GFP_ATOMIC); + if (!st->data_push) + return -ENOMEM; + + return result; +} + +void icm20602_rw_test(struct inv_icm20602_state *st) +{ + uint8_t val = 0; + + reg_set_20602.PWR_MGMT_2.reg_u.REG.STBY_ZG = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_2); + reg_set_20602.CONFIG.reg_u.REG.FIFO_MODE = 0x1; + icm20602_write_reg_simple(st, reg_set_20602.CONFIG); + + icm20602_read_reg(st, reg_set_20602.PWR_MGMT_2.address, &val); + icm20602_read_reg(st, reg_set_20602.CONFIG.address, &val); + +} + +int icm20602_detect(struct inv_icm20602_state *st) +{ + int result = MPU_SUCCESS; + uint8_t retry = 0, val = 0; + uint8_t usr_ctrl = 0; + + pr_debug("icm20602_detect\n"); + /* reset to make sure previous state are not there */ + reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x1; + result = icm20602_write_reg_simple(st, reg_set_20602.PWR_MGMT_1); + if (result) { + pr_err("mpu write reg 0x%x value 0x%x failed\n", + reg_set_20602.PWR_MGMT_1.reg_u.reg, + reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET); + return result; + } + reg_set_20602.PWR_MGMT_1.reg_u.REG.DEVICE_RESET = 0x0; + + /* the power up delay */ + msleep(30); + + /* out of sleep */ + result = icm20602_set_power_itg(st, true); + if (result) + return result; + /* get who am i register */ + while (retry < 10) { + /* get version (expecting 0x12 for the icm20602) */ + icm20602_read_reg(st, reg_set_20602.WHO_AM_I.address, &val); + if (val == ICM20602_WHO_AM_I) + break; + retry++; + } + + if (val != ICM20602_WHO_AM_I) { + pr_err("detect mpu failed,whoami reg 0x%x\n", val); + result = -MPU_FAIL; + } else { + pr_debug("detect mpu ok,whoami reg 0x%x\n", val); + } + icm20602_rw_test(st); + + return result; +} diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h new file mode 100644 index 000000000000..9c4dbd03c0f7 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_bsp.h @@ -0,0 +1,978 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* register high bit=1 for read */ +#define ICM20602_READ_REG(reg) (reg | 0x80) + +/* register high bit=0 for write */ +#define ICM20602_WRITE_REG(reg) (reg & (~0x80)) +#define ICM20602_WHO_AM_I 0x12 +#define ICM20602_INTERNAL_SAMPLE_RATE_HZ 1000 + +#define SELFTEST_COUNT 200 +#define ST_PRECISION 1000 +#define ACC_ST_SHIFT_MAX 150 +#define ACC_ST_SHIFT_MIN 50 +#define ACC_ST_AL_MIN 225 +#define ACC_ST_AL_MAX 675 +#define GYRO_ST_SHIFT 50 +#define GYRO_ST_AL 60 +#define GYRO_OFFSET_MAX 20 + +static const uint16_t mpu_st_tb[256] = { + 2620, 2646, 2672, 2699, 2726, 2753, 2781, 2808, + 2837, 2865, 2894, 2923, 2952, 2981, 3011, 3041, + 3072, 3102, 3133, 3165, 3196, 3228, 3261, 3293, + 3326, 3359, 3393, 3427, 3461, 3496, 3531, 3566, + 3602, 3638, 3674, 3711, 3748, 3786, 3823, 3862, + 3900, 3939, 3979, 4019, 4059, 4099, 4140, 4182, + 4224, 4266, 4308, 4352, 4395, 4439, 4483, 4528, + 4574, 4619, 4665, 4712, 4759, 4807, 4855, 4903, + 4953, 5002, 5052, 5103, 5154, 5205, 5257, 5310, + 5363, 5417, 5471, 5525, 5581, 5636, 5693, 5750, + 5807, 5865, 5924, 5983, 6043, 6104, 6165, 6226, + 6289, 6351, 6415, 6479, 6544, 6609, 6675, 6742, + 6810, 6878, 6946, 7016, 7086, 7157, 7229, 7301, + 7374, 7448, 7522, 7597, 7673, 7750, 7828, 7906, + 7985, 8065, 8145, 8227, 8309, 8392, 8476, 8561, + 8647, 8733, 8820, 8909, 8998, 9088, 9178, 9270, + 9363, 9457, 9551, 9647, 9743, 9841, 9939, 10038, + 10139, 10240, 10343, 10446, 10550, 10656, 10763, 10870, + 10979, 11089, 11200, 11312, 11425, 11539, 11654, 11771, + 11889, 12008, 12128, 12249, 12371, 12495, 12620, 12746, + 12874, 13002, 13132, 13264, 13396, 13530, 13666, 13802, + 13940, 14080, 14221, 14363, 14506, 14652, 14798, 14946, + 15096, 15247, 15399, 15553, 15709, 15866, 16024, 16184, + 16346, 16510, 16675, 16842, 17010, 17180, 17352, 17526, + 17701, 17878, 18057, 18237, 18420, 18604, 18790, 18978, + 19167, 19359, 19553, 19748, 19946, 20145, 20347, 20550, + 20756, 20963, 21173, 21385, 21598, 21814, 22033, 22253, + 22475, 22700, 22927, 23156, 23388, 23622, 23858, 24097, + 24338, 24581, 24827, 25075, 25326, 25579, 25835, 26093, + 26354, 26618, 26884, 27153, 27424, 27699, 27976, 28255, + 28538, 28823, 29112, 29403, 29697, 29994, 30294, 30597, + 30903, 31212, 31524, 31839, 32157, 32479, 32804 +}; + +enum inv_icm20602_reg_addr { + ADDR_XG_OFFS_TC_H = 0x04, + ADDR_XG_OFFS_TC_L, + ADDR_YG_OFFS_TC_H = 0x07, + ADDR_YG_OFFS_TC_L, + ADDR_ZG_OFFS_TC_H = 0x0A, + ADDR_ZG_OFFS_TC_L, + + ADDR_SELF_TEST_X_ACCEL = 0x0D, + ADDR_SELF_TEST_Y_ACCEL, + ADDR_SELF_TEST_Z_ACCEL, + + ADDR_XG_OFFS_USRH = 0x13, + ADDR_XG_OFFS_USRL, + ADDR_YG_OFFS_USRH, + ADDR_YG_OFFS_USRL, + ADDR_ZG_OFFS_USRH, + ADDR_ZG_OFFS_USRL, + + ADDR_SMPLRT_DIV, + ADDR_CONFIG, + + ADDR_GYRO_CONFIG, + + ADDR_ACCEL_CONFIG, + ADDR_ACCEL_CONFIG2, + + ADDR_LP_MODE_CFG, + + ADDR_ACCEL_WOM_X_THR = 0x20, + ADDR_ACCEL_WOM_Y_THR, + ADDR_ACCEL_WOM_Z_THR, + ADDR_FIFO_EN, + + ADDR_FSYNC_INT = 0x36, + ADDR_INT_PIN_CFG, + ADDR_INT_ENABLE, + ADDR_FIFO_WM_INT_STATUS, + ADDR_INT_STATUS, + + ADDR_ACCEL_XOUT_H, + ADDR_ACCEL_XOUT_L, + ADDR_ACCEL_YOUT_H, + ADDR_ACCEL_YOUT_L, + ADDR_ACCEL_ZOUT_H, + ADDR_ACCEL_ZOUT_L, + + ADDR_TEMP_OUT_H, + ADDR_TEMP_OUT_L, + + ADDR_GYRO_XOUT_H, + ADDR_GYRO_XOUT_L, + ADDR_GYRO_YOUT_H, + ADDR_GYRO_YOUT_L, + ADDR_GYRO_ZOUT_H, + ADDR_GYRO_ZOUT_L, + + ADDR_SELF_TEST_X_GYRO = 0x50, + ADDR_SELF_TEST_Y_GYRO, + ADDR_SELF_TEST_Z_GYRO, + + ADDR_FIFO_WM_TH1 = 0x60, + ADDR_FIFO_WM_TH2, + + ADDR_SIGNAL_PATH_RESET = 0x68, + ADDR_ACCEL_INTEL_CTRL, + ADDR_USER_CTRL, + + ADDR_PWR_MGMT_1, + ADDR_PWR_MGMT_2, + + ADDR_I2C_IF = 0x70, + + ADDR_FIFO_COUNTH = 0x72, + ADDR_FIFO_COUNTL, + ADDR_FIFO_R_W, + + ADDR_WHO_AM_I, + + ADDR_XA_OFFSET_H, + ADDR_XA_OFFSET_L, + ADDR_YA_OFFSET_H = 0x7A, + ADDR_YA_OFFSET_L, + ADDR_ZA_OFFSET_H = 0x7D, + ADDR_ZA_OFFSET_L +}; + +struct struct_XG_OFFS_TC_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_XG_OFFS_TC_H :2; + u8 REG_XG_OFFS_LP :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XG_OFFS_TC_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_XG_OFFS_TC_L :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_TC_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_YG_OFFS_TC_H :2; + u8 REG_YG_OFFS_LP :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_TC_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_YG_OFFS_TC_L :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_TC_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_ZG_OFFS_TC_H :2; + u8 REG_ZG_OFFS_LP :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_TC_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 REG_ZG_OFFS_TC_L :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_X_ACCEL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XA_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Y_ACCEL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YA_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Z_ACCEL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZA_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XG_OFFS_USRH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 X_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XG_OFFS_USRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 X_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_USRH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Y_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YG_OFFS_USRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Y_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_USRH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Z_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZG_OFFS_USRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 Z_OFFS_USR :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SMPLRT_DIV { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 SMPLRT_DIV :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_CONFIG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 DLFP_CFG :3; + u8 EXT_SYNC_SET :3; + u8 FIFO_MODE :1; + u8 USER_SET_BIT :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_CONFIG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FCHOICE_B :2; + u8 RESERVE0 :1; + u8 FS_SEL :2; + u8 ZG_ST :1; + u8 YG_ST :1; + u8 XG_ST :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_CONFIG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :3; + u8 ACCEL_FS_SEL :2; + u8 ZG_ST :1; + u8 YG_ST :1; + u8 XG_ST :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_CONFIG2 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 A_DLPF_CFG :3; + u8 ACCEL_FCHOICE_B :1; + u8 DEC2_CFG :2; + u8 RESERVE0 :2; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_LP_MODE_CFG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :4; + u8 G_AVGCFG :3; + u8 GYRO_CYCLE :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_WOM_X_THR { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_X_TH :8; + } REG; + u8 reg; + } reg_u; +}; + + +struct struct_ACCEL_WOM_Y_THR { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_Y_TH :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_WOM_Z_THR { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_Z_TH :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_EN { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE1 :3; + u8 ACCEL_FIFO_EN :1; + u8 GYRO_FIFO_EN :1; + u8 RESERVE0 :3; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FSYNC_INT { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :7; + u8 FSYNC_INT :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_INT_PIN_CFG { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :2; + u8 FSYNC_INT_MODE_EN:1; + u8 FSYNC_INT_LEVEL :1; + u8 INT_RD_CLEAR :1; + u8 LATCH_INT_EN :1; + u8 INT_OPEN :1; + u8 INT_LEVEL :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_INT_ENABLE { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 DATA_RDY_INT_EN :1; + u8 RESERVE0 :1; + u8 GDRIVE_INT_EN :1; + u8 FSYNC_INT_EN :1; + u8 FIFO_OFLOW_EN :1; + u8 WOM_Z_INT_EN :1; + u8 WOM_Y_INT_EN :1; + u8 WOM_X_INT_EN :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_WM_INT_STATUS { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE1 :6; + u8 FIFO_WM_INT :1; + u8 RESERVE0 :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_INT_STATUS { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 DATA_RDY_INT :1; + u8 RESERVE1 :1; + u8 GDRIVE_INT :1; + u8 RESERVE0 :1; + u8 FIFO_OFLOW_INT :1; + u8 WOM_Z_INT :1; + u8 WOM_Y_INT :1; + u8 WOM_X_INT :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_XOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_XOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_YOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_YOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_ZOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_ZOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ACCEL_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_TEMP_OUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 TEMP_OUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_TEMP_OUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 TEMP_OUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_XOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_XOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_XOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_YOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_YOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_YOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_ZOUT_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_GYRO_ZOUT_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 GYRO_ZOUT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_X_GYRO { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XG_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Y_GYRO { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YG_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SELF_TEST_Z_GYRO { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZG_ST_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_WM_TH1 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE0 :6; + u8 FIFO_WM_TH :2; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_WM_TH2 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_WM_TH :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_SIGNAL_PATH_RESET { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 TEMP_RST :1; + u8 ACCEL_RST :1; + u8 FIFO_WM_TH :6; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ACCEL_INTEL_CTRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WOM_TH_MODE :1; + u8 OUTPUT_LIMIT :1; + u8 RESERVE0 :4; + u8 ACCEL_INTEL_MODE :1; + u8 ACCEL_INTEL_EN :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_USER_CTRL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 SIG_COND_RST :1; + u8 RESERVE2 :1; + u8 FIFO_RST :1; + u8 RESERVE1 :3; + u8 FIFO_EN :1; + u8 RESERVE0 :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_PWR_MGMT_1 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 CLKSEL :3; + u8 TEMP_DIS :1; + u8 GYRO_STANDBY :1; + u8 CYCLE :1; + u8 SLEEP :1; + u8 DEVICE_RESET :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_PWR_MGMT_2 { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 STBY_ZG :1; + u8 STBY_YG :1; + u8 STBY_XG :1; + u8 STBY_ZA :1; + u8 STBY_YA :1; + u8 STBY_XA :1; + u8 RESERVE0 :2; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_I2C_IF { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 RESERVE1 :6; + u8 I2C_IF_DIS :1; + u8 RESERVE0 :1; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_COUNTH { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_COUNT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_COUNTL { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_COUNT :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_FIFO_R_W { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 FIFO_DATA :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_WHO_AM_I { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 WHOAMI :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XA_OFFSET_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_XA_OFFSET_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 XA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YA_OFFSET_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_YA_OFFSET_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 YA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZA_OFFSET_H { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +struct struct_ZA_OFFSET_L { + enum inv_icm20602_reg_addr address; + union { + struct { + u8 ZA_OFFS :8; + } REG; + u8 reg; + } reg_u; +}; + +/* + * struct inv_icm20602_reg_map - Notable registers. + * @sample_rate_div: Divider applied to gyro output rate. + * @lpf: Configures internal low pass filter. + * @user_ctrl: Enables/resets the FIFO. + * @fifo_en: Determines which data will appear in FIFO. + * @gyro_config: gyro config register. + * @accl_config: accel config register + * @fifo_count_h: Upper byte of FIFO count. + * @fifo_r_w: FIFO register. + * @raw_gyro: Address of first gyro register. + * @raw_accl: Address of first accel register. + * @temperature: temperature register + * @int_enable: Interrupt enable register. + * @pwr_mgmt_1: Controls chip's power state and clock source. + * @pwr_mgmt_2: Controls power state of individual sensors. + */ +struct inv_icm20602_reg_map { + struct struct_XG_OFFS_TC_H XG_OFFS_TC_H; + struct struct_XG_OFFS_TC_L XG_OFFS_TC_L; + struct struct_YG_OFFS_TC_H YG_OFFS_TC_H; + struct struct_YG_OFFS_TC_L YG_OFFS_TC_L; + struct struct_ZG_OFFS_TC_H ZG_OFFS_TC_H; + struct struct_ZG_OFFS_TC_L ZG_OFFS_TC_L; + + struct struct_SELF_TEST_X_ACCEL SELF_TEST_X_ACCEL; + struct struct_SELF_TEST_Y_ACCEL SELF_TEST_Y_ACCEL; + struct struct_SELF_TEST_Z_ACCEL SELF_TEST_Z_ACCEL; + + struct struct_XG_OFFS_USRH XG_OFFS_USRH; + struct struct_XG_OFFS_USRL XG_OFFS_USRL; + struct struct_YG_OFFS_USRH YG_OFFS_USRH; + struct struct_YG_OFFS_USRL YG_OFFS_USRL; + struct struct_ZG_OFFS_USRH ZG_OFFS_USRH; + struct struct_ZG_OFFS_USRL ZG_OFFS_USRL; + + struct struct_SMPLRT_DIV SMPLRT_DIV; + struct struct_CONFIG CONFIG; + + struct struct_GYRO_CONFIG GYRO_CONFIG; + + struct struct_ACCEL_CONFIG ACCEL_CONFIG; + struct struct_ACCEL_CONFIG2 ACCEL_CONFIG2; + + struct struct_LP_MODE_CFG LP_MODE_CFG; + + struct struct_ACCEL_WOM_X_THR ACCEL_WOM_X_THR; + struct struct_ACCEL_WOM_Y_THR ACCEL_WOM_Y_THR; + struct struct_ACCEL_WOM_Z_THR ACCEL_WOM_Z_THR; + + struct struct_FIFO_EN FIFO_EN; + struct struct_FSYNC_INT FSYNC_INT; + struct struct_INT_PIN_CFG INT_PIN_CFG; + struct struct_INT_ENABLE INT_ENABLE; + struct struct_FIFO_WM_INT_STATUS FIFO_WM_INT_STATUS; + struct struct_INT_STATUS INT_STATUS; + + struct struct_ACCEL_XOUT_H ACCEL_XOUT_H; + struct struct_ACCEL_XOUT_L ACCEL_XOUT_L; + struct struct_ACCEL_YOUT_H ACCEL_YOUT_H; + struct struct_ACCEL_YOUT_L ACCEL_YOUT_L; + struct struct_ACCEL_ZOUT_H ACCEL_ZOUT_H; + struct struct_ACCEL_ZOUT_L ACCEL_ZOUT_L; + + struct struct_TEMP_OUT_H TEMP_OUT_H; + struct struct_TEMP_OUT_L TEMP_OUT_L; + + struct struct_GYRO_XOUT_H GYRO_XOUT_H; + struct struct_GYRO_XOUT_L GYRO_XOUT_L; + struct struct_GYRO_YOUT_H GYRO_YOUT_H; + struct struct_GYRO_YOUT_L GYRO_YOUT_L; + struct struct_GYRO_ZOUT_H GYRO_ZOUT_H; + struct struct_GYRO_ZOUT_L GYRO_ZOUT_L; + + struct struct_SELF_TEST_X_GYRO SELF_TEST_X_GYRO; + struct struct_SELF_TEST_Y_GYRO SELF_TEST_Y_GYRO; + struct struct_SELF_TEST_Z_GYRO SELF_TEST_Z_GYRO; + struct struct_FIFO_WM_TH1 FIFO_WM_TH1; + struct struct_FIFO_WM_TH2 FIFO_WM_TH2; + struct struct_SIGNAL_PATH_RESET SIGNAL_PATH_RESET; + struct struct_ACCEL_INTEL_CTRL ACCEL_INTEL_CTRL; + struct struct_USER_CTRL USER_CTRL; + + struct struct_PWR_MGMT_1 PWR_MGMT_1; + struct struct_PWR_MGMT_2 PWR_MGMT_2; + + struct struct_I2C_IF I2C_IF; + + struct struct_FIFO_COUNTH FIFO_COUNTH; + struct struct_FIFO_COUNTL FIFO_COUNTL; + struct struct_FIFO_R_W FIFO_R_W; + + struct struct_WHO_AM_I WHO_AM_I; + + struct struct_XA_OFFSET_H XA_OFFSET_H; + struct struct_XA_OFFSET_L XA_OFFSET_L; + struct struct_YA_OFFSET_H YA_OFFSET_H; + struct struct_YA_OFFSET_L YA_OFFSET_L; + struct struct_ZA_OFFSET_H ZA_OFFSET_H; + struct struct_ZA_OFFSET_L ZA_OFFSET_L; +}; + + diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c new file mode 100644 index 000000000000..0f7fc9200424 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_core.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Copyright (C) 2012 Invensense, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_icm20602_iio.h" + +/* Attribute of icm20602 device init show */ +static ssize_t inv_icm20602_init_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static void inv_icm20602_def_config(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = st->config; + + config->user_fps_in_ms = 10; + config->gyro_lpf = INV_ICM20602_GYRO_LFP_92HZ; + config->gyro_fsr = ICM20602_GYRO_FSR_1000DPS; + config->acc_lpf = ICM20602_ACCLFP_99; + config->acc_fsr = ICM20602_ACC_FSR_4G; + config->gyro_accel_sample_rate = ICM20602_SAMPLE_RATE_100HZ; + config->fifo_enabled = true; + +} + +static void inv_icm20602_load_config(struct inv_icm20602_state *st) +{ + struct icm20602_user_config *config = st->config; + + if (config->user_fps_in_ms == 0) + inv_icm20602_def_config(st); + config->fifo_enabled = true; + +} + +static ssize_t inv_icm20602_init_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int result = MPU_SUCCESS; + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + inv_icm20602_load_config(st); + result |= icm20602_detect(st); + result |= icm20602_init_device(st); + icm20602_start_fifo(st); + if (result) + return result; + + return count; +} + +static IIO_DEVICE_ATTR( + inv_icm20602_init, + 0644, + inv_icm20602_init_show, + inv_icm20602_init_store, + 0); + +/* Attribute of gyro lpf base on the enum inv_icm20602_gyro_temp_lpf_e */ +static ssize_t inv_gyro_lpf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_gyro_lpf_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int gyro_lpf; + + if (kstrtoint(buf, 10, &gyro_lpf)) + return -EINVAL; + if (gyro_lpf > INV_ICM20602_GYRO_LFP_NUM) + return -EINVAL; + config->gyro_lpf = gyro_lpf; + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_gyro_lpf, + 0644, + inv_gyro_lpf_show, + inv_gyro_lpf_store, + 0); + +/* Attribute of gyro fsr base on enum inv_icm20602_gyro_temp_lpf_e */ +static ssize_t inv_gyro_fsr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_gyro_fsr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int gyro_fsr; + + if (kstrtoint(buf, 10, &gyro_fsr)) + return -EINVAL; + if (gyro_fsr > ICM20602_GYRO_FSR_NUM) + return -EINVAL; + + config->gyro_fsr = gyro_fsr; + return count; +} + +static IIO_DEVICE_ATTR( + inv_icm20602_gyro_fsr, + 0644, + inv_gyro_fsr_show, + inv_gyro_fsr_store, + 0); + +/* Attribute of gyro_self_test */ +static ssize_t inv_gyro_self_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_gyro_self_test_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return 0; +} +static IIO_DEVICE_ATTR( + inv_icm20602_gyro_self_test, + 0644, + inv_gyro_self_test_show, + inv_gyro_self_test_store, + 0); + +/* Attribute of gyro fsr base on enum inv_icm20602_acc_fsr_e */ +static ssize_t inv_gyro_acc_fsr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_gyro_acc_fsr_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int acc_fsr; + + if (kstrtoint(buf, 10, &acc_fsr)) + return -EINVAL; + if (acc_fsr > ICM20602_ACC_FSR_NUM) + return -EINVAL; + + config->acc_fsr = acc_fsr; + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_acc_fsr, + 0644, + inv_gyro_acc_fsr_show, + inv_gyro_acc_fsr_store, + 0); + +/* Attribute of gyro fsr base on enum inv_icm20602_acc_lpf_e */ +static ssize_t inv_gyro_acc_lpf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_gyro_acc_lpf_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int acc_lpf; + + if (kstrtoint(buf, 10, &acc_lpf)) + return -EINVAL; + if (acc_lpf > ICM20602_ACCLPF_NUM) + return -EINVAL; + + config->acc_fsr = acc_lpf; + return count; +} +static IIO_DEVICE_ATTR( + inv_icm20602_acc_lpf, + 0644, + inv_gyro_acc_lpf_show, + inv_gyro_acc_lpf_store, + 0); + +/* Attribute of acc_self_test */ +static ssize_t inv_acc_self_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_acc_self_test_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return 0; +} +static IIO_DEVICE_ATTR( + inv_icm20602_acc_self_test, + 0644, + inv_acc_self_test_show, + inv_acc_self_test_store, + 0); + +/* Attribute of user_fps_in_ms */ +static ssize_t inv_user_fps_in_ms_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_user_fps_in_ms_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int user_fps_in_ms; + + if (kstrtoint(buf, 10, &user_fps_in_ms)) + return -EINVAL; + if (user_fps_in_ms < 10) + return -EINVAL; + + config->user_fps_in_ms = user_fps_in_ms; + return count; +} +static IIO_DEVICE_ATTR( + inv_user_fps_in_ms, + 0644, + inv_user_fps_in_ms_show, + inv_user_fps_in_ms_store, + 0); + +/* Attribute of gyro_accel_sample_rate */ +static ssize_t inv_sampling_frequency_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t inv_sampling_frequency_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + return 0; +} +static IIO_DEV_ATTR_SAMP_FREQ( + 0644, + inv_sampling_frequency_show, + inv_sampling_frequency_store); + +static struct attribute *inv_icm20602_attributes[] = { + &iio_dev_attr_inv_icm20602_init.dev_attr.attr, + + &iio_dev_attr_inv_icm20602_gyro_self_test.dev_attr.attr, + &iio_dev_attr_inv_icm20602_gyro_fsr.dev_attr.attr, + &iio_dev_attr_inv_icm20602_gyro_lpf.dev_attr.attr, + + &iio_dev_attr_inv_icm20602_acc_self_test.dev_attr.attr, + &iio_dev_attr_inv_icm20602_acc_fsr.dev_attr.attr, + &iio_dev_attr_inv_icm20602_acc_lpf.dev_attr.attr, + + &iio_dev_attr_sampling_frequency.dev_attr.attr, + + &iio_dev_attr_inv_user_fps_in_ms.dev_attr.attr, + NULL, +}; + +#define INV_ICM20602_CHAN(_type, _channel2, _index) \ +{ \ + .type = _type, \ + .modified = 1, \ + .channel2 = _channel2, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_index = _index, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 16, \ + .storagebits = 16, \ + .shift = 0, \ + .endianness = IIO_BE, \ + }, \ +} + +static const struct iio_chan_spec inv_icm20602_channels[] = { + IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP), + + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) + | BIT(IIO_CHAN_INFO_OFFSET) + | BIT(IIO_CHAN_INFO_SCALE), + .scan_index = INV_ICM20602_SCAN_TEMP, + .channel2 = IIO_MOD_X, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .shift = 0, + .endianness = IIO_BE, + }, + }, + INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_ICM20602_SCAN_GYRO_X), + INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_ICM20602_SCAN_GYRO_Y), + INV_ICM20602_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_ICM20602_SCAN_GYRO_Z), + + INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_X, INV_ICM20602_SCAN_ACCL_X), + INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_ICM20602_SCAN_ACCL_Y), + INV_ICM20602_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_ICM20602_SCAN_ACCL_Z), +}; + +static const struct attribute_group inv_icm20602_attribute_group = { + .attrs = inv_icm20602_attributes, +}; + +static const struct iio_info icm20602_info = { + .driver_module = THIS_MODULE, + .read_raw = NULL, + .write_raw = NULL, + .attrs = &inv_icm20602_attribute_group, + .validate_trigger = inv_icm20602_validate_trigger, +}; + +static int of_populate_icm20602_dt(struct inv_icm20602_state *st) +{ + int result = MPU_SUCCESS; + + /* use client device irq */ + st->gpio = of_get_named_gpio(st->client->dev.of_node, + "invensense,icm20602-gpio", 0); + result = gpio_is_valid(st->gpio); + if (!result) { + pr_err("gpio_is_valid %d failed\n", st->gpio); + return -MPU_FAIL; + } + + result = gpio_request(st->gpio, "icm20602-irq"); + if (result) { + pr_err("gpio_request failed\n"); + return -MPU_FAIL; + } + + result = gpio_direction_input(st->gpio); + if (result) { + pr_err("gpio_direction_input failed\n"); + return -MPU_FAIL; + } + + st->client->irq = gpio_to_irq(st->gpio); + if (st->client->irq < 0) { + pr_err("gpio_to_irq failed\n"); + return -MPU_FAIL; + } + + return MPU_SUCCESS; +} + +/* + * inv_icm20602_probe() - probe function. + * @client: i2c client. + * @id: i2c device id. + * + * Returns 0 on success, a negative error code otherwise. + * The I2C address of the ICM-20602 is 0x68 or 0x69 + * depending upon the value driven on AD0 pin. + */ +static int inv_icm20602_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct inv_icm20602_state *st; + struct iio_dev *indio_dev; + int result = MPU_SUCCESS; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (indio_dev == NULL) { + result = -ENOMEM; + goto out_remove_trigger; + } + st = iio_priv(indio_dev); + st->client = client; + st->interface = ICM20602_I2C; + + pr_debug("i2c address is %x\n", client->addr); + result = of_populate_icm20602_dt(st); + if (result) + return result; + + st->config = kzalloc(sizeof(struct icm20602_user_config), GFP_ATOMIC); + if (st->config == NULL) + return -ENOMEM; + + icm20602_init_reg_map(); + + i2c_set_clientdata(client, indio_dev); + + dev_set_drvdata(&client->dev, indio_dev); + indio_dev->dev.parent = &client->dev; + indio_dev->name = ICM20602_DEV_NAME; + indio_dev->channels = inv_icm20602_channels; + indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels); + + indio_dev->info = &icm20602_info; + indio_dev->modes = INDIO_BUFFER_TRIGGERED; + result = iio_triggered_buffer_setup(indio_dev, + inv_icm20602_irq_handler, inv_icm20602_read_fifo_fn, NULL); + if (result) { + dev_err(&st->client->dev, " configure buffer fail %d\n", + result); + goto out_remove_trigger; + } + + result = inv_icm20602_probe_trigger(indio_dev); + if (result) { + dev_err(&st->client->dev, "trigger probe fail %d\n", result); + goto out_unreg_ring; + } + + INIT_KFIFO(st->timestamps); + spin_lock_init(&st->time_stamp_lock); + result = iio_device_register(indio_dev); + if (result) { + dev_err(&st->client->dev, "IIO register fail %d\n", result); + goto out_remove_trigger; + } + + return 0; + +out_remove_trigger: + inv_icm20602_remove_trigger(st); +out_unreg_ring: + iio_triggered_buffer_cleanup(indio_dev); +out_free: + iio_device_free(indio_dev); + gpio_free(st->gpio); + + return 0; +} + +static int inv_icm20602_remove(struct i2c_client *client) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(client); + struct inv_icm20602_state *st = iio_priv(indio_dev); + + gpio_free(st->gpio); + iio_device_unregister(indio_dev); + inv_icm20602_remove_trigger(st); + iio_triggered_buffer_cleanup(indio_dev); + iio_device_free(indio_dev); + + return 0; +} + +static int inv_icm20602_suspend(struct device *dev) +{ + return 0; +} + +static int inv_icm20602_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops icm20602_pm_ops = { + .resume = inv_icm20602_resume, + .suspend = inv_icm20602_suspend, +}; + +static const struct of_device_id icm20602_match_table[] = { + {.compatible = "invensense,icm20602"}, + {} +}; +MODULE_DEVICE_TABLE(of, icm20602_match_table); + +static const struct i2c_device_id inv_icm20602_id[] = { + {"icm20602", 0}, + {} +}; + +static struct i2c_driver icm20602_i2c_driver = { + .probe = inv_icm20602_probe, + .remove = inv_icm20602_remove, + .id_table = inv_icm20602_id, + .driver = { + .owner = THIS_MODULE, + .name = "inv-icm20602", + .of_match_table = icm20602_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + .pm = &icm20602_pm_ops, + }, +}; + +static int __init inv_icm20602_init(void) +{ + return i2c_add_driver(&icm20602_i2c_driver); +} +module_init(inv_icm20602_init); + +static void __exit inv_icm20602_exit(void) +{ + i2c_del_driver(&icm20602_i2c_driver); +} +module_exit(inv_icm20602_exit); + +MODULE_DESCRIPTION("icm20602 IMU driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h new file mode 100644 index 000000000000..943fc1e6ee28 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_iio.h @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Copyright (C) 2012 Invensense, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _INV_ICM20602_IIO_H_ +#define _INV_ICM20602_IIO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * it uses sensor irq to trigger + * if set INV20602_DEVICE_IRQ_TRIGGER as 1, + * otherwise use SMD IRQ to trigger + */ +#define INV20602_DEVICE_IRQ_TRIGGER 0 + +#if INV20602_DEVICE_IRQ_TRIGGER +#define INV20602_SMD_IRQ_TRIGGER 0 +#else +#define INV20602_SMD_IRQ_TRIGGER 1 +#endif + +#define INV_ICM20602_TIME_STAMP_TOR 5 +#define ICM20602_PACKAGE_SIZE 14 + +/* device enum */ +enum inv_devices { + INV_ICM20602, + INV_NUM_PARTS, +}; + +enum _mpu_err { + MPU_SUCCESS = 0, + MPU_FAIL = 1, + MPU_READ_FAIL = 2, + MPU_WRITE_FAIL = 3, +}; + +/* Gyro Full Scale Range Enum */ +enum inv_icm20602_gyro_fsr_e { + ICM20602_GYRO_FSR_250DPS = 0, + ICM20602_GYRO_FSR_500DPS, + ICM20602_GYRO_FSR_1000DPS, + ICM20602_GYRO_FSR_2000DPS, + ICM20602_GYRO_FSR_NUM, +}; + +/* Accelerometor Full Scale Range Enum */ +enum inv_icm20602_acc_fsr_e { + ICM20602_ACC_FSR_2G = 0, + ICM20602_ACC_FSR_4G, + ICM20602_ACC_FSR_8G, + ICM20602_ACC_FSR_16G, + ICM20602_ACC_FSR_NUM, +}; + +/* scan element definition */ +enum inv_icm20602_scan { + INV_ICM20602_SCAN_ACCL_X, + INV_ICM20602_SCAN_ACCL_Y, + INV_ICM20602_SCAN_ACCL_Z, + INV_ICM20602_SCAN_GYRO_X, + INV_ICM20602_SCAN_GYRO_Y, + INV_ICM20602_SCAN_GYRO_Z, + INV_ICM20602_SCAN_TEMP, + INV_ICM20602_SCAN_TIMESTAMP, +}; + +/* this is for CONFIGURATION reg bit[2:0] DLFP_CFG */ +enum inv_icm20602_gyro_temp_lpf_e { + INV_ICM20602_GLFP_250HZ = 0, /* 8KHz */ + INV_ICM20602_GYRO_LFP_176HZ, /* 1KHz */ + INV_ICM20602_GYRO_LFP_92HZ, + INV_ICM20602_GYRO_LFP_41HZ, + INV_ICM20602_GYRO_LFP_20HZ, + INV_ICM20602_GYRO_LFP_10HZ, + INV_ICM20602_GYRO_LFP_5HZ, + INV_ICM20602_GYRO_LFP_NUM, +}; + +enum inv_icm20602_gyro_sample_rate_e { + ICM20602_SAMPLE_RATE_100HZ = 100, + ICM20602_SAMPLE_RATE_200HZ = 200, + ICM20602_SAMPLE_RATE_500HZ = 500, + ICM20602_SAMPLE_RATE_1000HZ = 1000, +}; + +/* this is for ACCEL CONFIGURATION 2 reg */ +enum inv_icm20602_acc_lpf_e { + ICM20602_ACCLFP_218 = 1, + ICM20602_ACCLFP_99, + ICM20602_ACCLFP_44, + ICM20602_ACCLFP_21, + ICM20602_ACCLFP_10, + ICM20602_ACCLFP_5, + ICM20602_ACCLFP_420_NOLPF, + ICM20602_ACCLPF_NUM = 7, +}; + +/* IIO attribute address */ +enum INV_ICM20602_IIO_ATTR_ADDR { + ATTR_ICM20602_GYRO_MATRIX, + ATTR_ICM20602_ACCL_MATRIX, +}; + +/* this is for GYRO CONFIGURATION reg */ +enum inv_icm20602_fs_e { + INV_ICM20602_FS_250DPS = 0, + INV_ICM20602_FS_500DPS, + INV_ICM20602_FS_1000DPS, + INV_ICM20602_FS_2000DPS, + NUM_ICM20602_FS, +}; + +enum inv_icm20602_clock_sel_e { + INV_ICM20602_CLK_INTERNAL = 0, + INV_ICM20602_CLK_PLL, + INV_NUM_CLK, +}; + +enum inv_icm20602_spi_freq { + MPU_SPI_FREQUENCY_1MHZ = 960000UL, + MPU_SPI_FREQUENCY_5MHZ = 4800000UL, + MPU_SPI_FREQUENCY_8MHZ = 8000000UL, + MPU_SPI_FREQUENCY_10MHZ = 10000000UL, + MPU_SPI_FREQUENCY_15MHZ = 15000000UL, + MPU_SPI_FREQUENCY_20MHZ = 20000000UL, +}; + +#define MPU_SPI_BUF_LEN 512 +#define ICM20602_DEV_NAME "icm20602_iio" + +struct inv_icm20602_platform_data { + __s8 orientation[9]; +}; + +struct X_Y_Z { + u8 X; + u8 Y; + u8 Z; +}; + +enum RAW_TYPE { + ACCEL = 1, + GYRO = 2, + TEMP = 4, +}; + +struct icm20602_user_config { + enum inv_icm20602_gyro_temp_lpf_e gyro_lpf; + enum inv_icm20602_gyro_fsr_e gyro_fsr; + struct X_Y_Z gyro_self_test; + + enum inv_icm20602_acc_lpf_e acc_lpf; + enum inv_icm20602_acc_fsr_e acc_fsr; + struct X_Y_Z acc_self_test; + + uint32_t gyro_accel_sample_rate; + uint32_t user_fps_in_ms; + + bool fifo_enabled; + uint32_t fifo_waterlevel; + struct X_Y_Z wake_on_motion; +}; + +enum inv_icm20602_interface { + ICM20602_I2C = 0, + ICM20602_SPI +}; + +/* + * struct inv_icm20602_state - Driver state variables. + * @TIMESTAMP_FIFO_SIZE: fifo size for timestamp. + * @trig: IIO trigger. + * @chip_config: Cached attribute information. + * @reg: Map of important registers. + * @hw: Other hardware-specific information. + * @chip_type: chip type. + * @time_stamp_lock: spin lock to time stamp. + * @spi: spi devices + * @plat_data: platform data. + * @timestamps: kfifo queue to store time stamp. + */ +struct inv_icm20602_state { +#define TIMESTAMP_FIFO_SIZE 32 + enum inv_icm20602_interface interface; + struct iio_trigger *trig; + const struct inv_icm20602_reg_map *reg; + struct icm20602_user_config *config; + spinlock_t time_stamp_lock; + struct spi_device *spi; + struct i2c_client *client; + u8 fifo_packet_size; + int fifo_cnt_threshold; + char *buf; + struct struct_icm20602_data *data_push; + enum inv_devices chip_type; + int gpio; + DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE); +}; + +struct struct_icm20602_raw_data { + u8 ACCEL_XOUT_H; + u8 ACCEL_XOUT_L; + + u8 ACCEL_YOUT_H; + u8 ACCEL_YOUT_L; + + u8 ACCEL_ZOUT_H; + u8 ACCEL_ZOUT_L; + + u8 TEMP_OUT_H; + u8 TEMP_OUT_L; + + u8 GYRO_XOUT_H; + u8 GYRO_XOUT_L; + + u8 GYRO_YOUT_H; + u8 GYRO_YOUT_L; + + u8 GYRO_ZOUT_H; + u8 GYRO_ZOUT_L; +}; + +struct struct_icm20602_real_data { + u16 ACCEL_XOUT; + u16 ACCEL_YOUT; + u16 ACCEL_ZOUT; + + u16 GYRO_XOUT; + u16 GYRO_YOUT; + u16 GYRO_ZOUT; + + u16 TEMP_OUT; +}; + +struct struct_icm20602_data { + s64 timestamps; + struct struct_icm20602_raw_data raw_data; + struct struct_icm20602_real_data real_data; +}; + +extern struct iio_trigger *inv_trig; +irqreturn_t inv_icm20602_irq_handler(int irq, void *p); +irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p); +int inv_icm20602_reset_fifo(struct iio_dev *indio_dev); + +int inv_icm20602_probe_trigger(struct iio_dev *indio_dev); +void inv_icm20602_remove_trigger(struct inv_icm20602_state *st); +int inv_icm20602_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig); + +int icm20602_read_raw(struct inv_icm20602_state *st, + struct struct_icm20602_real_data *real_data, uint32_t type); +int icm20602_init_reg_map(void); +int icm20602_init_device(struct inv_icm20602_state *st); +int icm20602_detect(struct inv_icm20602_state *st); +int icm20602_read_fifo(struct inv_icm20602_state *st, + void *buf, const int size); +int icm20602_start_fifo(struct inv_icm20602_state *st); +#endif diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c new file mode 100644 index 000000000000..b0f93be33340 --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_ring.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Copyright (C) 2012 Invensense, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inv_icm20602_iio.h" +#include + +#define combine_8_to_16(upper, lower) ((_upper << 8) | _lower) + +static void inv_clear_kfifo(struct inv_icm20602_state *st) +{ + unsigned long flags; + + /* Take the spin lock sem to avoid interrupt kick in */ + spin_lock_irqsave(&st->time_stamp_lock, flags); + kfifo_reset(&st->timestamps); + spin_unlock_irqrestore(&st->time_stamp_lock, flags); +} + +int inv_icm20602_reset_fifo(struct iio_dev *indio_dev) +{ + int result; + //u8 d; + //struct inv_icm20602_state *st = iio_priv(indio_dev); + + return result; +} + +/* + * inv_icm20602_irq_handler() - Cache a timestamp at each data ready interrupt. + */ +irqreturn_t inv_icm20602_irq_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct inv_icm20602_state *st = iio_priv(indio_dev); + s64 timestamp; + + timestamp = iio_get_time_ns(indio_dev); + + kfifo_in_spinlocked(&st->timestamps, ×tamp, 1, + &st->time_stamp_lock); + + return IRQ_WAKE_THREAD; +} + +static int inv_icm20602_read_data(struct iio_dev *indio_dev) +{ + int result = MPU_SUCCESS; + struct inv_icm20602_state *st = iio_priv(indio_dev); + struct icm20602_user_config *config = st->config; + int package_count; + //char *buf = st->buf; + //struct struct_icm20602_data *data_push = st->data_push; + s64 timestamp; + int i; + + if (!st) + return -MPU_FAIL; + package_count = config->fifo_waterlevel / ICM20602_PACKAGE_SIZE; + mutex_lock(&indio_dev->mlock); + if (config->fifo_enabled) { + result = icm20602_read_fifo(st, + st->buf, config->fifo_waterlevel); + if (result != config->fifo_waterlevel) { + pr_err("icm20602 read fifo failed, result = %d\n", + result); + goto flush_fifo; + } + + for (i = 0; i < package_count; i++) { + memcpy((char *)(&st->data_push[i].raw_data), + st->buf, ICM20602_PACKAGE_SIZE); + result = kfifo_out(&st->timestamps, + ×tamp, 1); + /* when there is no timestamp, put it as 0 */ + if (result == 0) + timestamp = 0; + st->data_push[i].timestamps = timestamp; + iio_push_to_buffers(indio_dev, st->data_push+i); + st->buf += ICM20602_PACKAGE_SIZE; + } + } +//end_session: + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + return MPU_SUCCESS; + +flush_fifo: + /* Flush HW and SW FIFOs. */ + inv_clear_kfifo(st); + inv_icm20602_reset_fifo(indio_dev); + mutex_unlock(&indio_dev->mlock); + iio_trigger_notify_done(indio_dev->trig); + return MPU_SUCCESS; +} + +/* + * inv_icm20602_read_fifo() - Transfer data from hardware FIFO to KFIFO. + */ +irqreturn_t inv_icm20602_read_fifo_fn(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + + inv_icm20602_read_data(indio_dev); + return IRQ_HANDLED; +} diff --git a/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c new file mode 100644 index 000000000000..f05a6318fb6a --- /dev/null +++ b/drivers/iio/imu/inv_icm20602/inv_icm20602_trigger.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Copyright (C) 2012 Invensense, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include "inv_icm20602_iio.h" +#include + +static const struct iio_trigger_ops inv_icm20602_trigger_ops = { + .owner = THIS_MODULE, +}; + +int inv_icm20602_validate_trigger(struct iio_dev *indio_dev, + struct iio_trigger *trig) +{ + struct inv_icm20602_state *st = iio_priv(indio_dev); + + if (st->trig != trig) + return -EINVAL; + + return 0; +} + +int inv_icm20602_probe_trigger(struct iio_dev *indio_dev) +{ + int ret; + struct inv_icm20602_state *st = iio_priv(indio_dev); + + st->trig = iio_trigger_alloc("%s-dev%d", + indio_dev->name, + indio_dev->id); + if (st->trig == NULL) { + ret = -ENOMEM; + goto error_ret; + } + + ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll, + IRQF_TRIGGER_RISING, + "inv_icm20602", + st->trig); + if (ret) { + pr_err("request_irq failed\n"); + goto error_free_trig; + } + st->trig->dev.parent = &st->client->dev; + st->trig->ops = &inv_icm20602_trigger_ops; + iio_trigger_set_drvdata(st->trig, indio_dev); + ret = iio_trigger_register(st->trig); + if (ret) { + pr_err("iio_trigger_register failed\n"); + goto error_free_irq; + } + indio_dev->trig = st->trig; + + return 0; + +error_free_irq: + free_irq(st->client->irq, st->trig); +error_free_trig: + iio_trigger_free(st->trig); +error_ret: + return ret; +} + +void inv_icm20602_remove_trigger(struct inv_icm20602_state *st) +{ + iio_trigger_unregister(st->trig); + free_irq(st->client->irq, st->trig); + iio_trigger_free(st->trig); +} -- GitLab From c9bd286d11a5eb486fabc4fb6fd8c2ab231ee1ac Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Tue, 8 May 2018 16:19:52 +0530 Subject: [PATCH 1735/1834] defconfig: Enable crypto and quota2 configurations for msm8909w Enable crypto accelerator support and quota2 log support for msm8909w target. Change-Id: Ie4ef46807ffd518a12e96c357cfa938255c1299a Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909w-perf_defconfig | 2 ++ arch/arm/configs/msm8909w_defconfig | 1 + 2 files changed, 3 insertions(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 9b5574004872..4933e4cf71cd 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -132,6 +132,7 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y @@ -498,6 +499,7 @@ CONFIG_CRYPTO_TWOFISH=y CONFIG_CRYPTO_ANSI_CPRNG=y CONFIG_CRYPTO_DEV_QCE=y CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y CONFIG_CRYPTO_DEV_QCEDEV=y CONFIG_CRYPTO_DEV_OTA_CRYPTO=y CONFIG_CRYPTO_DEV_QCOM_ICE=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index bb6bc88e548f..7cbc1a5e6680 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -141,6 +141,7 @@ CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y CONFIG_NETFILTER_XT_MATCH_QTAGUID=y CONFIG_NETFILTER_XT_MATCH_QUOTA=y CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y CONFIG_NETFILTER_XT_MATCH_SOCKET=y CONFIG_NETFILTER_XT_MATCH_STATE=y CONFIG_NETFILTER_XT_MATCH_STATISTIC=y -- GitLab From ea220e212d26a367823aca207a50c5d7823e0484 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Mon, 7 May 2018 20:25:51 +0530 Subject: [PATCH 1736/1834] defconfig: msm: Enable kernel security configurations on msm8909w Enable kernel config to get stack canary protection as REGULAR. Change-Id: I3baffaf8e4f35f79034239fab27e3dc77d47a3da Signed-off-by: Sundara Vinayagam --- arch/arm/configs/msm8909w-perf_defconfig | 2 +- arch/arm/configs/msm8909w_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 9b5574004872..5eedf38929ac 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -30,7 +30,7 @@ CONFIG_BPF_SYSCALL=y CONFIG_EMBEDDED=y CONFIG_PROFILING=y CONFIG_OPROFILE=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index bb6bc88e548f..f529f587fcb6 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -34,7 +34,7 @@ CONFIG_BPF_SYSCALL=y CONFIG_EMBEDDED=y CONFIG_PROFILING=y CONFIG_OPROFILE=y -CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_CC_STACKPROTECTOR_REGULAR=y CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y -- GitLab From 241a0d7bfb107d80d29d86519cfe7b003bbb51a8 Mon Sep 17 00:00:00 2001 From: Hareesh Gundu Date: Fri, 6 Apr 2018 11:16:36 +0530 Subject: [PATCH 1737/1834] ARM: dts: msm: Update GPU chipid for SDM429 The SDM429 GPU is similar to SDM439 but has different clock plan. Update SDM429 GPU ID to A504 so that we can handle it. Change-Id: I6bf6c7f020272eadb378df3c00af867f053d13b2 Signed-off-by: Hareesh Gundu --- arch/arm64/boot/dts/qcom/sdm429.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm429.dtsi b/arch/arm64/boot/dts/qcom/sdm429.dtsi index 24e99053ba2c..19df05491c49 100644 --- a/arch/arm64/boot/dts/qcom/sdm429.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm429.dtsi @@ -207,3 +207,9 @@ "byte1_src"; #clock-cells = <1>; }; + +/* GPU overrides */ +&msm_gpu { + /* Update GPU chip ID*/ + qcom,chipid = <0x05000400>; +}; -- GitLab From f9b990c5aed07308f472016d81ce2b2c8906bb13 Mon Sep 17 00:00:00 2001 From: Shadab Naseem Date: Sat, 12 May 2018 21:52:43 +0530 Subject: [PATCH 1738/1834] drivers: pil-msa: Increase timeout for modem ramdump encryption Increase timeout to 13 seconds for modem ramdump encryption. At the lowest frequency, the 10sec timeout was not sufficient for encryption to get completed. Change-Id: I6103b048c89ca520a6f75bdb5c1834433b6f530c Signed-off-by: Shadab Naseem --- drivers/soc/qcom/pil-msa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index 6283477a7952..0c3a5c1a30a5 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -836,7 +836,7 @@ int pil_mss_debug_reset(struct pil_desc *pil) * complete before returning */ pr_info("Minidump: waiting encryption to complete\n"); - msleep(10000); + msleep(13000); if (pil->minidump_ss) { writel_relaxed(0x2, drv->reg_base + QDSP6SS_NMI_CFG); /* Let write complete before proceeding */ -- GitLab From cb37c71931563b23d6a45cf87a0db58165d3fa19 Mon Sep 17 00:00:00 2001 From: Vaishnavi Kommaraju Date: Mon, 9 Apr 2018 13:01:48 +0530 Subject: [PATCH 1739/1834] ARM: dts: msm: Add external codec support for SDM439 Add audio support for external codec on SDM439. Change-Id: I9ce544e545d1303077946a7bc1396f4ef4a3704b Signed-off-by: Vaishnavi Kommaraju --- arch/arm64/boot/dts/qcom/msm8937-audio.dtsi | 77 +++++++++++++------ arch/arm64/boot/dts/qcom/sdm439-audio.dtsi | 59 ++++++++++++++ .../boot/dts/qcom/sdm439-ext-audio-mtp.dtsi | 77 +++++++++++++++++++ .../arm64/boot/dts/qcom/sdm439-regulator.dtsi | 7 ++ arch/arm64/boot/dts/qcom/sdm439.dtsi | 1 + 5 files changed, 199 insertions(+), 22 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi index 2e4d38ecaf29..ffc266fb626c 100644 --- a/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937-audio.dtsi @@ -240,16 +240,23 @@ "SpkrRight IN", "SPK2 OUT"; qcom,tasha-mclk-clk-freq = <9600000>; + qcom,cdc-us-euro-gpios = <&tlmm 63 0>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; + qcom,cdc-us-eu-gpios = <&cdc_us_euro_sw>; + qcom,quin-mi2s-gpios = <&cdc_quin_mi2s_gpios>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, - <&afe>, <&lsm>, <&routing>; + <&afe>, <&lsm>, <&routing>, <&cpe>, + <&pcm_noirq>; asoc-platform-names = "msm-pcm-dsp.0", "msm-pcm-dsp.1", "msm-pcm-dsp.2", "msm-voip-dsp", "msm-pcm-voice", "msm-pcm-loopback", "msm-compress-dsp", "msm-pcm-hostless", "msm-pcm-afe", "msm-lsm-client", - "msm-pcm-routing"; + "msm-pcm-routing", "msm-cpe-lsm", + "msm-pcm-dsp-noirq"; asoc-cpu = <&dai_pri_auxpcm>, <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>, @@ -281,9 +288,6 @@ asoc-codec = <&stub_codec>, <&hdmi_dba>; asoc-codec-names = "msm-stub-codec.1", "msm-hdmi-dba-codec-rx"; - qcom,cdc-us-euro-gpios = <&tlmm 63 0>; - qcom,msm-mbhc-hphl-swh = <0>; - qcom,msm-mbhc-gnd-swh = <0>; qcom,wsa-max-devs = <2>; qcom,wsa-devs = <&wsa881x_211>, <&wsa881x_212>, @@ -292,11 +296,19 @@ "SpkrLeft", "SpkrRight"; }; + cpe: qcom,msm-cpe-lsm { + compatible = "qcom,msm-cpe-lsm"; + }; + wcd9xxx_intc: wcd9xxx-irq { status = "disabled"; + compatible = "qcom,wcd9xxx-irq"; + interrupt-controller; + #interrupt-cells = <1>; interrupt-parent = <&tlmm>; - interrupts = <73 0>; qcom,gpio-connect = <&tlmm 73 0>; + pinctrl-names = "default"; + pinctrl-0 = <&wcd_intr_default>; }; clock_audio: audio_ext_clk { @@ -306,28 +318,61 @@ qcom,node_has_rpm_clock; #clock-cells = <1>; qcom,audio-ref-clk-gpio = <&pm8937_gpios 1 0>; - qcom,lpass-mclk-id = "pri_mclk"; clocks = <&clock_gcc clk_div_clk2>; pinctrl-0 = <&cdc_mclk2_sleep>; pinctrl-1 = <&cdc_mclk2_active>; }; - wcd_rst_gpio: wcd_gpio_ctrl { + wcd_rst_gpio: msm_cdc_pinctrl { status = "disabled"; - qcom,cdc-rst-n-gpio = <&tlmm 68 0>; + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&cdc_reset_active>; + pinctrl-1 = <&cdc_reset_sleep>; }; }; &slim_msm { status = "disabled"; + + dai_slim: msm_dai_slim { + status = "disabled"; + compatible = "qcom,msm-dai-slim"; + elemental-addr = [ff ff ff fe 17 02]; + }; + wcd9335: tasha_codec { status = "disabled"; compatible = "qcom,tasha-slim-pgd"; + elemental-addr = [00 01 A0 01 17 02]; + + qcom,cdc-slim-ifd = "tasha-slim-ifd"; + qcom,cdc-slim-ifd-elemental-addr = [00 00 A0 01 17 02]; + + interrupt-parent = <&wcd9xxx_intc>; + interrupts = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 30>; + + qcom,wcd-rst-gpio-node = <&wcd_rst_gpio>; + clock-names = "wcd_clk", "wcd_native_clk"; clocks = <&clock_audio clk_audio_pmi_clk>, <&clock_audio clk_audio_ap_clk2>; - qcom,cdc-reset-gpio = <&tlmm 68 0>; + qcom,cdc-static-supplies = + "cdc-vdd-buck", + "cdc-buck-sido", + "cdc-vdd-tx-h", + "cdc-vdd-rx-h", + "cdc-vdd-px"; + qcom,cdc-on-demand-supplies = "cdc-vdd-mic-bias"; + qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias2-mv = <1800>; + qcom,cdc-micbias3-mv = <1800>; + qcom,cdc-micbias4-mv = <1800>; + + qcom,cdc-dmic-sample-rate = <2400000>; + qcom,cdc-mclk-clk-rate = <9600000>; cdc-vdd-buck-supply = <&eldo2_pm8937>; qcom,cdc-vdd-buck-voltage = <1800000 1800000>; @@ -355,18 +400,6 @@ }; }; -&pm8937_gpios { - gpio@c000 { - status = "ok"; - qcom,mode = <1>; - qcom,pull = <5>; - qcom,vin-sel = <0>; - qcom,src-sel = <2>; - qcom,master-en = <1>; - qcom,out-strength = <2>; - }; -}; - &pm8937_1 { pmic_analog_codec: analog-codec@f000 { status = "okay"; diff --git a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi index f6751d2445aa..5fc2114b2902 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-audio.dtsi @@ -24,6 +24,65 @@ qcom,msm-vdd-wsa-switch-voltage = <1800000>; qcom,msm-vdd-wsa-switch-current = <10000>; }; + + clock_audio_native: audio_ext_clk_native { + status = "disabled"; + compatible = "qcom,audio-ref-clk"; + #clock-cells = <1>; + qcom,codec-mclk-clk-freq = <11289600>; + qcom,audio-ref-clk-gpio = <&tlmm 66 0>; + qcom,lpass-mclk-id = "pri_mclk"; + pinctrl-names = "sleep", "active"; + pinctrl-0 = <&cdc_mclk2_sleep>; + pinctrl-1 = <&cdc_mclk2_active>; + }; +}; + + +&clock_audio { + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&tasha_mclk_default>; + pinctrl-1 = <&tasha_mclk_default>; + qcom,audio-ref-clk-gpio = <&pm8953_gpios 1 0>; +}; + +&wcd9335 { + cdc-vdd-buck-supply = <&dbu1>; + qcom,cdc-vdd-buck-voltage = <1800000 1800000>; + qcom,cdc-vdd-buck-current = <650000>; + + cdc-buck-sido-supply = <&dbu1>; + qcom,cdc-buck-sido-voltage = <1800000 1800000>; + qcom,cdc-buck-sido-current = <150000>; + + cdc-vdd-tx-h-supply = <&dbu1>; + qcom,cdc-vdd-tx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-tx-h-current = <25000>; + + cdc-vdd-rx-h-supply = <&dbu1>; + qcom,cdc-vdd-rx-h-voltage = <1800000 1800000>; + qcom,cdc-vdd-rx-h-current = <25000>; + + cdc-vdd-px-supply = <&dbu1>; + qcom,cdc-vdd-px-voltage = <1800000 1800000>; + qcom,cdc-vdd-px-current = <10000>; + + cdc-vdd-mic-bias-supply = <&pm8953_l13>; + qcom,cdc-vdd-mic-bias-voltage = <3075000 3075000>; + qcom,cdc-vdd-mic-bias-current = <15000>; +}; + +&pm8953_gpios { + tasha_mclk { + tasha_mclk_default: tasha_mclk_default{ + pins = "gpio1"; + function = "func1"; + qcom,drive-strength = <2>; + power-source = <0>; + bias-disable; + output-low; + }; + }; }; &pm8953_1 { diff --git a/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi b/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi new file mode 100644 index 000000000000..a74fb7588f1d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm439-ext-audio-mtp.dtsi @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&int_codec { + status = "disabled"; +}; + +&wsa881x_i2c_f { + status = "disabled"; +}; + +&wsa881x_i2c_45 { + status = "disabled"; +}; + +&cdc_pri_mi2s_gpios { + status = "disabled"; +}; + +&wsa881x_analog_vi_gpio { + status = "disabled"; +}; + +&wsa881x_analog_clk_gpio { + status = "disabled"; +}; + +&wsa881x_analog_reset_gpio { + status = "disabled"; +}; + +&slim_msm { + status = "okay"; +}; + +&dai_slim { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; + +&wcd9335 { + status = "okay"; +}; + +&cdc_us_euro_sw { + status = "okay"; +}; + +&cdc_quin_mi2s_gpios { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; +}; + diff --git a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi index f325925cdfa3..375039e3eecb 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439-regulator.dtsi @@ -469,4 +469,11 @@ qcom,cpr-voltage-scaling-factor-max = <0 2000 2000>; qcom,cpr-scaled-init-voltage-as-ceiling; }; + + dbu1: dbu1 { + compatible = "regulator-fixed"; + regulator-name = "dbu1"; + startup-delay-us = <0>; + enable-active-high; + }; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439.dtsi b/arch/arm64/boot/dts/qcom/sdm439.dtsi index 2df468fdc50d..0e4f6666462f 100644 --- a/arch/arm64/boot/dts/qcom/sdm439.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm439.dtsi @@ -14,6 +14,7 @@ #include "msm8937.dtsi" #include "sdm439-pm8953.dtsi" #include "sdm439-pmi632.dtsi" +#include "sdm439-audio.dtsi" / { model = "Qualcomm Technologies, Inc. SDM439"; -- GitLab From 3574358428e899438695383f53a04f8f94f34e87 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Sun, 13 May 2018 11:32:04 +0300 Subject: [PATCH 1740/1834] wil6210: Allow run-time PM in case platform ops defined Run-time PM is need to be allowed only in case platform ops defined. Change-Id: I86f11111f7361797263031c45c28249ab206fe72 Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/pm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 14533edc5833..0a96518a566f 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -33,7 +33,11 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) if (wmi_only || debug_fw) { wil_dbg_pm(wil, "Deny any suspend - %s mode\n", wmi_only ? "wmi_only" : "debug_fw"); - rc = -EPERM; + rc = -EBUSY; + goto out; + } + if (is_runtime && !wil->platform_ops.suspend) { + rc = -EBUSY; goto out; } if (!(ndev->flags & IFF_UP)) { -- GitLab From b7f1bce3a122497ceefadfb0c983e4c172988d20 Mon Sep 17 00:00:00 2001 From: Alexei Avshalom Lazar Date: Sun, 13 May 2018 11:34:06 +0300 Subject: [PATCH 1741/1834] wil6210: Enable run-time PM for all power management states wil6210_resume/wil6210_suspend/wil6210_pm_notify function is used for all power management states and not only for hibernate/sleep states. Change-Id: I86b6a34cb23705fc17b7cb6e55bbe62aae63ebcf Signed-off-by: Alexei Avshalom Lazar --- drivers/net/wireless/ath/wil6210/pcie_bus.c | 10 ++-------- drivers/net/wireless/ath/wil6210/wil6210.h | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 1875387d0eee..0f34c43a3eaa 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -33,10 +33,8 @@ module_param(ftm_mode, bool, 0444); MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false"); #ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP static int wil6210_pm_notify(struct notifier_block *notify_block, unsigned long mode, void *unused); -#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ static @@ -354,7 +352,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) } #ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP wil->pm_notify.notifier_call = wil6210_pm_notify; rc = register_pm_notifier(&wil->pm_notify); if (rc) @@ -362,7 +359,6 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) * be prevented in a later phase if needed */ wil_err(wil, "register_pm_notifier failed: %d\n", rc); -#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ wil6210_debugfs_init(wil); @@ -397,9 +393,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) wil_dbg_misc(wil, "pcie_remove\n"); #ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP unregister_pm_notifier(&wil->pm_notify); -#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ wil_pm_runtime_forbid(wil); @@ -428,7 +422,6 @@ static const struct pci_device_id wil6210_pcie_ids[] = { MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); #ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP static int wil6210_suspend(struct device *dev, bool is_runtime) { @@ -546,7 +539,6 @@ static int wil6210_pm_resume(struct device *dev) { return wil6210_resume(dev, false); } -#endif /* CONFIG_PM_SLEEP */ static int wil6210_pm_runtime_idle(struct device *dev) { @@ -578,10 +570,12 @@ static int wil6210_pm_runtime_suspend(struct device *dev) #endif /* CONFIG_PM */ static const struct dev_pm_ops wil6210_pm_ops = { +#ifdef CONFIG_PM SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend, wil6210_pm_runtime_resume, wil6210_pm_runtime_idle) +#endif /* CONFIG_PM */ }; static struct pci_driver wil6210_driver = { diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 9b68663d87cd..f4476ee4f870 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -798,9 +798,7 @@ struct wil6210_priv { int fw_calib_result; #ifdef CONFIG_PM -#ifdef CONFIG_PM_SLEEP struct notifier_block pm_notify; -#endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ bool suspend_resp_rcvd; -- GitLab From e3ec2821b2c489119f230d82e82c99724b93104c Mon Sep 17 00:00:00 2001 From: Gaurav Kohli Date: Tue, 24 Apr 2018 12:13:34 +0530 Subject: [PATCH 1742/1834] kthread/smpboot: Serialize kthread parking against wakeup The control cpu thread which initiates hotplug calls kthread_park() for hotplug thread and sets KTHREAD_SHOULD_PARK. After this control thread wakes up the hotplug thread. There is a chance that wakeup code sees the hotplug thread (running on AP core) in INTERRUPTIBLE state, but sets its state to RUNNING after hotplug thread has entered kthread_parkme() and changed its state to TASK_PARKED. This can result in panic later on in kthread_unpark(), as it sees KTHREAD_IS_PARKED flag set but fails to rebind the kthread, due to it being not in TASK_PARKED state. Fix this, by serializing wakeup state change, against state change before parking the kthread. Below is the possible race: Control thread Hotplug Thread kthread_park() set KTHREAD_SHOULD_PARK smpboot_thread_fn set_current_state(TASK_INTERRUPTIBLE); kthread_parkme wake_up_process() raw_spin_lock_irqsave(&p->pi_lock, flags); if (!(p->state & state)) -> this will fail goto out; __kthread_parkme __set_current_state(TASK_PARKED); if (p->on_rq && ttwu_remote(p, wake_flags)) ttwu_remote() p->state = TASK_RUNNING; schedule(); So to avoid this race, take pi_lock to serial state changes. Change-Id: Ie71645d37046f7ee74df880dbead29efbaad199a Suggested-by: Pavankumar Kondeti Signed-off-by: Neeraj Upadhyay Signed-off-by: Gaurav Kohli --- kernel/smpboot.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/kernel/smpboot.c b/kernel/smpboot.c index 1650578045fc..10c5a3a8d638 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c @@ -121,7 +121,45 @@ static int smpboot_thread_fn(void *data) } if (kthread_should_park()) { + /* + * Serialize against wakeup. If we take the lock first, + * wakeup is skipped. If we run later, we observe, + * TASK_RUNNING update from wakeup path, before moving + * forward. This helps avoid the race, where wakeup + * observes TASK_INTERRUPTIBLE, and also observes + * the TASK_PARKED in kthread_parkme() before updating + * task state to TASK_RUNNING. In this case, kthread + * gets parked in TASK_RUNNING state. This results + * in panic later on in kthread_unpark(), as it sees + * KTHREAD_IS_PARKED flag set but fails to rebind the + * kthread, due to it being not in TASK_PARKED state. + * + * Control thread Hotplug Thread + * + * kthread_park() + * set KTHREAD_SHOULD_PARK + * smpboot_thread_fn() + * set_current_state( + * TASK_INTERRUPTIBLE); + * kthread_parkme() + * + * wake_up_process() + * + * raw_spin_lock_irqsave(&p->pi_lock, flags); + * if (!(p->state & state)) + * goto out; + * + * __set_current_state( + * TASK_PARKED); + * + * if (p->on_rq && ttwu_remote(p, wake_flags)) + * ttwu_remote() + * p->state = TASK_RUNNING; + * schedule(); + */ + raw_spin_lock(¤t->pi_lock); __set_current_state(TASK_RUNNING); + raw_spin_unlock(¤t->pi_lock); preempt_enable(); if (ht->park && td->status == HP_THREAD_ACTIVE) { BUG_ON(td->cpu != smp_processor_id()); -- GitLab From 33151183b27f960246c24bc3b5b542523f018f92 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Wed, 28 Mar 2018 11:44:09 -0700 Subject: [PATCH 1743/1834] drm/msm/sde: propagate frame error through fence DMA fence driver supports error status indication to fence reader. Populate the frame status for sde fences so that client can consume or discard the buffer. Change-Id: I9b10f4ff3c97aa2c018a5f0b7f40089590aac3ae Signed-off-by: Prabhanjan Kandula --- drivers/gpu/drm/msm/sde/sde_connector.c | 8 +++++--- drivers/gpu/drm/msm/sde/sde_connector.h | 4 +++- drivers/gpu/drm/msm/sde/sde_crtc.c | 18 ++++++++++++------ drivers/gpu/drm/msm/sde/sde_fence.c | 18 ++++++++++-------- drivers/gpu/drm/msm/sde/sde_fence.h | 18 +++++++++++++++--- 5 files changed, 45 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c index d2f8d12cdaa6..1fd7d669ec20 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.c +++ b/drivers/gpu/drm/msm/sde/sde_connector.c @@ -1207,7 +1207,7 @@ void sde_connector_prepare_fence(struct drm_connector *connector) } void sde_connector_complete_commit(struct drm_connector *connector, - ktime_t ts) + ktime_t ts, enum sde_fence_event fence_event) { if (!connector) { SDE_ERROR("invalid connector\n"); @@ -1215,7 +1215,8 @@ void sde_connector_complete_commit(struct drm_connector *connector, } /* signal connector's retire fence */ - sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, false); + sde_fence_signal(&to_sde_connector(connector)->retire_fence, + ts, fence_event); } void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts) @@ -1226,7 +1227,8 @@ void sde_connector_commit_reset(struct drm_connector *connector, ktime_t ts) } /* signal connector's retire fence */ - sde_fence_signal(&to_sde_connector(connector)->retire_fence, ts, true); + sde_fence_signal(&to_sde_connector(connector)->retire_fence, + ts, SDE_FENCE_RESET_TIMELINE); } static void sde_connector_update_hdr_props(struct drm_connector *connector) diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h index c6f348ec80ef..238b037566a8 100644 --- a/drivers/gpu/drm/msm/sde/sde_connector.h +++ b/drivers/gpu/drm/msm/sde/sde_connector.h @@ -583,8 +583,10 @@ void sde_connector_prepare_fence(struct drm_connector *connector); * sde_connector_complete_commit - signal completion of current commit * @connector: Pointer to drm connector object * @ts: timestamp to be updated in the fence signalling + * @fence_event: enum value to indicate nature of fence event */ -void sde_connector_complete_commit(struct drm_connector *connector, ktime_t ts); +void sde_connector_complete_commit(struct drm_connector *connector, + ktime_t ts, enum sde_fence_event fence_event); /** * sde_connector_commit_reset - reset the completion signal diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 7daab2acf8a6..af75d75e90b6 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -2243,7 +2243,8 @@ static void sde_crtc_vblank_cb(void *data) SDE_EVT32_VERBOSE(DRMID(crtc)); } -static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts) +static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts, + bool is_error) { struct sde_crtc_retire_event *retire_event; struct sde_crtc *sde_crtc; @@ -2273,8 +2274,8 @@ static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts) SDE_ATRACE_BEGIN("signal_retire_fence"); for (i = 0; (i < retire_event->num_connectors) && retire_event->connectors[i]; ++i) - sde_connector_complete_commit( - retire_event->connectors[i], ts); + sde_connector_complete_commit(retire_event->connectors[i], + ts, is_error); SDE_ATRACE_END("signal_retire_fence"); } @@ -2347,13 +2348,17 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE) { SDE_ATRACE_BEGIN("signal_release_fence"); - sde_fence_signal(&sde_crtc->output_fence, fevent->ts, false); + sde_fence_signal(&sde_crtc->output_fence, fevent->ts, + (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) + ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); SDE_ATRACE_END("signal_release_fence"); } if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE) /* this api should be called without spin_lock */ - _sde_crtc_retire_event(crtc, fevent->ts); + _sde_crtc_retire_event(crtc, fevent->ts, + (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) + ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD) SDE_ERROR("crtc%d ts:%lld received panel dead event\n", @@ -4191,7 +4196,8 @@ static void sde_crtc_disable(struct drm_crtc *crtc) * reset the fence timeline if crtc will not be enabled for this commit */ if (!crtc->state->active || !crtc->state->enable) { - sde_fence_signal(&sde_crtc->output_fence, ktime_get(), true); + sde_fence_signal(&sde_crtc->output_fence, + ktime_get(), SDE_FENCE_RESET_TIMELINE); for (i = 0; i < cstate->num_connectors; ++i) sde_connector_commit_reset(cstate->connectors[i], ktime_get()); diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c index 686c6403fcf6..1f30a5c85abc 100644 --- a/drivers/gpu/drm/msm/sde/sde_fence.c +++ b/drivers/gpu/drm/msm/sde/sde_fence.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -278,7 +278,8 @@ void sde_fence_prepare(struct sde_fence_context *ctx) } } -static void _sde_fence_trigger(struct sde_fence_context *ctx, ktime_t ts) +static void _sde_fence_trigger(struct sde_fence_context *ctx, + ktime_t ts, bool error) { unsigned long flags; struct sde_fence *fc, *next; @@ -300,6 +301,7 @@ static void _sde_fence_trigger(struct sde_fence_context *ctx, ktime_t ts) list_for_each_entry_safe(fc, next, &local_list_head, fence_list) { spin_lock_irqsave(&ctx->lock, flags); + fc->base.error = error ? -EBUSY : 0; fc->base.timestamp = ts; is_signaled = fence_is_signaled_locked(&fc->base); spin_unlock_irqrestore(&ctx->lock, flags); @@ -351,7 +353,7 @@ int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val, if (fd >= 0) { rc = 0; - _sde_fence_trigger(ctx, ktime_get()); + _sde_fence_trigger(ctx, ktime_get(), false); } else { rc = fd; } @@ -360,7 +362,7 @@ int sde_fence_create(struct sde_fence_context *ctx, uint64_t *val, } void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, - bool reset_timeline) + enum sde_fence_event fence_event) { unsigned long flags; @@ -370,7 +372,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, } spin_lock_irqsave(&ctx->lock, flags); - if (reset_timeline) { + if (fence_event == SDE_FENCE_RESET_TIMELINE) { if ((int)(ctx->done_count - ctx->commit_count) < 0) { SDE_ERROR( "timeline reset attempt! done count:%d commit:%d\n", @@ -378,7 +380,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, ctx->done_count = ctx->commit_count; SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count, ktime_to_us(ts), - reset_timeline, SDE_EVTLOG_FATAL); + fence_event, SDE_EVTLOG_FATAL); } else { spin_unlock_irqrestore(&ctx->lock, flags); return; @@ -391,7 +393,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, SDE_ERROR("extra signal attempt! done count:%d commit:%d\n", ctx->done_count, ctx->commit_count); SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count, - ktime_to_us(ts), reset_timeline, SDE_EVTLOG_FATAL); + ktime_to_us(ts), fence_event, SDE_EVTLOG_FATAL); spin_unlock_irqrestore(&ctx->lock, flags); return; } @@ -400,7 +402,7 @@ void sde_fence_signal(struct sde_fence_context *ctx, ktime_t ts, SDE_EVT32(ctx->drm_id, ctx->done_count, ctx->commit_count, ktime_to_us(ts)); - _sde_fence_trigger(ctx, ts); + _sde_fence_trigger(ctx, ts, (fence_event == SDE_FENCE_SIGNAL_ERROR)); } void sde_fence_timeline_status(struct sde_fence_context *ctx, diff --git a/drivers/gpu/drm/msm/sde/sde_fence.h b/drivers/gpu/drm/msm/sde/sde_fence.h index 29d2ec740e4f..7891be45f138 100644 --- a/drivers/gpu/drm/msm/sde/sde_fence.h +++ b/drivers/gpu/drm/msm/sde/sde_fence.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -47,6 +47,18 @@ struct sde_fence_context { char name[SDE_FENCE_NAME_SIZE]; }; +/** + * enum sde_fence_event - sde fence event as hint fence operation + * @SDE_FENCE_SIGNAL: Signal the fence cleanly with current timeline + * @SDE_FENCE_RESET_TIMELINE: Reset timeline of the fence context + * @SDE_FENCE_SIGNAL: Signal the fence but indicate error throughfence status + */ +enum sde_fence_event { + SDE_FENCE_SIGNAL, + SDE_FENCE_RESET_TIMELINE, + SDE_FENCE_SIGNAL_ERROR +}; + #if IS_ENABLED(CONFIG_SYNC_FILE) /** * sde_sync_get - Query sync fence object from a file handle @@ -128,10 +140,10 @@ int sde_fence_create(struct sde_fence_context *fence, uint64_t *val, * sde_fence_signal - advance fence timeline to signal outstanding fences * @fence: Pointer fence container * @ts: fence timestamp - * @reset_timeline: reset the fence timeline to done count equal to commit count + * @fence_event: fence event to indicate nature of fence signal. */ void sde_fence_signal(struct sde_fence_context *fence, ktime_t ts, - bool reset_timeline); + enum sde_fence_event fence_event); /** * sde_fence_timeline_status - prints fence timeline status -- GitLab From 199cfcdcf4274583ebaddb959ba703814040e5eb Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Wed, 28 Mar 2018 11:45:20 -0700 Subject: [PATCH 1744/1834] drm/msm/sde: extend frame retire event handling Simplify retire event by avoiding special handling and extend frame event to identify the connector or encoder firing the frame event. As crtc can be really driving multiple connectors whose frame events are not same or synchronized, this isolation of events per connector is required to handle fences. Change-Id: I2e82ae2288da4206afa197749aa57a2621b4d3f7 Signed-off-by: Prabhanjan Kandula --- drivers/gpu/drm/msm/sde/sde_crtc.c | 168 +++++++++------------ drivers/gpu/drm/msm/sde/sde_crtc.h | 19 ++- drivers/gpu/drm/msm/sde/sde_encoder.c | 23 ++- drivers/gpu/drm/msm/sde/sde_encoder.h | 12 +- drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 2 + 5 files changed, 111 insertions(+), 113 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index af75d75e90b6..74bc49844e21 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -2116,15 +2116,62 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc) } } +static void sde_crtc_frame_event_cb(void *data, u32 event) +{ + struct drm_crtc *crtc = (struct drm_crtc *)data; + struct sde_crtc *sde_crtc; + struct msm_drm_private *priv; + struct sde_crtc_frame_event *fevent; + struct sde_crtc_frame_event_cb_data *cb_data; + unsigned long flags; + u32 crtc_id; + + cb_data = (struct sde_crtc_frame_event_cb_data *)data; + if (!data) { + SDE_ERROR("invalid parameters\n"); + return; + } + + crtc = cb_data->crtc; + if (!crtc || !crtc->dev || !crtc->dev->dev_private) { + SDE_ERROR("invalid parameters\n"); + return; + } + sde_crtc = to_sde_crtc(crtc); + priv = crtc->dev->dev_private; + crtc_id = drm_crtc_index(crtc); + + SDE_DEBUG("crtc%d\n", crtc->base.id); + SDE_EVT32_VERBOSE(DRMID(crtc), event); + + spin_lock_irqsave(&sde_crtc->spin_lock, flags); + fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, + struct sde_crtc_frame_event, list); + if (fevent) + list_del_init(&fevent->list); + spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); + + if (!fevent) { + SDE_ERROR("crtc%d event %d overflow\n", + crtc->base.id, event); + SDE_EVT32(DRMID(crtc), event); + return; + } + + fevent->event = event; + fevent->crtc = crtc; + fevent->connector = cb_data->connector; + fevent->ts = ktime_get(); + kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); +} + void sde_crtc_prepare_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { struct sde_crtc *sde_crtc; struct sde_crtc_state *cstate; struct drm_connector *conn; - struct sde_crtc_retire_event *retire_event = NULL; - unsigned long flags; - int i; + struct drm_encoder *encoder; if (!crtc || !crtc->state) { SDE_ERROR("invalid crtc\n"); @@ -2141,31 +2188,17 @@ void sde_crtc_prepare_commit(struct drm_crtc *crtc, drm_for_each_connector(conn, crtc->dev) if (conn->state && conn->state->crtc == crtc && cstate->num_connectors < MAX_CONNECTORS) { + encoder = conn->state->best_encoder; + if (encoder) + sde_encoder_register_frame_event_callback( + encoder, + sde_crtc_frame_event_cb, + crtc); + cstate->connectors[cstate->num_connectors++] = conn; sde_connector_prepare_fence(conn); } - for (i = 0; i < SDE_CRTC_FRAME_EVENT_SIZE; i++) { - retire_event = &sde_crtc->retire_events[i]; - if (list_empty(&retire_event->list)) - break; - retire_event = NULL; - } - - if (retire_event) { - retire_event->num_connectors = cstate->num_connectors; - for (i = 0; i < cstate->num_connectors; i++) - retire_event->connectors[i] = cstate->connectors[i]; - - spin_lock_irqsave(&sde_crtc->spin_lock, flags); - list_add_tail(&retire_event->list, - &sde_crtc->retire_event_list); - spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); - } else { - SDE_ERROR("crtc%d retire event overflow\n", crtc->base.id); - SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR); - } - /* prepare main output fence */ sde_fence_prepare(&sde_crtc->output_fence); } @@ -2243,39 +2276,16 @@ static void sde_crtc_vblank_cb(void *data) SDE_EVT32_VERBOSE(DRMID(crtc)); } -static void _sde_crtc_retire_event(struct drm_crtc *crtc, ktime_t ts, - bool is_error) +static void _sde_crtc_retire_event(struct drm_connector *connector, + ktime_t ts, bool is_error) { - struct sde_crtc_retire_event *retire_event; - struct sde_crtc *sde_crtc; - unsigned long flags; - int i; - - if (!crtc) { + if (!connector) { SDE_ERROR("invalid param\n"); return; } - sde_crtc = to_sde_crtc(crtc); - spin_lock_irqsave(&sde_crtc->spin_lock, flags); - retire_event = list_first_entry_or_null(&sde_crtc->retire_event_list, - struct sde_crtc_retire_event, list); - if (retire_event) - list_del_init(&retire_event->list); - spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); - - if (!retire_event) { - SDE_ERROR("crtc%d retire event without kickoff\n", - crtc->base.id); - SDE_EVT32(DRMID(crtc), SDE_EVTLOG_ERROR); - return; - } - SDE_ATRACE_BEGIN("signal_retire_fence"); - for (i = 0; (i < retire_event->num_connectors) && - retire_event->connectors[i]; ++i) - sde_connector_complete_commit(retire_event->connectors[i], - ts, is_error); + sde_connector_complete_commit(connector, ts, is_error); SDE_ATRACE_END("signal_retire_fence"); } @@ -2288,6 +2298,7 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) struct sde_kms *sde_kms; unsigned long flags; bool frame_done = false; + bool in_clone_mode = false; if (!work) { SDE_ERROR("invalid work handle\n"); @@ -2316,10 +2327,11 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_EVT32_VERBOSE(DRMID(crtc), fevent->event, SDE_EVTLOG_FUNC_ENTRY); - if (fevent->event & (SDE_ENCODER_FRAME_EVENT_DONE - | SDE_ENCODER_FRAME_EVENT_ERROR - | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { + in_clone_mode = sde_encoder_in_clone_mode(fevent->connector->encoder); + if (!in_clone_mode && (fevent->event & (SDE_ENCODER_FRAME_EVENT_ERROR + | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD + | SDE_ENCODER_FRAME_EVENT_DONE))) { if (atomic_read(&sde_crtc->frame_pending) < 1) { /* this should not happen */ SDE_ERROR("crtc%d ts:%lld invalid frame_pending:%d\n", @@ -2356,7 +2368,7 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) if (fevent->event & SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE) /* this api should be called without spin_lock */ - _sde_crtc_retire_event(crtc, fevent->ts, + _sde_crtc_retire_event(fevent->connector, fevent->ts, (fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ? SDE_FENCE_SIGNAL_ERROR : SDE_FENCE_SIGNAL); @@ -2373,46 +2385,6 @@ static void sde_crtc_frame_event_work(struct kthread_work *work) SDE_ATRACE_END("crtc_frame_event"); } -static void sde_crtc_frame_event_cb(void *data, u32 event) -{ - struct drm_crtc *crtc = (struct drm_crtc *)data; - struct sde_crtc *sde_crtc; - struct msm_drm_private *priv; - struct sde_crtc_frame_event *fevent; - unsigned long flags; - u32 crtc_id; - - if (!crtc || !crtc->dev || !crtc->dev->dev_private) { - SDE_ERROR("invalid parameters\n"); - return; - } - sde_crtc = to_sde_crtc(crtc); - priv = crtc->dev->dev_private; - crtc_id = drm_crtc_index(crtc); - - SDE_DEBUG("crtc%d\n", crtc->base.id); - SDE_EVT32_VERBOSE(DRMID(crtc), event); - - spin_lock_irqsave(&sde_crtc->spin_lock, flags); - fevent = list_first_entry_or_null(&sde_crtc->frame_event_list, - struct sde_crtc_frame_event, list); - if (fevent) - list_del_init(&fevent->list); - spin_unlock_irqrestore(&sde_crtc->spin_lock, flags); - - if (!fevent) { - SDE_ERROR("crtc%d event %d overflow\n", - crtc->base.id, event); - SDE_EVT32(DRMID(crtc), event); - return; - } - - fevent->event = event; - fevent->crtc = crtc; - fevent->ts = ktime_get(); - kthread_queue_work(&priv->event_thread[crtc_id].worker, &fevent->work); -} - void sde_crtc_complete_commit(struct drm_crtc *crtc, struct drm_crtc_state *old_state) { @@ -4262,7 +4234,7 @@ static void sde_crtc_enable(struct drm_crtc *crtc) if (encoder->crtc != crtc) continue; sde_encoder_register_frame_event_callback(encoder, - sde_crtc_frame_event_cb, (void *)crtc); + sde_crtc_frame_event_cb, crtc); } if (!sde_crtc->enabled && !sde_crtc->suspend && @@ -5873,10 +5845,6 @@ static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) list_add_tail(&sde_crtc->event_cache[i].list, &sde_crtc->event_free_list); - INIT_LIST_HEAD(&sde_crtc->retire_event_list); - for (i = 0; i < ARRAY_SIZE(sde_crtc->retire_events); i++) - INIT_LIST_HEAD(&sde_crtc->retire_events[i].list); - return rc; } diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 64f38211631d..06be19cce642 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -31,7 +31,8 @@ #define SDE_CRTC_NAME_SIZE 12 /* define the maximum number of in-flight frame events */ -#define SDE_CRTC_FRAME_EVENT_SIZE 4 +/* Expand it to 2x for handling atleast 2 connectors safely */ +#define SDE_CRTC_FRAME_EVENT_SIZE (4 * 2) /** * enum sde_crtc_client_type: crtc client type @@ -80,10 +81,21 @@ struct sde_crtc_mixer { u32 pipe_mask; }; +/** + * struct sde_crtc_frame_event_cb_data : info of drm objects of a frame event + * @crtc: pointer to drm crtc object registered for frame event + * @connector: pointer to drm connector which is source of frame event + */ +struct sde_crtc_frame_event_cb_data { + struct drm_crtc *crtc; + struct drm_connector *connector; +}; + /** * struct sde_crtc_frame_event: stores crtc frame event for crtc processing * @work: base work structure * @crtc: Pointer to crtc handling this event + * @connector: pointer to drm connector which is source of frame event * @list: event list * @ts: timestamp at queue entry * @event: event identifier @@ -91,6 +103,7 @@ struct sde_crtc_mixer { struct sde_crtc_frame_event { struct kthread_work work; struct drm_crtc *crtc; + struct drm_connector *connector; struct list_head list; ktime_t ts; u32 event; @@ -160,8 +173,6 @@ struct sde_crtc_event { * @frame_events : static allocation of in-flight frame events * @frame_event_list : available frame event list * @spin_lock : spin lock for frame event, transaction status, etc... - * @retire_events : static allocation of retire fence connector - * @retire_event_list : available retire fence connector list * @frame_done_comp : for frame_event_done synchronization * @event_thread : Pointer to event handler thread * @event_worker : Event worker queue @@ -232,8 +243,6 @@ struct sde_crtc { struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head frame_event_list; spinlock_t spin_lock; - struct sde_crtc_retire_event retire_events[SDE_CRTC_FRAME_EVENT_SIZE]; - struct list_head retire_event_list; struct completion frame_done_comp; /* for handling internal event thread */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index bea66931f967..e5c1e07afd4e 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -234,7 +234,7 @@ struct sde_encoder_virt { struct mutex enc_lock; DECLARE_BITMAP(frame_busy_mask, MAX_PHYS_ENCODERS_PER_VIRTUAL); void (*crtc_frame_event_cb)(void *, u32 event); - void *crtc_frame_event_cb_data; + struct sde_crtc_frame_event_cb_data crtc_frame_event_cb_data; struct timer_list vsync_event_timer; @@ -416,6 +416,14 @@ bool sde_encoder_is_dsc_merge(struct drm_encoder *drm_enc) return false; } +int sde_encoder_in_clone_mode(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); + + return sde_enc && sde_enc->cur_master && + sde_enc->cur_master->in_clone_mode; +} + static inline int _sde_encoder_power_enable(struct sde_encoder_virt *sde_enc, bool enable) { @@ -2838,8 +2846,8 @@ void sde_encoder_register_vblank_callback(struct drm_encoder *drm_enc, } void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc, - void (*frame_event_cb)(void *, u32 event), - void *frame_event_cb_data) + void (*frame_event_cb)(void *, u32 event), + struct drm_crtc *crtc) { struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); unsigned long lock_flags; @@ -2856,7 +2864,7 @@ void sde_encoder_register_frame_event_callback(struct drm_encoder *drm_enc, spin_lock_irqsave(&sde_enc->enc_spinlock, lock_flags); sde_enc->crtc_frame_event_cb = frame_event_cb; - sde_enc->crtc_frame_event_cb_data = frame_event_cb_data; + sde_enc->crtc_frame_event_cb_data.crtc = crtc; spin_unlock_irqrestore(&sde_enc->enc_spinlock, lock_flags); } @@ -2867,6 +2875,9 @@ static void sde_encoder_frame_done_callback( struct sde_encoder_virt *sde_enc = to_sde_encoder_virt(drm_enc); unsigned int i; + sde_enc->crtc_frame_event_cb_data.connector = + sde_enc->cur_master->connector; + if (event & (SDE_ENCODER_FRAME_EVENT_DONE | SDE_ENCODER_FRAME_EVENT_ERROR | SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) { @@ -2895,13 +2906,13 @@ static void sde_encoder_frame_done_callback( if (sde_enc->crtc_frame_event_cb) sde_enc->crtc_frame_event_cb( - sde_enc->crtc_frame_event_cb_data, + &sde_enc->crtc_frame_event_cb_data, event); } } else { if (sde_enc->crtc_frame_event_cb) sde_enc->crtc_frame_event_cb( - sde_enc->crtc_frame_event_cb_data, event); + &sde_enc->crtc_frame_event_cb_data, event); } } diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 0e8e9dd2b8e3..01f311dfcb2d 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -97,10 +97,10 @@ void sde_encoder_register_vblank_callback(struct drm_encoder *encoder, * will be called after the request is complete, or other events. * @encoder: encoder pointer * @cb: callback pointer, provide NULL to deregister - * @data: user data provided to callback + * @crtc: pointer to drm_crtc object interested in frame events */ void sde_encoder_register_frame_event_callback(struct drm_encoder *encoder, - void (*cb)(void *, u32), void *data); + void (*cb)(void *, u32), struct drm_crtc *crtc); /** * sde_encoder_get_rsc_client - gets the rsc client state for primary @@ -252,4 +252,12 @@ int sde_encoder_update_caps_for_cont_splash(struct drm_encoder *encoder); */ int sde_encoder_display_failure_notification(struct drm_encoder *enc); +/** + * sde_encoder_in_clone_mode - checks if underlying phys encoder is in clone + * mode or independent display mode. ref@ WB in Concurrent writeback mode. + * @drm_enc: Pointer to drm encoder structure + * @Return: true if successful in updating the encoder structure + */ +int sde_encoder_in_clone_mode(struct drm_encoder *enc); + #endif /* __SDE_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 9557d41dd8c9..2c7cee3088cb 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -263,6 +263,7 @@ struct sde_encoder_irq { * @irq: IRQ tracking structures * @cont_splash_single_flush Variable to check if single flush is enabled. * @cont_splash_settings Variable to store continuous splash settings. + * @in_clone_mode Indicates if encoder is in clone mode ref@CWB * @vfp_cached: cached vertical front porch to be used for * programming ROT and MDP fetch start */ @@ -294,6 +295,7 @@ struct sde_encoder_phys { struct sde_encoder_irq irq[INTR_IDX_MAX]; u32 cont_splash_single_flush; bool cont_splash_settings; + bool in_clone_mode; int vfp_cached; }; -- GitLab From 44ddbcd73b94f0bf36bcc17342f2b9031c05a6f3 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Sun, 1 Apr 2018 12:12:33 -0700 Subject: [PATCH 1745/1834] drm/msm/sde: relax crtc for driving multiple connectors Extend crtc implemtation for supporting a copy connector by limiting roi checks and mixer info population for only primary connector and remove existing bail out checks to restrict crtc to single connector. Change-Id: I6272d75625770e19b0fbb0427d262d349827390d Signed-off-by: Prabhanjan Kandula --- drivers/gpu/drm/msm/sde/sde_crtc.c | 92 ++++++++++++++++-------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index 74bc49844e21..c3b3d07f70b0 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -936,7 +936,9 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, struct sde_crtc *sde_crtc; struct sde_crtc_state *crtc_state; struct sde_rect *crtc_roi; - int i, num_attached_conns = 0; + struct msm_mode_info mode_info; + int i = 0; + int rc; bool is_crtc_roi_dirty; bool is_any_conn_roi_dirty; @@ -958,13 +960,14 @@ static int _sde_crtc_set_crtc_roi(struct drm_crtc *crtc, if (!conn_state || conn_state->crtc != crtc) continue; - if (num_attached_conns) { - SDE_ERROR( - "crtc%d: unsupported: roi on crtc w/ >1 connectors\n", - DRMID(crtc)); + rc = sde_connector_get_mode_info(conn_state, &mode_info); + if (rc) { + SDE_ERROR("failed to get mode info\n"); return -EINVAL; } - ++num_attached_conns; + + if (!mode_info.roi_caps.enabled) + continue; sde_conn = to_sde_connector(conn_state->connector); sde_conn_state = to_sde_connector_state(conn_state); @@ -1285,13 +1288,6 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, sde_crtc = to_sde_crtc(crtc); sde_crtc_state = to_sde_crtc_state(state); - if (hweight_long(state->connector_mask) != 1) { - SDE_ERROR("invalid connector count(%d) for crtc: %d\n", - (int)hweight_long(state->connector_mask), - crtc->base.id); - return -EINVAL; - } - /* * check connector array cached at modeset time since incoming atomic * state may not include any connectors if they aren't modified @@ -1307,41 +1303,40 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc, SDE_ERROR("failed to get mode info\n"); return -EINVAL; } - break; - } - if (!mode_info.roi_caps.enabled) - return 0; - - if (sde_crtc_state->user_roi_list.num_rects > - mode_info.roi_caps.num_roi) { - SDE_ERROR("roi count is more than supported limit, %d > %d\n", - sde_crtc_state->user_roi_list.num_rects, - mode_info.roi_caps.num_roi); - return -E2BIG; - } + if (!mode_info.roi_caps.enabled) + continue; - rc = _sde_crtc_set_crtc_roi(crtc, state); - if (rc) - return rc; + if (sde_crtc_state->user_roi_list.num_rects > + mode_info.roi_caps.num_roi) { + SDE_ERROR("roi count is exceeding limit, %d > %d\n", + sde_crtc_state->user_roi_list.num_rects, + mode_info.roi_caps.num_roi); + return -E2BIG; + } - rc = _sde_crtc_check_autorefresh(crtc, state); - if (rc) - return rc; + rc = _sde_crtc_set_crtc_roi(crtc, state); + if (rc) + return rc; - for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) { - rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx); + rc = _sde_crtc_check_autorefresh(crtc, state); if (rc) return rc; - } - rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state); - if (rc) - return rc; + for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) { + rc = _sde_crtc_set_lm_roi(crtc, state, lm_idx); + if (rc) + return rc; + } - rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state); - if (rc) - return rc; + rc = _sde_crtc_check_rois_centered_and_symmetric(crtc, state); + if (rc) + return rc; + + rc = _sde_crtc_check_planes_within_crtc_roi(crtc, state); + if (rc) + return rc; + } return 0; } @@ -2249,9 +2244,16 @@ enum sde_intf_mode sde_crtc_get_intf_mode(struct drm_crtc *crtc) return INTF_MODE_NONE; } - drm_for_each_encoder(encoder, crtc->dev) - if (encoder->crtc == crtc) - return sde_encoder_get_intf_mode(encoder); + drm_for_each_encoder(encoder, crtc->dev) { + if (encoder->crtc != crtc) + continue; + + /* continue if copy encoder is encountered */ + if (sde_encoder_in_clone_mode(encoder)) + continue; + + return sde_encoder_get_intf_mode(encoder); + } return INTF_MODE_NONE; } @@ -2935,6 +2937,10 @@ static void _sde_crtc_setup_mixers(struct drm_crtc *crtc) if (enc->crtc != crtc) continue; + /* avoid overwriting mixers info from a copy encoder */ + if (sde_encoder_in_clone_mode(enc)) + continue; + _sde_crtc_setup_mixer_for_encoder(crtc, enc); } -- GitLab From 7f9b8d44e33678b6d9370331fb87b9ee8222b3f0 Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Mon, 23 Apr 2018 19:02:00 -0700 Subject: [PATCH 1746/1834] drm/msm/sde: add CWB custom property support If concurrent writeback feature is supported by HW, add a new property on each CRTC through which client can request the data point of capture (LM or DSSP output). Availability of this property on crtc itself is indication for client about the availability of CWB feature. Change-Id: Ia6cf3b3f544d8d2f71fc2bcd376081f629e9d8ba Signed-off-by: Prabhanjan Kandula --- drivers/gpu/drm/msm/msm_drv.h | 1 + drivers/gpu/drm/msm/sde/sde_crtc.c | 11 +++++++++++ drivers/gpu/drm/msm/sde/sde_crtc.h | 10 ++++++++++ drivers/gpu/drm/msm/sde/sde_hw_catalog.c | 4 ++++ drivers/gpu/drm/msm/sde/sde_hw_catalog.h | 4 ++++ 5 files changed, 30 insertions(+) diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index ce4197bef697..fcdddb34f925 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -155,6 +155,7 @@ enum msm_mdp_crtc_property { CRTC_PROP_SECURITY_LEVEL, CRTC_PROP_IDLE_TIMEOUT, CRTC_PROP_DEST_SCALER, + CRTC_PROP_CAPTURE_OUTPUT, CRTC_PROP_ENABLE_SUI_ENHANCEMENT, diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c index c3b3d07f70b0..f0fcdb746b73 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.c +++ b/drivers/gpu/drm/msm/sde/sde_crtc.c @@ -4899,6 +4899,11 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, {SDE_DRM_SEC_ONLY, "sec_only"}, }; + static const struct drm_prop_enum_list e_cwb_data_points[] = { + {CAPTURE_MIXER_OUT, "capture_mixer_out"}, + {CAPTURE_DSPP_OUT, "capture_pp_out"}, + }; + SDE_DEBUG("\n"); if (!crtc || !catalog) { @@ -4978,6 +4983,12 @@ static void sde_crtc_install_properties(struct drm_crtc *crtc, "enable_sui_enhancement", 0, 0, U64_MAX, 0, CRTC_PROP_ENABLE_SUI_ENHANCEMENT); + if (catalog->has_cwb_support) + msm_property_install_enum(&sde_crtc->property_info, + "capture_mode", 0, 0, e_cwb_data_points, + ARRAY_SIZE(e_cwb_data_points), + CRTC_PROP_CAPTURE_OUTPUT); + msm_property_install_blob(&sde_crtc->property_info, "capabilities", DRM_MODE_PROP_IMMUTABLE, CRTC_PROP_INFO); diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.h b/drivers/gpu/drm/msm/sde/sde_crtc.h index 06be19cce642..4f610edbc74a 100644 --- a/drivers/gpu/drm/msm/sde/sde_crtc.h +++ b/drivers/gpu/drm/msm/sde/sde_crtc.h @@ -48,6 +48,16 @@ enum sde_crtc_client_type { RT_RSC_CLIENT, }; +/** + * enum sde_crtc_output_capture_point + * @MIXER_OUT : capture mixer output + * @DSPP_OUT : capture output of dspp + */ +enum sde_crtc_output_capture_point { + CAPTURE_MIXER_OUT, + CAPTURE_DSPP_OUT +}; + /** * @connectors : Currently associated drm connectors for retire event * @num_connectors: Number of associated drm connectors for retire event diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c index eacafe6045e1..475f8d08cc41 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.c @@ -1694,6 +1694,9 @@ static int sde_wb_parse_dt(struct device_node *np, struct sde_mdss_cfg *sde_cfg) set_bit(SDE_WB_XY_ROI_OFFSET, &wb->features); + if (sde_cfg->has_cwb_support) + set_bit(SDE_WB_HAS_CWB, &wb->features); + for (j = 0; j < sde_cfg->mdp_count; j++) { sde_cfg->mdp[j].clk_ctrls[wb->clk_ctrl].reg_off = PROP_BITVALUE_ACCESS(prop_value, @@ -3248,6 +3251,7 @@ static int _sde_hardware_pre_caps(struct sde_mdss_cfg *sde_cfg, uint32_t hw_rev) } else if (IS_SDM845_TARGET(hw_rev)) { /* update sdm845 target here */ sde_cfg->has_wb_ubwc = true; + sde_cfg->has_cwb_support = true; sde_cfg->perf.min_prefill_lines = 24; sde_cfg->vbif_qos_nlvl = 8; sde_cfg->ts_prefill_rev = 2; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h index 963b48fd552e..65919e9bfbf2 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_catalog.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_catalog.h @@ -261,6 +261,7 @@ enum { * @SDE_WB_QOS, Writeback supports QoS control, danger/safe/creq * @SDE_WB_QOS_8LVL, Writeback supports 8-level QoS control * @SDE_WB_CDP Writeback supports client driven prefetch + * @SDE_WB_HAS_CWB Writeback block supports concurrent writeback * @SDE_WB_MAX maximum value */ enum { @@ -279,6 +280,7 @@ enum { SDE_WB_QOS, SDE_WB_QOS_8LVL, SDE_WB_CDP, + SDE_WB_HAS_CWB, SDE_WB_MAX }; @@ -922,6 +924,7 @@ struct sde_perf_cfg { * @has_src_split source split feature status * @has_cdp Client driven prefetch feature status * @has_wb_ubwc UBWC feature supported on WB + * @has_cwb_support indicates if device supports primary capture through CWB * @ubwc_version UBWC feature version (0x0 for not supported) * @has_sbuf indicate if stream buffer is available * @sbuf_headroom stream buffer headroom in lines @@ -959,6 +962,7 @@ struct sde_mdss_cfg { bool has_cdp; bool has_dim_layer; bool has_wb_ubwc; + bool has_cwb_support; u32 ubwc_version; bool has_sbuf; u32 sbuf_headroom; -- GitLab From 77cc0ee35cc834ffcca04c054021205e0f3f4eec Mon Sep 17 00:00:00 2001 From: Prabhanjan Kandula Date: Sun, 15 Apr 2018 21:44:50 -0700 Subject: [PATCH 1747/1834] drm/msm/sde: concurrent writeback support Add support for capturing frame on primary through WB using concurrent writeback HW feature if supported. Changes include detecting CWB usecase by finding if WB is in clone mode, reserve same set of hw resources as in plain WB case and program CWB specific registers like ctrl_top and flush on primary. This change support dynamic capture enable or disable per frame. Signal only retire fence for CWB case as primary crtc handles release fence. WB irq handling is improved using helper functions in virtual encoder. Change also supports notifying frame error by registering for ping-pong overflow & signal retire fence with frame error if overflows. Change-Id: Ia9eebd0224282e87a758e848eb4e1d4ca7871059 Signed-off-by: Prabhanjan Kandula --- drivers/gpu/drm/msm/sde/sde_encoder.c | 17 +- drivers/gpu/drm/msm/sde/sde_encoder_phys.h | 9 +- drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c | 397 +++++++++++++----- drivers/gpu/drm/msm/sde/sde_hw_ctl.c | 20 +- drivers/gpu/drm/msm/sde/sde_hw_ctl.h | 11 +- drivers/gpu/drm/msm/sde/sde_hw_top.c | 13 + drivers/gpu/drm/msm/sde/sde_hw_top.h | 9 + drivers/gpu/drm/msm/sde/sde_hwio.h | 4 +- 8 files changed, 372 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index e5c1e07afd4e..793b4be0be44 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -1594,11 +1594,16 @@ static int _sde_encoder_update_rsc_client( * only primary command mode panel can request CMD state. * all other panels/displays can request for VID state including * secondary command mode panel. + * Clone mode encoder can request CLK STATE only. */ - rsc_state = enable ? - (((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) && - disp_info->is_primary) ? SDE_RSC_CMD_STATE : - SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE; + if (sde_encoder_in_clone_mode(drm_enc)) + rsc_state = enable ? SDE_RSC_CLK_STATE : SDE_RSC_IDLE_STATE; + else + rsc_state = enable ? + (((disp_info->capabilities & MSM_DISPLAY_CAP_CMD_MODE) + && disp_info->is_primary) ? SDE_RSC_CMD_STATE : + SDE_RSC_VID_STATE) : SDE_RSC_IDLE_STATE; + prefill_lines = config ? mode_info.prefill_lines + config->inline_rotate_prefill : mode_info.prefill_lines; @@ -3021,6 +3026,10 @@ static inline void _sde_encoder_trigger_start(struct sde_encoder_phys *phys) return; } + /* avoid ctrl start for encoder in clone mode */ + if (phys->in_clone_mode) + return; + ctl = phys->hw_ctl; if (phys->split_role == ENC_ROLE_SKIP) { SDE_DEBUG_ENC(to_sde_encoder_virt(phys->parent), diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 2c7cee3088cb..a9ee9436019c 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -194,6 +194,9 @@ struct sde_encoder_phys_ops { * @INTR_IDX_PINGPONG: Pingpong done unterrupt for cmd mode panel * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel * @INTR_IDX_RDPTR: Readpointer done unterrupt for cmd mode panel + * @INTR_IDX_WB_DONE: Writeback done interrupt for WB + * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP2 for Concurrent WB + * @INTR_IDX_PP2_OVFL: Pingpong overflow interrupt on PP3 for Concurrent WB * @INTR_IDX_AUTOREFRESH_DONE: Autorefresh done for cmd mode panel meaning * autorefresh has triggered a double buffer flip */ @@ -204,6 +207,9 @@ enum sde_intr_idx { INTR_IDX_CTL_START, INTR_IDX_RDPTR, INTR_IDX_AUTOREFRESH_DONE, + INTR_IDX_WB_DONE, + INTR_IDX_PP2_OVFL, + INTR_IDX_PP3_OVFL, INTR_IDX_MAX, }; @@ -369,7 +375,6 @@ struct sde_encoder_phys_cmd { * writeback specific operations * @base: Baseclass physical encoder structure * @hw_wb: Hardware interface to the wb registers - * @irq_idx: IRQ interface lookup index * @wbdone_timeout: Timeout value for writeback done in msec * @bypass_irqreg: Bypass irq register/unregister if non-zero * @wbdone_complete: for wbdone irq synchronization @@ -393,8 +398,6 @@ struct sde_encoder_phys_cmd { struct sde_encoder_phys_wb { struct sde_encoder_phys base; struct sde_hw_wb *hw_wb; - int irq_idx; - struct sde_irq_callback irq_cb; u32 wbdone_timeout; u32 bypass_irqreg; struct completion wbdone_complete; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c index 9a90075d8993..f15018d96b3d 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -32,6 +32,7 @@ #define TO_S15D16(_x_) ((_x_) << 7) +#define MULTIPLE_CONN_DETECTED(x) (x > 1) /** * sde_rgb2yuv_601l - rgb to yuv color space conversion matrix * @@ -398,6 +399,31 @@ static void sde_encoder_phys_wb_setup_fb(struct sde_encoder_phys *phys_enc, } } +static void _sde_encoder_phys_wb_setup_cwb(struct sde_encoder_phys *phys_enc, + bool enable) +{ + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_hw_wb *hw_wb = wb_enc->hw_wb; + struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg; + struct sde_hw_ctl *hw_ctl = phys_enc->hw_ctl; + struct sde_crtc *crtc = to_sde_crtc(wb_enc->crtc); + + if (!phys_enc->in_clone_mode) { + SDE_DEBUG("not in CWB mode. early return\n"); + return; + } + + memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg)); + intf_cfg->intf = SDE_NONE; + intf_cfg->wb = hw_wb->idx; + + hw_ctl = crtc->mixers[0].hw_ctl; + if (hw_ctl && hw_ctl->ops.update_wb_cfg) { + hw_ctl->ops.update_wb_cfg(hw_ctl, intf_cfg, enable); + SDE_DEBUG("in CWB mode adding WB for CTL_%d\n", + hw_ctl->idx - CTL_0); + } +} /** * sde_encoder_phys_wb_setup_cdp - setup chroma down prefetch block * @phys_enc: Pointer to physical encoder @@ -408,8 +434,12 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc) struct sde_hw_wb *hw_wb = wb_enc->hw_wb; struct sde_hw_intf_cfg *intf_cfg = &wb_enc->intf_cfg; - memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg)); + if (phys_enc->in_clone_mode) { + SDE_DEBUG("in CWB mode. early return\n"); + return; + } + memset(intf_cfg, 0, sizeof(struct sde_hw_intf_cfg)); intf_cfg->intf = SDE_NONE; intf_cfg->wb = hw_wb->idx; intf_cfg->mode_3d = sde_encoder_helper_get_3d_blend_mode(phys_enc); @@ -417,6 +447,98 @@ static void sde_encoder_phys_wb_setup_cdp(struct sde_encoder_phys *phys_enc) if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, intf_cfg); + +} + +static void _sde_enc_phys_wb_detect_cwb(struct sde_encoder_phys *phys_enc, + struct drm_crtc_state *crtc_state) +{ + struct drm_connector *conn; + struct drm_connector_state *conn_state; + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + const struct sde_wb_cfg *wb_cfg = wb_enc->hw_wb->caps; + int conn_count = 0; + + phys_enc->in_clone_mode = false; + + /* Check if WB has CWB support */ + if (!(wb_cfg->features & SDE_WB_HAS_CWB)) + return; + + /* Count the number of connectors on the given crtc */ + drm_for_each_connector(conn, crtc_state->crtc->dev) { + conn_state = + drm_atomic_get_connector_state(crtc_state->state, conn); + if ((conn->state && conn->state->crtc == crtc_state->crtc) || + (conn_state && + conn_state->crtc == crtc_state->crtc)) + conn_count++; + } + + + /* Enable clone mode If crtc has multiple connectors & one is WB */ + if (MULTIPLE_CONN_DETECTED(conn_count)) + phys_enc->in_clone_mode = true; + + SDE_DEBUG("detect CWB - status:%d\n", phys_enc->in_clone_mode); +} + +static int _sde_enc_phys_wb_validate_cwb(struct sde_encoder_phys *phys_enc, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) +{ + struct sde_crtc_state *cstate = to_sde_crtc_state(crtc_state); + struct sde_rect wb_roi = {0,}; + int data_pt; + int ds_outw = 0; + int ds_outh = 0; + int ds_in_use = false; + int i = 0; + int ret = 0; + + if (!phys_enc->in_clone_mode) { + SDE_DEBUG("not in CWB mode. early return\n"); + goto exit; + } + + ret = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi); + if (ret) { + SDE_ERROR("failed to get roi %d\n", ret); + goto exit; + } + + data_pt = sde_crtc_get_property(cstate, CRTC_PROP_CAPTURE_OUTPUT); + + /* compute cumulative ds output dimensions if in use */ + for (i = 0; i < cstate->num_ds; i++) + if (cstate->ds_cfg[i].scl3_cfg.enable) { + ds_in_use = true; + ds_outw += cstate->ds_cfg[i].scl3_cfg.dst_width; + ds_outh += cstate->ds_cfg[i].scl3_cfg.dst_height; + } + + /* if ds in use check wb roi against ds output dimensions */ + if ((data_pt == CAPTURE_DSPP_OUT) && ds_in_use && + ((wb_roi.w != ds_outw) || (wb_roi.h != ds_outh))) { + SDE_ERROR("invalid wb roi with dest scalar [%dx%d vs %dx%d]\n", + wb_roi.w, wb_roi.h, ds_outw, ds_outh); + ret = -EINVAL; + goto exit; + } + + /* validate conn roi against pu rect */ + if (!sde_kms_rect_is_null(&cstate->crtc_roi)) { + if (wb_roi.w != cstate->crtc_roi.w || + wb_roi.h != cstate->crtc_roi.h) { + SDE_ERROR("invalid wb roi with pu [%dx%d vs %dx%d]\n", + wb_roi.w, wb_roi.h, cstate->crtc_roi.w, + cstate->crtc_roi.h); + ret = -EINVAL; + goto exit; + } + } +exit: + return ret; } /** @@ -453,6 +575,8 @@ static int sde_encoder_phys_wb_atomic_check( return -EINVAL; } + _sde_enc_phys_wb_detect_cwb(phys_enc, crtc_state); + memset(&wb_roi, 0, sizeof(struct sde_rect)); rc = sde_wb_connector_state_get_output_roi(conn_state, &wb_roi); @@ -542,7 +666,62 @@ static int sde_encoder_phys_wb_atomic_check( } } - return 0; + rc = _sde_enc_phys_wb_validate_cwb(phys_enc, crtc_state, conn_state); + if (rc) { + SDE_ERROR("failed in cwb validation %d\n", rc); + return rc; + } + + return rc; +} + +static void _sde_encoder_phys_wb_update_cwb_flush( + struct sde_encoder_phys *phys_enc) +{ + struct sde_encoder_phys_wb *wb_enc; + struct sde_hw_wb *hw_wb; + struct sde_hw_ctl *hw_ctl; + struct sde_hw_cdm *hw_cdm; + struct sde_crtc *crtc; + struct sde_crtc_state *crtc_state; + u32 flush_mask = 0; + int capture_point = 0; + + if (!phys_enc->in_clone_mode) { + SDE_DEBUG("not in CWB mode. early return\n"); + return; + } + + wb_enc = to_sde_encoder_phys_wb(phys_enc); + crtc = to_sde_crtc(wb_enc->crtc); + crtc_state = to_sde_crtc_state(wb_enc->crtc->state); + + hw_wb = wb_enc->hw_wb; + hw_cdm = phys_enc->hw_cdm; + + /* In CWB mode, program actual source master sde_hw_ctl from crtc */ + hw_ctl = crtc->mixers[0].hw_ctl; + if (!hw_ctl) { + SDE_DEBUG("[wb:%d] no ctl assigned for CWB\n", + hw_wb->idx - WB_0); + return; + } + + capture_point = sde_crtc_get_property(crtc_state, + CRTC_PROP_CAPTURE_OUTPUT); + + phys_enc->hw_mdptop->ops.set_cwb_ppb_cntl(phys_enc->hw_mdptop, + crtc->num_mixers == CRTC_DUAL_MIXERS, + capture_point == CAPTURE_DSPP_OUT); + + if (hw_ctl->ops.get_bitmask_wb) + hw_ctl->ops.get_bitmask_wb(hw_ctl, &flush_mask, hw_wb->idx); + + if (hw_ctl->ops.get_bitmask_cdm && hw_cdm) + hw_ctl->ops.get_bitmask_cdm(hw_ctl, &flush_mask, hw_cdm->idx); + + if (hw_ctl->ops.update_pending_flush) + hw_ctl->ops.update_pending_flush(hw_ctl, flush_mask); } /** @@ -551,7 +730,7 @@ static int sde_encoder_phys_wb_atomic_check( */ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc) { - struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); + struct sde_encoder_phys_wb *wb_enc; struct sde_hw_wb *hw_wb; struct sde_hw_ctl *hw_ctl; struct sde_hw_cdm *hw_cdm; @@ -560,12 +739,18 @@ static void _sde_encoder_phys_wb_update_flush(struct sde_encoder_phys *phys_enc) if (!phys_enc) return; + wb_enc = to_sde_encoder_phys_wb(phys_enc); hw_wb = wb_enc->hw_wb; - hw_ctl = phys_enc->hw_ctl; hw_cdm = phys_enc->hw_cdm; + hw_ctl = phys_enc->hw_ctl; SDE_DEBUG("[wb:%d]\n", hw_wb->idx - WB_0); + if (phys_enc->in_clone_mode) { + SDE_DEBUG("in CWB mode. early return\n"); + return; + } + if (!hw_ctl) { SDE_DEBUG("[wb:%d] no ctl assigned\n", hw_wb->idx - WB_0); return; @@ -659,54 +844,28 @@ static void sde_encoder_phys_wb_setup( sde_encoder_phys_wb_setup_fb(phys_enc, fb, wb_roi); sde_encoder_phys_wb_setup_cdp(phys_enc); -} - -/** - * sde_encoder_phys_wb_unregister_irq - unregister writeback interrupt handler - * @phys_enc: Pointer to physical encoder - */ -static int sde_encoder_phys_wb_unregister_irq( - struct sde_encoder_phys *phys_enc) -{ - struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); - struct sde_hw_wb *hw_wb = wb_enc->hw_wb; - if (wb_enc->bypass_irqreg) - return 0; - - sde_core_irq_disable(phys_enc->sde_kms, &wb_enc->irq_idx, 1); - sde_core_irq_unregister_callback(phys_enc->sde_kms, wb_enc->irq_idx, - &wb_enc->irq_cb); - - SDE_DEBUG("un-register IRQ for wb %d, irq_idx=%d\n", - hw_wb->idx - WB_0, - wb_enc->irq_idx); - - return 0; + _sde_encoder_phys_wb_setup_cwb(phys_enc, true); } -/** - * sde_encoder_phys_wb_done_irq - writeback interrupt handler - * @arg: Pointer to writeback encoder - * @irq_idx: interrupt index - */ -static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) +static void _sde_encoder_phys_wb_frame_done_helper(void *arg, bool frame_error) { struct sde_encoder_phys_wb *wb_enc = arg; struct sde_encoder_phys *phys_enc = &wb_enc->base; struct sde_hw_wb *hw_wb = wb_enc->hw_wb; - u32 event = 0; + u32 event = frame_error ? SDE_ENCODER_FRAME_EVENT_ERROR : 0; + + event |= SDE_ENCODER_FRAME_EVENT_DONE | + SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE; - SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, - wb_enc->frame_count); + SDE_DEBUG("[wb:%d,%u]\n", hw_wb->idx - WB_0, wb_enc->frame_count); /* don't notify upper layer for internal commit */ if (phys_enc->enable_state == SDE_ENC_DISABLING) goto complete; - event = SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE - | SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE - | SDE_ENCODER_FRAME_EVENT_DONE; + if (!phys_enc->in_clone_mode) + event |= SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE; atomic_add_unless(&phys_enc->pending_retire_fence_cnt, -1, 0); if (phys_enc->parent_ops.handle_frame_done) @@ -724,58 +883,60 @@ static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) } /** - * sde_encoder_phys_wb_register_irq - register writeback interrupt handler - * @phys_enc: Pointer to physical encoder + * sde_encoder_phys_wb_done_irq - Pingpong overflow interrupt handler for CWB + * @arg: Pointer to writeback encoder + * @irq_idx: interrupt index */ -static int sde_encoder_phys_wb_register_irq(struct sde_encoder_phys *phys_enc) +static void sde_encoder_phys_cwb_ovflow(void *arg, int irq_idx) { - struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); - struct sde_hw_wb *hw_wb = wb_enc->hw_wb; - struct sde_irq_callback *irq_cb = &wb_enc->irq_cb; - enum sde_intr_type intr_type; - int ret = 0; + _sde_encoder_phys_wb_frame_done_helper(arg, true); +} - if (wb_enc->bypass_irqreg) - return 0; +/** + * sde_encoder_phys_wb_done_irq - writeback interrupt handler + * @arg: Pointer to writeback encoder + * @irq_idx: interrupt index + */ +static void sde_encoder_phys_wb_done_irq(void *arg, int irq_idx) +{ + _sde_encoder_phys_wb_frame_done_helper(arg, false); +} - intr_type = sde_encoder_phys_wb_get_intr_type(hw_wb); - wb_enc->irq_idx = sde_core_irq_idx_lookup(phys_enc->sde_kms, - intr_type, hw_wb->idx); - if (wb_enc->irq_idx < 0) { - SDE_ERROR( - "failed to lookup IRQ index for WB_DONE with wb=%d\n", - hw_wb->idx - WB_0); - return -EINVAL; - } +/** + * sde_encoder_phys_wb_irq_ctrl - irq control of WB + * @phys: Pointer to physical encoder + * @enable: indicates enable or disable interrupts + */ +static void sde_encoder_phys_wb_irq_ctrl( + struct sde_encoder_phys *phys, bool enable) +{ - irq_cb->func = sde_encoder_phys_wb_done_irq; - irq_cb->arg = wb_enc; - ret = sde_core_irq_register_callback(phys_enc->sde_kms, - wb_enc->irq_idx, irq_cb); - if (ret) { - SDE_ERROR("failed to register IRQ callback WB_DONE\n"); - return ret; - } + struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys); + int index = 0; - ret = sde_core_irq_enable(phys_enc->sde_kms, &wb_enc->irq_idx, 1); - if (ret) { - SDE_ERROR( - "failed to enable IRQ for WB_DONE, wb %d, irq_idx=%d\n", - hw_wb->idx - WB_0, - wb_enc->irq_idx); - wb_enc->irq_idx = -EINVAL; - - /* Unregister callback on IRQ enable failure */ - sde_core_irq_unregister_callback(phys_enc->sde_kms, - wb_enc->irq_idx, irq_cb); - return ret; - } + if (!wb_enc) + return; - SDE_DEBUG("registered IRQ for wb %d, irq_idx=%d\n", - hw_wb->idx - WB_0, - wb_enc->irq_idx); + if (wb_enc->bypass_irqreg) + return; - return ret; + if (enable) { + sde_encoder_helper_register_irq(phys, INTR_IDX_WB_DONE); + if (phys->in_clone_mode) { + for (index = 0; index < CRTC_DUAL_MIXERS; index++) + sde_encoder_helper_register_irq(phys, + index ? INTR_IDX_PP3_OVFL + : INTR_IDX_PP2_OVFL); + } + } else { + sde_encoder_helper_unregister_irq(phys, INTR_IDX_WB_DONE); + if (phys->in_clone_mode) { + for (index = 0; index < CRTC_DUAL_MIXERS; index++) + sde_encoder_helper_unregister_irq(phys, + index ? INTR_IDX_PP3_OVFL + : INTR_IDX_PP2_OVFL); + } + } } /** @@ -846,6 +1007,7 @@ static int sde_encoder_phys_wb_wait_for_commit_done( u32 irq_status, event = 0; u64 wb_time = 0; int rc = 0; + int irq_idx = phys_enc->irq[INTR_IDX_WB_DONE].irq_idx; u32 timeout = max_t(u32, wb_enc->wbdone_timeout, KICKOFF_TIMEOUT_MS); /* Return EWOULDBLOCK since we know the wait isn't necessary */ @@ -860,7 +1022,7 @@ static int sde_encoder_phys_wb_wait_for_commit_done( /* signal completion if commit with no framebuffer */ if (!wb_enc->wb_fb) { SDE_DEBUG("no output framebuffer\n"); - sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx); + _sde_encoder_phys_wb_frame_done_helper(wb_enc, false); } ret = wait_for_completion_timeout(&wb_enc->wbdone_complete, @@ -870,11 +1032,11 @@ static int sde_encoder_phys_wb_wait_for_commit_done( SDE_EVT32(DRMID(phys_enc->parent), WBID(wb_enc), wb_enc->frame_count); irq_status = sde_core_irq_read(phys_enc->sde_kms, - wb_enc->irq_idx, true); + irq_idx, true); if (irq_status) { SDE_DEBUG("wb:%d done but irq not triggered\n", WBID(wb_enc)); - sde_encoder_phys_wb_done_irq(wb_enc, wb_enc->irq_idx); + _sde_encoder_phys_wb_frame_done_helper(wb_enc, false); } else { SDE_ERROR("wb:%d kickoff timed out\n", WBID(wb_enc)); @@ -891,8 +1053,6 @@ static int sde_encoder_phys_wb_wait_for_commit_done( } } - sde_encoder_phys_wb_unregister_irq(phys_enc); - if (!rc) wb_enc->end_time = ktime_get(); @@ -937,19 +1097,12 @@ static int sde_encoder_phys_wb_prepare_for_kickoff( struct sde_encoder_kickoff_params *params) { struct sde_encoder_phys_wb *wb_enc = to_sde_encoder_phys_wb(phys_enc); - int ret; SDE_DEBUG("[wb:%d,%u]\n", wb_enc->hw_wb->idx - WB_0, wb_enc->kickoff_count); reinit_completion(&wb_enc->wbdone_complete); - ret = sde_encoder_phys_wb_register_irq(phys_enc); - if (ret) { - SDE_ERROR("failed to register irq %d\n", ret); - return ret; - } - wb_enc->kickoff_count++; /* set OT limit & enable traffic shaper */ @@ -957,6 +1110,8 @@ static int sde_encoder_phys_wb_prepare_for_kickoff( _sde_encoder_phys_wb_update_flush(phys_enc); + _sde_encoder_phys_wb_update_cwb_flush(phys_enc); + /* vote for iommu/clk/bus */ wb_enc->start_time = ktime_get(); @@ -977,6 +1132,15 @@ static void sde_encoder_phys_wb_trigger_flush(struct sde_encoder_phys *phys_enc) return; } + /* + * Bail out iff in CWB mode. In case of CWB, primary control-path + * which is actually driving would trigger the flush + */ + if (phys_enc->in_clone_mode) { + SDE_DEBUG("in CWB mode. early return\n"); + return; + } + SDE_DEBUG("[wb:%d]\n", wb_enc->hw_wb->idx - WB_0); /* clear pending flush if commit with no framebuffer */ @@ -1183,6 +1347,13 @@ static void sde_encoder_phys_wb_disable(struct sde_encoder_phys *phys_enc) goto exit; } + /* avoid reset frame for CWB */ + if (phys_enc->in_clone_mode) { + _sde_encoder_phys_wb_setup_cwb(phys_enc, false); + phys_enc->in_clone_mode = false; + goto exit; + } + /* reset h/w before final flush */ if (phys_enc->hw_ctl->ops.clear_pending_flush) phys_enc->hw_ctl->ops.clear_pending_flush(phys_enc->hw_ctl); @@ -1320,6 +1491,7 @@ static void sde_encoder_phys_wb_init_ops(struct sde_encoder_phys_ops *ops) ops->trigger_flush = sde_encoder_phys_wb_trigger_flush; ops->trigger_start = sde_encoder_helper_trigger_start; ops->hw_reset = sde_encoder_helper_hw_reset; + ops->irq_control = sde_encoder_phys_wb_irq_ctrl; } /** @@ -1332,6 +1504,7 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( struct sde_encoder_phys *phys_enc; struct sde_encoder_phys_wb *wb_enc; struct sde_hw_mdp *hw_mdp; + struct sde_encoder_irq *irq; int ret = 0; SDE_DEBUG("\n"); @@ -1348,7 +1521,6 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( ret = -ENOMEM; goto fail_alloc; } - wb_enc->irq_idx = -EINVAL; wb_enc->wbdone_timeout = KICKOFF_TIMEOUT_MS; init_completion(&wb_enc->wbdone_complete); @@ -1411,7 +1583,36 @@ struct sde_encoder_phys *sde_encoder_phys_wb_init( phys_enc->intf_idx = p->intf_idx; phys_enc->enc_spinlock = p->enc_spinlock; atomic_set(&phys_enc->pending_retire_fence_cnt, 0); - INIT_LIST_HEAD(&wb_enc->irq_cb.list); + + irq = &phys_enc->irq[INTR_IDX_WB_DONE]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "wb_done"; + irq->hw_idx = wb_enc->hw_wb->idx; + irq->irq_idx = -1; + irq->intr_type = sde_encoder_phys_wb_get_intr_type(wb_enc->hw_wb); + irq->intr_idx = INTR_IDX_WB_DONE; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_wb_done_irq; + + irq = &phys_enc->irq[INTR_IDX_PP2_OVFL]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "pp2_overflow"; + irq->hw_idx = CWB_2; + irq->irq_idx = -1; + irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW; + irq->intr_idx = INTR_IDX_PP2_OVFL; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_cwb_ovflow; + + irq = &phys_enc->irq[INTR_IDX_PP3_OVFL]; + INIT_LIST_HEAD(&irq->cb.list); + irq->name = "pp3_overflow"; + irq->hw_idx = CWB_3; + irq->irq_idx = -1; + irq->intr_type = SDE_IRQ_TYPE_CWB_OVERFLOW; + irq->intr_idx = INTR_IDX_PP3_OVFL; + irq->cb.arg = wb_enc; + irq->cb.func = sde_encoder_phys_cwb_ovflow; /* create internal buffer for disable logic */ if (_sde_encoder_phys_wb_init_internal_fb(wb_enc, diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c index 303d96e3625c..2146611b66d7 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -576,6 +576,23 @@ static void sde_hw_ctl_intf_cfg(struct sde_hw_ctl *ctx, SDE_REG_WRITE(c, CTL_TOP, intf_cfg); } +static void sde_hw_ctl_update_wb_cfg(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg *cfg, bool enable) { + struct sde_hw_blk_reg_map *c = &ctx->hw; + u32 intf_cfg = 0; + + if (!cfg->wb) + return; + + intf_cfg = SDE_REG_READ(c, CTL_TOP); + if (enable) + intf_cfg |= (cfg->wb & 0x3) + 2; + else + intf_cfg &= ~((cfg->wb & 0x3) + 2); + + SDE_REG_WRITE(c, CTL_TOP, intf_cfg); +} + static inline u32 sde_hw_ctl_read_ctl_top(struct sde_hw_ctl *ctx) { struct sde_hw_blk_reg_map *c; @@ -638,6 +655,7 @@ static void _setup_ctl_ops(struct sde_hw_ctl_ops *ops, ops->read_ctl_top = sde_hw_ctl_read_ctl_top; ops->read_ctl_layers = sde_hw_ctl_read_ctl_layers; ops->setup_intf_cfg = sde_hw_ctl_intf_cfg; + ops->update_wb_cfg = sde_hw_ctl_update_wb_cfg; ops->reset = sde_hw_ctl_reset_control; ops->get_reset = sde_hw_ctl_get_reset_status; ops->hard_reset = sde_hw_ctl_hard_reset; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h index 9eb31f17adc5..75631dd8074e 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -150,6 +150,15 @@ struct sde_hw_ctl_ops { void (*setup_intf_cfg)(struct sde_hw_ctl *ctx, struct sde_hw_intf_cfg *cfg); + /** + * Update the interface selection with input WB config + * @ctx : ctl path ctx pointer + * @cfg : pointer to input wb config + * @enable : set if true, clear otherwise + */ + void (*update_wb_cfg)(struct sde_hw_ctl *ctx, + struct sde_hw_intf_cfg *cfg, bool enable); + int (*reset)(struct sde_hw_ctl *c); /** diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.c b/drivers/gpu/drm/msm/sde/sde_hw_top.c index 8b89ebbbb6ac..cf646bdbee40 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_top.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_top.c @@ -376,6 +376,18 @@ static void sde_hw_intf_audio_select(struct sde_hw_mdp *mdp) SDE_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1); } +static void sde_hw_program_cwb_ppb_ctrl(struct sde_hw_mdp *mdp, + bool dual, bool dspp_out) +{ + u32 value = dspp_out ? 0x4 : 0x0; + + SDE_REG_WRITE(&mdp->hw, PPB2_CNTL, value); + if (dual) { + value |= 0x1; + SDE_REG_WRITE(&mdp->hw, PPB3_CNTL, value); + } +} + static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, unsigned long cap) { @@ -385,6 +397,7 @@ static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops, ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl; ops->get_danger_status = sde_hw_get_danger_status; ops->setup_vsync_source = sde_hw_setup_vsync_source; + ops->set_cwb_ppb_cntl = sde_hw_program_cwb_ppb_ctrl; ops->get_safe_status = sde_hw_get_safe_status; ops->get_split_flush_status = sde_hw_get_split_flush; ops->setup_dce = sde_hw_setup_dce; diff --git a/drivers/gpu/drm/msm/sde/sde_hw_top.h b/drivers/gpu/drm/msm/sde/sde_hw_top.h index 950a62cee8ef..210ea5379e3b 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_top.h +++ b/drivers/gpu/drm/msm/sde/sde_hw_top.h @@ -194,6 +194,15 @@ struct sde_hw_mdp_ops { * @mdp: mdp top context driver */ void (*intf_audio_select)(struct sde_hw_mdp *mdp); + + /** + * set_cwb_ppb_cntl - select the data point for CWB + * @mdp: mdp top context driver + * @dual: indicates if dual pipe line needs to be programmed + * @dspp_out : true if dspp output required. LM is default tap point + */ + void (*set_cwb_ppb_cntl)(struct sde_hw_mdp *mdp, + bool dual, bool dspp_out); }; struct sde_hw_mdp { diff --git a/drivers/gpu/drm/msm/sde/sde_hwio.h b/drivers/gpu/drm/msm/sde/sde_hwio.h index cc020d993def..a59222350a11 100644 --- a/drivers/gpu/drm/msm/sde/sde_hwio.h +++ b/drivers/gpu/drm/msm/sde/sde_hwio.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -40,6 +40,8 @@ #define PPB0_CONFIG 0x334 #define PPB1_CNTL 0x338 #define PPB1_CONFIG 0x33C +#define PPB2_CNTL 0x370 +#define PPB3_CNTL 0x374 #define HW_EVENTS_CTL 0x37C #define CLK_CTRL3 0x3A8 #define CLK_STATUS3 0x3AC -- GitLab From b35a5584da9f460c65019214f244050058d54c27 Mon Sep 17 00:00:00 2001 From: Shiraz Hashim Date: Tue, 1 May 2018 17:58:51 +0530 Subject: [PATCH 1748/1834] mm: cma: Increase retries if less blocks available If a particular cma region has lesser free blocks then increase retries to avoid allocation failure due to page being temporarily busy. Change-Id: I92021fd75315b266a978f7a5b0235344c800cba2 Signed-off-by: Shiraz Hashim --- mm/cma.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mm/cma.c b/mm/cma.c index 5fc18097fcc5..e97ad01ef148 100644 --- a/mm/cma.c +++ b/mm/cma.c @@ -438,6 +438,8 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) struct page *page = NULL; int retry_after_sleep = 0; int ret = -ENOMEM; + int max_retries = 2; + int available_regions = 0; if (!cma || !cma->count) return NULL; @@ -464,8 +466,15 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) bitmap_maxno, start, bitmap_count, mask, offset); if (bitmap_no >= bitmap_maxno) { - if (retry_after_sleep < 2) { + if (retry_after_sleep < max_retries) { start = 0; + /* + * update max retries if available free regions + * are less. + */ + if (available_regions < 3) + max_retries = 5; + available_regions = 0; /* * Page may be momentarily pinned by some other * process which has been scheduled out, eg. @@ -483,6 +492,8 @@ struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align) break; } } + + available_regions++; bitmap_set(cma->bitmap, bitmap_no, bitmap_count); /* * It's safe to drop the lock here. We've marked this region for -- GitLab From 7cc81107297efcae6b466753c87856f345beaebe Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Fri, 23 Mar 2018 10:23:58 +0530 Subject: [PATCH 1749/1834] power: smb1355: force enable clock while device is active To optimize on power the SMB hardware disables the Bandgap/clock when the charger is removed. When this happens, the SMB1355 IRQ line stays stuck in its last known state. I.e. if there was an interrupt pending (the IRQ line is low) and if the Bandgap/clock gets disabled, the line stays stuck low forever causing a storm of interrupts. Fix this by forcing SMB1355 clock "on" as long as device is up and and running and turn off the clock in ship-mode and shutdown path. Change-Id: If01e07c63119b6af555ffd064d1055417c6b3e46 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/smb1355-charger.c | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/power/supply/qcom/smb1355-charger.c b/drivers/power/supply/qcom/smb1355-charger.c index 327ae630143e..1d99ccb9dd14 100644 --- a/drivers/power/supply/qcom/smb1355-charger.c +++ b/drivers/power/supply/qcom/smb1355-charger.c @@ -108,6 +108,9 @@ #define BARK_BITE_WDOG_PET_REG (MISC_BASE + 0x43) #define BARK_BITE_WDOG_PET_BIT BIT(0) +#define CLOCK_REQUEST_REG (MISC_BASE + 0x44) +#define CLOCK_REQUEST_CMD_BIT BIT(0) + #define WD_CFG_REG (MISC_BASE + 0x51) #define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7) #define BARK_WDOG_INT_EN_BIT BIT(6) @@ -249,6 +252,9 @@ struct smb1355 { static bool is_secure(struct smb1355 *chip, int addr) { + if (addr == CLOCK_REQUEST_REG) + return true; + /* assume everything above 0xA0 is secure */ return (addr & 0xFF) >= 0xA0; } @@ -265,6 +271,25 @@ static int smb1355_read(struct smb1355 *chip, u16 addr, u8 *val) return rc; } +static int smb1355_masked_force_write(struct smb1355 *chip, u16 addr, u8 mask, + u8 val) +{ + int rc; + + mutex_lock(&chip->write_lock); + if (is_secure(chip, addr)) { + rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5); + if (rc < 0) + goto unlock; + } + + rc = regmap_write_bits(chip->regmap, addr, mask, val); + +unlock: + mutex_unlock(&chip->write_lock); + return rc; +} + static int smb1355_masked_write(struct smb1355 *chip, u16 addr, u8 mask, u8 val) { int rc; @@ -494,6 +519,7 @@ static enum power_supply_property smb1355_parallel_props[] = { POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_CURRENT_MAX, + POWER_SUPPLY_PROP_SET_SHIP_MODE, }; static int smb1355_get_prop_batt_charge_type(struct smb1355 *chip, @@ -635,6 +661,10 @@ static int smb1355_parallel_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PARALLEL_FCC_MAX: val->intval = chip->max_fcc; break; + case POWER_SUPPLY_PROP_SET_SHIP_MODE: + /* Not in ship mode as long as device is active */ + val->intval = 0; + break; default: pr_err_ratelimited("parallel psy get prop %d not supported\n", prop); @@ -726,6 +756,20 @@ static int smb1355_set_current_max(struct smb1355 *chip, int curr) return rc; } +static int smb1355_clk_request(struct smb1355 *chip, bool enable) +{ + int rc; + + rc = smb1355_masked_force_write(chip, CLOCK_REQUEST_REG, + CLOCK_REQUEST_CMD_BIT, + enable ? CLOCK_REQUEST_CMD_BIT : 0); + if (rc < 0) + pr_err("Couldn't %s clock rc=%d\n", + enable ? "enable" : "disable", rc); + + return rc; +} + static int smb1355_parallel_set_prop(struct power_supply *psy, enum power_supply_property prop, const union power_supply_propval *val) @@ -752,6 +796,11 @@ static int smb1355_parallel_set_prop(struct power_supply *psy, chip->c_health = val->intval; power_supply_changed(chip->parallel_psy); break; + case POWER_SUPPLY_PROP_SET_SHIP_MODE: + if (!val->intval) + break; + rc = smb1355_clk_request(chip, false); + break; default: pr_debug("parallel power supply set prop %d not supported\n", prop); @@ -930,6 +979,11 @@ static int smb1355_init_hw(struct smb1355 *chip) { int rc; + /* request clock always on */ + rc = smb1355_clk_request(chip, true); + if (rc < 0) + return rc; + /* enable watchdog bark and bite interrupts, and disable the watchdog */ rc = smb1355_masked_write(chip, WD_CFG_REG, WDOG_TIMER_EN_BIT | WDOG_TIMER_EN_ON_PLUGIN_BIT | BITE_WDOG_INT_EN_BIT @@ -1340,6 +1394,8 @@ static void smb1355_shutdown(struct platform_device *pdev) rc = smb1355_set_parallel_charging(chip, true); if (rc < 0) pr_err("Couldn't disable parallel path rc=%d\n", rc); + + smb1355_clk_request(chip, false); } static struct platform_driver smb1355_driver = { -- GitLab From 92d9690e0db29b6a1d8fa77014a850aa4d147c3a Mon Sep 17 00:00:00 2001 From: Naseer Ahmed Date: Tue, 3 Jan 2017 16:57:19 -0500 Subject: [PATCH 1750/1834] msm: mdss: Reset compression config after dynamic DSC off When dynamically switching modes from DSC on to off, the compression mode control register should be set to 0 to avoid corruption on the output. Change-Id: Id4387063b767bf0f307c13831b9c6ecc31c20650 Signed-off-by: Naseer Ahmed --- drivers/video/fbdev/msm/mdss_dsi.h | 2 +- drivers/video/fbdev/msm/mdss_dsi_host.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index fd6c4d9b469e..44b1e710b197 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -407,7 +407,7 @@ struct mdss_dsi_ctrl_pdata { int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp); void (*switch_mode)(struct mdss_panel_data *pdata, int mode); struct mdss_panel_data panel_data; - unsigned char *ctrl_base; + unsigned char __iomem *ctrl_base; struct mdss_io_data ctrl_io; struct mdss_io_data mmss_misc_io; struct mdss_io_data phy_io; diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index ca0af2bd8944..2ec96d499488 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -1244,6 +1244,15 @@ void mdss_dsi_dsc_config(struct mdss_dsi_ctrl_pdata *ctrl, struct dsc_desc *dsc) { u32 data, offset; + if (!dsc) { + if (ctrl->panel_mode == DSI_VIDEO_MODE) + offset = MDSS_DSI_VIDEO_COMPRESSION_MODE_CTRL; + else + offset = MDSS_DSI_COMMAND_COMPRESSION_MODE_CTRL; + MIPI_OUTP((ctrl->ctrl_base) + offset, 0); + return; + } + if (dsc->pkt_per_line <= 0) { pr_err("%s: Error: pkt_per_line cannot be negative or 0\n", __func__); @@ -1432,8 +1441,7 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata) MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x5C, stream_total); } - if (dsc) /* compressed */ - mdss_dsi_dsc_config(ctrl_pdata, dsc); + mdss_dsi_dsc_config(ctrl_pdata, dsc); } void mdss_dsi_ctrl_setup(struct mdss_dsi_ctrl_pdata *ctrl) -- GitLab From 812f5008fbc93e64d264b4024a7209f0352c1dfc Mon Sep 17 00:00:00 2001 From: Sandeep Panda Date: Fri, 24 Feb 2017 11:36:59 +0530 Subject: [PATCH 1751/1834] msm: mdss: add debug bus support for dsi block Add support to dump dsi debug bus registers to memory or print in xlog. This will be helpful in analyzing HW behavior more precisely while debugging DSI stability issues. Change-Id: I7735897d9f24ca06e15015cf0d277bfe800b35bf Signed-off-by: Sandeep Panda --- drivers/video/fbdev/msm/mdss_debug.c | 54 +++++++++++ drivers/video/fbdev/msm/mdss_debug.h | 1 + drivers/video/fbdev/msm/mdss_debug_xlog.c | 21 ++++- drivers/video/fbdev/msm/mdss_dsi.c | 94 +++++++++++++++++++ drivers/video/fbdev/msm/mdss_dsi.h | 6 +- drivers/video/fbdev/msm/mdss_dsi_host.c | 6 +- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 2 +- drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 6 +- drivers/video/fbdev/msm/mdss_mdp_intf_video.c | 2 +- 9 files changed, 183 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_debug.c b/drivers/video/fbdev/msm/mdss_debug.c index f38d40c8aa18..29ebcad4c818 100644 --- a/drivers/video/fbdev/msm/mdss_debug.c +++ b/drivers/video/fbdev/msm/mdss_debug.c @@ -46,6 +46,42 @@ #define INVALID_XIN_ID 0xFF +static u32 dsi_dbg_bus_sdm660[] = { + 0x0001, 0x1001, 0x0001, 0x0011, + 0x1021, 0x0021, 0x0031, 0x0041, + 0x0051, 0x0061, 0x3061, 0x0061, + 0x2061, 0x2061, 0x1061, 0x1061, + 0x1061, 0x0071, 0x0071, 0x0071, + 0x0081, 0x0081, 0x00A1, 0x00A1, + 0x10A1, 0x20A1, 0x30A1, 0x10A1, + 0x10A1, 0x30A1, 0x20A1, 0x00B1, + 0x00C1, 0x00C1, 0x10C1, 0x20C1, + 0x30C1, 0x00D1, 0x00D1, 0x20D1, + 0x30D1, 0x00E1, 0x00E1, 0x00E1, + 0x00F1, 0x00F1, 0x0101, 0x0101, + 0x1101, 0x2101, 0x3101, 0x0111, + 0x0141, 0x1141, 0x0141, 0x1141, + 0x1141, 0x0151, 0x0151, 0x1151, + 0x2151, 0x3151, 0x0161, 0x0161, + 0x1161, 0x0171, 0x0171, 0x0181, + 0x0181, 0x0191, 0x0191, 0x01A1, + 0x01A1, 0x01B1, 0x01B1, 0x11B1, + 0x21B1, 0x01C1, 0x01C1, 0x11C1, + 0x21C1, 0x31C1, 0x01D1, 0x01D1, + 0x01D1, 0x01D1, 0x11D1, 0x21D1, + 0x21D1, 0x01E1, 0x01E1, 0x01F1, + 0x01F1, 0x0201, 0x0201, 0x0211, + 0x0221, 0x0231, 0x0241, 0x0251, + 0x0281, 0x0291, 0x0281, 0x0291, + 0x02A1, 0x02B1, 0x02C1, 0x0321, + 0x0321, 0x1321, 0x2321, 0x3321, + 0x0331, 0x0331, 0x1331, 0x0341, + 0x0341, 0x1341, 0x2341, 0x3341, + 0x0351, 0x0361, 0x0361, 0x1361, + 0x2361, 0x0371, 0x0381, 0x0391, + 0x03C1, 0x03D1, 0x03E1, 0x03F1, +}; + static DEFINE_MUTEX(mdss_debug_lock); static char panel_reg[2] = {DEFAULT_READ_PANEL_POWER_MODE_REG, 0x00}; @@ -1786,6 +1822,24 @@ void mdss_misr_crc_collect(struct mdss_data_type *mdata, int block_id, } +void mdss_dsi_debug_bus_init(struct mdss_dsi_data *sdata) +{ + if (!sdata) + return; + + sdata->dbg_bus = NULL; + sdata->dbg_bus_size = 0; + + switch (sdata->shared_data->hw_rev) { + case MDSS_DSI_HW_REV_201: + sdata->dbg_bus = dsi_dbg_bus_sdm660; + sdata->dbg_bus_size = ARRAY_SIZE(dsi_dbg_bus_sdm660); + break; + default: + break; + } +} + int mdss_dump_misr_data(char **buf, u32 size) { struct mdss_mdp_misr_map *dsi0_map; diff --git a/drivers/video/fbdev/msm/mdss_debug.h b/drivers/video/fbdev/msm/mdss_debug.h index 0d482c033d0f..3c8da2967ec3 100644 --- a/drivers/video/fbdev/msm/mdss_debug.h +++ b/drivers/video/fbdev/msm/mdss_debug.h @@ -173,6 +173,7 @@ u32 get_dump_range(struct dump_offset *range_node, size_t max_offset); void mdss_dump_reg(const char *dump_name, u32 reg_dump_flag, char *addr, int len, u32 **dump_mem, bool from_isr); void mdss_mdp_debug_mid(u32 mid); +void mdss_dump_dsi_debug_bus(u32 bus_dump_flag, u32 **dump_mem); #else struct mdss_debug_base; struct dump_offset; diff --git a/drivers/video/fbdev/msm/mdss_debug_xlog.c b/drivers/video/fbdev/msm/mdss_debug_xlog.c index a651b5586e90..7bf4f1100e2c 100644 --- a/drivers/video/fbdev/msm/mdss_debug_xlog.c +++ b/drivers/video/fbdev/msm/mdss_debug_xlog.c @@ -32,6 +32,7 @@ #define XLOG_DEFAULT_REGDUMP 0x2 /* dump in RAM */ #define XLOG_DEFAULT_DBGBUSDUMP 0x2 /* dump in RAM */ #define XLOG_DEFAULT_VBIF_DBGBUSDUMP 0x2 /* dump in RAM */ +#define XLOG_DEFAULT_DSI_DBGBUSDUMP 0x2 /* dump in RAM */ /* * xlog will print this number of entries when it is called through @@ -73,14 +74,17 @@ struct mdss_dbg_xlog { u32 enable_reg_dump; u32 enable_dbgbus_dump; u32 enable_vbif_dbgbus_dump; + u32 enable_dsi_dbgbus_dump; struct work_struct xlog_dump_work; struct mdss_debug_base *blk_arr[MDSS_DEBUG_BASE_MAX]; bool work_panic; bool work_dbgbus; bool work_vbif_dbgbus; + bool work_dsi_dbgbus; u32 *dbgbus_dump; /* address for the debug bus dump */ u32 *vbif_dbgbus_dump; /* address for the vbif debug bus dump */ u32 *nrt_vbif_dbgbus_dump; /* address for the nrt vbif debug bus dump */ + u32 *dsi_dbgbus_dump; /* address for the dsi debug bus dump */ } mdss_dbg_xlog; static inline bool mdss_xlog_is_enabled(u32 flag) @@ -572,7 +576,7 @@ struct mdss_debug_base *get_dump_blk_addr(const char *blk_name) static void mdss_xlog_dump_array(struct mdss_debug_base *blk_arr[], u32 len, bool dead, const char *name, bool dump_dbgbus, - bool dump_vbif_dbgbus) + bool dump_vbif_dbgbus, bool dump_dsi_dbgbus) { int i; @@ -596,6 +600,10 @@ static void mdss_xlog_dump_array(struct mdss_debug_base *blk_arr[], &mdss_dbg_xlog.nrt_vbif_dbgbus_dump, false); } + if (dump_dsi_dbgbus) + mdss_dump_dsi_debug_bus(mdss_dbg_xlog.enable_dsi_dbgbus_dump, + &mdss_dbg_xlog.dsi_dbgbus_dump); + if (dead && mdss_dbg_xlog.panic_on_err) panic(name); } @@ -607,7 +615,8 @@ static void xlog_debug_work(struct work_struct *work) ARRAY_SIZE(mdss_dbg_xlog.blk_arr), mdss_dbg_xlog.work_panic, "xlog_workitem", mdss_dbg_xlog.work_dbgbus, - mdss_dbg_xlog.work_vbif_dbgbus); + mdss_dbg_xlog.work_vbif_dbgbus, + mdss_dbg_xlog.work_dsi_dbgbus); } void mdss_xlog_tout_handler_default(bool queue, const char *name, ...) @@ -615,6 +624,7 @@ void mdss_xlog_tout_handler_default(bool queue, const char *name, ...) int i, index = 0; bool dead = false; bool dump_dbgbus = false, dump_vbif_dbgbus = false; + bool dump_dsi_dbgbus = false; va_list args; char *blk_name = NULL; struct mdss_debug_base *blk_base = NULL; @@ -650,6 +660,9 @@ void mdss_xlog_tout_handler_default(bool queue, const char *name, ...) if (!strcmp(blk_name, "vbif_dbg_bus")) dump_vbif_dbgbus = true; + if (!strcmp(blk_name, "dsi_dbg_bus")) + dump_dsi_dbgbus = true; + if (!strcmp(blk_name, "panic")) dead = true; } @@ -660,10 +673,11 @@ void mdss_xlog_tout_handler_default(bool queue, const char *name, ...) mdss_dbg_xlog.work_panic = dead; mdss_dbg_xlog.work_dbgbus = dump_dbgbus; mdss_dbg_xlog.work_vbif_dbgbus = dump_vbif_dbgbus; + mdss_dbg_xlog.work_dsi_dbgbus = dump_dsi_dbgbus; schedule_work(&mdss_dbg_xlog.xlog_dump_work); } else { mdss_xlog_dump_array(blk_arr, blk_len, dead, name, dump_dbgbus, - dump_vbif_dbgbus); + dump_vbif_dbgbus, dump_dsi_dbgbus); } } @@ -752,6 +766,7 @@ int mdss_create_xlog_debug(struct mdss_debug_data *mdd) mdss_dbg_xlog.enable_reg_dump = XLOG_DEFAULT_REGDUMP; mdss_dbg_xlog.enable_dbgbus_dump = XLOG_DEFAULT_DBGBUSDUMP; mdss_dbg_xlog.enable_vbif_dbgbus_dump = XLOG_DEFAULT_VBIF_DBGBUSDUMP; + mdss_dbg_xlog.enable_dsi_dbgbus_dump = XLOG_DEFAULT_DSI_DBGBUSDUMP; pr_info("xlog_status: enable:%d, panic:%d, dump:%d\n", mdss_dbg_xlog.xlog_enable, mdss_dbg_xlog.panic_on_err, diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index d8e74dab4251..3fe8ad22d3a6 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "mdss.h" #include "mdss_panel.h" @@ -46,6 +47,97 @@ static struct mdss_dsi_data *mdss_dsi_res; static struct pm_qos_request mdss_dsi_pm_qos_request; +void mdss_dump_dsi_debug_bus(u32 bus_dump_flag, + u32 **dump_mem) +{ + struct mdss_dsi_data *sdata = mdss_dsi_res; + struct mdss_dsi_ctrl_pdata *m_ctrl, *s_ctrl; + bool in_log, in_mem; + u32 *dump_addr = NULL; + u32 status0 = 0, status1 = 0; + phys_addr_t phys = 0; + int list_size = 0; + int i; + bool dsi0_active = false, dsi1_active = false; + + if (!sdata || !sdata->dbg_bus || !sdata->dbg_bus_size) + return; + + m_ctrl = sdata->ctrl_pdata[0]; + s_ctrl = sdata->ctrl_pdata[1]; + + if (!m_ctrl) + return; + + if (m_ctrl && m_ctrl->shared_data->dsi0_active) + dsi0_active = true; + if (s_ctrl && s_ctrl->shared_data->dsi1_active) + dsi1_active = true; + + list_size = (sdata->dbg_bus_size * sizeof(sdata->dbg_bus[0]) * 4); + + in_log = (bus_dump_flag & MDSS_DBG_DUMP_IN_LOG); + in_mem = (bus_dump_flag & MDSS_DBG_DUMP_IN_MEM); + + if (in_mem) { + if (!(*dump_mem)) + *dump_mem = dma_alloc_coherent(&sdata->pdev->dev, + list_size, &phys, GFP_KERNEL); + + if (*dump_mem) { + dump_addr = *dump_mem; + pr_info("%s: start_addr:0x%pK end_addr:0x%pK\n", + __func__, dump_addr, dump_addr + list_size); + } else { + in_mem = false; + pr_err("dump_mem: allocation fails\n"); + } + } + + pr_info("========= Start DSI Debug Bus =========\n"); + + mdss_dsi_clk_ctrl(m_ctrl, m_ctrl->dsi_clk_handle, + MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_ON); + + for (i = 0; i < sdata->dbg_bus_size; i++) { + if (dsi0_active) { + writel_relaxed(sdata->dbg_bus[i], + m_ctrl->ctrl_base + 0x124); + wmb(); /* ensure regsiter is committed */ + } + if (dsi1_active) { + writel_relaxed(sdata->dbg_bus[i], + s_ctrl->ctrl_base + 0x124); + wmb(); /* ensure register is committed */ + } + + if (dsi0_active) { + status0 = readl_relaxed(m_ctrl->ctrl_base + 0x128); + if (in_log) + pr_err("CTRL:0 bus_ctrl: 0x%x status: 0x%x\n", + sdata->dbg_bus[i], status0); + } + if (dsi1_active) { + status1 = readl_relaxed(s_ctrl->ctrl_base + 0x128); + if (in_log) + pr_err("CTRL:1 bus_ctrl: 0x%x status: 0x%x\n", + sdata->dbg_bus[i], status1); + } + + if (dump_addr && in_mem) { + dump_addr[i*4] = sdata->dbg_bus[i]; + dump_addr[i*4 + 1] = status0; + dump_addr[i*4 + 2] = status1; + dump_addr[i*4 + 3] = 0x0; + } + } + + mdss_dsi_clk_ctrl(m_ctrl, m_ctrl->dsi_clk_handle, + MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF); + + pr_info("========End DSI Debug Bus=========\n"); +} + static void mdss_dsi_pm_qos_add_request(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { struct irq_info *irq_info; @@ -3340,6 +3432,8 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) else ctrl_pdata->shared_data->dsi1_active = true; + mdss_dsi_debug_bus_init(mdss_dsi_res); + return 0; error_shadow_clk_deinit: diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 44b1e710b197..5e921ff515ce 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -57,7 +57,7 @@ #define MDSS_DSI_HW_REV_104 0x10040000 /* 8996 */ #define MDSS_DSI_HW_REV_104_1 0x10040001 /* 8996 */ #define MDSS_DSI_HW_REV_104_2 0x10040002 /* 8937 */ - +#define MDSS_DSI_HW_REV_201 20010000 /* 660 */ #define MDSS_DSI_HW_REV_STEP_0 0x0 #define MDSS_DSI_HW_REV_STEP_1 0x1 #define MDSS_DSI_HW_REV_STEP_2 0x2 @@ -297,6 +297,8 @@ struct mdss_dsi_data { * mutex, clocks, regulator information, setup information */ struct dsi_shared_data *shared_data; + u32 *dbg_bus; + int dbg_bus_size; }; /* @@ -684,6 +686,8 @@ void mdss_dsi_set_reg(struct mdss_dsi_ctrl_pdata *ctrl, int off, int mdss_dsi_phy_pll_reset_status(struct mdss_dsi_ctrl_pdata *ctrl); int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata, int power_state); +void mdss_dsi_debug_bus_init(struct mdss_dsi_data *sdata); + static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module) { switch (module) { diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 2ec96d499488..20a9f13fce25 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -1498,6 +1498,8 @@ int mdss_dsi_bta_status_check(struct mdss_dsi_ctrl_pdata *ctrl_pdata) /* mask out overflow errors */ if (ignore_underflow) mdss_dsi_set_reg(ctrl_pdata, 0x10c, 0x0f0000, 0x0f0000); + + MDSS_XLOG(ctrl_pdata->ndx, ctrl_pdata->mdp_busy); MIPI_OUTP(ctrl_pdata->ctrl_base + 0x098, 0x01); /* trigger */ wmb(); /* ensure write is finished before progressing */ @@ -2118,6 +2120,7 @@ static int mdss_dsi_cmd_dma_tx(struct mdss_dsi_ctrl_pdata *ctrl, MIPI_OUTP((ctrl->ctrl_base) + 0x090, 0x01); wmb(); /* ensure write is finished before progressing */ + MDSS_XLOG(ctrl->dma_addr, len); if (ctrl->do_unicast) { /* let cmd_trigger to kickoff later */ @@ -3145,7 +3148,7 @@ static void __dsi_error_counter(struct dsi_err_container *err_container) pr_err("%s: panic in WQ as dsi error intrs within:%dms\n", __func__, err_container->err_time_delta); MDSS_XLOG_TOUT_HANDLER_WQ("mdp", "dsi0_ctrl", "dsi0_phy", - "dsi1_ctrl", "dsi1_phy"); + "dsi1_ctrl", "dsi1_phy", "dsi_dbg_bus", "panic"); } } @@ -3235,6 +3238,7 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) } if (isr & DSI_INTR_VIDEO_DONE) { + MDSS_XLOG(ctrl->ndx, isr, 0x111); spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_VIDEO_TERM); complete(&ctrl->video_comp); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 344d6efc2f37..6b32c723eeee 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -4344,7 +4344,7 @@ void mdss_mdp_check_ctl_reset_status(struct mdss_mdp_ctl *ctl) if (status) { pr_err("hw recovery is not complete for ctl:%d\n", ctl->num); MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt", "dbg_bus", - "vbif_dbg_bus", "panic"); + "vbif_dbg_bus", "dsi_dbg_bus", "panic"); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index 764b8303d228..b49e9545acad 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -1975,12 +1975,14 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg) MDSS_XLOG(0xbad); MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt", - "dbg_bus", "vbif_dbg_bus", "panic"); + "dbg_bus", "vbif_dbg_bus", + "dsi_dbg_bus", "panic"); } else if (ctx->pp_timeout_report_cnt == MAX_RECOVERY_TRIALS) { MDSS_XLOG(0xbad2); MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif", "vbif_nrt", - "dbg_bus", "vbif_dbg_bus", "panic"); + "dbg_bus", "vbif_dbg_bus", + "dsi_dbg_bus", "panic"); mdss_fb_report_panel_dead(ctl->mfd); } diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c index 7b69aa398425..f18987ce4da7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_video.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_video.c @@ -1252,7 +1252,7 @@ static int mdss_mdp_video_wait4vsync(struct mdss_mdp_ctl *ctl) pr_err("error polling for vsync\n"); MDSS_XLOG_TOUT_HANDLER("mdp", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl", "dsi1_phy", "vbif", "dbg_bus", - "vbif_dbg_bus", "panic"); + "vbif_dbg_bus", "dsi_dbg_bus", "panic"); } } else { rc = 0; -- GitLab From 75a16fa5e4285dc834e09f1c0b0422bed952e2fc Mon Sep 17 00:00:00 2001 From: Monika Singh Date: Fri, 13 Apr 2018 17:14:33 +0530 Subject: [PATCH 1752/1834] ARM: dts: msm: Mount system and vendor for SDM439 Add avb flag when mounting system and vendor images for non-multislot. When multislot is disabled system is not the root folder hence early mounting to be done using dtsi. Change-Id: I8d523bfb634479ff56d6328559569f1c8d535e08 Signed-off-by: Monika Singh --- arch/arm64/boot/dts/qcom/msm8937.dtsi | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/msm8937.dtsi b/arch/arm64/boot/dts/qcom/msm8937.dtsi index d22101fe41e6..66c7e7cd987f 100644 --- a/arch/arm64/boot/dts/qcom/msm8937.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8937.dtsi @@ -30,6 +30,11 @@ firmware: firmware { android { compatible = "android,firmware"; + vbmeta { + compatible = "android,vbmeta"; + parts = "vbmeta,boot,system,vendor,dtbo,recovery"; + }; + fstab { compatible = "android,fstab"; vendor { @@ -37,7 +42,7 @@ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,avb"; status = "ok"; }; system { @@ -45,7 +50,7 @@ dev = "/dev/block/platform/soc/7824900.sdhci/by-name/system"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait"; + fsmgr_flags = "wait,avb"; status = "ok"; }; -- GitLab From ee1cc4bc858ac08bbe14aa6412ea54c29e9fc0e6 Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Mon, 14 May 2018 12:32:27 +0530 Subject: [PATCH 1753/1834] defconfig: arm: msm: Add video configs for msm8909w Add config to enable video on msm8909w 32bit. Change-Id: I1cf73a2abee7e25d3e1016d2d1c9f1fee85db7ec Signed-off-by: Arun kumar --- arch/arm/configs/msm8909w-perf_defconfig | 2 ++ arch/arm/configs/msm8909w_defconfig | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 9b5574004872..a63ab11b99d3 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -310,6 +310,8 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_VIDC_3X_V4L2=y +CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index bb6bc88e548f..88259b50a1c9 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -322,6 +322,8 @@ CONFIG_MEDIA_CAMERA_SUPPORT=y CONFIG_MEDIA_CONTROLLER=y CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_MSM_VIDC_3X_V4L2=y +CONFIG_MSM_VIDC_3X_GOVERNORS=y CONFIG_QCOM_KGSL=y CONFIG_FB=y CONFIG_FB_VIRTUAL=y -- GitLab From 553512b86a3f6ac20544559a96501c7d4360636c Mon Sep 17 00:00:00 2001 From: Vishwanath Raju K Date: Tue, 17 Apr 2018 18:00:02 +0530 Subject: [PATCH 1754/1834] ARM: dts: msm: modem carveout size is reduced for qcs605. Reduced pil_modem_mem size to 49MB from 62MB for QCS605. Change-Id: I0d5d7a29b86b626d6c03d365f6d701d6c0b6370e Signed-off-by: Vishwanath Raju K --- arch/arm64/boot/dts/qcom/qcs605.dtsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/qcs605.dtsi b/arch/arm64/boot/dts/qcom/qcs605.dtsi index be88a5dfead1..747593f87f88 100644 --- a/arch/arm64/boot/dts/qcom/qcs605.dtsi +++ b/arch/arm64/boot/dts/qcom/qcs605.dtsi @@ -19,39 +19,39 @@ }; &pil_modem_mem { - reg = <0 0x8b000000 0 0x3e00000>; + reg = <0 0x8b000000 0 0x3100000>; }; &pil_video_mem { - reg = <0 0x8ee00000 0 0x500000>; + reg = <0 0x8e100000 0 0x500000>; }; &wlan_msa_mem { - reg = <0 0x8f300000 0 0x100000>; + reg = <0 0x8e600000 0 0x100000>; }; &pil_cdsp_mem { - reg = <0 0x8f400000 0 0x800000>; + reg = <0 0x8e700000 0 0x800000>; }; &pil_mba_mem { - reg = <0 0x8fc00000 0 0x200000>; + reg = <0 0x8ef00000 0 0x200000>; }; &pil_adsp_mem { - reg = <0 0x8fe00000 0 0x1e00000>; + reg = <0 0x8f100000 0 0x1e00000>; }; &pil_ipa_fw_mem { - reg = <0 0x91c00000 0 0x10000>; + reg = <0 0x90f00000 0 0x10000>; }; &pil_ipa_gsi_mem { - reg = <0 0x91c10000 0 0x5000>; + reg = <0 0x90f10000 0 0x5000>; }; &pil_gpu_mem { - reg = <0 0x91c15000 0 0x2000>; + reg = <0 0x90f15000 0 0x2000>; }; &adsp_mem { -- GitLab From 9ec0ee5b7679771458fb93ccdbd66bf7c6826690 Mon Sep 17 00:00:00 2001 From: Vamshi Krishna B V Date: Thu, 10 May 2018 18:00:49 +0530 Subject: [PATCH 1755/1834] power: qpnp-qg: Add CYCLE_COUNT property Currently, CYCLE_COUNTS property shows the bucket cycle counters as a string. Add CYCLE_COUNT property in QG that can provide an average of all the bucket counters. Move the helper functions that gets the cycle_counts and cycle_count property to fg-alg.c so that it can re-used. CRs-Fixed: 2238261 Change-Id: I18c32590c4c30e6d347284b43ac0a408614c0ffa Signed-off-by: Vamshi Krishna B V --- drivers/power/supply/qcom/fg-alg.c | 66 ++++++++++++++++++++++++++++- drivers/power/supply/qcom/fg-alg.h | 4 +- drivers/power/supply/qcom/qg-core.h | 1 - drivers/power/supply/qcom/qpnp-qg.c | 34 +++------------ 4 files changed, 74 insertions(+), 31 deletions(-) diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c index f1ce5b3057d7..9b9a88028dc9 100644 --- a/drivers/power/supply/qcom/fg-alg.c +++ b/drivers/power/supply/qcom/fg-alg.c @@ -164,13 +164,13 @@ void cycle_count_update(struct cycle_counter *counter, int batt_soc, } /** - * get_cycle_count - + * get_bucket_cycle_count - * @counter: Cycle counter object * * Returns the cycle counter for a SOC bucket. * */ -int get_cycle_count(struct cycle_counter *counter) +static int get_bucket_cycle_count(struct cycle_counter *counter) { int count; @@ -186,6 +186,68 @@ int get_cycle_count(struct cycle_counter *counter) return count; } +/** + * get_cycle_counts - + * @counter: Cycle counter object + * @buf: Bucket cycle counts formatted in a string returned to the caller + * + * Get cycle count for all buckets in a string format + */ +int get_cycle_counts(struct cycle_counter *counter, const char **buf) +{ + int i, rc, len = 0; + + for (i = 1; i <= BUCKET_COUNT; i++) { + counter->id = i; + rc = get_bucket_cycle_count(counter); + if (rc < 0) { + pr_err("Couldn't get cycle count rc=%d\n", rc); + return rc; + } + + if (sizeof(counter->str_buf) - len < 8) { + pr_err("Invalid length %d\n", len); + return -EINVAL; + } + + len += snprintf(counter->str_buf+len, 8, "%d ", rc); + } + + counter->str_buf[len] = '\0'; + *buf = counter->str_buf; + return 0; +} + +/** + * get_cycle_count - + * @counter: Cycle counter object + * @count: Average cycle count returned to the caller + * + * Get average cycle count for all buckets + */ +int get_cycle_count(struct cycle_counter *counter, int *count) +{ + int i, rc, temp = 0; + + for (i = 1; i <= BUCKET_COUNT; i++) { + counter->id = i; + rc = get_bucket_cycle_count(counter); + if (rc < 0) { + pr_err("Couldn't get cycle count rc=%d\n", rc); + return rc; + } + + temp += rc; + } + + /* + * Normalize the counter across each bucket so that we can get + * the overall charge cycle count. + */ + *count = temp / BUCKET_COUNT; + return 0; +} + /** * cycle_count_init - * @counter: Cycle counter object diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h index 0853ad9c32b7..7c2500720297 100644 --- a/drivers/power/supply/qcom/fg-alg.h +++ b/drivers/power/supply/qcom/fg-alg.h @@ -21,6 +21,7 @@ struct cycle_counter { bool started[BUCKET_COUNT]; u16 count[BUCKET_COUNT]; u8 last_soc[BUCKET_COUNT]; + char str_buf[BUCKET_COUNT * 8]; int id; int last_bucket; struct mutex lock; @@ -61,7 +62,8 @@ int restore_cycle_count(struct cycle_counter *counter); void clear_cycle_count(struct cycle_counter *counter); void cycle_count_update(struct cycle_counter *counter, int batt_soc, int charge_status, bool charge_done, bool input_present); -int get_cycle_count(struct cycle_counter *counter); +int get_cycle_count(struct cycle_counter *counter, int *count); +int get_cycle_counts(struct cycle_counter *counter, const char **buf); int cycle_count_init(struct cycle_counter *counter); void cap_learning_abort(struct cap_learning *cl); void cap_learning_update(struct cap_learning *cl, int batt_temp, diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h index 05ca4529e6c6..a1aeac2b86ef 100644 --- a/drivers/power/supply/qcom/qg-core.h +++ b/drivers/power/supply/qcom/qg-core.h @@ -126,7 +126,6 @@ struct qpnp_qg { struct cap_learning *cl; /* charge counter */ struct cycle_counter *counter; - char counter_buf[BUCKET_COUNT * 8]; }; enum ocv_type { diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 09705ade7b30..14b9205ebfc1 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -1171,32 +1171,6 @@ static int qg_get_battery_capacity(struct qpnp_qg *chip, int *soc) return 0; } -static const char *qg_get_cycle_counts(struct qpnp_qg *chip) -{ - int i, rc, len = 0; - char *buf; - - buf = chip->counter_buf; - for (i = 1; i <= BUCKET_COUNT; i++) { - chip->counter->id = i; - rc = get_cycle_count(chip->counter); - if (rc < 0) { - pr_err("Couldn't get cycle count rc=%d\n", rc); - return NULL; - } - - if (sizeof(chip->counter_buf) - len < 8) { - pr_err("Invalid length %d\n", len); - return NULL; - } - - len += snprintf(buf+len, 8, "%d ", rc); - } - - buf[len] = '\0'; - return buf; -} - static int qg_psy_set_property(struct power_supply *psy, enum power_supply_property psp, const union power_supply_propval *pval) @@ -1302,7 +1276,12 @@ static int qg_psy_get_property(struct power_supply *psy, pval->intval = (int)temp; break; case POWER_SUPPLY_PROP_CYCLE_COUNTS: - pval->strval = qg_get_cycle_counts(chip); + rc = get_cycle_counts(chip->counter, &pval->strval); + if (rc < 0) + pval->strval = NULL; + break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + rc = get_cycle_count(chip->counter, &pval->intval); break; default: pr_debug("Unsupported property %d\n", psp); @@ -1340,6 +1319,7 @@ static enum power_supply_property qg_psy_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MAX, POWER_SUPPLY_PROP_BATT_FULL_CURRENT, POWER_SUPPLY_PROP_BATT_PROFILE_VERSION, + POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, -- GitLab From 3c50bb4fc8b87f5eda3e513a11544af80039d629 Mon Sep 17 00:00:00 2001 From: Sreelakshmi Gownipalli Date: Thu, 11 Jan 2018 10:45:23 -0800 Subject: [PATCH 1756/1834] diag: Initialize memory device memory pools Initialize memory device memory pools for diag bridge only during diag bridge initialization. Change-Id: I6454ced55e020ade9e3bb99a266548f77f79e193 Signed-off-by: Sreelakshmi Gownipalli Signed-off-by: Manoj Prabhu B --- drivers/char/diag/diag_memorydevice.c | 45 +++++++++++++++++++++++++-- drivers/char/diag/diag_memorydevice.h | 4 ++- drivers/char/diag/diagchar_core.c | 1 + 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index ce0c7bb2fbef..55b1b4961eeb 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -384,7 +384,7 @@ int diag_md_init(void) int i, j; struct diag_md_info *ch = NULL; - for (i = 0; i < NUM_DIAG_MD_DEV; i++) { + for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) { ch = &diag_md[i]; ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize; ch->tbl = kzalloc(ch->num_tbl_entries * @@ -408,12 +408,53 @@ int diag_md_init(void) return -ENOMEM; } +int diag_md_mdm_init(void) +{ + int i, j; + struct diag_md_info *ch = NULL; + + for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) { + ch = &diag_md[i]; + ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize; + ch->tbl = kcalloc(ch->num_tbl_entries, sizeof(*ch->tbl), + GFP_KERNEL); + if (!ch->tbl) + goto fail; + + for (j = 0; j < ch->num_tbl_entries; j++) { + ch->tbl[j].buf = NULL; + ch->tbl[j].len = 0; + ch->tbl[j].ctx = 0; + } + spin_lock_init(&(ch->lock)); + } + + return 0; + +fail: + diag_md_mdm_exit(); + return -ENOMEM; +} + void diag_md_exit(void) { int i; struct diag_md_info *ch = NULL; - for (i = 0; i < NUM_DIAG_MD_DEV; i++) { + for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) { + ch = &diag_md[i]; + kfree(ch->tbl); + ch->num_tbl_entries = 0; + ch->ops = NULL; + } +} + +void diag_md_mdm_exit(void) +{ + int i; + struct diag_md_info *ch = NULL; + + for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; kfree(ch->tbl); ch->num_tbl_entries = 0; diff --git a/drivers/char/diag/diag_memorydevice.h b/drivers/char/diag/diag_memorydevice.h index 35a1ee35a956..9b4aa392233d 100644 --- a/drivers/char/diag/diag_memorydevice.h +++ b/drivers/char/diag/diag_memorydevice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -46,7 +46,9 @@ struct diag_md_info { extern struct diag_md_info diag_md[NUM_DIAG_MD_DEV]; int diag_md_init(void); +int diag_md_mdm_init(void); void diag_md_exit(void); +void diag_md_mdm_exit(void); void diag_md_open_all(void); void diag_md_close_all(void); int diag_md_register(int id, int ctx, struct diag_mux_ops *ops); diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 0d3389a82bca..54a4d98271b3 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -969,6 +969,7 @@ static int diag_remote_init(void) poolsize_mdm_dci_write); diagmem_setsize(POOL_TYPE_QSC_MUX, itemsize_qsc_usb, poolsize_qsc_usb); + diag_md_mdm_init(); driver->hdlc_encode_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE, GFP_KERNEL); if (!driver->hdlc_encode_buf) return -ENOMEM; -- GitLab From c4feb89e1f7921e816f7a48b529b294658911130 Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Mon, 7 May 2018 18:43:45 -0700 Subject: [PATCH 1757/1834] power: smb5: Import CYCLE_COUNT property Healthd can read CYCLE_COUNT property under battery power supply and expose it in the logs. Import CYCLE_COUNT property from FG driver and show it under battery power supply. CRs-Fixed: 2238261 Change-Id: I0f044004c3826dec223a0bde0f65adde1c305da9 Signed-off-by: Subbaraman Narayanamurthy --- drivers/power/supply/qcom/qpnp-smb5.c | 4 ++++ drivers/power/supply/qcom/smb5-lib.c | 13 +++++++++++++ drivers/power/supply/qcom/smb5-lib.h | 2 ++ 3 files changed, 19 insertions(+) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 7a3a4dcc3969..5de42f46b43f 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -973,6 +973,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, POWER_SUPPLY_PROP_CHARGE_COUNTER, + POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_RECHARGE_SOC, }; @@ -1067,6 +1068,9 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_COUNTER: rc = smblib_get_prop_batt_charge_counter(chg, val); break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + rc = smblib_get_prop_batt_cycle_count(chg, val); + break; case POWER_SUPPLY_PROP_RECHARGE_SOC: val->intval = chg->auto_recharge_soc; break; diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 3152669ef15b..aca5f5b75676 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1447,6 +1447,19 @@ int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, return rc; } +int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_CYCLE_COUNT, val); + return rc; +} + /*********************** * BATTERY PSY SETTERS * ***********************/ diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 668ce5ffaed5..07d9e268b332 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -453,6 +453,8 @@ int smblib_get_prop_batt_temp(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_charge_counter(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_batt_cycle_count(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_input_suspend(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_batt_capacity(struct smb_charger *chg, -- GitLab From 52e9a0e321e444339d32fd62c21d5e4eef76f9d0 Mon Sep 17 00:00:00 2001 From: Jingbiao Lu Date: Fri, 11 May 2018 15:21:23 +0800 Subject: [PATCH 1758/1834] ARM: dts: msm: Add 32-bit DT Overlay support Add 32-bit DT OVERLAY support. Change-Id: I57ed8f1d0e754cb1cefbf7613148ce7683d6e6ff Signed-off-by: Jingbiao Lu --- arch/arm/Makefile | 4 ++++ arch/arm/boot/Makefile | 4 ++-- arch/arm/boot/dts/qcom/Makefile | 14 +++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/arch/arm/Makefile b/arch/arm/Makefile index a6d57944fbda..f66f377db2e4 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -13,6 +13,10 @@ # Ensure linker flags are correct LDFLAGS := +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +export DTC_FLAGS := -@ +endif + LDFLAGS_vmlinux :=-p --no-undefined -X --pic-veneer ifeq ($(CONFIG_CPU_ENDIAN_BE8),y) LDFLAGS_vmlinux += --be8 diff --git a/arch/arm/boot/Makefile b/arch/arm/boot/Makefile index 2fa123e315cc..52e8c50aeee0 100644 --- a/arch/arm/boot/Makefile +++ b/arch/arm/boot/Makefile @@ -34,10 +34,10 @@ targets := Image zImage xipImage bootpImage uImage DTB_NAMES := $(subst $\",,$(CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE_NAMES)) ifneq ($(DTB_NAMES),) DTB_LIST := $(addsuffix .dtb,$(DTB_NAMES)) +DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST)) else -DTB_LIST := $(dtb-y) +DTB_OBJS := $(shell find $(obj)/dts/ -name \*.dtb) endif -DTB_OBJS := $(addprefix $(obj)/dts/,$(DTB_LIST)) ifeq ($(CONFIG_XIP_KERNEL),y) diff --git a/arch/arm/boot/dts/qcom/Makefile b/arch/arm/boot/dts/qcom/Makefile index 4642d0d67ac3..e6af69d030b9 100644 --- a/arch/arm/boot/dts/qcom/Makefile +++ b/arch/arm/boot/dts/qcom/Makefile @@ -21,14 +21,18 @@ dtb-$(CONFIG_ARCH_MDM9607) += mdm9607-mtp.dtb \ mdm9607-ttp.dtb targets += dtbs -targets += $(addprefix ../, $(dtb-y)) -$(obj)/../%.dtb: $(src)/%.dts FORCE +include $(srctree)/arch/arm64/boot/dts/qcom/Makefile +$(obj)/%.dtb: $(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE $(call if_changed_dep,dtc) -include $(srctree)/arch/arm64/boot/dts/qcom/Makefile -$(obj)/../%.dtb: $(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +$(obj)/%.dtbo:$(src)/../../../../arm64/boot/dts/qcom/%.dts FORCE $(call if_changed_dep,dtc) + $(call if_changed,dtbo_verify) -dtbs: $(addprefix $(obj)/../,$(dtb-y)) +dtbs: $(addprefix $(obj)/,$(dtb-y)) $(addprefix $(obj)/,$(dtbo-y)) +else +dtbs: $(addprefix $(obj)/,$(dtb-y)) +endif clean-files := *.dtb -- GitLab From b42c9748b34b4793a9b382f1186e24dac63e06f5 Mon Sep 17 00:00:00 2001 From: Jingbiao Lu Date: Tue, 24 Apr 2018 15:24:10 +0530 Subject: [PATCH 1759/1834] ARM: dts: msm: add device tree overlay support for sda439/sda429 Add device tree overlay support for sdm439/sdm429. Change-Id: I9bec8566d51eb00146eb8f8da22030c51bb1ffd5 Signed-off-by: Jingbiao Lu --- arch/arm64/boot/dts/qcom/Makefile | 4 ++++ arch/arm64/boot/dts/qcom/sda429.dts | 23 +++++++++++++++++++ arch/arm64/boot/dts/qcom/sda439.dts | 23 +++++++++++++++++++ .../boot/dts/qcom/sdm429-cdp-overlay.dts | 1 - .../boot/dts/qcom/sdm429-mtp-overlay.dts | 1 - .../boot/dts/qcom/sdm429-qrd-overlay.dts | 1 - .../boot/dts/qcom/sdm439-cdp-overlay.dts | 1 - .../boot/dts/qcom/sdm439-mtp-overlay.dts | 1 - .../boot/dts/qcom/sdm439-qrd-overlay.dts | 1 - 9 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sda429.dts create mode 100644 arch/arm64/boot/dts/qcom/sda439.dts diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 31d4b0d5bc0f..7ef7c7dc807b 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -368,14 +368,18 @@ sdm632-qrd-overlay.dtbo-base := sdm632.dtb \ sdm632-pm8004.dtb sdm439-mtp-overlay.dtbo-base := sdm439.dtb \ + sda439.dtb \ msm8937-interposer-sdm439.dtb sdm439-cdp-overlay.dtbo-base := sdm439.dtb \ + sda439.dtb \ msm8937-interposer-sdm439.dtb sdm439-qrd-overlay.dtbo-base := sdm439.dtb \ msm8937-interposer-sdm439.dtb sdm429-mtp-overlay.dtbo-base := sdm429.dtb \ + sda429.dtb \ msm8937-interposer-sdm429.dtb sdm429-cdp-overlay.dtbo-base := sdm429.dtb \ + sda429.dtb \ msm8937-interposer-sdm429.dtb sdm429-qrd-overlay.dtbo-base := sdm429.dtb \ msm8937-interposer-sdm429.dtb diff --git a/arch/arm64/boot/dts/qcom/sda429.dts b/arch/arm64/boot/dts/qcom/sda429.dts new file mode 100644 index 000000000000..6a26f23f3d25 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda429.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sda429.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA429 CDP"; + compatible = "qcom,sda429-cdp", "qcom,sda429", "qcom,cdp"; + qcom,pmic-id = <0x010016 0x25 0x0 0x0>; + qcom.pmic-name = "PMI632"; +}; diff --git a/arch/arm64/boot/dts/qcom/sda439.dts b/arch/arm64/boot/dts/qcom/sda439.dts new file mode 100644 index 000000000000..a124c759b6fe --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sda439.dts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "sda439.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDA439"; + compatible = "qcom,sda439"; + qcom,pmic-id = <0x010016 0x25 0x0 0x0>; + qcom.pmic-name = "PMI632"; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts index 93a9ae99af6b..c55c2a508bae 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-cdp-overlay.dts @@ -22,5 +22,4 @@ / { model = "CDP"; qcom,board-id = <1 3>; - qcom,msm-id = <354 0x0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts index 3a339daa99d6..7735b35ced88 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-mtp-overlay.dts @@ -22,5 +22,4 @@ / { model = "MTP"; qcom,board-id = <8 2>; - qcom,msm-id = <354 0x0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts index 8abccb7aa1b9..fae68c994356 100644 --- a/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm429-qrd-overlay.dts @@ -22,5 +22,4 @@ / { model = "QRD"; qcom,board-id = <0xb 3>; - qcom,msm-id = <354 0x0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts index 6d6f99bb56aa..5e866721dffd 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-cdp-overlay.dts @@ -22,5 +22,4 @@ / { model = "CDP"; qcom,board-id = <1 2>; - qcom,msm-id = <353 0x0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts index df8a0d72a8cd..8b6c6fb7f152 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-mtp-overlay.dts @@ -22,5 +22,4 @@ / { model = "MTP"; qcom,board-id = <8 1>; - qcom,msm-id = <353 0x0>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts index ac059c4da549..ed6b2ade25ea 100644 --- a/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm439-qrd-overlay.dts @@ -22,5 +22,4 @@ / { model = "QRD"; qcom,board-id = <0xb 2>; - qcom,msm-id = <353 0x0>; }; -- GitLab From cdf49003b59d3e239b8f7a381a75d54a7be7bf47 Mon Sep 17 00:00:00 2001 From: Jingbiao Lu Date: Thu, 12 Apr 2018 16:49:06 +0800 Subject: [PATCH 1760/1834] ARM: dts: msm: add sdm439 device tree for external codec Add base device tree files for sdm439 platforms with external audio codec. Add device tree files for its overlay support as well. Change-Id: Ib091f2e1840aaf267a6c37a1cd69d34c6769c06c Signed-off-by: Jingbiao Lu --- arch/arm64/boot/dts/qcom/Makefile | 7 +++-- .../sdm439-external-codec-mtp-overlay.dts | 28 +++++++++++++++++++ .../dts/qcom/sdm439-external-codec-mtp.dts | 25 +++++++++++++++++ .../boot/dts/qcom/sdm439-external-codec.dtsi | 12 ++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 31d4b0d5bc0f..3661d224540e 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -308,7 +308,8 @@ dtbo-$(CONFIG_ARCH_SDM632) += sdm632-rumi-overlay.dtbo \ dtbo-$(CONFIG_ARCH_SDM439) += sdm439-mtp-overlay.dtbo \ sdm439-cdp-overlay.dtbo \ - sdm439-qrd-overlay.dtbo + sdm439-qrd-overlay.dtbo \ + sdm439-external-codec-mtp-overlay.dtbo dtbo-$(CONFIG_ARCH_SDM429) += sdm429-mtp-overlay.dtbo \ sdm429-cdp-overlay.dtbo \ @@ -373,6 +374,7 @@ sdm439-cdp-overlay.dtbo-base := sdm439.dtb \ msm8937-interposer-sdm439.dtb sdm439-qrd-overlay.dtbo-base := sdm439.dtb \ msm8937-interposer-sdm439.dtb +sdm439-external-codec-mtp-overlay.dtbo-base := sdm439.dtb sdm429-mtp-overlay.dtbo-base := sdm429.dtb \ msm8937-interposer-sdm429.dtb sdm429-cdp-overlay.dtbo-base := sdm429.dtb \ @@ -459,7 +461,8 @@ dtb-$(CONFIG_ARCH_SDM439) += sdm439-mtp.dtb \ sdm439-cdp.dtb \ sdm439-qrd.dtb \ sda439-mtp.dtb \ - sda439-cdp.dtb + sda439-cdp.dtb \ + sdm439-external-codec-mtp.dtb dtb-$(CONFIG_ARCH_SDM429) += sdm429-mtp.dtb \ sdm429-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts new file mode 100644 index 000000000000..468f514f6cfb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; +/plugin/; + +#include +#include +#include + +#include "sdm439-mtp.dtsi" +#include "sdm439-external-codec.dtsi" + +/ { + model = "MTP"; + qcom,board-id = <8 3>; + qcom,msm-id = <353 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts new file mode 100644 index 000000000000..e2a86bb49636 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec-mtp.dts @@ -0,0 +1,25 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +/dts-v1/; + +#include "sdm439.dtsi" +#include "sdm439-mtp.dtsi" +#include "sdm439-external-codec.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. SDM439 Audio Codec MTP"; + compatible = "qcom,sdm439-mtp", "qcom,sdm439", "qcom,mtp"; + qcom,board-id = <8 3>; + qcom,pmic-id = <0x010016 0x25 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi b/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi new file mode 100644 index 000000000000..83864ef31939 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/sdm439-external-codec.dtsi @@ -0,0 +1,12 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "sdm439-ext-audio-mtp.dtsi" -- GitLab From 27ed00c2fe38a43db2023ead854f56cf176eb847 Mon Sep 17 00:00:00 2001 From: Shaoqing Liu Date: Fri, 11 May 2018 16:10:51 +0800 Subject: [PATCH 1761/1834] soc: qcom: dcc: Avoid huge memory allcation Check size of DCC configuration. Limit the size according to SRAM size. CRs-Fixed: 2224975 Change-Id: I40f4211468c93ece42b85e1f2d326b16965bce22 Signed-off-by: Shaoqing Liu --- drivers/soc/qcom/dcc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/dcc.c b/drivers/soc/qcom/dcc.c index a68728626f0a..bef0757e112c 100644 --- a/drivers/soc/qcom/dcc.c +++ b/drivers/soc/qcom/dcc.c @@ -731,7 +731,8 @@ static int dcc_config_add(struct dcc_drvdata *drvdata, unsigned int addr, mutex_lock(&drvdata->mutex); - if (!len) { + /* Check the len to avoid allocate huge memory */ + if (!len || len > (drvdata->ram_size / 8)) { dev_err(drvdata->dev, "DCC: Invalid length!\n"); ret = -EINVAL; goto err; -- GitLab From afaee36030de3c2783989b0ada6a32a412d50323 Mon Sep 17 00:00:00 2001 From: Mohammed Khajapasha Date: Fri, 4 Sep 2015 20:33:31 +0530 Subject: [PATCH 1762/1834] printk: Make the console flush configurable in hotplug path The thread which initiates the hot plug can get scheduled out, while trying to acquire the console lock, thus increasing the hot plug latency. This option allows to selectively disable the console flush and in turn reduce the hot plug latency. Change-Id: I42507804d321b29b7761146a6c175d959bf79925 Signed-off-by: Mohammed Khajapasha Signed-off-by: Prasad Sodagudi Signed-off-by: Neeraj Upadhyay --- init/Kconfig | 10 ++++++++++ kernel/printk/printk.c | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/init/Kconfig b/init/Kconfig index 2e57658cb740..6358ad3e7864 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -840,6 +840,16 @@ config LOG_BUF_SHIFT 13 => 8 KB 12 => 4 KB +config CONSOLE_FLUSH_ON_HOTPLUG + bool "Enable console flush configurable in hot plug code path" + depends on HOTPLUG_CPU + def_bool n + help + In cpu hot plug path console lock acquire and release causes the + console to flush. If console lock is not free hot plug latency + increases. So make console flush configurable in hot plug path + and default disabled to help in cpu hot plug latencies. + config LOG_CPU_MAX_BUF_SHIFT int "CPU kernel log buffer size contribution (13 => 8 KB, 17 => 128KB)" depends on SMP diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 20fc294fbd13..6d78a6e8af28 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -2172,6 +2172,8 @@ void resume_console(void) console_unlock(); } +#ifdef CONFIG_CONSOLE_FLUSH_ON_HOTPLUG + /** * console_cpu_notify - print deferred console messages after CPU hotplug * @self: notifier struct @@ -2197,6 +2199,8 @@ static int console_cpu_notify(struct notifier_block *self, return NOTIFY_OK; } +#endif + /** * console_lock - lock the console system for exclusive use. * @@ -2846,7 +2850,9 @@ static int __init printk_late_init(void) unregister_console(con); } } +#ifdef CONFIG_CONSOLE_FLUSH_ON_HOTPLUG hotcpu_notifier(console_cpu_notify, 0); +#endif return 0; } late_initcall(printk_late_init); -- GitLab From 31996f6b0a38ddc8e948edd932872d4c4c63dad0 Mon Sep 17 00:00:00 2001 From: Pranav Patel Date: Wed, 2 May 2018 18:18:15 +0530 Subject: [PATCH 1763/1834] ARM: dts: msm: Add DT support for APQ8053 SOM based devices Avoid code duplication by moving common code to parent dtsi file. Also add some required nodes which were missed out earlier. Change-Id: I19f942c528685ae2e081d884d0a71b8e5833fe74 Signed-off-by: Pranav Patel --- arch/arm64/boot/dts/qcom/Makefile | 4 + .../dts/qcom/apq8053-lite-dragon-v2.0.dts | 1 - .../dts/qcom/apq8053-lite-dragon-v2.0.dtsi | 61 ++--------- .../boot/dts/qcom/apq8053-lite-dragon.dtsi | 103 +++++++++++++----- .../dts/qcom/apq8053-lite-harman-v1.0.dts | 27 +++++ .../dts/qcom/apq8053-lite-harman-v1.0.dtsi | 80 ++++++++++++++ .../dts/qcom/apq8053-lite-lenovo-v1.0.dts | 27 +++++ .../dts/qcom/apq8053-lite-lenovo-v1.0.dtsi | 68 ++++++++++++ .../dts/qcom/apq8053-lite-lenovo-v1.1.dts | 27 +++++ .../dts/qcom/apq8053-lite-lenovo-v1.1.dtsi | 62 +++++++++++ .../boot/dts/qcom/apq8053-lite-lge-v1.0.dts | 27 +++++ .../boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi | 30 +++++ 12 files changed, 437 insertions(+), 80 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 31d4b0d5bc0f..ebd3348a4a9d 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -398,6 +398,10 @@ dtb-$(CONFIG_ARCH_MSM8953) += msm8953-cdp.dtb \ apq8053-iot-mtp.dtb \ apq8053-lite-dragon-v1.0.dtb \ apq8053-lite-dragon-v2.0.dtb \ + apq8053-lite-lenovo-v1.0.dtb \ + apq8053-lite-lenovo-v1.1.dtb \ + apq8053-lite-harman-v1.0.dtb \ + apq8053-lite-lge-v1.0.dtb \ msm8953-pmi8940-cdp.dtb \ msm8953-pmi8940-mtp.dtb \ msm8953-pmi8937-cdp.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts index d7836e5485bb..55d8b7b13e6e 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dts @@ -13,7 +13,6 @@ /dts-v1/; -#include "apq8053-lite.dtsi" #include "apq8053-lite-dragon-v2.0.dtsi" / { diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi index 947af4d1fa13..bb40018e1737 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon-v2.0.dtsi @@ -12,68 +12,25 @@ */ #include "apq8053-lite-dragon.dtsi" -#include "msm8953-mdss-panels.dtsi" - -&i2c_3 { - status = "okay"; - himax_ts@48 { - compatible = "himax,hxcommon"; - reg = <0x48>; - interrupt-parent = <&tlmm>; - interrupts = <65 0x2>; - vdd-supply = <&pm8953_l10>; - avdd-supply = <&pm8953_l5>; - pinctrl-names = "pmx_ts_active","pmx_ts_suspend", - "pmx_ts_release"; - pinctrl-0 = <&ts_int_active &ts_reset_active>; - pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; - pinctrl-2 = <&ts_release>; - himax,panel-coords = <0 800 0 1280>; - himax,display-coords = <0 800 0 1280>; - himax,irq-gpio = <&tlmm 65 0x2008>; - report_type = <1>; - }; -}; - -&mdss_mdp { - qcom,mdss-pref-prim-intf = "dsi"; -}; - -&mdss_dsi { - hw-config = "single_dsi"; -}; &mdss_dsi0 { - qcom,dsi-pref-prim-pan = <&dsi_boyi_hx83100a_800p_video>; - pinctrl-names = "mdss_default", "mdss_sleep"; pinctrl-0 = <&mdss_dsi_active &mdss_te_active &mdss_dsi_gpio>; pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend &mdss_dsi_gpio>; - - vdd-supply = <&pm8953_l10>; - vddio-supply = <&pm8953_l6>; - lab-supply = <&lab_regulator>; - ibb-supply = <&ibb_regulator>; - - qcom,platform-te-gpio = <&tlmm 24 0>; - qcom,platform-reset-gpio = <&tlmm 61 0>; - qcom,platform-bklight-en-gpio = <&tlmm 100 0>; }; -&mdss_dsi1 { - status = "disabled"; +&pm8953_l4 { + status = "okay"; + regulator-always-on; }; -&labibb { - status = "okay"; - qpnp,qpnp-labibb-mode = "lcd"; +&camera0 { + qcom,mount-angle = <90>; }; -&wled { - qcom,cons-sync-write-delay-us = <1000>; - qcom,led-strings-list = [00 01 02 03]; +&camera1 { + qcom,mount-angle = <90>; }; -&pm8953_l4 { - status = "okay"; - regulator-always-on; +&camera2{ + qcom,mount-angle = <90>; }; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi index 5e3ddce4f481..e5b4c84a6ba1 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -11,6 +11,7 @@ * GNU General Public License for more details. */ +#include "apq8053-lite.dtsi" #include "msm8953-pinctrl.dtsi" #include "apq8053-camera-sensor-dragon.dtsi" #include "pmi8950.dtsi" @@ -185,39 +186,22 @@ &i2c_3 { status = "okay"; - focaltech@38 { - compatible = "focaltech,5x06"; - reg = <0x38>; + himax_ts@48 { + compatible = "himax,hxcommon"; + reg = <0x48>; interrupt-parent = <&tlmm>; interrupts = <65 0x2>; vdd-supply = <&pm8953_l10>; - vcc_i2c-supply = <&pm8953_l5>; - /* pins used by touchscreen */ + avdd-supply = <&pm8953_l5>; pinctrl-names = "pmx_ts_active","pmx_ts_suspend", - "pmx_ts_release"; + "pmx_ts_release"; pinctrl-0 = <&ts_int_active &ts_reset_active>; pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; pinctrl-2 = <&ts_release>; - focaltech,name = "ft5606"; - focaltech,family-id = <0x08>; - focaltech,reset-gpio = <&tlmm 64 0x0>; - focaltech,irq-gpio = <&tlmm 65 0x2008>; - focaltech,display-coords = <0 0 1919 1199>; - focaltech,panel-coords = <0 0 1919 1199>; - focaltech,no-force-update; - focaltech,i2c-pull-up; - focaltech,group-id = <1>; - focaltech,hard-reset-delay-ms = <20>; - focaltech,soft-reset-delay-ms = <200>; - focaltech,num-max-touches = <5>; - focaltech,fw-delay-aa-ms = <30>; - focaltech,fw-delay-55-ms = <30>; - focaltech,fw-upgrade-id1 = <0x79>; - focaltech,fw-upgrade-id2 = <0x08>; - focaltech,fw-delay-readid-ms = <10>; - focaltech,fw-delay-era-flsh-ms = <2000>; - focaltech,fw-auto-cal; - focaltech,resume-in-workqueue; + himax,panel-coords = <0 800 0 1280>; + himax,display-coords = <0 800 0 1280>; + himax,irq-gpio = <&tlmm 65 0x2008>; + report_type = <1>; }; }; @@ -229,6 +213,71 @@ status = "disabled"; }; +#include "msm8953-mdss-panels.dtsi" +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi_active { + mux { + pins = "gpio61", "gpio100"; + function = "gpio"; + }; + + config { + pins = "gpio61", "gpio100"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; +}; + +&mdss_dsi_suspend { + mux { + pins = "gpio61", "gpio100"; + function = "gpio"; + }; + + config { + pins = "gpio61", "gpio100"; + drive-strength = <2>; + bias-pull-down; + }; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_boyi_hx83100a_800p_video>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + vdd-supply = <&pm8953_l10>; + vddio-supply = <&pm8953_l6>; + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; + + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 61 0>; + qcom,platform-bklight-en-gpio = <&tlmm 100 0>; +}; + +&mdss_dsi1 { + status = "disabled"; +}; + +&labibb { + status = "okay"; + qpnp,qpnp-labibb-mode = "lcd"; +}; + +&wled { + qcom,cons-sync-write-delay-us = <1000>; + qcom,led-strings-list = [00 01 02 03]; +}; &blsp1_uart0 { status = "ok"; pinctrl-names = "default"; @@ -301,7 +350,7 @@ pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off &sdc2_wlan_gpio_off>; - qcom,clk-rates = <400000 20000000 25000000 50000000>; + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000>; qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; status = "ok"; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts new file mode 100644 index 000000000000..203b6b89ef6a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8053-lite-harman-v1.0.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 Lite Harman v1.0 Board"; + compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", + "qcom,dragonboard"; + qcom,board-id= <0x01020020 0>; +}; + +&blsp2_uart0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi new file mode 100644 index 000000000000..5cf8ac06ff43 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-harman-v1.0.dtsi @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "apq8053-lite-dragon.dtsi" + +&pm8953_l4 { + status = "okay"; + regulator-always-on; +}; + +&pm8953_l10 { + status = "okay"; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; +}; + +&pm8953_l2 { + status = "okay"; + regulator-always-on; +}; + +&pm8953_l17 { + status = "okay"; + regulator-always-on; +}; + +&pm8953_l22 { + status = "okay"; + regulator-always-on; +}; + +&i2c_3 { + status = "okay"; + /delete-node/ himax_ts@48; + focaltech_ts@38 { + compatible = "focaltech,fts"; + reg = <0x38>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2>; + vdd-supply = <&pm8953_l10>; + avdd-supply = <&pm8953_l6>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend", + "pmx_ts_release"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + pinctrl-2 = <&ts_release>; + focaltech,display-coords = <0 0 800 1280>; + focaltech,reset-gpio = <&tlmm 64 0x0>; + focaltech,irq-gpio = <&tlmm 65 0x2>; + focaltech,max-touch-number = <5>; + report_type = <1>; + }; +}; + +&wled { + qcom,led-strings-list = [00 01 02]; +}; + +&camera0 { + qcom,mount-angle = <90>; +}; + +&camera1 { + qcom,mount-angle = <90>; +}; + +&camera2{ + qcom,mount-angle = <90>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts new file mode 100644 index 000000000000..325accffdf5c --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8053-lite-lenovo-v1.0.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.0 Board"; + compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", + "qcom,dragonboard"; + qcom,board-id= <0x01010020 0>; +}; + +&blsp2_uart0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi new file mode 100644 index 000000000000..4d9c40c2d070 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.0.dtsi @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "apq8053-lite-dragon.dtsi" + +&mdss_dsi0 { + qcom,ext_vdd-gpio = <&tlmm 100 0>; + qcom,platform-bklight-en-gpio = <&tlmm 95 0>; + + qcom,platform-lane-config = [00 00 ff 0f + 00 00 ff 0f + 00 00 ff 0f + 00 00 ff 0f + 00 00 ff 8f]; +}; + +&eeprom0 { + gpios = <&tlmm 26 0>, + <&tlmm 40 0>, + <&tlmm 118 0>, + <&tlmm 119 0>, + <&tlmm 39 0>; + qcom,gpio-vdig = <3>; + qcom,gpio-vana = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA", + "CAM_STANDBY0"; +}; + +&camera0 { + qcom,mount-angle = <270>; + gpios = <&tlmm 26 0>, + <&tlmm 40 0>, + <&tlmm 39 0>, + <&tlmm 118 0>, + <&tlmm 119 0>; + qcom,gpio-vdig = <3>; + qcom,gpio-vana = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0", + "CAM_VDIG", + "CAM_VANA"; +}; + +&camera1 { + qcom,mount-angle = <270>; +}; + +&camera2{ + qcom,mount-angle = <270>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts new file mode 100644 index 000000000000..0c7b5577ff4d --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8053-lite-lenovo-v1.1.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 Lite Lenovo v1.1 Board"; + compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", + "qcom,dragonboard"; + qcom,board-id= <0x01010120 0>; +}; + +&blsp2_uart0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi new file mode 100644 index 000000000000..396fd55b7c3a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lenovo-v1.1.dtsi @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "apq8053-lite-dragon.dtsi" + +&i2c_3 { + status = "okay"; + /delete-node/ himax_ts@48; +}; + +&eeprom0 { + gpios = <&tlmm 26 0>, + <&tlmm 40 0>, + <&tlmm 118 0>, + <&tlmm 119 0>, + <&tlmm 39 0>; + qcom,gpio-vdig = <3>; + qcom,gpio-vana = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG", + "CAM_VANA", + "CAM_STANDBY0"; +}; + +&camera0 { + qcom,mount-angle = <270>; + gpios = <&tlmm 26 0>, + <&tlmm 40 0>, + <&tlmm 39 0>, + <&tlmm 118 0>, + <&tlmm 119 0>; + qcom,gpio-vdig = <3>; + qcom,gpio-vana = <4>; + qcom,gpio-req-tbl-num = <0 1 2 3 4>; + qcom,gpio-req-tbl-flags = <1 0 0 0 0>; + qcom,gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_STANDBY0", + "CAM_VDIG", + "CAM_VANA"; +}; + +&camera1 { + qcom,mount-angle = <270>; +}; + +&camera2{ + qcom,mount-angle = <270>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts new file mode 100644 index 000000000000..70952dc6d835 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8053-lite-lge-v1.0.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8053 Lite LGE v1.0 Board"; + compatible = "qcom,apq8053-lite-dragonboard", "qcom,apq8053", + "qcom,dragonboard"; + qcom,board-id= <0x01030020 0>; +}; + +&blsp2_uart0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi new file mode 100644 index 000000000000..db0331e18ce6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-lge-v1.0.dtsi @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "apq8053-lite-dragon.dtsi" + +&wled { + qcom,fs-curr-ua = <17500>; +}; + +&camera0 { + qcom,mount-angle = <180>; +}; + +&camera1 { + qcom,mount-angle = <180>; +}; + +&camera2 { + qcom,mount-angle = <180>; +}; -- GitLab From 3dc611b49fe120e5b1894e9cf95905cf83419b9f Mon Sep 17 00:00:00 2001 From: Raviteja Tamatam Date: Fri, 21 Apr 2017 16:41:06 +0530 Subject: [PATCH 1764/1834] msm: mdss: align smmu domain mapping to 128 MB Change the size of smmu create mapping to have 128 MB alignnment as kernel upstream code on 32-bit mode expects 128 MB aligned virtual address. Change-Id: I5e533f948bbcf4e82ba22b273b1bcad068e4959c Signed-off-by: Raviteja Tamatam --- drivers/video/fbdev/msm/mdss_smmu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_smmu.c b/drivers/video/fbdev/msm/mdss_smmu.c index fbbdaf22b169..1d832066b56d 100644 --- a/drivers/video/fbdev/msm/mdss_smmu.c +++ b/drivers/video/fbdev/msm/mdss_smmu.c @@ -692,13 +692,13 @@ int mdss_smmu_init(struct mdss_data_type *mdata, struct device *dev) } static struct mdss_smmu_domain mdss_mdp_unsec = { - "mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_1M, (SZ_4G - SZ_1M)}; + "mdp_0", MDSS_IOMMU_DOMAIN_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)}; static struct mdss_smmu_domain mdss_rot_unsec = { - NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_1M, (SZ_4G - SZ_1M)}; + NULL, MDSS_IOMMU_DOMAIN_ROT_UNSECURE, SZ_128K, (SZ_4G - SZ_128M)}; static struct mdss_smmu_domain mdss_mdp_sec = { - "mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_1M, (SZ_4G - SZ_1M)}; + "mdp_1", MDSS_IOMMU_DOMAIN_SECURE, SZ_128K, (SZ_4G - SZ_128M)}; static struct mdss_smmu_domain mdss_rot_sec = { - NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_1M, (SZ_4G - SZ_1M)}; + NULL, MDSS_IOMMU_DOMAIN_ROT_SECURE, SZ_128K, (SZ_4G - SZ_128M)}; static const struct of_device_id mdss_smmu_dt_match[] = { { .compatible = "qcom,smmu_mdp_unsec", .data = &mdss_mdp_unsec}, -- GitLab From f033e7661cc0a4d7c18337d83a6b9cfd7cd995ad Mon Sep 17 00:00:00 2001 From: Devi Sandeep Endluri V V Date: Mon, 14 May 2018 15:13:14 +0530 Subject: [PATCH 1765/1834] msm8937: defconfig: Enable CONFIG_NETFILTER_XT_MATCH_BPF Enable bpf match support for targets with kernel 4.9 and above so that iptable command from netd (userspace module) with -m bpf doesn't fail. CRs-Fixed: 2228931 Change-Id: I5fd6015cf154f00118aa7069bd630a28ace25a32 Signed-off-by: Devi Sandeep Endluri V V --- arch/arm64/configs/msm8937-perf_defconfig | 1 + arch/arm64/configs/msm8937_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm64/configs/msm8937-perf_defconfig b/arch/arm64/configs/msm8937-perf_defconfig index 4c6b6a1b39b4..ac5421322231 100644 --- a/arch/arm64/configs/msm8937-perf_defconfig +++ b/arch/arm64/configs/msm8937-perf_defconfig @@ -148,6 +148,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y diff --git a/arch/arm64/configs/msm8937_defconfig b/arch/arm64/configs/msm8937_defconfig index 11bd200bdd36..4fafcc463009 100644 --- a/arch/arm64/configs/msm8937_defconfig +++ b/arch/arm64/configs/msm8937_defconfig @@ -152,6 +152,7 @@ CONFIG_NETFILTER_XT_TARGET_TPROXY=y CONFIG_NETFILTER_XT_TARGET_TRACE=y CONFIG_NETFILTER_XT_TARGET_SECMARK=y CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y CONFIG_NETFILTER_XT_MATCH_COMMENT=y CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y CONFIG_NETFILTER_XT_MATCH_CONNMARK=y -- GitLab From 7f81edae7f5b239382932820079c78d85b52dc05 Mon Sep 17 00:00:00 2001 From: Mohammed Javid Date: Tue, 10 Apr 2018 15:33:48 +0530 Subject: [PATCH 1766/1834] msm: ipa: Fix to slab out of bounds issue Add changes to verify passed value with in the allocated max array size range or not before accessing structure. Change-Id: If70493e937f6f0bc29bbfe08bf43738bdb4e9cf4 Acked-by: Ashok Vuyyuru Signed-off-by: Mohammed Javid --- drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c | 58 ++++++++++++--- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 70 ++++++++++++++++--- drivers/platform/msm/ipa/ipa_v3/ipa_flt.c | 4 +- 3 files changed, 114 insertions(+), 18 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c index f062ed259fd4..953469aef7a9 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_debugfs.c @@ -432,6 +432,8 @@ static ssize_t ipa_read_hdr(struct file *file, char __user *ubuf, size_t count, list_for_each_entry(entry, &ipa_ctx->hdr_tbl.head_hdr_entry_list, link) { + if (entry->cookie != IPA_HDR_COOKIE) + continue; nbytes = scnprintf( dbg_buff, IPA_MAX_MSG_LEN, @@ -606,6 +608,14 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) if (attrib->protocol_eq_present) pr_err("protocol:%d ", attrib->protocol_eq); + if (attrib->num_ihl_offset_range_16 > + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) { + IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS, + attrib->num_ihl_offset_range_16); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_range_16; i++) { pr_err( "(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ", @@ -614,6 +624,12 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_range_16[i].range_high); } + if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) { + IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_32; i++) { pr_err( "(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ", @@ -635,6 +651,12 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_eq_16.value); } + if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) { + IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_meq_32; i++) { pr_err( "(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ", @@ -643,6 +665,12 @@ static int ipa_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->ihl_offset_meq_32[i].value); } + if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) { + IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_128; i++) { for (j = 0; j < 16; j++) { addr[j] = attrib->offset_meq_128[i].value[j]; @@ -812,11 +840,14 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, u32 rt_tbl_idx; u32 bitmap; bool eq; + int res = 0; tbl = &ipa_ctx->glob_flt_tbl[ip]; mutex_lock(&ipa_ctx->lock); i = 0; list_for_each_entry(entry, &tbl->head_flt_rule_list, link) { + if (entry->cookie != IPA_FLT_COOKIE) + continue; if (entry->rule.eq_attrib_type) { rt_tbl_idx = entry->rule.rt_tbl_idx; bitmap = entry->rule.eq_attrib.rule_eq_bitmap; @@ -835,10 +866,14 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, i, entry->rule.action, rt_tbl_idx); pr_err("attrib_mask:%08x retain_hdr:%d eq:%d ", bitmap, entry->rule.retain_hdr, eq); - if (eq) - ipa_attrib_dump_eq( + if (eq) { + res = ipa_attrib_dump_eq( &entry->rule.eq_attrib); - else + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } + } else ipa_attrib_dump( &entry->rule.attrib, ip); i++; @@ -848,6 +883,8 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, tbl = &ipa_ctx->flt_tbl[j][ip]; i = 0; list_for_each_entry(entry, &tbl->head_flt_rule_list, link) { + if (entry->cookie != IPA_FLT_COOKIE) + continue; if (entry->rule.eq_attrib_type) { rt_tbl_idx = entry->rule.rt_tbl_idx; bitmap = entry->rule.eq_attrib.rule_eq_bitmap; @@ -867,18 +904,23 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, pr_err("attrib_mask:%08x retain_hdr:%d ", bitmap, entry->rule.retain_hdr); pr_err("eq:%d ", eq); - if (eq) - ipa_attrib_dump_eq( - &entry->rule.eq_attrib); - else + if (eq) { + res = ipa_attrib_dump_eq( + &entry->rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } + } else ipa_attrib_dump( &entry->rule.attrib, ip); i++; } } +bail: mutex_unlock(&ipa_ctx->lock); - return 0; + return res; } static ssize_t ipa_read_stats(struct file *file, char __user *ubuf, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index ee9c49c20bfb..dc5f5e0037aa 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -372,6 +372,8 @@ static ssize_t ipa3_read_hdr(struct file *file, char __user *ubuf, size_t count, list_for_each_entry(entry, &ipa3_ctx->hdr_tbl.head_hdr_entry_list, link) { + if (entry->cookie != IPA_HDR_COOKIE) + continue; nbytes = scnprintf( dbg_buff, IPA_MAX_MSG_LEN, @@ -556,6 +558,12 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) if (attrib->tc_eq_present) pr_err("tc:%d ", attrib->tc_eq); + if (attrib->num_offset_meq_128 > IPA_IPFLTR_NUM_MEQ_128_EQNS) { + IPAERR_RL("num_offset_meq_128 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_128_EQNS, attrib->num_offset_meq_128); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_128; i++) { for (j = 0; j < 16; j++) { addr[j] = attrib->offset_meq_128[i].value[j]; @@ -567,6 +575,12 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) mask, addr); } + if (attrib->num_offset_meq_32 > IPA_IPFLTR_NUM_MEQ_32_EQNS) { + IPAERR_RL("num_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_MEQ_32_EQNS, attrib->num_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_offset_meq_32; i++) pr_err( "(ofst_meq32: ofst:%u mask:0x%x val:0x%x) ", @@ -574,6 +588,12 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->offset_meq_32[i].mask, attrib->offset_meq_32[i].value); + if (attrib->num_ihl_offset_meq_32 > IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS) { + IPAERR_RL("num_ihl_offset_meq_32 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_MEQ_32_EQNS, attrib->num_ihl_offset_meq_32); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_meq_32; i++) pr_err( "(ihl_ofst_meq32: ofts:%d mask:0x%x val:0x%x) ", @@ -588,6 +608,14 @@ static int ipa3_attrib_dump_eq(struct ipa_ipfltri_rule_eq *attrib) attrib->metadata_meq32.mask, attrib->metadata_meq32.value); + if (attrib->num_ihl_offset_range_16 > + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS) { + IPAERR_RL("num_ihl_offset_range_16 Max %d passed value %d\n", + IPA_IPFLTR_NUM_IHL_RANGE_16_EQNS, + attrib->num_ihl_offset_range_16); + return -EPERM; + } + for (i = 0; i < attrib->num_ihl_offset_range_16; i++) pr_err( "(ihl_ofst_range16: ofst:%u lo:%u hi:%u) ", @@ -780,7 +808,11 @@ static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf, pr_err("rule_id:%u prio:%u retain_hdr:%u ", rules[rl].id, rules[rl].priority, rules[rl].retain_hdr); - ipa3_attrib_dump_eq(&rules[rl].eq_attrib); + res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } pr_err("=== Routing Table %d = Non-Hashable Rules ===\n", tbl); @@ -811,7 +843,11 @@ static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf, pr_err("rule_id:%u prio:%u retain_hdr:%u\n", rules[rl].id, rules[rl].priority, rules[rl].retain_hdr); - ipa3_attrib_dump_eq(&rules[rl].eq_attrib); + res = ipa3_attrib_dump_eq(&rules[rl].eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } pr_err("\n"); } @@ -885,6 +921,7 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, u32 rt_tbl_idx; u32 bitmap; bool eq; + int res = 0; mutex_lock(&ipa3_ctx->lock); @@ -894,6 +931,8 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, tbl = &ipa3_ctx->flt_tbl[j][ip]; i = 0; list_for_each_entry(entry, &tbl->head_flt_rule_list, link) { + if (entry->cookie != IPA_FLT_COOKIE) + continue; if (entry->rule.eq_attrib_type) { rt_tbl_idx = entry->rule.rt_tbl_idx; bitmap = entry->rule.eq_attrib.rule_eq_bitmap; @@ -919,18 +958,23 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count, pr_err("pdn index %d, set metadata %d ", entry->rule.pdn_idx, entry->rule.set_metadata); - if (eq) - ipa3_attrib_dump_eq( - &entry->rule.eq_attrib); - else + if (eq) { + res = ipa3_attrib_dump_eq( + &entry->rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } + } else ipa3_attrib_dump( &entry->rule.attrib, ip); i++; } } +bail: mutex_unlock(&ipa3_ctx->lock); - return 0; + return res; } static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf, @@ -985,7 +1029,11 @@ static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf, pr_err("pdn: %u, set_metadata: %u ", rules[rl].rule.pdn_idx, rules[rl].rule.set_metadata); - ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib); + res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } pr_err("=== Filtering Table ep:%d = Non-Hashable Rules ===\n", @@ -1013,7 +1061,11 @@ static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf, pr_err("pdn: %u, set_metadata: %u ", rules[rl].rule.pdn_idx, rules[rl].rule.set_metadata); - ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib); + res = ipa3_attrib_dump_eq(&rules[rl].rule.eq_attrib); + if (res) { + IPAERR_RL("failed read attrib eq\n"); + goto bail; + } } pr_err("\n"); } diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index 29fd54796499..674277364a31 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -61,8 +61,10 @@ static int ipa3_generate_flt_hw_rule(enum ipa_ip_type ip, gen_params.rule = (const struct ipa_flt_rule *)&entry->rule; res = ipahal_flt_generate_hw_rule(&gen_params, &entry->hw_len, buf); - if (res) + if (res) { IPAERR_RL("failed to generate flt h/w rule\n"); + return res; + } return 0; } -- GitLab From df664e1ecaef26957f829e0fab94ea7133c37ff0 Mon Sep 17 00:00:00 2001 From: Skylar Chang Date: Mon, 14 May 2018 14:34:05 -0700 Subject: [PATCH 1767/1834] msm: ipa: Do not set perf profile on DPL For USB use cases there are two PM clients which are created: USB and USB_DPL. DPL should not be setting performance profile with IPA PM as it is not a tethering interface. Change-Id: Ie4ab7482a39a1520e2c2ed4e42560d23542a762c Acked-by: Ady Abraham Signed-off-by: Skylar Chang --- drivers/platform/msm/ipa/ipa_clients/ipa_usb.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c index ebf1d2963f06..d9e3ab9d2fcc 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c @@ -1847,12 +1847,15 @@ static int ipa3_usb_xdci_connect_internal( } if (ipa_pm_is_used()) { - result = ipa_pm_set_perf_profile( - ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl, - params->max_supported_bandwidth_mbps); - if (result) { - IPA_USB_ERR("failed to set perf profile\n"); - return result; + /* perf profile is not set on USB DPL pipe */ + if (ttype != IPA_USB_TRANSPORT_DPL) { + result = ipa_pm_set_perf_profile( + ipa3_usb_ctx->ttype_ctx[ttype].pm_ctx.hdl, + params->max_supported_bandwidth_mbps); + if (result) { + IPA_USB_ERR("failed to set perf profile\n"); + return result; + } } result = ipa_pm_activate_sync( -- GitLab From a19c4c148539ad421b2114d7fdb269ee4e27e27f Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 7 May 2018 20:51:12 -0700 Subject: [PATCH 1768/1834] ARM: dts: msm: Add no vote option for EMAC clocks in sdxpoorwills Update clock vector for EMAC memory and config clocks. Add option to vote for zero bandwidth. Change-Id: Ib1b536d8b68bf4df677dfebaa39caf8a4e640394 CRs-Fixed: 2122162 Acked-by: Rahul Kawadgave Signed-off-by: Sunil Paidimarri --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index c6608a87bf47..737c5793dcca 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1252,9 +1252,10 @@ "rx-ch0-intr", "rx-ch1-intr", "rx-ch2-intr", "rx-ch3-intr"; qcom,msm-bus,name = "emac"; - qcom,msm-bus,num-cases = <3>; + qcom,msm-bus,num-cases = <4>; qcom,msm-bus,num-paths = <2>; qcom,msm-bus,vectors-KBps = + <98 512 0 0>, <1 781 0 0>, /* No vote */ <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ -- GitLab From 8efcc67eb60c7733a0e6061902eb8bc002035a79 Mon Sep 17 00:00:00 2001 From: Sunil Paidimarri Date: Mon, 14 May 2018 15:51:54 -0700 Subject: [PATCH 1769/1834] ARM: dts: msm: Fix the bus vector names for EMAC in sdxpoorwills Fix the name for zero bandwidth index in bus vector. Change-Id: I8c252d0568119e8fa75b16022b663a8a06eb64d0 CRs-Fixed: 2241827 Acked-by: Rahul Kawadgave Signed-off-by: Sunil Paidimarri --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index 737c5793dcca..e6e0e0977636 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -1259,7 +1259,7 @@ <98 512 1250 0>, <1 781 0 40000>, /* 10Mbps vote */ <98 512 12500 0>, <1 781 0 40000>, /* 100Mbps vote */ <98 512 125000 0>, <1 781 0 40000>; /* 1000Mbps vote */ - qcom,bus-vector-names = "10", "100", "1000"; + qcom,bus-vector-names = "0", "10", "100", "1000"; clocks = <&clock_gcc GCC_ETH_AXI_CLK>, <&clock_gcc GCC_ETH_PTP_CLK>, <&clock_gcc GCC_ETH_RGMII_CLK>, -- GitLab From 184ffb2036b1799ab833972e3e48259721305f98 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Thu, 10 May 2018 18:32:02 -0700 Subject: [PATCH 1770/1834] msm: ipa: Fix compilation error with CONFIG_RMNET_IPA=n Fix a defined-but-not-used warning. Change-Id: I84665de6195a421909fe1ca7af84e042f43b5590 Signed-off-by: Patrick Daly --- drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h index 1f5d619ef573..98f5574b28ea 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -281,7 +281,7 @@ static inline void ipa_broadcast_quota_reach_ind { } -static int rmnet_ipa_reset_tethering_stats +static inline int rmnet_ipa_reset_tethering_stats ( struct wan_ioctl_reset_tether_stats *data ) -- GitLab From 0e1c06b89117805de27ce4585241e3546ea40dcb Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Mon, 7 May 2018 10:47:33 +0530 Subject: [PATCH 1771/1834] clk: qcom: Add clk_ops to support runtime frequencies for esc clock Some of the display panels requires multiple clock frequencies to be derived runtime from the sources for its operation. Add support for the same by adding esc clk_ops to calculate the desired divider at run time for accuracy. Change-Id: Ie3ec84bb1927f5313c887344368dceffb06035be Signed-off-by: Amit Nischal --- drivers/clk/qcom/clk-rcg.h | 3 +- drivers/clk/qcom/clk-rcg2.c | 70 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index aaf2324c0e05..f7599785c08b 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2013, 2016-2018, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -185,6 +185,7 @@ extern const struct clk_ops clk_byte2_ops; extern const struct clk_ops clk_pixel_ops; extern const struct clk_ops clk_gfx3d_ops; extern const struct clk_ops clk_dp_ops; +extern const struct clk_ops clk_esc_ops; extern int clk_rcg2_get_dfs_clock_rate(struct clk_rcg2 *clk, struct device *dev, u8 rcg_flags); diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 00989a8cca5e..057f0e11c4fc 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -1191,6 +1191,76 @@ const struct clk_ops clk_gfx3d_ops = { }; EXPORT_SYMBOL_GPL(clk_gfx3d_ops); +static int clk_esc_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + unsigned long parent_rate, div; + u32 mask = BIT(rcg->hid_width) - 1; + struct clk_hw *p; + unsigned long rate = req->rate; + + if (rate == 0) + return -EINVAL; + + p = req->best_parent_hw; + req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate); + + div = ((2 * parent_rate) / rate) - 1; + div = min_t(u32, div, mask); + + req->rate = clk_rcg2_calc_rate(parent_rate, 0, 0, 0, div); + + return 0; +} + +static int clk_esc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_rcg2 *rcg = to_clk_rcg2(hw); + struct freq_tbl f = { 0 }; + unsigned long div; + int i, num_parents = clk_hw_get_num_parents(hw); + u32 mask = BIT(rcg->hid_width) - 1; + u32 cfg; + + div = ((2 * parent_rate) / rate) - 1; + div = min_t(u32, div, mask); + + f.pre_div = div; + + regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg); + cfg &= CFG_SRC_SEL_MASK; + cfg >>= CFG_SRC_SEL_SHIFT; + + for (i = 0; i < num_parents; i++) { + if (cfg == rcg->parent_map[i].cfg) { + f.src = rcg->parent_map[i].src; + return clk_rcg2_configure(rcg, &f); + } + } + + return -EINVAL; +} + +static int clk_esc_set_rate_and_parent(struct clk_hw *hw, + unsigned long rate, unsigned long parent_rate, u8 index) +{ + return clk_esc_set_rate(hw, rate, parent_rate); +} + +const struct clk_ops clk_esc_ops = { + .is_enabled = clk_rcg2_is_enabled, + .get_parent = clk_rcg2_get_parent, + .set_parent = clk_rcg2_set_parent, + .recalc_rate = clk_rcg2_recalc_rate, + .determine_rate = clk_esc_determine_rate, + .set_rate = clk_esc_set_rate, + .set_rate_and_parent = clk_esc_set_rate_and_parent, + .list_registers = clk_rcg2_list_registers, +}; +EXPORT_SYMBOL(clk_esc_ops); + /* Common APIs to be used for DFS based RCGR */ static u8 clk_parent_index_pre_div_and_mode(struct clk_hw *hw, u32 offset, u32 *mode, u32 *pre_div) -- GitLab From d36ee76f07e8cc397a21651548e133a2b5ddd06e Mon Sep 17 00:00:00 2001 From: Teng Fei Fan Date: Fri, 11 May 2018 08:09:46 +0800 Subject: [PATCH 1772/1834] ARM: dts: msm: Update device tree to support 32-bit kernel on sdm632 Below error is observed when 32-bit kernel runs on sdm632: unrecognized/unsupported device tree list. So delete compatible in device tree to support 32bit kernel. Change-Id: I334b04125f70e30e271acb2ddb77c840d2220251 Signed-off-by: Teng Fei Fan --- arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts | 1 - arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts | 1 - arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts | 1 - arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts | 1 - arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts | 1 - arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts | 1 - 6 files changed, 6 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts index e12ad512bd5f..97c938991567 100644 --- a/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm450-cdp-s2-overlay.dts @@ -18,7 +18,6 @@ / { model = "CDP S2"; - compatible = "qcom,cdp"; qcom,board-id = <1 2>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts index ae522a55ff8a..3dd7200cc343 100644 --- a/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm450-mtp-s3-overlay.dts @@ -18,7 +18,6 @@ / { model = "MTP S3"; - compatible = "qcom,mtp"; qcom,board-id = <8 3>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts index 558c3c652016..e8dca18d73b5 100644 --- a/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm450-qrd-sku4-overlay.dts @@ -18,7 +18,6 @@ / { model = "QRD SKU4"; - compatible = "qcom,qrd"; qcom,board-id = <0xb 1>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts index eb5afbd526a6..c3e0ba9208c7 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-cdp-s3-overlay.dts @@ -18,7 +18,6 @@ / { model = "Ext Codec CDP S3"; - compatible = "qcom,cdp"; qcom,board-id = <1 3>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts index 5656fd00fc53..63b51ab85425 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-ext-codec-mtp-s4-overlay.dts @@ -18,7 +18,6 @@ / { model = "Ext Codec MTP S4"; - compatible = "qcom,mtp"; qcom,board-id = <8 4>; }; diff --git a/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts b/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts index e6217e536fb0..4b7f6b25bc6a 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts +++ b/arch/arm64/boot/dts/qcom/sdm632-qrd-overlay.dts @@ -18,7 +18,6 @@ / { model = "QRD"; - compatible = "qcom,qrd"; qcom,board-id = <0xb 3>; }; -- GitLab From e3e742ec7a4c3e488c60b12e77fd30e58ebdcf75 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Sun, 29 Apr 2018 22:11:42 -0700 Subject: [PATCH 1773/1834] drm/msm/dsi-staging: separate link HS and LP clocks Separate DSI high speed (HS) clocks from low power (LP) clock, so that we can have better control in enabling and disabling these clocks independently. Some DSI hardware versions need LP clocks to be turned on before programming DSI PHY. Change-Id: I05efde2bb2a7f737e2f952554b41e3ab74e990e5 Signed-off-by: Aravind Venkateswaran --- drivers/gpu/drm/msm/dsi-staging/dsi_clk.h | 59 ++- .../gpu/drm/msm/dsi-staging/dsi_clk_manager.c | 417 ++++++++++++------ drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 49 +- drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h | 6 +- drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 18 +- drivers/gpu/drm/msm/dsi-staging/dsi_display.h | 17 +- 6 files changed, 383 insertions(+), 183 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h index d89760ec0049..bdc60d243c55 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk.h @@ -43,6 +43,13 @@ enum dsi_link_clk_type { DSI_LINK_CLK_MAX, }; +enum dsi_link_clk_op_type { + DSI_LINK_CLK_SET_RATE = BIT(0), + DSI_LINK_CLK_PREPARE = BIT(1), + DSI_LINK_CLK_ENABLE = BIT(2), + DSI_LINK_CLK_START = BIT(0) | BIT(1) | BIT(2), +}; + enum dsi_clk_type { DSI_CORE_CLK = BIT(0), DSI_LINK_CLK = BIT(1), @@ -50,6 +57,12 @@ enum dsi_clk_type { DSI_CLKS_MAX = BIT(2), }; +enum dsi_lclk_type { + DSI_LINK_NONE = 0, + DSI_LINK_LP_CLK = BIT(0), + DSI_LINK_HS_CLK = BIT(1), +}; + struct dsi_clk_ctrl_info { enum dsi_clk_type clk_type; enum dsi_clk_state clk_state; @@ -82,23 +95,29 @@ struct dsi_core_clk_info { }; /** - * struct dsi_link_clk_info - Link clock information for DSI hardware. - * @byte_clk: Handle to DSI byte clock. - * @pixel_clk: Handle to DSI pixel clock. - * @esc_clk: Handle to DSI escape clock. + * struct dsi_link_hs_clk_info - Set of high speed link clocks for DSI HW + * @byte_clk: Handle to DSI byte_clk. + * @pixel_clk: Handle to DSI pixel_clk. * @byte_intf_clk: Handle to DSI byte intf. clock. */ -struct dsi_link_clk_info { +struct dsi_link_hs_clk_info { struct clk *byte_clk; struct clk *pixel_clk; - struct clk *esc_clk; struct clk *byte_intf_clk; }; +/** + * struct dsi_link_lp_clk_info - Set of low power link clocks for DSI HW. + * @esc_clk: Handle to DSI escape clock. + */ +struct dsi_link_lp_clk_info { + struct clk *esc_clk; +}; + /** * struct link_clk_freq - Clock frequency information for Link clocks - * @byte_clk_rate: Frequency of DSI byte clock in KHz. - * @pixel_clk_rate: Frequency of DSI pixel clock in KHz. + * @byte_clk_rate: Frequency of DSI byte_clk in KHz. + * @pixel_clk_rate: Frequency of DSI pixel_clk in KHz. * @esc_clk_rate: Frequency of DSI escape clock in KHz. */ struct link_clk_freq { @@ -111,48 +130,56 @@ struct link_clk_freq { * typedef *pre_clockoff_cb() - Callback before clock is turned off * @priv: private data pointer. * @clk_type: clock which is being turned off. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ typedef int (*pre_clockoff_cb)(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, enum dsi_clk_state new_state); /** * typedef *post_clockoff_cb() - Callback after clock is turned off * @priv: private data pointer. * @clk_type: clock which was turned off. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ typedef int (*post_clockoff_cb)(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, enum dsi_clk_state curr_state); /** * typedef *post_clockon_cb() - Callback after clock is turned on * @priv: private data pointer. * @clk_type: clock which was turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ typedef int (*post_clockon_cb)(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, enum dsi_clk_state curr_state); /** * typedef *pre_clockon_cb() - Callback before clock is turned on * @priv: private data pointer. * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type.Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ typedef int (*pre_clockon_cb)(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, enum dsi_clk_state new_state); @@ -160,7 +187,8 @@ typedef int (*pre_clockon_cb)(void *priv, * struct dsi_clk_info - clock information for DSI hardware. * @name: client name. * @c_clks[MAX_DSI_CTRL] array of core clock configurations - * @l_clks[MAX_DSI_CTRL] array of link clock configurations + * @l_lp_clks[MAX_DSI_CTRL] array of low power(esc) clock configurations + * @l_hs_clks[MAX_DSI_CTRL] array of high speed clock configurations * @bus_handle[MAX_DSI_CTRL] array of bus handles * @ctrl_index[MAX_DSI_CTRL] array of DSI controller indexes mapped * to core and link clock configurations @@ -175,7 +203,8 @@ typedef int (*pre_clockon_cb)(void *priv, struct dsi_clk_info { char name[MAX_STRING_LEN]; struct dsi_core_clk_info c_clks[MAX_DSI_CTRL]; - struct dsi_link_clk_info l_clks[MAX_DSI_CTRL]; + struct dsi_link_lp_clk_info l_lp_clks[MAX_DSI_CTRL]; + struct dsi_link_hs_clk_info l_hs_clks[MAX_DSI_CTRL]; u32 bus_handle[MAX_DSI_CTRL]; u32 ctrl_index[MAX_DSI_CTRL]; pre_clockoff_cb pre_clkoff_cb; @@ -189,8 +218,8 @@ struct dsi_clk_info { /** * struct dsi_clk_link_set - Pair of clock handles to describe link clocks - * @byte_clk: Handle to DSi byte clock. - * @pixel_clk: Handle to DSI pixel clock. + * @byte_clk: Handle to DSi byte_clk. + * @pixel_clk: Handle to DSI pixel_clk. */ struct dsi_clk_link_set { struct clk *byte_clk; @@ -263,10 +292,10 @@ int dsi_clk_set_link_frequencies(void *client, struct link_clk_freq freq, /** - * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock + * dsi_clk_set_pixel_clk_rate() - set frequency for pixel_clk * @client: DSI clock client pointer. - * @pixel_clk: Pixel clock rate in Hz. - * @index: Index of the DSI controller. + * @pixel_clk: Pixel_clk rate in Hz. + * @index: Index of the DSI controller. * return: error code in case of failure or 0 for success. */ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c index 434d38306df5..2e3828ef11e2 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_clk_manager.c @@ -24,7 +24,8 @@ struct dsi_core_clks { }; struct dsi_link_clks { - struct dsi_link_clk_info clks; + struct dsi_link_hs_clk_info hs_clks; + struct dsi_link_lp_clk_info lp_clks; struct link_clk_freq freq; }; @@ -124,7 +125,7 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index) struct dsi_clk_mngr *mngr; mngr = c->mngr; - rc = clk_set_rate(mngr->link_clks[index].clks.pixel_clk, pixel_clk); + rc = clk_set_rate(mngr->link_clks[index].hs_clks.pixel_clk, pixel_clk); if (rc) pr_err("failed to set clk rate for pixel clk, rc=%d\n", rc); else @@ -147,7 +148,7 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index) struct dsi_clk_mngr *mngr; mngr = c->mngr; - rc = clk_set_rate(mngr->link_clks[index].clks.byte_clk, byte_clk); + rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk); if (rc) pr_err("failed to set clk rate for byte clk, rc=%d\n", rc); else @@ -285,38 +286,39 @@ int dsi_core_clk_stop(struct dsi_core_clks *c_clks) return rc; } -static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index) +static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks, + int index) { int rc = 0; struct dsi_clk_mngr *mngr; + struct dsi_link_clks *l_clks; if (index >= MAX_DSI_CTRL) { pr_err("Invalid DSI ctrl index\n"); return -EINVAL; } + l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[index]); - if (mngr->is_cont_splash_enabled) - return 0; + /* * In an ideal world, cont_splash_enabled should not be required inside * the clock manager. But, in the current driver cont_splash_enabled * flag is set inside mdp driver and there is no interface event * associated with this flag setting. */ - rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->freq.esc_clk_rate); - if (rc) { - pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc); - goto error; - } + if (mngr->is_cont_splash_enabled) + return 0; - rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->freq.byte_clk_rate); + rc = clk_set_rate(link_hs_clks->byte_clk, + l_clks->freq.byte_clk_rate); if (rc) { pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc); goto error; } - rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->freq.pix_clk_rate); + rc = clk_set_rate(link_hs_clks->pixel_clk, + l_clks->freq.pix_clk_rate); if (rc) { pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc); goto error; @@ -327,8 +329,8 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index) * For DPHY: byte_intf_clk_rate = byte_clk_rate / 2 * todo: this needs to be revisited when support for CPHY is added */ - if (l_clks->clks.byte_intf_clk) { - rc = clk_set_rate(l_clks->clks.byte_intf_clk, + if (link_hs_clks->byte_intf_clk) { + rc = clk_set_rate(link_hs_clks->byte_intf_clk, (l_clks->freq.byte_clk_rate / 2)); if (rc) { pr_err("set_rate failed for byte_intf_clk rc = %d\n", @@ -340,30 +342,24 @@ static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks, int index) return rc; } -static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks) +static int dsi_link_hs_clk_prepare(struct dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; - rc = clk_prepare(l_clks->clks.esc_clk); - if (rc) { - pr_err("Failed to prepare dsi esc clk, rc=%d\n", rc); - goto esc_clk_err; - } - - rc = clk_prepare(l_clks->clks.byte_clk); + rc = clk_prepare(link_hs_clks->byte_clk); if (rc) { pr_err("Failed to prepare dsi byte clk, rc=%d\n", rc); goto byte_clk_err; } - rc = clk_prepare(l_clks->clks.pixel_clk); + rc = clk_prepare(link_hs_clks->pixel_clk); if (rc) { pr_err("Failed to prepare dsi pixel clk, rc=%d\n", rc); goto pixel_clk_err; } - if (l_clks->clks.byte_intf_clk) { - rc = clk_prepare(l_clks->clks.byte_intf_clk); + if (link_hs_clks->byte_intf_clk) { + rc = clk_prepare(link_hs_clks->byte_intf_clk); if (rc) { pr_err("Failed to prepare dsi byte intf clk, rc=%d\n", rc); @@ -374,48 +370,39 @@ static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks) return rc; byte_intf_clk_err: - clk_unprepare(l_clks->clks.pixel_clk); + clk_unprepare(link_hs_clks->pixel_clk); pixel_clk_err: - clk_unprepare(l_clks->clks.byte_clk); + clk_unprepare(link_hs_clks->byte_clk); byte_clk_err: - clk_unprepare(l_clks->clks.esc_clk); -esc_clk_err: return rc; } -static void dsi_link_clk_unprepare(struct dsi_link_clks *l_clks) +static void dsi_link_hs_clk_unprepare(struct dsi_link_hs_clk_info *link_hs_clks) { - if (l_clks->clks.byte_intf_clk) - clk_unprepare(l_clks->clks.byte_intf_clk); - clk_unprepare(l_clks->clks.pixel_clk); - clk_unprepare(l_clks->clks.byte_clk); - clk_unprepare(l_clks->clks.esc_clk); + if (link_hs_clks->byte_intf_clk) + clk_unprepare(link_hs_clks->byte_intf_clk); + clk_unprepare(link_hs_clks->pixel_clk); + clk_unprepare(link_hs_clks->byte_clk); } -static int dsi_link_clk_enable(struct dsi_link_clks *l_clks) +static int dsi_link_hs_clk_enable(struct dsi_link_hs_clk_info *link_hs_clks) { int rc = 0; - rc = clk_enable(l_clks->clks.esc_clk); - if (rc) { - pr_err("Failed to enable dsi esc clk, rc=%d\n", rc); - goto esc_clk_err; - } - - rc = clk_enable(l_clks->clks.byte_clk); + rc = clk_enable(link_hs_clks->byte_clk); if (rc) { pr_err("Failed to enable dsi byte clk, rc=%d\n", rc); goto byte_clk_err; } - rc = clk_enable(l_clks->clks.pixel_clk); + rc = clk_enable(link_hs_clks->pixel_clk); if (rc) { pr_err("Failed to enable dsi pixel clk, rc=%d\n", rc); goto pixel_clk_err; } - if (l_clks->clks.byte_intf_clk) { - rc = clk_enable(l_clks->clks.byte_intf_clk); + if (link_hs_clks->byte_intf_clk) { + rc = clk_enable(link_hs_clks->byte_intf_clk); if (rc) { pr_err("Failed to enable dsi byte intf clk, rc=%d\n", rc); @@ -426,28 +413,26 @@ static int dsi_link_clk_enable(struct dsi_link_clks *l_clks) return rc; byte_intf_clk_err: - clk_disable(l_clks->clks.pixel_clk); + clk_disable(link_hs_clks->pixel_clk); pixel_clk_err: - clk_disable(l_clks->clks.byte_clk); + clk_disable(link_hs_clks->byte_clk); byte_clk_err: - clk_disable(l_clks->clks.esc_clk); -esc_clk_err: return rc; } -static void dsi_link_clk_disable(struct dsi_link_clks *l_clks) +static void dsi_link_hs_clk_disable(struct dsi_link_hs_clk_info *link_hs_clks) { - if (l_clks->clks.byte_intf_clk) - clk_disable(l_clks->clks.byte_intf_clk); - clk_disable(l_clks->clks.esc_clk); - clk_disable(l_clks->clks.pixel_clk); - clk_disable(l_clks->clks.byte_clk); + if (link_hs_clks->byte_intf_clk) + clk_disable(link_hs_clks->byte_intf_clk); + clk_disable(link_hs_clks->pixel_clk); + clk_disable(link_hs_clks->byte_clk); } /** * dsi_link_clk_start() - enable dsi link clocks */ -static int dsi_link_clk_start(struct dsi_link_clks *clks, int index) +static int dsi_link_hs_clk_start(struct dsi_link_hs_clk_info *link_hs_clks, + enum dsi_link_clk_op_type op_type, int index) { int rc = 0; @@ -456,28 +441,34 @@ static int dsi_link_clk_start(struct dsi_link_clks *clks, int index) return -EINVAL; } - rc = dsi_link_clk_set_rate(clks, index); - if (rc) { - pr_err("failed to set clk rates, rc = %d\n", rc); - goto error; + if (op_type & DSI_LINK_CLK_SET_RATE) { + rc = dsi_link_hs_clk_set_rate(link_hs_clks, index); + if (rc) { + pr_err("failed to set HS clk rates, rc = %d\n", rc); + goto error; + } } - rc = dsi_link_clk_prepare(clks); - if (rc) { - pr_err("failed to prepare link clks, rc = %d\n", rc); - goto error; + if (op_type & DSI_LINK_CLK_PREPARE) { + rc = dsi_link_hs_clk_prepare(link_hs_clks); + if (rc) { + pr_err("failed to prepare link HS clks, rc = %d\n", rc); + goto error; + } } - rc = dsi_link_clk_enable(clks); - if (rc) { - pr_err("failed to enable link clks, rc = %d\n", rc); - goto error_unprepare; + if (op_type & DSI_LINK_CLK_ENABLE) { + rc = dsi_link_hs_clk_enable(link_hs_clks); + if (rc) { + pr_err("failed to enable link HS clks, rc = %d\n", rc); + goto error_unprepare; + } } - pr_debug("Link clocks are enabled\n"); + pr_debug("HS Link clocks are enabled\n"); return rc; error_unprepare: - dsi_link_clk_unprepare(clks); + dsi_link_hs_clk_unprepare(link_hs_clks); error: return rc; } @@ -485,13 +476,69 @@ static int dsi_link_clk_start(struct dsi_link_clks *clks, int index) /** * dsi_link_clk_stop() - Stop DSI link clocks. */ -int dsi_link_clk_stop(struct dsi_link_clks *clks) +static int dsi_link_hs_clk_stop(struct dsi_link_hs_clk_info *link_hs_clks) +{ + struct dsi_link_clks *l_clks; + + l_clks = container_of(link_hs_clks, struct dsi_link_clks, hs_clks); + + dsi_link_hs_clk_disable(link_hs_clks); + dsi_link_hs_clk_unprepare(link_hs_clks); + + pr_debug("HS Link clocks disabled\n"); + + return 0; +} + +static int dsi_link_lp_clk_start(struct dsi_link_lp_clk_info *link_lp_clks) +{ + int rc = 0; + struct dsi_clk_mngr *mngr; + struct dsi_link_clks *l_clks; + + l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); + + mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]); + if (!mngr) + return -EINVAL; + /* + * In an ideal world, cont_splash_enabled should not be required inside + * the clock manager. But, in the current driver cont_splash_enabled + * flag is set inside mdp driver and there is no interface event + * associated with this flag setting. Also, set rate for clock need not + * be called for every enable call. It should be done only once when + * coming out of suspend. + */ + if (mngr->is_cont_splash_enabled) + goto prepare; + + rc = clk_set_rate(link_lp_clks->esc_clk, l_clks->freq.esc_clk_rate); + if (rc) { + pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc); + goto error; + } + +prepare: + rc = clk_prepare_enable(link_lp_clks->esc_clk); + if (rc) { + pr_err("Failed to enable dsi esc clk\n"); + clk_unprepare(l_clks->lp_clks.esc_clk); + } +error: + pr_debug("LP Link clocks are enabled\n"); + return rc; +} + +static int dsi_link_lp_clk_stop( + struct dsi_link_lp_clk_info *link_lp_clks) { - dsi_link_clk_disable(clks); - dsi_link_clk_unprepare(clks); + struct dsi_link_clks *l_clks; + + l_clks = container_of(link_lp_clks, struct dsi_link_clks, lp_clks); - pr_debug("Link clocks disabled\n"); + clk_disable_unprepare(l_clks->lp_clks.esc_clk); + pr_debug("LP Link clocks are disabled\n"); return 0; } @@ -556,7 +603,7 @@ static int dsi_display_core_clk_enable(struct dsi_core_clks *clks, } static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, - u32 ctrl_count, u32 master_ndx) + enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx) { int rc = 0; int i; @@ -570,27 +617,56 @@ static int dsi_display_link_clk_enable(struct dsi_link_clks *clks, m_clks = &clks[master_ndx]; - rc = dsi_link_clk_start(m_clks, master_ndx); - if (rc) { - pr_err("failed to turn on master clocks, rc=%d\n", rc); - goto error; + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_start(&m_clks->lp_clks); + if (rc) { + pr_err("failed to turn on master lp link clocks, rc=%d\n", + rc); + goto error; + } + } + + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_start(&m_clks->hs_clks, + DSI_LINK_CLK_START, master_ndx); + if (rc) { + pr_err("failed to turn on master hs link clocks, rc=%d\n", + rc); + goto error; + } } - /* Turn on rest of the core clocks */ for (i = 0; i < ctrl_count; i++) { clk = &clks[i]; if (!clk || (clk == m_clks)) continue; - rc = dsi_link_clk_start(clk, i); - if (rc) { - pr_err("failed to turn on clocks, rc=%d\n", rc); - goto error_disable_master; + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_start(&clk->lp_clks); + if (rc) { + pr_err("failed to turn on lp link clocks, rc=%d\n", + rc); + goto error_disable_master; + } + } + + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_start(&clk->hs_clks, + DSI_LINK_CLK_START, i); + if (rc) { + pr_err("failed to turn on hs link clocks, rc=%d\n", + rc); + goto error_disable_master; + } } } return rc; + error_disable_master: - (void)dsi_link_clk_stop(m_clks); + if (l_type == DSI_LINK_LP_CLK) + (void)dsi_link_lp_clk_stop(&m_clks->lp_clks); + else if (l_type == DSI_LINK_HS_CLK) + (void)dsi_link_hs_clk_stop(&m_clks->hs_clks); error: return rc; } @@ -646,7 +722,7 @@ static int dsi_display_core_clk_disable(struct dsi_core_clks *clks, } static int dsi_display_link_clk_disable(struct dsi_link_clks *clks, - u32 ctrl_count, u32 master_ndx) + enum dsi_lclk_type l_type, u32 ctrl_count, u32 master_ndx) { int rc = 0; int i; @@ -667,18 +743,103 @@ static int dsi_display_link_clk_disable(struct dsi_link_clks *clks, if (!clk || (clk == m_clks)) continue; - rc = dsi_link_clk_stop(clk); + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_stop(&clk->lp_clks); + if (rc) + pr_err("failed to turn off lp link clocks, rc=%d\n", + rc); + } + + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_stop(&clk->hs_clks); + if (rc) + pr_err("failed to turn off hs link clocks, rc=%d\n", + rc); + } + } + + if (l_type & DSI_LINK_LP_CLK) { + rc = dsi_link_lp_clk_stop(&m_clks->lp_clks); if (rc) - pr_err("failed to turn off clocks, rc=%d\n", rc); + pr_err("failed to turn off master lp link clocks, rc=%d\n", + rc); } - rc = dsi_link_clk_stop(m_clks); - if (rc) - pr_err("failed to turn off master clocks, rc=%d\n", rc); + if (l_type & DSI_LINK_HS_CLK) { + rc = dsi_link_hs_clk_stop(&m_clks->hs_clks); + if (rc) + pr_err("failed to turn off master hs link clocks, rc=%d\n", + rc); + } return rc; } +static int dsi_clk_update_link_clk_state(struct dsi_link_clks *l_clks, + enum dsi_lclk_type l_type, u32 l_state, bool enable) +{ + int rc = 0; + struct dsi_clk_mngr *mngr; + + mngr = container_of(l_clks, struct dsi_clk_mngr, link_clks[0]); + if (!mngr) + return -EINVAL; + + if (enable) { + if (mngr->pre_clkon_cb) { + rc = mngr->pre_clkon_cb(mngr->priv_data, DSI_LINK_CLK, + l_type, l_state); + if (rc) { + pr_err("pre link clk on cb failed for type %d\n", + l_type); + goto error; + } + } + rc = dsi_display_link_clk_enable(l_clks, l_type, + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + pr_err("failed to start link clk type %d rc=%d\n", + l_type, rc); + goto error; + } + + if (mngr->post_clkon_cb) { + rc = mngr->post_clkon_cb(mngr->priv_data, DSI_LINK_CLK, + l_type, l_state); + if (rc) { + pr_err("post link clk on cb failed for type %d\n", + l_type); + goto error; + } + } + } else { + if (mngr->pre_clkoff_cb) { + rc = mngr->pre_clkoff_cb(mngr->priv_data, + DSI_LINK_CLK, l_type, l_state); + if (rc) + pr_err("pre link clk off cb failed\n"); + } + + rc = dsi_display_link_clk_disable(l_clks, l_type, + mngr->dsi_ctrl_count, mngr->master_ndx); + if (rc) { + pr_err("failed to stop link clk type %d, rc = %d\n", + l_type, rc); + goto error; + } + + if (mngr->post_clkoff_cb) { + rc = mngr->post_clkoff_cb(mngr->priv_data, + DSI_LINK_CLK, l_type, l_state); + if (rc) + pr_err("post link clk off cb failed\n"); + } + } + +error: + return rc; +} + static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, struct dsi_link_clks *l_clks, u32 l_state) { @@ -710,6 +871,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->core_clk_state == DSI_CLK_OFF) { rc = mngr->pre_clkon_cb(mngr->priv_data, DSI_CORE_CLK, + DSI_LINK_NONE, DSI_CLK_ON); if (rc) { pr_err("failed to turn on MDP FS rc= %d\n", rc); @@ -726,6 +888,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->post_clkon_cb) { rc = mngr->post_clkon_cb(mngr->priv_data, DSI_CORE_CLK, + DSI_LINK_NONE, DSI_CLK_ON); if (rc) pr_err("post clk on cb failed, rc = %d\n", rc); @@ -735,25 +898,15 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (l_clks) { if (l_state == DSI_CLK_ON) { - if (mngr->pre_clkon_cb) { - rc = mngr->pre_clkon_cb(mngr->priv_data, - DSI_LINK_CLK, l_state); - if (rc) - pr_err("pre link clk on cb failed\n"); - } - rc = dsi_display_link_clk_enable(l_clks, - mngr->dsi_ctrl_count, mngr->master_ndx); - if (rc) { - pr_err("failed to start link clk rc= %d\n", rc); + rc = dsi_clk_update_link_clk_state(l_clks, + DSI_LINK_LP_CLK, l_state, true); + if (rc) + goto error; + + rc = dsi_clk_update_link_clk_state(l_clks, + DSI_LINK_HS_CLK, l_state, true); + if (rc) goto error; - } - if (mngr->post_clkon_cb) { - rc = mngr->post_clkon_cb(mngr->priv_data, - DSI_LINK_CLK, - l_state); - if (rc) - pr_err("post link clk on cb failed\n"); - } } else { /* * Two conditions that need to be checked for Link @@ -784,36 +937,26 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, } rc = dsi_display_link_clk_enable(l_clks, + (DSI_LINK_LP_CLK & DSI_LINK_HS_CLK), mngr->dsi_ctrl_count, mngr->master_ndx); if (rc) { - pr_err("Link clks did not start\n"); + pr_err("LP Link clks did not start\n"); goto error; } l_c_on = true; pr_debug("ECG: core and Link_on\n"); } - if (mngr->pre_clkoff_cb) { - rc = mngr->pre_clkoff_cb(mngr->priv_data, - DSI_LINK_CLK, l_state); - if (rc) - pr_err("pre link clk off cb failed\n"); - } + rc = dsi_clk_update_link_clk_state(l_clks, + DSI_LINK_HS_CLK, l_state, false); + if (rc) + goto error; - rc = dsi_display_link_clk_disable(l_clks, - mngr->dsi_ctrl_count, mngr->master_ndx); - if (rc) { - pr_err("failed to stop link clk, rc = %d\n", - rc); + rc = dsi_clk_update_link_clk_state(l_clks, + DSI_LINK_LP_CLK, l_state, false); + if (rc) goto error; - } - if (mngr->post_clkoff_cb) { - rc = mngr->post_clkoff_cb(mngr->priv_data, - DSI_LINK_CLK, l_state); - if (rc) - pr_err("post link clk off cb failed\n"); - } /* * This check is to save unnecessary clock state * change when going from EARLY_GATE to OFF. In the @@ -872,6 +1015,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->pre_clkoff_cb) { rc = mngr->pre_clkoff_cb(mngr->priv_data, DSI_CORE_CLK, + DSI_LINK_NONE, c_state); if (rc) pr_err("pre core clk off cb failed\n"); @@ -888,6 +1032,7 @@ static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state, if (mngr->post_clkoff_cb) { rc = mngr->post_clkoff_cb(mngr->priv_data, DSI_CORE_CLK, + DSI_LINK_NONE, DSI_CLK_OFF); if (rc) pr_err("post clkoff cb fail, rc = %d\n", @@ -1095,7 +1240,8 @@ static int dsi_display_link_clk_force_update(void *client) } rc = dsi_display_link_clk_disable(l_clks, - mngr->dsi_ctrl_count, mngr->master_ndx); + (DSI_LINK_LP_CLK | DSI_LINK_HS_CLK), + mngr->dsi_ctrl_count, mngr->master_ndx); if (rc) { pr_err("%s, failed to stop link clk, rc = %d\n", __func__, rc); @@ -1103,7 +1249,8 @@ static int dsi_display_link_clk_force_update(void *client) } rc = dsi_display_link_clk_enable(l_clks, - mngr->dsi_ctrl_count, mngr->master_ndx); + (DSI_LINK_LP_CLK | DSI_LINK_HS_CLK), + mngr->dsi_ctrl_count, mngr->master_ndx); if (rc) { pr_err("%s, failed to start link clk rc= %d\n", __func__, rc); @@ -1267,8 +1414,10 @@ void *dsi_display_clk_mngr_register(struct dsi_clk_info *info) for (i = 0; i < mngr->dsi_ctrl_count; i++) { memcpy(&mngr->core_clks[i].clks, &info->c_clks[i], sizeof(struct dsi_core_clk_info)); - memcpy(&mngr->link_clks[i].clks, &info->l_clks[i], - sizeof(struct dsi_link_clk_info)); + memcpy(&mngr->link_clks[i].hs_clks, &info->l_hs_clks[i], + sizeof(struct dsi_link_hs_clk_info)); + memcpy(&mngr->link_clks[i].lp_clks, &info->l_lp_clks[i], + sizeof(struct dsi_link_lp_clk_info)); mngr->core_clks[i].bus_handle = info->bus_handle[i]; mngr->ctrl_index[i] = info->ctrl_index[i]; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c index c7c640f51a49..7c68fb1e724e 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c @@ -498,7 +498,8 @@ static int dsi_ctrl_init_regmap(struct platform_device *pdev, static int dsi_ctrl_clocks_deinit(struct dsi_ctrl *ctrl) { struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks; - struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks; + struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks; + struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks; struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks; if (core->mdp_core_clk) @@ -514,16 +515,17 @@ static int dsi_ctrl_clocks_deinit(struct dsi_ctrl *ctrl) memset(core, 0x0, sizeof(*core)); - if (link->byte_clk) - devm_clk_put(&ctrl->pdev->dev, link->byte_clk); - if (link->pixel_clk) - devm_clk_put(&ctrl->pdev->dev, link->pixel_clk); - if (link->esc_clk) - devm_clk_put(&ctrl->pdev->dev, link->esc_clk); - if (link->byte_intf_clk) - devm_clk_put(&ctrl->pdev->dev, link->byte_intf_clk); + if (hs_link->byte_clk) + devm_clk_put(&ctrl->pdev->dev, hs_link->byte_clk); + if (hs_link->pixel_clk) + devm_clk_put(&ctrl->pdev->dev, hs_link->pixel_clk); + if (lp_link->esc_clk) + devm_clk_put(&ctrl->pdev->dev, lp_link->esc_clk); + if (hs_link->byte_intf_clk) + devm_clk_put(&ctrl->pdev->dev, hs_link->byte_intf_clk); - memset(link, 0x0, sizeof(*link)); + memset(hs_link, 0x0, sizeof(*hs_link)); + memset(lp_link, 0x0, sizeof(*lp_link)); if (rcg->byte_clk) devm_clk_put(&ctrl->pdev->dev, rcg->byte_clk); @@ -540,7 +542,8 @@ static int dsi_ctrl_clocks_init(struct platform_device *pdev, { int rc = 0; struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks; - struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks; + struct dsi_link_lp_clk_info *lp_link = &ctrl->clk_info.lp_link_clks; + struct dsi_link_hs_clk_info *hs_link = &ctrl->clk_info.hs_link_clks; struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks; core->mdp_core_clk = devm_clk_get(&pdev->dev, "mdp_core_clk"); @@ -573,30 +576,30 @@ static int dsi_ctrl_clocks_init(struct platform_device *pdev, pr_debug("can't get mnoc clock, rc=%d\n", rc); } - link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk"); - if (IS_ERR(link->byte_clk)) { - rc = PTR_ERR(link->byte_clk); + hs_link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk"); + if (IS_ERR(hs_link->byte_clk)) { + rc = PTR_ERR(hs_link->byte_clk); pr_err("failed to get byte_clk, rc=%d\n", rc); goto fail; } - link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk"); - if (IS_ERR(link->pixel_clk)) { - rc = PTR_ERR(link->pixel_clk); + hs_link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk"); + if (IS_ERR(hs_link->pixel_clk)) { + rc = PTR_ERR(hs_link->pixel_clk); pr_err("failed to get pixel_clk, rc=%d\n", rc); goto fail; } - link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk"); - if (IS_ERR(link->esc_clk)) { - rc = PTR_ERR(link->esc_clk); + lp_link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk"); + if (IS_ERR(lp_link->esc_clk)) { + rc = PTR_ERR(lp_link->esc_clk); pr_err("failed to get esc_clk, rc=%d\n", rc); goto fail; } - link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk"); - if (IS_ERR(link->byte_intf_clk)) { - link->byte_intf_clk = NULL; + hs_link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk"); + if (IS_ERR(hs_link->byte_intf_clk)) { + hs_link->byte_intf_clk = NULL; pr_debug("can't find byte intf clk, rc=%d\n", rc); } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h index e08ef99911b6..b059fc550a3a 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h @@ -100,7 +100,8 @@ struct dsi_ctrl_power_info { /** * struct dsi_ctrl_clk_info - clock information for DSI controller * @core_clks: Core clocks needed to access DSI controller registers. - * @link_clks: Link clocks required to transmit data over DSI link. + * @hs_link_clks: Clocks required to transmit high speed data over DSI + * @lp_link_clks: Clocks required to perform low power ops over DSI * @rcg_clks: Root clock generation clocks generated in MMSS_CC. The * output of the PLL is set as parent for these root * clocks. These clocks are specific to controller @@ -114,7 +115,8 @@ struct dsi_ctrl_power_info { struct dsi_ctrl_clk_info { /* Clocks parsed from DT */ struct dsi_core_clk_info core_clks; - struct dsi_link_clk_info link_clks; + struct dsi_link_hs_clk_info hs_link_clks; + struct dsi_link_lp_clk_info lp_link_clks; struct dsi_clk_link_set rcg_clks; /* Clocks set by DSI Manager */ diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index adcec15ee219..de9162af8d83 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -3003,6 +3003,7 @@ static void dsi_display_ctrl_isr_configure(struct dsi_display *display, bool en) int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk, + enum dsi_lclk_type l_type, enum dsi_clk_state new_state) { int rc = 0; @@ -3060,6 +3061,7 @@ int dsi_pre_clkoff_cb(void *priv, int dsi_post_clkon_cb(void *priv, enum dsi_clk_type clk, + enum dsi_lclk_type l_type, enum dsi_clk_state curr_state) { int rc = 0; @@ -3148,6 +3150,7 @@ int dsi_post_clkon_cb(void *priv, int dsi_post_clkoff_cb(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, enum dsi_clk_state curr_state) { int rc = 0; @@ -3175,6 +3178,7 @@ int dsi_post_clkoff_cb(void *priv, int dsi_pre_clkon_cb(void *priv, enum dsi_clk_type clk_type, + enum dsi_lclk_type l_type, enum dsi_clk_state new_state) { int rc = 0; @@ -4391,10 +4395,16 @@ static int dsi_display_bind(struct device *dev, goto error_ctrl_deinit; } - memcpy(&info.c_clks[i], &display_ctrl->ctrl->clk_info.core_clks, - sizeof(struct dsi_core_clk_info)); - memcpy(&info.l_clks[i], &display_ctrl->ctrl->clk_info.link_clks, - sizeof(struct dsi_link_clk_info)); + memcpy(&info.c_clks[i], + (&display_ctrl->ctrl->clk_info.core_clks), + sizeof(struct dsi_core_clk_info)); + memcpy(&info.l_hs_clks[i], + (&display_ctrl->ctrl->clk_info.hs_link_clks), + sizeof(struct dsi_link_hs_clk_info)); + memcpy(&info.l_lp_clks[i], + (&display_ctrl->ctrl->clk_info.lp_link_clks), + sizeof(struct dsi_link_lp_clk_info)); + info.c_clks[i].phandle = &priv->phandle; info.bus_handle[i] = display_ctrl->ctrl->axi_bus_info.bus_handle; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h index 6b1c0292becf..56120160cb57 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h @@ -497,12 +497,14 @@ int dsi_display_disable(struct dsi_display *display); * dsi_pre_clkoff_cb() - Callback before clock is turned off * @priv: private data pointer. * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ int dsi_pre_clkoff_cb(void *priv, enum dsi_clk_type clk_type, - enum dsi_clk_state new_state); + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state); /** * dsi_display_update_pps() - update PPS buffer. @@ -519,35 +521,40 @@ int dsi_display_update_pps(char *pps_cmd, void *display); * dsi_post_clkoff_cb() - Callback after clock is turned off * @priv: private data pointer. * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ int dsi_post_clkoff_cb(void *priv, enum dsi_clk_type clk_type, - enum dsi_clk_state curr_state); + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state); /** * dsi_post_clkon_cb() - Callback after clock is turned on * @priv: private data pointer. * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @curr_state: current state for the clock. * * @return: error code. */ int dsi_post_clkon_cb(void *priv, enum dsi_clk_type clk_type, - enum dsi_clk_state curr_state); - + enum dsi_lclk_type l_type, + enum dsi_clk_state curr_state); /** * dsi_pre_clkon_cb() - Callback before clock is turned on * @priv: private data pointer. * @clk_type: clock which is being turned on. + * @l_type: specifies if the clock is HS or LP type. Valid only for link clocks. * @new_state: next state for the clock. * * @return: error code. */ int dsi_pre_clkon_cb(void *priv, enum dsi_clk_type clk_type, - enum dsi_clk_state new_state); + enum dsi_lclk_type l_type, + enum dsi_clk_state new_state); /** * dsi_display_unprepare() - power off display hardware. -- GitLab From eecc567c10d9120c7014824320969680be957234 Mon Sep 17 00:00:00 2001 From: Vijayavardhan Vennapusa Date: Wed, 9 Mar 2016 18:32:45 +0530 Subject: [PATCH 1774/1834] USB: gadget: f_fs: Allocate extra buffer for IN endpoint USB AXI prefetch requires additional 256 bytes than actual required buffer size for USB IN endpoint. But Currently driver is allocating for USB OUT endpoint. Hence fix this by allocating extra buffer for USB IN endpoint only. Change-Id: I3c2d299d8dce3d826b153856e2cd8366b33a2dd6 Signed-off-by: Vijayavardhan Vennapusa --- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 8eed1b3af76e..997433231588 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1097,7 +1097,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) spin_unlock_irq(&epfile->ffs->eps_lock); extra_buf_alloc = ffs->gadget->extra_buf_alloc; - if (io_data->read) + if (!io_data->read) data = kmalloc(data_len + extra_buf_alloc, GFP_KERNEL); else -- GitLab From c05db37586010caf8c7afa31d46c2eec4c4dc25f Mon Sep 17 00:00:00 2001 From: Raja Mallik Date: Thu, 3 May 2018 18:04:31 +0530 Subject: [PATCH 1775/1834] ARM: dts: msm: Add audio support for msm8909w Add device nodes for BG codec audio to work on msm8909w target. Adapt existing pinctrl changes as per 4.9 kernel. Add common audio support file with BG and external codec for msm8909 targets. Change-Id: Ia700d0f29c3e481e60cad4b2d792f52b453fd269 Signed-off-by: Raja Mallik Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar Signed-off-by: Sundara Vinayagam --- .../bindings/sound/qcom-audio-dev.txt | 16 ++ .../dts/qcom/msm-audio-lpass-msm8909.dtsi | 152 ++++++++++++++++++ .../boot/dts/qcom/msm8909-audio-bg_codec.dtsi | 75 ++++----- 3 files changed, 196 insertions(+), 47 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi diff --git a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt index 7b8ae6f2df3f..1e4d2c12d559 100644 --- a/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt +++ b/Documentation/devicetree/bindings/sound/qcom-audio-dev.txt @@ -434,6 +434,9 @@ Required properties: Required properties: - compatible : "qcom,wcd-dsp-glink" + - qcom,msm-codec-glink-edge: Name of the glink edge which is used + for IPC. + If no name is set, it defaults to "wdsp" * msm_ext_disp_audio_codec_rx @@ -722,6 +725,7 @@ Example: wcd_dsp_glink { compatible = "qcom,wcd-dsp-glink"; + qcom,msm-codec-glink-edge = "bg"; }; msm_ext_disp_audio_codec_rx { @@ -1180,6 +1184,18 @@ Required properties: When clock rate is set to zero, then external clock is assumed. + - qcom,msm-cpudai-tdm-afe-ebit-unsupported: Notify if ebit + setting is needed.When this is + set, along with clock rate as + zero, then afe is not configured + for clock. + + - qcom,msm-cpudai-tdm-sec-port-enable: For chipsets with the + limitation where we need to enable + both RX and TX AFE ports, this flag + is used to enable TX/RX port for + RX/TX streams. + - qcom,msm-cpudai-tdm-clk-internal: Clock Source. 0 - EBIT clock from clk tree 1 - IBIT clock from clk tree diff --git a/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi new file mode 100644 index 000000000000..fe9094fb0068 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm-audio-lpass-msm8909.dtsi @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + pcm0: qcom,msm-pcm { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <0>; + }; + + routing: qcom,msm-pcm-routing { + compatible = "qcom,msm-pcm-routing"; + }; + + compr: qcom,msm-compr-dsp { + compatible = "qcom,msm-compr-dsp"; + }; + + pcm1: qcom,msm-pcm-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <1>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "regular"; + }; + + pcm2: qcom,msm-ultra-low-latency { + compatible = "qcom,msm-pcm-dsp"; + qcom,msm-pcm-dsp-id = <2>; + qcom,msm-pcm-low-latency; + qcom,latency-level = "ultra"; + }; + + compress: qcom,msm-compress-dsp { + compatible = "qcom,msm-compress-dsp"; + }; + + voip: qcom,msm-voip-dsp { + compatible = "qcom,msm-voip-dsp"; + }; + + voice: qcom,msm-pcm-voice { + compatible = "qcom,msm-pcm-voice"; + qcom,destroy-cvd; + }; + + stub_codec: qcom,msm-stub-codec { + compatible = "qcom,msm-stub-codec"; + }; + + qcom,msm-dai-fe { + compatible = "qcom,msm-dai-fe"; + }; + + afe: qcom,msm-pcm-afe { + compatible = "qcom,msm-pcm-afe"; + }; + + loopback: qcom,msm-pcm-loopback { + compatible = "qcom,msm-pcm-loopback"; + }; + + lsm: qcom,msm-lsm-client { + compatible = "qcom,msm-lsm-client"; + }; + + qcom,msm-dai-q6 { + compatible = "qcom,msm-dai-q6"; + bt_sco_rx: qcom,msm-dai-q6-bt-sco-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12288>; + }; + + bt_sco_tx: qcom,msm-dai-q6-bt-sco-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12289>; + }; + + int_fm_rx: qcom,msm-dai-q6-int-fm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12292>; + }; + + int_fm_tx: qcom,msm-dai-q6-int-fm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <12293>; + }; + + afe_pcm_rx: qcom,msm-dai-q6-be-afe-pcm-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <224>; + }; + + afe_pcm_tx: qcom,msm-dai-q6-be-afe-pcm-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <225>; + }; + + afe_proxy_rx: qcom,msm-dai-q6-afe-proxy-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <241>; + }; + + afe_proxy_tx: qcom,msm-dai-q6-afe-proxy-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <240>; + }; + + incall_record_rx: qcom,msm-dai-q6-incall-record-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32771>; + }; + + incall_record_tx: qcom,msm-dai-q6-incall-record-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32772>; + }; + + incall_music_rx: qcom,msm-dai-q6-incall-music-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32773>; + }; + + incall_music_2_rx: qcom,msm-dai-q6-incall-music-2-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <32770>; + }; + + usb_audio_rx: qcom,msm-dai-q6-usb-audio-rx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28672>; + }; + + usb_audio_tx: qcom,msm-dai-q6-usb-audio-tx { + compatible = "qcom,msm-dai-q6-dev"; + qcom,msm-dai-q6-dev-id = <28673>; + }; + }; + + hostless: qcom,msm-pcm-hostless { + compatible = "qcom,msm-pcm-hostless"; + }; + +}; diff --git a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi index f2cea322ecc5..fa6498edcd7d 100644 --- a/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909-audio-bg_codec.dtsi @@ -9,8 +9,15 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ +#include "msm-audio-lpass-msm8909.dtsi" &soc { + qcom,msm-audio-apr { + compatible = "qcom,msm-audio-apr"; + msm_audio_apr_dummy { + compatible = "qcom,msm-audio-apr-dummy"; + }; + }; audio_codec_bg: sound { status = "disabled"; compatible = "qcom,msm-bg-audio-codec"; @@ -28,6 +35,8 @@ qcom,msm-ext-pa = "primary"; qcom,tdm-audio-intf; qcom,msm-afe-clk-ver = <1>; + qcom,split-a2dp; + qcom,pri-mi2s-gpios = <&cdc_dmic_gpios>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&lpa>, @@ -69,7 +78,12 @@ asoc-codec = <&stub_codec>; asoc-codec-names = "msm-stub-codec.1"; }; - + cdc_dmic_gpios: cdc_dmic_pinctrl { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; + }; pri_tdm_rx: qcom,msm-dai-tdm-pri-rx { compatible = "qcom,msm-dai-tdm"; qcom,msm-cpudai-tdm-group-id = <37120>; @@ -77,49 +91,32 @@ qcom,msm-cpudai-tdm-group-port-id = <36864 36866 36868 36870>; qcom,msm-cpudai-tdm-clk-rate = <0>; qcom,msm-cpudai-tdm-afe-ebit-unsupported; + qcom,msm-cpudai-tdm-clk-internal = <0>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-sec-port-enable; qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; - pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36864>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_pri_tdm_rx_1: qcom,msm-dai-q6-tdm-pri-rx-1 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36866>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_pri_tdm_rx_2: qcom,msm-dai-q6-tdm-pri-rx-2 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36868>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_pri_tdm_rx_3: qcom,msm-dai-q6-tdm-pri-rx-3 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36870>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -131,49 +128,32 @@ qcom,msm-cpudai-tdm-group-port-id = <36865 36867 36869 36871>; qcom,msm-cpudai-tdm-clk-rate = <0>; qcom,msm-cpudai-tdm-afe-ebit-unsupported; + qcom,msm-cpudai-tdm-clk-internal = <0>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <0>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-sec-port-enable; qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; - pinctrl-names = "default", "sleep"; - pinctrl-0 = <&quat_mi2s_active &quat_mi2s_din_active>; - pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_din_sleep>; dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36865>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_pri_tdm_tx_1: qcom,msm-dai-q6-tdm-pri-tx-1 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36867>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_pri_tdm_tx_2: qcom,msm-dai-q6-tdm-pri-tx-2 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36869>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; dai_pri_tdm_tx_3: qcom,msm-dai-q6-tdm-pri-tx-3 { compatible = "qcom,msm-dai-q6-tdm"; qcom,msm-cpudai-tdm-dev-id = <36871>; - qcom,msm-cpudai-tdm-sync-mode = <0>; - qcom,msm-cpudai-tdm-sync-src = <0>; - qcom,msm-cpudai-tdm-data-out = <0>; - qcom,msm-cpudai-tdm-invert-sync = <0>; - qcom,msm-cpudai-tdm-data-delay = <0>; qcom,msm-cpudai-tdm-data-align = <0>; }; }; @@ -187,6 +167,7 @@ status = "disabled"; compatible = "qcom,bg-codec"; qcom,subsys-name = "modem"; + qcom,bg-speaker-connected; qcom,bg-glink { compatible = "qcom,bg-cdc-glink"; qcom,msm-glink-channels = <4>; -- GitLab From 85c4033153cd052d9c27c601d3905ffd8004d071 Mon Sep 17 00:00:00 2001 From: Jayant Shekhar Date: Tue, 8 May 2018 11:46:36 +0530 Subject: [PATCH 1776/1834] drm/msm/sde: Increase command mode idle timeout in early wake-up Sometimes updates from framework comes with slight delay after early wake up. In such case prevent clock switch off to avoid frame miss or jank in next update. So, increase the command mode idle timeout sufficiently to prevent such issue. Change-Id: I4c92f3cfca5402ee9f6ee29beaf7a32506ac92c7 Signed-off-by: Jayant Shekhar --- drivers/gpu/drm/msm/sde/sde_encoder.c | 13 ++++++++++--- drivers/gpu/drm/msm/sde/sde_encoder.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index bea66931f967..3f251b9b14d7 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -2301,10 +2301,17 @@ static int sde_encoder_resource_control(struct drm_encoder *drm_enc, _sde_encoder_resource_control_rsc_update(drm_enc, true); _sde_encoder_resource_control_helper(drm_enc, true); + /* + * In some cases, commit comes with slight delay + * (> 80 ms)after early wake up, prevent clock switch + * off to avoid jank in next update. So, increase the + * command mode idle timeout sufficiently to prevent + * such case. + */ kthread_mod_delayed_work(&disp_thread->worker, - &sde_enc->delayed_off_work, - msecs_to_jiffies( - IDLE_POWERCOLLAPSE_DURATION)); + &sde_enc->delayed_off_work, + msecs_to_jiffies( + IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP)); sde_enc->rc_state = SDE_ENC_RC_STATE_ON; } diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 0e8e9dd2b8e3..f0d99e7b9957 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -31,6 +31,7 @@ #define SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE BIT(4) #define IDLE_POWERCOLLAPSE_DURATION (66 - 16/2) +#define IDLE_POWERCOLLAPSE_IN_EARLY_WAKEUP (200 - 16/2) /** * Encoder functions and data types -- GitLab From c1e552dd1017dde49b55b540fd7650ced53d5c51 Mon Sep 17 00:00:00 2001 From: Avaneesh Kumar Dwivedi Date: Fri, 11 May 2018 16:57:50 +0530 Subject: [PATCH 1777/1834] soc: qcom: Collect minidump when encryption not required Minidump was supported only with encrypted dumps, but there are cases when minidump need to be collected even when encryption is not supported. This change caters to such requirement and collects minidump even when encryption is not required. Change-Id: I74d94099fd58fe076fc6e9168bac8744f97d2e46 Signed-off-by: Avaneesh Kumar Dwivedi --- drivers/soc/qcom/peripheral-loader.c | 7 +++++-- drivers/soc/qcom/pil-msa.c | 12 ++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/drivers/soc/qcom/peripheral-loader.c b/drivers/soc/qcom/peripheral-loader.c index 360dbcf9ee89..877637927319 100644 --- a/drivers/soc/qcom/peripheral-loader.c +++ b/drivers/soc/qcom/peripheral-loader.c @@ -263,6 +263,7 @@ int pil_do_ramdump(struct pil_desc *desc, struct pil_priv *priv = desc->priv; struct pil_seg *seg; int count = 0, ret; + u32 encryption_status = 0; if (desc->minidump_ss) { pr_info("Minidump : md_ss_toc->md_ss_toc_init is 0x%x\n", @@ -280,12 +281,14 @@ int pil_do_ramdump(struct pil_desc *desc, * Collect minidump if SS ToC is valid and segment table * is initialized in memory and encryption status is set. */ + encryption_status = desc->minidump_ss->encryption_status; + if ((desc->minidump_ss->md_ss_smem_regions_baseptr != 0) && (desc->minidump_ss->md_ss_toc_init == true) && (desc->minidump_ss->md_ss_enable_status == MD_SS_ENABLED)) { - if (desc->minidump_ss->encryption_status == - MD_SS_ENCR_DONE) { + if (encryption_status == MD_SS_ENCR_DONE || + encryption_status == MD_SS_ENCR_NOTREQ) { pr_info("Minidump : Dumping for %s\n", desc->name); return pil_do_minidump(desc, minidump_dev); diff --git a/drivers/soc/qcom/pil-msa.c b/drivers/soc/qcom/pil-msa.c index 6283477a7952..83bbc860055b 100644 --- a/drivers/soc/qcom/pil-msa.c +++ b/drivers/soc/qcom/pil-msa.c @@ -797,14 +797,18 @@ int pil_mss_reset_load_mba(struct pil_desc *pil) int pil_mss_debug_reset(struct pil_desc *pil) { struct q6v5_data *drv = container_of(pil, struct q6v5_data, desc); + u32 encryption_status; int ret; + if (!pil->minidump_ss) return 0; - if (pil->minidump_ss) { - if (pil->minidump_ss->md_ss_enable_status != MD_SS_ENABLED) - return 0; - } + + encryption_status = pil->minidump_ss->encryption_status; + + if ((pil->minidump_ss->md_ss_enable_status != MD_SS_ENABLED) || + encryption_status == MD_SS_ENCR_NOTREQ) + return 0; /* * Bring subsystem out of reset and enable required -- GitLab From 882868a033f23c196eea57ed110ac8b30051f39b Mon Sep 17 00:00:00 2001 From: Amit Nischal Date: Mon, 7 May 2018 10:53:04 +0530 Subject: [PATCH 1778/1834] clk: qcom: Update ops for esc clock source Some of the display panels require various escape clock frequencies for its operation. Add support for the same by update esc clock ops to clk_esc_ops. Change-Id: I3fe1e98bcdb15e3384fffc17089276e2257be7f3 Signed-off-by: Amit Nischal --- drivers/clk/qcom/dispcc-sdm845.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/clk/qcom/dispcc-sdm845.c b/drivers/clk/qcom/dispcc-sdm845.c index d4f27d79f638..0c49fa4bd137 100644 --- a/drivers/clk/qcom/dispcc-sdm845.c +++ b/drivers/clk/qcom/dispcc-sdm845.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -328,13 +328,12 @@ static struct clk_rcg2 disp_cc_mdss_esc0_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = disp_cc_parent_map_0, - .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_esc0_clk_src", .parent_names = disp_cc_parent_names_0, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_esc_ops, VDD_CX_FMAX_MAP1( MIN, 19200000), }, @@ -345,13 +344,12 @@ static struct clk_rcg2 disp_cc_mdss_esc1_clk_src = { .mnd_width = 0, .hid_width = 5, .parent_map = disp_cc_parent_map_0, - .freq_tbl = ftbl_disp_cc_mdss_esc0_clk_src, .clkr.hw.init = &(struct clk_init_data){ .name = "disp_cc_mdss_esc1_clk_src", .parent_names = disp_cc_parent_names_0, .num_parents = 4, .flags = CLK_SET_RATE_PARENT, - .ops = &clk_rcg2_ops, + .ops = &clk_esc_ops, VDD_CX_FMAX_MAP1( MIN, 19200000), }, -- GitLab From 2df1522f406ae11feb89d12fad5fbb5930e12ec2 Mon Sep 17 00:00:00 2001 From: Deepak Kumar Date: Tue, 15 May 2018 10:09:29 +0530 Subject: [PATCH 1779/1834] msm: kgsl: Take a refcount only for memtype ION in imported_mem_show In imported_mem_show, we are only interested in entries of memory type ION. Take a reference count only on ION entries and only if they are not marked as pending free. This would avoid the overhead of taking and putting a reference count on unneeded entries which are generally much higher in number than ION entries. Change-Id: I036d49b082f352e00333ed9212a098a4510abfe1 Signed-off-by: Deepak Kumar --- drivers/gpu/msm/kgsl_sharedmem.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index 2e84bade75ee..14653eab3186 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -110,27 +110,25 @@ imported_mem_show(struct kgsl_process_private *priv, id++, entry = idr_get_next(&priv->mem_idr, &id)) { int egl_surface_count = 0, egl_image_count = 0; - struct kgsl_memdesc *m; + struct kgsl_memdesc *m = &entry->memdesc; - if (kgsl_mem_entry_get(entry) == 0) + if ((kgsl_memdesc_usermem_type(m) != KGSL_MEM_ENTRY_ION) || + entry->pending_free || (kgsl_mem_entry_get(entry) == 0)) continue; spin_unlock(&priv->mem_lock); - m = &entry->memdesc; - if (kgsl_memdesc_usermem_type(m) == KGSL_MEM_ENTRY_ION) { - kgsl_get_egl_counts(entry, &egl_surface_count, - &egl_image_count); + kgsl_get_egl_counts(entry, &egl_surface_count, + &egl_image_count); - if (kgsl_memdesc_get_memtype(m) == - KGSL_MEMTYPE_EGL_SURFACE) - imported_mem += m->size; - else if (egl_surface_count == 0) { - uint64_t size = m->size; + if (kgsl_memdesc_get_memtype(m) == + KGSL_MEMTYPE_EGL_SURFACE) + imported_mem += m->size; + else if (egl_surface_count == 0) { + uint64_t size = m->size; - do_div(size, (egl_image_count ? - egl_image_count : 1)); - imported_mem += size; - } + do_div(size, (egl_image_count ? + egl_image_count : 1)); + imported_mem += size; } kgsl_mem_entry_put(entry); -- GitLab From cdaab093a247c7b446547fe01297557d3f5d32e5 Mon Sep 17 00:00:00 2001 From: Zhenhua Huang Date: Fri, 20 Apr 2018 12:33:09 +0800 Subject: [PATCH 1780/1834] ARM: dts: msm: Disable 'no-map-fixup' for modem carveout on msm8953 CONFIG_ENABLE_VMALLOC_SAVING and 'no-map-fixup' are not effective together as 'no-map-fixup' performs a delayed carveout while vmalloc saving feature coming up early assumes it to be logical mapped region, thus not being able to reuse corresponding address space for vmalloc. At the same time, 'no-map-fixup' causes the present_pages of zone not accurate as memblock_remove() called later than statistics generated. CRs-fixed: 2220858 Change-Id: I35a1f8106d890211aaa3d1b032b3d1de32331f14 Signed-off-by: Zhenhua Huang --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index 50ee0e8b1b64..005bcb9ee203 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -68,7 +68,7 @@ modem_mem: modem_region@0 { compatible = "removed-dma-pool"; - no-map-fixup; + no-map; reg = <0x0 0x86c00000 0x0 0x6a00000>; }; -- GitLab From a3cd980eb30fd406cd82b41b244419d54b0e5816 Mon Sep 17 00:00:00 2001 From: Ajay Agarwal Date: Tue, 15 May 2018 14:47:49 +0530 Subject: [PATCH 1781/1834] usb: gadget: f_rndis: Setup netdevice with name 'rndis0' Currently we are registering net device with the name 'usb0' from f_rndis. But the netmanager daemon expects the RNDIS netdevice name to be 'rndis0' for proper configurations. Hence change the netdevice name to rndis0. Change-Id: Id01b96b88ed80ad0d528d70ea0d9ac16897075df Signed-off-by: Ajay Agarwal --- drivers/usb/gadget/function/f_rndis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index bc4f9f72af8a..814b4a3e4a5e 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -767,7 +767,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) */ if (!rndis_opts->bound) { mutex_lock(&rndis_opts->lock); - rndis_opts->net = gether_setup_default(); + rndis_opts->net = gether_setup_name_default("rndis"); if (IS_ERR(rndis_opts->net)) { status = PTR_ERR(rndis_opts->net); mutex_unlock(&rndis_opts->lock); -- GitLab From e3f6992200351e93b6b90c18945d48fd518f5506 Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Tue, 15 May 2018 15:22:44 +0530 Subject: [PATCH 1782/1834] ARM: dts: msm: Add rpmh master stats node for sdxpoorwills RPMH master stats provides support to display various master stats information using sysfs. Change-Id: I620204f63287fda1c7b51cb20ffbf3e97769f190 Signed-off-by: Maulik Shah --- arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi index 77fc53306022..505f242a28ae 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills-pm.dtsi @@ -98,4 +98,9 @@ reg = <0xC300000 0x1000>, <0xC370004 0x4>; reg-names = "phys_addr_base", "offset_addr"; }; + + qcom,rpmh-master-stats@b211200 { + compatible = "qcom,rpmh-master-stats-v1"; + reg = <0xb211200 0x60>; + }; }; -- GitLab From 2d49222a8e31666ea5f1112e8d8c860372255219 Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Fri, 23 Mar 2018 12:42:58 +0530 Subject: [PATCH 1783/1834] input: touchscreen: Add himax touchscreen support apq8053-lite FEP-V2 SOM has 2 variants of display Panel - 8" and 10". For 8" display panel the touch vendor is Himax. Add Himax touchscreen support for 8" Display Panel. Git-Repo: https://github.com/HimaxSoftware/msm-3.18 Change-Id: Icd68acfd4f119da98e928e5b5842866c1c7df2f6 Signed-off-by: Paul Chang (cherry picked from commit aa2965fae3f8d791d0fd4c8105408bee807b540c) (cherry picked from commit 714259e2f1eadeb712fdb9cf6e6619fe6eece156) (cherry picked from commit 788fbe836fcabb5493596a2ccc393645665e47c5) (cherry picked from commit 884851757226bb87dd51c5686ee9935a7cd95403) (cherry picked from commit a2b465b13af90f22233943c492b6f09a4fa892e7) (cherry picked from commit 1f5b2aaafa1d9935b0831b641edebd18cf05eb04) (cherry picked from commit 3f6ec12edd3200d6d3c4c32b93e4ed390160403d) (cherry picked from commit 7bc077d513ac739518734a4ab7fee80ca63a9d02) (cherry picked from commit 97afcbfbca30b5eeb3b8acc10e2d1b430650e7a0) (cherry picked from commit 566ec5a310816f2527a0f06e164a90fca7c04650) (cherry picked from commit c91150831a152e1123902f36194802124b7d8aca) (cherry picked from commit c48e3f6d989efadc818563a154e8c029d6c8acfd) (cherry picked from commit fc785e480943fec46cc85a920592de714c9662e9) Signed-off-by: Vijay Navnath Kamble --- .../bindings/input/touchscreen/himax.txt | 17 + drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + .../hxchipset/HX83100_Amber_0901_030B.i | 0 .../input/touchscreen/hxchipset/HX_CRC_124.i | 0 .../input/touchscreen/hxchipset/HX_CRC_128.i | 0 .../input/touchscreen/hxchipset/HX_CRC_60.i | 0 .../input/touchscreen/hxchipset/HX_CRC_64.i | 0 drivers/input/touchscreen/hxchipset/Kconfig | 21 + drivers/input/touchscreen/hxchipset/Makefile | 3 + .../touchscreen/hxchipset/himax_common.c | 1936 ++++++++++++++ .../touchscreen/hxchipset/himax_common.h | 395 +++ .../input/touchscreen/hxchipset/himax_debug.c | 2329 +++++++++++++++++ .../input/touchscreen/hxchipset/himax_debug.h | 181 ++ .../input/touchscreen/hxchipset/himax_ic.c | 2118 +++++++++++++++ .../input/touchscreen/hxchipset/himax_ic.h | 82 + .../touchscreen/hxchipset/himax_platform.c | 796 ++++++ .../touchscreen/hxchipset/himax_platform.h | 135 + 18 files changed, 8026 insertions(+) create mode 100644 drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i create mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_124.i create mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_128.i create mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_60.i create mode 100644 drivers/input/touchscreen/hxchipset/HX_CRC_64.i create mode 100644 drivers/input/touchscreen/hxchipset/Kconfig create mode 100644 drivers/input/touchscreen/hxchipset/Makefile create mode 100644 drivers/input/touchscreen/hxchipset/himax_common.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_common.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_debug.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_ic.h create mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.c create mode 100644 drivers/input/touchscreen/hxchipset/himax_platform.h diff --git a/Documentation/devicetree/bindings/input/touchscreen/himax.txt b/Documentation/devicetree/bindings/input/touchscreen/himax.txt index 258ffec27b8f..b54c85971927 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/himax.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/himax.txt @@ -3,3 +3,20 @@ Himax touch controller Required properties: - compatible : Should be "himax,hxcommon" + - reg : i2c slave address of the device. + - interrupt-parent : parent of interrupt. + - himax,irq-gpio : irq gpio. + - himax,reset-gpio : reset gpio. + - vdd-supply : Power supply needed to power up the device. + - avdd-supply : Power source required to power up i2c bus. + - himax,panel-coords : panel coordinates for the chip in pixels. + It is a four tuple consisting of min x, + min y, max x and max y values. + - himax,display-coords : display coordinates in pixels. It is a four + tuple consisting of min x, min y, max x and + max y values + +Optional properties: + - himax,3v3-gpio : gpio acting as 3.3 v supply. + - report_type : Multi-touch protocol type. Default 0. + 0 for protocol A, 1 for protocol B. diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 25791c2a1533..6c4156a5fe67 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1279,4 +1279,16 @@ config FT_SECURE_TOUCH If unsure, say N. +config TOUCHSCREEN_HIMAX_CHIPSET + bool "Himax touchpanel CHIPSET" + depends on I2C + help + Say Y here if you have a Himax CHIPSET touchscreen. + HIMAX controllers are multi touch controllers which can + report 10 touches at a time. + + If unsure, say N. + +source "drivers/input/touchscreen/hxchipset/Kconfig" + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 34e88236feff..a5952cab1e75 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -104,3 +104,4 @@ obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_FTS) += focaltech_touch/ +obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ diff --git a/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i b/drivers/input/touchscreen/hxchipset/HX83100_Amber_0901_030B.i new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_124.i b/drivers/input/touchscreen/hxchipset/HX_CRC_124.i new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_128.i b/drivers/input/touchscreen/hxchipset/HX_CRC_128.i new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_60.i b/drivers/input/touchscreen/hxchipset/HX_CRC_60.i new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/drivers/input/touchscreen/hxchipset/HX_CRC_64.i b/drivers/input/touchscreen/hxchipset/HX_CRC_64.i new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/drivers/input/touchscreen/hxchipset/Kconfig b/drivers/input/touchscreen/hxchipset/Kconfig new file mode 100644 index 000000000000..ebf3aa478af5 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Kconfig @@ -0,0 +1,21 @@ +# +# Himax Touchscreen driver configuration +# + +config TOUCHSCREEN_HIMAX_I2C + tristate "HIMAX chipset i2c touchscreen" + depends on TOUCHSCREEN_HIMAX_CHIPSET + help + This enables support for HIMAX CHIPSET over I2C based touchscreens. + +config TOUCHSCREEN_HIMAX_DEBUG + tristate "HIMAX debug function" + depends on TOUCHSCREEN_HIMAX_I2C + help + This enables support for HIMAX debug function. + +config HMX_DB + tristate "HIMAX driver test over Dragon Board" + depends on TOUCHSCREEN_HIMAX_I2C + help + This enables support for HIMAX driver test over Dragon Board. diff --git a/drivers/input/touchscreen/hxchipset/Makefile b/drivers/input/touchscreen/hxchipset/Makefile new file mode 100644 index 000000000000..509d4913bc39 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/Makefile @@ -0,0 +1,3 @@ +# Makefile for the Himax touchscreen drivers. + +obj-$(CONFIG_TOUCHSCREEN_HIMAX_I2C) += himax_platform.o himax_ic.o himax_common.o himax_debug.o diff --git a/drivers/input/touchscreen/hxchipset/himax_common.c b/drivers/input/touchscreen/hxchipset/himax_common.c new file mode 100644 index 000000000000..417b0c08e361 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.c @@ -0,0 +1,1936 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_common.h" +#include "himax_ic.h" + +#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#define FRAME_COUNT 5 + +#if defined(HX_AUTO_UPDATE_FW) + static unsigned char i_CTPM_FW[]= + { + #include "HX83100_Amber_0901_030B.i" + }; +#endif + +#ifdef HX_ESD_WORKAROUND + extern void HX_report_ESD_event(void); + unsigned char ESD_00_counter = 0; + unsigned char ESD_00_Flag = 0; +#endif + +//static int tpd_keys_local[HX_KEY_MAX_COUNT] = HX_KEY_ARRAY; // for Virtual key array + +struct himax_ts_data *private_ts; +struct himax_ic_data* ic_data; + +static int HX_TOUCH_INFO_POINT_CNT; + +#ifdef HX_AUTO_UPDATE_FW +extern unsigned long FW_VER_MAJ_FLASH_ADDR; +extern unsigned long FW_VER_MIN_FLASH_ADDR; +extern unsigned long CFG_VER_MAJ_FLASH_ADDR; +extern unsigned long CFG_VER_MIN_FLASH_ADDR; +#endif +extern unsigned long FW_VER_MAJ_FLASH_LENG; +extern unsigned long FW_VER_MIN_FLASH_LENG; +extern unsigned long CFG_VER_MAJ_FLASH_LENG; +extern unsigned long CFG_VER_MIN_FLASH_LENG; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +//PROC-START +#ifdef HX_TP_PROC_FLASH_DUMP +extern void himax_ts_flash_func(void); +extern void setFlashBuffer(void); +extern bool getFlashDumpGoing(void); +extern uint8_t getSysOperation(void); +extern void setSysOperation(uint8_t operation); +#endif + +#ifdef HX_TP_PROC_HITOUCH +extern bool hitouch_is_connect; +#endif + +#ifdef HX_TP_PROC_DIAG + extern int touch_monitor_stop_flag; + extern int touch_monitor_stop_limit; + extern void himax_ts_diag_func(void); + extern int16_t *getMutualBuffer(void); + extern int16_t *getMutualNewBuffer(void); + extern int16_t *getMutualOldBuffer(void); + extern int16_t *getSelfBuffer(void); + extern uint8_t getXChannel(void); + extern uint8_t getYChannel(void); + extern uint8_t getDiagCommand(void); + extern void setXChannel(uint8_t x); + extern void setYChannel(uint8_t y); + extern void setMutualBuffer(void); + extern void setMutualNewBuffer(void); + extern void setMutualOldBuffer(void); + extern uint8_t coordinate_dump_enable; + extern struct file *coordinate_fn; + extern uint8_t diag_coor[128]; +#ifdef HX_TP_PROC_2T2R + extern int16_t *getMutualBuffer_2(void); + extern uint8_t getXChannel_2(void); + extern uint8_t getYChannel_2(void); + extern void setXChannel_2(uint8_t x); + extern void setYChannel_2(uint8_t y); + extern void setMutualBuffer_2(void); +#endif +#endif +//PROC-END +#endif + +extern int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata); +extern int himax_ts_pinctrl_init(struct himax_ts_data *ts); + +static uint8_t vk_press; +static uint8_t AA_press; +static uint8_t EN_NoiseFilter; +static uint8_t Last_EN_NoiseFilter; +static int hx_point_num; // for himax_ts_work_func use +static int p_point_num = 0xFFFF; +static int tpd_key; +static int tpd_key_old; +static int probe_fail_flag; +static bool config_load; +static struct himax_config *config_selected; + +//static int iref_number = 11; +//static bool iref_found = false; + +#ifdef HX_USB_DETECT2 +extern bool USB_Flag; +#endif + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data); +#elif defined(CONFIG_HAS_EARLYSUSPEND) +static void himax_ts_early_suspend(struct early_suspend *h); +static void himax_ts_late_resume(struct early_suspend *h); +#endif + +int himax_input_register(struct himax_ts_data *ts) +{ + int ret; + ts->input_dev = input_allocate_device(); + if (ts->input_dev == NULL) { + ret = -ENOMEM; + E("%s: Failed to allocate input device\n", __func__); + return ret; + } + ts->input_dev->name = "himax-touchscreen"; + + set_bit(EV_SYN, ts->input_dev->evbit); + set_bit(EV_ABS, ts->input_dev->evbit); + set_bit(EV_KEY, ts->input_dev->evbit); + + set_bit(KEY_BACK, ts->input_dev->keybit); + set_bit(KEY_HOME, ts->input_dev->keybit); + set_bit(KEY_MENU, ts->input_dev->keybit); + set_bit(KEY_SEARCH, ts->input_dev->keybit); +#if defined(HX_SMART_WAKEUP) + set_bit(KEY_POWER, ts->input_dev->keybit); + set_bit(KEY_CUST_01, ts->input_dev->keybit); + set_bit(KEY_CUST_02, ts->input_dev->keybit); + set_bit(KEY_CUST_03, ts->input_dev->keybit); + set_bit(KEY_CUST_04, ts->input_dev->keybit); + set_bit(KEY_CUST_05, ts->input_dev->keybit); + set_bit(KEY_CUST_06, ts->input_dev->keybit); + set_bit(KEY_CUST_07, ts->input_dev->keybit); + set_bit(KEY_CUST_08, ts->input_dev->keybit); + set_bit(KEY_CUST_09, ts->input_dev->keybit); + set_bit(KEY_CUST_10, ts->input_dev->keybit); + set_bit(KEY_CUST_11, ts->input_dev->keybit); + set_bit(KEY_CUST_12, ts->input_dev->keybit); + set_bit(KEY_CUST_13, ts->input_dev->keybit); + set_bit(KEY_CUST_14, ts->input_dev->keybit); + set_bit(KEY_CUST_15, ts->input_dev->keybit); +#endif + set_bit(BTN_TOUCH, ts->input_dev->keybit); + + set_bit(KEY_F10, ts->input_dev->keybit); + + set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit); + + if (ts->protocol_type == PROTOCOL_TYPE_A) { + //ts->input_dev->mtsize = ts->nFinger_support; + input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, + 0, 3, 0, 0); + } else {/* PROTOCOL_TYPE_B */ + set_bit(MT_TOOL_FINGER, ts->input_dev->keybit); + input_mt_init_slots(ts->input_dev, ts->nFinger_support,0); + } + + I("input_set_abs_params: mix_x %d, max_x %d, min_y %d, max_y %d\n", + ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_x_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,ts->pdata->abs_y_min, ts->pdata->abs_y_max, ts->pdata->abs_y_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,ts->pdata->abs_pressure_min, ts->pdata->abs_pressure_max, ts->pdata->abs_pressure_fuzz, 0); + input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,ts->pdata->abs_width_min, ts->pdata->abs_width_max, ts->pdata->abs_pressure_fuzz, 0); + +// input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0, ((ts->pdata->abs_pressure_max << 16) | ts->pdata->abs_width_max), 0, 0); +// input_set_abs_params(ts->input_dev, ABS_MT_POSITION, 0, (BIT(31) | (ts->pdata->abs_x_max << 16) | ts->pdata->abs_y_max), 0, 0); + + return input_register_device(ts->input_dev); +} + +static void calcDataSize(uint8_t finger_num) +{ + struct himax_ts_data *ts_data = private_ts; + ts_data->coord_data_size = 4 * finger_num; + ts_data->area_data_size = ((finger_num / 4) + (finger_num % 4 ? 1 : 0)) * 4; + ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size - ts_data->area_data_size - 4 - 4 - 1; + ts_data->raw_data_nframes = ((uint32_t)ts_data->x_channel * ts_data->y_channel + + ts_data->x_channel + ts_data->y_channel) / ts_data->raw_data_frame_size + + (((uint32_t)ts_data->x_channel * ts_data->y_channel + + ts_data->x_channel + ts_data->y_channel) % ts_data->raw_data_frame_size)? 1 : 0; + I("%s: coord_data_size: %d, area_data_size:%d, raw_data_frame_size:%d, raw_data_nframes:%d", __func__, ts_data->coord_data_size, ts_data->area_data_size, ts_data->raw_data_frame_size, ts_data->raw_data_nframes); +} + +static void calculate_point_number(void) +{ + HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4 ; + + if ( (ic_data->HX_MAX_PT % 4) == 0) + HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4 ; + else + HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) +1) * 4 ; +} + +#if 0 +static int himax_read_Sensor_ID(struct i2c_client *client) +{ + uint8_t val_high[1], val_low[1], ID0=0, ID1=0; + char data[3]; + const int normalRetry = 10; + int sensor_id; + + data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + //read id pin high + i2c_himax_read(client, 0x57, val_high, 1, normalRetry); + + data[0] = 0x56; data[1] = 0x01; data[2] = 0x01;/*ID pin PULL Low*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + //read id pin low + i2c_himax_read(client, 0x57, val_low, 1, normalRetry); + + if((val_high[0] & 0x01) ==0) + ID0=0x02;/*GND*/ + else if((val_low[0] & 0x01) ==0) + ID0=0x01;/*Floating*/ + else + ID0=0x04;/*VCC*/ + + if((val_high[0] & 0x02) ==0) + ID1=0x02;/*GND*/ + else if((val_low[0] & 0x02) ==0) + ID1=0x01;/*Floating*/ + else + ID1=0x04;/*VCC*/ + if((ID0==0x04)&&(ID1!=0x04)) + { + data[0] = 0x56; data[1] = 0x02; data[2] = 0x01;/*ID pin PULL High,Low*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + } + else if((ID0!=0x04)&&(ID1==0x04)) + { + data[0] = 0x56; data[1] = 0x01; data[2] = 0x02;/*ID pin PULL Low,High*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + } + else if((ID0==0x04)&&(ID1==0x04)) + { + data[0] = 0x56; data[1] = 0x02; data[2] = 0x02;/*ID pin PULL High,High*/ + i2c_himax_master_write(client, &data[0],3,normalRetry); + usleep_range(1000, 2000); + + } + sensor_id=(ID1<<4)|ID0; + + data[0] = 0xE4; data[1] = sensor_id; + i2c_himax_master_write(client, &data[0],2,normalRetry);/*Write to MCU*/ + usleep_range(1000, 2000); + + return sensor_id; + +} +#endif +static void himax_power_on_initCMD(struct i2c_client *client) +{ + I("%s:\n", __func__); + + himax_touch_information(client); + + //himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM +} + +#ifdef HX_AUTO_UPDATE_FW +static int i_update_FW(void) +{ + int upgrade_times = 0; + unsigned char* ImageBuffer = i_CTPM_FW; + int fullFileLength = sizeof(i_CTPM_FW); + int i_FW_VER = 0, i_CFG_VER = 0; + uint8_t ret = -1, result = 0; +// uint8_t tmp_addr[4]; +// uint8_t tmp_data[4]; + int CRC_from_FW = 0; + int CRC_Check_result = 0; + + i_FW_VER = i_CTPM_FW[FW_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[FW_VER_MIN_FLASH_ADDR]; + i_CFG_VER = i_CTPM_FW[CFG_VER_MAJ_FLASH_ADDR]<<8 |i_CTPM_FW[CFG_VER_MIN_FLASH_ADDR]; + + I("%s: i_fullFileLength = %d\n", __func__,fullFileLength); + + himax_sense_off(private_ts->client); + msleep(500); + + CRC_from_FW = himax_check_CRC(private_ts->client,fw_image_64k); + CRC_Check_result = Calculate_CRC_with_AP(ImageBuffer, CRC_from_FW,fw_image_64k); + I("%s: Check sum result = %d\n", __func__,CRC_Check_result); + //I("%s: ic_data->vendor_fw_ver = %X, i_FW_VER = %X,\n", __func__,ic_data->vendor_fw_ver, i_FW_VER); + //I("%s: ic_data->vendor_config_ver = %X, i_CFG_VER = %X,\n", __func__,ic_data->vendor_config_ver, i_CFG_VER); + + if ((CRC_Check_result == 0)|| ( ic_data->vendor_fw_ver < i_FW_VER ) || ( ic_data->vendor_config_ver < i_CFG_VER )) + { + himax_int_enable(private_ts->client->irq,0); +update_retry: + if(fullFileLength == FW_SIZE_60k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,ImageBuffer,fullFileLength,false); + }else if (fullFileLength == FW_SIZE_64k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,ImageBuffer,fullFileLength,false); + }else if (fullFileLength == FW_SIZE_124k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,ImageBuffer,fullFileLength,false); + }else if (fullFileLength == FW_SIZE_128k){ + ret = fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,ImageBuffer,fullFileLength,false); + } + if(ret == 0){ + upgrade_times++; + E("%s: TP upgrade error, upgrade_times = %d\n", __func__, upgrade_times); + if(upgrade_times < 3) + goto update_retry; + else + { + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + result = -1;//upgrade fail + } + } + else if(ret == 1){ +/* + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); + + // 2. Write driver initial code condition + // write value from AHB I2C : 0x8001_C603 = 0x000000FF + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xC6; tmp_addr[0] = 0x03; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xFF; + himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); + + // 1. Set DDREG_Req = 0 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(private_ts->client, tmp_addr, 1, tmp_data); +*/ + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + + ic_data->vendor_fw_ver = i_FW_VER; + ic_data->vendor_config_ver = i_CFG_VER; + result = 1;//upgrade success + I("%s: TP upgrade OK\n", __func__); + } + + himax_int_enable(private_ts->client->irq,1); + return result; + } + else + { + himax_sense_on(private_ts->client, 0x01); + return 0;//NO upgrade + } +} +#endif + +#ifdef HX_RST_PIN_FUNC +void himax_HW_reset(uint8_t loadconfig,uint8_t int_off) +{ + struct himax_ts_data *ts = private_ts; + int ret = 0; + + return; + if (ts->rst_gpio) { + if(int_off) + { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq,0); + else { + hrtimer_cancel(&ts->timer); + ret = cancel_work_sync(&ts->work); + } + } + + I("%s: Now reset the Touch chip.\n", __func__); + + himax_rst_gpio_set(ts->rst_gpio, 0); + msleep(20); + himax_rst_gpio_set(ts->rst_gpio, 1); + msleep(20); + + if(loadconfig) + himax_loadSensorConfig(private_ts->client,private_ts->pdata); + + if(int_off) + { + if (ts->use_irq) + himax_int_enable(private_ts->client->irq,1); + else + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + } + } +} +#endif + +int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata) +{ + + if (!client) { + E("%s: Necessary parameters client are null!\n", __func__); + return -EINVAL; + } + + if(config_load == false) + { + config_selected = kzalloc(sizeof(*config_selected), GFP_KERNEL); + if (config_selected == NULL) { + E("%s: alloc config_selected fail!\n", __func__); + return -ENOMEM; + } + } + + himax_power_on_initCMD(client); + + himax_int_enable(client->irq,0); + himax_read_FW_ver(client); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + himax_int_enable(client->irq,1); + I("FW_VER : %X \n",ic_data->vendor_fw_ver); + + ic_data->vendor_sensor_id=0x2602; + I("sensor_id=%x.\n",ic_data->vendor_sensor_id); + + himax_sense_on(private_ts->client, 0x01);//1=Flash, 0=SRAM + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + I("%s: initialization complete\n", __func__); + + return 1; +} + +#ifdef HX_ESD_WORKAROUND +void ESD_HW_REST(void) +{ + I("START_Himax TP: ESD - Reset\n"); + + HX_report_ESD_event(); + ESD_00_counter = 0; + ESD_00_Flag = 0; + /*************************************/ + if (private_ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(private_ts->input_dev); + input_report_key(private_ts->input_dev, BTN_TOUCH, 0); + input_sync(private_ts->input_dev); + /*************************************/ + + I("END_Himax TP: ESD - Reset\n"); +} +#endif +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable) +{ + uint8_t tmp_data[4]; + + if(HSEN_enable) + { + I(" %s in", __func__); + HSEN_bit_retry: + himax_set_HSEN_enable(client,HSEN_enable); + msleep(20); + himax_get_HSEN_enable(client,tmp_data); + I("%s: Read HSEN bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + if(tmp_data[0]!= 0x01) + { + I("%s: retry HSEN bit write data[0]=%x \n",__func__,tmp_data[0]); + goto HSEN_bit_retry; + } + } +} + +static void himax_HSEN_func(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, + hsen_work.work); + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); +} + +#endif + +#ifdef HX_SMART_WAKEUP +#ifdef HX_GESTURE_TRACK +static void gest_pt_log_coordinate(int rx, int tx) +{ + //driver report x y with range 0 - 255 , we scale it up to x/y pixel + gest_pt_x[gest_pt_cnt] = rx*(ic_data->HX_X_RES)/255; + gest_pt_y[gest_pt_cnt] = tx*(ic_data->HX_Y_RES)/255; +} +#endif +static int himax_parse_wake_event(struct himax_ts_data *ts) +{ + uint8_t buf[64]; + unsigned char check_sum_cal = 0; +#ifdef HX_GESTURE_TRACK + int tmp_max_x=0x00,tmp_min_x=0xFFFF,tmp_max_y=0x00,tmp_min_y=0xFFFF; + int gest_len; +#endif + int i=0, check_FC = 0, gesture_flag = 0; + + himax_burst_enable(ts->client, 0); + himax_read_event_stack(ts->client,buf,56); + + for(i=0;igest_pt_x[i]) + tmp_min_x=gest_pt_x[i]; + if(tmp_max_ygest_pt_y[i]) + tmp_min_y=gest_pt_y[i]; + } + I("gest_point x_min= %d, x_max= %d, y_min= %d, y_max= %d\n",tmp_min_x,tmp_max_x,tmp_min_y,tmp_max_y); + gest_start_x=gest_pt_x[0]; + gn_gesture_coor[0] = gest_start_x; + gest_start_y=gest_pt_y[0]; + gn_gesture_coor[1] = gest_start_y; + gest_end_x=gest_pt_x[gest_pt_cnt-1]; + gn_gesture_coor[2] = gest_end_x; + gest_end_y=gest_pt_y[gest_pt_cnt-1]; + gn_gesture_coor[3] = gest_end_y; + gest_width = tmp_max_x - tmp_min_x; + gn_gesture_coor[4] = gest_width; + gest_height = tmp_max_y - tmp_min_y; + gn_gesture_coor[5] = gest_height; + gest_mid_x = (tmp_max_x + tmp_min_x)/2; + gn_gesture_coor[6] = gest_mid_x; + gest_mid_y = (tmp_max_y + tmp_min_y)/2; + gn_gesture_coor[7] = gest_mid_y; + gn_gesture_coor[8] = gest_mid_x;//gest_up_x + gn_gesture_coor[9] = gest_mid_y-gest_height/2;//gest_up_y + gn_gesture_coor[10] = gest_mid_x;//gest_down_x + gn_gesture_coor[11] = gest_mid_y+gest_height/2; //gest_down_y + gn_gesture_coor[12] = gest_mid_x-gest_width/2; //gest_left_x + gn_gesture_coor[13] = gest_mid_y; //gest_left_y + gn_gesture_coor[14] = gest_mid_x+gest_width/2; //gest_right_x + gn_gesture_coor[15] = gest_mid_y; //gest_right_y + + } + + } +#endif + if(gesture_flag != 0x80) + { + if(!ts->gesture_cust_en[gesture_flag]) + { + I("%s NOT report customer key \n ",__func__); + return 0;//NOT report customer key + } + } + else + { + if(!ts->gesture_cust_en[0]) + { + I("%s NOT report report double click \n",__func__); + return 0;//NOT report power key + } + } + + if(gesture_flag == 0x80) + return EV_GESTURE_PWR; + else + return gesture_flag; +} + +void himax_wake_check_func(void) +{ + int ret_event = 0, KEY_EVENT = 0; + + ret_event = himax_parse_wake_event(private_ts); + switch (ret_event) { + case EV_GESTURE_PWR: + KEY_EVENT = KEY_POWER; + break; + case EV_GESTURE_01: + KEY_EVENT = KEY_CUST_01; + break; + case EV_GESTURE_02: + KEY_EVENT = KEY_CUST_02; + break; + case EV_GESTURE_03: + KEY_EVENT = KEY_CUST_03; + break; + case EV_GESTURE_04: + KEY_EVENT = KEY_CUST_04; + break; + case EV_GESTURE_05: + KEY_EVENT = KEY_CUST_05; + break; + case EV_GESTURE_06: + KEY_EVENT = KEY_CUST_06; + break; + case EV_GESTURE_07: + KEY_EVENT = KEY_CUST_07; + break; + case EV_GESTURE_08: + KEY_EVENT = KEY_CUST_08; + break; + case EV_GESTURE_09: + KEY_EVENT = KEY_CUST_09; + break; + case EV_GESTURE_10: + KEY_EVENT = KEY_CUST_10; + break; + case EV_GESTURE_11: + KEY_EVENT = KEY_CUST_11; + break; + case EV_GESTURE_12: + KEY_EVENT = KEY_CUST_12; + break; + case EV_GESTURE_13: + KEY_EVENT = KEY_CUST_13; + break; + case EV_GESTURE_14: + KEY_EVENT = KEY_CUST_14; + break; + case EV_GESTURE_15: + KEY_EVENT = KEY_CUST_15; + break; + } + if(ret_event) + { + I(" %s SMART WAKEUP KEY event %x press\n",__func__,KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 1); + input_sync(private_ts->input_dev); + //msleep(100); + I(" %s SMART WAKEUP KEY event %x release\n",__func__,KEY_EVENT); + input_report_key(private_ts->input_dev, KEY_EVENT, 0); + input_sync(private_ts->input_dev); + FAKE_POWER_KEY_SEND=true; +#ifdef HX_GESTURE_TRACK + I("gest_start_x= %d, gest_start_y= %d, gest_end_x= %d, gest_end_y= %d\n",gest_start_x,gest_start_y, + gest_end_x,gest_end_y); + I("gest_width= %d, gest_height= %d, gest_mid_x= %d, gest_mid_y= %d\n",gest_width,gest_height, + gest_mid_x,gest_mid_y); + I("gest_up_x= %d, gest_up_y= %d, gest_down_x= %d, gest_down_y= %d\n",gn_gesture_coor[8],gn_gesture_coor[9], + gn_gesture_coor[10],gn_gesture_coor[11]); + I("gest_left_x= %d, gest_left_y= %d, gest_right_x= %d, gest_right_y= %d\n",gn_gesture_coor[12],gn_gesture_coor[13], + gn_gesture_coor[14],gn_gesture_coor[15]); +#endif + } +} + +#endif +static void himax_ts_button_func(int tp_key_index,struct himax_ts_data *ts) +{ + uint16_t x_position = 0, y_position = 0; +if ( tp_key_index != 0x00) + { + I("virtual key index =%x\n",tp_key_index); + if ( tp_key_index == 0x01) { + vk_press = 1; + I("back key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[0].index) { + x_position = (ts->button[0].x_range_min + ts->button[0].x_range_max) / 2; + y_position = (ts->button[0].y_range_min + ts->button[0].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_BACK, 1); + } + else if ( tp_key_index == 0x02) { + vk_press = 1; + I("home key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[1].index) { + x_position = (ts->button[1].x_range_min + ts->button[1].x_range_max) / 2; + y_position = (ts->button[1].y_range_min + ts->button[1].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_HOME, 1); + } + else if ( tp_key_index == 0x04) { + vk_press = 1; + I("APP_switch key pressed\n"); + if (ts->pdata->virtual_key) + { + if (ts->button[2].index) { + x_position = (ts->button[2].x_range_min + ts->button[2].x_range_max) / 2; + y_position = (ts->button[2].y_range_min + ts->button[2].y_range_max) / 2; + } + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, 0); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + input_mt_sync(ts->input_dev); + } else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, + 1); + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, + 100); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, + 100); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, + x_position); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, + y_position); + } + } + else + input_report_key(ts->input_dev, KEY_F10, 1); + } + input_sync(ts->input_dev); + } +else/*tp_key_index =0x00*/ + { + I("virtual key released\n"); + vk_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) { + input_mt_sync(ts->input_dev); + } + else if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, 0); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + input_report_key(ts->input_dev, KEY_BACK, 0); + input_report_key(ts->input_dev, KEY_HOME, 0); + input_report_key(ts->input_dev, KEY_F10, 0); + input_sync(ts->input_dev); + } +} + +void himax_ts_work(struct himax_ts_data *ts) +{ + int ret = 0; + uint8_t finger_num, hw_reset_check[2]; + uint8_t buf[128]; + uint8_t finger_on = 0; + int32_t loop_i; + uint16_t check_sum_cal = 0; + int raw_cnt_max ; + int raw_cnt_rmd ; + int hx_touch_info_size; + uint8_t coordInfoSize = ts->coord_data_size + ts->area_data_size + 4; + +#ifdef HX_TP_PROC_DIAG + int16_t *mutual_data; + int16_t *self_data; + uint8_t diag_cmd; + int i; + int mul_num; + int self_num; + int RawDataLen = 0; + //coordinate dump start + char coordinate_char[15+(ic_data->HX_MAX_PT+5)*2*5+2]; + //coordinate dump end +#endif + + memset(buf, 0x00, sizeof(buf)); + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + + raw_cnt_max = ic_data->HX_MAX_PT/4; + raw_cnt_rmd = ic_data->HX_MAX_PT%4; + +#if defined(HX_USB_DETECT2) + himax_cable_detect_func(); +#endif + + if (raw_cnt_rmd != 0x00) //more than 4 fingers + { + RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+2)*4; + } + else //less than 4 fingers + { + RawDataLen = cal_data_len(raw_cnt_rmd, ic_data->HX_MAX_PT, raw_cnt_max); + hx_touch_info_size = (ic_data->HX_MAX_PT+raw_cnt_max+1)*4; + } + +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if( diag_cmd ){ + ret = read_event_stack(ts->client, buf, 128); + } + else{ + if(touch_monitor_stop_flag != 0){ + ret = read_event_stack(ts->client, buf, 128); + touch_monitor_stop_flag-- ; + } + else{ + ret = read_event_stack(ts->client, buf, hx_touch_info_size); + } + } + + if (!ret) +#else + if(!read_event_stack(ts->client, buf, hx_touch_info_size)) +#endif + { + E("%s: can't read data from chip!\n", __func__); + goto err_workqueue_out; + } + post_read_event_stack(ts->client); +#ifdef HX_ESD_WORKAROUND + for(i = 0; i < hx_touch_info_size; i++) + { + if(buf[i] == 0xED)/*case 1 ESD recovery flow*/ + { + check_sum_cal = 1; + + }else if(buf[i] == 0x00) + { + ESD_00_Flag = 1; + } + else + { + check_sum_cal = 0; + ESD_00_counter = 0; + ESD_00_Flag = 0; + i = hx_touch_info_size; + break; + } + } + if (ESD_00_Flag == 1){ + ESD_00_counter ++; + } + if (ESD_00_counter > 1){ + check_sum_cal = 2; + } + + if (check_sum_cal == 2 && HX_ESD_RESET_ACTIVATE == 0) + { + I("[HIMAX TP MSG]: ESD event checked - ALL Zero.\n"); + ESD_HW_REST(); + return; + } + + if (check_sum_cal == 1 && HX_ESD_RESET_ACTIVATE == 0) + { + I("[HIMAX TP MSG]: ESD event checked - ALL 0xED.\n"); + ESD_HW_REST(); + return; + } + else if (HX_ESD_RESET_ACTIVATE) + { +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(50)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(50)); +#endif + HX_ESD_RESET_ACTIVATE = 0;/*drop 1st interrupts after chip reset*/ + I("[HIMAX TP MSG]:%s: Back from reset, ready to serve.\n", __func__); + } +#endif + for (loop_i = 0, check_sum_cal = 0; loop_i < hx_touch_info_size; loop_i++) + check_sum_cal += buf[loop_i]; + + if ((check_sum_cal % 0x100 != 0) ) + { + I("[HIMAX TP MSG] checksum fail : check_sum_cal: 0x%02X\n", check_sum_cal); + return; + } + + if (ts->debug_log_level & BIT(0)) { + I("%s: raw data:\n", __func__); + for (loop_i = 0; loop_i < hx_touch_info_size; loop_i++) { + I("P %d = 0x%2.2X ", loop_i, buf[loop_i]); + if (loop_i % 8 == 7) + I("\n"); + } + } + + //touch monitor raw data fetch +#ifdef HX_TP_PROC_DIAG + diag_cmd = getDiagCommand(); + if (diag_cmd >= 1 && diag_cmd <= 6) + { + //Check 124th byte CRC + if(!diag_check_sum(hx_touch_info_size, buf)) + { + goto bypass_checksum_failed_packet; + } +#ifdef HX_TP_PROC_2T2R + if(Is_2T2R && diag_cmd == 4) + { + mutual_data = getMutualBuffer_2(); + self_data = getSelfBuffer(); + + // initiallize the block number of mutual and self + mul_num = getXChannel_2() * getYChannel_2(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel_2() + getYChannel_2() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel_2() + getYChannel_2(); +#endif + } + else +#endif + { + mutual_data = getMutualBuffer(); + self_data = getSelfBuffer(); + + // initiallize the block number of mutual and self + mul_num = getXChannel() * getYChannel(); + +#ifdef HX_EN_SEL_BUTTON + self_num = getXChannel() + getYChannel() + ic_data->HX_BT_NUM; +#else + self_num = getXChannel() + getYChannel(); +#endif + } + + diag_parse_raw_data(hx_touch_info_size, RawDataLen, mul_num, self_num, buf, diag_cmd, mutual_data, self_data); + + } + else if (diag_cmd == 7) + { + memcpy(&(diag_coor[0]), &buf[0], 128); + } + //coordinate dump start + if (coordinate_dump_enable == 1) + { + for(i=0; i<(15 + (ic_data->HX_MAX_PT+5)*2*5); i++) + { + coordinate_char[i] = 0x20; + } + coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5] = 0xD; + coordinate_char[15 + (ic_data->HX_MAX_PT+5)*2*5 + 1] = 0xA; + } + //coordinate dump end +bypass_checksum_failed_packet: +#endif + EN_NoiseFilter = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>3); + //I("EN_NoiseFilter=%d\n",EN_NoiseFilter); + EN_NoiseFilter = EN_NoiseFilter & 0x01; + //I("EN_NoiseFilter2=%d\n",EN_NoiseFilter); + +#if defined(HX_EN_SEL_BUTTON) || defined(HX_EN_MUT_BUTTON) + tpd_key = (buf[HX_TOUCH_INFO_POINT_CNT+2]>>4); + if (tpd_key == 0x0F)/*All (VK+AA)leave*/ + { + tpd_key = 0x00; + } + //I("[DEBUG] tpd_key: %x\r\n", tpd_key); +#else + tpd_key = 0x00; +#endif + + p_point_num = hx_point_num; + + if (buf[HX_TOUCH_INFO_POINT_CNT] == 0xff) + hx_point_num = 0; + else + hx_point_num= buf[HX_TOUCH_INFO_POINT_CNT] & 0x0f; + + // Touch Point information + if (hx_point_num != 0 ) { + if(vk_press == 0x00) + { + uint16_t old_finger = ts->pre_finger_mask; + ts->pre_finger_mask = 0; + finger_num = buf[coordInfoSize - 4] & 0x0F; + finger_on = 1; + AA_press = 1; + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + int base = loop_i * 4; + int x = buf[base] << 8 | buf[base + 1]; + int y = (buf[base + 2] << 8 | buf[base + 3]); + int w = buf[(ts->nFinger_support * 4) + loop_i]; + if(x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 && y <= ts->pdata->abs_y_max){ + finger_num--; + + if ((ts->debug_log_level & BIT(3)) > 0) + { + if (old_finger >> loop_i == 0) + { + if (ts->useScreenRes) + { + I("status: Screen:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", + loop_i+1, x * ts->widthFactor >> SHIFTBITS, + y * ts->heightFactor >> SHIFTBITS, w, EN_NoiseFilter); + } + else + { + I("status: Raw:F:%02d Down, X:%d, Y:%d, W:%d, N:%d\n", + loop_i+1, x, y, w, EN_NoiseFilter); + } + } + } + + if (ts->protocol_type == PROTOCOL_TYPE_B) + { + input_mt_slot(ts->input_dev, loop_i); + } + + input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, w); + input_report_abs(ts->input_dev, ABS_MT_PRESSURE, w); + input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y); + + if (ts->protocol_type == PROTOCOL_TYPE_A) + { + input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, loop_i); + input_mt_sync(ts->input_dev); + } + else + { + ts->last_slot = loop_i; + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 1); + } + + if (!ts->first_pressed) + { + ts->first_pressed = 1; + I("S1@%d, %d\n", x, y); + } + + ts->pre_finger_data[loop_i][0] = x; + ts->pre_finger_data[loop_i][1] = y; + + + if (ts->debug_log_level & BIT(1)) + I("Finger %d=> X:%d, Y:%d W:%d, Z:%d, F:%d, N:%d\n", + loop_i + 1, x, y, w, w, loop_i + 1, EN_NoiseFilter); + + ts->pre_finger_mask = ts->pre_finger_mask + (1 << loop_i); + + } else { + if (ts->protocol_type == PROTOCOL_TYPE_B) + { + input_mt_slot(ts->input_dev, loop_i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + + if (loop_i == 0 && ts->first_pressed == 1) + { + ts->first_pressed = 2; + I("E1@%d, %d\n", + ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + } + if ((ts->debug_log_level & BIT(3)) > 0) + { + if (old_finger >> loop_i == 1) + { + if (ts->useScreenRes) + { + I("status: Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", + loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); + } + else + { + I("status: Raw:F:%02d Up, X:%d, Y:%d, N:%d\n", + loop_i+1, ts->pre_finger_data[loop_i][0], + ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); + } + } + } + } + } + + }else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { + //temp_x[0] = 0xFFFF; + //temp_y[0] = 0xFFFF; + //temp_x[1] = 0xFFFF; + //temp_y[1] = 0xFFFF; + himax_ts_button_func(tpd_key,ts); + finger_on = 0; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } else if (hx_point_num == 0){ + if(AA_press) + { + // leave event + finger_on = 0; + AA_press = 0; + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + + for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) { + if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { + if (ts->protocol_type == PROTOCOL_TYPE_B) { + input_mt_slot(ts->input_dev, loop_i); + input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0); + } + } + } + if (ts->pre_finger_mask > 0) { + for (loop_i = 0; loop_i < ts->nFinger_support && (ts->debug_log_level & BIT(3)) > 0; loop_i++) { + if (((ts->pre_finger_mask >> loop_i) & 1) == 1) { + if (ts->useScreenRes) { + I("status:%X, Screen:F:%02d Up, X:%d, Y:%d, N:%d\n", 0, loop_i+1, ts->pre_finger_data[loop_i][0] * ts->widthFactor >> SHIFTBITS, + ts->pre_finger_data[loop_i][1] * ts->heightFactor >> SHIFTBITS, Last_EN_NoiseFilter); + } else { + I("status:%X, Raw:F:%02d Up, X:%d, Y:%d, N:%d\n",0, loop_i+1, ts->pre_finger_data[loop_i][0],ts->pre_finger_data[loop_i][1], Last_EN_NoiseFilter); + } + } + } + ts->pre_finger_mask = 0; + } + + if (ts->first_pressed == 1) { + ts->first_pressed = 2; + I("E1@%d, %d\n",ts->pre_finger_data[0][0] , ts->pre_finger_data[0][1]); + } + + if (ts->debug_log_level & BIT(1)) + I("All Finger leave\n"); + + } + else if (tpd_key != 0x00) { + himax_ts_button_func(tpd_key,ts); + finger_on = 1; + } + else if ((tpd_key_old != 0x00)&&(tpd_key == 0x00)) { + himax_ts_button_func(tpd_key,ts); + finger_on = 0; + } + input_report_key(ts->input_dev, BTN_TOUCH, finger_on); + input_sync(ts->input_dev); + } + tpd_key_old = tpd_key; + Last_EN_NoiseFilter = EN_NoiseFilter; + +workqueue_out: + return; + +err_workqueue_out: + I("%s: Now reset the Touch chip.\n", __func__); + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + + goto workqueue_out; +} +enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer) +{ + struct himax_ts_data *ts; + + ts = container_of(timer, struct himax_ts_data, timer); + queue_work(ts->himax_wq, &ts->work); + hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL); + return HRTIMER_NORESTART; +} + +#if defined(HX_USB_DETECT) +static void himax_cable_tp_status_handler_func(int connect_status) +{ + struct himax_ts_data *ts; + I("Touch: cable change to %d\n", connect_status); + ts = private_ts; + if (ts->cable_config) { + if (!atomic_read(&ts->suspend_mode)) { + if ((!!connect_status) != ts->usb_connected) { + if (!!connect_status) { + ts->cable_config[1] = 0x01; + ts->usb_connected = 0x01; + } else { + ts->cable_config[1] = 0x00; + ts->usb_connected = 0x00; + } + + i2c_himax_master_write(ts->client, ts->cable_config, + sizeof(ts->cable_config), HIMAX_I2C_RETRY_TIMES); + + I("%s: Cable status change: 0x%2.2X\n", __func__, ts->cable_config[1]); + } else + I("%s: Cable status is the same as previous one, ignore.\n", __func__); + } else { + if (connect_status) + ts->usb_connected = 0x01; + else + ts->usb_connected = 0x00; + I("%s: Cable status remembered: 0x%2.2X\n", __func__, ts->usb_connected); + } + } +} + +static struct t_cable_status_notifier himax_cable_status_handler = { + .name = "usb_tp_connected", + .func = himax_cable_tp_status_handler_func, +}; + +#endif + +#if defined(HX_USB_DETECT2) +void himax_cable_detect_func(void) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + struct himax_ts_data *ts; + u32 connect_status = 0; + + connect_status = USB_Flag;//upmu_is_chr_det(); + ts = private_ts; + //I("Touch: cable status=%d, cable_config=%p, usb_connected=%d \n", connect_status,ts->cable_config, ts->usb_connected); + if (ts->cable_config) { + if ((!!connect_status) != ts->usb_connected) { + //notify USB plug/unplug + // 0x9008_8060 ==> 0x0000_0000/0001 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x60; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; + + if (!!connect_status) { + tmp_data[0] = 0x01; + ts->usb_connected = 0x01; + } else { + tmp_data[0] = 0x00; + ts->usb_connected = 0x00; + } + + himax_flash_write_burst(ts->client, tmp_addr, tmp_data); + + I("%s: Cable status change: 0x%2.2X\n", __func__, ts->usb_connected); + } + //else + //I("%s: Cable status is the same as previous one, ignore.\n", __func__); + } +} +#endif + +#ifdef CONFIG_FB +int himax_fb_register(struct himax_ts_data *ts) +{ + int ret = 0; + + I(" %s in", __func__); + ts->fb_notif.notifier_call = fb_notifier_callback; + ret = fb_register_client(&ts->fb_notif); + if (ret) + E(" Unable to register fb_notifier: %d\n", ret); + + return ret; +} +#endif + +#ifdef HX_SMART_WAKEUP +void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable) +{ + uint8_t tmp_data[4]; + + if(SMWP_enable) + { + SMWP_bit_retry: + himax_set_SMWP_enable(client, SMWP_enable); + msleep(20); + himax_get_SMWP_enable(client,tmp_data); + I("%s: Read SMWP bit data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + if(tmp_data[0]!= 0x01) + { + I("%s: retry SMWP bit write data[0]=%x \n",__func__,tmp_data[0]); + goto SMWP_bit_retry; + } + } +} + +static void himax_SMWP_work(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, + smwp_work.work); + I(" %s in", __func__); + + himax_set_SMWP_func(ts->client,ts->SMWP_enable); + +} +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP +static void himax_ts_flash_work_func(struct work_struct *work) +{ + himax_ts_flash_func(); +} +#endif + +#ifdef HX_TP_PROC_DIAG +static void himax_ts_diag_work_func(struct work_struct *work) +{ + himax_ts_diag_func(); +} +#endif + +void himax_ts_init(struct himax_ts_data *ts) +{ + int ret = 0, err = 0; + struct himax_i2c_platform_data *pdata; + struct i2c_client *client; + + client = ts->client; + pdata = ts->pdata; + + I("%s: Start.\n", __func__); + + /* Set pinctrl in active state */ + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (ret < 0) { + E("Failed to set pin in active state %d",ret); + } + } + + himax_burst_enable(client, 0); + + //Get Himax IC Type / FW information / Calculate the point number + if (himax_check_chip_version(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + if (himax_ic_package_check(ts->client) == false) { + E("Himax chip doesn NOT EXIST"); + goto err_ic_package_failed; + } + + if (pdata->virtual_key) + ts->button = pdata->virtual_key; +#ifdef HX_TP_PROC_FLASH_DUMP + ts->flash_wq = create_singlethread_workqueue("himax_flash_wq"); + if (!ts->flash_wq) + { + E("%s: create flash workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + + INIT_WORK(&ts->flash_work, himax_ts_flash_work_func); + + setSysOperation(0); + setFlashBuffer(); +#endif + +#ifdef HX_TP_PROC_DIAG + ts->himax_diag_wq = create_singlethread_workqueue("himax_diag"); + if (!ts->himax_diag_wq) + { + E("%s: create diag workqueue failed\n", __func__); + err = -ENOMEM; + goto err_create_wq_failed; + } + INIT_DELAYED_WORK(&ts->himax_diag_delay_wrok, himax_ts_diag_work_func); +#endif + +himax_read_FW_ver(client); + +#ifdef HX_AUTO_UPDATE_FW + I(" %s in", __func__); + if(i_update_FW() == false) + I("NOT Have new FW=NOT UPDATE=\n"); + else + I("Have new FW=UPDATE=\n"); +#endif + + //Himax Power On and Load Config + if (himax_loadSensorConfig(client, pdata) < 0) { + E("%s: Load Sesnsor configuration failed, unload driver.\n", __func__); + goto err_detect_failed; + } + + calculate_point_number(); +#ifdef HX_TP_PROC_DIAG + setXChannel(ic_data->HX_RX_NUM); // X channel + setYChannel(ic_data->HX_TX_NUM); // Y channel + + setMutualBuffer(); + setMutualNewBuffer(); + setMutualOldBuffer(); + if (getMutualBuffer() == NULL) { + E("%s: mutual buffer allocate fail failed\n", __func__); + return; + } +#ifdef HX_TP_PROC_2T2R + if(Is_2T2R){ + setXChannel_2(ic_data->HX_RX_NUM_2); // X channel + setYChannel_2(ic_data->HX_TX_NUM_2); // Y channel + + setMutualBuffer_2(); + + if (getMutualBuffer_2() == NULL) { + E("%s: mutual buffer 2 allocate fail failed\n", __func__); + return; + } + } +#endif +#endif +#ifdef CONFIG_OF + ts->power = pdata->power; +#endif + ts->pdata = pdata; + + ts->x_channel = ic_data->HX_RX_NUM; + ts->y_channel = ic_data->HX_TX_NUM; + ts->nFinger_support = ic_data->HX_MAX_PT; + //calculate the i2c data size + calcDataSize(ts->nFinger_support); + I("%s: calcDataSize complete\n", __func__); +#ifdef CONFIG_OF + ts->pdata->abs_pressure_min = 0; + ts->pdata->abs_pressure_max = 200; + ts->pdata->abs_width_min = 0; + ts->pdata->abs_width_max = 200; + pdata->cable_config[0] = 0x90; + pdata->cable_config[1] = 0x00; +#endif + ts->suspended = false; +#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + ts->cable_config = pdata->cable_config; +#endif + ts->protocol_type = pdata->protocol_type; + I("%s: Use Protocol Type %c\n", __func__, + ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B'); + + ret = himax_input_register(ts); + if (ret) { + E("%s: Unable to register %s input device\n", + __func__, ts->input_dev->name); + goto err_input_register_device_failed; + } +#ifdef HX_SMART_WAKEUP + ts->SMWP_enable=0; + wake_lock_init(&ts->ts_SMWP_wake_lock, WAKE_LOCK_SUSPEND, HIMAX_common_NAME); + + ts->himax_smwp_wq = create_singlethread_workqueue("HMX_SMWP_WORK"); + if (!ts->himax_smwp_wq) { + E(" allocate himax_smwp_wq failed\n"); + err = -ENOMEM; + goto err_smwp_wq_failed; + } + INIT_DELAYED_WORK(&ts->smwp_work, himax_SMWP_work); +#endif +#ifdef HX_HIGH_SENSE + ts->HSEN_enable=0; + ts->himax_hsen_wq = create_singlethread_workqueue("HMX_HSEN_WORK"); + if (!ts->himax_hsen_wq) { + E(" allocate himax_hsen_wq failed\n"); + err = -ENOMEM; + goto err_hsen_wq_failed; + } + INIT_DELAYED_WORK(&ts->hsen_work, himax_HSEN_func); +#endif + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_init(); +#endif + +#if defined(HX_USB_DETECT) + if (ts->cable_config) + cable_detect_register_notifier(&himax_cable_status_handler); +#endif + + err = himax_ts_register_interrupt(ts->client); + if (err) + goto err_register_interrupt_failed; + return; + +err_register_interrupt_failed: +#ifdef HX_HIGH_SENSE +err_hsen_wq_failed: +#endif +#ifdef HX_SMART_WAKEUP +err_smwp_wq_failed: + wake_lock_destroy(&ts->ts_SMWP_wake_lock); +#endif +err_input_register_device_failed: + input_free_device(ts->input_dev); +err_detect_failed: +#ifdef HX_TP_PROC_FLASH_DUMP +err_create_wq_failed: +#endif +err_ic_package_failed: + +return; +} + +int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + int err = 0; + struct himax_ts_data *ts; + struct himax_i2c_platform_data *pdata; + + //Check I2C functionality + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + E("%s: i2c check functionality error\n", __func__); + err = -ENODEV; + goto err_check_functionality_failed; + } + + ts = kzalloc(sizeof(struct himax_ts_data), GFP_KERNEL); + if (ts == NULL) { + E("%s: allocate himax_ts_data failed\n", __func__); + err = -ENOMEM; + goto err_alloc_data_failed; + } + + i2c_set_clientdata(client, ts); + ts->client = client; + ts->dev = &client->dev; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (pdata == NULL) { /*Allocate Platform data space*/ + err = -ENOMEM; + goto err_dt_platform_data_fail; + } + + ic_data = kzalloc(sizeof(*ic_data), GFP_KERNEL); + if (ic_data == NULL) { /*Allocate IC data space*/ + err = -ENOMEM; + goto err_dt_ic_data_fail; + } + +#ifdef CONFIG_OF + if (client->dev.of_node) { /*DeviceTree Init Platform_data*/ + err = himax_parse_dt(ts, pdata); + if (err < 0) { + I(" pdata is NULL for DT\n"); + goto err_alloc_dt_pdata_failed; + } + } +#endif + +#ifdef HX_RST_PIN_FUNC + ts->rst_gpio = pdata->gpio_reset; +#endif + +himax_gpio_power_config(ts->client, pdata); + + err = himax_ts_pinctrl_init(ts); + if (err || ts->ts_pinctrl == NULL) { + E(" Pinctrl init failed\n"); + } + +#ifndef CONFIG_OF + if (pdata->power) { + err = pdata->power(1); + if (err < 0) { + E("%s: power on failed\n", __func__); + goto err_power_failed; + } + } +#endif + ts->pdata = pdata; + private_ts = ts; + + mutex_init(&ts->fb_mutex); + /* ts initialization is deferred till FB_UNBLACK event; + * probe is considered pending till then.*/ + ts->probe_done = false; +#ifdef CONFIG_FB + err = himax_fb_register(ts); + if (err) { + E("Falied to register fb notifier\n"); + err = -ENOMEM; + goto err_fb_notif_wq_create; + } +#endif + + return 0; + +#ifdef CONFIG_FB +err_fb_notif_wq_create: +#endif +#ifdef CONFIG_OF +err_alloc_dt_pdata_failed: +#else +err_power_failed: +err_get_platform_data_fail: +#endif + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + err = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (err) + E("failed to select relase pinctrl state %d\n", + err); + } + } + kfree(ic_data); + +err_dt_ic_data_fail: + kfree(pdata); + +err_dt_platform_data_fail: + kfree(ts); + +err_alloc_data_failed: + +err_check_functionality_failed: + probe_fail_flag = 1; + return err; + +} + +int himax_chip_common_remove(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret; +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + himax_touch_proc_deinit(); +#endif +#ifdef CONFIG_FB + if (fb_unregister_client(&ts->fb_notif)) + dev_err(&client->dev, "Error occurred while unregistering fb_notifier.\n"); +#endif + + if (!ts->use_irq) + hrtimer_cancel(&ts->timer); + + destroy_workqueue(ts->himax_wq); + + if (ts->protocol_type == PROTOCOL_TYPE_B) + input_mt_destroy_slots(ts->input_dev); + + input_unregister_device(ts->input_dev); + + if (ts->ts_pinctrl) { + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + devm_pinctrl_put(ts->ts_pinctrl); + ts->ts_pinctrl = NULL; + } else { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_release); + if (ret) + E("failed to select relase pinctrl state %d\n", + ret); + } + } +#ifdef HX_SMART_WAKEUP + wake_lock_destroy(&ts->ts_SMWP_wake_lock); +#endif + kfree(ts); + + return 0; + +} + +int himax_chip_common_suspend(struct himax_ts_data *ts) +{ + int ret; + + if(ts->suspended) + { + I("%s: Already suspended. Skipped. \n", __func__); + return 0; + } + else + { + ts->suspended = true; + I("%s: enter \n", __func__); + } + +#ifdef HX_TP_PROC_FLASH_DUMP + if (getFlashDumpGoing()) + { + I("[himax] %s: Flash dump is going, reject suspend\n",__func__); + return 0; + } +#endif +#ifdef HX_TP_PROC_HITOUCH + if(hitouch_is_connect) + { + I("[himax] %s: Hitouch connect, reject suspend\n",__func__); + return 0; + } +#endif +#ifdef HX_SMART_WAKEUP + if(ts->SMWP_enable) + { + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + FAKE_POWER_KEY_SEND=false; + I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",__func__); + return 0; + } +#endif +#ifdef HX_ESD_WORKAROUND + ESD_00_counter = 0; + ESD_00_Flag = 0; +#endif + if (!ts->use_irq) { + ret = cancel_work_sync(&ts->work); + if (ret) + himax_int_enable(ts->client->irq,1); + } + + //ts->first_pressed = 0; + atomic_set(&ts->suspend_mode, 1); + ts->pre_finger_mask = 0; + + if (ts->ts_pinctrl) { + ret = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_suspend); + if (ret < 0) { + E("Failed to get idle pinctrl state %d\n", ret); + } + } + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + + return 0; +} + +int himax_chip_common_resume(struct himax_ts_data *ts) +{ + int retval; + + I("%s: enter \n", __func__); + + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(1); + + + /*************************************/ + if (ts->protocol_type == PROTOCOL_TYPE_A) + input_mt_sync(ts->input_dev); + input_report_key(ts->input_dev, BTN_TOUCH, 0); + input_sync(ts->input_dev); + /*************************************/ + + + if (ts->ts_pinctrl) { + retval = pinctrl_select_state(ts->ts_pinctrl, + ts->pinctrl_state_active); + if (retval < 0) { + E("Cannot get default pinctrl state %d\n", retval); + goto err_pinctrl_select_resume; + } + } + + atomic_set(&ts->suspend_mode, 0); + + himax_int_enable(ts->client->irq,1); + + ts->suspended = false; +#if defined(HX_USB_DETECT2) + ts->usb_connected = 0x00; + himax_cable_detect_func(); +#endif +#ifdef HX_SMART_WAKEUP + queue_delayed_work(ts->himax_smwp_wq, &ts->smwp_work, msecs_to_jiffies(1000)); +#endif +#ifdef HX_HIGH_SENSE + queue_delayed_work(ts->himax_hsen_wq, &ts->hsen_work, msecs_to_jiffies(1000)); +#endif + return 0; +err_pinctrl_select_resume: + if (ts->pdata->powerOff3V3 && ts->pdata->power) + ts->pdata->power(0); + return retval; +} + diff --git a/drivers/input/touchscreen/hxchipset/himax_common.h b/drivers/input/touchscreen/hxchipset/himax_common.h new file mode 100644 index 000000000000..27ce9aafd959 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_common.h @@ -0,0 +1,395 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_COMMON_H +#define HIMAX_COMMON_H + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "himax_platform.h" + +#if defined(CONFIG_FB) +#include +#include +#elif defined(CONFIG_HAS_EARLYSUSPEND) +#include +#endif + +#ifdef CONFIG_OF +#include +#endif +#define HIMAX_DRIVER_VER "0.2.4.0" + +#define FLASH_DUMP_FILE "/data/user/Flash_Dump.bin" +#define DIAG_COORDINATE_FILE "/sdcard/Coordinate_Dump.csv" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +#define HX_TP_PROC_DIAG +#define HX_TP_PROC_REGISTER +#define HX_TP_PROC_DEBUG +#define HX_TP_PROC_FLASH_DUMP +#define HX_TP_PROC_SELF_TEST +#define HX_TP_PROC_RESET +#define HX_TP_PROC_SENSE_ON_OFF +//#define HX_TP_PROC_2T2R + +int himax_touch_proc_init(void); +void himax_touch_proc_deinit(void); +#endif + +//===========Himax Option function============= +//#define HX_RST_PIN_FUNC +//#define HX_AUTO_UPDATE_FW +//#define HX_HIGH_SENSE +//#define HX_SMART_WAKEUP +//#define HX_USB_DETECT +//#define HX_ESD_WORKAROUND +//#define HX_USB_DETECT2 + +//#define HX_EN_SEL_BUTTON // Support Self Virtual key ,default is close +#define HX_EN_MUT_BUTTON // Support Mutual Virtual Key ,default is close + +#define HX_KEY_MAX_COUNT 4 +#define DEFAULT_RETRY_CNT 3 + +#define HX_VKEY_0 KEY_BACK +#define HX_VKEY_1 KEY_HOME +#define HX_VKEY_2 KEY_RESERVED +#define HX_VKEY_3 KEY_RESERVED +#define HX_KEY_ARRAY {HX_VKEY_0, HX_VKEY_1, HX_VKEY_2, HX_VKEY_3} + +#define SHIFTBITS 5 +//#define FLASH_SIZE 131072 +#define FW_SIZE_60k 61440 +#define FW_SIZE_64k 65536 +#define FW_SIZE_124k 126976 +#define FW_SIZE_128k 131072 + +struct himax_ic_data { + int vendor_fw_ver; + int vendor_config_ver; + int vendor_sensor_id; + int HX_RX_NUM; + int HX_TX_NUM; + int HX_BT_NUM; + int HX_X_RES; + int HX_Y_RES; + int HX_MAX_PT; + bool HX_XY_REVERSE; + bool HX_INT_IS_EDGE; +#ifdef HX_TP_PROC_2T2R + int HX_RX_NUM_2; + int HX_TX_NUM_2; +#endif +}; + +struct himax_virtual_key { + int index; + int keycode; + int x_range_min; + int x_range_max; + int y_range_min; + int y_range_max; +}; + +struct himax_config { + uint8_t default_cfg; + uint8_t sensor_id; + uint8_t fw_ver; + uint16_t length; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + uint8_t c1[11]; + uint8_t c2[11]; + uint8_t c3[11]; + uint8_t c4[11]; + uint8_t c5[11]; + uint8_t c6[11]; + uint8_t c7[11]; + uint8_t c8[11]; + uint8_t c9[11]; + uint8_t c10[11]; + uint8_t c11[11]; + uint8_t c12[11]; + uint8_t c13[11]; + uint8_t c14[11]; + uint8_t c15[11]; + uint8_t c16[11]; + uint8_t c17[11]; + uint8_t c18[17]; + uint8_t c19[15]; + uint8_t c20[5]; + uint8_t c21[11]; + uint8_t c22[4]; + uint8_t c23[3]; + uint8_t c24[3]; + uint8_t c25[4]; + uint8_t c26[2]; + uint8_t c27[2]; + uint8_t c28[2]; + uint8_t c29[2]; + uint8_t c30[2]; + uint8_t c31[2]; + uint8_t c32[2]; + uint8_t c33[2]; + uint8_t c34[2]; + uint8_t c35[3]; + uint8_t c36[5]; + uint8_t c37[5]; + uint8_t c38[9]; + uint8_t c39[14]; + uint8_t c40[159]; + uint8_t c41[99]; +}; + +struct himax_ts_data { + bool suspended; + bool probe_done; + struct mutex fb_mutex; + atomic_t suspend_mode; + uint8_t x_channel; + uint8_t y_channel; + uint8_t useScreenRes; + uint8_t diag_command; + + uint8_t protocol_type; + uint8_t first_pressed; + uint8_t coord_data_size; + uint8_t area_data_size; + uint8_t raw_data_frame_size; + uint8_t raw_data_nframes; + uint8_t nFinger_support; + uint8_t irq_enabled; + uint8_t diag_self[50]; + + uint16_t finger_pressed; + uint16_t last_slot; + uint16_t pre_finger_mask; + + uint32_t debug_log_level; + uint32_t widthFactor; + uint32_t heightFactor; + uint32_t tw_x_min; + uint32_t tw_x_max; + uint32_t tw_y_min; + uint32_t tw_y_max; + uint32_t pl_x_min; + uint32_t pl_x_max; + uint32_t pl_y_min; + uint32_t pl_y_max; + + int use_irq; + int (*power)(int on); + int pre_finger_data[10][2]; + + struct device *dev; + struct workqueue_struct *himax_wq; + struct work_struct work; + struct input_dev *input_dev; + struct hrtimer timer; + struct i2c_client *client; + struct himax_i2c_platform_data *pdata; + struct himax_virtual_key *button; + +#if defined(CONFIG_FB) + struct notifier_block fb_notif; +#elif defined(CONFIG_HAS_EARLYSUSPEND) + struct early_suspend early_suspend; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + struct workqueue_struct *flash_wq; + struct work_struct flash_work; +#endif + +#ifdef HX_RST_PIN_FUNC + int rst_gpio; +#endif + +#ifdef HX_TP_PROC_DIAG + struct workqueue_struct *himax_diag_wq; + struct delayed_work himax_diag_delay_wrok; +#endif +#ifdef HX_SMART_WAKEUP + uint8_t SMWP_enable; + uint8_t gesture_cust_en[16]; + struct wake_lock ts_SMWP_wake_lock; + struct workqueue_struct *himax_smwp_wq; + struct delayed_work smwp_work; +#endif + +#ifdef HX_HIGH_SENSE + uint8_t HSEN_enable; + struct workqueue_struct *himax_hsen_wq; + struct delayed_work hsen_work; +#endif + +#if defined(HX_USB_DETECT)||defined(HX_USB_DETECT2) + uint8_t usb_connected; + uint8_t *cable_config; +#endif + + /* pinctrl data */ + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + struct pinctrl_state *pinctrl_state_release; +}; + +#define HX_CMD_NOP 0x00 +#define HX_CMD_SETMICROOFF 0x35 +#define HX_CMD_SETROMRDY 0x36 +#define HX_CMD_TSSLPIN 0x80 +#define HX_CMD_TSSLPOUT 0x81 +#define HX_CMD_TSSOFF 0x82 +#define HX_CMD_TSSON 0x83 +#define HX_CMD_ROE 0x85 +#define HX_CMD_RAE 0x86 +#define HX_CMD_RLE 0x87 +#define HX_CMD_CLRES 0x88 +#define HX_CMD_TSSWRESET 0x9E +#define HX_CMD_SETDEEPSTB 0xD7 +#define HX_CMD_SET_CACHE_FUN 0xDD +#define HX_CMD_SETIDLE 0xF2 +#define HX_CMD_SETIDLEDELAY 0xF3 +#define HX_CMD_SELFTEST_BUFFER 0x8D +#define HX_CMD_MANUALMODE 0x42 +#define HX_CMD_FLASH_ENABLE 0x43 +#define HX_CMD_FLASH_SET_ADDRESS 0x44 +#define HX_CMD_FLASH_WRITE_REGISTER 0x45 +#define HX_CMD_FLASH_SET_COMMAND 0x47 +#define HX_CMD_FLASH_WRITE_BUFFER 0x48 +#define HX_CMD_FLASH_PAGE_ERASE 0x4D +#define HX_CMD_FLASH_SECTOR_ERASE 0x4E +#define HX_CMD_CB 0xCB +#define HX_CMD_EA 0xEA +#define HX_CMD_4A 0x4A +#define HX_CMD_4F 0x4F +#define HX_CMD_B9 0xB9 +#define HX_CMD_76 0x76 + +enum input_protocol_type { + PROTOCOL_TYPE_A = 0x00, + PROTOCOL_TYPE_B = 0x01, +}; + +#ifdef HX_HIGH_SENSE +void himax_set_HSEN_func(struct i2c_client *client,uint8_t HSEN_enable); +#endif + +#ifdef HX_SMART_WAKEUP +#define GEST_PTLG_ID_LEN (4) +#define GEST_PTLG_HDR_LEN (4) +#define GEST_PTLG_HDR_ID1 (0xCC) +#define GEST_PTLG_HDR_ID2 (0x44) +#define GEST_PT_MAX_NUM (128) + +#ifdef HX_GESTURE_TRACK +static int gest_pt_cnt; +static int gest_pt_x[GEST_PT_MAX_NUM]; +static int gest_pt_y[GEST_PT_MAX_NUM]; +static int gest_start_x,gest_start_y,gest_end_x,gest_end_y; +static int gest_width,gest_height,gest_mid_x,gest_mid_y; +static int gn_gesture_coor[16]; +#endif + +void himax_set_SMWP_func(struct i2c_client *client,uint8_t SMWP_enable); +extern bool FAKE_POWER_KEY_SEND; + + enum gesture_event_type { + EV_GESTURE_01 = 0x01, + EV_GESTURE_02, + EV_GESTURE_03, + EV_GESTURE_04, + EV_GESTURE_05, + EV_GESTURE_06, + EV_GESTURE_07, + EV_GESTURE_08, + EV_GESTURE_09, + EV_GESTURE_10, + EV_GESTURE_11, + EV_GESTURE_12, + EV_GESTURE_13, + EV_GESTURE_14, + EV_GESTURE_15, + EV_GESTURE_PWR = 0x80, + }; + +#define KEY_CUST_01 251 +#define KEY_CUST_02 252 +#define KEY_CUST_03 253 +#define KEY_CUST_04 254 +#define KEY_CUST_05 255 +#define KEY_CUST_06 256 +#define KEY_CUST_07 257 +#define KEY_CUST_08 258 +#define KEY_CUST_09 259 +#define KEY_CUST_10 260 +#define KEY_CUST_11 261 +#define KEY_CUST_12 262 +#define KEY_CUST_13 263 +#define KEY_CUST_14 264 +#define KEY_CUST_15 265 +#endif + +#ifdef HX_ESD_WORKAROUND + extern u8 HX_ESD_RESET_ACTIVATE; +#endif + +extern int irq_enable_count; + +#ifdef QCT +irqreturn_t himax_ts_thread(int irq, void *ptr); +int himax_input_register(struct himax_ts_data *ts); +#endif + +extern int himax_chip_common_probe(struct i2c_client *client, const struct i2c_device_id *id); +extern int himax_chip_common_remove(struct i2c_client *client); +extern int himax_chip_common_suspend(struct himax_ts_data *ts); +extern int himax_chip_common_resume(struct himax_ts_data *ts); +int himax_loadSensorConfig(struct i2c_client *client, struct himax_i2c_platform_data *pdata); + +#ifdef HX_USB_DETECT2 +//extern kal_bool upmu_is_chr_det(void); +void himax_cable_detect_func(void); +#endif + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.c b/drivers/input/touchscreen/hxchipset/himax_debug.c new file mode 100644 index 000000000000..f8bee11b4351 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.c @@ -0,0 +1,2329 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_debug.h" +#include "himax_ic.h" + +//struct himax_debug_data* debug_data; + +extern struct himax_ic_data* ic_data; +extern struct himax_ts_data *private_ts; +extern unsigned char IC_TYPE; +extern unsigned char IC_CHECKSUM; +extern int himax_input_register(struct himax_ts_data *ts); +#ifdef QCT +extern irqreturn_t himax_ts_thread(int irq, void *ptr); +#endif +#ifdef MTK +#ifdef CONFIG_OF_TOUCH +extern irqreturn_t tpd_eint_interrupt_handler(int irq, void *desc); +#else +extern void tpd_eint_interrupt_handler(void); +#endif +#endif + +#ifdef HX_TP_PROC_DIAG +#ifdef HX_TP_PROC_2T2R +int HX_RX_NUM_2 = 0; +int HX_TX_NUM_2 = 0; +#endif +int touch_monitor_stop_flag = 0; +int touch_monitor_stop_limit = 5; +uint8_t g_diag_arr_num = 0; +#endif + +#ifdef HX_ESD_WORKAROUND +u8 HX_ESD_RESET_ACTIVATE; +#endif + +#ifdef HX_SMART_WAKEUP +bool FAKE_POWER_KEY_SEND; +#endif + +//============================================================================================================= +// +// Segment : Himax PROC Debug Function +// +//============================================================================================================= +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + +static ssize_t himax_vendor_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + + ret += snprintf(temp_buf, len, "%s_FW:%#x_CFG:%#x_SensorId:%#x\n", HIMAX_common_NAME, + ic_data->vendor_fw_ver, ic_data->vendor_config_ver, ic_data->vendor_sensor_id); + HX_PROC_SEND_FLAG=1; + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static const struct file_operations himax_proc_vendor_ops = +{ + .owner = THIS_MODULE, + .read = himax_vendor_read, +}; + +static ssize_t himax_attn_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + ssize_t ret = 0; + struct himax_ts_data *ts_data; + char *temp_buf; + + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "attn = %x\n", himax_int_gpio_read(ts_data->pdata->gpio_irq)); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + + +static const struct file_operations himax_proc_attn_ops = +{ + .owner = THIS_MODULE, + .read = himax_attn_read, +}; + +static ssize_t himax_int_en_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "%d ", ts->irq_enabled); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_int_en_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[12]= {0}; + int value, ret=0; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + + if (buf_tmp[0] == '0') + value = false; + else if (buf_tmp[0] == '1') + value = true; + else + return -EINVAL; + + if (value) { + if(ic_data->HX_INT_IS_EDGE) + { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq,1); +#else + //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); + //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); + mt_eint_registration(ts->client->irq, EINTF_TRIGGER_FALLING, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, ts->client->name, ts); +#endif + } + else + { +#ifdef MTK +#ifdef CONFIG_OF_TOUCH + himax_int_enable(ts->client->irq,1); +#else + //mt_eint_set_sens(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_TYPE); + //mt_eint_set_hw_debounce(CUST_EINT_TOUCH_PANEL_NUM, CUST_EINT_TOUCH_PANEL_DEBOUNCE_CN); + mt_eint_registration(ts->client->irq, EINTF_TRIGGER_LOW, tpd_eint_interrupt_handler, 1); +#endif +#endif +#ifdef QCT + ret = request_threaded_irq(ts->client->irq, NULL, himax_ts_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, ts->client->name, ts); +#endif + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + } + } else { + himax_int_enable(ts->client->irq,0); + free_irq(ts->client->irq, ts); + ts->irq_enabled = 0; + } + + return len; +} + +static const struct file_operations himax_proc_int_en_ops = +{ + .owner = THIS_MODULE, + .read = himax_int_en_read, + .write = himax_int_en_write, +}; + +static ssize_t himax_layout_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t ret = 0; + char *temp_buf; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "%d ", ts->pdata->abs_x_min); + ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_x_max); + ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_min); + ret += snprintf(temp_buf+ret, len-ret, "%d ", ts->pdata->abs_y_max); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_layout_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf_tmp[5]; + int i = 0, j = 0, k = 0, ret; + unsigned long value; + int layout[4] = {0}; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + for (i = 0; i < 20; i++) { + if (buf[i] == ',' || buf[i] == '\n') { + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + if (i - j <= 5) + memcpy(buf_tmp, buf + j, i - j); + else { + I("buffer size is over 5 char\n"); + return len; + } + j = i + 1; + if (k < 4) { + ret = kstrtoul(buf_tmp, 10, &value); + layout[k++] = value; + } + } + } + if (k == 4) { + ts->pdata->abs_x_min=layout[0]; + ts->pdata->abs_x_max=layout[1]; + ts->pdata->abs_y_min=layout[2]; + ts->pdata->abs_y_max=layout[3]; + I("%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + input_unregister_device(ts->input_dev); + himax_input_register(ts); + } else + I("ERR@%d, %d, %d, %d\n",ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min, ts->pdata->abs_y_max); + return len; +} + +static const struct file_operations himax_proc_layout_ops = +{ + .owner = THIS_MODULE, + .read = himax_layout_read, + .write = himax_layout_write, +}; + +static ssize_t himax_debug_level_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts_data; + size_t ret = 0; + char *temp_buf; + ts_data = private_ts; + + if (!HX_PROC_SEND_FLAG) { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + ret += snprintf(temp_buf, len, "%d\n", ts_data->debug_log_level); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + + return ret; +} + +static ssize_t himax_debug_level_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts; + char buf_tmp[11]; + int i; + ts = private_ts; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + + ts->debug_log_level = 0; + for(i=0; i='0' && buf_tmp[i]<='9' ) + ts->debug_log_level |= (buf_tmp[i]-'0'); + else if( buf_tmp[i]>='A' && buf_tmp[i]<='F' ) + ts->debug_log_level |= (buf_tmp[i]-'A'+10); + else if( buf_tmp[i]>='a' && buf_tmp[i]<='f' ) + ts->debug_log_level |= (buf_tmp[i]-'a'+10); + + if(i!=len-2) + ts->debug_log_level <<= 4; + } + + if (ts->debug_log_level & BIT(3)) { + if (ts->pdata->screenWidth > 0 && ts->pdata->screenHeight > 0 && + (ts->pdata->abs_x_max - ts->pdata->abs_x_min) > 0 && + (ts->pdata->abs_y_max - ts->pdata->abs_y_min) > 0) { + ts->widthFactor = (ts->pdata->screenWidth << SHIFTBITS)/(ts->pdata->abs_x_max - ts->pdata->abs_x_min); + ts->heightFactor = (ts->pdata->screenHeight << SHIFTBITS)/(ts->pdata->abs_y_max - ts->pdata->abs_y_min); + if (ts->widthFactor > 0 && ts->heightFactor > 0) + ts->useScreenRes = 1; + else { + ts->heightFactor = 0; + ts->widthFactor = 0; + ts->useScreenRes = 0; + } + } else + I("Enable finger debug with raw position mode!\n"); + } else { + ts->useScreenRes = 0; + ts->widthFactor = 0; + ts->heightFactor = 0; + } + + return len; +} + +static const struct file_operations himax_proc_debug_level_ops = +{ + .owner = THIS_MODULE, + .read = himax_debug_level_read, + .write = himax_debug_level_write, +}; + +#ifdef HX_TP_PROC_REGISTER +static ssize_t himax_proc_register_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + uint16_t loop_i; + uint8_t data[128]; + char *temp_buf; + + memset(data, 0x00, sizeof(data)); + + I("himax_register_show: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + himax_register_read(private_ts->client, register_command, 1, data); + + ret += snprintf(temp_buf, len, "command: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + + for (loop_i = 0; loop_i < 128; loop_i++) { + ret += snprintf(temp_buf+ret, len-ret, "0x%2.2X ", data[loop_i]); + if ((loop_i % 16) == 15) + ret += snprintf(temp_buf+ret, len-ret, "\n"); + } + ret += snprintf(temp_buf+ret, len-ret, "\n"); + HX_PROC_SEND_FLAG=1; + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_proc_register_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[16], length = 0; + unsigned long result = 0; + uint8_t loop_i = 0; + uint16_t base = 5; + uint8_t write_da[128]; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memset(write_da, 0x0, sizeof(write_da)); + + I("himax %s \n",buf); + + if ((buf[0] == 'r' || buf[0] == 'w') && buf[1] == ':') { + + if (buf[2] == 'x') { + memcpy(buf_tmp, buf + 3, 8); + if (!kstrtoul(buf_tmp, 16, &result)) + { + register_command[0] = (uint8_t)result; + register_command[1] = (uint8_t)(result >> 8); + register_command[2] = (uint8_t)(result >> 16); + register_command[3] = (uint8_t)(result >> 24); + } + base = 11; + I("CMD: %x,%x,%x,%x\n", register_command[0],register_command[1],register_command[2],register_command[3]); + + for (loop_i = 0; loop_i < 128 && (base+10)<80; loop_i++) { + if (buf[base] == '\n') { + if (buf[0] == 'w') { + himax_register_write(private_ts->client, register_command, 1, write_da); + I("CMD: %x, %x, %x, %x, len=%d\n", write_da[0], write_da[1],write_da[2],write_da[3],length); + } + I("\n"); + return len; + } + if (buf[base + 1] == 'x') { + buf_tmp[10] = '\n'; + buf_tmp[11] = '\0'; + memcpy(buf_tmp, buf + base + 2, 8); + if (!kstrtoul(buf_tmp, 16, &result)) { + write_da[loop_i] = (uint8_t)result; + write_da[loop_i+1] = (uint8_t)(result >> 8); + write_da[loop_i+2] = (uint8_t)(result >> 16); + write_da[loop_i+3] = (uint8_t)(result >> 24); + } + length+=4; + } + base += 10; + } + } + } + return len; +} + +static const struct file_operations himax_proc_register_ops = +{ + .owner = THIS_MODULE, + .read = himax_proc_register_read, + .write = himax_proc_register_write, +}; +#endif + +#ifdef HX_TP_PROC_DIAG +int16_t *getMutualBuffer(void) +{ + return diag_mutual; +} +int16_t *getMutualNewBuffer(void) +{ + return diag_mutual_new; +} +int16_t *getMutualOldBuffer(void) +{ + return diag_mutual_old; +} +int16_t *getSelfBuffer(void) +{ + return &diag_self[0]; +} +uint8_t getXChannel(void) +{ + return x_channel; +} +uint8_t getYChannel(void) +{ + return y_channel; +} +uint8_t getDiagCommand(void) +{ + return diag_command; +} +void setXChannel(uint8_t x) +{ + x_channel = x; +} +void setYChannel(uint8_t y) +{ + y_channel = y; +} +void setMutualBuffer(void) +{ + diag_mutual = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualNewBuffer(void) +{ + diag_mutual_new = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} +void setMutualOldBuffer(void) +{ + diag_mutual_old = kzalloc(x_channel * y_channel * sizeof(int16_t), GFP_KERNEL); +} + +#ifdef HX_TP_PROC_2T2R +int16_t *getMutualBuffer_2(void) +{ + return diag_mutual_2; +} +uint8_t getXChannel_2(void) +{ + return x_channel_2; +} +uint8_t getYChannel_2(void) +{ + return y_channel_2; +} +void setXChannel_2(uint8_t x) +{ + x_channel_2 = x; +} +void setYChannel_2(uint8_t y) +{ + y_channel_2 = y; +} +void setMutualBuffer_2(void) +{ + diag_mutual_2 = kzalloc(x_channel_2 * y_channel_2 * sizeof(int16_t), GFP_KERNEL); +} +#endif + +static ssize_t himax_diag_arrange_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + //struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + g_diag_arr_num = buf[0] - '0'; + I("%s: g_diag_arr_num = %d \n", __func__,g_diag_arr_num); + + return len; +} + +static const struct file_operations himax_proc_diag_arrange_ops = +{ + .owner = THIS_MODULE, + .write = himax_diag_arrange_write, +}; + +static void himax_diag_arrange_print(struct seq_file *s, int i, int j, int transpose) +{ + if(transpose) + seq_printf(s, "%6d", diag_mutual[ j + i*x_channel]); + else + seq_printf(s, "%6d", diag_mutual[ i + j*x_channel]); +} + +static void himax_diag_arrange_inloop(struct seq_file *s, int in_init,bool transpose, int j) +{ + int i; + int in_max = 0; + + if(transpose) + in_max = y_channel; + else + in_max = x_channel; + + if (in_init > 0) + { + for(i = in_init-1;i >= 0;i--) + { + himax_diag_arrange_print(s, i, j, transpose); + } + } + else + { + for (i = 0; i < in_max; i++) + { + himax_diag_arrange_print(s, i, j, transpose); + } + } +} + +static void himax_diag_arrange_outloop(struct seq_file *s, int transpose, int out_init, int in_init) +{ + int j; + int out_max = 0; + + if(transpose) + out_max = x_channel; + else + out_max = y_channel; + + if(out_init > 0) + { + for(j = out_init-1;j >= 0;j--) + { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } + else + { + for(j = 0;j < out_max;j++) + { + himax_diag_arrange_inloop(s, in_init, transpose, j); + seq_printf(s, " %5d\n", diag_self[j]); + } + } +} + +static void himax_diag_arrange(struct seq_file *s) +{ + int bit2,bit1,bit0; + int i; + + bit2 = g_diag_arr_num >> 2; + bit1 = g_diag_arr_num >> 1 & 0x1; + bit0 = g_diag_arr_num & 0x1; + + if (g_diag_arr_num < 4) + { + himax_diag_arrange_outloop(s, bit2, bit1 * y_channel, bit0 * x_channel); + for (i = y_channel; i < x_channel + y_channel; i++) { + seq_printf(s, "%6d", diag_self[i]); + } + } + else + { + himax_diag_arrange_outloop(s, bit2, bit1 * x_channel, bit0 * y_channel); + for (i = x_channel; i < x_channel + y_channel; i++) { + seq_printf(s, "%6d", diag_self[i]); + } + } +} + +static void *himax_diag_seq_start(struct seq_file *s, loff_t *pos) +{ + if (*pos>=1) return NULL; + return (void *)((unsigned long) *pos+1); +} + +static void *himax_diag_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return NULL; +} +static void himax_diag_seq_stop(struct seq_file *s, void *v) +{ +} +static int himax_diag_seq_read(struct seq_file *s, void *v) +{ + size_t count = 0; + int32_t loop_i;//,loop_j + uint16_t mutual_num, self_num, width; + +#ifdef HX_TP_PROC_2T2R + if(Is_2T2R && diag_command == 4) + { + mutual_num = x_channel_2 * y_channel_2; + self_num = x_channel_2 + y_channel_2; //don't add KEY_COUNT + width = x_channel_2; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel_2, y_channel_2); + } + else +#endif + { + mutual_num = x_channel * y_channel; + self_num = x_channel + y_channel; //don't add KEY_COUNT + width = x_channel; + seq_printf(s, "ChannelStart: %4d, %4d\n\n", x_channel, y_channel); + } + + // start to show out the raw data in adb shell + if (diag_command >= 1 && diag_command <= 6) { + if (diag_command <= 3) { + himax_diag_arrange(s); + seq_printf(s, "\n\n"); +#ifdef HX_EN_SEL_BUTTON + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) + seq_printf(s, "%6d", diag_self[HX_RX_NUM + HX_TX_NUM + loop_i]); +#endif +#ifdef HX_TP_PROC_2T2R + }else if(Is_2T2R && diag_command == 4 ) { + for (loop_i = 0; loop_i < mutual_num; loop_i++) { + seq_printf(s, "%4d", diag_mutual_2[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, " %6d\n", diag_self[width + loop_i/width]); + } + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < width; loop_i++) { + seq_printf(s, "%6d", diag_self[loop_i]); + if (((loop_i) % width) == (width - 1)) + seq_printf(s, "\n"); + } +#ifdef HX_EN_SEL_BUTTON + seq_printf(s, "\n"); + for (loop_i = 0; loop_i < HX_BT_NUM; loop_i++) + seq_printf(s, "%4d", diag_self[HX_RX_NUM_2 + HX_TX_NUM_2 + loop_i]); +#endif +#endif + } else if (diag_command > 4) { + for (loop_i = 0; loop_i < self_num; loop_i++) { + seq_printf(s, "%4d", diag_self[loop_i]); + if (((loop_i - mutual_num) % width) == (width - 1)) + seq_printf(s, "\n"); + } + } else { + for (loop_i = 0; loop_i < mutual_num; loop_i++) { + seq_printf(s, "%4d", diag_mutual[loop_i]); + if ((loop_i % width) == (width - 1)) + seq_printf(s, "\n"); + } + } + seq_printf(s, "ChannelEnd"); + seq_printf(s, "\n"); + } else if (diag_command == 7) { + for (loop_i = 0; loop_i < 128 ;loop_i++) { + if ((loop_i % 16) == 0) + seq_printf(s, "LineStart:"); + seq_printf(s, "%4d", diag_coor[loop_i]); + if ((loop_i % 16) == 15) + seq_printf(s, "\n"); + } + } else if (diag_command == 9 || diag_command == 91 || diag_command == 92){ + himax_diag_arrange(s); + seq_printf(s, "\n"); + } + + return count; +} +static const struct seq_operations himax_diag_seq_ops = +{ + .start = himax_diag_seq_start, + .next = himax_diag_seq_next, + .stop = himax_diag_seq_stop, + .show = himax_diag_seq_read, +}; +static int himax_diag_proc_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &himax_diag_seq_ops); +}; +bool DSRAM_Flag; + +//DSRAM thread +void himax_ts_diag_func(void) +{ + int i=0, j=0; + unsigned int index = 0; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + uint8_t info_data[total_size]; + int16_t *mutual_data = NULL; + int16_t *mutual_data_new = NULL; + int16_t *mutual_data_old = NULL; + int16_t new_data; + + himax_burst_enable(private_ts->client, 1); + if(diag_command == 9 || diag_command == 91) + { + mutual_data = getMutualBuffer(); + }else if(diag_command == 92){ + mutual_data = getMutualBuffer(); + mutual_data_new = getMutualNewBuffer(); + mutual_data_old = getMutualOldBuffer(); + } + himax_get_DSRAM_data(private_ts->client, info_data); + + index = 0; + for (i = 0; i < ic_data->HX_TX_NUM; i++) + { + for (j = 0; j < ic_data->HX_RX_NUM; j++) + { + new_data = (short)(info_data[index + 1] << 8 | info_data[index]); + if(diag_command == 9){ + mutual_data[i*ic_data->HX_RX_NUM+j] = new_data; + }else if(diag_command == 91){ //Keep max data for 100 frame + if(mutual_data[i * ic_data->HX_RX_NUM + j] < new_data) + mutual_data[i * ic_data->HX_RX_NUM + j] = new_data; + }else if(diag_command == 92){ //Cal data for [N]-[N-1] frame + mutual_data_new[i * ic_data->HX_RX_NUM + j] = new_data; + mutual_data[i * ic_data->HX_RX_NUM + j] = mutual_data_new[i * ic_data->HX_RX_NUM + j] - mutual_data_old[i * ic_data->HX_RX_NUM + j]; + } + index += 2; + } + } + if(diag_command == 92){ + memcpy(mutual_data_old,mutual_data_new,x_channel * y_channel * sizeof(int16_t)); //copy N data to N-1 array + } + diag_max_cnt++; + if(diag_command == 9 || diag_command == 92){ + queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); + }else if(diag_command == 91){ + if(diag_max_cnt > 100) //count for 100 frame + { + //Clear DSRAM flag + DSRAM_Flag = false; + + //Enable ISR + himax_int_enable(private_ts->client->irq,1); + + //===================================== + // test result command : 0x8002_0324 ==> 0x00 + //===================================== + himax_diag_register_set(private_ts->client, 0x00); + }else{ + queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 1/10*HZ); + } + } +} + +static ssize_t himax_diag_write(struct file *filp, const char __user *buff, size_t len, loff_t *data) +{ + char messages[80] = {0}; + + uint8_t command[2] = {0x00, 0x00}; + uint8_t receive[1]; + + memset(receive, 0x00, sizeof(receive)); + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(messages, buff, len)) + { + return -EFAULT; + } + if (messages[1] == 0x0A){ + diag_command =messages[0] - '0'; + }else{ + diag_command =(messages[0] - '0')*10 + (messages[1] - '0'); + } + + I("[Himax]diag_command=0x%x\n",diag_command); + if (diag_command < 0x04){ + if(DSRAM_Flag) + { + //1. Clear DSRAM flag + DSRAM_Flag = false; + + //2. Stop DSRAM thread + cancel_delayed_work_sync(&private_ts->himax_diag_delay_wrok); + + //3. Enable ISR + himax_int_enable(private_ts->client->irq,1); + } + command[0] = diag_command; + himax_diag_register_set(private_ts->client, command[0]); + } + //coordinate dump start + else if (diag_command == 0x08) { + E("%s: coordinate_dump_file_create error\n", __func__); + } + else if (diag_command == 0x09 || diag_command == 91 || diag_command == 92){ + diag_max_cnt = 0; + memset(diag_mutual, 0x00, x_channel * y_channel * sizeof(int16_t)); //Set data 0 everytime + + //1. Disable ISR + himax_int_enable(private_ts->client->irq,0); + + //2. Start DSRAM thread + //himax_diag_register_set(private_ts->client, 0x0A); + + queue_delayed_work(private_ts->himax_diag_wq, &private_ts->himax_diag_delay_wrok, 2*HZ/100); + + I("%s: Start get raw data in DSRAM\n", __func__); + + //3. Set DSRAM flag + DSRAM_Flag = true; + }else{ + command[0] = 0x00; + himax_diag_register_set(private_ts->client, command[0]); + E("[Himax]Diag command error!diag_command=0x%x\n",diag_command); + } + return len; +} + +static const struct file_operations himax_proc_diag_ops = +{ + .owner = THIS_MODULE, + .open = himax_diag_proc_open, + .read = seq_read, + .write = himax_diag_write, +}; +#endif + +#ifdef HX_TP_PROC_RESET +static ssize_t himax_reset_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[12]; + + if (len >= 12) + { + I("%s: no command exceeds 12 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf_tmp, buff, len)) + { + return -EFAULT; + } + //if (buf_tmp[0] == '1') + // ESD_HW_REST(); + + return len; +} + +static const struct file_operations himax_proc_reset_ops = +{ + .owner = THIS_MODULE, + .write = himax_reset_write, +}; +#endif + +#ifdef HX_TP_PROC_DEBUG +static ssize_t himax_debug_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf){ + HX_PROC_SEND_FLAG=0; + return count; + } + + if (debug_level_cmd == 't') + { + if (fw_update_complete) + count += snprintf(temp_buf+count, len-count, "FW Update Complete "); + else + { + count += snprintf(temp_buf+count, len-count, "FW Update Fail "); + } + } + else if (debug_level_cmd == 'h') + { + if (handshaking_result == 0) + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Running)\n", handshaking_result); + } + else if (handshaking_result == 1) + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (MCU Stop)\n", handshaking_result); + } + else if (handshaking_result == 2) + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = %d (I2C Error)\n", handshaking_result); + } + else + { + count += snprintf(temp_buf+count, len-count, "Handshaking Result = error\n"); + } + } + else if (debug_level_cmd == 'v') + { + count += snprintf(temp_buf+count, len-count, "FW_VER = "); + count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_fw_ver); + count += snprintf(temp_buf+count, len-count, "CONFIG_VER = "); + count += snprintf(temp_buf+count, len-count, "0x%2.2X\n", ic_data->vendor_config_ver); + count += snprintf(temp_buf+count, len-count, "\n"); + } + else if (debug_level_cmd == 'd') + { + count += snprintf(temp_buf+count, len-count, "Himax Touch IC Information :\n"); + if (IC_TYPE == HX_85XX_D_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : D\n"); + } + else if (IC_TYPE == HX_85XX_E_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : E\n"); + } + else if (IC_TYPE == HX_85XX_ES_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : ES\n"); + } + else if (IC_TYPE == HX_85XX_F_SERIES_PWON) + { + count += snprintf(temp_buf+count, len-count, "IC Type : F\n"); + } + else + { + count += snprintf(temp_buf+count, len-count, "IC Type error.\n"); + } + + if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_SW) + { + count += snprintf(temp_buf+count, len-count, "IC Checksum : SW\n"); + } + else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_HW) + { + count += snprintf(temp_buf+count, len-count, "IC Checksum : HW\n"); + } + else if (IC_CHECKSUM == HX_TP_BIN_CHECKSUM_CRC) + { + count += snprintf(temp_buf+count, len-count, "IC Checksum : CRC\n"); + } + else + { + count += snprintf(temp_buf+count, len-count, "IC Checksum error.\n"); + } + + if (ic_data->HX_INT_IS_EDGE) + { + count += snprintf(temp_buf+count, len-count, "Interrupt : EDGE TIRGGER\n"); + } + else + { + count += snprintf(temp_buf+count, len-count, "Interrupt : LEVEL TRIGGER\n"); + } + + count += snprintf(temp_buf+count, len-count, "RX Num : %d\n", ic_data->HX_RX_NUM); + count += snprintf(temp_buf+count, len-count, "TX Num : %d\n", ic_data->HX_TX_NUM); + count += snprintf(temp_buf+count, len-count, "BT Num : %d\n", ic_data->HX_BT_NUM); + count += snprintf(temp_buf+count, len-count, "X Resolution : %d\n", ic_data->HX_X_RES); + count += snprintf(temp_buf+count, len-count, "Y Resolution : %d\n", ic_data->HX_Y_RES); + count += snprintf(temp_buf+count, len-count, "Max Point : %d\n", ic_data->HX_MAX_PT); + count += snprintf(temp_buf+count, len-count, "XY reverse : %d\n", ic_data->HX_XY_REVERSE); + #ifdef HX_TP_PROC_2T2R + if(Is_2T2R) + { + count += snprintf(temp_buf+count, len-count, "2T2R panel\n"); + count += snprintf(temp_buf+count, len-count, "RX Num_2 : %d\n", HX_RX_NUM_2); + count += snprintf(temp_buf+count, len-count, "TX Num_2 : %d\n", HX_TX_NUM_2); + } + #endif + } + else if (debug_level_cmd == 'i') + { + count += snprintf(temp_buf+count, len-count, "Himax Touch Driver Version:\n"); + count += snprintf(temp_buf+count, len-count, "%s\n", HIMAX_DRIVER_VER); + } + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + return count; +} + +static ssize_t himax_debug_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + const struct firmware *fw = NULL; + unsigned char *fw_data = NULL; + char fileName[128]; + char buf[80] = {0}; + int result; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if ( buf[0] == 'h') //handshaking + { + debug_level_cmd = buf[0]; + + himax_int_enable(private_ts->client->irq,0); + + handshaking_result = himax_hand_shaking(private_ts->client); //0:Running, 1:Stop, 2:I2C Fail + + himax_int_enable(private_ts->client->irq,1); + + return len; + } + + else if ( buf[0] == 'v') //firmware version + { + debug_level_cmd = buf[0]; + himax_int_enable(private_ts->client->irq,0); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(false,false); +#endif + himax_read_FW_ver(private_ts->client); + //himax_check_chip_version(); +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + himax_int_enable(private_ts->client->irq,1); + return len; + } + + else if ( buf[0] == 'd') //ic information + { + debug_level_cmd = buf[0]; + return len; + } + + else if ( buf[0] == 'i') //driver version + { + debug_level_cmd = buf[0]; + return len; + } + + else if (buf[0] == 't') + { + + himax_int_enable(private_ts->client->irq,0); + + debug_level_cmd = buf[0]; + fw_update_complete = false; + + memset(fileName, 0, 128); + // parse the file name + snprintf(fileName, len-4, "%s", &buf[4]); + I("%s: upgrade from file(%s) start!\n", __func__, fileName); + // open file + result = request_firmware(&fw, fileName, private_ts->dev); + if (result) { + E("%s: open firmware file failed\n", __func__); + goto firmware_upgrade_done; + //return len; + } + + I("%s: FW len %d\n", __func__, fw->size); + fw_data = (unsigned char *)fw->data; + + I("%s: FW image,len %d: %02X, %02X, %02X, %02X\n", __func__, result, upgrade_fw[0], upgrade_fw[1], upgrade_fw[2], upgrade_fw[3]); + + if (fw_data != NULL) + { + // start to upgrade + himax_int_enable(private_ts->client->irq,0); + + if ((buf[1] == '6') && (buf[2] == '0')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_60k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else if ((buf[1] == '6') && (buf[2] == '4')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_64k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else if ((buf[1] == '2') && (buf[2] == '4')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_124k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else if ((buf[1] == '2') && (buf[2] == '8')) + { + if (fts_ctpm_fw_upgrade_with_sys_fs_128k(private_ts->client,upgrade_fw, result, false) == 0) + { + E("%s: TP upgrade error, line: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + else + { + I("%s: TP upgrade OK, line: %d\n", __func__, __LINE__); + fw_update_complete = true; + } + } + else + { + E("%s: Flash command fail: %d\n", __func__, __LINE__); + fw_update_complete = false; + } + release_firmware(fw); + goto firmware_upgrade_done; + //return count; + } + } + + firmware_upgrade_done: + +#ifdef HX_RST_PIN_FUNC + himax_HW_reset(true,false); +#endif + + himax_sense_on(private_ts->client, 0x01); + msleep(120); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq,1); + + //todo himax_chip->tp_firmware_upgrade_proceed = 0; + //todo himax_chip->suspend_state = 0; + //todo enable_irq(himax_chip->irq); + return len; +} + +static const struct file_operations himax_proc_debug_ops = +{ + .owner = THIS_MODULE, + .read = himax_debug_read, + .write = himax_debug_write, +}; + +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + +static uint8_t getFlashCommand(void) +{ + return flash_command; +} + +static uint8_t getFlashDumpProgress(void) +{ + return flash_progress; +} + +static uint8_t getFlashDumpComplete(void) +{ + return flash_dump_complete; +} + +static uint8_t getFlashDumpFail(void) +{ + return flash_dump_fail; +} + +uint8_t getSysOperation(void) +{ + return sys_operation; +} + +static uint8_t getFlashReadStep(void) +{ + return flash_read_step; +} +/* +static uint8_t getFlashDumpSector(void) +{ + return flash_dump_sector; +} + +static uint8_t getFlashDumpPage(void) +{ + return flash_dump_page; +} +*/ +bool getFlashDumpGoing(void) +{ + return flash_dump_going; +} + +void setFlashBuffer(void) +{ + flash_buffer = kzalloc(Flash_Size * sizeof(uint8_t), GFP_KERNEL); + if (flash_buffer) + memset(flash_buffer,0x00,Flash_Size); +} + +void setSysOperation(uint8_t operation) +{ + sys_operation = operation; +} + +static void setFlashDumpProgress(uint8_t progress) +{ + flash_progress = progress; + //I("setFlashDumpProgress : progress = %d ,flash_progress = %d \n",progress,flash_progress); +} + +static void setFlashDumpComplete(uint8_t status) +{ + flash_dump_complete = status; +} + +static void setFlashDumpFail(uint8_t fail) +{ + flash_dump_fail = fail; +} + +static void setFlashCommand(uint8_t command) +{ + flash_command = command; +} + +static void setFlashReadStep(uint8_t step) +{ + flash_read_step = step; +} + +static void setFlashDumpSector(uint8_t sector) +{ + flash_dump_sector = sector; +} + +static void setFlashDumpPage(uint8_t page) +{ + flash_dump_page = page; +} + +static void setFlashDumpGoing(bool going) +{ + flash_dump_going = going; +} + +static ssize_t himax_proc_flash_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int ret = 0; + int loop_i; + uint8_t local_flash_read_step=0; + uint8_t local_flash_complete = 0; + uint8_t local_flash_progress = 0; + uint8_t local_flash_command = 0; + uint8_t local_flash_fail = 0; + char *temp_buf; + local_flash_complete = getFlashDumpComplete(); + local_flash_progress = getFlashDumpProgress(); + local_flash_command = getFlashCommand(); + local_flash_fail = getFlashDumpFail(); + + I("flash_progress = %d \n",local_flash_progress); + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + + if (local_flash_fail) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Fail \n"); + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (!local_flash_complete) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Ongoing:0x%2.2x \n",flash_progress); + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 1 && local_flash_complete) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:Complete \n"); + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + if (local_flash_command == 3 && local_flash_complete) + { + ret += snprintf(temp_buf+ret, len-ret, "FlashStart: \n"); + for(loop_i = 0; loop_i < 128; loop_i++) + { + ret += snprintf(temp_buf+ret, len-ret, "x%2.2x", flash_buffer[loop_i]); + if ((loop_i % 16) == 15) + { + ret += snprintf(temp_buf+ret, len-ret, "\n"); + } + } + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + return ret; + } + + //flash command == 0 , report the data + local_flash_read_step = getFlashReadStep(); + + ret += snprintf(temp_buf+ret, len-ret, "FlashStart:%2.2x \n",local_flash_read_step); + + for (loop_i = 0; loop_i < 1024; loop_i++) + { + ret += snprintf(temp_buf+ret, len-ret, "x%2.2X", flash_buffer[local_flash_read_step*1024 + loop_i]); + + if ((loop_i % 16) == 15) + { + ret += snprintf(temp_buf+ret, len-ret, "\n"); + } + } + + ret += snprintf(temp_buf+ret, len-ret, "FlashEnd"); + ret += snprintf(temp_buf+ret, len-ret, "\n"); + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +static ssize_t himax_proc_flash_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf_tmp[6]; + unsigned long result = 0; + uint8_t loop_i = 0; + int base = 0; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + + I("%s: buf[0] = %s\n", __func__, buf); + + if (getSysOperation() == 1) + { + E("%s: PROC is busy , return!\n", __func__); + return len; + } + + if (buf[0] == '0') + { + setFlashCommand(0); + if (buf[1] == ':' && buf[2] == 'x') + { + memcpy(buf_tmp, buf + 3, 2); + I("%s: read_Step = %s\n", __func__, buf_tmp); + if (!kstrtoul(buf_tmp, 16, &result)) + { + I("%s: read_Step = %lu \n", __func__, result); + setFlashReadStep(result); + } + } + } + else if (buf[0] == '1')// 1_60,1_64,1_24,1_28 for flash size 60k,64k,124k,128k + { + setSysOperation(1); + setFlashCommand(1); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_' ) && (buf[2] == '6' )){ + if (buf[3] == '0'){ + Flash_Size = FW_SIZE_60k; + }else if (buf[3] == '4'){ + Flash_Size = FW_SIZE_64k; + } + }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ + if (buf[3] == '4'){ + Flash_Size = FW_SIZE_124k; + }else if (buf[3] == '8'){ + Flash_Size = FW_SIZE_128k; + } + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '2') // 2_60,2_64,2_24,2_28 for flash size 60k,64k,124k,128k + { + setSysOperation(1); + setFlashCommand(2); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + if ((buf[1] == '_' ) && (buf[2] == '6' )){ + if (buf[3] == '0'){ + Flash_Size = FW_SIZE_60k; + }else if (buf[3] == '4'){ + Flash_Size = FW_SIZE_64k; + } + }else if ((buf[1] == '_' ) && (buf[2] == '2' )){ + if (buf[3] == '4'){ + Flash_Size = FW_SIZE_124k; + }else if (buf[3] == '8'){ + Flash_Size = FW_SIZE_128k; + } + } + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '3') + { + setSysOperation(1); + setFlashCommand(3); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpSector(result); + } + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpPage(result); + } + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + else if (buf[0] == '4') + { + I("%s: command 4 enter.\n", __func__); + setSysOperation(1); + setFlashCommand(4); + setFlashDumpProgress(0); + setFlashDumpComplete(0); + setFlashDumpFail(0); + + memcpy(buf_tmp, buf + 3, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpSector(result); + } + else + { + E("%s: command 4 , sector error.\n", __func__); + return len; + } + + memcpy(buf_tmp, buf + 7, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + setFlashDumpPage(result); + } + else + { + E("%s: command 4 , page error.\n", __func__); + return len; + } + + base = 11; + + I("=========Himax flash page buffer start=========\n"); + for(loop_i=0;loop_i<128 && base<80;loop_i++) + { + memcpy(buf_tmp, buf + base, 2); + if (!kstrtoul(buf_tmp, 16, &result)) + { + flash_buffer[loop_i] = result; + I("%d ",flash_buffer[loop_i]); + if (loop_i % 16 == 15) + { + I("\n"); + } + } + base += 3; + } + I("=========Himax flash page buffer end=========\n"); + + queue_work(private_ts->flash_wq, &private_ts->flash_work); + } + return len; +} + +static const struct file_operations himax_proc_flash_ops = +{ + .owner = THIS_MODULE, + .read = himax_proc_flash_read, + .write = himax_proc_flash_write, +}; + +void himax_ts_flash_func(void) +{ + uint8_t local_flash_command = 0; + + himax_int_enable(private_ts->client->irq,0); + setFlashDumpGoing(true); + + //sector = getFlashDumpSector(); + //page = getFlashDumpPage(); + + local_flash_command = getFlashCommand(); + + msleep(100); + + I("%s: local_flash_command = %d enter.\n", __func__,local_flash_command); + + if ((local_flash_command == 1 || local_flash_command == 2)|| (local_flash_command==0x0F)) + { + himax_flash_dump_func(private_ts->client, local_flash_command,Flash_Size, flash_buffer); + } + + I("Complete~~~~~~~~~~~~~~~~~~~~~~~\n"); + + if (local_flash_command == 2) + { + E("Flash dump failed\n"); + } + + himax_int_enable(private_ts->client->irq,1); + setFlashDumpGoing(false); + + setFlashDumpComplete(1); + setSysOperation(0); + return; + +/* Flash_Dump_i2c_transfer_error: + + himax_int_enable(private_ts->client->irq,1); + setFlashDumpGoing(false); + setFlashDumpComplete(0); + setFlashDumpFail(1); + setSysOperation(0); + return; +*/ +} + +#endif + +#ifdef HX_TP_PROC_SELF_TEST +static ssize_t himax_self_test_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + int val=0x00; + int ret = 0; + char *temp_buf; + + I("%s: enter, %d \n", __func__, __LINE__); + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + himax_int_enable(private_ts->client->irq,0);//disable irq + val = himax_chip_self_test(private_ts->client); +#ifdef HX_ESD_WORKAROUND + HX_ESD_RESET_ACTIVATE = 1; +#endif + himax_int_enable(private_ts->client->irq,1);//enable irq + + if (val == 0x01) { + ret += snprintf(temp_buf+ret, len-ret, "Self_Test Pass\n"); + } else { + ret += snprintf(temp_buf+ret, len-ret, "Self_Test Fail\n"); + } + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + HX_PROC_SEND_FLAG=0; + return ret; +} + +/* +static ssize_t himax_chip_self_test_store(struct device *dev,struct device_attribute *attr, const char *buf, size_t count) +{ + char buf_tmp[2]; + unsigned long result = 0; + + memset(buf_tmp, 0x0, sizeof(buf_tmp)); + memcpy(buf_tmp, buf, 2); + if(!kstrtoul(buf_tmp, 16, &result)) + { + sel_type = (uint8_t)result; + } + I("sel_type = %x \r\n", sel_type); + return count; +} +*/ + +static const struct file_operations himax_proc_self_test_ops = +{ + .owner = THIS_MODULE, + .read = himax_self_test_read, +}; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF +static ssize_t himax_sense_on_off_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if(buf[0] == '0') + { + himax_sense_off(private_ts->client); + I("Sense off \n"); + } + else if(buf[0] == '1') + { + if(buf[1] == '1'){ + himax_sense_on(private_ts->client, 0x01); + I("Sense on re-map off, run flash \n"); + }else if(buf[1] == '0'){ + himax_sense_on(private_ts->client, 0x00); + I("Sense on re-map on, run sram \n"); + }else{ + I("Do nothing \n"); + } + } + else + { + I("Do nothing \n"); + } + return len; +} + +static const struct file_operations himax_proc_sense_on_off_ops = +{ + .owner = THIS_MODULE, + .write = himax_sense_on_off_write, +}; +#endif + +#ifdef HX_HIGH_SENSE +static ssize_t himax_HSEN_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + size_t count = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return count; + } + count = snprintf(temp_buf, len, "%d\n", ts->HSEN_enable); + HX_PROC_SEND_FLAG=1; + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + } + else + HX_PROC_SEND_FLAG=0; + return count; +} + +static ssize_t himax_HSEN_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + if (buf[0] == '0'){ + ts->HSEN_enable = 0; + } + else if (buf[0] == '1'){ + ts->HSEN_enable = 1; + } + else + return -EINVAL; + + himax_set_HSEN_func(ts->client, ts->HSEN_enable); + + I("%s: HSEN_enable = %d.\n", __func__, ts->HSEN_enable); + + return len; +} + +static const struct file_operations himax_proc_HSEN_ops = +{ + .owner = THIS_MODULE, + .read = himax_HSEN_read, + .write = himax_HSEN_write, +}; +#endif + +#ifdef HX_SMART_WAKEUP +static ssize_t himax_SMWP_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + size_t count = 0; + struct himax_ts_data *ts = private_ts; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return count; + } + count = snprintf(temp_buf, len, "%d\n", ts->SMWP_enable); + + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG=1; + } + else + HX_PROC_SEND_FLAG=0; + + return count; +} + +static ssize_t himax_SMWP_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + + if (buf[0] == '0') + { + ts->SMWP_enable = 0; + } + else if (buf[0] == '1') + { + ts->SMWP_enable = 1; + } + else + return -EINVAL; + + himax_set_SMWP_func(ts->client, ts->SMWP_enable); + HX_SMWP_EN = ts->SMWP_enable; + I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN); + + return len; +} + +static const struct file_operations himax_proc_SMWP_ops = +{ + .owner = THIS_MODULE, + .read = himax_SMWP_read, + .write = himax_SMWP_write, +}; + +static ssize_t himax_GESTURE_read(struct file *file, char *buf, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i =0; + int ret = 0; + char *temp_buf; + + if(!HX_PROC_SEND_FLAG) + { + temp_buf = kzalloc(len, GFP_KERNEL); + if (!temp_buf) { + HX_PROC_SEND_FLAG=0; + return ret; + } + for(i=0;i<16;i++) + ret += snprintf(temp_buf+ret, len-ret, "ges_en[%d]=%d\n", i, ts->gesture_cust_en[i]); + HX_PROC_SEND_FLAG = 1; + if (copy_to_user(buf, temp_buf, len)) + { + I("%s,here:%d\n", __func__, __LINE__); + } + + kfree(temp_buf); + HX_PROC_SEND_FLAG = 1; + } + else + { + HX_PROC_SEND_FLAG = 0; + ret = 0; + } + return ret; +} + +static ssize_t himax_GESTURE_write(struct file *file, const char *buff, + size_t len, loff_t *pos) +{ + struct himax_ts_data *ts = private_ts; + int i =0; + char buf[80] = {0}; + + if (len >= 80) + { + I("%s: no command exceeds 80 chars.\n", __func__); + return -EFAULT; + } + if (copy_from_user(buf, buff, len)) + { + return -EFAULT; + } + + I("himax_GESTURE_store= %s \n",buf); + for (i=0;i<16;i++) + { + if (buf[i] == '0') + ts->gesture_cust_en[i]= 0; + else if (buf[i] == '1') + ts->gesture_cust_en[i]= 1; + else + ts->gesture_cust_en[i]= 0; + I("gesture en[%d]=%d \n", i, ts->gesture_cust_en[i]); + } + return len; +} + +static const struct file_operations himax_proc_Gesture_ops = +{ + .owner = THIS_MODULE, + .read = himax_GESTURE_read, + .write = himax_GESTURE_write, +}; +#endif + +int himax_touch_proc_init(void) +{ + himax_touch_proc_dir = proc_mkdir( HIMAX_PROC_TOUCH_FOLDER, NULL); + if (himax_touch_proc_dir == NULL) + { + E(" %s: himax_touch_proc_dir file create failed!\n", __func__); + return -ENOMEM; + } + + himax_proc_debug_level_file = proc_create(HIMAX_PROC_DEBUG_LEVEL_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_level_ops); + if (himax_proc_debug_level_file == NULL) + { + E(" %s: proc debug_level file create failed!\n", __func__); + goto fail_1; + } + + himax_proc_vendor_file = proc_create(HIMAX_PROC_VENDOR_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_vendor_ops); + if(himax_proc_vendor_file == NULL) + { + E(" %s: proc vendor file create failed!\n", __func__); + goto fail_2; + } + + himax_proc_attn_file = proc_create(HIMAX_PROC_ATTN_FILE, (S_IRUGO),himax_touch_proc_dir, &himax_proc_attn_ops); + if(himax_proc_attn_file == NULL) + { + E(" %s: proc attn file create failed!\n", __func__); + goto fail_3; + } + + himax_proc_int_en_file = proc_create(HIMAX_PROC_INT_EN_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_int_en_ops); + if(himax_proc_int_en_file == NULL) + { + E(" %s: proc int en file create failed!\n", __func__); + goto fail_4; + } + + himax_proc_layout_file = proc_create(HIMAX_PROC_LAYOUT_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_layout_ops); + if(himax_proc_layout_file == NULL) + { + E(" %s: proc layout file create failed!\n", __func__); + goto fail_5; + } + +#ifdef HX_TP_PROC_RESET + himax_proc_reset_file = proc_create(HIMAX_PROC_RESET_FILE, (S_IWUSR), himax_touch_proc_dir, &himax_proc_reset_ops); + if(himax_proc_reset_file == NULL) + { + E(" %s: proc reset file create failed!\n", __func__); + goto fail_6; + } +#endif + +#ifdef HX_TP_PROC_DIAG + himax_proc_diag_file = proc_create(HIMAX_PROC_DIAG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_ops); + if(himax_proc_diag_file == NULL) + { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7; + } + himax_proc_diag_arrange_file = proc_create(HIMAX_PROC_DIAG_ARR_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_diag_arrange_ops); + if(himax_proc_diag_arrange_file == NULL) + { + E(" %s: proc diag file create failed!\n", __func__); + goto fail_7_1; + } +#endif + +#ifdef HX_TP_PROC_REGISTER + himax_proc_register_file = proc_create(HIMAX_PROC_REGISTER_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_register_ops); + if(himax_proc_register_file == NULL) + { + E(" %s: proc register file create failed!\n", __func__); + goto fail_8; + } +#endif + +#ifdef HX_TP_PROC_DEBUG + himax_proc_debug_file = proc_create(HIMAX_PROC_DEBUG_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_debug_ops); + if(himax_proc_debug_file == NULL) + { + E(" %s: proc debug file create failed!\n", __func__); + goto fail_9; + } +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + himax_proc_flash_dump_file = proc_create(HIMAX_PROC_FLASH_DUMP_FILE, (S_IWUSR|S_IRUGO), himax_touch_proc_dir, &himax_proc_flash_ops); + if(himax_proc_flash_dump_file == NULL) + { + E(" %s: proc flash dump file create failed!\n", __func__); + goto fail_10; + } +#endif + +#ifdef HX_TP_PROC_SELF_TEST + himax_proc_self_test_file = proc_create(HIMAX_PROC_SELF_TEST_FILE, (S_IRUGO), himax_touch_proc_dir, &himax_proc_self_test_ops); + if(himax_proc_self_test_file == NULL) + { + E(" %s: proc self_test file create failed!\n", __func__); + goto fail_11; + } +#endif + +#ifdef HX_HIGH_SENSE + himax_proc_HSEN_file = proc_create(HIMAX_PROC_HSEN_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_HSEN_ops); + if(himax_proc_HSEN_file == NULL) + { + E(" %s: proc HSEN file create failed!\n", __func__); + goto fail_12; + } +#endif + +#ifdef HX_SMART_WAKEUP + himax_proc_SMWP_file = proc_create(HIMAX_PROC_SMWP_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_SMWP_ops); + if(himax_proc_SMWP_file == NULL) + { + E(" %s: proc SMWP file create failed!\n", __func__); + goto fail_13; + } + himax_proc_GESTURE_file = proc_create(HIMAX_PROC_GESTURE_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_Gesture_ops); + if(himax_proc_GESTURE_file == NULL) + { + E(" %s: proc GESTURE file create failed!\n", __func__); + goto fail_14; + } +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + himax_proc_SENSE_ON_OFF_file = proc_create(HIMAX_PROC_SENSE_ON_OFF_FILE, (S_IWUSR|S_IRUGO|S_IWUGO), himax_touch_proc_dir, &himax_proc_sense_on_off_ops); + if(himax_proc_SENSE_ON_OFF_file == NULL) + { + E(" %s: proc SENSE_ON_OFF file create failed!\n", __func__); + goto fail_15; + } +#endif + + return 0 ; + +#ifdef HX_TP_PROC_SENSE_ON_OFF + fail_15: +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); + fail_14: + remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); + fail_13: +#endif +#ifdef HX_HIGH_SENSE + remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); + fail_12: +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry( HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir ); + fail_11: +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry( HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir ); + fail_10: +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); + fail_9: +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry( HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir ); + fail_8: +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry( HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir ); + fail_7: + remove_proc_entry( HIMAX_PROC_DIAG_ARR_FILE, himax_touch_proc_dir ); + fail_7_1: +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); + fail_6: +#endif + remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); + fail_5: remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); + fail_4: remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); + fail_3: remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); + fail_2: remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); + fail_1: remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); + return -ENOMEM; +} + +void himax_touch_proc_deinit(void) +{ +#ifdef HX_TP_PROC_SENSE_ON_OFF + remove_proc_entry( HIMAX_PROC_SENSE_ON_OFF_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_SMART_WAKEUP + remove_proc_entry( HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_DOT_VIEW + remove_proc_entry( HIMAX_PROC_HSEN_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_TP_PROC_SELF_TEST + remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_FLASH_DUMP + remove_proc_entry(HIMAX_PROC_FLASH_DUMP_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DEBUG + remove_proc_entry( HIMAX_PROC_DEBUG_FILE, himax_touch_proc_dir ); +#endif +#ifdef HX_TP_PROC_REGISTER + remove_proc_entry(HIMAX_PROC_REGISTER_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_DIAG + remove_proc_entry(HIMAX_PROC_DIAG_FILE, himax_touch_proc_dir); +#endif +#ifdef HX_TP_PROC_RESET + remove_proc_entry( HIMAX_PROC_RESET_FILE, himax_touch_proc_dir ); +#endif + remove_proc_entry( HIMAX_PROC_LAYOUT_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_INT_EN_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_ATTN_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_VENDOR_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_DEBUG_LEVEL_FILE, himax_touch_proc_dir ); + remove_proc_entry( HIMAX_PROC_TOUCH_FOLDER, NULL ); +} +#endif diff --git a/drivers/input/touchscreen/hxchipset/himax_debug.h b/drivers/input/touchscreen/hxchipset/himax_debug.h new file mode 100644 index 000000000000..91a7ae2eb7ab --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_debug.h @@ -0,0 +1,181 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) + #define HIMAX_PROC_TOUCH_FOLDER "android_touch" + #define HIMAX_PROC_DEBUG_LEVEL_FILE "debug_level" + #define HIMAX_PROC_VENDOR_FILE "vendor" + #define HIMAX_PROC_ATTN_FILE "attn" + #define HIMAX_PROC_INT_EN_FILE "int_en" + #define HIMAX_PROC_LAYOUT_FILE "layout" + + static struct proc_dir_entry *himax_touch_proc_dir; + static struct proc_dir_entry *himax_proc_debug_level_file; + static struct proc_dir_entry *himax_proc_vendor_file; + static struct proc_dir_entry *himax_proc_attn_file; + static struct proc_dir_entry *himax_proc_int_en_file; + static struct proc_dir_entry *himax_proc_layout_file; + + uint8_t HX_PROC_SEND_FLAG; + +extern int himax_touch_proc_init(void); +extern void himax_touch_proc_deinit(void); +bool getFlashDumpGoing(void); + +#ifdef HX_TP_PROC_REGISTER + #define HIMAX_PROC_REGISTER_FILE "register" + struct proc_dir_entry *himax_proc_register_file; + uint8_t register_command[4]; +#endif + +#ifdef HX_TP_PROC_DIAG + #define HIMAX_PROC_DIAG_FILE "diag" + struct proc_dir_entry *himax_proc_diag_file; + #define HIMAX_PROC_DIAG_ARR_FILE "diag_arr" + struct proc_dir_entry *himax_proc_diag_arrange_file; + +#ifdef HX_TP_PROC_2T2R + static bool Is_2T2R; + static uint8_t x_channel_2; + static uint8_t y_channel_2; + static uint8_t *diag_mutual_2; + + int16_t *getMutualBuffer_2(void); + uint8_t getXChannel_2(void); + uint8_t getYChannel_2(void); + + void setMutualBuffer_2(void); + void setXChannel_2(uint8_t x); + void setYChannel_2(uint8_t y); +#endif + uint8_t x_channel; + uint8_t y_channel; + int16_t *diag_mutual; + int16_t *diag_mutual_new; + int16_t *diag_mutual_old; + uint8_t diag_max_cnt; + + int diag_command; + uint8_t diag_coor[128];// = {0xFF}; + int16_t diag_self[100] = {0}; + + int16_t *getMutualBuffer(void); + int16_t *getMutualNewBuffer(void); + int16_t *getMutualOldBuffer(void); + int16_t *getSelfBuffer(void); + uint8_t getDiagCommand(void); + uint8_t getXChannel(void); + uint8_t getYChannel(void); + + void setMutualBuffer(void); + void setMutualNewBuffer(void); + void setMutualOldBuffer(void); + void setXChannel(uint8_t x); + void setYChannel(uint8_t y); + uint8_t coordinate_dump_enable = 0; + struct file *coordinate_fn; +#endif + +#ifdef HX_TP_PROC_DEBUG + #define HIMAX_PROC_DEBUG_FILE "debug" + struct proc_dir_entry *himax_proc_debug_file = NULL; + + bool fw_update_complete = false; + int handshaking_result = 0; + unsigned char debug_level_cmd = 0; + unsigned char upgrade_fw[128*1024]; +#endif + +#ifdef HX_TP_PROC_FLASH_DUMP + #define HIMAX_PROC_FLASH_DUMP_FILE "flash_dump" + struct proc_dir_entry *himax_proc_flash_dump_file = NULL; + + static int Flash_Size = 131072; + static uint8_t *flash_buffer = NULL; + static uint8_t flash_command = 0; + static uint8_t flash_read_step = 0; + static uint8_t flash_progress = 0; + static uint8_t flash_dump_complete = 0; + static uint8_t flash_dump_fail = 0; + static uint8_t sys_operation = 0; + static uint8_t flash_dump_sector = 0; + static uint8_t flash_dump_page = 0; + static bool flash_dump_going = false; + + static uint8_t getFlashCommand(void); + static uint8_t getFlashDumpComplete(void); + static uint8_t getFlashDumpFail(void); + static uint8_t getFlashDumpProgress(void); + static uint8_t getFlashReadStep(void); + //static uint8_t getFlashDumpSector(void); + //static uint8_t getFlashDumpPage(void); + + void setFlashBuffer(void); + uint8_t getSysOperation(void); + + static void setFlashCommand(uint8_t command); + static void setFlashReadStep(uint8_t step); + static void setFlashDumpComplete(uint8_t complete); + static void setFlashDumpFail(uint8_t fail); + static void setFlashDumpProgress(uint8_t progress); + void setSysOperation(uint8_t operation); + static void setFlashDumpSector(uint8_t sector); + static void setFlashDumpPage(uint8_t page); + static void setFlashDumpGoing(bool going); + +#endif + +#ifdef HX_TP_PROC_SELF_TEST + #define HIMAX_PROC_SELF_TEST_FILE "self_test" + struct proc_dir_entry *himax_proc_self_test_file = NULL; + uint32_t **raw_data_array; + uint8_t X_NUM = 0, Y_NUM = 0; + uint8_t sel_type = 0x0D; +#endif + +#ifdef HX_TP_PROC_RESET +#define HIMAX_PROC_RESET_FILE "reset" +extern void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); +struct proc_dir_entry *himax_proc_reset_file = NULL; +#endif + +#ifdef HX_HIGH_SENSE + #define HIMAX_PROC_HSEN_FILE "HSEN" + struct proc_dir_entry *himax_proc_HSEN_file = NULL; +#endif + +#ifdef HX_TP_PROC_SENSE_ON_OFF + #define HIMAX_PROC_SENSE_ON_OFF_FILE "SenseOnOff" + struct proc_dir_entry *himax_proc_SENSE_ON_OFF_file = NULL; +#endif + +#ifdef HX_RST_PIN_FUNC + void himax_HW_reset(uint8_t loadconfig,uint8_t int_off); +#endif + +#ifdef HX_SMART_WAKEUP +#define HIMAX_PROC_SMWP_FILE "SMWP" +struct proc_dir_entry *himax_proc_SMWP_file = NULL; +#define HIMAX_PROC_GESTURE_FILE "GESTURE" +struct proc_dir_entry *himax_proc_GESTURE_file = NULL; +uint8_t HX_SMWP_EN = 0; +//extern bool FAKE_POWER_KEY_SEND; +#endif + +#endif + diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.c b/drivers/input/touchscreen/hxchipset/himax_ic.c new file mode 100644 index 000000000000..6ad8dc03149b --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.c @@ -0,0 +1,2118 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_ic.h" + +static unsigned char i_TP_CRC_FW_128K[]= +{ + #include "HX_CRC_128.i" +}; +static unsigned char i_TP_CRC_FW_64K[]= +{ + #include "HX_CRC_64.i" +}; +static unsigned char i_TP_CRC_FW_124K[]= +{ + #include "HX_CRC_124.i" +}; +static unsigned char i_TP_CRC_FW_60K[]= +{ + #include "HX_CRC_60.i" +}; + + +unsigned long FW_VER_MAJ_FLASH_ADDR; +unsigned long FW_VER_MAJ_FLASH_LENG; +unsigned long FW_VER_MIN_FLASH_ADDR; +unsigned long FW_VER_MIN_FLASH_LENG; +unsigned long CFG_VER_MAJ_FLASH_ADDR; +unsigned long CFG_VER_MAJ_FLASH_LENG; +unsigned long CFG_VER_MIN_FLASH_ADDR; +unsigned long CFG_VER_MIN_FLASH_LENG; + +unsigned char IC_TYPE = 0; +unsigned char IC_CHECKSUM = 0; + +extern struct himax_ic_data* ic_data; + +int himax_hand_shaking(struct i2c_client *client) //0:Running, 1:Stop, 2:I2C Fail +{ + int ret, result; + uint8_t hw_reset_check[1]; + uint8_t hw_reset_check_2[1]; + uint8_t buf0[2]; + uint8_t IC_STATUS_CHECK = 0xAA; + + memset(hw_reset_check, 0x00, sizeof(hw_reset_check)); + memset(hw_reset_check_2, 0x00, sizeof(hw_reset_check_2)); + + buf0[0] = 0xF2; + if (IC_STATUS_CHECK == 0xAA) { + buf0[1] = 0xAA; + IC_STATUS_CHECK = 0x55; + } else { + buf0[1] = 0x55; + IC_STATUS_CHECK = 0xAA; + } + + ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0xF2 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + msleep(50); + + buf0[0] = 0xF2; + buf0[1] = 0x00; + ret = i2c_himax_master_write(client, buf0, 2, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:write 0x92 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + usleep_range(2000, 4000); + + ret = i2c_himax_read(client, 0xD1, hw_reset_check, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + + if ((IC_STATUS_CHECK != hw_reset_check[0])) { + usleep_range(2000, 4000); + ret = i2c_himax_read(client, 0xD1, hw_reset_check_2, 1, HIMAX_I2C_RETRY_TIMES); + if (ret < 0) { + E("[Himax]:i2c_himax_read 0xD1 failed line: %d \n",__LINE__); + goto work_func_send_i2c_msg_fail; + } + + if (hw_reset_check[0] == hw_reset_check_2[0]) { + result = 1; + } else { + result = 0; + } + } else { + result = 0; + } + + return result; + +work_func_send_i2c_msg_fail: + return 2; +} + +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + if(diag_command != 0) + diag_command = diag_command + 5; + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0x80; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = diag_command; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer) +{ + //struct himax_ts_data *ts = container_of(work, struct himax_ts_data, flash_work); + +// uint8_t sector = 0; +// uint8_t page = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260] = {0}; + int page_prog_start = 0; + int i = 0; + + himax_sense_off(client); + himax_burst_enable(client, 0); + /*=============Dump Flash Start=============*/ + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < Flash_Size; page_prog_start = page_prog_start + 256) + { + //================================= + // SPI Transfer Control + // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + // Set read start address : 0x8000_0028 ==> 0x0000_0000 + // Set command : 0x8000_0024 ==> 0x0000_003B + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //================================== + // AHB_I2C Burst Read + // Set SPI data register : 0x8000_002C ==> 0x00 + //================================== + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(client, 0x00 ,out_buffer, 4, 3); + + //================================== + // Read access : 0x0C ==> 0x00 + //================================== + out_buffer[0] = 0x00; + i2c_himax_write(client, 0x0C ,out_buffer, 1, 3); + + //================================== + // Read 128 bytes two times + //================================== + i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); + for (i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + + i2c_himax_read(client, 0x08 ,in_buffer, 128, 3); + for (i = 0; i < 128; i++) + flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; + + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + +/*=============Dump Flash End=============*/ + //msleep(100); + /* + for( i=0 ; i<8 ;i++) + { + for(j=0 ; j<64 ; j++) + { + setFlashDumpProgress(i*32 + j); + } + } + */ + himax_sense_on(client, 0x01); + + return; + +} + +int himax_chip_self_test(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + int pf_value=0x00; + uint8_t test_result_id = 0; + int j; + + memset(tmp_addr, 0x00, sizeof(tmp_addr)); + memset(tmp_data, 0x00, sizeof(tmp_data)); + + himax_interface_on(client); + himax_sense_off(client); + + //Set criteria + himax_burst_enable(client, 1); + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x94; + tmp_data[3] = 0x14; tmp_data[2] = 0xC8; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_data[7] = 0x13; tmp_data[6] = 0x60; tmp_data[5] = 0x0A; tmp_data[4] = 0x99; + + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 8); + + //start selftest + // 0x9008_805C ==> 0x0000_0001 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x5C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + himax_sense_on(client, 1); + + msleep(2000); + + himax_sense_off(client); + msleep(20); + + //===================================== + // Read test result ID : 0x9008_8078 ==> 0xA/0xB/0xC/0xF + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x78; + himax_register_read(client, tmp_addr, 1, tmp_data); + + test_result_id = tmp_data[0]; + + I("%s: check test result, test_result_id=%x, test_result=%x\n", __func__ + ,test_result_id,tmp_data[0]); + + if (test_result_id==0xF) { + I("[Himax]: self-test pass\n"); + pf_value = 0x1; + } else { + E("[Himax]: self-test fail\n"); + pf_value = 0x0; + } + himax_burst_enable(client, 1); + + for (j = 0;j < 10; j++){ + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x06; tmp_addr[1] = 0x00; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("[Himax]: 9006000C = %d\n", tmp_data[0]); + if (tmp_data[0] != 0){ + tmp_data[3] = 0x90; tmp_data[2] = 0x06; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + tmp_data[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + i2c_himax_read(client, 0x08, tmp_data, 124,HIMAX_I2C_RETRY_TIMES); + }else{ + break; + } + } + + himax_sense_on(client, 1); + msleep(120); + + return pf_value; +} + +void himax_set_HSEN_enable(struct i2c_client *client, uint8_t HSEN_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = HSEN_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x50; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +void himax_set_SMWP_enable(struct i2c_client *client, uint8_t SMWP_enable) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = SMWP_enable; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} + +void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data) +{ + uint8_t tmp_addr[4]; + + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x54; + himax_register_read(client, tmp_addr, 1, tmp_data); +} + +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte) +{ + uint8_t tmp_data[4]; + + tmp_data[0] = 0x31; + if ( i2c_himax_write(client, 0x13 ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return -EBUSY; + } + + tmp_data[0] = (0x10 | auto_add_4_byte); + if ( i2c_himax_write(client, 0x0D ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return -EBUSY; + } + return 0; + +} + +void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data) +{ + uint8_t tmp_data[4]; + int i = 0; + int address = 0; + + if(read_length>256) + { + E("%s: read len over 256!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 1); + else + himax_burst_enable(client, 0); + address = (read_addr[3] << 24) + (read_addr[2] << 16) + (read_addr[1] << 8) + read_addr[0]; + i = address; + tmp_data[0] = (uint8_t)i; + tmp_data[1] = (uint8_t)(i >> 8); + tmp_data[2] = (uint8_t)(i >> 16); + tmp_data[3] = (uint8_t)(i >> 24); + if ( i2c_himax_write(client, 0x00 ,tmp_data, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + tmp_data[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,tmp_data, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x08 ,read_data, read_length * 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + if (read_length > 1) + himax_burst_enable(client, 0); +} + +void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data) +{ + uint8_t tmpbyte[2]; + + if ( i2c_himax_write(client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + tmpbyte[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x08 ,&read_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x09 ,&read_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x0A ,&read_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x0B ,&read_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_read(client, 0x18 ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }// No bus request + + if ( i2c_himax_read(client, 0x0F ,&tmpbyte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + }// idle state + +} + +void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data) +{ + uint8_t data_byte[8]; + int i = 0, j = 0; + + for (i = 0; i < 4; i++) + { + data_byte[i] = reg_byte[i]; + } + for (j = 4; j < 8; j++) + { + data_byte[j] = write_data[j-4]; + } + + if ( i2c_himax_write(client, 0x00 ,data_byte, 8, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + +} + +int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length) +{ + uint8_t data_byte[256]; + int i = 0, j = 0; + + for (i = 0; i < 4; i++) + { + data_byte[i] = reg_byte[i]; + } + for (j = 4; j < length + 4; j++) + { + data_byte[j] = write_data[j - 4]; + } + + if ( i2c_himax_write(client, 0x00 ,data_byte, length + 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return -EBUSY; + } + + return 0; +} + +int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data) +{ + int i =0, address = 0; + int ret = 0; + + address = (write_addr[3] << 24) + (write_addr[2] << 16) + (write_addr[1] << 8) + write_addr[0]; + + for (i = address; i < address + write_length * 4; i = i + 4) + { + if (write_length > 1) + { + ret = himax_burst_enable(client, 1); + if(ret) + return ret; + } + else + { + ret = himax_burst_enable(client, 0); + if(ret) + return ret; + } + ret = himax_flash_write_burst_lenth(client, write_addr, write_data, write_length * 4); + if(ret < 0) + return ret; + } + + return 0; +} + +void himax_sense_off(struct i2c_client *client) +{ + uint8_t wdt_off = 0x00; + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + himax_burst_enable(client, 0); + + while(wdt_off == 0x00) + { + // 0x9000_800C ==> 0x0000_AC53 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0xAC; tmp_data[0] = 0x53; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read Watch Dog disable password : 0x9000_800C ==> 0x0000_AC53 + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x80; tmp_addr[0] = 0x0C; + himax_register_read(client, tmp_addr, 1, tmp_data); + + //Check WDT + if (tmp_data[0] == 0x53 && tmp_data[1] == 0xAC && tmp_data[2] == 0x00 && tmp_data[3] == 0x00) + wdt_off = 0x01; + else + wdt_off = 0x00; + } + + // VCOM //0x9008_806C ==> 0x0000_0001 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x08; tmp_addr[1] = 0x80; tmp_addr[0] = 0x6C; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(20); + + // 0x9000_0010 ==> 0x0000_00DA + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xDA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read CPU clock off password : 0x9000_0010 ==> 0x0000_00DA + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + himax_register_read(client, tmp_addr, 1, tmp_data); + I("%s: CPU clock off password data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + +} + +void himax_interface_on(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[5]; + + //=========================================== + // Any Cmd for ineterface on : 0x9000_0000 ==> 0x0000_0000 + //=========================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + himax_flash_read(client, tmp_addr, tmp_data); //avoid RD/WR fail +} + +bool wait_wip(struct i2c_client *client, int Timing) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t in_buffer[10]; + //uint8_t out_buffer[20]; + int retry_cnt = 0; + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = 0x01; + + do + { + //===================================== + // SPI Transfer Control : 0x8000_0020 ==> 0x4200_0003 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x42; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x03; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // SPI Command : 0x8000_0024 ==> 0x0000_0005 + // read 0x8000_002C for 0x01, means wait success + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x05; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + in_buffer[0] = in_buffer[1] = in_buffer[2] = in_buffer[3] = 0xFF; + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + himax_register_read(client, tmp_addr, 1, in_buffer); + + if ((in_buffer[0] & 0x01) == 0x00) + return true; + + retry_cnt++; + + if (in_buffer[0] != 0x00 || in_buffer[1] != 0x00 || in_buffer[2] != 0x00 || in_buffer[3] != 0x00) + I("%s:Wait wip retry_cnt:%d, buffer[0]=%d, buffer[1]=%d, buffer[2]=%d, buffer[3]=%d \n", __func__, + retry_cnt,in_buffer[0],in_buffer[1],in_buffer[2],in_buffer[3]); + + if (retry_cnt > 100) + { + E("%s: Wait wip error!\n", __func__); + return false; + } + msleep(Timing); + }while ((in_buffer[0] & 0x01) == 0x01); + return true; +} + +void himax_sense_on(struct i2c_client *client, uint8_t FlashMode) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + + himax_interface_on(client); + himax_burst_enable(client, 0); + //CPU reset + // 0x9000_0014 ==> 0x0000_00CA + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xCA; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read pull low CPU reset signal : 0x9000_0014 ==> 0x0000_00CA + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: check pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + + // 0x9000_0014 ==> 0x0000_0000 + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Read revert pull low CPU reset signal : 0x9000_0014 ==> 0x0000_0000 + //===================================== + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x14; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: revert pull low CPU reset signal data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", __func__ + ,tmp_data[0],tmp_data[1],tmp_data[2],tmp_data[3]); + + //===================================== + // Reset TCON + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + usleep_range(10000, 20000); + tmp_addr[3] = 0x80; tmp_addr[2] = 0x02; tmp_addr[1] = 0x01; tmp_addr[0] = 0xE0; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + if (FlashMode == 0x00) //SRAM + { + //===================================== + // Re-map + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xF1; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map ON\n", __func__); + } + else + { + //===================================== + // Re-map off + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + I("%s:83100_Chip_Re-map OFF\n", __func__); + } + //===================================== + // CPU clock on + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + +} + +void himax_chip_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Chip Erase + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Chip Erase + // Erase Command : 0x8000_0024 ==> 0x0000_00C7 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0xC7; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(2000); + + if (!wait_wip(client, 100)) + E("%s:83100_Chip_Erase Fail\n", __func__); + +} + +bool himax_block_erase(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Chip Erase + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Block Erase + // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr + // 0x8000_0020 ==> 0x6700_0000 //control + // 0x8000_0024 ==> 0x0000_0052 //BE + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x52; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(1000); + + if (!wait_wip(client, 100)) + { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + else + { + return true; + } + +} + +bool himax_sector_erase(struct i2c_client *client, int start_addr) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int page_prog_start = 0; + + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + for (page_prog_start = start_addr; page_prog_start < start_addr + 0x0F000; page_prog_start = page_prog_start + 0x1000) + { + //===================================== + // Chip Erase + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //===================================== + // Sector Erase + // Erase Command : 0x8000_0028 ==> 0x0000_0000 //SPI addr + // 0x8000_0020 ==> 0x6700_0000 //control + // 0x8000_0024 ==> 0x0000_0020 //SE + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; tmp_data[2] = (uint8_t)(page_prog_start >> 16); tmp_data[1] = (uint8_t)(page_prog_start >> 8); tmp_data[0] = (uint8_t)page_prog_start; + } + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x67; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x20; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + msleep(200); + + if (!wait_wip(client, 100)) + { + E("%s:83100_Erase Fail\n", __func__); + return false; + } + } + return true; +} + +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content) +{ + int i = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[128]; + int FW_length = 0x4000; // 0x4000 = 16K bin file + + //himax_sense_off(client); + + for (i = 0; i < FW_length; i = i + 128) + { + himax_burst_enable(client, 1); + + if (i < 0x100) + { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = 0x00; + tmp_addr[0] = i; + } + else if (i >= 0x100 && i < 0x10000) + { + tmp_addr[3] = 0x08; + tmp_addr[2] = 0x00; + tmp_addr[1] = (i >> 8); + tmp_addr[0] = i; + } + + memcpy(&tmp_data[0], &FW_content[i], 128); + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 128); + + } + + if (!wait_wip(client, 100)) + E("%s:83100_Sram_Write Fail\n", __func__); +} + +bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size) +{ + int i = 0; + uint8_t out_buffer[20]; + uint8_t in_buffer[128]; + uint8_t *get_fw_content; + + get_fw_content = kzalloc(0x4000*sizeof(uint8_t), GFP_KERNEL); + if (!get_fw_content) + return false; + + for (i = 0; i < 0x4000; i = i + 128) + { + himax_burst_enable(client, 1); + + //================================== + // AHB_I2C Burst Read + //================================== + if (i < 0x100) + { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = 0x00; + out_buffer[0] = i; + } + else if (i >= 0x100 && i < 0x10000) + { + out_buffer[3] = 0x08; + out_buffer[2] = 0x00; + out_buffer[1] = (i >> 8); + out_buffer[0] = i; + } + + if ( i2c_himax_write(client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + out_buffer[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + + if ( i2c_himax_read(client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return false; + } + memcpy(&get_fw_content[i], &in_buffer[0], 128); + } + + for (i = 0; i < FW_Size; i++) + { + if (FW_File[i] != get_fw_content[i]) + { + E("%s: fail! SRAM[%x]=%x NOT CRC_ifile=%x\n", __func__,i,get_fw_content[i],FW_File[i]); + return false; + } + } + + kfree(get_fw_content); + + return true; +} + +void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size) +{ + int page_prog_start = 0; + int program_length = 48; + int i = 0, j = 0, k = 0; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t buring_data[256]; // Read for flash data, 128K + // 4 bytes for 0x80002C padding + + //himax_interface_on(client); + himax_burst_enable(client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) + { + //msleep(5); + //===================================== + // Write Enable : 1. 0x8000_0020 ==> 0x4700_0000 + // 2. 0x8000_0024 ==> 0x0000_0006 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x47; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x06; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //================================= + // SPI Transfer Control + // Set 256 bytes page write : 0x8000_0020 ==> 0x610F_F000 + // Set read start address : 0x8000_0028 ==> 0x0000_0000 + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x61; tmp_data[2] = 0x0F; tmp_data[1] = 0xF0; tmp_data[0] = 0x00; + // data bytes should be 0x6100_0000 + ((word_number)*4-1)*4096 = 0x6100_0000 + 0xFF000 = 0x610F_F000 + // Programmable size = 1 page = 256 bytes, word_number = 256 byte / 4 = 64 + himax_flash_write_burst(client, tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + //tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; // Flash start address 1st : 0x0000_0000 + + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + + himax_flash_write_burst(client, tmp_addr, tmp_data); + + + //================================= + // Send 16 bytes data : 0x8000_002C ==> 16 bytes data + //================================= + buring_data[0] = 0x2C; + buring_data[1] = 0x00; + buring_data[2] = 0x00; + buring_data[3] = 0x80; + + for (i = /*0*/page_prog_start, j = 0; i < 16 + page_prog_start/**/; i++, j++) /// <------ bin file + { + buring_data[j + 4] = FW_content[i]; + } + + + if ( i2c_himax_write(client, 0x00 ,buring_data, 20, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + //================================= + // Write command : 0x8000_0024 ==> 0x0000_0002 + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x02; + himax_flash_write_burst(client, tmp_addr, tmp_data); + + //================================= + // Send 240 bytes data : 0x8000_002C ==> 240 bytes data + //================================= + + for (j = 0; j < 5; j++) + { + for (i = (page_prog_start + 16 + (j * 48)), k = 0; i < (page_prog_start + 16 + (j * 48)) + program_length; i++, k++) /// <------ bin file + { + buring_data[k+4] = FW_content[i];//(byte)i; + } + + if ( i2c_himax_write(client, 0x00 ,buring_data, program_length+4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + } + + if (!wait_wip(client, 1)) + E("%s:83100_Flash_Programming Fail\n", __func__); + } +} + +bool himax_check_chip_version(struct i2c_client *client) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t ret_data = 0x00; + int i = 0; + int ret = 0; + himax_sense_off(client); + for (i = 0; i < 5; i++) + { + // 1. Set DDREG_Req = 1 (0x9000_0020 = 0x0000_0001) (Lock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x01; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if(ret) + return false; + + // 2. Set bank as 0 (0x8001_BD01 = 0x0000_0000) + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xBD; tmp_addr[0] = 0x01; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + ret = himax_register_write(client, tmp_addr, 1, tmp_data); + if(ret) + return false; + + // 3. Read driver ID register RF4H 1 byte (0x8001_F401) + // Driver register RF4H 1 byte value = 0x84H, read back value will become 0x84848484 + tmp_addr[3] = 0x80; tmp_addr[2] = 0x01; tmp_addr[1] = 0xF4; tmp_addr[0] = 0x01; + himax_register_read(client, tmp_addr, 1, tmp_data); + ret_data = tmp_data[0]; + + I("%s:Read driver IC ID = %X\n", __func__, ret_data); + if (ret_data == 0x84) + { + IC_TYPE = HX_83100_SERIES_PWON; + //himax_sense_on(client, 0x01); + ret_data = true; + break; + } + else + { + ret_data = false; + E("%s:Read driver ID register Fail:\n", __func__); + } + } + // 4. After read finish, set DDREG_Req = 0 (0x9000_0020 = 0x0000_0000) (Unlock register R/W from driver) + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_register_write(client, tmp_addr, 1, tmp_data); + //himax_sense_on(client, 0x01); + return ret_data; +} + +#if 1 +int himax_check_CRC(struct i2c_client *client, int mode) +{ + bool burnFW_success = false; + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + int tmp_value; + int CRC_value = 0; + + memset(tmp_data, 0x00, sizeof(tmp_data)); + + if (1) + { + if(mode == fw_image_60k) + { + himax_sram_write(client, (i_TP_CRC_FW_60K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_60K, 0x4000); + } + else if(mode == fw_image_64k) + { + himax_sram_write(client, (i_TP_CRC_FW_64K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_64K, 0x4000); + } + else if(mode == fw_image_124k) + { + himax_sram_write(client, (i_TP_CRC_FW_124K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_124K, 0x4000); + } + else if(mode == fw_image_128k) + { + himax_sram_write(client, (i_TP_CRC_FW_128K)); + burnFW_success = himax_sram_verify(client, i_TP_CRC_FW_128K, 0x4000); + } + if (burnFW_success) + { + I("%s: Start to do CRC FW mode=%d \n", __func__,mode); + himax_sense_on(client, 0x00); // run CRC firmware + + while(true) + { + msleep(100); + + tmp_addr[3] = 0x90; + tmp_addr[2] = 0x08; + tmp_addr[1] = 0x80; + tmp_addr[0] = 0x94; + himax_register_read(client, tmp_addr, 1, tmp_data); + + I("%s: CRC from firmware is %x, %x, %x, %x \n", __func__,tmp_data[3], + tmp_data[2],tmp_data[1],tmp_data[0]); + + if (tmp_data[3] == 0xFF && tmp_data[2] == 0xFF && tmp_data[1] == 0xFF && tmp_data[0] == 0xFF) + { + } + else + break; + } + + CRC_value = tmp_data[3]; + + tmp_value = tmp_data[2] << 8; + CRC_value += tmp_value; + + tmp_value = tmp_data[1] << 16; + CRC_value += tmp_value; + + tmp_value = tmp_data[0] << 24; + CRC_value += tmp_value; + + I("%s: CRC Value is %x \n", __func__, CRC_value); + + //Close Remapping + //===================================== + // Re-map close + //===================================== + tmp_addr[3] = 0x90; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x00; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x00; + himax_flash_write_burst_lenth(client, tmp_addr, tmp_data, 4); + return CRC_value; + } + else + { + E("%s: SRAM write fail\n", __func__); + return 0; + } + } + else + I("%s: NO CRC Check File \n", __func__); + + return 0; +} + +bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode) +{ + uint8_t tmp_data[4]; + int i, j; + int fw_data; + int fw_data_2; + int CRC = 0xFFFFFFFF; + int PolyNomial = 0x82F63B78; + int length = 0; + + if (mode == fw_image_128k) + length = 0x8000; + else if (mode == fw_image_124k) + length = 0x7C00; + else if (mode == fw_image_64k) + length = 0x4000; + else //if (mode == fw_image_60k) + length = 0x3C00; + + for (i = 0; i < length; i++) + { + fw_data = FW_content[i * 4 ]; + + for (j = 1; j < 4; j++) + { + fw_data_2 = FW_content[i * 4 + j]; + fw_data += (fw_data_2) << (8 * j); + } + + CRC = fw_data ^ CRC; + + for (j = 0; j < 32; j++) + { + if ((CRC % 2) != 0) + { + CRC = ((CRC >> 1) & 0x7FFFFFFF) ^ PolyNomial; + } + else + { + CRC = (((CRC >> 1) ^ 0x7FFFFFFF)& 0x7FFFFFFF); + } + } + } + + I("%s: CRC calculate from bin file is %x \n", __func__, CRC); + + tmp_data[0] = (uint8_t)(CRC >> 24); + tmp_data[1] = (uint8_t)(CRC >> 16); + tmp_data[2] = (uint8_t)(CRC >> 8); + tmp_data[3] = (uint8_t) CRC; + + CRC = tmp_data[0]; + CRC += tmp_data[1] << 8; + CRC += tmp_data[2] << 16; + CRC += tmp_data[3] << 24; + + I("%s: CRC calculate from bin file REVERSE %x \n", __func__, CRC); + I("%s: CRC calculate from FWis %x \n", __func__, CRC_from_FW); + if (CRC_from_FW == CRC) + return true; + else + return false; +} +#endif + +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) //64k + { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_sector_erase(client, 0x00000)) + { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x0F000); + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_60k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_60k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x10000) //64k + { + E("%s: The file size is not 64K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + himax_flash_programming(client, fw, len); + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_64k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_64k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) //128k + { + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + if (!himax_block_erase(client)) + { + E("%s:Block erase fail!Please restart the IC.\n", __func__); + return false; + } + + if (!himax_sector_erase(client, 0x10000)) + { + E("%s:Sector erase fail!Please restart the IC.\n", __func__); + return false; + } + himax_flash_programming(client, fw, 0x1F000); + + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_124k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_124k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref) +{ + int CRC_from_FW = 0; + int burnFW_success = 0; + + if (len != 0x20000) //128k + { + E("%s: The file size is not 128K bytes\n", __func__); + return false; + } + himax_sense_off(client); + msleep(500); + himax_interface_on(client); + himax_chip_erase(client); + + himax_flash_programming(client, fw, len); + + //burnFW_success = himax_83100_Verify(fw, len); + //if(burnFW_success==false) + // return burnFW_success; + + CRC_from_FW = himax_check_CRC(client,fw_image_128k); + burnFW_success = Calculate_CRC_with_AP(fw, CRC_from_FW,fw_image_128k); + //himax_sense_on(client, 0x01); + return burnFW_success; +} + +void himax_touch_information(struct i2c_client *client) +{ + uint8_t cmd[4]; + char data[12] = {0}; + + I("%s:IC_TYPE =%d\n", __func__,IC_TYPE); + + if(IC_TYPE == HX_83100_SERIES_PWON) + { + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xF8; + himax_register_read(client, cmd, 1, data); + + ic_data->HX_RX_NUM = data[1]; + ic_data->HX_TX_NUM = data[2]; + ic_data->HX_MAX_PT = data[3]; + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xFC; + himax_register_read(client, cmd, 1, data); + + if((data[1] & 0x04) == 0x04) { + ic_data->HX_XY_REVERSE = true; + } else { + ic_data->HX_XY_REVERSE = false; + } + ic_data->HX_Y_RES = data[3]*256; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x01; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + ic_data->HX_Y_RES = ic_data->HX_Y_RES + data[0]; + ic_data->HX_X_RES = data[1]*256 + data[2]; + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x8C; + himax_register_read(client, cmd, 1, data); + if((data[0] & 0x01) == 1) { + ic_data->HX_INT_IS_EDGE = true; + } else { + ic_data->HX_INT_IS_EDGE = false; + } + if (ic_data->HX_RX_NUM > 40) + ic_data->HX_RX_NUM = 29; + if (ic_data->HX_TX_NUM > 20) + ic_data->HX_TX_NUM = 16; + if (ic_data->HX_MAX_PT > 10) + ic_data->HX_MAX_PT = 10; + if (ic_data->HX_Y_RES > 2000) + ic_data->HX_Y_RES = 1280; + if (ic_data->HX_X_RES > 2000) + ic_data->HX_X_RES = 720; +#ifdef HX_EN_MUT_BUTTON + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0xE8; + himax_register_read(client, cmd, 1, data); + ic_data->HX_BT_NUM = data[3]; +#endif + I("%s:HX_RX_NUM =%d,HX_TX_NUM =%d,HX_MAX_PT=%d \n", __func__,ic_data->HX_RX_NUM,ic_data->HX_TX_NUM,ic_data->HX_MAX_PT); + I("%s:HX_XY_REVERSE =%d,HX_Y_RES =%d,HX_X_RES=%d \n", __func__,ic_data->HX_XY_REVERSE,ic_data->HX_Y_RES,ic_data->HX_X_RES); + I("%s:HX_INT_IS_EDGE =%d \n", __func__,ic_data->HX_INT_IS_EDGE); + } + else + { + ic_data->HX_RX_NUM = 0; + ic_data->HX_TX_NUM = 0; + ic_data->HX_BT_NUM = 0; + ic_data->HX_X_RES = 0; + ic_data->HX_Y_RES = 0; + ic_data->HX_MAX_PT = 0; + ic_data->HX_XY_REVERSE = false; + ic_data->HX_INT_IS_EDGE = false; + } +} + +void himax_read_FW_ver(struct i2c_client *client) +{ + uint8_t cmd[4]; + uint8_t data[64] = {0}; + + //===================================== + // Read FW version : 0x0000_E303 + //===================================== + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x00; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[3]<<8; + + cmd[3] = 0x00; cmd[2] = 0x00; cmd[1] = 0xE3; cmd[0] = 0x04; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_config_ver = data[0] | ic_data->vendor_config_ver; + I("CFG_VER : %X \n",ic_data->vendor_config_ver); + + cmd[3] = 0x08; cmd[2] = 0x00; cmd[1] = 0x00; cmd[0] = 0x28; + himax_register_read(client, cmd, 1, data); + + ic_data->vendor_fw_ver = data[0]<<8 | data[1]; + I("FW_VER : %X \n",ic_data->vendor_fw_ver); + + + return; +} + +bool himax_ic_package_check(struct i2c_client *client) +{ +#if 0 + uint8_t cmd[3]; + uint8_t data[3]; + + memset(cmd, 0x00, sizeof(cmd)); + memset(data, 0x00, sizeof(data)); + + if (i2c_himax_read(client, 0xD1, cmd, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false ; + + if (i2c_himax_read(client, 0x31, data, 3, HIMAX_I2C_RETRY_TIMES) < 0) + return false; + + if((data[0] == 0x85 && data[1] == 0x29)) + { + IC_TYPE = HX_85XX_F_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 64901; //0xFD85 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 64902; //0xFD86 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 64928; //0xFDA0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 64940; //0xFDAC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x F\n"); + } + if((data[0] == 0x85 && data[1] == 0x30) || (cmd[0] == 0x05 && cmd[1] == 0x85 && cmd[2] == 0x29)) + { + IC_TYPE = HX_85XX_E_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; //0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x E\n"); + } + else if((data[0] == 0x85 && data[1] == 0x31)) + { + IC_TYPE = HX_85XX_ES_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; //0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; //0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; //0x00A0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; //0x00AC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x ES\n"); + } + else if ((data[0] == 0x85 && data[1] == 0x28) || (cmd[0] == 0x04 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28))) { + IC_TYPE = HX_85XX_D_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 160; // 0x00A0 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 172; // 0x00AC + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x D\n"); + } else if ((data[0] == 0x85 && data[1] == 0x23) || (cmd[0] == 0x03 && cmd[1] == 0x85 && + (cmd[2] == 0x26 || cmd[2] == 0x27 || cmd[2] == 0x28 || cmd[2] == 0x29))) { + IC_TYPE = HX_85XX_C_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 134; // 0x0086 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 135; // 0x0087 + CFG_VER_MAJ_FLASH_LENG = 12; + CFG_VER_MIN_FLASH_ADDR = 147; // 0x0093 + CFG_VER_MIN_FLASH_LENG = 12; + I("Himax IC package 852x C\n"); + } else if ((data[0] == 0x85 && data[1] == 0x26) || + (cmd[0] == 0x02 && cmd[1] == 0x85 && + (cmd[2] == 0x19 || cmd[2] == 0x25 || cmd[2] == 0x26))) { + IC_TYPE = HX_85XX_B_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 133; // 0x0085 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 728; // 0x02D8 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 692; // 0x02B4 + CFG_VER_MAJ_FLASH_LENG = 3; + CFG_VER_MIN_FLASH_ADDR = 704; // 0x02C0 + CFG_VER_MIN_FLASH_LENG = 3; + I("Himax IC package 852x B\n"); + } else if ((data[0] == 0x85 && data[1] == 0x20) || (cmd[0] == 0x01 && + cmd[1] == 0x85 && cmd[2] == 0x19)) { + IC_TYPE = HX_85XX_A_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_SW; + I("Himax IC package 852x A\n"); + } else { + E("Himax IC package incorrect!!\n"); + }*/ +#else + IC_TYPE = HX_83100_SERIES_PWON; + IC_CHECKSUM = HX_TP_BIN_CHECKSUM_CRC; + //Himax: Set FW and CFG Flash Address + FW_VER_MAJ_FLASH_ADDR = 57384; //0xE028 + FW_VER_MAJ_FLASH_LENG = 1; + FW_VER_MIN_FLASH_ADDR = 57385; //0xE029 + FW_VER_MIN_FLASH_LENG = 1; + CFG_VER_MAJ_FLASH_ADDR = 58115; //0xE303 + CFG_VER_MAJ_FLASH_LENG = 1; + CFG_VER_MIN_FLASH_ADDR = 58116; //0xE304 + CFG_VER_MIN_FLASH_LENG = 1; + I("Himax IC package 83100_in\n"); + +#endif + return true; +} + +void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length) +{ + uint8_t cmd[4]; + + cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + } + + i2c_himax_read(client, 0x08, buf, length, HIMAX_I2C_RETRY_TIMES); +} + +#if 0 +static void himax_83100_Flash_Write(uint8_t * reg_byte, uint8_t * write_data) +{ + uint8_t tmpbyte[2]; + + if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if (isBusrtOn == false) + { + tmpbyte[0] = 0x01; + if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } +} +#endif +#if 0 +static void himax_83100_Flash_Burst_Write(uint8_t * reg_byte, uint8_t * write_data) +{ + //uint8_t tmpbyte[2]; + int i = 0; + + if ( i2c_himax_write(private_ts->client, 0x00 ,®_byte[0], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x01 ,®_byte[1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x02 ,®_byte[2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x03 ,®_byte[3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + // Write 256 bytes with continue burst mode + for (i = 0; i < 256; i = i + 4) + { + if ( i2c_himax_write(private_ts->client, 0x04 ,&write_data[i], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x05 ,&write_data[i+1], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x06 ,&write_data[i+2], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + + if ( i2c_himax_write(private_ts->client, 0x07 ,&write_data[i+3], 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + return; + } + } + + //if (isBusrtOn == false) + //{ + // tmpbyte[0] = 0x01; + // if ( i2c_himax_write(private_ts->client, 0x0C ,&tmpbyte[0], 1, 3) < 0) { + // E("%s: i2c access fail!\n", __func__); + // return; + // } + //} + +} +#endif + +#if 0 +static bool himax_83100_Verify(uint8_t *FW_File, int FW_Size) +{ + uint8_t tmp_addr[4]; + uint8_t tmp_data[4]; + uint8_t out_buffer[20]; + uint8_t in_buffer[260]; + + int fail_addr=0, fail_cnt=0; + int page_prog_start = 0; + int i = 0; + + himax_interface_on(private_ts->client); + himax_burst_enable(private_ts->client, 0); + + //===================================== + // SPI Transfer Format : 0x8000_0010 ==> 0x0002_0780 + //===================================== + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x10; + tmp_data[3] = 0x00; tmp_data[2] = 0x02; tmp_data[1] = 0x07; tmp_data[0] = 0x80; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + for (page_prog_start = 0; page_prog_start < FW_Size; page_prog_start = page_prog_start + 256) + { + //================================= + // SPI Transfer Control + // Set 256 bytes page read : 0x8000_0020 ==> 0x6940_02FF + // Set read start address : 0x8000_0028 ==> 0x0000_0000 + // Set command : 0x8000_0024 ==> 0x0000_003B + //================================= + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x20; + tmp_data[3] = 0x69; tmp_data[2] = 0x40; tmp_data[1] = 0x02; tmp_data[0] = 0xFF; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x28; + if (page_prog_start < 0x100) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = 0x00; + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x100 && page_prog_start < 0x10000) + { + tmp_data[3] = 0x00; + tmp_data[2] = 0x00; + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + else if (page_prog_start >= 0x10000 && page_prog_start < 0x1000000) + { + tmp_data[3] = 0x00; + tmp_data[2] = (uint8_t)(page_prog_start >> 16); + tmp_data[1] = (uint8_t)(page_prog_start >> 8); + tmp_data[0] = (uint8_t)page_prog_start; + } + himax_83100_Flash_Write(tmp_addr, tmp_data); + + tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x24; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x00; tmp_data[0] = 0x3B; + himax_83100_Flash_Write(tmp_addr, tmp_data); + + //================================== + // AHB_I2C Burst Read + // Set SPI data register : 0x8000_002C ==> 0x00 + //================================== + out_buffer[0] = 0x2C; + out_buffer[1] = 0x00; + out_buffer[2] = 0x00; + out_buffer[3] = 0x80; + i2c_himax_write(private_ts->client, 0x00 ,out_buffer, 4, HIMAX_I2C_RETRY_TIMES); + + //================================== + // Read access : 0x0C ==> 0x00 + //================================== + out_buffer[0] = 0x00; + i2c_himax_write(private_ts->client, 0x0C ,out_buffer, 1, HIMAX_I2C_RETRY_TIMES); + + //================================== + // Read 128 bytes two times + //================================== + i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[i + page_prog_start] = in_buffer[i]; + + i2c_himax_read(private_ts->client, 0x08 ,in_buffer, 128, HIMAX_I2C_RETRY_TIMES); + for (i = 0; i < 128; i++) + flash_buffer[(i + 128) + page_prog_start] = in_buffer[i]; + + //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + //himax_register_read(tmp_addr, 32, out in_buffer); + //for (int i = 0; i < 128; i++) + // flash_buffer[i + page_prog_start] = in_buffer[i]; + //tmp_addr[3] = 0x80; tmp_addr[2] = 0x00; tmp_addr[1] = 0x00; tmp_addr[0] = 0x2C; + //himax_register_read(tmp_addr, 32, out in_buffer); + //for (int i = 0; i < 128; i++) + // flash_buffer[i + page_prog_start] = in_buffer[i]; + + I("%s:Verify Progress: %x\n", __func__, page_prog_start); + } + + fail_cnt = 0; + for (i = 0; i < FW_Size; i++) + { + if (FW_File[i] != flash_buffer[i]) + { + if (fail_cnt == 0) + fail_addr = i; + + fail_cnt++; + //E("%s Fail Block:%x\n", __func__, i); + //return false; + } + } + if (fail_cnt > 0) + { + E("%s:Start Fail Block:%x and fail block count=%x\n" , __func__,fail_addr,fail_cnt); + return false; + } + + I("%s:Byte read verify pass.\n", __func__); + return true; + +} +#endif + +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data) +{ + int i; + int cnt = 0; + unsigned char tmp_addr[4]; + unsigned char tmp_data[4]; + uint8_t max_i2c_size = 32; + int total_size = ic_data->HX_TX_NUM * ic_data->HX_RX_NUM * 2; + int total_size_4bytes = total_size / 4; + int total_read_times = 0; + unsigned long address = 0x08000468; + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x00; tmp_data[2] = 0x00; tmp_data[1] = 0x5A; tmp_data[0] = 0xA5; + himax_flash_write_burst(client, tmp_addr, tmp_data); + do + { + cnt++; + himax_register_read(client, tmp_addr, 1, tmp_data); + usleep_range(10000, 20000); + } while ((tmp_data[1] != 0xA5 || tmp_data[0] != 0x5A) && cnt < 100); + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x68; + if (total_size_4bytes % max_i2c_size == 0) + { + total_read_times = total_size_4bytes / max_i2c_size; + } + else + { + total_read_times = total_size_4bytes / max_i2c_size + 1; + } + for (i = 0; i < (total_read_times); i++) + { + if ( total_size_4bytes >= max_i2c_size) + { + himax_register_read(client, tmp_addr, max_i2c_size, &info_data[i*max_i2c_size*4]); + total_size_4bytes = total_size_4bytes - max_i2c_size; + } + else + { + himax_register_read(client, tmp_addr, total_size_4bytes % max_i2c_size, &info_data[i*max_i2c_size*4]); + } + address += max_i2c_size*4; + tmp_addr[1] = (uint8_t)((address>>8)&0x00FF); + tmp_addr[0] = (uint8_t)((address)&0x00FF); + } + tmp_addr[3] = 0x08; tmp_addr[2] = 0x00; tmp_addr[1] = 0x04; tmp_addr[0] = 0x64; + tmp_data[3] = 0x11; tmp_data[2] = 0x22; tmp_data[1] = 0x33; tmp_data[0] = 0x44; + himax_flash_write_burst(client, tmp_addr, tmp_data); +} +//ts_work +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max){ + int RawDataLen; + if (raw_cnt_rmd != 0x00) { + RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+3)*4) - 1; + }else{ + RawDataLen = 124 - ((HX_MAX_PT+raw_cnt_max+2)*4) - 1; + } + return RawDataLen; +} + +bool read_event_stack(struct i2c_client *client, uint8_t *buf, int length) +{ + uint8_t cmd[4]; + + if(length > 56) + length = 124; + //===================== + //AHB I2C Burst Read + //===================== + cmd[0] = 0x31; + if ( i2c_himax_write(client, 0x13 ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x10; + if ( i2c_himax_write(client, 0x0D ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + //===================== + //Read event stack + //===================== + cmd[3] = 0x90; cmd[2] = 0x06; cmd[1] = 0x00; cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x00 ,cmd, 4, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + + cmd[0] = 0x00; + if ( i2c_himax_write(client, 0x0C ,cmd, 1, HIMAX_I2C_RETRY_TIMES) < 0) { + E("%s: i2c access fail!\n", __func__); + goto err_workqueue_out; + } + i2c_himax_read(client, 0x08, buf, length,HIMAX_I2C_RETRY_TIMES); + return 1; + + err_workqueue_out: + return 0; +} + +bool post_read_event_stack(struct i2c_client *client) +{ + return 1; +} +bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf) //return checksum value +{ + uint16_t check_sum_cal = 0; + int i; + + //Check 124th byte CRC + for (i = hx_touch_info_size, check_sum_cal = 0; i < 124; i=i+2) + { + check_sum_cal += (buf[i+1]*256 + buf[i]); + } + if (check_sum_cal % 0x10000 != 0) + { + I("%s: diag check sum fail! check_sum_cal=%X, hx_touch_info_size=%d, \n",__func__,check_sum_cal, hx_touch_info_size); + return 0; + } + return 1; +} + + +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data) +{ + int RawDataLen_word; + int index = 0; + int temp1, temp2,i; + + if (buf[hx_touch_info_size] == 0x3A && buf[hx_touch_info_size+1] == 0xA3 && buf[hx_touch_info_size+2] > 0 && buf[hx_touch_info_size+3] == diag_cmd+5 ) + { + RawDataLen_word = RawDataLen/2; + index = (buf[hx_touch_info_size+2] - 1) * RawDataLen_word; + //I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + for (i = 0; i < RawDataLen_word; i++) + { + temp1 = index + i; + + if (temp1 < mul_num) + { //mutual + mutual_data[index + i] = buf[i*2 + hx_touch_info_size+4+1]*256 + buf[i*2 + hx_touch_info_size+4]; //4: RawData Header, 1:HSB + } + else + {//self + temp1 = i + index; + temp2 = self_num + mul_num; + + if (temp1 >= temp2) + { + break; + } + + self_data[i+index-mul_num] = buf[i*2 + hx_touch_info_size+4]; //4: RawData Header + self_data[i+index-mul_num+1] = buf[i*2 + hx_touch_info_size+4+1]; + } + } + } + else + { + I("[HIMAX TP MSG]%s: header format is wrong!\n", __func__); + I("Header[%d]: %x, %x, %x, %x, mutual: %d, self: %d\n", index, buf[56], buf[57], buf[58], buf[59], mul_num, self_num); + } +} diff --git a/drivers/input/touchscreen/hxchipset/himax_ic.h b/drivers/input/touchscreen/hxchipset/himax_ic.h new file mode 100644 index 000000000000..18cd12b8b36f --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_ic.h @@ -0,0 +1,82 @@ +/* Himax Android Driver Sample Code for HMX83100 chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +#include + + +#define HX_85XX_A_SERIES_PWON 1 +#define HX_85XX_B_SERIES_PWON 2 +#define HX_85XX_C_SERIES_PWON 3 +#define HX_85XX_D_SERIES_PWON 4 +#define HX_85XX_E_SERIES_PWON 5 +#define HX_85XX_ES_SERIES_PWON 6 +#define HX_85XX_F_SERIES_PWON 7 +#define HX_83100_SERIES_PWON 8 + +#define HX_TP_BIN_CHECKSUM_SW 1 +#define HX_TP_BIN_CHECKSUM_HW 2 +#define HX_TP_BIN_CHECKSUM_CRC 3 + +enum fw_image_type { + fw_image_60k = 0x01, + fw_image_64k, + fw_image_124k, + fw_image_128k, +}; + +int himax_hand_shaking(struct i2c_client *client); +void himax_set_SMWP_enable(struct i2c_client *client,uint8_t SMWP_enable); +void himax_get_SMWP_enable(struct i2c_client *client,uint8_t *tmp_data); +void himax_set_HSEN_enable(struct i2c_client *client,uint8_t HSEN_enable); +void himax_get_HSEN_enable(struct i2c_client *client,uint8_t *tmp_data); +void himax_diag_register_set(struct i2c_client *client, uint8_t diag_command); +void himax_flash_dump_func(struct i2c_client *client, uint8_t local_flash_command, int Flash_Size, uint8_t *flash_buffer); +int himax_chip_self_test(struct i2c_client *client); +int himax_burst_enable(struct i2c_client *client, uint8_t auto_add_4_byte); ////himax_83100_BURST_INC0_EN +void himax_register_read(struct i2c_client *client, uint8_t *read_addr, int read_length, uint8_t *read_data); ////RegisterRead83100 +void himax_flash_read(struct i2c_client *client, uint8_t *reg_byte, uint8_t *read_data); ////himax_83100_Flash_Read +void himax_flash_write_burst(struct i2c_client *client, uint8_t * reg_byte, uint8_t * write_data); ////himax_83100_Flash_Write_Burst +int himax_flash_write_burst_lenth(struct i2c_client *client, uint8_t *reg_byte, uint8_t *write_data, int length); ////himax_83100_Flash_Write_Burst_lenth +int himax_register_write(struct i2c_client *client, uint8_t *write_addr, int write_length, uint8_t *write_data); ////RegisterWrite83100 +void himax_sense_off(struct i2c_client *client); ////himax_83100_SenseOff +void himax_interface_on(struct i2c_client *client); ////himax_83100_Interface_on +bool wait_wip(struct i2c_client *client, int Timing); +void himax_sense_on(struct i2c_client *client, uint8_t FlashMode); ////himax_83100_SenseOn +void himax_chip_erase(struct i2c_client *client); ////himax_83100_Chip_Erase +bool himax_block_erase(struct i2c_client *client); ////himax_83100_Block_Erase +bool himax_sector_erase(struct i2c_client *client, int start_addr); ////himax_83100_Sector_Erase +void himax_sram_write(struct i2c_client *client, uint8_t *FW_content); ////himax_83100_Sram_Write +bool himax_sram_verify(struct i2c_client *client, uint8_t *FW_File, int FW_Size); ////himax_83100_Sram_Verify +void himax_flash_programming(struct i2c_client *client, uint8_t *FW_content, int FW_Size); ////himax_83100_Flash_Programming +bool himax_check_chip_version(struct i2c_client *client); ////himax_83100_CheckChipVersion +int himax_check_CRC(struct i2c_client *client, int mode); ////himax_83100_Check_CRC +bool Calculate_CRC_with_AP(unsigned char *FW_content , int CRC_from_FW, int mode); +int fts_ctpm_fw_upgrade_with_sys_fs_60k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +int fts_ctpm_fw_upgrade_with_sys_fs_64k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +int fts_ctpm_fw_upgrade_with_sys_fs_124k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +int fts_ctpm_fw_upgrade_with_sys_fs_128k(struct i2c_client *client, unsigned char *fw, int len, bool change_iref); +void himax_touch_information(struct i2c_client *client); +void himax_read_FW_ver(struct i2c_client *client); +bool himax_ic_package_check(struct i2c_client *client); +void himax_read_event_stack(struct i2c_client *client, uint8_t *buf, uint8_t length); +int cal_data_len(int raw_cnt_rmd, int HX_MAX_PT, int raw_cnt_max); +bool read_event_stack(struct i2c_client *client, uint8_t *buf_ts, int length); +bool post_read_event_stack(struct i2c_client *client); +bool diag_check_sum( uint8_t hx_touch_info_size, uint8_t *buf_ts); //return checksum value +void diag_parse_raw_data(int hx_touch_info_size, int RawDataLen, int mul_num, int self_num, uint8_t *buf_ts, uint8_t diag_cmd, int16_t *mutual_data, int16_t *self_data); +void himax_get_DSRAM_data(struct i2c_client *client, uint8_t *info_data); \ No newline at end of file diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.c b/drivers/input/touchscreen/hxchipset/himax_platform.c new file mode 100644 index 000000000000..7e8a1d6572c5 --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.c @@ -0,0 +1,796 @@ +/* Himax Android Driver Sample Code for HIMAX chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#include "himax_platform.h" +#include "himax_common.h" + +int irq_enable_count = 0; +#ifdef HX_SMART_WAKEUP +#define TS_WAKE_LOCK_TIMEOUT (2 * HZ) +#endif + +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" + +extern struct himax_ic_data* ic_data; +extern void himax_ts_work(struct himax_ts_data *ts); +extern enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer); +extern int himax_ts_init(struct himax_ts_data *ts); + +extern int tp_rst_gpio; + +#ifdef HX_TP_PROC_DIAG +extern uint8_t getDiagCommand(void); +#endif + +void himax_vk_parser(struct device_node *dt, + struct himax_i2c_platform_data *pdata) +{ + u32 data = 0; + uint8_t cnt = 0, i = 0; + uint32_t coords[4] = {0}; + struct device_node *node, *pp = NULL; + struct himax_virtual_key *vk; + + node = of_parse_phandle(dt, "virtualkey", 0); + if (node == NULL) { + I(" DT-No vk info in DT"); + return; + } else { + while ((pp = of_get_next_child(node, pp))) + cnt++; + if (!cnt) + return; + + vk = kzalloc(cnt * (sizeof *vk), GFP_KERNEL); + if (!vk) + return; + pp = NULL; + while ((pp = of_get_next_child(node, pp))) { + if (of_property_read_u32(pp, "idx", &data) == 0) + vk[i].index = data; + if (of_property_read_u32_array(pp, "range", coords, 4) == 0) { + vk[i].x_range_min = coords[0], vk[i].x_range_max = coords[1]; + vk[i].y_range_min = coords[2], vk[i].y_range_max = coords[3]; + } else + I(" range faile"); + i++; + } + pdata->virtual_key = vk; + for (i = 0; i < cnt; i++) + I(" vk[%d] idx:%d x_min:%d, y_max:%d", i,pdata->virtual_key[i].index, + pdata->virtual_key[i].x_range_min, pdata->virtual_key[i].y_range_max); + } +} + +int himax_parse_dt(struct himax_ts_data *ts, + struct himax_i2c_platform_data *pdata) +{ + int rc, coords_size = 0; + uint32_t coords[4] = {0}; + struct property *prop; + struct device_node *dt = ts->client->dev.of_node; + u32 data = 0; + + prop = of_find_property(dt, "himax,panel-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid panel coords size %d", __func__, coords_size); + } + + if (of_property_read_u32_array(dt, "himax,panel-coords", coords, coords_size) == 0) { + pdata->abs_x_min = coords[0], pdata->abs_x_max = coords[1]; + pdata->abs_y_min = coords[2], pdata->abs_y_max = coords[3]; + I(" DT-%s:panel-coords = %d, %d, %d, %d\n", __func__, pdata->abs_x_min, + pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max); + } + + prop = of_find_property(dt, "himax,display-coords", NULL); + if (prop) { + coords_size = prop->length / sizeof(u32); + if (coords_size != 4) + D(" %s:Invalid display coords size %d", __func__, coords_size); + } + rc = of_property_read_u32_array(dt, "himax,display-coords", coords, coords_size); + if (rc && (rc != -EINVAL)) { + D(" %s:Fail to read display-coords %d\n", __func__, rc); + return rc; + } + pdata->screenWidth = coords[1]; + pdata->screenHeight = coords[3]; + I(" DT-%s:display-coords = (%d, %d)", __func__, pdata->screenWidth, + pdata->screenHeight); + + pdata->gpio_irq = of_get_named_gpio(dt, "himax,irq-gpio", 0); + if (!gpio_is_valid(pdata->gpio_irq)) { + I(" DT:gpio_irq value is not valid\n"); + } + + pdata->gpio_reset = of_get_named_gpio(dt, "himax,rst-gpio", 0); + if (!gpio_is_valid(pdata->gpio_reset)) { + I(" DT:gpio_rst value is not valid\n"); + } + pdata->gpio_3v3_en = of_get_named_gpio(dt, "himax,3v3-gpio", 0); + if (!gpio_is_valid(pdata->gpio_3v3_en)) { + I(" DT:gpio_3v3_en value is not valid\n"); + } + I(" DT:gpio_irq=%d, gpio_rst=%d, gpio_3v3_en=%d", pdata->gpio_irq, pdata->gpio_reset, pdata->gpio_3v3_en); + + if (of_property_read_u32(dt, "report_type", &data) == 0) { + pdata->protocol_type = data; + I(" DT:protocol_type=%d", pdata->protocol_type); + } + + himax_vk_parser(dt, pdata); + + return 0; +} + +int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 2) == 2) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; + +} + +int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length + 1]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length + 1, + .buf = buf, + } + }; + + buf[0] = command; + memcpy(buf+1, data, length); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; + +} + +int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry) +{ + int retry; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = length, + .buf = data, + } + }; + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + if (retry == toRetry) { + E("%s: i2c_read_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; +} + +int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry) +{ + return i2c_himax_write(client, command, NULL, 0, toRetry); +} + +int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry) +{ + int retry/*, loop_i*/; + uint8_t buf[length]; + + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = length, + .buf = buf, + } + }; + + memcpy(buf, data, length); + + for (retry = 0; retry < toRetry; retry++) { + if (i2c_transfer(client->adapter, msg, 1) == 1) + break; + msleep(20); + } + + if (retry == toRetry) { + E("%s: i2c_write_block retry over %d\n", + __func__, toRetry); + return -EIO; + } + return 0; +} + +void himax_int_enable(int irqnum, int enable) +{ + if (enable == 1 && irq_enable_count == 0) { + enable_irq(irqnum); + irq_enable_count++; + } else if (enable == 0 && irq_enable_count == 1) { + disable_irq_nosync(irqnum); + irq_enable_count--; + } + I("irq_enable_count = %d", irq_enable_count); +} + +void himax_rst_gpio_set(int pinnum, uint8_t value) +{ + gpio_direction_output(pinnum, value); +} + +uint8_t himax_int_gpio_read(int pinnum) +{ + return gpio_get_value(pinnum); +} + +#if defined(CONFIG_HMX_DB) +static int himax_regulator_configure(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int retval; + pdata->vcc_dig = regulator_get(&client->dev, + "vdd"); + if (IS_ERR(pdata->vcc_dig)) + { + E("%s: Failed to get regulator vdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_dig); + return retval; + } + pdata->vcc_ana = regulator_get(&client->dev, + "avdd"); + if (IS_ERR(pdata->vcc_ana)) + { + E("%s: Failed to get regulator avdd\n", + __func__); + retval = PTR_ERR(pdata->vcc_ana); + regulator_put(pdata->vcc_ana); + return retval; + } + + return 0; +}; + +static int himax_power_on(struct himax_i2c_platform_data *pdata, bool on) +{ + int retval; + + if (on) + { + retval = regulator_enable(pdata->vcc_dig); + if (retval) + { + E("%s: Failed to enable regulator vdd\n", + __func__); + return retval; + } + msleep(100); + retval = regulator_enable(pdata->vcc_ana); + if (retval) + { + E("%s: Failed to enable regulator avdd\n", + __func__); + regulator_disable(pdata->vcc_dig); + return retval; + } + } + else + { + regulator_disable(pdata->vcc_dig); + regulator_disable(pdata->vcc_ana); + } + + return 0; +} + +int himax_ts_pinctrl_init(struct himax_ts_data *ts) +{ + int retval; + + /* Get pinctrl if target uses pinctrl */ + ts->ts_pinctrl = devm_pinctrl_get(&(ts->client->dev)); + if (IS_ERR_OR_NULL(ts->ts_pinctrl)) { + retval = PTR_ERR(ts->ts_pinctrl); + dev_dbg(&ts->client->dev, + "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + ts->pinctrl_state_active + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_ACTIVE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_active)) { + retval = PTR_ERR(ts->pinctrl_state_active); + dev_err(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_suspend + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_SUSPEND); + if (IS_ERR_OR_NULL(ts->pinctrl_state_suspend)) { + retval = PTR_ERR(ts->pinctrl_state_suspend); + dev_err(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + + ts->pinctrl_state_release + = pinctrl_lookup_state(ts->ts_pinctrl, + PINCTRL_STATE_RELEASE); + if (IS_ERR_OR_NULL(ts->pinctrl_state_release)) { + retval = PTR_ERR(ts->pinctrl_state_release); + dev_dbg(&ts->client->dev, + "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_RELEASE, retval); + } + + return 0; + +err_pinctrl_lookup: + devm_pinctrl_put(ts->ts_pinctrl); +err_pinctrl_get: + ts->ts_pinctrl = NULL; + return retval; +} + +int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int error; + + error = himax_regulator_configure(client, pdata); + if (error) + { + E("Failed to intialize hardware\n"); + goto err_regulator_not_on; + } + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + { + /* configure touchscreen reset out gpio */ + error = gpio_request(pdata->gpio_reset, "hmx_reset_gpio"); + if (error) + { + E("unable to request gpio [%d]\n", + pdata->gpio_reset); + goto err_regulator_on; + } + + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_reset_req; + } + } +#endif + + error = himax_power_on(pdata, true); + if (error) + { + E("Failed to power on hardware\n"); + goto err_gpio_reset_req; + } +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "hmx_gpio_irq"); + if (error) + { + E("unable to request gpio [%d]\n", + pdata->gpio_irq); + goto err_power_on; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_irq); + goto err_gpio_irq_req; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } + else + { + E("irq gpio not provided\n"); + goto err_power_on; + } +#endif + + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + goto err_gpio_irq_req; + } + } +#endif + return 0; +#ifdef HX_RST_PIN_FUNC + err_gpio_irq_req: +#endif +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + gpio_free(pdata->gpio_irq); + err_power_on: +#endif + himax_power_on(pdata, false); + err_gpio_reset_req: +#ifdef HX_RST_PIN_FUNC + if (gpio_is_valid(pdata->gpio_reset)) + gpio_free(pdata->gpio_reset); + err_regulator_on: +#endif + err_regulator_not_on: + + return error; +} + +#else +int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata) +{ + int error=0; + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) + { + error = gpio_request(pdata->gpio_reset, "himax-reset"); + if (error < 0) + { + E("%s: request reset pin failed\n", __func__); + return error; + } + error = gpio_direction_output(pdata->gpio_reset, 0); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } +#endif + if (pdata->gpio_3v3_en >= 0) + { + error = gpio_request(pdata->gpio_3v3_en, "himax-3v3_en"); + if (error < 0) + { + E("%s: request 3v3_en pin failed\n", __func__); + return error; + } + gpio_direction_output(pdata->gpio_3v3_en, 1); + I("3v3_en pin =%d\n", gpio_get_value(pdata->gpio_3v3_en)); + } + +#ifdef HX_IRQ_PIN_FUNC + if (gpio_is_valid(pdata->gpio_irq)) + { + /* configure touchscreen irq gpio */ + error = gpio_request(pdata->gpio_irq, "himax_gpio_irq"); + if (error) + { + E("unable to request gpio [%d]\n",pdata->gpio_irq); + return error; + } + error = gpio_direction_input(pdata->gpio_irq); + if (error) + { + E("unable to set direction for gpio [%d]\n",pdata->gpio_irq); + return error; + } + client->irq = gpio_to_irq(pdata->gpio_irq); + } + else + { + E("irq gpio not provided\n"); + return error; + } +#endif + + msleep(20); + +#ifdef HX_RST_PIN_FUNC + if (pdata->gpio_reset >= 0) + { + error = gpio_direction_output(pdata->gpio_reset, 1); + if (error) + { + E("unable to set direction for gpio [%d]\n", + pdata->gpio_reset); + return error; + } + } + msleep(20); +#endif + + return error; + } +#endif + +static void himax_ts_isr_func(struct himax_ts_data *ts) +{ + himax_ts_work(ts); +} + +irqreturn_t himax_ts_thread(int irq, void *ptr) +{ + uint8_t diag_cmd; + struct himax_ts_data *ts = ptr; + struct timespec timeStart, timeEnd, timeDelta; + + diag_cmd = getDiagCommand(); + + if (ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeStart); + usleep_range(5000, 7000); + //I(" Irq start time = %ld.%06ld s\n", + // timeStart.tv_sec, timeStart.tv_nsec/1000); + } + +#ifdef HX_SMART_WAKEUP + if (atomic_read(&ts->suspend_mode)&&(!FAKE_POWER_KEY_SEND)&&(ts->SMWP_enable)&&(!diag_cmd)) { + wake_lock_timeout(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT); + msleep(200); + himax_wake_check_func(); + return IRQ_HANDLED; + } +#endif + himax_ts_isr_func((struct himax_ts_data *)ptr); + if(ts->debug_log_level & BIT(2)) { + getnstimeofday(&timeEnd); + timeDelta.tv_nsec = (timeEnd.tv_sec*1000000000+timeEnd.tv_nsec) + -(timeStart.tv_sec*1000000000+timeStart.tv_nsec); + //I("Irq finish time = %ld.%06ld s\n", + // timeEnd.tv_sec, timeEnd.tv_nsec/1000); + //I("Touch latency = %ld us\n", timeDelta.tv_nsec/1000); + } + return IRQ_HANDLED; +} + +static void himax_ts_work_func(struct work_struct *work) +{ + struct himax_ts_data *ts = container_of(work, struct himax_ts_data, work); + himax_ts_work(ts); +} + +int tp_irq = -1; + +int himax_ts_register_interrupt(struct i2c_client *client) +{ + struct himax_ts_data *ts = i2c_get_clientdata(client); + int ret = 0; + + ts->irq_enabled = 0; + //Work functon + if (client->irq) {/*INT mode*/ + ts->use_irq = 1; + if(ic_data->HX_INT_IS_EDGE) + { + I("%s edge triiger falling\n ",__func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, ts); + } + else + { + I("%s level trigger low\n ",__func__); + ret = request_threaded_irq(client->irq, NULL, himax_ts_thread,IRQF_TRIGGER_LOW | IRQF_ONESHOT, client->name, ts); + } + if (ret == 0) { + ts->irq_enabled = 1; + irq_enable_count = 1; + tp_irq = client->irq; + I("%s: irq enabled at qpio: %d\n", __func__, client->irq); +#ifdef HX_SMART_WAKEUP + irq_set_irq_wake(client->irq, 1); +#endif + } else { + ts->use_irq = 0; + E("%s: request_irq failed\n", __func__); + } + } else { + I("%s: client->irq is empty, use polling mode.\n", __func__); + } + + if (!ts->use_irq) {/*if use polling mode need to disable HX_ESD_WORKAROUND function*/ + ts->himax_wq = create_singlethread_workqueue("himax_touch"); + + INIT_WORK(&ts->work, himax_ts_work_func); + + hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ts->timer.function = himax_ts_timer_func; + hrtimer_start(&ts->timer, ktime_set(1, 0), HRTIMER_MODE_REL); + I("%s: polling mode enabled\n", __func__); + } + return ret; +} + +static int himax_common_suspend(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter \n", __func__); + + himax_chip_common_suspend(ts); + return 0; +} + +static int himax_common_resume(struct device *dev) +{ + struct himax_ts_data *ts = dev_get_drvdata(dev); + + I("%s: enter \n", __func__); + + himax_chip_common_resume(ts); + return 0; +} + +#if defined(CONFIG_FB) +int fb_notifier_callback(struct notifier_block *self, + unsigned long event, void *data) +{ + struct fb_event *evdata = data; + int *blank; + struct himax_ts_data *ts= + container_of(self, struct himax_ts_data, fb_notif); + + I(" %s\n", __func__); + if (evdata && evdata->data && event == FB_EVENT_BLANK && ts && + ts->client) { + blank = evdata->data; + + mutex_lock(&ts->fb_mutex); + switch (*blank) { + case FB_BLANK_UNBLANK: + if (!ts->probe_done) { + himax_ts_init(ts); + ts->probe_done = true; + } else { + himax_common_resume(&ts->client->dev); + } + break; + + case FB_BLANK_POWERDOWN: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_NORMAL: + himax_common_suspend(&ts->client->dev); + break; + } + mutex_unlock(&ts->fb_mutex); + } + + return 0; +} +#endif + +static const struct i2c_device_id himax_common_ts_id[] = { + {HIMAX_common_NAME, 0 }, + {} +}; + +static const struct dev_pm_ops himax_common_pm_ops = { +#if (!defined(CONFIG_FB)) + .suspend = himax_common_suspend, + .resume = himax_common_resume, +#endif +}; + +#ifdef CONFIG_OF +static const struct of_device_id himax_match_table[] = { + {.compatible = "himax,hxcommon" }, + {}, +}; +#else +#define himax_match_table NULL +#endif + +static struct i2c_driver himax_common_driver = { + .id_table = himax_common_ts_id, + .probe = himax_chip_common_probe, + .remove = himax_chip_common_remove, + .driver = { + .name = HIMAX_common_NAME, + .owner = THIS_MODULE, + .of_match_table = himax_match_table, +#ifdef CONFIG_PM + .pm = &himax_common_pm_ops, +#endif + }, +}; + +static void __init himax_common_init_async(void *unused, async_cookie_t cookie) +{ + I("%s:Enter \n", __func__); + i2c_add_driver(&himax_common_driver); +} + +static int __init himax_common_init(void) +{ + I("Himax common touch panel driver init\n"); + async_schedule(himax_common_init_async, NULL); + return 0; +} + +static void __exit himax_common_exit(void) +{ + i2c_del_driver(&himax_common_driver); +} + +module_init(himax_common_init); +module_exit(himax_common_exit); + +MODULE_DESCRIPTION("Himax_common driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/touchscreen/hxchipset/himax_platform.h b/drivers/input/touchscreen/hxchipset/himax_platform.h new file mode 100644 index 000000000000..1223685683aa --- /dev/null +++ b/drivers/input/touchscreen/hxchipset/himax_platform.h @@ -0,0 +1,135 @@ +/* Himax Android Driver Sample Code for Himax chipset +* +* Copyright (C) 2015 Himax Corporation. +* +* This software is licensed under the terms of the GNU General Public +* License version 2, as published by the Free Software Foundation, and +* may be copied, distributed, and modified under those terms. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +*/ + +#ifndef HIMAX_PLATFORM_H +#define HIMAX_PLATFORM_H + +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_HMX_DB) +#include +#endif + +#define QCT + +#define HIMAX_I2C_RETRY_TIMES 10 + +#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG) +#define D(x...) pr_debug("[HXTP] " x) +#define I(x...) pr_info("[HXTP] " x) +#define W(x...) pr_warning("[HXTP][WARNING] " x) +#define E(x...) pr_err("[HXTP][ERROR] " x) +#define DIF(x...) \ +do {\ + if (debug_flag) \ + pr_debug("[HXTP][DEBUG] " x) \ +} while(0) +#else +#define D(x...) +#define I(x...) +#define W(x...) +#define E(x...) +#define DIF(x...) +#endif + +#if defined(CONFIG_HMX_DB) +/* Analog voltage @2.7 V */ +#define HX_VTG_MIN_UV 2700000 +#define HX_VTG_MAX_UV 3300000 +#define HX_ACTIVE_LOAD_UA 15000 +#define HX_LPM_LOAD_UA 10 +/* Digital voltage @1.8 V */ +#define HX_VTG_DIG_MIN_UV 1800000 +#define HX_VTG_DIG_MAX_UV 1800000 +#define HX_ACTIVE_LOAD_DIG_UA 10000 +#define HX_LPM_LOAD_DIG_UA 10 + +#define HX_I2C_VTG_MIN_UV 1800000 +#define HX_I2C_VTG_MAX_UV 1800000 +#define HX_I2C_LOAD_UA 10000 +#define HX_I2C_LPM_LOAD_UA 10 +#endif + +#define HIMAX_common_NAME "himax_tp" +#define HIMAX_I2C_ADDR 0x48 +#define INPUT_DEV_NAME "himax-touchscreen" + +struct himax_i2c_platform_data { + int abs_x_min; + int abs_x_max; + int abs_x_fuzz; + int abs_y_min; + int abs_y_max; + int abs_y_fuzz; + int abs_pressure_min; + int abs_pressure_max; + int abs_pressure_fuzz; + int abs_width_min; + int abs_width_max; + int screenWidth; + int screenHeight; + uint8_t fw_version; + uint8_t tw_id; + uint8_t powerOff3V3; + uint8_t cable_config[2]; + uint8_t protocol_type; + int gpio_irq; + int gpio_reset; + int gpio_3v3_en; + int (*power)(int on); + void (*reset)(void); + struct himax_virtual_key *virtual_key; + struct kobject *vk_obj; + struct kobj_attribute *vk2Use; + + struct himax_config *hx_config; + int hx_config_size; +#if defined(CONFIG_HMX_DB) + bool i2c_pull_up; + bool digital_pwr_regulator; + int reset_gpio; + u32 reset_gpio_flags; + int irq_gpio; + u32 irq_gpio_flags; + + struct regulator *vcc_ana; //For Dragon Board + struct regulator *vcc_dig; //For Dragon Board + struct regulator *vcc_i2c; //For Dragon Board +#endif +}; + + +extern int irq_enable_count; +extern int i2c_himax_read(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_write(struct i2c_client *client, uint8_t command, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_write_command(struct i2c_client *client, uint8_t command, uint8_t toRetry); +extern int i2c_himax_master_write(struct i2c_client *client, uint8_t *data, uint8_t length, uint8_t toRetry); +extern int i2c_himax_read_command(struct i2c_client *client, uint8_t length, uint8_t *data, uint8_t *readlength, uint8_t toRetry); +extern void himax_int_enable(int irqnum, int enable); +extern int himax_ts_register_interrupt(struct i2c_client *client); +extern void himax_rst_gpio_set(int pinnum, uint8_t value); +extern uint8_t himax_int_gpio_read(int pinnum); + +extern int himax_gpio_power_config(struct i2c_client *client,struct himax_i2c_platform_data *pdata); + +#if defined(CONFIG_FB) +extern int fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data); +#endif + +#endif -- GitLab From 6a75f69de53115feb7f0cf07131f7dee16d07289 Mon Sep 17 00:00:00 2001 From: Vijay Navnath Kamble Date: Tue, 3 Apr 2018 16:52:35 +0530 Subject: [PATCH 1784/1834] defconfig: msm8953: Add himax touch support Enable himax touch driver in msm8953_defconfig and msm8953-perf_defconfig. Change-Id: I7c135be4f75562c769a3840d6a34d9197785a716 Signed-off-by: Vijay Navnath Kamble --- arch/arm/configs/msm8953-perf_defconfig | 4 ++++ arch/arm/configs/msm8953_defconfig | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 2ba24d9f84b1..9dfdd88e5229 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -307,6 +307,10 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 829901843a3f..3bea49fe87da 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -312,6 +312,10 @@ CONFIG_INPUT_JOYSTICK=y CONFIG_INPUT_TOUCHSCREEN=y CONFIG_TOUCHSCREEN_FT5X06=y CONFIG_TOUCHSCREEN_GEN_VKEYS=y +CONFIG_TOUCHSCREEN_HIMAX_CHIPSET=y +CONFIG_TOUCHSCREEN_HIMAX_I2C=y +CONFIG_TOUCHSCREEN_HIMAX_DEBUG=y +CONFIG_HMX_DB=y CONFIG_INPUT_MISC=y CONFIG_INPUT_HBTP_INPUT=y CONFIG_INPUT_QPNP_POWER_ON=y -- GitLab From 7a92d57bc1d4da80f0568aab8d9421439bd1db3e Mon Sep 17 00:00:00 2001 From: Anurag Chouhan Date: Thu, 3 May 2018 16:59:40 +0530 Subject: [PATCH 1785/1834] icnss: Check force error fatal before the early indication check Currently, force error fatal is neglected in case if early indication is received from the firmware. check for the force error fatal before checking the early indication. Change-Id: I491b4342e90ea171839dd86e8764a63b147d65a3 Signed-off-by: Anurag Chouhan --- drivers/soc/qcom/icnss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 683b074a862e..c2542996eb91 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -2453,6 +2453,9 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, if (!test_bit(ICNSS_WLFW_EXISTS, &priv->state)) goto out; + if (priv->force_err_fatal) + ICNSS_ASSERT(0); + if (priv->early_crash_ind) { icnss_pr_dbg("PD Down ignored as early indication is processed: %d, state: 0x%lx\n", event_data->crashed, priv->state); @@ -2467,9 +2470,6 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, goto out; } - if (priv->force_err_fatal) - ICNSS_ASSERT(0); - icnss_fw_crashed(priv, event_data); out: -- GitLab From 71d44ab6bb0012a6afc55602e24f1970fe913af3 Mon Sep 17 00:00:00 2001 From: "Chinkit Kumar,Kirti Kumar Parmar" Date: Fri, 4 May 2018 15:34:34 +0530 Subject: [PATCH 1786/1834] arm: Kconfig: Add support for HWDEP for 32-bit QCOM target Audio driver is dependent on HWDEP. Enable HWDEP as dependency in kconfig. Change-Id: I07706414517ca4aabe4090ce278e9dfbeabc3ca5 Signed-off-by: Chinkit Kumar,Kirti Kumar Parmar Signed-off-by: Sundara Vinayagam --- arch/arm/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 04b1c061c927..54e93a006618 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -574,6 +574,7 @@ config ARCH_QCOM select PINCTRL select ARCH_WANT_KMAP_ATOMIC_FLUSH select SND_SOC_COMPRESS + select SND_HWDEP help Support for Qualcomm MSM/QSD based systems. This runs on the apps processor of the MSM/QSD and depends on a shared memory -- GitLab From 31ff143a4ba566e40a6dbbba5ce01d333eb78d09 Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Wed, 9 May 2018 19:49:48 -0700 Subject: [PATCH 1787/1834] perf: Add exclude_idle support for armv7 PMU By adding the exclude_idle support, the driver would update the PMU counter values into event->count right before it goes into an idle state. This way, even if the client, from another core, tries to read the value during this idle period, it would return the last updated value before moving into idle without waking the idle core up. Change-Id: Iccc9a9d73e7079b27d0e2978bd286c4c464ce28f Signed-off-by: Raghavendra Rao Ananta --- arch/arm/kernel/perf_event_v7.c | 81 +++++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 13 deletions(-) diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 4f9e2b54bb8e..5b6cb335cf54 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -1066,8 +1066,6 @@ static int armv7pmu_set_event_filter(struct hw_perf_event *event, { unsigned long config_base = 0; - if (attr->exclude_idle) - return -EPERM; if (attr->exclude_user) config_base |= ARMV7_EXCLUDE_USER; if (attr->exclude_kernel) @@ -1184,11 +1182,68 @@ static void armv7_read_num_pmnc_events(void *info) *nb_cnt += 1; } -static int armv7_probe_num_events(struct arm_pmu *arm_pmu) +static void armv7_pmu_idle_update(struct arm_pmu *cpu_pmu) { - return smp_call_function_any(&arm_pmu->supported_cpus, + struct pmu_hw_events *hw_events; + struct perf_event *event; + int idx; + + if (!cpu_pmu) + return; + + hw_events = this_cpu_ptr(cpu_pmu->hw_events); + if (!hw_events) + return; + + for (idx = 0; idx < cpu_pmu->num_events; ++idx) { + event = hw_events->events[idx]; + + if (!event || !event->attr.exclude_idle || + event->state != PERF_EVENT_STATE_ACTIVE) + continue; + + cpu_pmu->pmu.read(event); + } +} + +struct armv7_pmu_idle_nb { + struct arm_pmu *cpu_pmu; + struct notifier_block perf_cpu_idle_nb; +}; + +static int armv7_pmu_idle_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct armv7_pmu_idle_nb *pmu_idle_nb = container_of(nb, + struct armv7_pmu_idle_nb, perf_cpu_idle_nb); + + if (action == IDLE_START) + armv7_pmu_idle_update(pmu_idle_nb->cpu_pmu); + + return NOTIFY_OK; +} + +static int armv7_probe_pmu(struct arm_pmu *arm_pmu) +{ + int ret; + struct armv7_pmu_idle_nb *pmu_idle_nb; + + pmu_idle_nb = devm_kzalloc(&arm_pmu->plat_device->dev, + sizeof(*pmu_idle_nb), GFP_KERNEL); + if (!pmu_idle_nb) + return -ENOMEM; + + ret = smp_call_function_any(&arm_pmu->supported_cpus, armv7_read_num_pmnc_events, &arm_pmu->num_events, 1); + if (ret) + return ret; + + pmu_idle_nb->cpu_pmu = arm_pmu; + pmu_idle_nb->perf_cpu_idle_nb.notifier_call = armv7_pmu_idle_notifier; + idle_notifier_register(&pmu_idle_nb->perf_cpu_idle_nb); + + return 0; } static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) @@ -1200,7 +1255,7 @@ static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu) &armv7_pmuv1_events_attr_group; cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &armv7_pmu_format_attr_group; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu) @@ -1212,7 +1267,7 @@ static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu) &armv7_pmuv1_events_attr_group; cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &armv7_pmu_format_attr_group; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu) @@ -1224,7 +1279,7 @@ static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu) &armv7_pmuv1_events_attr_group; cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &armv7_pmu_format_attr_group; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu) @@ -1237,7 +1292,7 @@ static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu) &armv7_pmuv2_events_attr_group; cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &armv7_pmu_format_attr_group; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) @@ -1250,7 +1305,7 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu) &armv7_pmuv2_events_attr_group; cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &armv7_pmu_format_attr_group; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) @@ -1263,7 +1318,7 @@ static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu) &armv7_pmuv2_events_attr_group; cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = &armv7_pmu_format_attr_group; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu) @@ -1660,7 +1715,7 @@ static int krait_pmu_init(struct arm_pmu *cpu_pmu) cpu_pmu->disable = krait_pmu_disable_event; cpu_pmu->get_event_idx = krait_pmu_get_event_idx; cpu_pmu->clear_event_idx = krait_pmu_clear_event_idx; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } /* @@ -1983,7 +2038,7 @@ static int scorpion_pmu_init(struct arm_pmu *cpu_pmu) cpu_pmu->disable = scorpion_pmu_disable_event; cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) @@ -1996,7 +2051,7 @@ static int scorpion_mp_pmu_init(struct arm_pmu *cpu_pmu) cpu_pmu->disable = scorpion_pmu_disable_event; cpu_pmu->get_event_idx = scorpion_pmu_get_event_idx; cpu_pmu->clear_event_idx = scorpion_pmu_clear_event_idx; - return armv7_probe_num_events(cpu_pmu); + return armv7_probe_pmu(cpu_pmu); } static const struct of_device_id armv7_pmu_of_device_ids[] = { -- GitLab From 805b65816dbe98837f89e6e773c7480d93a5011e Mon Sep 17 00:00:00 2001 From: Raghavendra Rao Ananta Date: Mon, 7 May 2018 11:09:22 -0700 Subject: [PATCH 1788/1834] ARM: dts: msm: Do not initialize the reset line for sda845+sdx24 In the event of the modem error fatal, it excepts the APQ to hold the reset line as it is during its bootup. Initializing this to LOW would trigger a cold reset on the modem. As a result, the modem is powered-off, and the ramdumps are lost. Avoiding initializing the reset gpio to LOW would hold the modem up (unchanged) and the ramdumps are available. Change-Id: I7e1c50583d74cbe9c113086940e78c7ad7901ec4 Signed-off-by: Raghavendra Rao Ananta --- arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi index 0b678a86f3e7..c4b4a5030c43 100644 --- a/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi +++ b/arch/arm64/boot/dts/qcom/sda845-sdxpoorwills.dtsi @@ -32,7 +32,6 @@ /* MDM PON conrol*/ pins = "gpio10"; function = "normal"; - output-low; power-source = <0>; }; }; -- GitLab From 9cb4d21343bb5a95bae5e0b87718794636fa6797 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Mon, 14 May 2018 18:35:41 -0700 Subject: [PATCH 1789/1834] msm: ipa4: IPA PM Unit tests init fix Destroy the PM before unit testing since every test case will re-init the PM with their own parameters. Take out rpmh dependency for unit tests and move in ipa.c. Change-Id: I4975340b7ba0210aebe0631778fe85c4023feb11 CRs-fixed: 2238471 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa.c | 8 +++-- drivers/platform/msm/ipa/test/ipa_pm_ut.c | 40 +++++++++++++++-------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 9eb3c352d832..c523b3d1eae8 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -3947,16 +3947,18 @@ int ipa3_set_clock_plan_from_pm(int idx) { u32 clk_rate; - if (!ipa3_ctx->enable_clock_scaling) + IPADBG_LOW("idx = %d\n", idx); + + if (!ipa3_ctx->enable_clock_scaling) { + ipa3_ctx->ipa3_active_clients.bus_vote_idx = idx; return 0; + } if (ipa3_ctx->ipa3_hw_mode != IPA_HW_MODE_NORMAL) { IPAERR("not supported in this mode\n"); return 0; } - IPADBG_LOW("idx = %d\n", idx); - if (idx <= 0 || idx >= ipa3_ctx->ctrl->msm_bus_data_ptr->num_usecases) { IPAERR("bad voltage\n"); return -EINVAL; diff --git a/drivers/platform/msm/ipa/test/ipa_pm_ut.c b/drivers/platform/msm/ipa/test/ipa_pm_ut.c index e07040a73e28..83b705d42019 100644 --- a/drivers/platform/msm/ipa/test/ipa_pm_ut.c +++ b/drivers/platform/msm/ipa/test/ipa_pm_ut.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,18 +23,32 @@ struct callback_param { static int ipa_pm_ut_setup(void **ppriv) { + int i; IPA_UT_DBG("Start Setup\n"); /* decrement UT vote */ IPA_ACTIVE_CLIENTS_DEC_SPECIAL("IPA_UT"); + /*decouple PM from RPM */ + ipa3_ctx->enable_clock_scaling = false; + + if (ipa3_ctx->use_ipa_pm) { + for (i = 0; i < IPA_PM_MAX_CLIENTS; i++) { + ipa_pm_deactivate_sync(i); + ipa_pm_deregister(i); + } + + ipa_pm_destroy(); + } + return 0; } static int ipa_pm_ut_teardown(void *priv) { IPA_UT_DBG("Start Teardown\n"); + IPA_UT_ERR("WARNING: IPA_PM HAS BEEN DESTROYED, REBOOT TO RE_INIT\n"); /* undo UT vote */ IPA_ACTIVE_CLIENTS_INC_SPECIAL("IPA_UT"); @@ -106,7 +120,7 @@ static int ipa_pm_ut_single_registration(void *priv) struct callback_param user_data; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -223,7 +237,7 @@ static int ipa_pm_ut_double_register_activate(void *priv) struct callback_param user_data; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -327,7 +341,7 @@ static int ipa_pm_ut_deferred_deactivate(void *priv) struct callback_param user_data; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -436,7 +450,7 @@ static int ipa_pm_ut_two_clients_activate(void *priv) struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -648,7 +662,7 @@ static int ipa_pm_ut_deactivate_all_deferred(void *priv) struct callback_param user_data; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -797,7 +811,7 @@ static int ipa_pm_ut_deactivate_after_activate(void *priv) struct callback_param user_data; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -885,7 +899,7 @@ static int ipa_pm_ut_atomic_activate(void *priv) unsigned long flags; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -957,7 +971,7 @@ static int ipa_pm_ut_deactivate_loop(void *priv) int i, hdl_USB, hdl_WLAN, vote; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -1095,7 +1109,7 @@ static int ipa_pm_ut_set_perf_profile(void *priv) int hdl_USB, hdl_WLAN, vote, idx; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -1210,7 +1224,7 @@ static int ipa_pm_ut_group_tput(void *priv) int hdl_USB, hdl_WLAN, hdl_MODEM, vote, idx; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -1377,7 +1391,7 @@ static int ipa_pm_ut_skip_clk_vote_tput(void *priv) int hdl_USB, hdl_WLAN, hdl_MODEM, vote, idx; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000} }; @@ -1542,7 +1556,7 @@ static int ipa_pm_ut_simple_exception(void *priv) }; struct ipa_pm_init_params init_params = { - .threshold_size = IPA_PM_THRESHOLD_MAX, + .threshold_size = 2, .default_threshold = {600, 1000}, .exception_size = 1, .exceptions[0] = exceptions, -- GitLab From 2b9efc4da6169f7778da29106b3dcc7096be9c36 Mon Sep 17 00:00:00 2001 From: Sundara Vinayagam Date: Sat, 7 Apr 2018 21:51:28 +0530 Subject: [PATCH 1790/1834] ARM: dts: msm: Aligning DT files based on 4.9 kernel for msm8909w Minor changes are done on implementation of dt nodes and remove deprecated changes from 3.18 kernel. Change-Id: If5f30ec051edd92908b24393f2552db5eefec855 Signed-off-by: Sundara Vinayagam Signed-off-by: Sanjib Ranjan Pradhan --- .../devicetree/bindings/arm/coresight.txt | 222 +---- .../bindings/arm/msm/lpm-workarounds.txt | 55 -- Documentation/devicetree/bindings/mcd/mcd.txt | 29 - .../boot/dts/qcom/msm8909-coresight.dtsi | 908 ++++++++++-------- arch/arm64/boot/dts/qcom/msm8909-ion.dtsi | 6 - arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi | 24 - arch/arm64/boot/dts/qcom/msm8909.dtsi | 13 - 7 files changed, 522 insertions(+), 735 deletions(-) delete mode 100644 Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt delete mode 100644 Documentation/devicetree/bindings/mcd/mcd.txt diff --git a/Documentation/devicetree/bindings/arm/coresight.txt b/Documentation/devicetree/bindings/arm/coresight.txt index bda03f0863e1..3a966104a258 100644 --- a/Documentation/devicetree/bindings/arm/coresight.txt +++ b/Documentation/devicetree/bindings/arm/coresight.txt @@ -1,222 +1,12 @@ * CoreSight Components: CoreSight components are compliant with the ARM CoreSight architecture -specification and can be connected in various topologies to suite a particular -SoCs tracing needs. These trace components can generally be classified as sinks, -links and sources. Trace data produced by one or more sources flows through the -intermediate links connecting the source to the currently selected sink. Each -CoreSight component device should use these properties to describe its hardware -characteristcs. - -Required properties: - -- compatible : name of the component used for driver matching, should be one of - the following: - "arm,coresight-tmc" for coresight tmc-etr or tmc-etf device, - "arm,coresight-tpiu" for coresight tpiu device, - "qcom,coresight-replicator" for coresight replicator device, - "arm,coresight-funnel" for coresight funnel devices, - "qcom,coresight-tpda" for coresight tpda device, - "qcom,coresight-tpdm" for coresight tpdm device, - "qcom,coresight-dbgui" for coresight dbgui device - "arm,coresight-stm" for coresight stm trace device, - "arm,coresight-etm" for coresight etm trace devices, - "arm,coresight-etmv4" for coresight etmv4 trace devices, - "qcom,coresight-csr" for coresight csr device, - "arm,coresight-cti" for coresight cti devices, - "qcom,coresight-hwevent" for coresight hardware event devices - "arm,coresight-fuse" for coresight fuse v1 device, - "arm,coresight-fuse-v2" for coresight fuse v2 device, - "arm,coresight-fuse-v3" for coresight fuse v3 device, - "qcom,coresight-remote-etm" for coresight remote processor etm trace device, - "qcom,coresight-qpdi" for coresight qpdi device -- reg : physical base address and length of the register set(s) of the component. - Not required for the following compatible string: - - "qcom,coresight-remote-etm" -- reg-names : names corresponding to each reg property value. - Not required for the following compatible string: - - "qcom,coresight-remote-etm" - The reg-names that need to be used with corresponding compatible string - for a coresight device are: - - for coresight tmc-etr or tmc-etf device: - compatible : should be "arm,coresight-tmc" - reg-names : should be: - "tmc-base" - physical base address of tmc configuration - registers - "bam-base" - physical base address of tmc-etr bam registers - - for coresight tpiu device: - compatible : should be "arm,coresight-tpiu" - reg-names : should be: - "tpiu-base" - physical base address of tpiu registers - - for coresight replicator device - compatible : should be "qcom,coresight-replicator" - reg-names : should be: - "replicator-base" - physical base address of replicator - registers - - for coresight funnel devices - compatible : should be "arm,coresight-funnel" - reg-names : should be: - "funnel-base" - physical base address of funnel registers - - for coresight tpda trace device - compatible : should be "qcom,coresight-tpda" - reg-names : should be: - "tpda-base" - physical base address of tpda registers - - for coresight tpdm trace device - compatible : should be "qcom,coresight-tpdm" - reg-names : should be: - "tpdm-base" - physical base address of tpdm registers - - for coresight dbgui device: - compatible : should be "qcom,coresight-dbgui" - reg-names : should be: - "dbgui-base" - physical base address of dbgui registers - - for coresight stm trace device - compatible : should be "arm,coresight-stm" - reg-names : should be: - "stm-base" - physical base address of stm configuration - registers - "stm-data-base" - physical base address of stm data registers - - for coresight etm trace devices - compatible : should be "arm,coresight-etm" - reg-names : should be: - "etm-base" - physical base address of etm registers - - for coresight etmv4 trace devices - compatible : should be "arm,coresight-etmv4" - reg-names : should be: - "etm-base" - physical base address of etmv4 registers - - for coresight csr device: - compatible : should be "qcom,coresight-csr" - reg-names : should be: - "csr-base" - physical base address of csr registers - - for coresight cti devices: - compatible : should be "arm,coresight-cti" - reg-names : should be: - "cti-base" - physical base address of cti registers - - for coresight hardware event devices: - compatible : should be "qcom,coresight-hwevent" - reg-names : should be: - "" - physical base address of hardware event mux - control registers where is subsystem mux it - represents - - for coresight fuse device: - compatible : should be "arm,coresight-fuse" - reg-names : should be: - "fuse-base" - physical base address of fuse registers - "nidnt-fuse-base" - physical base address of nidnt fuse registers - "qpdi-fuse-base" - physical base address of qpdi fuse registers - - for coresight qpdi device: - compatible : should be "qcom,coresight-qpdi" - reg-names : should be: - "qpdi-base" - physical base address of qpdi registers -- coresight-id : unique integer identifier for the component -- coresight-name : unique descriptive name of the component -- coresight-nr-inports : number of input ports on the component - -Optional properties: - -- coresight-outports : list of output port numbers of this component -- coresight-child-list : list of phandles pointing to the children of this - component -- coresight-child-ports : list of input port numbers of the children -- coresight-default-sink : represents the default compile time CoreSight sink -- coresight-ctis : list of ctis that this component interacts with -- qcom,cti-save : boolean, indicating cti context needs to be saved and restored -- qcom,cti-hwclk : boolean, indicating support of hardware clock to access cti - registers to be saved and restored -- qcom,cti-gpio-trigin : cti trigger input driven by gpio -- qcom,cti-gpio-trigout : cti trigger output sent to gpio -- qcom,pc-save : program counter save implemented -- qcom,blk-size : block size for tmc-etr to usb transfers -- qcom,memory-size : size of coherent memory to be allocated for tmc-etr buffer -- qcom,round-robin : indicates if per core etms are allowed round-robin access - by the funnel -- qcom,write-64bit : only 64bit data writes supported by stm -- qcom,data-barrier : barrier required for every stm data write to channel space -- -supply: phandle to the regulator device tree node. The required - is "vdd" for SD card and "vdd-io" for SD - I/O supply. Used for tpiu component -- qcom,-voltage-level : specifies voltage level for vdd supply. Should - be specified in pairs (min, max) with units - being uV. Here can be "vdd" for SD card - vdd supply or "vdd-io" for SD I/O vdd supply. -- qcom,-current-level : specifies current load levels for vdd supply. - Should be specified in pairs (lpm, hpm) with - units being uA. Here can be "vdd" for - SD card vdd supply or "vdd-io" for SD I/O vdd - supply. -- qcom,hwevent-clks : list of clocks required by hardware event driver -- qcom,hwevent-regs : list of regulators required by hardware event driver -- qcom,byte-cntr-absent : specifies if the byte counter feature is absent on - the device. Only relevant in case of tmc-etr device. -- interrupts : where a is 0 or 1 depending on if the interrupt is - spi/ppi, b is the interrupt number and c is the mask, -- interrupt-names : a list of strings that map in order to the list of - interrupts specified in the 'interrupts' property. -- qcom,sg-enable : indicates whether scatter gather feature is supported for TMC - ETR configuration. -- qcom,force-reg-dump : boolean, indicate whether TMC register need to be dumped. - Used for TMC component -- qcom,nidntsw : boolean, indicating NIDnT software debug or trace support - present. Used for tpiu component -- qcom,nidnthw : boolean, indicating NIDnT hardware sensing support present. - Used for tpiu component - qcom,nidntsw and qcom,nidnthw are mutually exclusive properties, either of - these may specified for tpiu component -- qcom,nidnt-swduart : boolean, indicating NIDnT swd uart support present. Used - for tpiu component -- qcom,nidnt-swdtrc : boolean, indicating NIDnT swd trace support present. Used - for tpiu component -- qcom,nidnt-jtag : boolean, indicating NIDnT jtag debug support present. Used - for tpiu component -- qcom,nidnt-spmi : boolean, indicating NIDnT spmi debug support present. Used - for tpiu component -- nidnt-gpio : specifies gpio for NIDnT hardware detection -- nidnt-gpio-polarity : specifies gpio polarity for NIDnT hardware detection -- pinctrl-names : names corresponding to the numbered pinctrl. The allowed - names are subset of the following: cti-trigin-pctrl, - cti-trigout-pctrl. Used for cti component -- pinctrl-: list of pinctrl phandles for the different pinctrl states. Refer - to "Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt". -- qcom,funnel-save-restore : boolean, indicating funnel port needs to be disabled - for the ETM whose CPU is being powered down. The port - state is restored when CPU is powered up. Used for - funnel component. -- qcom,tmc-flush-powerdown : boolean, indicating trace data needs to be flushed before - powering down CPU. Used for TMC component. -- qcom,bc-elem-size : specifies the BC element size supported by each monitor - connected to the aggregator on each port. Should be specified - in pairs (port, bc element size). -- qcom,tc-elem-size : specifies the TC element size supported by each monitor - connected to the aggregator on each port. Should be specified - in pairs (port, tc element size). -- qcom,dsb-elem-size : specifies the DSB element size supported by each monitor - connected to the aggregator on each port. Should be specified - in pairs (port, dsb element size). -- qcom,cmb-elem-size : specifies the CMB element size supported by each monitor - connected to the aggregator on each port. Should be specified - in pairs (port, cmb element size). -- qcom,clk-enable: specifies whether additional clock bit needs to be set for - M4M TPDM. -- qcom,tpda-atid : specifies the ATID for TPDA. -- qcom,inst-id : QMI instance id for remote ETMs. -- qcom,noovrflw-enable : boolean, indicating whether no overflow bit needs to be - set in ETM stall control register. -- coresight-cti-cpu : cpu phandle for cpu cti, required when qcom,cti-save is true -- coresight-etm-cpu : specifies phandle for the cpu associated with the ETM device -- qcom,dbgui-addr-offset : indicates the offset of dbgui address registers -- qcom,dbgui-data-offset : indicates the offset of dbgui data registers -- qcom,dbgui-size : indicates the size of dbgui address and data registers -- qcom,pmic-carddetect-gpio : indicates the hotplug capabilities of the qpdi driver -- qcom,cpuss-debug-cgc: debug clock gating phandle for etm - reg : the clock gating register for each cluster - cluster : indicate the cluster number - -coresight-outports, coresight-child-list and coresight-child-ports lists will -be of the same length and will have a one to one correspondence among the -elements at the same list index. - -coresight-default-sink must be specified for one of the sink devices that is -intended to be made the default sink. Other sink devices must not have this -specified. Not specifying this property on any of the sinks is invalid. +specification and can be connected in various topologies to suit a particular +SoCs tracing needs. These trace components can generally be classified as +sinks, links and sources. Trace data produced by one or more sources flows +through the intermediate links connecting the source to the currently selected +sink. Each CoreSight component device should use these properties to describe +its hardware characteristcs. * Required properties for all components *except* non-configurable replicators: diff --git a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt b/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt deleted file mode 100644 index 0304035492a1..000000000000 --- a/Documentation/devicetree/bindings/arm/msm/lpm-workarounds.txt +++ /dev/null @@ -1,55 +0,0 @@ -* LPM Workarounds - -The required properties are: - -- compatible: "qcom,lpm-workarounds" - -The optional properties are: -- reg: The physical address and the size of the l1_l2_gcc and l2_pwr_sts - regitsters of performance cluster. - -- reg-names: "l2_pwr_sts" - string to identify l2_pwr_sts physical address. - "l1_l2_gcc" - string to identify l1_l2_gcc physical address. - -- qcom,lpm-wa-cx-turbo-unvote: Indicates the workaround to unvote CX turbo - vote when system is coming out of rpm assisted power collaspe. - lpm-cx-supply is required if this is present. - -- lpm-cx-supply: will hold handle for CX regulator supply which is used - to unvote. - -- qcom,lpm-wa-skip-l2-spm: Due to a hardware bug on 8939 and 8909, secure - world needs to disable and enable L2 SPM to get the proper context - in secure watchdog bite cases. With this workaround there is a race - in programming L2 SPM between HLOS and secure world. This leads to - stability issues. To avoid this program L2 SPM only in secure world - based on the L2 mode flag passed. Set lpm-wa-skip-l2-spm node if this - is required. - -- qcom,lpm-wa-dynamic-clock-gating: Due to a hardware bug on 8952, L1/L2 dynamic - clock gating needs to be enabled by software for performance cluster - cores and L2. Set lpm-wa-dynamic-clock-gating node if this workaround is - required. - -- qcom,cpu-offline-mask: Dynamic clock gating should be enabled when cluster is - in L2 PC. Each bit of cpu-offline-mask lists the cpu no. to hotplug by KTM - driver. - -- qcom,non-boot-cpu-index: will hold index of non boot cluster cpu. - -- qcom,l1-l2-gcc-secure: indicates L1/L2 clock enabling register is secure. - -Example: - -qcom,lpm-workarounds { - compatible = "qcom,lpm-workarounds"; - reg = <0x0B011018 0x4>, - <0x0B011088 0x4>; - reg-names = "l2-pwr-sts", "l1-l2-gcc"; - lpm-cx-supply = <&pm8916_s2_corner>; - qcom,lpm-wa-cx-turbo-unvote; - qcom,lpm-wa-skip-l2-spm; - qcom,lpm-wa-dynamic-clock-gating; - qcom,cpu-offline-mask = "0xF"; - qcom,non-boot-cpu-index = <4>; -} diff --git a/Documentation/devicetree/bindings/mcd/mcd.txt b/Documentation/devicetree/bindings/mcd/mcd.txt deleted file mode 100644 index 4077ee2250b2..000000000000 --- a/Documentation/devicetree/bindings/mcd/mcd.txt +++ /dev/null @@ -1,29 +0,0 @@ -* MCD (MobiCore Driver) - -t-base is an operating system running in the secure world (TrustZone). -The t-base implementation consists of several components in the -secure world and the non-secure world (kernel and user space). The -MobiCore driver communicates with the t-base operating system that -exists in TrustZone. - -Required properties: - - compatible: Should be "qcom,mcd" - - qcom,ce-hw-instance: should contain crypto HW instance - - qcom,ce-device: Device number - - clocks: Array of listing - all the clocks that are accesed by this subsystem. - - qcom,ce-opp-freq: indicates the CE operating frequency in Hz, changes from target to target. - -Example: - mcd { - compatible = "qcom,mcd"; - qcom,ce-hw-instance = <0>; - qcom,ce-device = <0>; - clocks = <&clock_gcc clk_crypto_clk_src>, - <&clock_gcc clk_gcc_crypto_clk>, - <&clock_gcc clk_gcc_crypto_ahb_clk>, - <&clock_gcc clk_gcc_crypto_axi_clk>; - clock-names = "core_clk_src", "core_clk", - "iface_clk", "bus_clk"; - qcom,ce-opp-freq = <100000000>; - }; diff --git a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi index 4e7d6f8b955a..9d35b0628db6 100644 --- a/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909-coresight.dtsi @@ -1,623 +1,747 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and + * it under the terms of the GNU General Public License version 2 an * only version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ &soc { tmc_etr: tmc@826000 { - compatible = "arm,coresight-tmc"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + reg = <0x826000 0x1000>, <0x884000 0x15000>; reg-names = "tmc-base", "bam-base"; + interrupts = <0 166 0>; interrupt-names = "byte-cntr-irq"; - qcom,memory-size = <0x100000>; - qcom,sg-enable; + arm,buffer-size = <0x100000>; + arm,sg-enable; - coresight-id = <0>; coresight-name = "coresight-tmc-etr"; - coresight-nr-inports = <1>; coresight-ctis = <&cti0 &cti8>; + coresight-csr = <&csr>; + clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; }; - tpiu: tpiu@820000 { - compatible = "arm,coresight-tpiu"; - reg = <0x820000 0x1000>, - <0x1100000 0xb0000>; - reg-names = "tpiu-base", "nidnt-base"; - - coresight-id = <1>; - coresight-name = "coresight-tpiu"; - coresight-nr-inports = <1>; - - qcom,nidnthw; - qcom,nidnt-swduart; - qcom,nidnt-swdtrc; - qcom,nidnt-jtag; - qcom,nidnt-spmi; - nidnt-gpio = <38>; - nidnt-gpio-polarity = <1>; + tmc_etf: tmc@825000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; - interrupts = <0 82 0>; - interrupt-names = "nidnt-irq"; + reg = <0x825000 0x1000>; + reg-names = "tmc-base"; - vdd-supply = <&pm8909_l11>; - qcom,vdd-voltage-level = <2950000 2950000>; - qcom,vdd-current-level = <15000 400000>; + coresight-name = "coresight-tmc-etf"; - vdd-io-supply = <&pm8909_l12>; - qcom,vdd-io-voltage-level = <2950000 2950000>; - qcom,vdd-io-current-level = <200 50000>; + arm,default-sink; + coresight-ctis = <&cti0 &cti8>; + coresight-csr = <&csr>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + tmc_etf_out_replicator:endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_tmc_etf>; + }; + }; + }; }; replicator: replicator@824000 { - compatible = "qcom,coresight-replicator"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + reg = <0x824000 0x1000>; reg-names = "replicator-base"; - coresight-id = <2>; coresight-name = "coresight-replicator"; - coresight-nr-inports = <1>; - coresight-outports = <0 1>; - coresight-child-list = <&tmc_etr &tpiu>; - coresight-child-ports = <0 0>; + clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; - }; + clock-names = "apb_pclk"; - tmc_etf: tmc@825000 { - compatible = "arm,coresight-tmc"; - reg = <0x825000 0x1000>; - reg-names = "tmc-base"; - - coresight-id = <3>; - coresight-name = "coresight-tmc-etf"; - coresight-nr-inports = <1>; - coresight-outports = <0>; - coresight-child-list = <&replicator>; - coresight-child-ports = <0>; - coresight-default-sink; - coresight-ctis = <&cti0 &cti8>; + ports { + #address-cells = <1>; + #size-cells = <0>; - clocks = <&clock_rpm clk_qdss_clk>, - <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + port@0 { + replicator_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + port@1 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; }; funnel_in0: funnel@821000 { - compatible = "arm,coresight-funnel"; + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x821000 0x1000>; reg-names = "funnel-base"; - coresight-id = <4>; coresight-name = "coresight-funnel-in0"; - coresight-nr-inports = <8>; - coresight-outports = <0>; - coresight-child-list = <&tmc_etf>; - coresight-child-ports = <0>; + clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; - }; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + funnel_in0_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_in0>; + }; + }; + port@1 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + + port@2 { + reg = <3>; + funnel_in0_in_funnel_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_center_out_funnel_in0>; + }; + }; + + port@3 { + reg = <4>; + funnel_in0_in_funnel_right: endpoint { + slave-mode; + remote-endpoint = + <&funnel_right_out_funnel_in0>; + }; + }; + + port@4 { + + reg = <0>; + funnel_in0_in_rpm_etm0: endpoint { + slave-mode; + remote-endpoint = + <&rpm_etm0_out_funnel_center>; + }; + }; + + port@5 { + reg = <1>; + funnel_in0_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_right>; + }; + }; + }; + }; + + funnel_center: funnel@869000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; - funnel_in2: funnel@869000 { - compatible = "arm,coresight-funnel"; reg = <0x869000 0x1000>; reg-names = "funnel-base"; - coresight-id = <5>; - coresight-name = "coresight-funnel-in2"; - coresight-nr-inports = <8>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <6>; + coresight-name = "coresight-funnel-center"; + clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_center_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_center>; + }; + }; + + port@2 { + reg = <2>; + funnel_center_in_dbgui: endpoint { + slave-mode; + remote-endpoint = + <&dbgui_out_funnel_center>; + }; + }; + }; }; - funnel_in3: funnel@868000 { - compatible = "arm,coresight-funnel"; + funnel_right: funnel@868000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + reg = <0x868000 0x1000>; reg-names = "funnel-base"; - coresight-id = <6>; - coresight-name = "coresight-funnel-in3"; - coresight-nr-inports = <2>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in2>; - coresight-child-ports = <7>; + coresight-name = "coresight-funnel-right"; + clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; - }; + clock-names = "apb_pclk"; - cti0: cti@810000 { - compatible = "arm,coresight-cti"; - reg = <0x810000 0x1000>; - reg-names = "cti-base"; + ports { + #address-cells = <1>; + #size-cells = <0>; - coresight-id = <7>; - coresight-name = "coresight-cti0"; - coresight-nr-inports = <0>; - clocks = <&clock_rpm clk_qdss_clk>, - <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; - }; + port@0 { + funnel_right_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_right>; + }; + }; - cti1: cti@811000 { - compatible = "arm,coresight-cti"; - reg = <0x811000 0x1000>; - reg-names = "cti-base"; + port@2 { + reg = <2>; + funnel_right_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_right>; + }; + }; - coresight-id = <8>; - coresight-name = "coresight-cti1"; - coresight-nr-inports = <0>; - clocks = <&clock_rpm clk_qdss_clk>, - <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + port@3 { + reg = <0>; + funnel_right_in_wcn_etm0: endpoint { + slave-mode; + remote-endpoint = + <&wcn_etm0_out_funnel_mm>; + }; + }; + }; }; - cti2: cti@812000 { - compatible = "arm,coresight-cti"; - reg = <0x812000 0x1000>; - reg-names = "cti-base"; + funnel_apss: funnel@855000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; - coresight-id = <9>; - coresight-name = "coresight-cti2"; - coresight-nr-inports = <0>; - clocks = <&clock_rpm clk_qdss_clk>, - <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; - }; + reg = <0x855000 0x1000>; + reg-names = "funnel-base"; - cti3: cti@813000 { - compatible = "arm,coresight-cti"; - reg = <0x813000 0x1000>; - reg-names = "cti-base"; + coresight-name = "coresight-funnel-apss"; - coresight-id = <10>; - coresight-name = "coresight-cti3"; - coresight-nr-inports = <0>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_apss_out_funnel_right: endpoint { + remote-endpoint = + <&funnel_right_in_funnel_apss>; + }; + }; + + port@1 { + reg = <4>; + funnel_apss0_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss0>; + }; + }; + + port@2 { + reg = <5>; + funnel_apss0_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss0>; + }; + }; + + port@3 { + reg = <6>; + funnel_apss0_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss0>; + }; + }; + + port@4 { + reg = <7>; + funnel_apss0_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss0>; + }; + }; + + }; + }; - cti4: cti@814000 { - compatible = "arm,coresight-cti"; - reg = <0x814000 0x1000>; - reg-names = "cti-base"; + tpiu: tpiu@820000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b912>; + coresight-name = "coresight-tpiu"; - coresight-id = <11>; - coresight-name = "coresight-cti4"; - coresight-nr-inports = <0>; + reg = <0x820000 0x1000>, + <0x1100000 0xb0000>; + reg-names = "tpiu-base", "nidnt-base"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - cti5: cti@815000 { - compatible = "arm,coresight-cti"; - reg = <0x815000 0x1000>; - reg-names = "cti-base"; + etm0: etm@84c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b955>; + + reg = <0x84c000 0x1000>; + cpu = <&CPU0>; + coresight-name = "coresight-etm0"; - coresight-id = <12>; - coresight-name = "coresight-cti5"; - coresight-nr-inports = <0>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; + + port { + etm0_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm0>; + }; + }; }; - cti6: cti@816000 { - compatible = "arm,coresight-cti"; - reg = <0x816000 0x1000>; - reg-names = "cti-base"; + etm1: etm@84d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b955>; + + reg = <0x84d000 0x1000>; + cpu = <&CPU1>; + coresight-name = "coresight-etm1"; - coresight-id = <13>; - coresight-name = "coresight-cti6"; - coresight-nr-inports = <0>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; - qcom,cti-gpio-trigout = <2>; - pinctrl-names = "cti-trigout-pctrl"; - pinctrl-0 = <&trigout_a0>; + port { + etm1_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm1>; + }; + }; }; - cti7: cti@817000 { - compatible = "arm,coresight-cti"; - reg = <0x817000 0x1000>; - reg-names = "cti-base"; + etm2: etm@84e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b955>; + + reg = <0x84e000 0x1000>; + cpu = <&CPU2>; + coresight-name = "coresight-etm2"; - coresight-id = <14>; - coresight-name = "coresight-cti7"; - coresight-nr-inports = <0>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm2>; + }; + }; }; - cti8: cti@818000 { - compatible = "arm,coresight-cti"; - reg = <0x818000 0x1000>; - reg-names = "cti-base"; + etm3: etm@84f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b955>; + + reg = <0x84f000 0x1000>; + coresight-name = "coresight-etm3"; + cpu = <&CPU3>; - coresight-id = <15>; - coresight-name = "coresight-cti8"; - coresight-nr-inports = <0>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm3>; + }; + }; }; - cti_cpu0: cti@851000 { - compatible = "arm,coresight-cti"; - reg = <0x851000 0x1000>; - reg-names = "cti-base"; + stm: stm@802000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; - coresight-id = <16>; - coresight-name = "coresight-cti-cpu0"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU0>; + reg = <0x802000 0x1000>, + <0x9280000 0x180000>; + reg-names = "stm-base", "stm-stimulus-base"; - qcom,cti-save; + coresight-name = "coresight-stm"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; - }; + clock-names = "apb_pclk"; - cti_cpu1: cti@852000 { - compatible = "arm,coresight-cti"; - reg = <0x852000 0x1000>; - reg-names = "cti-base"; + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; - coresight-id = <17>; - coresight-name = "coresight-cti-cpu1"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU1>; + cti0: cti@810000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - qcom,cti-save; + reg = <0x810000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti0"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - cti_cpu2: cti@853000 { - compatible = "arm,coresight-cti"; - reg = <0x853000 0x1000>; - reg-names = "cti-base"; - - coresight-id = <18>; - coresight-name = "coresight-cti-cpu2"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU2>; + cti1: cti@811000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - qcom,cti-save; + reg = <0x811000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti1"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - cti_cpu3: cti@854000 { - compatible = "arm,coresight-cti"; - reg = <0x854000 0x1000>; - reg-names = "cti-base"; - - coresight-id = <19>; - coresight-name = "coresight-cti-cpu3"; - coresight-nr-inports = <0>; - coresight-cti-cpu = <&CPU3>; + cti2: cti@812000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - qcom,cti-save; + reg = <0x812000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti2"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - cti_rpm_cpu0: cti@83c000 { - compatible = "arm,coresight-cti"; - reg = <0x83c000 0x1000>; - reg-names = "cti-base"; + cti3: cti@813000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <20>; - coresight-name = "coresight-cti-rpm-cpu0"; - coresight-nr-inports = <0>; + reg = <0x813000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti3"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - cti_modem_cpu0: cti@838000 { - compatible = "arm,coresight-cti"; - reg = <0x838000 0x1000>; - reg-names = "cti-base"; + cti4: cti@814000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <21>; - coresight-name = "coresight-cti-modem-cpu0"; - coresight-nr-inports = <0>; + reg = <0x814000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti4"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - cti_wcn_cpu0: cti@835000 { - compatible = "arm,coresight-cti"; - reg = <0x835000 0x1000>; - reg-names = "cti-base"; + cti5: cti@815000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <22>; - coresight-name = "coresight-cti-wcn-cpu0"; - coresight-nr-inports = <0>; + reg = <0x815000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti5"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - cti_video_cpu0: cti@830000 { - compatible = "arm,coresight-cti"; - reg = <0x830000 0x1000>; - reg-names = "cti-base"; + cti6: cti@816000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <23>; - coresight-name = "coresight-cti-video-cpu0"; - coresight-nr-inports = <0>; + reg = <0x816000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti6"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - stm: stm@802000 { - compatible = "arm,coresight-stm"; - reg = <0x802000 0x1000>, - <0x9280000 0x180000>; - reg-names = "stm-base", "stm-data-base"; + cti7: cti@817000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x817000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti7"; - coresight-id = <24>; - coresight-name = "coresight-stm"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <7>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - csr: csr@801000 { - compatible = "qcom,coresight-csr"; - reg = <0x801000 0x1000>; - reg-names = "csr-base"; + cti8: cti@818000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <25>; - coresight-name = "coresight-csr"; - coresight-nr-inports = <0>; + reg = <0x818000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti8"; - qcom,blk-size = <1>; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - funnel_apss: funnel@855000 { - compatible = "arm,coresight-funnel"; - reg = <0x855000 0x1000>; - reg-names = "funnel-base"; + cti_cpu0: cti@851000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <26>; - coresight-name = "coresight-funnel-apss"; - coresight-nr-inports = <4>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <4>; + reg = <0x851000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + qcom,cti-save; clocks = <&clock_rpm clk_qdss_clk>, - <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + <&clock_rpm clk_qdss_a_clk>; + clock-names = "apb_pclk"; }; - etm0: etm@84c000 { - compatible = "arm,coresight-etm"; - reg = <0x84c000 0x1000>; - reg-names = "etm-base"; + cti_cpu1: cti@852000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <27>; - coresight-name = "coresight-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss>; - coresight-child-ports = <0>; - coresight-etm-cpu = <&CPU0>; + reg = <0x852000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + qcom,cti-save; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - etm1: etm@84d000 { - compatible = "arm,coresight-etm"; - reg = <0x84d000 0x1000>; - reg-names = "etm-base"; + cti_cpu2: cti@853000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <28>; - coresight-name = "coresight-etm1"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss>; - coresight-child-ports = <1>; - coresight-etm-cpu = <&CPU1>; + reg = <0x853000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + qcom,cti-save; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - etm2: etm@84e000 { - compatible = "arm,coresight-etm"; - reg = <0x84e000 0x1000>; - reg-names = "etm-base"; + cti_cpu3: cti@854000{ + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <29>; - coresight-name = "coresight-etm2"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss>; - coresight-child-ports = <2>; - coresight-etm-cpu = <&CPU2>; + reg = <0x854000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + qcom,cti-save; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - etm3: etm@84f000 { - compatible = "arm,coresight-etm"; - reg = <0x84f000 0x1000>; - reg-names = "etm-base"; + cti_modem_cpu0: cti@838000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <30>; - coresight-name = "coresight-etm3"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_apss>; - coresight-child-ports = <3>; - coresight-etm-cpu = <&CPU3>; + reg = <0x838000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-modem-cpu0"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - hwevent: hwevent@86c000 { - compatible = "qcom,coresight-hwevent"; - reg = <0x86c000 0x108>, - <0x86cfb0 0x4>, - <0x78c5010 0x4>, - <0x7885010 0x4>; - reg-names = "wrapper-mux", "wrapper-lockaccess", "usbbam-mux", - "blsp-mux"; - coresight-id = <31>; - coresight-name = "coresight-hwevent"; - coresight-nr-inports = <0>; + /* Venus CTI */ + cti_video_cpu0: cti@830000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x830000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-video-cpu0"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; - rpm_etm0 { - compatible = "qcom,coresight-remote-etm"; + /* Pronto CTI */ + cti_wcn_cpu0: cti@835000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; - coresight-id = <32>; - coresight-name = "coresight-rpm-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <0>; + reg = <0x835000 0x1000>; + reg-names = "cti-base"; + coresight-name = "coresight-cti-wcn-cpu0"; - qcom,inst-id = <4>; + clocks = <&clock_rpm clk_qdss_clk>, + <&clock_rpm clk_qdss_a_clk>; + clock-names = "apb_pclk"; }; wcn_etm0 { compatible = "qcom,coresight-remote-etm"; - - coresight-id = <33>; coresight-name = "coresight-wcn-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in3>; - coresight-child-ports = <0>; - qcom,inst-id = <3>; + + port { + wcn_etm0_out_funnel_mm: endpoint { + remote-endpoint = <&funnel_right_in_wcn_etm0>; + }; + }; }; + /* MSS_SCL */ modem_etm0 { compatible = "qcom,coresight-remote-etm"; - - coresight-id = <34>; coresight-name = "coresight-modem-etm0"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in0>; - coresight-child-ports = <2>; + qcom,inst-id = <11>; - qcom,inst-id = <2>; + port { + modem_etm0_out_funnel_right: endpoint { + remote-endpoint = <&funnel_in0_in_modem_etm0>; + }; + }; }; - fuse: fuse@5e01c { - compatible = "arm,coresight-fuse-v2"; - reg = <0x5e01c 0x8>, - <0x58040 0x4>, - <0x5e00c 0x4>; - reg-names = "fuse-base", "nidnt-fuse-base", "qpdi-fuse-base"; + rpm_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-rpm-etm0"; + qcom,inst-id = <4>; - coresight-id = <35>; - coresight-name = "coresight-fuse"; - coresight-nr-inports = <0>; + port { + rpm_etm0_out_funnel_center: endpoint { + remote-endpoint = <&funnel_in0_in_rpm_etm0>; + }; + }; }; - qpdi: qpdi@1941000 { - compatible = "qcom,coresight-qpdi"; - reg = <0x1941000 0x4>; - reg-names = "qpdi-base"; - - coresight-id = <36>; - coresight-name = "coresight-qpdi"; - coresight-nr-inports = <0>; + csr: csr@801000 { + compatible = "qcom,coresight-csr"; + reg = <0x801000 0x1000>; + reg-names = "csr-base"; - vdd-supply = <&pm8909_l11>; - qcom,vdd-voltage-level = <2800000 2950000>; - qcom,vdd-current-level = <15000 400000>; + coresight-name = "coresight-csr"; - vdd-io-supply = <&pm8909_l12>; - qcom,vdd-io-voltage-level = <1800000 2950000>; - qcom,vdd-io-current-level = <200 50000>; + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + qcom,blk-size = <1>; }; dbgui: dbgui@86d000 { compatible = "qcom,coresight-dbgui"; reg = <0x86d000 0x1000>; reg-names = "dbgui-base"; - - coresight-id = <37>; coresight-name = "coresight-dbgui"; - coresight-nr-inports = <0>; - coresight-outports = <0>; - coresight-child-list = <&funnel_in2>; - coresight-child-ports = <2>; qcom,dbgui-addr-offset = <0x30>; - qcom,dbgui-data-offset = <0xB0>; - qcom,dbgui-size = <32>; + qcom,dbgui-data-offset = <0x130>; + qcom,dbgui-size = <64>; + + clocks = <&clock_rpm clk_qdss_clk>, + <&clock_rpm clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + dbgui_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_dbgui>; + }; + }; + }; + + hwevent: hwevent@86c000 { + compatible = "qcom,coresight-hwevent"; + + reg = <0x86c000 0x108>, + <0x86cfb0 0x4>, + <0x78c5010 0x4>, + <0x7885010 0x4>; + + reg-names = "center-wrapper-mux", "center-wrapper-lockaccess", + "right-wrapper-mux", "right-wrapper-lockaccess"; + + coresight-csr = <&csr>; + coresight-name = "coresight-hwevent"; clocks = <&clock_rpm clk_qdss_clk>, <&clock_rpm clk_qdss_a_clk>; - clock-names = "core_clk", "core_a_clk"; + clock-names = "apb_pclk"; }; + }; diff --git a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi index 858429bc2d95..cd21e6ea9eb2 100644 --- a/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909-ion.dtsi @@ -33,12 +33,6 @@ qcom,ion-heap-type = "DMA"; }; - modem_heap: qcom,ion-heap@26 { /* MODEM HEAP */ - reg = <26>; - memory-region = <&modem_adsp_mem>; - qcom,ion-heap-type = "DMA"; - }; - qcom,ion-heap@19 { /* QSEECOM TA HEAP */ reg = <19>; memory-region = <&qseecom_ta_mem>; diff --git a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi index 18fc575851d1..e2fbc9efc82b 100644 --- a/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909-mtp.dtsi @@ -410,27 +410,3 @@ }; }; }; - -/* CoreSight */ -&tpiu { - pinctrl-names = "sdcard", "trace", "swduart", - "swdtrc", "jtag", "spmi"; - /* NIDnT */ - pinctrl-0 = <&qdsd_clk_sdcard &qdsd_cmd_sdcard - &qdsd_data0_sdcard &qdsd_data1_sdcard - &qdsd_data2_sdcard &qdsd_data3_sdcard>; - pinctrl-1 = <&qdsd_clk_trace &qdsd_cmd_trace - &qdsd_data0_trace &qdsd_data1_trace - &qdsd_data2_trace &qdsd_data3_trace>; - pinctrl-2 = <&qdsd_cmd_swduart &qdsd_data0_swduart - &qdsd_data1_swduart &qdsd_data2_swduart - &qdsd_data3_swduart>; - pinctrl-3 = <&qdsd_clk_swdtrc &qdsd_cmd_swdtrc - &qdsd_data0_swdtrc &qdsd_data1_swdtrc - &qdsd_data2_swdtrc &qdsd_data3_swdtrc>; - pinctrl-4 = <&qdsd_cmd_jtag &qdsd_data0_jtag - &qdsd_data1_jtag &qdsd_data2_jtag - &qdsd_data3_jtag>; - pinctrl-5 = <&qdsd_clk_spmi &qdsd_cmd_spmi - &qdsd_data0_spmi &qdsd_data3_spmi>; -}; diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi index a6d42f1c6ec8..d61606f80cd4 100644 --- a/arch/arm64/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi @@ -1947,19 +1947,6 @@ memory-region = <&modem_adsp_mem>; }; - mcd { - compatible = "qcom,mcd"; - qcom,ce-hw-instance = <0>; - qcom,ce-device = <0>; - clocks = <&clock_gcc clk_crypto_clk_src>, - <&clock_gcc clk_gcc_crypto_clk>, - <&clock_gcc clk_gcc_crypto_ahb_clk>, - <&clock_gcc clk_gcc_crypto_axi_clk>; - clock-names = "core_clk_src", "core_clk", - "iface_clk", "bus_clk"; - qcom,ce-opp-freq = <100000000>; - }; - cpu0_slp_sts: cpu-sleep-status@b088008 { reg = <0xb088008 0x100>; qcom,sleep-status-mask= <0x80000>; -- GitLab From bc12aac7c0a82ca1d3c01dfcae1ac5a442419d72 Mon Sep 17 00:00:00 2001 From: Veera Sundaram Sankaran Date: Tue, 15 May 2018 10:50:20 -0700 Subject: [PATCH 1791/1834] drm/msm/sde: fix invalid loop-condition in clear dim_layer Fix the loop-condition to clear dim_layer settings in all the stages including the max supported stage. Change-Id: I0d5637eac8f14973adac443b2383f2b5aa7fa587 Signed-off-by: Veera Sundaram Sankaran --- drivers/gpu/drm/msm/sde/sde_hw_lm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/msm/sde/sde_hw_lm.c b/drivers/gpu/drm/msm/sde/sde_hw_lm.c index 4e677c2a326e..97a3ea4489aa 100644 --- a/drivers/gpu/drm/msm/sde/sde_hw_lm.c +++ b/drivers/gpu/drm/msm/sde/sde_hw_lm.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -179,7 +179,7 @@ static void sde_hw_lm_clear_dim_layer(struct sde_hw_mixer *ctx) u32 reset = BIT(16), val; reset = ~reset; - for (i = SDE_STAGE_0; i < sblk->maxblendstages; i++) { + for (i = SDE_STAGE_0; i <= sblk->maxblendstages; i++) { stage_off = _stage_offset(ctx, i); if (WARN_ON(stage_off < 0)) return; -- GitLab From ba420e903189b9ab97afa6f64b7e153b9d4d5756 Mon Sep 17 00:00:00 2001 From: Mayank Chopra Date: Tue, 8 May 2018 18:04:24 -0700 Subject: [PATCH 1792/1834] ARM: dts: msm: Enable vdd-io for APQ8053 Lite dragonboard vdd-io regulator is brought to a good state only by wlan driver invocation post boot. This causes bluetooth initialization failure in the cases when bt is invoked before wifi as vdd-io is not initialized. Enable vdd-io so that it is ready for bt and/or wifi at boot. Change-Id: I9f1bb62d13ac10d7f8b3e75debb33d94d60df301 Signed-off-by: Mayank Chopra --- arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi index 5e3ddce4f481..567634357f50 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -290,6 +290,7 @@ &sdhc_2 { /* device communication power supply */ vdd-io-supply = <&pm8953_l12>; + qcom,vdd-io-always-on; qcom,vdd-io-voltage-level = <1800000 1800000>; qcom,vdd-io-current-level = <200 22000>; -- GitLab From c0dbf64cfb95d5dbfa6e136e48dafd66b785354e Mon Sep 17 00:00:00 2001 From: shaoxing Date: Tue, 20 Mar 2018 19:43:05 +0800 Subject: [PATCH 1793/1834] drivers: input: vl53l0x: Add TOF Vl53l0x sensor for APQ8009 Robotics This change add STM vl53l0x sensor driver for APQ8009 Robotics. VL53L0X is a ranging and gesture detection sensor through i2c in 400kb/s. Icm20602 driver can push the data to userspace by sysfs which is calibrate by the driver application. Change-Id: I1d248d71397ec0e1b551419bf58cbe22d2dfff7f From: FMenziesENG Signed-off-by: FMenziesENG [xuji@codeaurora.org: Add API to userspace through sysfs] Signed-off-by: xuji --- .../bindings/input/misc/stmvl53l0x.txt | 36 + drivers/input/misc/Kconfig | 12 + drivers/input/misc/Makefile | 2 + drivers/input/misc/vl53l0x/Makefile | 20 + drivers/input/misc/vl53l0x/inc/vl53l0x_api.h | 1943 +++++++++++ .../vl53l0x/inc/vl53l0x_api_calibration.h | 75 + .../input/misc/vl53l0x/inc/vl53l0x_api_core.h | 98 + .../misc/vl53l0x/inc/vl53l0x_api_ranging.h | 37 + .../misc/vl53l0x/inc/vl53l0x_api_strings.h | 268 ++ drivers/input/misc/vl53l0x/inc/vl53l0x_def.h | 619 ++++ .../input/misc/vl53l0x/inc/vl53l0x_device.h | 246 ++ .../misc/vl53l0x/inc/vl53l0x_i2c_platform.h | 397 +++ .../vl53l0x_interrupt_threshold_settings.h | 183 + .../input/misc/vl53l0x/inc/vl53l0x_platform.h | 213 ++ .../misc/vl53l0x/inc/vl53l0x_platform_log.h | 99 + .../input/misc/vl53l0x/inc/vl53l0x_tuning.h | 135 + .../input/misc/vl53l0x/inc/vl53l0x_types.h | 54 + drivers/input/misc/vl53l0x/src/vl53l0x_api.c | 3096 +++++++++++++++++ .../vl53l0x/src/vl53l0x_api_calibration.c | 1266 +++++++ .../input/misc/vl53l0x/src/vl53l0x_api_core.c | 2220 ++++++++++++ .../misc/vl53l0x/src/vl53l0x_api_ranging.c | 32 + .../misc/vl53l0x/src/vl53l0x_api_strings.c | 455 +++ .../misc/vl53l0x/src/vl53l0x_i2c_platform.c | 384 ++ .../input/misc/vl53l0x/src/vl53l0x_platform.c | 232 ++ .../input/misc/vl53l0x/src/vl53l0x_port_i2c.c | 168 + drivers/input/misc/vl53l0x/stmvl53l0x-cci.h | 57 + drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h | 35 + drivers/input/misc/vl53l0x/stmvl53l0x.h | 186 + .../misc/vl53l0x/stmvl53l0x_module-cci.c | 411 +++ .../misc/vl53l0x/stmvl53l0x_module-i2c.c | 246 ++ .../input/misc/vl53l0x/stmvl53l0x_module.c | 1893 ++++++++++ 31 files changed, 15118 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt create mode 100644 drivers/input/misc/vl53l0x/Makefile create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_api.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_def.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_device.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h create mode 100644 drivers/input/misc/vl53l0x/inc/vl53l0x_types.h create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_api.c create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_platform.c create mode 100644 drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c create mode 100644 drivers/input/misc/vl53l0x/stmvl53l0x-cci.h create mode 100644 drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h create mode 100644 drivers/input/misc/vl53l0x/stmvl53l0x.h create mode 100644 drivers/input/misc/vl53l0x/stmvl53l0x_module-cci.c create mode 100644 drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c create mode 100644 drivers/input/misc/vl53l0x/stmvl53l0x_module.c diff --git a/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt new file mode 100644 index 000000000000..bf10122de8a8 --- /dev/null +++ b/Documentation/devicetree/bindings/input/misc/stmvl53l0x.txt @@ -0,0 +1,36 @@ +STM VL53L0X Time-of-Flight ranging and gesture detection sensor driver + +Description: + +The VL53L0X is a new generation Time-of-Flight +(ToF) laser-ranging module housed in the +smallest package on the market today, providing +accurate distance measurement whatever the +target reflectances unlike conventional +technologies. It can measure absolute distances +up to 2m, setting a new benchmark in ranging +performance levels, opening the door to various +new applications. +The VL53L0X integrates a leading-edge SPAD +array (Single Photon Avalanche Diodes) and +embeds ST’s second generation FlightSenseTM +patented technology. +The VL53L0X’s 940 nm VCSEL emitter (Vertical +Cavity Surface-Emitting Laser), is totally invisible +to the human eye, coupled with internal physical +infrared filters, it enables longer ranging +distances, higher immunity to ambient light, and +better robustness to cover glass optical crosstalk. + +Required properties: + + - compatible : Should be "st,stmvl53l0". + - reg : i2c slave address of the device. + +Example: + i2c@f9925000 { + vl53l0x@52 { + compatible = "st,stmvl53l0"; + reg = <0x52>; + }; + }; diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 3026c0624bb4..f8a987a61bd7 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -398,6 +398,18 @@ config INPUT_KEYCHORD To compile this driver as a module, choose M here: the module will be called keychord. + +config STMVL53L0X + tristate "STM VL53L0X Ranging Sensor" + depends on I2C + help + Say Y here if you want to enable the key chord driver + This is a Time-of-Flight (ToF) laser-ranging sensor, provide + the distance from obstacle. + + To compile this driver as a module, choose M here: the module will + be called vl5310x. + config INPUT_KEYSPAN_REMOTE tristate "Keyspan DMR USB remote control" depends on USB_ARCH_HAS_HCD diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index c3af7c28d1dd..149273c9f2c4 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -82,3 +82,5 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o +obj-$(CONFIG_INPUT_PIXART_OTS_PAT9125_SWITCH) += ots_pat9125/ +obj-$(CONFIG_STMVL53L0X) += vl53l0x/ diff --git a/drivers/input/misc/vl53l0x/Makefile b/drivers/input/misc/vl53l0x/Makefile new file mode 100644 index 000000000000..af00414d93f5 --- /dev/null +++ b/drivers/input/misc/vl53l0x/Makefile @@ -0,0 +1,20 @@ +# +# Makefile for the vl53L0X drivers. +# + +# Each configuration option enables a list of files. +FEATURE_USE_CCI := false +#FEATURE_USE_CCI := true + +ifeq ($(FEATURE_USE_CCI), true) +ccflags-y += -Idrivers/input/misc/vl53l0x/inc -DCAMERA_CCI +else +ccflags-y += -Idrivers/input/misc/vl53l0x/inc -DSTM_TEST +endif + +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/io +ccflags-y += -Idrivers/media/platform/msm/camera_v2 +ccflags-y += -Idrivers/media/platform/msm/camera_v2/common +ccflags-y += -Idrivers/media/platform/msm/camera_v2/sensor/cci +obj-$(CONFIG_STMVL53L0X) += stmvl53l0x.o +stmvl53l0x-objs := stmvl53l0x_module.o stmvl53l0x_module-i2c.o stmvl53l0x_module-cci.o src/vl53l0x_api_calibration.o src/vl53l0x_api_core.o src/vl53l0x_api_ranging.o src/vl53l0x_api_strings.o src/vl53l0x_api.o src/vl53l0x_platform.o src/vl53l0x_i2c_platform.o src/vl53l0x_port_i2c.o diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h new file mode 100644 index 000000000000..a0e0e791613e --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api.h @@ -0,0 +1,1943 @@ +/* + * vl53l0x_api.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_API_H_ +#define _VL_API_H_ + +#include "vl53l0x_api_strings.h" +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef _MSC_VER +# ifdef VL_API_EXPORTS +# define VL_API __declspec(dllexport) +# else +# define VL_API +# endif +#else +# define VL_API +#endif + +/** @defgroup VL_cut11_group VL53L0X cut1.1 Function Definition + * @brief VL53L0X cut1.1 Function Definition + * @{ + */ + +/** @defgroup VL_general_group VL53L0X General Functions + * @brief General functions and definitions + * @{ + */ + +/** + * @brief Return the VL53L0X PAL Implementation Version + * + * @note This function doesn't access to the device + * + * @param pVersion Pointer to current PAL Implementation Version + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetVersion(struct VL_Version_t *pVersion); + +/** + * @brief Return the PAL Specification Version used for the current + * implementation. + * + * @note This function doesn't access to the device + * + * @param pPalSpecVersion Pointer to current PAL Specification Version + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalSpecVersion( + struct VL_Version_t *pPalSpecVersion); + +/** + * @brief Reads the Product Revision for a for given Device + * This function can be used to distinguish cut1.0 from cut1.1. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pProductRevisionMajor Pointer to Product Revision Major + * for a given Device + * @param pProductRevisionMinor Pointer to Product Revision Minor + * for a given Device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetProductRevision(struct vl_data *Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor); + +/** + * @brief Reads the Device information for given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVL_DeviceInfo Pointer to current device info for a given + * Device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceInfo(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo); + +/** + * @brief Read current status of the error register for the selected device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pDeviceErrorStatus Pointer to current error code of the device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev, + uint8_t *pDeviceErrorStatus); + +/** + * @brief Human readable Range Status string for a given RangeStatus + * + * @note This function doesn't access to the device + * + * @param RangeStatus The RangeStatus code as stored on + * @a struct VL_RangingMeasurementData_t + * @param pRangeStatusString The returned RangeStatus string. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString); + +/** + * @brief Human readable error string for a given Error Code + * + * @note This function doesn't access to the device + * + * @param ErrorCode The error code as stored on ::uint8_t + * @param pDeviceErrorString The error string corresponding to the ErrorCode + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceErrorString( + uint8_t ErrorCode, char *pDeviceErrorString); + +/** + * @brief Human readable error string for current PAL error status + * + * @note This function doesn't access to the device + * + * @param PalErrorCode The error code as stored on @a int8_t + * @param pPalErrorString The error string corresponding to the + * PalErrorCode + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalErrorString(int8_t PalErrorCode, + char *pPalErrorString); + +/** + * @brief Human readable PAL State string + * + * @note This function doesn't access to the device + * + * @param PalStateCode The State code as stored on @a uint8_t + * @param pPalStateString The State string corresponding to the + * PalStateCode + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalStateString(uint8_t PalStateCode, + char *pPalStateString); + +/** + * @brief Reads the internal state of the PAL for a given Device + * + * @note This function doesn't access to the device + * + * @param Dev Device Handle + * @param pPalState Pointer to current state of the PAL for a + * given Device + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPalState(struct vl_data *Dev, + uint8_t *pPalState); + +/** + * @brief Set the power mode for a given Device + * The power mode can be Standby or Idle. Different level of both Standby and + * Idle can exists. + * This function should not be used when device is in Ranging state. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param PowerMode The value of the power mode to set. + * see ::uint8_t + * Valid values are: + * VL_POWERMODE_STANDBY_LEVEL1, + * VL_POWERMODE_IDLE_LEVEL1 + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when PowerMode + * is not in the supported list + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetPowerMode(struct vl_data *Dev, + uint8_t PowerMode); + +/** + * @brief Get the power mode for a given Device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pPowerMode Pointer to the current value of the power + * mode. see ::uint8_t + * Valid values are: + * VL_POWERMODE_STANDBY_LEVEL1, + * VL_POWERMODE_IDLE_LEVEL1 + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetPowerMode(struct vl_data *Dev, + uint8_t *pPowerMode); + +/** + * Set or over-hide part to part calibration offset + * \sa VL_DataInit() VL_GetOffsetCalibrationDataMicroMeter() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param OffsetCalibrationDataMicroMeter Offset (microns) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetOffsetCalibrationDataMicroMeter( + struct vl_data *Dev, int32_t OffsetCalibrationDataMicroMeter); + +/** + * @brief Get part to part calibration offset + * + * @par Function Description + * Should only be used after a successful call to @a VL_DataInit to backup + * device NVM value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pOffsetCalibrationDataMicroMeter Return part to part + * calibration offset from device (microns) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetOffsetCalibrationDataMicroMeter( + struct vl_data *Dev, int32_t *pOffsetCalibrationDataMicroMeter); + +/** + * Set the linearity corrective gain + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LinearityCorrectiveGain Linearity corrective + * gain in x1000 + * if value is 1000 then no modification is applied. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev, + int16_t LinearityCorrectiveGain); + +/** + * @brief Get the linearity corrective gain + * + * @par Function Description + * Should only be used after a successful call to @a VL_DataInit to backup + * device NVM value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pLinearityCorrectiveGain Pointer to the linearity + * corrective gain in x1000 + * if value is 1000 then no modification is applied. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev, + uint16_t *pLinearityCorrectiveGain); + +/** + * Set Group parameter Hold state + * + * @par Function Description + * Set or remove device internal group parameter hold + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param GroupParamHold Group parameter Hold state to be set (on/off) + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_SetGroupParamHold(struct vl_data *Dev, + uint8_t GroupParamHold); + +/** + * @brief Get the maximal distance for actual setup + * @par Function Description + * Device must be initialized through @a VL_SetParameters() prior calling + * this function. + * + * Any range value more than the value returned is to be considered as + * "no target detected" or + * "no target in detectable range"\n + * @warning The maximal distance depends on the setup + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param pUpperLimitMilliMeter The maximal range limit for actual setup + * (in millimeter) + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev, + uint16_t *pUpperLimitMilliMeter); + + +/** + * @brief Get the Total Signal Rate + * @par Function Description + * This function will return the Total Signal Rate after a good ranging is done. + * + * @note This function access to Device + * + * @param Dev Device Handle + * @param pTotalSignalRate Total Signal Rate value in Mega count per second + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_GetTotalSignalRate(struct vl_data *Dev, + unsigned int *pTotalSignalRate); + +/** @} VL_general_group */ + +/** @defgroup VL_init_group VL53L0X Init Functions + * @brief VL53L0X Init Functions + * @{ + */ + +/** + * @brief Set new device address + * + * After completion the device will answer to the new address programmed. + * This function should be called when several devices are used in parallel + * before start programming the sensor. + * When a single device us used, there is no need to call this function. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param DeviceAddress The new Device address + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetDeviceAddress(struct vl_data *Dev, + uint8_t DeviceAddress); + +/** + * + * @brief One time device initialization + * + * To be called once and only once after device is brought out of reset + * (Chip enable) and booted see @a VL_WaitDeviceBooted() + * + * @par Function Description + * When not used after a fresh device "power up" or reset, it may return + * @a #VL_ERROR_CALIBRATION_WARNING meaning wrong calibration data + * may have been fetched from device that can result in ranging offset error\n + * If application cannot execute device reset or need to run VL_DataInit + * multiple time then it must ensure proper offset calibration saving and + * restore on its own by using @a VL_GetOffsetCalibrationData() on first + * power up and then @a VL_SetOffsetCalibrationData() in all subsequent + * init. + * This function will change the uint8_t from VL_STATE_POWERDOWN to + * VL_STATE_WAIT_STATICINIT. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_DataInit(struct vl_data *Dev); + +/** + * @brief Set the tuning settings pointer + * + * This function is used to specify the Tuning settings buffer to be used + * for a given device. The buffer contains all the necessary data to permit + * the API to write tuning settings. + * This function permit to force the usage of either external or internal + * tuning settings. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pTuningSettingBuffer Pointer to tuning settings buffer. + * @param UseInternalTuningSettings Use internal tuning settings value. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings); + +/** + * @brief Get the tuning settings pointer and the internal external switch + * value. + * + * This function is used to get the Tuning settings buffer pointer and the + * value. + * of the switch to select either external or internal tuning settings. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param ppTuningSettingBuffer Pointer to tuning settings buffer. + * @param pUseInternalTuningSettings Pointer to store Use internal tuning + * settings value. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev, + uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings); + +/** + * @brief Do basic device init (and eventually patch loading) + * This function will change the uint8_t from + * VL_STATE_WAIT_STATICINIT to VL_STATE_IDLE. + * In this stage all default setting will be applied. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_StaticInit(struct vl_data *Dev); + +/** + * @brief Wait for device booted after chip enable (hardware standby) + * This function can be run only when uint8_t is VL_STATE_POWERDOWN. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + * + */ +VL_API int8_t VL_WaitDeviceBooted(struct vl_data *Dev); + +/** + * @brief Do an hard reset or soft reset (depending on implementation) of the + * device \nAfter call of this function, device must be in same state as right + * after a power-up sequence.This function will change the uint8_t to + * VL_STATE_POWERDOWN. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_ResetDevice(struct vl_data *Dev); + +/** @} VL_init_group */ + +/** @defgroup VL_parameters_group VL53L0X Parameters Functions + * @brief Functions used to prepare and setup the device + * @{ + */ + +/** + * @brief Prepare device for operation + * @par Function Description + * Update device with provided parameters + * @li Then start ranging operation. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pDeviceParameters Pointer to store current device parameters. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetDeviceParameters(struct vl_data *Dev, + const struct VL_DeviceParameters_t *pDeviceParameters); + +/** + * @brief Retrieve current device parameters + * @par Function Description + * Get actual parameters of the device + * @li Then start ranging operation. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pDeviceParameters Pointer to store current device parameters. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDeviceParameters(struct vl_data *Dev, + struct VL_DeviceParameters_t *pDeviceParameters); + +/** + * @brief Set a new device mode + * @par Function Description + * Set device to a new mode (ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param DeviceMode New device mode to apply + * Valid values are: + * VL_DEVICEMODE_SINGLE_RANGING + * VL_DEVICEMODE_CONTINUOUS_RANGING + * VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING + * VL_DEVICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when DeviceMode is + * not in the supported list + */ +VL_API int8_t VL_SetDeviceMode(struct vl_data *Dev, + uint8_t DeviceMode); + +/** + * @brief Get current new device mode + * @par Function Description + * Get actual mode of the device(ranging, histogram ...) + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pDeviceMode Pointer to current apply mode value + * Valid values are: + * VL_DEVICEMODE_SINGLE_RANGING + * VL_DEVICEMODE_CONTINUOUS_RANGING + * VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING + * VL_DEVICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode is not in the supported list + */ +VL_API int8_t VL_GetDeviceMode(struct vl_data *Dev, + uint8_t *pDeviceMode); + +/** + * @brief Sets the resolution of range measurements. + * @par Function Description + * Set resolution of range measurements to either 0.25mm if + * fraction enabled or 1mm if not enabled. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param Enable Enable high resolution + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetRangeFractionEnable(struct vl_data *Dev, + uint8_t Enable); + +/** + * @brief Gets the fraction enable parameter indicating the resolution of + * range measurements. + * + * @par Function Description + * Gets the fraction enable state, which translates to the resolution of + * range measurements as follows :Enabled:=0.25mm resolution, + * Not Enabled:=1mm resolution. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pEnable Output Parameter reporting the fraction enable state. + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetFractionEnable(struct vl_data *Dev, + uint8_t *pEnable); + +/** + * @brief Set a new Histogram mode + * @par Function Description + * Set device to a new Histogram mode + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param HistogramMode New device mode to apply + * Valid values are: + * VL_HISTOGRAMMODE_DISABLED + * struct vl_data *ICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when + * HistogramMode is not in the supported list + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetHistogramMode(struct vl_data *Dev, + uint8_t HistogramMode); + +/** + * @brief Get current new device mode + * @par Function Description + * Get current Histogram mode of a Device + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pHistogramMode Pointer to current Histogram Mode value + * Valid values are: + * VL_HISTOGRAMMODE_DISABLED + * struct vl_data *ICEMODE_SINGLE_HISTOGRAM + * VL_HISTOGRAMMODE_REFERENCE_ONLY + * VL_HISTOGRAMMODE_RETURN_ONLY + * VL_HISTOGRAMMODE_BOTH + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetHistogramMode(struct vl_data *Dev, + uint8_t *pHistogramMode); + +/** + * @brief Set Ranging Timing Budget in microseconds + * + * @par Function Description + * Defines the maximum time allowed by the user to the device to run a + * full ranging sequence for the current mode (ranging, histogram, ASL ...) + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param MeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * Valid values are: + * >= 17000 microsecs when wraparound enabled + * >= 12000 microsecs when wraparound disabled + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned if + MeasurementTimingBudgetMicroSeconds out of range + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetMeasurementTimingBudgetMicroSeconds( + struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +/** + * @brief Get Ranging Timing Budget in microseconds + * + * @par Function Description + * Returns the programmed the maximum time allowed by the user to the + * device to run a full ranging sequence for the current mode + * (ranging, histogram, ASL ...) + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementTimingBudgetMicroSeconds Max measurement time in + * microseconds. + * Valid values are: + * >= 17000 microsecs when wraparound enabled + * >= 12000 microsecs when wraparound disabled + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetMeasurementTimingBudgetMicroSeconds( + struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + +/** + * @brief Gets the VCSEL pulse period. + * + * @par Function Description + * This function retrieves the VCSEL pulse period for the given period type. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param VcselPeriodType VCSEL period identifier (pre-range|final). + * @param pVCSELPulsePeriod Pointer to VCSEL period value. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriod); + +/** + * @brief Sets the VCSEL pulse period. + * + * @par Function Description + * This function retrieves the VCSEL pulse period for the given period type. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param VcselPeriodType VCSEL period identifier (pre-range|final). + * @param VCSELPulsePeriod VCSEL period value + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error VcselPeriodType parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriod); + +/** + * @brief Sets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function enables/disables a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param SequenceStepEnabled Demanded state {0=Off,1=On} + * is enabled. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t SequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of a requested sequence step. + * + * @par Function Description + * This function retrieves the state of a requested sequence step, i.e. on/off. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepEnabled Out parameter reporting if the sequence step + * is enabled {0=Off,1=On}. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled); + +/** + * @brief Gets the (on/off) state of all sequence steps. + * + * @par Function Description + * This function retrieves the state of all sequence step in the scheduler. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pSchedulerSequenceSteps Pointer to struct containing result. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepEnables(struct vl_data *Dev, + struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps); + +/** + * @brief Sets the timeout of a requested sequence step. + * + * @par Function Description + * This function sets the timeout of a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param TimeOutMilliSecs Demanded timeout + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, unsigned int TimeOutMilliSecs); + +/** + * @brief Gets the timeout of a requested sequence step. + * + * @par Function Description + * This function retrieves the timeout of a requested sequence step. + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param SequenceStepId Sequence step identifier. + * @param pTimeOutMilliSecs Timeout value. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS Error SequenceStepId parameter not + * supported. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int *pTimeOutMilliSecs); + +/** + * @brief Gets number of sequence steps managed by the API. + * + * @par Function Description + * This function retrieves the number of sequence steps currently managed + * by the API + * + * @note This function Accesses the device + * + * @param Dev Device Handle + * @param pNumberOfSequenceSteps Out parameter reporting the number of + * sequence steps. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev, + uint8_t *pNumberOfSequenceSteps); + +/** + * @brief Gets the name of a given sequence step. + * + * @par Function Description + * This function retrieves the name of sequence steps corresponding to + * SequenceStepId. + * + * @note This function doesn't Accesses the device + * + * @param SequenceStepId Sequence step identifier. + * @param pSequenceStepsString Pointer to Info string + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSequenceStepsInfo( + uint8_t SequenceStepId, char *pSequenceStepsString); + +/** + * Program continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param InterMeasurementPeriodMilliSeconds Inter-Measurement Period in ms. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetInterMeasurementPeriodMilliSeconds( + struct vl_data *Dev, uint32_t InterMeasurementPeriodMilliSeconds); + +/** + * Get continuous mode Inter-Measurement period in milliseconds + * + * @par Function Description + * When trying to set too short time return INVALID_PARAMS minimal value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pInterMeasurementPeriodMilliSeconds Pointer to programmed + * Inter-Measurement Period in milliseconds. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetInterMeasurementPeriodMilliSeconds( + struct vl_data *Dev, uint32_t *pInterMeasurementPeriodMilliSeconds); + +/** + * @brief Enable/Disable Cross talk compensation feature + * + * @note This function is not Implemented. + * Enable/Disable Cross Talk by set to zero the Cross Talk value + * by using @a VL_SetXTalkCompensationRateMegaCps(). + * + * @param Dev Device Handle + * @param XTalkCompensationEnable Cross talk compensation + * to be set 0=disabled else = enabled + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t XTalkCompensationEnable); + +/** + * @brief Get Cross talk compensation rate + * + * @note This function is not Implemented. + * Enable/Disable Cross Talk by set to zero the Cross Talk value by + * using @a VL_SetXTalkCompensationRateMegaCps(). + * + * @param Dev Device Handle + * @param pXTalkCompensationEnable Pointer to the Cross talk compensation + * state 0=disabled or 1 = enabled + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t *pXTalkCompensationEnable); + +/** + * @brief Set Cross talk compensation rate + * + * @par Function Description + * Set Cross talk compensation rate. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param XTalkCompensationRateMegaCps Compensation rate in + * Mega counts per second (16.16 fix point) see datasheet for details + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetXTalkCompensationRateMegaCps( + struct vl_data *Dev, unsigned int XTalkCompensationRateMegaCps); + +/** + * @brief Get Cross talk compensation rate + * + * @par Function Description + * Get Cross talk compensation rate. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pXTalkCompensationRateMegaCps Pointer to Compensation rate + in Mega counts per second (16.16 fix point) see datasheet for details + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetXTalkCompensationRateMegaCps( + struct vl_data *Dev, unsigned int *pXTalkCompensationRateMegaCps); + +/** + * @brief Set Reference Calibration Parameters + * + * @par Function Description + * Set Reference Calibration Parameters. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param VhvSettings Parameter for VHV + * @param PhaseCal Parameter for PhaseCal + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetRefCalibration(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal); + +/** + * @brief Get Reference Calibration Parameters + * + * @par Function Description + * Get Reference Calibration Parameters. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVhvSettings Pointer to VHV parameter + * @param pPhaseCal Pointer to PhaseCal Parameter + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetRefCalibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + +/** + * @brief Get the number of the check limit managed by a given Device + * + * @par Function Description + * This function give the number of the check limit managed by the Device + * + * @note This function doesn't Access to the device + * + * @param pNumberOfLimitCheck Pointer to the number of check limit. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetNumberOfLimitCheck( + uint16_t *pNumberOfLimitCheck); + +/** + * @brief Return a description string for a given limit check number + * + * @par Function Description + * This function returns a description string for a given limit check number. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckString Pointer to the + description string of the given check limit. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is + returned when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckInfo(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString); + +/** + * @brief Return a the Status of the specified check limit + * + * @par Function Description + * This function returns the Status of the specified check limit. + * The value indicate if the check is fail or not. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckStatus Pointer to the + Limit Check Status of the given check limit. + * LimitCheckStatus : + * 0 the check is not fail + * 1 the check if fail or not enabled + * + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is + returned when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckStatus(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus); + +/** + * @brief Enable/Disable a specific limit check + * + * @par Function Description + * This function Enable/Disable a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param LimitCheckEnable if 1 the check limit + * corresponding to LimitCheckId is Enabled + * if 0 the check limit + * corresponding to LimitCheckId is disabled + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable); + +/** + * @brief Get specific limit check enable state + * + * @par Function Description + * This function get the enable state of a specific limit check. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckEnable Pointer to the check limit enable + * value. + * if 1 the check limit + * corresponding to LimitCheckId is Enabled + * if 0 the check limit + * corresponding to LimitCheckId is disabled + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + +/** + * @brief Set a specific limit check value + * + * @par Function Description + * This function set a specific limit check value. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param LimitCheckValue Limit check Value for a given + * LimitCheckId + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned when either + * LimitCheckId or LimitCheckValue value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetLimitCheckValue(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int LimitCheckValue); + +/** + * @brief Get a specific limit check value + * + * @par Function Description + * This function get a specific limit check value from device then it updates + * internal values and check enables. + * The limit check is identified with the LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckValue Pointer to Limit + * check Value for a given LimitCheckId. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned + * when LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckValue(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckValue); + +/** + * @brief Get the current value of the signal used for the limit check + * + * @par Function Description + * This function get a the current value of the signal used for the limit check. + * To obtain the latest value you should run a ranging before. + * The value reported is linked to the limit check identified with the + * LimitCheckId. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param LimitCheckId Limit Check ID + * (0<= LimitCheckId < VL_GetNumberOfLimitCheck() ). + * @param pLimitCheckCurrent Pointer to current Value for a + * given LimitCheckId. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned when + * LimitCheckId value is out of range. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent); + +/** + * @brief Enable (or disable) Wrap around Check + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param WrapAroundCheckEnable Wrap around Check to be set + * 0=disabled, other = enabled + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t WrapAroundCheckEnable); + +/** + * @brief Get setup of Wrap around Check + * + * @par Function Description + * This function get the wrapAround check enable parameters + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pWrapAroundCheckEnable Pointer to the Wrap around Check state + * 0=disabled or 1 = enabled + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t *pWrapAroundCheckEnable); + +/** + * @brief Set Dmax Calibration Parameters for a given device + * When one of the parameter is zero, this function will get parameter + * from NVM. + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param RangeMilliMeter Calibration Distance + * @param SignalRateRtnMegaCps Signal rate return read at CalDistance + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetDmaxCalParameters(struct vl_data *Dev, + uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps); + +/** + * @brief Get Dmax Calibration Parameters for a given device + * + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pRangeMilliMeter Pointer to Calibration Distance + * @param pSignalRateRtnMegaCps Pointer to Signal rate return + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetDmaxCalParameters(struct vl_data *Dev, + uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps); + +/** @} VL_parameters_group */ + +/** @defgroup VL_measurement_group VL53L0X Measurement Functions + * @brief Functions used for the measurements + * @{ + */ + +/** + * @brief Single shot measurement. + * + * @par Function Description + * Perform simple measurement sequence (Start measure, Wait measure to end, + * and returns when measurement is done). + * Once function returns, user can get valid data by calling + * VL_GetRangingMeasurement or VL_GetHistogramMeasurement + * depending on defined measurement mode + * User should Clear the interrupt in case this are enabled by using the + * function VL_ClearInterruptMask(). + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformSingleMeasurement(struct vl_data *Dev); + +/** + * @brief Perform Reference Calibration + * + * @details Perform a reference calibration of the Device. + * This function should be run from time to time before doing + * a ranging measurement. + * This function will launch a special ranging measurement, so + * if interrupt are enable an interrupt will be done. + * This function will clear the interrupt generated automatically. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pVhvSettings Pointer to vhv settings parameter. + * @param pPhaseCal Pointer to PhaseCal parameter. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformRefCalibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + +/** + * @brief Perform XTalk Measurement + * + * @details Measures the current cross talk from glass in front + * of the sensor. + * This functions performs a histogram measurement and uses the results + * to measure the crosstalk. For the function to be successful, there + * must be no target in front of the sensor. + * + * @warning This function is a blocking function + * + * @warning This function is not supported when the final range + * vcsel clock period is set below 10 PCLKS. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param TimeoutMs Histogram measurement duration. + * @param pXtalkPerSpad Output parameter containing the crosstalk + * measurement result, in MCPS/Spad. Format fixpoint 16:16. + * @param pAmbientTooHigh Output parameter which indicate that + * pXtalkPerSpad is not good if the Ambient is too high. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS vcsel clock period not supported + * for this operation. Must not be less than 10PCLKS. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev, + uint32_t TimeoutMs, unsigned int *pXtalkPerSpad, + uint8_t *pAmbientTooHigh); + +/** + * @brief Perform XTalk Calibration + * + * @details Perform a XTalk calibration of the Device. + * This function will launch a ranging measurement, if interrupts + * are enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the XTalk compensation + * and it will enable the cross talk before exit. + * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @note This function change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING + * + * @param Dev Device Handle + * @param XTalkCalDistance XTalkCalDistance value used for the XTalk + * computation. + * @param pXTalkCompensationRateMegaCps Pointer to new + * XTalkCompensation value. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformXTalkCalibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps); + +/** + * @brief Perform Offset Calibration + * + * @details Perform a Offset calibration of the Device. + * This function will launch a ranging measurement, if interrupts are + * enabled an interrupt will be done. + * This function will clear the interrupt generated automatically. + * This function will program a new value for the Offset calibration value + * This function will disable the VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD. + * + * @warning This function is a blocking function + * + * @note This function Access to the device + * + * @note This function does not change the device mode. + * + * @param Dev Device Handle + * @param CalDistanceMilliMeter Calibration distance value used for the + * offset compensation. + * @param pOffsetMicroMeter Pointer to new Offset value computed by the + * function. + * + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformOffsetCalibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter); + +/** + * @brief Start device measurement + * + * @details Started measurement will depend on device parameters set through + * @a VL_SetParameters() + * This is a non-blocking function. + * This function will change the uint8_t from VL_STATE_IDLE to + * VL_STATE_RUNNING. + * + * @note This function Access to the device + * + + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return VL_ERROR_MODE_NOT_SUPPORTED This error occurs when + * DeviceMode programmed with @a VL_SetDeviceMode is not in the supported + * list: + * Supported mode are: + * struct vl_data *ICEMODE_SINGLE_RANGING, + * struct vl_data *ICEMODE_CONTINUOUS_RANGING, + * struct vl_data *ICEMODE_CONTINUOUS_TIMED_RANGING + * @return VL_ERROR_TIME_OUT Time out on start measurement + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_StartMeasurement(struct vl_data *Dev); + +/** + * @brief Stop device measurement + * + * @details Will set the device in standby mode at end of current measurement\n + * Not necessary in single mode as device shall return automatically + * in standby mode at end of measurement. + * This function will change the uint8_t from + * VL_STATE_RUNNING to VL_STATE_IDLE. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_StopMeasurement(struct vl_data *Dev); + +/** + * @brief Return Measurement Data Ready + * + * @par Function Description + * This function indicate that a measurement data is ready. + * This function check if interrupt mode is used then check is done accordingly. + * If perform function clear the interrupt, this function will not work, + * like in case of @a VL_PerformSingleRangingMeasurement(). + * The previous function is blocking function, VL_GetMeasurementDataReady + * is used for non-blocking capture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementDataReady Pointer to Measurement Data Ready. + * 0=data not ready, 1 = data ready + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetMeasurementDataReady(struct vl_data *Dev, + uint8_t *pMeasurementDataReady); + +/** + * @brief Wait for device ready for a new measurement command. + * Blocking function. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param MaxLoop Max Number of polling loop (timeout). + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_WaitDeviceReadyForNewMeasurement( + struct vl_data *Dev, uint32_t MaxLoop); + +/** + * @brief Retrieve the Reference Signal after a measurements + * + * @par Function Description + * Get Reference Signal from last successful Ranging measurement + * This function return a valid value after that you call the + * @a VL_GetRangingMeasurementData(). + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pMeasurementRefSignal Pointer to the Ref Signal to fill up. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev, + unsigned int *pMeasurementRefSignal); + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Ranging measurement + * @warning USER should take care about @a VL_GetNumberOfROIZones() + * before get data. + * PAL will fill a NumberOfROIZones times the corresponding data + * structure used in the measurement function. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetRangingMeasurementData(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Retrieve the measurements from device for a given setup + * + * @par Function Description + * Get data from last successful Histogram measurement + * @warning USER should take care about @a VL_GetNumberOfROIZones() + * before get data. + * PAL will fill a NumberOfROIZones times the corresponding data structure + * used in the measurement function. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param pHistogramMeasurementData Pointer to the histogram data structure. + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + +/** + * @brief Performs a single ranging measurement and retrieve the ranging + * measurement data + * + * @par Function Description + * This function will change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING with @a VL_SetDeviceMode(), + * It performs measurement with @a VL_PerformSingleMeasurement() + * It get data from last successful Ranging measurement with + * @a VL_GetRangingMeasurementData. + * Finally it clear the interrupt with @a VL_ClearInterruptMask(). + * + * @note This function Access to the device + * + * @note This function change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING + * + * @param Dev Device Handle + * @param pRangingMeasurementData Pointer to the data structure to fill up. + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformSingleRangingMeasurement( + struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + +/** + * @brief Performs a single histogram measurement and retrieve the histogram + * measurement data + * Is equivalent to VL_PerformSingleMeasurement + + * VL_GetHistogramMeasurementData + * + * @par Function Description + * Get data from last successful Ranging measurement. + * This function will clear the interrupt in case of these are enabled. + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param pHistogramMeasurementData Pointer to the data structure to fill up. + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_PerformSingleHistogramMeasurement( + struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + +/** + * @brief Set the number of ROI Zones to be used for a specific Device + * + * @par Function Description + * Set the number of ROI Zones to be used for a specific Device. + * The programmed value should be less than the max number of ROI Zones given + * with @a VL_GetMaxNumberOfROIZones(). + * This version of API manage only one zone. + * + * @param Dev Device Handle + * @param NumberOfROIZones Number of ROI Zones to be used for a + * specific Device. + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INVALID_PARAMS This error is returned if + * NumberOfROIZones != 1 + */ +VL_API int8_t VL_SetNumberOfROIZones(struct vl_data *Dev, + uint8_t NumberOfROIZones); + +/** + * @brief Get the number of ROI Zones managed by the Device + * + * @par Function Description + * Get number of ROI Zones managed by the Device + * USER should take care about @a VL_GetNumberOfROIZones() + * before get data after a perform measurement. + * PAL will fill a NumberOfROIZones times the corresponding data + * structure used in the measurement function. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pNumberOfROIZones Pointer to the Number of ROI Zones value. + * @return VL_ERROR_NONE Success + */ +VL_API int8_t VL_GetNumberOfROIZones(struct vl_data *Dev, + uint8_t *pNumberOfROIZones); + +/** + * @brief Get the Maximum number of ROI Zones managed by the Device + * + * @par Function Description + * Get Maximum number of ROI Zones managed by the Device. + * + * @note This function doesn't Access to the device + * + * @param Dev Device Handle + * @param pMaxNumberOfROIZones Pointer to the Maximum Number + * of ROI Zones value. + * @return VL_ERROR_NONE Success + */ +VL_API int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev, + uint8_t *pMaxNumberOfROIZones); + +/** @} VL_measurement_group */ + +/** @defgroup VL_interrupt_group VL53L0X Interrupt Functions + * @brief Functions used for interrupt managements + * @{ + */ + +/** + * @brief Set the configuration of GPIO pin for a given device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param Pin ID of the GPIO Pin + * @param Functionality Select Pin functionality. + * Refer to ::uint8_t + * @param DeviceMode Device Mode associated to the Gpio. + * @param Polarity Set interrupt polarity. Active high + * or active low see ::uint8_t + * @return VL_ERROR_NONE Success + * @return VL_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted. + * @return VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs + * when Functionality programmed is not in the supported list: + * Supported value are: + * VL_GPIOFUNCTIONALITY_OFF, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH, + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT, + * VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t DeviceMode, uint8_t Functionality, + uint8_t Polarity); + +/** + * @brief Get current configuration for GPIO pin for a given device + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param Pin ID of the GPIO Pin + * @param pDeviceMode Pointer to Device Mode associated to the Gpio. + * @param pFunctionality Pointer to Pin functionality. + * Refer to ::uint8_t + * @param pPolarity Pointer to interrupt polarity. + * Active high or active low see ::uint8_t + * @return VL_ERROR_NONE Success + * @return VL_ERROR_GPIO_NOT_EXISTING Only Pin=0 is accepted. + * @return VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED This error occurs + * when Functionality programmed is not in the supported list: + * Supported value are: + * VL_GPIOFUNCTIONALITY_OFF, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH, + * VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT, + * VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t *pDeviceMode, + uint8_t *pFunctionality, + uint8_t *pPolarity); + +/** + * @brief Set low and high Interrupt thresholds for a given mode + * (ranging, ALS, ...) for a given device + * + * @par Function Description + * Set low and high Interrupt thresholds for a given mode (ranging, ALS, ...) + * for a given device + * + * @note This function Access to the device + * + * @note DeviceMode is ignored for the current device + * + * @param Dev Device Handle + * @param DeviceMode Device Mode for which change thresholds + * @param ThresholdLow Low threshold (mm, lux ..., depending on the mode) + * @param ThresholdHigh High threshold (mm, lux ..., depending on the mode) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int ThresholdLow, + unsigned int ThresholdHigh); + +/** + * @brief Get high and low Interrupt thresholds for a given mode + * (ranging, ALS, ...) for a given device + * + * @par Function Description + * Get high and low Interrupt thresholds for a given mode (ranging, ALS, ...) + * for a given device + * + * @note This function Access to the device + * + * @note DeviceMode is ignored for the current device + * + * @param Dev Device Handle + * @param DeviceMode Device Mode from which read thresholds + * @param pThresholdLow Low threshold (mm, lux ..., depending on the mode) + * @param pThresholdHigh High threshold (mm, lux ..., depending on the mode) + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int *pThresholdLow, + unsigned int *pThresholdHigh); + +/** + * @brief Return device stop completion status + * + * @par Function Description + * Returns stop completiob status. + * User shall call this function after a stop command + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pStopStatus Pointer to status variable to update + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetStopCompletedStatus(struct vl_data *Dev, + uint32_t *pStopStatus); + + +/** + * @brief Clear given system interrupt condition + * + * @par Function Description + * Clear given interrupt(s). + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param InterruptMask Mask of interrupts to clear + * @return VL_ERROR_NONE Success + * @return VL_ERROR_INTERRUPT_NOT_CLEARED Cannot clear interrupts + * + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_ClearInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask); + +/** + * @brief Return device interrupt status + * + * @par Function Description + * Returns currently raised interrupts by the device. + * User shall be able to activate/deactivate interrupts through + * @a VL_SetGpioConfig() + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pInterruptMaskStatus Pointer to status variable to update + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev, + uint32_t *pInterruptMaskStatus); + +/** + * @brief Configure ranging interrupt reported to system + * + * @note This function is not Implemented + * + * @param Dev Device Handle + * @param InterruptMask Mask of interrupt to Enable/disable + * (0:interrupt disabled or 1: interrupt enabled) + * @return VL_ERROR_NOT_IMPLEMENTED Not implemented + */ +VL_API int8_t VL_EnableInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask); + +/** @} VL_interrupt_group */ + +/** @defgroup VL_SPADfunctions_group VL53L0X SPAD Functions + * @brief Functions used for SPAD managements + * @{ + */ + +/** + * @brief Set the SPAD Ambient Damper Threshold value + * + * @par Function Description + * This function set the SPAD Ambient Damper Threshold value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param SpadAmbientDamperThreshold SPAD Ambient Damper Threshold value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t SpadAmbientDamperThreshold); + +/** + * @brief Get the current SPAD Ambient Damper Threshold value + * + * @par Function Description + * This function get the SPAD Ambient Damper Threshold value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pSpadAmbientDamperThreshold Pointer to programmed + * SPAD Ambient Damper Threshold value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperThreshold); + +/** + * @brief Set the SPAD Ambient Damper Factor value + * + * @par Function Description + * This function set the SPAD Ambient Damper Factor value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param SpadAmbientDamperFactor SPAD Ambient Damper Factor value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t SpadAmbientDamperFactor); + +/** + * @brief Get the current SPAD Ambient Damper Factor value + * + * @par Function Description + * This function get the SPAD Ambient Damper Factor value + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param pSpadAmbientDamperFactor Pointer to programmed SPAD Ambient + * Damper Factor value + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperFactor); + +/** + * @brief Performs Reference Spad Management + * + * @par Function Description + * The reference SPAD initialization procedure determines the minimum amount + * of reference spads to be enables to achieve a target reference signal rate + * and should be performed once during initialization. + * + * @note This function Access to the device + * + * @note This function change the device mode to + * struct vl_data *ICEMODE_SINGLE_RANGING + * + * @param Dev Device Handle + * @param refSpadCount Reports ref Spad Count + * @param isApertureSpads Reports if spads are of type + * aperture or non-aperture. + * 1:=aperture, 0:=Non-Aperture + * @return VL_ERROR_NONE Success + * @return VL_ERROR_REF_SPAD_INIT Error in the Ref Spad procedure. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_PerformRefSpadManagement(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + +/** + * @brief Applies Reference SPAD configuration + * + * @par Function Description + * This function applies a given number of reference spads, identified as + * either Aperture or Non-Aperture. + * The requested spad count and type are stored within the device specific + * parameters data for access by the host. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param refSpadCount Number of ref spads. + * @param isApertureSpads Defines if spads are of type + * aperture or non-aperture. + * 1:=aperture, 0:=Non-Aperture + * @return VL_ERROR_NONE Success + * @return VL_ERROR_REF_SPAD_INIT Error in the in the reference + * spad configuration. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_SetReferenceSpads(struct vl_data *Dev, + uint32_t refSpadCount, uint8_t isApertureSpads); + +/** + * @brief Retrieves SPAD configuration + * + * @par Function Description + * This function retrieves the current number of applied reference spads + * and also their type : Aperture or Non-Aperture. + * + * @note This function Access to the device + * + * @param Dev Device Handle + * @param refSpadCount Number ref Spad Count + * @param isApertureSpads Reports if spads are of type + * aperture or non-aperture. + * 1:=aperture, 0:=Non-Aperture + * @return VL_ERROR_NONE Success + * @return VL_ERROR_REF_SPAD_INIT Error in the in the reference + * spad configuration. + * @return "Other error code" See ::int8_t + */ +VL_API int8_t VL_GetReferenceSpads(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + +/** @} VL_SPADfunctions_group */ + +/** @} VL_cut11_group */ + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h new file mode 100644 index 000000000000..5964e0b0ed41 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_calibration.h @@ -0,0 +1,75 @@ +/* + * vl53l0x_api_calibration.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_API_CALIBRATION_H_ +#define _VL_API_CALIBRATION_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +int8_t VL_perform_xtalk_calibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps); + +int8_t VL_perform_offset_calibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, + int32_t *pOffsetMicroMeter); + +int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter); + +int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter); + +int8_t VL_apply_offset_adjustment(struct vl_data *Dev); + +int8_t VL_perform_ref_spad_management(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + +int8_t VL_set_reference_spads(struct vl_data *Dev, + uint32_t count, uint8_t isApertureSpads); + +int8_t VL_get_reference_spads(struct vl_data *Dev, + uint32_t *pSpadCount, uint8_t *pIsApertureSpads); + +int8_t VL_perform_phase_calibration(struct vl_data *Dev, + uint8_t *pPhaseCal, const uint8_t get_data_enable, + const uint8_t restore_config); + +int8_t VL_perform_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable); + +int8_t VL_set_ref_calibration(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal); + +int8_t VL_get_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + + + + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_CALIBRATION_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h new file mode 100644 index 000000000000..ac368cf8c598 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_core.h @@ -0,0 +1,98 @@ +/* + * vl53l0x_api_core.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_API_CORE_H_ +#define _VL_API_CORE_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +int8_t VL_reverse_bytes(uint8_t *data, uint32_t size); + +int8_t VL_measurement_poll_for_completion(struct vl_data *Dev); + +uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks); + +uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg); + +uint32_t VL_isqrt(uint32_t num); + +uint32_t VL_quadrature_sum(uint32_t a, uint32_t b); + +int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option); + +int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK); + +int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK); + +uint32_t VL_decode_timeout(uint16_t encoded_timeout); + +int8_t get_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t *pTimeOutMicroSecs); + +int8_t set_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t TimeOutMicroSecs); + +int8_t VL_set_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds); + +int8_t VL_get_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds); + +int8_t VL_load_tuning_settings(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer); + +int8_t VL_calc_sigma_estimate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *pSigmaEstimate, uint32_t *pDmax_mm); + +int8_t VL_get_total_xtalk_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_xtalk_rate_mcps); + +int8_t VL_get_total_signal_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_signal_rate_mcps); + +int8_t VL_get_pal_range_status(struct vl_data *Dev, + uint8_t DeviceRangeStatus, + unsigned int SignalRate, + uint16_t EffectiveSpadRtnCount, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + uint8_t *pPalRangeStatus); + +uint32_t VL_calc_timeout_mclks(struct vl_data *Dev, + uint32_t timeout_period_us, uint8_t vcsel_period_pclks); + +uint16_t VL_encode_timeout(uint32_t timeout_macro_clks); + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_CORE_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h new file mode 100644 index 000000000000..e6b48fc59c41 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_ranging.h @@ -0,0 +1,37 @@ +/* + * vl53l0x_api_ranging.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_API_RANGING_H_ +#define _VL_API_RANGING_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + + + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_API_RANGING_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h new file mode 100644 index 000000000000..78a2dcd4e794 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_api_strings.h @@ -0,0 +1,268 @@ +/* + * vl53l0x_api_strings.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + + +#ifndef VL_API_STRINGS_H_ +#define VL_API_STRINGS_H_ + +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +int8_t VL_get_device_info(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo); + +int8_t VL_get_device_error_string(uint8_t ErrorCode, + char *pDeviceErrorString); + +int8_t VL_get_range_status_string(uint8_t RangeStatus, + char *pRangeStatusString); + +int8_t VL_get_pal_error_string(int8_t PalErrorCode, + char *pPalErrorString); + +int8_t VL_get_pal_state_string(uint8_t PalStateCode, + char *pPalStateString); + +int8_t VL_get_sequence_steps_info( + uint8_t SequenceStepId, + char *pSequenceStepsString); + +int8_t VL_get_limit_check_info(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString); + + +#ifdef USE_EMPTY_STRING + #define VL_STRING_DEVICE_INFO_NAME "" + #define VL_STRING_DEVICE_INFO_NAME_TS0 "" + #define VL_STRING_DEVICE_INFO_NAME_TS1 "" + #define VL_STRING_DEVICE_INFO_NAME_TS2 "" + #define VL_STRING_DEVICE_INFO_NAME_ES1 "" + #define VL_STRING_DEVICE_INFO_TYPE "" + + /* PAL ERROR strings */ + #define VL_STRING_ERROR_NONE "" + #define VL_STRING_ERROR_CALIBRATION_WARNING "" + #define VL_STRING_ERROR_MIN_CLIPPED "" + #define VL_STRING_ERROR_UNDEFINED "" + #define VL_STRING_ERROR_INVALID_PARAMS "" + #define VL_STRING_ERROR_NOT_SUPPORTED "" + #define VL_STRING_ERROR_RANGE_ERROR "" + #define VL_STRING_ERROR_TIME_OUT "" + #define VL_STRING_ERROR_MODE_NOT_SUPPORTED "" + #define VL_STRING_ERROR_BUFFER_TOO_SMALL "" + #define VL_STRING_ERROR_GPIO_NOT_EXISTING "" + #define VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED "" + #define VL_STRING_ERROR_CONTROL_INTERFACE "" + #define VL_STRING_ERROR_INVALID_COMMAND "" + #define VL_STRING_ERROR_DIVISION_BY_ZERO "" + #define VL_STRING_ERROR_REF_SPAD_INIT "" + #define VL_STRING_ERROR_NOT_IMPLEMENTED "" + + #define VL_STRING_UNKNOWN_ERROR_CODE "" + + + + /* Range Status */ + #define VL_STRING_RANGESTATUS_NONE "" + #define VL_STRING_RANGESTATUS_RANGEVALID "" + #define VL_STRING_RANGESTATUS_SIGMA "" + #define VL_STRING_RANGESTATUS_SIGNAL "" + #define VL_STRING_RANGESTATUS_MINRANGE "" + #define VL_STRING_RANGESTATUS_PHASE "" + #define VL_STRING_RANGESTATUS_HW "" + + + /* Range Status */ + #define VL_STRING_STATE_POWERDOWN "" + #define VL_STRING_STATE_WAIT_STATICINIT "" + #define VL_STRING_STATE_STANDBY "" + #define VL_STRING_STATE_IDLE "" + #define VL_STRING_STATE_RUNNING "" + #define VL_STRING_STATE_UNKNOWN "" + #define VL_STRING_STATE_ERROR "" + + + /* Device Specific */ + #define VL_STRING_DEVICEERROR_NONE "" + #define VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE "" + #define VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE "" + #define VL_STRING_DEVICEERROR_NOVHVVALUEFOUND "" + #define VL_STRING_DEVICEERROR_MSRCNOTARGET "" + #define VL_STRING_DEVICEERROR_SNRCHECK "" + #define VL_STRING_DEVICEERROR_RANGEPHASECHECK "" + #define VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK "" + #define VL_STRING_DEVICEERROR_TCC "" + #define VL_STRING_DEVICEERROR_PHASECONSISTENCY "" + #define VL_STRING_DEVICEERROR_MINCLIP "" + #define VL_STRING_DEVICEERROR_RANGECOMPLETE "" + #define VL_STRING_DEVICEERROR_ALGOUNDERFLOW "" + #define VL_STRING_DEVICEERROR_ALGOOVERFLOW "" + #define VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD "" + #define VL_STRING_DEVICEERROR_UNKNOWN "" + + /* Check Enable */ + #define VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE "" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE "" + #define VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP "" + #define VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD "" + + /* Sequence Step */ + #define VL_STRING_SEQUENCESTEP_TCC "" + #define VL_STRING_SEQUENCESTEP_DSS "" + #define VL_STRING_SEQUENCESTEP_MSRC "" + #define VL_STRING_SEQUENCESTEP_PRE_RANGE "" + #define VL_STRING_SEQUENCESTEP_FINAL_RANGE "" +#else + #define VL_STRING_DEVICE_INFO_NAME "VL53L0X cut1.0" + #define VL_STRING_DEVICE_INFO_NAME_TS0 "VL53L0X TS0" + #define VL_STRING_DEVICE_INFO_NAME_TS1 "VL53L0X TS1" + #define VL_STRING_DEVICE_INFO_NAME_TS2 "VL53L0X TS2" + #define VL_STRING_DEVICE_INFO_NAME_ES1 "VL53L0X ES1 or later" + #define VL_STRING_DEVICE_INFO_TYPE "VL53L0X" + + /* PAL ERROR strings */ + #define VL_STRING_ERROR_NONE \ + "No Error" + #define VL_STRING_ERROR_CALIBRATION_WARNING \ + "Calibration Warning Error" + #define VL_STRING_ERROR_MIN_CLIPPED \ + "Min clipped error" + #define VL_STRING_ERROR_UNDEFINED \ + "Undefined error" + #define VL_STRING_ERROR_INVALID_PARAMS \ + "Invalid parameters error" + #define VL_STRING_ERROR_NOT_SUPPORTED \ + "Not supported error" + #define VL_STRING_ERROR_RANGE_ERROR \ + "Range error" + #define VL_STRING_ERROR_TIME_OUT \ + "Time out error" + #define VL_STRING_ERROR_MODE_NOT_SUPPORTED \ + "Mode not supported error" + #define VL_STRING_ERROR_BUFFER_TOO_SMALL \ + "Buffer too small" + #define VL_STRING_ERROR_GPIO_NOT_EXISTING \ + "GPIO not existing" + #define VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED \ + "GPIO funct not supported" + #define VL_STRING_ERROR_INTERRUPT_NOT_CLEARED \ + "Interrupt not Cleared" + #define VL_STRING_ERROR_CONTROL_INTERFACE \ + "Control Interface Error" + #define VL_STRING_ERROR_INVALID_COMMAND \ + "Invalid Command Error" + #define VL_STRING_ERROR_DIVISION_BY_ZERO \ + "Division by zero Error" + #define VL_STRING_ERROR_REF_SPAD_INIT \ + "Reference Spad Init Error" + #define VL_STRING_ERROR_NOT_IMPLEMENTED \ + "Not implemented error" + + #define VL_STRING_UNKNOWN_ERROR_CODE \ + "Unknown Error Code" + + + + /* Range Status */ + #define VL_STRING_RANGESTATUS_NONE "No Update" + #define VL_STRING_RANGESTATUS_RANGEVALID "Range Valid" + #define VL_STRING_RANGESTATUS_SIGMA "Sigma Fail" + #define VL_STRING_RANGESTATUS_SIGNAL "Signal Fail" + #define VL_STRING_RANGESTATUS_MINRANGE "Min Range Fail" + #define VL_STRING_RANGESTATUS_PHASE "Phase Fail" + #define VL_STRING_RANGESTATUS_HW "Hardware Fail" + + + /* Range Status */ + #define VL_STRING_STATE_POWERDOWN "POWERDOWN State" + #define VL_STRING_STATE_WAIT_STATICINIT \ + "Wait for staticinit State" + #define VL_STRING_STATE_STANDBY "STANDBY State" + #define VL_STRING_STATE_IDLE "IDLE State" + #define VL_STRING_STATE_RUNNING "RUNNING State" + #define VL_STRING_STATE_UNKNOWN "UNKNOWN State" + #define VL_STRING_STATE_ERROR "ERROR State" + + + /* Device Specific */ + #define VL_STRING_DEVICEERROR_NONE "No Update" + #define VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE \ + "VCSEL Continuity Test Failure" + #define VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE \ + "VCSEL Watchdog Test Failure" + #define VL_STRING_DEVICEERROR_NOVHVVALUEFOUND \ + "No VHV Value found" + #define VL_STRING_DEVICEERROR_MSRCNOTARGET \ + "MSRC No Target Error" + #define VL_STRING_DEVICEERROR_SNRCHECK \ + "SNR Check Exit" + #define VL_STRING_DEVICEERROR_RANGEPHASECHECK \ + "Range Phase Check Error" + #define VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK \ + "Sigma Threshold Check Error" + #define VL_STRING_DEVICEERROR_TCC \ + "TCC Error" + #define VL_STRING_DEVICEERROR_PHASECONSISTENCY \ + "Phase Consistency Error" + #define VL_STRING_DEVICEERROR_MINCLIP \ + "Min Clip Error" + #define VL_STRING_DEVICEERROR_RANGECOMPLETE \ + "Range Complete" + #define VL_STRING_DEVICEERROR_ALGOUNDERFLOW \ + "Range Algo Underflow Error" + #define VL_STRING_DEVICEERROR_ALGOOVERFLOW \ + "Range Algo Overlow Error" + #define VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD \ + "Range Ignore Threshold Error" + #define VL_STRING_DEVICEERROR_UNKNOWN \ + "Unknown error code" + + /* Check Enable */ + #define VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE \ + "SIGMA FINAL RANGE" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE \ + "SIGNAL RATE FINAL RANGE" + #define VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP \ + "SIGNAL REF CLIP" + #define VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD \ + "RANGE IGNORE THRESHOLD" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC \ + "SIGNAL RATE MSRC" + #define VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE \ + "SIGNAL RATE PRE RANGE" + + /* Sequence Step */ + #define VL_STRING_SEQUENCESTEP_TCC "TCC" + #define VL_STRING_SEQUENCESTEP_DSS "DSS" + #define VL_STRING_SEQUENCESTEP_MSRC "MSRC" + #define VL_STRING_SEQUENCESTEP_PRE_RANGE "PRE RANGE" + #define VL_STRING_SEQUENCESTEP_FINAL_RANGE "FINAL RANGE" +#endif /* USE_EMPTY_STRING */ + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h new file mode 100644 index 000000000000..50495a0dc7d2 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_def.h @@ -0,0 +1,619 @@ +/* + * vl53l0x_def.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/** + * @file VL_def.h + * + * @brief Type definitions for VL53L0X API. + * + */ + + +#ifndef _VL_DEF_H_ +#define _VL_DEF_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup VL_globaldefine_group VL53L0X Defines + * @brief VL53L0X Defines + * @{ + */ + + +/** PAL SPECIFICATION major version */ +#define VL53L0X10_SPECIFICATION_VER_MAJOR 1 +/** PAL SPECIFICATION minor version */ +#define VL53L0X10_SPECIFICATION_VER_MINOR 2 +/** PAL SPECIFICATION sub version */ +#define VL53L0X10_SPECIFICATION_VER_SUB 7 +/** PAL SPECIFICATION sub version */ +#define VL53L0X10_SPECIFICATION_VER_REVISION 1440 + +/** VL53L0X PAL IMPLEMENTATION major version */ +#define VL53L0X10_IMPLEMENTATION_VER_MAJOR 1 +/** VL53L0X PAL IMPLEMENTATION minor version */ +#define VL53L0X10_IMPLEMENTATION_VER_MINOR 0 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL53L0X10_IMPLEMENTATION_VER_SUB 9 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL53L0X10_IMPLEMENTATION_VER_REVISION 3673 + +/** PAL SPECIFICATION major version */ +#define VL_SPECIFICATION_VER_MAJOR 1 +/** PAL SPECIFICATION minor version */ +#define VL_SPECIFICATION_VER_MINOR 2 +/** PAL SPECIFICATION sub version */ +#define VL_SPECIFICATION_VER_SUB 7 +/** PAL SPECIFICATION sub version */ +#define VL_SPECIFICATION_VER_REVISION 1440 + +/** VL53L0X PAL IMPLEMENTATION major version */ +#define VL_IMPLEMENTATION_VER_MAJOR 1 +/** VL53L0X PAL IMPLEMENTATION minor version */ +#define VL_IMPLEMENTATION_VER_MINOR 0 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL_IMPLEMENTATION_VER_SUB 2 +/** VL53L0X PAL IMPLEMENTATION sub version */ +#define VL_IMPLEMENTATION_VER_REVISION 4823 +#define VL_DEFAULT_MAX_LOOP 2000 +#define VL_MAX_STRING_LENGTH 32 + + +#include "vl53l0x_device.h" +#include "vl53l0x_types.h" + + +/**************************************** + * PRIVATE define do not edit + ****************************************/ + +/** @brief Defines the parameters of the Get Version Functions + */ +struct VL_Version_t { + uint32_t revision; /*!< revision number */ + uint8_t major; /*!< major number */ + uint8_t minor; /*!< minor number */ + uint8_t build; /*!< build number */ +}; + + +/** @brief Defines the parameters of the Get Device Info Functions + */ +struct VL_DeviceInfo_t { + char Name[VL_MAX_STRING_LENGTH]; + /*!< Name of the Device e.g. Left_Distance */ + char Type[VL_MAX_STRING_LENGTH]; + /*!< Type of the Device e.g VL53L0X */ + char ProductId[VL_MAX_STRING_LENGTH]; + /*!< Product Identifier String */ + uint8_t ProductType; + /*!< Product Type, VL53L0X = 1, VL53L1 = 2 */ + uint8_t ProductRevisionMajor; + /*!< Product revision major */ + uint8_t ProductRevisionMinor; + /*!< Product revision minor */ +}; + + +/** @defgroup VL_define_Error_group Error and Warning code returned by API + * The following DEFINE are used to identify the PAL ERROR + * @{ + */ + +#define VL_ERROR_NONE ((int8_t) 0) +#define VL_ERROR_CALIBRATION_WARNING ((int8_t) -1) + /*!< Warning invalid calibration data may be in used*/ + /*\a VL_InitData()*/ + /*\a VL_GetOffsetCalibrationData*/ + /*\a VL_SetOffsetCalibrationData */ +#define VL_ERROR_MIN_CLIPPED ((int8_t) -2) + /*!< Warning parameter passed was clipped to min before to be applied */ + +#define VL_ERROR_UNDEFINED ((int8_t) -3) + /*!< Unqualified error */ +#define VL_ERROR_INVALID_PARAMS ((int8_t) -4) + /*!< Parameter passed is invalid or out of range */ +#define VL_ERROR_NOT_SUPPORTED ((int8_t) -5) + /*!< Function is not supported in current mode or configuration */ +#define VL_ERROR_RANGE_ERROR ((int8_t) -6) + /*!< Device report a ranging error interrupt status */ +#define VL_ERROR_TIME_OUT ((int8_t) -7) + /*!< Aborted due to time out */ +#define VL_ERROR_MODE_NOT_SUPPORTED ((int8_t) -8) + /*!< Asked mode is not supported by the device */ +#define VL_ERROR_BUFFER_TOO_SMALL ((int8_t) -9) + /*!< ... */ +#define VL_ERROR_GPIO_NOT_EXISTING ((int8_t) -10) + /*!< User tried to setup a non-existing GPIO pin */ +#define VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED ((int8_t) -11) + /*!< unsupported GPIO functionality */ +#define VL_ERROR_INTERRUPT_NOT_CLEARED ((int8_t) -12) + /*!< Error during interrupt clear */ +#define VL_ERROR_CONTROL_INTERFACE ((int8_t) -20) + /*!< error reported from IO functions */ +#define VL_ERROR_INVALID_COMMAND ((int8_t) -30) + /*!< The command is not allowed in the current device state*/ + /* * (power down) */ +#define VL_ERROR_DIVISION_BY_ZERO ((int8_t) -40) + /*!< In the function a division by zero occurs */ +#define VL_ERROR_REF_SPAD_INIT ((int8_t) -50) + /*!< Error during reference SPAD initialization */ +#define VL_ERROR_NOT_IMPLEMENTED ((int8_t) -99) + /*!< Tells requested functionality has not been implemented yet or*/ + /* * not compatible with the device */ +/** @} VL_define_Error_group */ + + +/** @defgroup VL_define_DeviceModes_group Defines Device modes + * Defines all possible modes for the device + * @{ + */ + +#define VL_DEVICEMODE_SINGLE_RANGING ((uint8_t) 0) +#define VL_DEVICEMODE_CONTINUOUS_RANGING ((uint8_t) 1) +#define VL_DEVICEMODE_SINGLE_HISTOGRAM ((uint8_t) 2) +#define VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING ((uint8_t) 3) +#define VL_DEVICEMODE_SINGLE_ALS ((uint8_t) 10) +#define VL_DEVICEMODE_GPIO_DRIVE ((uint8_t) 20) +#define VL_DEVICEMODE_GPIO_OSC ((uint8_t) 21) + /* ... Modes to be added depending on device */ +/** @} VL_define_DeviceModes_group */ + + + +/** @defgroup VL_define_HistogramModes_group Defines Histogram modes + * Defines all possible Histogram modes for the device + * @{ + */ + +#define VL_HISTOGRAMMODE_DISABLED ((uint8_t) 0) + /*!< Histogram Disabled */ +#define VL_HISTOGRAMMODE_REFERENCE_ONLY ((uint8_t) 1) + /*!< Histogram Reference array only */ +#define VL_HISTOGRAMMODE_RETURN_ONLY ((uint8_t) 2) + /*!< Histogram Return array only */ +#define VL_HISTOGRAMMODE_BOTH ((uint8_t) 3) + /*!< Histogram both Reference and Return Arrays */ + /* ... Modes to be added depending on device */ +/** @} VL_define_HistogramModes_group */ + + +/** @defgroup VL_define_PowerModes_group List of available Power Modes + * List of available Power Modes + * @{ + */ + +#define VL_POWERMODE_STANDBY_LEVEL1 ((uint8_t) 0) + /*!< Standby level 1 */ +#define VL_POWERMODE_STANDBY_LEVEL2 ((uint8_t) 1) + /*!< Standby level 2 */ +#define VL_POWERMODE_IDLE_LEVEL1 ((uint8_t) 2) + /*!< Idle level 1 */ +#define VL_POWERMODE_IDLE_LEVEL2 ((uint8_t) 3) + /*!< Idle level 2 */ + +/** @} VL_define_PowerModes_group */ + + +/** @brief Defines all parameters for the device + */ +struct VL_DeviceParameters_t { + uint8_t DeviceMode; + /*!< Defines type of measurement to be done for the next measure */ + uint8_t HistogramMode; + /*!< Defines type of histogram measurement to be done for the next*/ + /* * measure */ + uint32_t MeasurementTimingBudgetMicroSeconds; + /*!< Defines the allowed total time for a single measurement */ + uint32_t InterMeasurementPeriodMilliSeconds; + /*!< Defines time between two consecutive measurements (between two*/ + /* * measurement starts). If set to 0 means back-to-back mode */ + uint8_t XTalkCompensationEnable; + /*!< Tells if Crosstalk compensation shall be enable or not */ + uint16_t XTalkCompensationRangeMilliMeter; + /*!< CrossTalk compensation range in millimeter */ + unsigned int XTalkCompensationRateMegaCps; + /*!< CrossTalk compensation rate in Mega counts per seconds.*/ + /* * Expressed in 16.16 fixed point format. */ + int32_t RangeOffsetMicroMeters; + /*!< Range offset adjustment (mm). */ + + uint8_t LimitChecksEnable[VL_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check enable for this device. */ + uint8_t LimitChecksStatus[VL_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Status of the check linked to last*/ + /** measurement. */ + unsigned int LimitChecksValue[VL_CHECKENABLE_NUMBER_OF_CHECKS]; + /*!< This Array store all the Limit Check value for this device */ + + uint8_t WrapAroundCheckEnable; + /*!< Tells if Wrap Around Check shall be enable or not */ +}; + + +/** @defgroup VL_define_State_group Defines the current status + * of the device Defines the current status of the device + * @{ + */ + +#define VL_STATE_POWERDOWN ((uint8_t) 0) + /*!< Device is in HW reset */ +#define VL_STATE_WAIT_STATICINIT ((uint8_t) 1) + /*!< Device is initialized and wait for static initialization */ +#define VL_STATE_STANDBY ((uint8_t) 2) + /*!< Device is in Low power Standby mode */ +#define VL_STATE_IDLE ((uint8_t) 3) + /*!< Device has been initialized and ready to do measurements */ +#define VL_STATE_RUNNING ((uint8_t) 4) + /*!< Device is performing measurement */ +#define VL_STATE_UNKNOWN ((uint8_t) 98) + /*!< Device is in unknown state and need to be rebooted */ +#define VL_STATE_ERROR ((uint8_t) 99) + /*!< Device is in error state and need to be rebooted */ + +/** @} VL_define_State_group */ + + +/** @brief Structure containing the Dmax computation parameters and data + */ +struct VL_DMaxData_t { + int32_t AmbTuningWindowFactor_K; + /*!< internal algo tuning (*1000) */ + int32_t RetSignalAt0mm; + /*!< intermediate dmax computation value caching */ +}; + +/** + * @struct VL_RangeData_t + * @brief Range measurement data. + */ +struct VL_RangingMeasurementData_t { + uint32_t TimeStamp; /*!< 32-bit time stamp. */ + uint32_t MeasurementTimeUsec; + /*!< Give the Measurement time needed by the device to do the */ + /** measurement.*/ + + + uint16_t RangeMilliMeter; /*!< range distance in millimeter. */ + + uint16_t RangeDMaxMilliMeter; + /*!< Tells what is the maximum detection distance of */ + /* the device */ + /* * in current setup and environment conditions (Filled when */ + /* * applicable) */ + + unsigned int SignalRateRtnMegaCps; + /*!< Return signal rate (MCPS)\n these is a 16.16 fix point */ + /* * value, which is effectively a measure of target */ + /* * reflectance.*/ + unsigned int AmbientRateRtnMegaCps; + /*!< Return ambient rate (MCPS)\n these is a 16.16 fix point */ + /* * value, which is effectively a measure of the ambien */ + /* * t light.*/ + + uint16_t EffectiveSpadRtnCount; + /*!< Return the effective SPAD count for the return signal. */ + /* * To obtain Real value it should be divided by 256 */ + + uint8_t ZoneId; + /*!< Denotes which zone and range scheduler stage the range */ + /* * data relates to. */ + uint8_t RangeFractionalPart; + /*!< Fractional part of range distance. Final value is a */ + /* * FixPoint168 value. */ + uint8_t RangeStatus; + /*!< Range Status for the current measurement. This is device */ + /* * dependent. Value = 0 means value is valid. */ + /* * See \ref RangeStatusPage */ +}; + + +#define VL_HISTOGRAM_BUFFER_SIZE 24 + +/** + * @struct VL_HistogramData_t + * @brief Histogram measurement data. + */ +struct VL_HistogramMeasurementData_t { + /* Histogram Measurement data */ + uint32_t HistogramData[VL_HISTOGRAM_BUFFER_SIZE]; + /*!< Histogram data */ + uint8_t HistogramType; /*!< Indicate the types of histogram data : */ + /*Return only, Reference only, both Return and Reference */ + uint8_t FirstBin; /*!< First Bin value */ + uint8_t BufferSize; /*!< Buffer Size - Set by the user.*/ + uint8_t NumberOfBins; + /*!< Number of bins filled by the histogram measurement */ + + uint8_t ErrorStatus; + /*!< Error status of the current measurement. \n */ + /* see @a ::uint8_t @a VL_GetStatusErrorString() */ +}; + +#define VL_REF_SPAD_BUFFER_SIZE 6 + +/** + * @struct VL_SpadData_t + * @brief Spad Configuration Data. + */ +struct VL_SpadData_t { + uint8_t RefSpadEnables[VL_REF_SPAD_BUFFER_SIZE]; + /*!< Reference Spad Enables */ + uint8_t RefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE]; + /*!< Reference Spad Good Spad Map */ +}; + +struct VL_DeviceSpecificParameters_t { + unsigned int OscFrequencyMHz; /* Frequency used */ + + uint16_t LastEncodedTimeout; + /* last encoded Time out used for timing budget*/ + + uint8_t Pin0GpioFunctionality; + /* store the functionality of the GPIO: pin0 */ + + uint32_t FinalRangeTimeoutMicroSecs; + /*!< Execution time of the final range*/ + uint8_t FinalRangeVcselPulsePeriod; + /*!< Vcsel pulse period (pll clocks) for the final range measurement*/ + uint32_t PreRangeTimeoutMicroSecs; + /*!< Execution time of the final range*/ + uint8_t PreRangeVcselPulsePeriod; + /*!< Vcsel pulse period (pll clocks) for the pre-range measurement*/ + + uint16_t SigmaEstRefArray; + /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */ + uint16_t SigmaEstEffPulseWidth; + /*!< Effective Pulse width for sigma estimate in 1/100th */ + /* * of ns e.g. 900 = 9.0ns */ + uint16_t SigmaEstEffAmbWidth; + /*!< Effective Ambient width for sigma estimate in 1/100th of ns */ + /* * e.g. 500 = 5.0ns */ + + + uint8_t ReadDataFromDeviceDone; /* Indicate if read from device has */ + /*been done (==1) or not (==0) */ + uint8_t ModuleId; /* Module ID */ + uint8_t Revision; /* test Revision */ + char ProductId[VL_MAX_STRING_LENGTH]; + /* Product Identifier String */ + uint8_t ReferenceSpadCount; /* used for ref spad management */ + uint8_t ReferenceSpadType; /* used for ref spad management */ + uint8_t RefSpadsInitialised; /* reports if ref spads are initialised. */ + uint32_t PartUIDUpper; /*!< Unique Part ID Upper */ + uint32_t PartUIDLower; /*!< Unique Part ID Lower */ + unsigned int SignalRateMeasFixed400mm; /*!< Peek Signal rate at 400 mm*/ + +}; + +/** + * @struct VL_DevData_t + * + * @brief VL53L0X PAL device ST private data structure \n + * End user should never access any of these field directly + * + * These must never access directly but only via macro + */ +struct VL_DevData_t { + struct VL_DMaxData_t DMaxData; + /*!< Dmax Data */ + int32_t Part2PartOffsetNVMMicroMeter; + /*!< backed up NVM value */ + int32_t Part2PartOffsetAdjustmentNVMMicroMeter; + /*!< backed up NVM value representing additional offset adjustment */ + struct VL_DeviceParameters_t CurrentParameters; + /*!< Current Device Parameter */ + struct VL_RangingMeasurementData_t LastRangeMeasure; + /*!< Ranging Data */ + struct VL_HistogramMeasurementData_t LastHistogramMeasure; + /*!< Histogram Data */ + struct VL_DeviceSpecificParameters_t DeviceSpecificParameters; + /*!< Parameters specific to the device */ + struct VL_SpadData_t SpadData; + /*!< Spad Data */ + uint8_t SequenceConfig; + /*!< Internal value for the sequence config */ + uint8_t RangeFractionalEnable; + /*!< Enable/Disable fractional part of ranging data */ + uint8_t PalState; + /*!< Current state of the PAL for this device */ + uint8_t PowerMode; + /*!< Current Power Mode */ + uint16_t SigmaEstRefArray; + /*!< Reference array sigma value in 1/100th of [mm] e.g. 100 = 1mm */ + uint16_t SigmaEstEffPulseWidth; + /*!< Effective Pulse width for sigma estimate in 1/100th */ + /* of ns e.g. 900 = 9.0ns */ + uint16_t SigmaEstEffAmbWidth; + /*!< Effective Ambient width for sigma estimate in 1/100th of ns */ + /* * e.g. 500 = 5.0ns */ + uint8_t StopVariable; + /*!< StopVariable used during the stop sequence */ + uint16_t targetRefRate; + /*!< Target Ambient Rate for Ref spad management */ + unsigned int SigmaEstimate; + /*!< Sigma Estimate - based on ambient & VCSEL rates and */ + /** signal_total_events */ + unsigned int SignalEstimate; + /*!< Signal Estimate - based on ambient & VCSEL rates and cross talk */ + unsigned int LastSignalRefMcps; + /*!< Latest Signal ref in Mcps */ + uint8_t *pTuningSettingsPointer; + /*!< Pointer for Tuning Settings table */ + uint8_t UseInternalTuningSettings; + /*!< Indicate if we use Tuning Settings table */ + uint16_t LinearityCorrectiveGain; + /*!< Linearity Corrective Gain value in x1000 */ + uint16_t DmaxCalRangeMilliMeter; + /*!< Dmax Calibration Range millimeter */ + unsigned int DmaxCalSignalRateRtnMegaCps; + /*!< Dmax Calibration Signal Rate Return MegaCps */ + +}; + + +/** @defgroup VL_define_InterruptPolarity_group Defines the Polarity + * of the Interrupt + * Defines the Polarity of the Interrupt + * @{ + */ + +#define VL_INTERRUPTPOLARITY_LOW ((uint8_t) 0) +/*!< Set active low polarity best setup for falling edge. */ +#define VL_INTERRUPTPOLARITY_HIGH ((uint8_t) 1) +/*!< Set active high polarity best setup for rising edge. */ + +/** @} VL_define_InterruptPolarity_group */ + + +/** @defgroup VL_define_VcselPeriod_group Vcsel Period Defines + * Defines the range measurement for which to access the vcsel period. + * @{ + */ + +#define VL_VCSEL_PERIOD_PRE_RANGE ((uint8_t) 0) +/*!>9)&0xFFFF) +#define VL_FIXPOINT97TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<9) + +#define VL_FIXPOINT1616TOFIXPOINT88(Value) \ + (uint16_t)((Value>>8)&0xFFFF) +#define VL_FIXPOINT88TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<8) + +#define VL_FIXPOINT1616TOFIXPOINT412(Value) \ + (uint16_t)((Value>>4)&0xFFFF) +#define VL_FIXPOINT412TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<4) + +#define VL_FIXPOINT1616TOFIXPOINT313(Value) \ + (uint16_t)((Value>>3)&0xFFFF) +#define VL_FIXPOINT313TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<3) + +#define VL_FIXPOINT1616TOFIXPOINT08(Value) \ + (uint8_t)((Value>>8)&0x00FF) +#define VL_FIXPOINT08TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<8) + +#define VL_FIXPOINT1616TOFIXPOINT53(Value) \ + (uint8_t)((Value>>13)&0x00FF) +#define VL_FIXPOINT53TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<13) + +#define VL_FIXPOINT1616TOFIXPOINT102(Value) \ + (uint16_t)((Value>>14)&0x0FFF) +#define VL_FIXPOINT102TOFIXPOINT1616(Value) \ + (unsigned int)(Value<<12) + +#define VL_MAKEUINT16(lsb, msb) (uint16_t)((((uint16_t)msb)<<8) + \ + (uint16_t)lsb) + +/** @} VL_define_GeneralMacro_group */ + +/** @} VL_globaldefine_group */ + + + + + + + +#ifdef __cplusplus +} +#endif + + +#endif /* _VL_DEF_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h new file mode 100644 index 000000000000..b296ff8d93c7 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_device.h @@ -0,0 +1,246 @@ +/* + * vl53l0x_device.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/** + * Device specific defines. To be adapted by implementer for the targeted + * device. + */ + +#ifndef _VL_DEVICE_H_ +#define _VL_DEVICE_H_ + +#include "vl53l0x_types.h" + + +/** @defgroup VL_DevSpecDefines_group VL53L0X cut1.1 + * Device Specific Defines + * @brief VL53L0X cut1.1 Device Specific Defines + * @{ + */ + + +/** @defgroup uint8_t_group Device Error + * @brief Device Error code + * + * This enum is Device specific it should be updated in the implementation + * Use @a VL_GetStatusErrorString() to get the string. + * It is related to Status Register of the Device. + * @{ + */ + +#define VL_DEVICEERROR_NONE ((uint8_t) 0) + /*!< 0 NoError */ +#define VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE ((uint8_t) 1) +#define VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE ((uint8_t) 2) +#define VL_DEVICEERROR_NOVHVVALUEFOUND ((uint8_t) 3) +#define VL_DEVICEERROR_MSRCNOTARGET ((uint8_t) 4) +#define VL_DEVICEERROR_SNRCHECK ((uint8_t) 5) +#define VL_DEVICEERROR_RANGEPHASECHECK ((uint8_t) 6) +#define VL_DEVICEERROR_SIGMATHRESHOLDCHECK ((uint8_t) 7) +#define VL_DEVICEERROR_TCC ((uint8_t) 8) +#define VL_DEVICEERROR_PHASECONSISTENCY ((uint8_t) 9) +#define VL_DEVICEERROR_MINCLIP ((uint8_t) 10) +#define VL_DEVICEERROR_RANGECOMPLETE ((uint8_t) 11) +#define VL_DEVICEERROR_ALGOUNDERFLOW ((uint8_t) 12) +#define VL_DEVICEERROR_ALGOOVERFLOW ((uint8_t) 13) +#define VL_DEVICEERROR_RANGEIGNORETHRESHOLD ((uint8_t) 14) + +/** @} end of uint8_t_group */ + + +/** @defgroup VL_CheckEnable_group Check Enable list + * @brief Check Enable code + * + * Define used to specify the LimitCheckId. + * Use @a VL_GetLimitCheckInfo() to get the string. + * @{ + */ + +#define VL_CHECKENABLE_SIGMA_FINAL_RANGE 0 +#define VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE 1 +#define VL_CHECKENABLE_SIGNAL_REF_CLIP 2 +#define VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD 3 +#define VL_CHECKENABLE_SIGNAL_RATE_MSRC 4 +#define VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE 5 + +#define VL_CHECKENABLE_NUMBER_OF_CHECKS 6 + +/** @} end of VL_CheckEnable_group */ + + +/** @defgroup uint8_t_group Gpio Functionality + * @brief Defines the different functionalities for the device GPIO(s) + * @{ + */ + +#define VL_GPIOFUNCTIONALITY_OFF \ + ((uint8_t) 0) /*!< NO Interrupt */ +#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW \ + ((uint8_t) 1) /*!< Level Low (value < thresh_low) */ +#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH \ + ((uint8_t) 2)/*!< Level High (value > thresh_high)*/ +#define VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT \ + ((uint8_t) 3) + /*!< Out Of Window (value < thresh_low OR value > thresh_high) */ +#define VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY \ + ((uint8_t) 4) /*!< New Sample Ready */ + +/** @} end of uint8_t_group */ + + +/* Device register map */ + +/** @defgroup VL_DefineRegisters_group Define Registers + * @brief List of all the defined registers + * @{ + */ +#define VL_REG_SYSRANGE_START 0x000 + /** mask existing bit in #VL_REG_SYSRANGE_START*/ + #define VL_REG_SYSRANGE_MODE_MASK 0x0F + /** bit 0 in #VL_REG_SYSRANGE_START write 1 toggle state in */ + /* continuous mode and arm next shot in single shot mode */ + #define VL_REG_SYSRANGE_MODE_START_STOP 0x01 + /** bit 1 write 0 in #VL_REG_SYSRANGE_START set single shot mode */ + #define VL_REG_SYSRANGE_MODE_SINGLESHOT 0x00 + /** bit 1 write 1 in #VL_REG_SYSRANGE_START set back-to-back */ + /* operation mode */ + #define VL_REG_SYSRANGE_MODE_BACKTOBACK 0x02 + /** bit 2 write 1 in #VL_REG_SYSRANGE_START set timed operation */ + /* * mode */ + #define VL_REG_SYSRANGE_MODE_TIMED 0x04 + /** bit 3 write 1 in #VL_REG_SYSRANGE_START set histogram operation */ + /* * mode */ + #define VL_REG_SYSRANGE_MODE_HISTOGRAM 0x08 + + +#define VL_REG_SYSTEM_THRESH_HIGH 0x000C +#define VL_REG_SYSTEM_THRESH_LOW 0x000E + + +#define VL_REG_SYSTEM_SEQUENCE_CONFIG 0x0001 +#define VL_REG_SYSTEM_RANGE_CONFIG 0x0009 +#define VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD 0x0004 + + +#define VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO 0x000A + #define VL_REG_SYSTEM_INTERRUPT_GPIO_DISABLED 0x00 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_LOW 0x01 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_LEVEL_HIGH 0x02 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_OUT_OF_WINDOW 0x03 + #define VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY 0x04 + +#define VL_REG_GPIO_HV_MUX_ACTIVE_HIGH 0x0084 + + +#define VL_REG_SYSTEM_INTERRUPT_CLEAR 0x000B + +/* Result registers */ +#define VL_REG_RESULT_INTERRUPT_STATUS 0x0013 +#define VL_REG_RESULT_RANGE_STATUS 0x0014 + +#define VL_REG_RESULT_CORE_PAGE 1 +#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN 0x00BC +#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_RTN 0x00C0 +#define VL_REG_RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF 0x00D0 +#define VL_REG_RESULT_CORE_RANGING_TOTAL_EVENTS_REF 0x00D4 +#define VL_REG_RESULT_PEAK_SIGNAL_RATE_REF 0x00B6 + +/* Algo register */ + +#define VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM 0x0028 + +#define VL_REG_I2C_SLAVE_DEVICE_ADDRESS 0x008a + +/* Check Limit registers */ +#define VL_REG_MSRC_CONFIG_CONTROL 0x0060 + +#define VL_REG_PRE_RANGE_CONFIG_MIN_SNR 0X0027 +#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW 0x0056 +#define VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH 0x0057 +#define VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT 0x0064 + +#define VL_REG_FINAL_RANGE_CONFIG_MIN_SNR 0X0067 +#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW 0x0047 +#define VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH 0x0048 +#define VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT 0x0044 + + +#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_HI 0X0061 +#define VL_REG_PRE_RANGE_CONFIG_SIGMA_THRESH_LO 0X0062 + +/* PRE RANGE registers */ +#define VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD 0x0050 +#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0051 +#define VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0052 + +#define VL_REG_SYSTEM_HISTOGRAM_BIN 0x0081 +#define VL_REG_HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT 0x0033 +#define VL_REG_HISTOGRAM_CONFIG_READOUT_CTRL 0x0055 + +#define VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD 0x0070 +#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI 0x0071 +#define VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO 0x0072 +#define VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS 0x0020 + +#define VL_REG_MSRC_CONFIG_TIMEOUT_MACROP 0x0046 + + +#define VL_REG_SOFT_RESET_GO2_SOFT_RESET_N 0x00bf +#define VL_REG_IDENTIFICATION_MODEL_ID 0x00c0 +#define VL_REG_IDENTIFICATION_REVISION_ID 0x00c2 + +#define VL_REG_OSC_CALIBRATE_VAL 0x00f8 + + +#define VL_SIGMA_ESTIMATE_MAX_VALUE 65535 +/* equivalent to a range sigma of 655.35mm */ + +#define VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH 0x032 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 0x0B0 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_1 0x0B1 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_2 0x0B2 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_3 0x0B3 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_4 0x0B4 +#define VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_5 0x0B5 + +#define VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT 0xB6 +#define VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD 0x4E /* 0x14E */ +#define VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET 0x4F /* 0x14F */ +#define VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE 0x80 + +/* + * Speed of light in um per 1E-10 Seconds + */ + +#define VL_SPEED_OF_LIGHT_IN_AIR 2997 + +#define VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV 0x0089 + +#define VL_REG_ALGO_PHASECAL_LIM 0x0030 /* 0x130 */ +#define VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT 0x0030 + +/** @} VL_DefineRegisters_group */ + +/** @} VL_DevSpecDefines_group */ + + +#endif + +/* _VL_DEVICE_H_ */ + + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h new file mode 100644 index 000000000000..3cd5d691c52e --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_i2c_platform.h @@ -0,0 +1,397 @@ +/* + * vl53l0x_i2c_platform.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/** + * @file VL_i2c_platform.h + * @brief Function prototype definitions for EWOK Platform layer. + * + */ + + +#ifndef _VL_I2C_PLATFORM_H_ +#define _VL_I2C_PLATFORM_H_ + +#include "vl53l0x_def.h" + + +/** Maximum buffer size to be used in i2c */ +#define VL_MAX_I2C_XFER_SIZE 64 + +/** + * @brief Typedef defining .\n + * The developer should modify this to suit the platform being deployed. + * + */ + +/** + * @brief Typedef defining 8 bit unsigned char type.\n + * The developer should modify this to suit the platform being deployed. + * + */ +#define I2C 0x01 +#define SPI 0x00 + +#define COMMS_BUFFER_SIZE 64 +/*MUST be the same size as the SV task buffer */ + +#define BYTES_PER_WORD 2 +#define BYTES_PER_DWORD 4 + +#define VL_MAX_STRING_LENGTH_PLT 256 + +/** + * @brief Initialise platform comms. + * + * @param comms_type - selects between I2C and SPI + * @param comms_speed_khz - unsigned short containing the I2C speed in kHz + * + * @return status - status 0 = ok, 1 = error + * + */ + +int32_t VL_comms_initialise(uint8_t comms_type, + uint16_t comms_speed_khz); + +/** + * @brief Close platform comms. + * + * @return status - status 0 = ok, 1 = error + * + */ + +int32_t VL_comms_close(void); + +/** + * @brief Cycle Power to Device + * + * @return status - status 0 = ok, 1 = error + * + */ + +int32_t VL_cycle_power(void); + +int32_t VL_set_page(struct vl_data *dev, uint8_t page_data); + +/** + * @brief Writes the supplied byte buffer to the device + * + * Wrapper for SystemVerilog Write Multi task + * + * @code + * + * Example: + * + * uint8_t *spad_enables; + * + * int status = VL_write_multi(RET_SPAD_EN_0, spad_enables, 36); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint8_t buffer containing the data to be written + * @param count - number of bytes in the supplied byte buffer + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count); + + +/** + * @brief Reads the requested number of bytes from the device + * + * Wrapper for SystemVerilog Read Multi task + * + * @code + * + * Example: + * + * uint8_t buffer[COMMS_BUFFER_SIZE]; + * + * int status = status = VL_read_multi(DEVICE_ID, buffer, 2) + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to the uint8_t buffer to store read data + * @param count - number of uint8_t's to read + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count); + + +/** + * @brief Writes a single byte to the device + * + * Wrapper for SystemVerilog Write Byte task + * + * @code + * + * Example: + * + * uint8_t page_number = MAIN_SELECT_PAGE; + * + * int status = VL_write_byte(PAGE_SELECT, page_number); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param data - uint8_t data value to write + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_byte(struct vl_data *dev, uint8_t index, uint8_t data); + + +/** + * @brief Writes a single word (16-bit unsigned) to the device + * + * Manages the big-endian nature of the device (first byte written is the + * MS byte). + * Uses SystemVerilog Write Multi task. + * + * @code + * + * Example: + * + * uint16_t nvm_ctrl_pulse_width = 0x0004; + * + * int status = VL_write_word(NVM_CTRL__PULSE_WIDTH_MSB, + * nvm_ctrl_pulse_width); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param data - uin16_t data value write + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_word(struct vl_data *dev, uint8_t index, uint16_t data); + + +/** + * @brief Writes a single dword (32-bit unsigned) to the device + * + * Manages the big-endian nature of the device (first byte written is the + * MS byte). + * Uses SystemVerilog Write Multi task. + * + * @code + * + * Example: + * + * uint32_t nvm_data = 0x0004; + * + * int status = VL_write_dword(NVM_CTRL__DATAIN_MMM, nvm_data); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param data - uint32_t data value to write + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t data); + + + +/** + * @brief Reads a single byte from the device + * + * Uses SystemVerilog Read Byte task. + * + * @code + * + * Example: + * + * uint8_t device_status = 0; + * + * int status = VL_read_byte(STATUS, &device_status); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint8_t data value + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_byte(struct vl_data *dev, uint8_t index, uint8_t *pdata); + + +/** + * @brief Reads a single word (16-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * Uses SystemVerilog Read Multi task. + * + * @code + * + * Example: + * + * uint16_t timeout = 0; + * + * int status = VL_read_word(TIMEOUT_OVERALL_PERIODS_MSB, &timeout); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint16_t data value + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_word(struct vl_data *dev, uint8_t index, uint16_t *pdata); + + +/** + * @brief Reads a single dword (32-bit unsigned) from the device + * + * Manages the big-endian nature of the device (first byte read is the MS byte). + * Uses SystemVerilog Read Multi task. + * + * @code + * + * Example: + * + * uint32_t range_1 = 0; + * + * int status = VL_read_dword(RANGE_1_MMM, &range_1); + * + * @endcode + * + * @param address - uint8_t device address value + * @param index - uint8_t register index value + * @param pdata - pointer to uint32_t data value + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata); + + +/** + * @brief Implements a programmable wait in us + * + * Wrapper for SystemVerilog Wait in micro seconds task + * + * @param wait_us - integer wait in micro seconds + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_platform_wait_us(int32_t wait_us); + + +/** + * @brief Implements a programmable wait in ms + * + * Wrapper for SystemVerilog Wait in milli seconds task + * + * @param wait_ms - integer wait in milli seconds + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_wait_ms(int32_t wait_ms); + + +/** + * @brief Set GPIO value + * + * @param level - input level - either 0 or 1 + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_set_gpio(uint8_t level); + + +/** + * @brief Get GPIO value + * + * @param plevel - uint8_t pointer to store GPIO level (0 or 1) + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_get_gpio(uint8_t *plevel); + +/** + * @brief Release force on GPIO + * + * @return status - SystemVerilog status 0 = ok, 1 = error + * + */ + +int32_t VL_release_gpio(void); + + +/** + * @brief Get the frequency of the timer used for ranging results time stamps + * + * @param[out] ptimer_freq_hz : pointer for timer frequency + * + * @return status : 0 = ok, 1 = error + * + */ + +int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz); + +/** + * @brief Get the timer value in units of timer_freq_hz + * (see VL_get_timestamp_frequency()) + * + * @param[out] ptimer_count : pointer for timer count value + * + * @return status : 0 = ok, 1 = error + * + */ + +int32_t VL_get_timer_value(int32_t *ptimer_count); +int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len); +int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len); + +#endif /* _VL_I2C_PLATFORM_H_ */ + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h new file mode 100644 index 000000000000..ecfc99453d8e --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_interrupt_threshold_settings.h @@ -0,0 +1,183 @@ +/* + * vl53l0x_interrupt_threshold_settings.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ +#define _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ + + +#ifdef __cplusplus +extern "C" { +#endif + + +uint8_t InterruptThresholdSettings[] = { + + /* Start of Interrupt Threshold Settings */ + 0x1, 0xff, 0x00, + 0x1, 0x80, 0x01, + 0x1, 0xff, 0x01, + 0x1, 0x00, 0x00, + 0x1, 0xff, 0x01, + 0x1, 0x4f, 0x02, + 0x1, 0xFF, 0x0E, + 0x1, 0x00, 0x03, + 0x1, 0x01, 0x84, + 0x1, 0x02, 0x0A, + 0x1, 0x03, 0x03, + 0x1, 0x04, 0x08, + 0x1, 0x05, 0xC8, + 0x1, 0x06, 0x03, + 0x1, 0x07, 0x8D, + 0x1, 0x08, 0x08, + 0x1, 0x09, 0xC6, + 0x1, 0x0A, 0x01, + 0x1, 0x0B, 0x02, + 0x1, 0x0C, 0x00, + 0x1, 0x0D, 0xD5, + 0x1, 0x0E, 0x18, + 0x1, 0x0F, 0x12, + 0x1, 0x10, 0x01, + 0x1, 0x11, 0x82, + 0x1, 0x12, 0x00, + 0x1, 0x13, 0xD5, + 0x1, 0x14, 0x18, + 0x1, 0x15, 0x13, + 0x1, 0x16, 0x03, + 0x1, 0x17, 0x86, + 0x1, 0x18, 0x0A, + 0x1, 0x19, 0x09, + 0x1, 0x1A, 0x08, + 0x1, 0x1B, 0xC2, + 0x1, 0x1C, 0x03, + 0x1, 0x1D, 0x8F, + 0x1, 0x1E, 0x0A, + 0x1, 0x1F, 0x06, + 0x1, 0x20, 0x01, + 0x1, 0x21, 0x02, + 0x1, 0x22, 0x00, + 0x1, 0x23, 0xD5, + 0x1, 0x24, 0x18, + 0x1, 0x25, 0x22, + 0x1, 0x26, 0x01, + 0x1, 0x27, 0x82, + 0x1, 0x28, 0x00, + 0x1, 0x29, 0xD5, + 0x1, 0x2A, 0x18, + 0x1, 0x2B, 0x0B, + 0x1, 0x2C, 0x28, + 0x1, 0x2D, 0x78, + 0x1, 0x2E, 0x28, + 0x1, 0x2F, 0x91, + 0x1, 0x30, 0x00, + 0x1, 0x31, 0x0B, + 0x1, 0x32, 0x00, + 0x1, 0x33, 0x0B, + 0x1, 0x34, 0x00, + 0x1, 0x35, 0xA1, + 0x1, 0x36, 0x00, + 0x1, 0x37, 0xA0, + 0x1, 0x38, 0x00, + 0x1, 0x39, 0x04, + 0x1, 0x3A, 0x28, + 0x1, 0x3B, 0x30, + 0x1, 0x3C, 0x0C, + 0x1, 0x3D, 0x04, + 0x1, 0x3E, 0x0F, + 0x1, 0x3F, 0x79, + 0x1, 0x40, 0x28, + 0x1, 0x41, 0x1E, + 0x1, 0x42, 0x2F, + 0x1, 0x43, 0x87, + 0x1, 0x44, 0x00, + 0x1, 0x45, 0x0B, + 0x1, 0x46, 0x00, + 0x1, 0x47, 0x0B, + 0x1, 0x48, 0x00, + 0x1, 0x49, 0xA7, + 0x1, 0x4A, 0x00, + 0x1, 0x4B, 0xA6, + 0x1, 0x4C, 0x00, + 0x1, 0x4D, 0x04, + 0x1, 0x4E, 0x01, + 0x1, 0x4F, 0x00, + 0x1, 0x50, 0x00, + 0x1, 0x51, 0x80, + 0x1, 0x52, 0x09, + 0x1, 0x53, 0x08, + 0x1, 0x54, 0x01, + 0x1, 0x55, 0x00, + 0x1, 0x56, 0x0F, + 0x1, 0x57, 0x79, + 0x1, 0x58, 0x09, + 0x1, 0x59, 0x05, + 0x1, 0x5A, 0x00, + 0x1, 0x5B, 0x60, + 0x1, 0x5C, 0x05, + 0x1, 0x5D, 0xD1, + 0x1, 0x5E, 0x0C, + 0x1, 0x5F, 0x3C, + 0x1, 0x60, 0x00, + 0x1, 0x61, 0xD0, + 0x1, 0x62, 0x0B, + 0x1, 0x63, 0x03, + 0x1, 0x64, 0x28, + 0x1, 0x65, 0x10, + 0x1, 0x66, 0x2A, + 0x1, 0x67, 0x39, + 0x1, 0x68, 0x0B, + 0x1, 0x69, 0x02, + 0x1, 0x6A, 0x28, + 0x1, 0x6B, 0x10, + 0x1, 0x6C, 0x2A, + 0x1, 0x6D, 0x61, + 0x1, 0x6E, 0x0C, + 0x1, 0x6F, 0x00, + 0x1, 0x70, 0x0F, + 0x1, 0x71, 0x79, + 0x1, 0x72, 0x00, + 0x1, 0x73, 0x0B, + 0x1, 0x74, 0x00, + 0x1, 0x75, 0x0B, + 0x1, 0x76, 0x00, + 0x1, 0x77, 0xA1, + 0x1, 0x78, 0x00, + 0x1, 0x79, 0xA0, + 0x1, 0x7A, 0x00, + 0x1, 0x7B, 0x04, + 0x1, 0xFF, 0x04, + 0x1, 0x79, 0x1D, + 0x1, 0x7B, 0x27, + 0x1, 0x96, 0x0E, + 0x1, 0x97, 0xFE, + 0x1, 0x98, 0x03, + 0x1, 0x99, 0xEF, + 0x1, 0x9A, 0x02, + 0x1, 0x9B, 0x44, + 0x1, 0x73, 0x07, + 0x1, 0x70, 0x01, + 0x1, 0xff, 0x01, + 0x1, 0x00, 0x01, + 0x1, 0xff, 0x00, + 0x00, 0x00, 0x00 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_INTERRUPT_THRESHOLD_SETTINGS_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h new file mode 100644 index 000000000000..d896fe800f8b --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform.h @@ -0,0 +1,213 @@ +/* + * vl53l0x_platform.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_PLATFORM_H_ +#define _VL_PLATFORM_H_ + +#include +#include "vl53l0x_def.h" +#include "vl53l0x_platform_log.h" + +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" +#include "stmvl53l0x.h" + +/** + * @file vl53l0x_platform.h + * + * @brief All end user OS/platform/application porting + */ + +/** + * @defgroup VL_platform_group VL53L0 Platform Functions + * @brief VL53L0 Platform Functions + * @{ + */ + +/** + * @def PALDevDataGet + * @brief Get ST private structure @a struct VL_DevData_t data access + * + * @param Dev Device Handle + * @param field ST structure field name + * It maybe used and as real data "ref" not just as "get" for sub-structure item + * like PALDevDataGet(FilterData.field)[i] or + * PALDevDataGet(FilterData.MeasurementIndex)++ + */ +#define PALDevDataGet(Dev, field) (Dev->Data.field) + +/** + * @def PALDevDataSet(Dev, field, data) + * @brief Set ST private structure @a struct VL_DevData_t data field + * @param Dev Device Handle + * @param field ST structure field na*me + * @param data Data to be set + */ +#define PALDevDataSet(Dev, field, data) ((Dev->Data.field) = (data)) + + +/** + * @defgroup VL_registerAccess_group PAL Register Access Functions + * @brief PAL Register Access Functions + * @{ + */ + +/** + * Lock comms interface to serialize all commands to a shared I2C interface + * for a specific device + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_LockSequenceAccess(struct vl_data *Dev); + +/** + * Unlock comms interface to serialize all commands to a shared I2C interface + * for a specific device + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_UnlockSequenceAccess(struct vl_data *Dev); + + +/** + * Writes the supplied byte buffer to the device + * @param Dev Device Handle + * @param index The register index + * @param pdata Pointer to uint8_t buffer containing the data + * to be written + * @param count Number of bytes in the supplied byte buffer + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count); + +/** + * Reads the requested number of bytes from the device + * @param Dev Device Handle + * @param index The register index + * @param pdata Pointer to the uint8_t buffer to store read data + * @param count Number of uint8_t's to read + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count); + +/** + * Write single byte register + * @param Dev Device Handle + * @param index The register index + * @param data 8 bit register data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data); + +/** + * Write word register + * @param Dev Device Handle + * @param index The register index + * @param data 16 bit register data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data); + +/** + * Write double word (4 byte) register + * @param Dev Device Handle + * @param index The register index + * @param data 32 bit register data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data); + +/** + * Read single byte register + * @param Dev Device Handle + * @param index The register index + * @param data pointer to 8 bit data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data); + +/** + * Read word (2byte) register + * @param Dev Device Handle + * @param index The register index + * @param data pointer to 16 bit data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data); + +/** + * Read dword (4byte) register + * @param Dev Device Handle + * @param index The register index + * @param data pointer to 32 bit data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data); + +/** + * Threat safe Update (read/modify/write) single byte register + * + * Final_reg = (Initial_reg & and_data) |or_data + * + * @param Dev Device Handle + * @param index The register index + * @param AndData 8 bit and data + * @param OrData 8 bit or data + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index, + uint8_t AndData, uint8_t OrData); + +/** @} end of VL_registerAccess_group */ + + +/** + * @brief execute delay in all polling API call + * + * A typical multi-thread or RTOs implementation is to sleep the task for + * some 5ms (with 100Hz max rate faster polling is not needed) + * if nothing specific is need you can define it as an empty/void macro + * @code + * #define VL_PollingDelay(...) (void)0 + * @endcode + * @param Dev Device Handle + * @return VL_ERROR_NONE Success + * @return "Other error code" See ::int8_t + */ +int8_t VL_PollingDelay(struct vl_data *Dev); +/* usually best implemented as a real function */ + +/** @} end of VL_platform_group */ + +#endif /* _VL_PLATFORM_H_ */ + + + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h new file mode 100644 index 000000000000..a8f22c5b2cef --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_platform_log.h @@ -0,0 +1,99 @@ +/* + * vl53l0x_platform_log.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_PLATFORM_LOG_H_ +#define _VL_PLATFORM_LOG_H_ + +#include +/* LOG Functions */ + + +/** + * @file vl53l0x_platform_log.h + * + * @brief platform log function definition + */ + +/* #define VL_LOG_ENABLE */ + +enum { + TRACE_LEVEL_NONE, + TRACE_LEVEL_ERRORS, + TRACE_LEVEL_WARNING, + TRACE_LEVEL_INFO, + TRACE_LEVEL_DEBUG, + TRACE_LEVEL_ALL, + TRACE_LEVEL_IGNORE +}; + +enum { + TRACE_FUNCTION_NONE = 0, + TRACE_FUNCTION_I2C = 1, + TRACE_FUNCTION_ALL = 0x7fffffff /* all bits except sign */ +}; + +enum { + TRACE_MODULE_NONE = 0x0, + TRACE_MODULE_API = 0x1, + TRACE_MODULE_PLATFORM = 0x2, + TRACE_MODULE_ALL = 0x7fffffff /* all bits except sign */ +}; + + +#ifdef VL_LOG_ENABLE + +#include + + +extern uint32_t _trace_level; + + + +int32_t VL_trace_config(char *filename, uint32_t modules, + uint32_t level, uint32_t functions); + +#define trace_print_module_function(...) + +#define LOG_GET_TIME() 0 +#define _LOG_FUNCTION_START(module, fmt, ...) \ + dbg("beg %s start @%d\t" fmt "\n", \ + __func__, LOG_GET_TIME(), ##__VA_ARGS__) + +#define _LOG_FUNCTION_END(module, status, ...)\ + dbg("end %s start @%d Status %d\n", \ + __func__, LOG_GET_TIME(), (int)status) + +#define _LOG_FUNCTION_END_FMT(module, status, fmt, ...)\ + dbg("End %s @%d %d\t"fmt"\n", \ + __func__, LOG_GET_TIME(), (int)status, ##__VA_ARGS__) + + +#else /* VL_LOG_ENABLE no logging */ + #define VL_ErrLog(...) (void)0 + #define _LOG_FUNCTION_START(module, fmt, ...) (void)0 + #define _LOG_FUNCTION_END(module, status, ...) (void)0 + #define _LOG_FUNCTION_END_FMT(module, status, fmt, ...) (void)0 +#endif /* else */ + +#define VL_COPYSTRING(str, ...) strlcpy(str, ##__VA_ARGS__, sizeof(str)) + + +#endif /* _VL_PLATFORM_LOG_H_ */ + + + diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h new file mode 100644 index 000000000000..ba2998ac7b01 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_tuning.h @@ -0,0 +1,135 @@ +/* + * vl53l0x_tuning.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VL_TUNING_H_ +#define _VL_TUNING_H_ + +#include "vl53l0x_def.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +uint8_t DefaultTuningSettings[] = { + + /* update 02/11/2015_v36 */ + 0x01, 0xFF, 0x01, + 0x01, 0x00, 0x00, + + 0x01, 0xFF, 0x00, + 0x01, 0x09, 0x00, + 0x01, 0x10, 0x00, + 0x01, 0x11, 0x00, + + 0x01, 0x24, 0x01, + 0x01, 0x25, 0xff, + 0x01, 0x75, 0x00, + + 0x01, 0xFF, 0x01, + 0x01, 0x4e, 0x2c, + 0x01, 0x48, 0x00, + 0x01, 0x30, 0x20, + + 0x01, 0xFF, 0x00, + 0x01, 0x30, 0x09, /* mja changed from 0x64. */ + 0x01, 0x54, 0x00, + 0x01, 0x31, 0x04, + 0x01, 0x32, 0x03, + 0x01, 0x40, 0x83, + 0x01, 0x46, 0x25, + 0x01, 0x60, 0x00, + 0x01, 0x27, 0x00, + 0x01, 0x50, 0x06, + 0x01, 0x51, 0x00, + 0x01, 0x52, 0x96, + 0x01, 0x56, 0x08, + 0x01, 0x57, 0x30, + 0x01, 0x61, 0x00, + 0x01, 0x62, 0x00, + 0x01, 0x64, 0x00, + 0x01, 0x65, 0x00, + 0x01, 0x66, 0xa0, + + 0x01, 0xFF, 0x01, + 0x01, 0x22, 0x32, + 0x01, 0x47, 0x14, + 0x01, 0x49, 0xff, + 0x01, 0x4a, 0x00, + + 0x01, 0xFF, 0x00, + 0x01, 0x7a, 0x0a, + 0x01, 0x7b, 0x00, + 0x01, 0x78, 0x21, + + 0x01, 0xFF, 0x01, + 0x01, 0x23, 0x34, + 0x01, 0x42, 0x00, + 0x01, 0x44, 0xff, + 0x01, 0x45, 0x26, + 0x01, 0x46, 0x05, + 0x01, 0x40, 0x40, + 0x01, 0x0E, 0x06, + 0x01, 0x20, 0x1a, + 0x01, 0x43, 0x40, + + 0x01, 0xFF, 0x00, + 0x01, 0x34, 0x03, + 0x01, 0x35, 0x44, + + 0x01, 0xFF, 0x01, + 0x01, 0x31, 0x04, + 0x01, 0x4b, 0x09, + 0x01, 0x4c, 0x05, + 0x01, 0x4d, 0x04, + + + 0x01, 0xFF, 0x00, + 0x01, 0x44, 0x00, + 0x01, 0x45, 0x20, + 0x01, 0x47, 0x08, + 0x01, 0x48, 0x28, + 0x01, 0x67, 0x00, + 0x01, 0x70, 0x04, + 0x01, 0x71, 0x01, + 0x01, 0x72, 0xfe, + 0x01, 0x76, 0x00, + 0x01, 0x77, 0x00, + + 0x01, 0xFF, 0x01, + 0x01, 0x0d, 0x01, + + 0x01, 0xFF, 0x00, + 0x01, 0x80, 0x01, + 0x01, 0x01, 0xF8, + + 0x01, 0xFF, 0x01, + 0x01, 0x8e, 0x01, + 0x01, 0x00, 0x01, + 0x01, 0xFF, 0x00, + 0x01, 0x80, 0x00, + + 0x00, 0x00, 0x00 +}; + +#ifdef __cplusplus +} +#endif + +#endif /* _VL_TUNING_H_ */ diff --git a/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h new file mode 100644 index 000000000000..be40e83d7013 --- /dev/null +++ b/drivers/input/misc/vl53l0x/inc/vl53l0x_types.h @@ -0,0 +1,54 @@ +/* + * vl53l0x_types.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef VL_TYPES_H_ +#define VL_TYPES_H_ + +#include + +#ifndef NULL +#error "TODO review NULL definition or add required include " +#define NULL 0 +#endif + +#if !defined(STDINT_H) && !defined(_GCC_STDINT_H) \ + && !defined(_STDINT_H) && !defined(_LINUX_TYPES_H) + +#pragma message( +"Review type definition of STDINT define for your platform and add to above") + +/* + * target platform do not provide stdint or use a different #define than above + * to avoid seeing the message below addapt the #define list above or implement + * all type and delete these pragma + */ + +unsigned int uint32_t; +int int32_t; + +unsigned short uint16_t; +short int16_t; + +unsigned char uint8_t; + +signed char int8_t; + + +#endif /* _STDINT_H */ + +#endif /* VL_TYPES_H_ */ diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c new file mode 100644 index 000000000000..888947f2d834 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api.c @@ -0,0 +1,3096 @@ +/* + * vl53l0x_api.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "vl53l0x_api.h" +#include "vl53l0x_tuning.h" +#include "vl53l0x_interrupt_threshold_settings.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_calibration.h" +#include "vl53l0x_api_strings.h" + +#ifndef __KERNEL__ +#include +#endif +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + +#ifdef VL_LOG_ENABLE +#define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_API, \ + level, TRACE_FUNCTION_NONE, ##__VA_ARGS__) +#endif + +/* Group PAL General Functions */ + +int8_t VL_GetVersion(struct VL_Version_t *pVersion) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pVersion->major = VL_IMPLEMENTATION_VER_MAJOR; + pVersion->minor = VL_IMPLEMENTATION_VER_MINOR; + pVersion->build = VL_IMPLEMENTATION_VER_SUB; + + pVersion->revision = VL_IMPLEMENTATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalSpecVersion(struct VL_Version_t *pPalSpecVersion) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + pPalSpecVersion->major = VL_SPECIFICATION_VER_MAJOR; + pPalSpecVersion->minor = VL_SPECIFICATION_VER_MINOR; + pPalSpecVersion->build = VL_SPECIFICATION_VER_SUB; + + pPalSpecVersion->revision = VL_SPECIFICATION_VER_REVISION; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetProductRevision(struct vl_data *Dev, + uint8_t *pProductRevisionMajor, uint8_t *pProductRevisionMinor) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t revision_id; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_IDENTIFICATION_REVISION_ID, + &revision_id); + *pProductRevisionMajor = 1; + *pProductRevisionMinor = (revision_id & 0xF0) >> 4; + + LOG_FUNCTION_END(Status); + return Status; + +} + +int8_t VL_GetDeviceInfo(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_device_info(Dev, pVL_DeviceInfo); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDeviceErrorStatus(struct vl_data *Dev, + uint8_t *pDeviceErrorStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t RangeStatus; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS, + &RangeStatus); + + *pDeviceErrorStatus = (uint8_t)((RangeStatus & 0x78) >> 3); + + LOG_FUNCTION_END(Status); + return Status; +} + + +int8_t VL_GetDeviceErrorString(uint8_t ErrorCode, + char *pDeviceErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_device_error_string(ErrorCode, pDeviceErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetRangeStatusString(uint8_t RangeStatus, + char *pRangeStatusString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_range_status_string(RangeStatus, + pRangeStatusString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalErrorString(int8_t PalErrorCode, + char *pPalErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_pal_error_string(PalErrorCode, pPalErrorString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalStateString(uint8_t PalStateCode, + char *pPalStateString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_pal_state_string(PalStateCode, pPalStateString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPalState(struct vl_data *Dev, uint8_t *pPalState) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pPalState = PALDevDataGet(Dev, PalState); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetPowerMode(struct vl_data *Dev, + uint8_t PowerMode) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + /* Only level1 of Power mode exists */ + if ((PowerMode != VL_POWERMODE_STANDBY_LEVEL1) + && (PowerMode != VL_POWERMODE_IDLE_LEVEL1)) { + Status = VL_ERROR_MODE_NOT_SUPPORTED; + } else if (PowerMode == VL_POWERMODE_STANDBY_LEVEL1) { + /* set the standby level1 of power mode */ + Status = VL_WrByte(Dev, 0x80, 0x00); + if (Status == VL_ERROR_NONE) { + /* Set PAL State to standby */ + PALDevDataSet(Dev, PalState, VL_STATE_STANDBY); + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_STANDBY_LEVEL1); + } + + } else { + /* VL_POWERMODE_IDLE_LEVEL1 */ + Status = VL_WrByte(Dev, 0x80, 0x00); + if (Status == VL_ERROR_NONE) + Status = VL_StaticInit(Dev); + + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_IDLE_LEVEL1); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetPowerMode(struct vl_data *Dev, + uint8_t *pPowerMode) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + /* Only level1 of Power mode exists */ + Status = VL_RdByte(Dev, 0x80, &Byte); + + if (Status == VL_ERROR_NONE) { + if (Byte == 1) { + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_IDLE_LEVEL1); + } else { + PALDevDataSet(Dev, PowerMode, + VL_POWERMODE_STANDBY_LEVEL1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetOffsetCalibrationDataMicroMeter(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_offset_calibration_data_micro_meter(Dev, + OffsetCalibrationDataMicroMeter); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetOffsetCalibrationDataMicroMeter(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_offset_calibration_data_micro_meter(Dev, + pOffsetCalibrationDataMicroMeter); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetLinearityCorrectiveGain(struct vl_data *Dev, + int16_t LinearityCorrectiveGain) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if ((LinearityCorrectiveGain < 0) || (LinearityCorrectiveGain > 1000)) + Status = VL_ERROR_INVALID_PARAMS; + else { + PALDevDataSet(Dev, LinearityCorrectiveGain, + LinearityCorrectiveGain); + + if (LinearityCorrectiveGain != 1000) { + /* Disable FW Xtalk */ + Status = VL_WrWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, 0); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLinearityCorrectiveGain(struct vl_data *Dev, + uint16_t *pLinearityCorrectiveGain) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pLinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetGroupParamHold(struct vl_data *Dev, uint8_t GroupParamHold) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetUpperLimitMilliMeter(struct vl_data *Dev, + uint16_t *pUpperLimitMilliMeter) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetTotalSignalRate(struct vl_data *Dev, + unsigned int *pTotalSignalRate) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_RangingMeasurementData_t LastRangeDataBuffer; + + LOG_FUNCTION_START(""); + + LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure); + + Status = VL_get_total_signal_rate( + Dev, &LastRangeDataBuffer, pTotalSignalRate); + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL General Functions */ + +/* Group PAL Init Functions */ +int8_t VL_SetDeviceAddress(struct vl_data *Dev, uint8_t DeviceAddress) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, VL_REG_I2C_SLAVE_DEVICE_ADDRESS, + DeviceAddress / 2); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_DataInit(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_DeviceParameters_t CurrentParameters; + int i; + uint8_t StopVariable; + + LOG_FUNCTION_START(""); + + /* by default the I2C is running at 1V8 if you want to change it you */ + /* need to include this define at compilation level. */ +#ifdef USE_I2C_2V8 + Status = VL_UpdateByte(Dev, + VL_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV, + 0xFE, + 0x01); +#endif + + /* Set I2C standard mode */ + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0x88, 0x00); + + VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone, 0); + +#ifdef USE_IQC_STATION + if (Status == VL_ERROR_NONE) + Status = VL_apply_offset_adjustment(Dev); +#endif + + /* Default value is 1000 for Linearity Corrective Gain */ + PALDevDataSet(Dev, LinearityCorrectiveGain, 1000); + + /* Dmax default Parameter */ + PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400); + PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps, + (unsigned int)((0x00016B85))); /* 1.42 No Cover Glass*/ + + /* Set Default static parameters */ + /* *set first temporary values 9.44MHz * 65536 = 618660 */ + VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, 618660); + + /* Set Default XTalkCompensationRateMegaCps to 0 */ + VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, 0); + + /* Get default parameters */ + Status = VL_GetDeviceParameters(Dev, &CurrentParameters); + if (Status == VL_ERROR_NONE) { + /* initialize PAL values */ + CurrentParameters.DeviceMode = VL_DEVICEMODE_SINGLE_RANGING; + CurrentParameters.HistogramMode = VL_HISTOGRAMMODE_DISABLED; + PALDevDataSet(Dev, CurrentParameters, CurrentParameters); + } + + /* Sigma estimator variable */ + PALDevDataSet(Dev, SigmaEstRefArray, 100); + PALDevDataSet(Dev, SigmaEstEffPulseWidth, 900); + PALDevDataSet(Dev, SigmaEstEffAmbWidth, 500); + PALDevDataSet(Dev, targetRefRate, 0x0A00); /* 20 MCPS in 9:7 format */ + + /* Use internal default settings */ + PALDevDataSet(Dev, UseInternalTuningSettings, 1); + + Status |= VL_WrByte(Dev, 0x80, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + Status |= VL_RdByte(Dev, 0x91, &StopVariable); + PALDevDataSet(Dev, StopVariable, StopVariable); + Status |= VL_WrByte(Dev, 0x00, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x00); + + /* Enable all check */ + for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL_ERROR_NONE) + Status |= VL_SetLimitCheckEnable(Dev, i, 1); + else + break; + + } + + /* Disable the following checks */ + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_RATE_MSRC, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE, 0); + + /* Limit default values */ + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + (unsigned int)(18 * 65536)); + } + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (unsigned int)(25 * 65536 / 100)); + /* 0.25 * 65536 */ + } + + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + (unsigned int)(35 * 65536)); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckValue(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + (unsigned int)(0 * 65536)); + } + + if (Status == VL_ERROR_NONE) { + + PALDevDataSet(Dev, SequenceConfig, 0xFF); + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + 0xFF); + + /* Set PAL state to tell that we are waiting for call to */ + /* * VL_StaticInit */ + PALDevDataSet(Dev, PalState, VL_STATE_WAIT_STATICINIT); + } + + if (Status == VL_ERROR_NONE) + VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 0); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetTuningSettingBuffer(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer, uint8_t UseInternalTuningSettings) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (UseInternalTuningSettings == 1) { + /* Force use internal settings */ + PALDevDataSet(Dev, UseInternalTuningSettings, 1); + } else { + + /* check that the first byte is not 0 */ + if (*pTuningSettingBuffer != 0) { + PALDevDataSet(Dev, pTuningSettingsPointer, + pTuningSettingBuffer); + PALDevDataSet(Dev, UseInternalTuningSettings, 0); + + } else { + Status = VL_ERROR_INVALID_PARAMS; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetTuningSettingBuffer(struct vl_data *Dev, + uint8_t **ppTuningSettingBuffer, uint8_t *pUseInternalTuningSettings) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *ppTuningSettingBuffer = PALDevDataGet(Dev, pTuningSettingsPointer); + *pUseInternalTuningSettings = PALDevDataGet(Dev, + UseInternalTuningSettings); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_StaticInit(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_DeviceParameters_t CurrentParameters = {0}; + uint8_t *pTuningSettingBuffer; + uint16_t tempword = 0; + uint8_t tempbyte = 0; + uint8_t UseInternalTuningSettings = 0; + uint32_t count = 0; + uint8_t isApertureSpads = 0; + uint32_t refSpadCount = 0; + uint8_t ApertureSpads = 0; + uint8_t vcselPulsePeriodPCLK; + uint32_t seqTimeoutMicroSecs; + + LOG_FUNCTION_START(""); + + Status = VL_get_info_from_device(Dev, 1); + + /* set the ref spad from NVM */ + count = (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount); + ApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType); + + /* NVM value invalid */ + if ((ApertureSpads > 1) || + ((ApertureSpads == 1) && (count > 32)) || + ((ApertureSpads == 0) && (count > 12))) + Status = VL_perform_ref_spad_management(Dev, &refSpadCount, + &isApertureSpads); + else + Status = VL_set_reference_spads(Dev, count, ApertureSpads); + + + /* Initialize tuning settings buffer to prevent compiler warning. */ + pTuningSettingBuffer = DefaultTuningSettings; + + if (Status == VL_ERROR_NONE) { + UseInternalTuningSettings = PALDevDataGet(Dev, + UseInternalTuningSettings); + + if (UseInternalTuningSettings == 0) + pTuningSettingBuffer = PALDevDataGet(Dev, + pTuningSettingsPointer); + else + pTuningSettingBuffer = DefaultTuningSettings; + + } + + if (Status == VL_ERROR_NONE) + Status = VL_load_tuning_settings(Dev, + pTuningSettingBuffer); + + + /* Set interrupt config to new sample ready */ + if (Status == VL_ERROR_NONE) { + Status = VL_SetGpioConfig(Dev, 0, 0, + VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY, + VL_INTERRUPTPOLARITY_LOW); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_RdWord(Dev, 0x84, &tempword); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER(Dev, OscFrequencyMHz, + VL_FIXPOINT412TOFIXPOINT1616(tempword)); + } + + /* After static init, some device parameters may be changed, */ + /* * so update them */ + if (Status == VL_ERROR_NONE) + Status = VL_GetDeviceParameters(Dev, &CurrentParameters); + + + if (Status == VL_ERROR_NONE) { + Status = VL_GetFractionEnable(Dev, &tempbyte); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, RangeFractionalEnable, tempbyte); + + } + + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, CurrentParameters, CurrentParameters); + + + /* read the sequence config and save it */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_SYSTEM_SEQUENCE_CONFIG, &tempbyte); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, tempbyte); + + } + + /* Disable MSRC and TCC by default */ + if (Status == VL_ERROR_NONE) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, 0); + + + if (Status == VL_ERROR_NONE) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_MSRC, 0); + + + /* Set PAL State to standby */ + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, PalState, VL_STATE_IDLE); + + + + /* Store pre-range vcsel period */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetVcselPulsePeriod( + Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &vcselPulsePeriodPCLK); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, PreRangeVcselPulsePeriod, + vcselPulsePeriodPCLK); + } + + /* Store final-range vcsel period */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetVcselPulsePeriod( + Dev, + VL_VCSEL_PERIOD_FINAL_RANGE, + &vcselPulsePeriodPCLK); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, FinalRangeVcselPulsePeriod, + vcselPulsePeriodPCLK); + } + + /* Store pre-range timeout */ + if (Status == VL_ERROR_NONE) { + Status = get_sequence_step_timeout( + Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &seqTimeoutMicroSecs); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + PreRangeTimeoutMicroSecs, + seqTimeoutMicroSecs); + } + + /* Store final-range timeout */ + if (Status == VL_ERROR_NONE) { + Status = get_sequence_step_timeout( + Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + &seqTimeoutMicroSecs); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + FinalRangeTimeoutMicroSecs, + seqTimeoutMicroSecs); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_WaitDeviceBooted(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_ResetDevice(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + /* Set reset bit */ + Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N, + 0x00); + + /* Wait for some time */ + if (Status == VL_ERROR_NONE) { + do { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_MODEL_ID, &Byte); + } while (Byte != 0x00); + } + + VL_PollingDelay(Dev); + + /* Release reset */ + Status = VL_WrByte(Dev, VL_REG_SOFT_RESET_GO2_SOFT_RESET_N, + 0x01); + + /* Wait until correct boot-up of the device */ + if (Status == VL_ERROR_NONE) { + do { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_MODEL_ID, &Byte); + } while (Byte == 0x00); + } + + VL_PollingDelay(Dev); + + /* Set PAL State to VL_STATE_POWERDOWN */ + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, PalState, VL_STATE_POWERDOWN); + + + LOG_FUNCTION_END(Status); + return Status; +} +/* End Group PAL Init Functions */ + +/* Group PAL Parameters Functions */ +int8_t VL_SetDeviceParameters(struct vl_data *Dev, + const struct VL_DeviceParameters_t *pDeviceParameters) +{ + int8_t Status = VL_ERROR_NONE; + int i; + + LOG_FUNCTION_START(""); + Status = VL_SetDeviceMode(Dev, pDeviceParameters->DeviceMode); + + if (Status == VL_ERROR_NONE) + Status = VL_SetInterMeasurementPeriodMilliSeconds(Dev, + pDeviceParameters->InterMeasurementPeriodMilliSeconds); + + + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationRateMegaCps(Dev, + pDeviceParameters->XTalkCompensationRateMegaCps); + + + if (Status == VL_ERROR_NONE) + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, + pDeviceParameters->RangeOffsetMicroMeters); + + + for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + if (Status == VL_ERROR_NONE) + Status |= VL_SetLimitCheckEnable(Dev, i, + pDeviceParameters->LimitChecksEnable[i]); + else + break; + + if (Status == VL_ERROR_NONE) + Status |= VL_SetLimitCheckValue(Dev, i, + pDeviceParameters->LimitChecksValue[i]); + else + break; + + } + + if (Status == VL_ERROR_NONE) + Status = VL_SetWrapAroundCheckEnable(Dev, + pDeviceParameters->WrapAroundCheckEnable); + + if (Status == VL_ERROR_NONE) + Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + pDeviceParameters->MeasurementTimingBudgetMicroSeconds); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDeviceParameters(struct vl_data *Dev, + struct VL_DeviceParameters_t *pDeviceParameters) +{ + int8_t Status = VL_ERROR_NONE; + int i; + + LOG_FUNCTION_START(""); + + Status = VL_GetDeviceMode(Dev, &(pDeviceParameters->DeviceMode)); + + if (Status == VL_ERROR_NONE) + Status = VL_GetInterMeasurementPeriodMilliSeconds(Dev, + &(pDeviceParameters->InterMeasurementPeriodMilliSeconds)); + + + if (Status == VL_ERROR_NONE) + pDeviceParameters->XTalkCompensationEnable = 0; + + if (Status == VL_ERROR_NONE) + Status = VL_GetXTalkCompensationRateMegaCps(Dev, + &(pDeviceParameters->XTalkCompensationRateMegaCps)); + + + if (Status == VL_ERROR_NONE) + Status = VL_GetOffsetCalibrationDataMicroMeter(Dev, + &(pDeviceParameters->RangeOffsetMicroMeters)); + + + if (Status == VL_ERROR_NONE) { + for (i = 0; i < VL_CHECKENABLE_NUMBER_OF_CHECKS; i++) { + /* get first the values, then the enables. + * VL_GetLimitCheckValue will modify the enable + * flags + */ + if (Status == VL_ERROR_NONE) { + Status |= VL_GetLimitCheckValue(Dev, i, + &(pDeviceParameters->LimitChecksValue[i])); + } else { + break; + } + if (Status == VL_ERROR_NONE) { + Status |= VL_GetLimitCheckEnable(Dev, i, + &(pDeviceParameters->LimitChecksEnable[i])); + } else { + break; + } + } + } + + if (Status == VL_ERROR_NONE) { + Status = VL_GetWrapAroundCheckEnable(Dev, + &(pDeviceParameters->WrapAroundCheckEnable)); + } + + /* Need to be done at the end as it uses VCSELPulsePeriod */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetMeasurementTimingBudgetMicroSeconds(Dev, + &(pDeviceParameters->MeasurementTimingBudgetMicroSeconds)); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetDeviceMode(struct vl_data *Dev, + uint8_t DeviceMode) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START("%d", (int)DeviceMode); + + switch (DeviceMode) { + case VL_DEVICEMODE_SINGLE_RANGING: + case VL_DEVICEMODE_CONTINUOUS_RANGING: + case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING: + case VL_DEVICEMODE_GPIO_DRIVE: + case VL_DEVICEMODE_GPIO_OSC: + /* Supported modes */ + VL_SETPARAMETERFIELD(Dev, DeviceMode, DeviceMode); + break; + default: + /* Unsupported mode */ + Status = VL_ERROR_MODE_NOT_SUPPORTED; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDeviceMode(struct vl_data *Dev, + uint8_t *pDeviceMode) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, DeviceMode, *pDeviceMode); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetRangeFractionEnable(struct vl_data *Dev, uint8_t Enable) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START("%d", (int)Enable); + + Status = VL_WrByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, Enable); + + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, RangeFractionalEnable, Enable); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetFractionEnable(struct vl_data *Dev, uint8_t *pEnabled) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_RANGE_CONFIG, pEnabled); + + if (Status == VL_ERROR_NONE) + *pEnabled = (*pEnabled & 1); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetHistogramMode(struct vl_data *Dev, + uint8_t HistogramMode) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetHistogramMode(struct vl_data *Dev, + uint8_t *pHistogramMode) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev, + uint32_t MeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_measurement_timing_budget_micro_seconds(Dev, + MeasurementTimingBudgetMicroSeconds); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetMeasurementTimingBudgetMicroSeconds(struct vl_data *Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_measurement_timing_budget_micro_seconds(Dev, + pMeasurementTimingBudgetMicroSeconds); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_vcsel_pulse_period(Dev, VcselPeriodType, + VCSELPulsePeriodPCLK); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetVcselPulsePeriod(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_vcsel_pulse_period(Dev, VcselPeriodType, + pVCSELPulsePeriodPCLK); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t SequenceStepEnabled) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + uint8_t SequenceConfigNew = 0; + uint32_t MeasurementTimingBudgetMicroSeconds; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + &SequenceConfig); + + SequenceConfigNew = SequenceConfig; + + if (Status == VL_ERROR_NONE) { + if (SequenceStepEnabled == 1) { + + /* Enable requested sequence step + */ + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + SequenceConfigNew |= 0x10; + break; + case VL_SEQUENCESTEP_DSS: + SequenceConfigNew |= 0x28; + break; + case VL_SEQUENCESTEP_MSRC: + SequenceConfigNew |= 0x04; + break; + case VL_SEQUENCESTEP_PRE_RANGE: + SequenceConfigNew |= 0x40; + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + SequenceConfigNew |= 0x80; + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } else { + /* Disable requested sequence step + */ + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + SequenceConfigNew &= 0xef; + break; + case VL_SEQUENCESTEP_DSS: + SequenceConfigNew &= 0xd7; + break; + case VL_SEQUENCESTEP_MSRC: + SequenceConfigNew &= 0xfb; + break; + case VL_SEQUENCESTEP_PRE_RANGE: + SequenceConfigNew &= 0xbf; + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + SequenceConfigNew &= 0x7f; + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } + } + + if (SequenceConfigNew != SequenceConfig) { + /* Apply New Setting */ + if (Status == VL_ERROR_NONE) { + Status = VL_WrByte(Dev, + VL_REG_SYSTEM_SEQUENCE_CONFIG, SequenceConfigNew); + } + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfigNew); + + + /* Recalculate timing budget */ + if (Status == VL_ERROR_NONE) { + VL_GETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + + VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + } + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t sequence_step_enabled(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t SequenceConfig, + uint8_t *pSequenceStepEnabled) +{ + int8_t Status = VL_ERROR_NONE; + *pSequenceStepEnabled = 0; + + LOG_FUNCTION_START(""); + + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + *pSequenceStepEnabled = (SequenceConfig & 0x10) >> 4; + break; + case VL_SEQUENCESTEP_DSS: + *pSequenceStepEnabled = (SequenceConfig & 0x08) >> 3; + break; + case VL_SEQUENCESTEP_MSRC: + *pSequenceStepEnabled = (SequenceConfig & 0x04) >> 2; + break; + case VL_SEQUENCESTEP_PRE_RANGE: + *pSequenceStepEnabled = (SequenceConfig & 0x40) >> 6; + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + *pSequenceStepEnabled = (SequenceConfig & 0x80) >> 7; + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSequenceStepEnable(struct vl_data *Dev, + uint8_t SequenceStepId, uint8_t *pSequenceStepEnabled) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + &SequenceConfig); + + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, SequenceStepId, + SequenceConfig, pSequenceStepEnabled); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSequenceStepEnables(struct vl_data *Dev, + struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + &SequenceConfig); + + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_TCC, SequenceConfig, + &pSchedulerSequenceSteps->TccOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_DSS, SequenceConfig, + &pSchedulerSequenceSteps->DssOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_MSRC, SequenceConfig, + &pSchedulerSequenceSteps->MsrcOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_PRE_RANGE, SequenceConfig, + &pSchedulerSequenceSteps->PreRangeOn); + } + if (Status == VL_ERROR_NONE) { + Status = sequence_step_enabled(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, SequenceConfig, + &pSchedulerSequenceSteps->FinalRangeOn); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetNumberOfSequenceSteps(struct vl_data *Dev, + uint8_t *pNumberOfSequenceSteps) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfSequenceSteps = VL_SEQUENCESTEP_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSequenceStepsInfo( + uint8_t SequenceStepId, char *pSequenceStepsString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_sequence_steps_info( + SequenceStepId, + pSequenceStepsString); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_SetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, unsigned int TimeOutMilliSecs) +{ + int8_t Status = VL_ERROR_NONE; + int8_t Status1 = VL_ERROR_NONE; + uint32_t TimeoutMicroSeconds = ((TimeOutMilliSecs * 1000) + 0x8000) + >> 16; + uint32_t MeasurementTimingBudgetMicroSeconds; + unsigned int OldTimeOutMicroSeconds; + + LOG_FUNCTION_START(""); + + /* Read back the current value in case we need to revert back to this. + */ + Status = get_sequence_step_timeout(Dev, SequenceStepId, + &OldTimeOutMicroSeconds); + + if (Status == VL_ERROR_NONE) { + Status = set_sequence_step_timeout(Dev, SequenceStepId, + TimeoutMicroSeconds); + } + + if (Status == VL_ERROR_NONE) { + VL_GETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + + /* At this point we don't know if the requested */ + /* value is valid, */ + /* therefore proceed to update the entire timing budget and */ + /* if this fails, revert back to the previous value. */ + Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + + if (Status != VL_ERROR_NONE) { + Status1 = set_sequence_step_timeout(Dev, SequenceStepId, + OldTimeOutMicroSeconds); + + if (Status1 == VL_ERROR_NONE) { + Status1 = + VL_SetMeasurementTimingBudgetMicroSeconds( + Dev, + MeasurementTimingBudgetMicroSeconds); + } + + Status = Status1; + } + } + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetSequenceStepTimeout(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int *pTimeOutMilliSecs) +{ + int8_t Status = VL_ERROR_NONE; + uint32_t TimeoutMicroSeconds; + + LOG_FUNCTION_START(""); + + Status = get_sequence_step_timeout(Dev, SequenceStepId, + &TimeoutMicroSeconds); + if (Status == VL_ERROR_NONE) { + TimeoutMicroSeconds <<= 8; + *pTimeOutMilliSecs = (TimeoutMicroSeconds + 500)/1000; + *pTimeOutMilliSecs <<= 8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev, + uint32_t InterMeasurementPeriodMilliSeconds) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t osc_calibrate_val; + uint32_t IMPeriodMilliSeconds; + + LOG_FUNCTION_START(""); + + Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL, + &osc_calibrate_val); + + if (Status == VL_ERROR_NONE) { + if (osc_calibrate_val != 0) { + IMPeriodMilliSeconds = + InterMeasurementPeriodMilliSeconds + * osc_calibrate_val; + } else { + IMPeriodMilliSeconds = + InterMeasurementPeriodMilliSeconds; + } + Status = VL_WrDWord(Dev, + VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD, + IMPeriodMilliSeconds); + } + + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, + InterMeasurementPeriodMilliSeconds, + InterMeasurementPeriodMilliSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetInterMeasurementPeriodMilliSeconds(struct vl_data *Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t osc_calibrate_val; + uint32_t IMPeriodMilliSeconds; + + LOG_FUNCTION_START(""); + + Status = VL_RdWord(Dev, VL_REG_OSC_CALIBRATE_VAL, + &osc_calibrate_val); + + if (Status == VL_ERROR_NONE) { + Status = VL_RdDWord(Dev, + VL_REG_SYSTEM_INTERMEASUREMENT_PERIOD, + &IMPeriodMilliSeconds); + } + + if (Status == VL_ERROR_NONE) { + if (osc_calibrate_val != 0) { + *pInterMeasurementPeriodMilliSeconds = + IMPeriodMilliSeconds / osc_calibrate_val; + } + VL_SETPARAMETERFIELD(Dev, + InterMeasurementPeriodMilliSeconds, + *pInterMeasurementPeriodMilliSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t XTalkCompensationEnable) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int TempFix1616; + uint16_t LinearityCorrectiveGain; + + LOG_FUNCTION_START(""); + + LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain); + + if ((XTalkCompensationEnable == 0) + || (LinearityCorrectiveGain != 1000)) { + TempFix1616 = 0; + } else { + VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, + TempFix1616); + } + + /* the following register has a format 3.13 */ + Status = VL_WrWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, + VL_FIXPOINT1616TOFIXPOINT313(TempFix1616)); + + if (Status == VL_ERROR_NONE) { + if (XTalkCompensationEnable == 0) { + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 0); + } else { + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetXTalkCompensationEnable(struct vl_data *Dev, + uint8_t *pXTalkCompensationEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8); + *pXTalkCompensationEnable = Temp8; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetXTalkCompensationRateMegaCps(struct vl_data *Dev, + unsigned int XTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + uint16_t LinearityCorrectiveGain; + uint16_t data; + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, Temp8); + LinearityCorrectiveGain = PALDevDataGet(Dev, LinearityCorrectiveGain); + + if (Temp8 == 0) { /* disabled write only internal value */ + VL_SETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, + XTalkCompensationRateMegaCps); + } else { + /* the following register has a format 3.13 */ + if (LinearityCorrectiveGain == 1000) { + data = VL_FIXPOINT1616TOFIXPOINT313( + XTalkCompensationRateMegaCps); + } else { + data = 0; + } + + Status = VL_WrWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, data); + + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, + XTalkCompensationRateMegaCps); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetXTalkCompensationRateMegaCps(struct vl_data *Dev, + unsigned int *pXTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t Value; + unsigned int TempFix1616; + + LOG_FUNCTION_START(""); + + Status = VL_RdWord(Dev, + VL_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, (uint16_t *)&Value); + if (Status == VL_ERROR_NONE) { + if (Value == 0) { + /* the Xtalk is disabled return value from memory */ + VL_GETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, TempFix1616); + *pXTalkCompensationRateMegaCps = TempFix1616; + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 0); + } else { + TempFix1616 = VL_FIXPOINT313TOFIXPOINT1616(Value); + *pXTalkCompensationRateMegaCps = TempFix1616; + VL_SETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, TempFix1616); + VL_SETPARAMETERFIELD(Dev, XTalkCompensationEnable, + 1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetRefCalibration(struct vl_data *Dev, uint8_t VhvSettings, + uint8_t PhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_ref_calibration(Dev, VhvSettings, PhaseCal); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetRefCalibration(struct vl_data *Dev, uint8_t *pVhvSettings, + uint8_t *pPhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_ref_calibration(Dev, pVhvSettings, pPhaseCal); + + LOG_FUNCTION_END(Status); + return Status; +} + +/* + * CHECK LIMIT FUNCTIONS + */ + +int8_t VL_GetNumberOfLimitCheck(uint16_t *pNumberOfLimitCheck) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfLimitCheck = VL_CHECKENABLE_NUMBER_OF_CHECKS; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckInfo(struct vl_data *Dev, uint16_t LimitCheckId, + char *pLimitCheckString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_limit_check_info(Dev, LimitCheckId, + pLimitCheckString); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckStatus(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + } else { + + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + LimitCheckId, Temp8); + + *pLimitCheckStatus = Temp8; + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t LimitCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int TempFix1616 = 0; + uint8_t LimitCheckEnableInt = 0; + uint8_t LimitCheckDisable = 0; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + } else { + if (LimitCheckEnable == 0) { + TempFix1616 = 0; + LimitCheckEnableInt = 0; + LimitCheckDisable = 1; + + } else { + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, TempFix1616); + LimitCheckDisable = 0; + /* this to be sure to have either 0 or 1 */ + LimitCheckEnableInt = 1; + } + + switch (LimitCheckId) { + + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + LimitCheckEnableInt); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + + Status = VL_WrWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, + VL_FIXPOINT1616TOFIXPOINT97(TempFix1616)); + + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + LimitCheckEnableInt); + + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + LimitCheckEnableInt); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + + Temp8 = (uint8_t)(LimitCheckDisable << 1); + Status = VL_UpdateByte(Dev, + VL_REG_MSRC_CONFIG_CONTROL, + 0xFE, Temp8); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + + Temp8 = (uint8_t)(LimitCheckDisable << 4); + Status = VL_UpdateByte(Dev, + VL_REG_MSRC_CONFIG_CONTROL, + 0xEF, Temp8); + + break; + + + default: + Status = VL_ERROR_INVALID_PARAMS; + + } + + } + + if (Status == VL_ERROR_NONE) { + if (LimitCheckEnable == 0) { + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, 0); + } else { + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, 1); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckEnable(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + *pLimitCheckEnable = 0; + } else { + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, + LimitCheckId, Temp8); + *pLimitCheckEnable = Temp8; + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId, + unsigned int LimitCheckValue) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Temp8; + + LOG_FUNCTION_START(""); + + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksEnable, LimitCheckId, + Temp8); + + if (Temp8 == 0) { /* disabled write only internal value */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } else { + + switch (LimitCheckId) { + + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + LimitCheckValue); + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + + Status = VL_WrWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, + VL_FIXPOINT1616TOFIXPOINT97( + LimitCheckValue)); + + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + LimitCheckValue); + + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + + /* internal computation: */ + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + LimitCheckValue); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + + Status = VL_WrWord(Dev, + VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT, + VL_FIXPOINT1616TOFIXPOINT97( + LimitCheckValue)); + + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + + } + + if (Status == VL_ERROR_NONE) { + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + LimitCheckId, LimitCheckValue); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetLimitCheckValue(struct vl_data *Dev, uint16_t LimitCheckId, + unsigned int *pLimitCheckValue) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t EnableZeroValue = 0; + uint16_t Temp16; + unsigned int TempFix1616; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* internal computation: */ + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, TempFix1616); + EnableZeroValue = 0; + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + Status = VL_RdWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, + &Temp16); + if (Status == VL_ERROR_NONE) + TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16); + + + EnableZeroValue = 1; + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + /* internal computation: */ + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_SIGNAL_REF_CLIP, TempFix1616); + EnableZeroValue = 0; + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + /* internal computation: */ + VL_GETARRAYPARAMETERFIELD(Dev, LimitChecksValue, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, TempFix1616); + EnableZeroValue = 0; + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + Status = VL_RdWord(Dev, + VL_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT, + &Temp16); + if (Status == VL_ERROR_NONE) + TempFix1616 = VL_FIXPOINT97TOFIXPOINT1616(Temp16); + + + EnableZeroValue = 0; + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + + } + + if (Status == VL_ERROR_NONE) { + + if (EnableZeroValue == 1) { + + if (TempFix1616 == 0) { + /* disabled: return value from memory */ + VL_GETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + *pLimitCheckValue = TempFix1616; + VL_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 0); + } else { + *pLimitCheckValue = TempFix1616; + VL_SETARRAYPARAMETERFIELD(Dev, + LimitChecksValue, LimitCheckId, + TempFix1616); + VL_SETARRAYPARAMETERFIELD(Dev, + LimitChecksEnable, LimitCheckId, 1); + } + } else { + *pLimitCheckValue = TempFix1616; + } + } + + LOG_FUNCTION_END(Status); + return Status; + +} + +int8_t VL_GetLimitCheckCurrent(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_RangingMeasurementData_t LastRangeDataBuffer; + + LOG_FUNCTION_START(""); + + if (LimitCheckId >= VL_CHECKENABLE_NUMBER_OF_CHECKS) { + Status = VL_ERROR_INVALID_PARAMS; + } else { + switch (LimitCheckId) { + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + /* Need to run a ranging to have the latest values */ + *pLimitCheckCurrent = PALDevDataGet(Dev, SigmaEstimate); + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + /* Need to run a ranging to have the latest values */ + *pLimitCheckCurrent = PALDevDataGet(Dev, + LastSignalRefMcps); + + break; + + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + /* Need to run a ranging to have the latest values */ + LastRangeDataBuffer = PALDevDataGet(Dev, + LastRangeMeasure); + *pLimitCheckCurrent = + LastRangeDataBuffer.SignalRateRtnMegaCps; + + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } + + LOG_FUNCTION_END(Status); + return Status; + +} + +/* + * WRAPAROUND Check + */ +int8_t VL_SetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t WrapAroundCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + uint8_t WrapAroundCheckEnableInt; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &Byte); + if (WrapAroundCheckEnable == 0) { + /* Disable wraparound */ + Byte = Byte & 0x7F; + WrapAroundCheckEnableInt = 0; + } else { + /*Enable wraparound */ + Byte = Byte | 0x80; + WrapAroundCheckEnableInt = 1; + } + + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, Byte); + + if (Status == VL_ERROR_NONE) { + PALDevDataSet(Dev, SequenceConfig, Byte); + VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable, + WrapAroundCheckEnableInt); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetWrapAroundCheckEnable(struct vl_data *Dev, + uint8_t *pWrapAroundCheckEnable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t data; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, &data); + if (Status == VL_ERROR_NONE) { + PALDevDataSet(Dev, SequenceConfig, data); + if (data & (0x01 << 7)) + *pWrapAroundCheckEnable = 0x01; + else + *pWrapAroundCheckEnable = 0x00; + } + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, WrapAroundCheckEnable, + *pWrapAroundCheckEnable); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetDmaxCalParameters(struct vl_data *Dev, + uint16_t RangeMilliMeter, unsigned int SignalRateRtnMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int SignalRateRtnMegaCpsTemp = 0; + + LOG_FUNCTION_START(""); + + /* Check if one of input parameter is zero, in that case the */ + /* value are get from NVM */ + if ((RangeMilliMeter == 0) || (SignalRateRtnMegaCps == 0)) { + /* NVM parameters */ + /* Run VL_get_info_from_device wit option 4 to get */ + /* signal rate at 400 mm if the value have been already */ + /* get this function will return with no access to device */ + VL_get_info_from_device(Dev, 4); + + SignalRateRtnMegaCpsTemp = VL_GETDEVICESPECIFICPARAMETER( + Dev, SignalRateMeasFixed400mm); + + PALDevDataSet(Dev, DmaxCalRangeMilliMeter, 400); + PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps, + SignalRateRtnMegaCpsTemp); + } else { + /* User parameters */ + PALDevDataSet(Dev, DmaxCalRangeMilliMeter, RangeMilliMeter); + PALDevDataSet(Dev, DmaxCalSignalRateRtnMegaCps, + SignalRateRtnMegaCps); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetDmaxCalParameters(struct vl_data *Dev, + uint16_t *pRangeMilliMeter, unsigned int *pSignalRateRtnMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pRangeMilliMeter = PALDevDataGet(Dev, DmaxCalRangeMilliMeter); + *pSignalRateRtnMegaCps = PALDevDataGet(Dev, + DmaxCalSignalRateRtnMegaCps); + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL Parameters Functions */ + +/* Group PAL Measurement Functions */ +int8_t VL_PerformSingleMeasurement(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t DeviceMode; + + LOG_FUNCTION_START(""); + + /* Get Current DeviceMode */ + Status = VL_GetDeviceMode(Dev, &DeviceMode); + + /* Start immediately to run a single ranging measurement in case of */ + /* single ranging or single histogram */ + if (Status == VL_ERROR_NONE + && DeviceMode == VL_DEVICEMODE_SINGLE_RANGING) + Status = VL_StartMeasurement(Dev); + + + if (Status == VL_ERROR_NONE) + Status = VL_measurement_poll_for_completion(Dev); + + + /* Change PAL State in case of single ranging or single histogram */ + if (Status == VL_ERROR_NONE + && DeviceMode == VL_DEVICEMODE_SINGLE_RANGING) + PALDevDataSet(Dev, PalState, VL_STATE_IDLE); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformSingleHistogramMeasurement(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformRefCalibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_ref_calibration(Dev, pVhvSettings, + pPhaseCal, 1); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformXTalkMeasurement(struct vl_data *Dev, + uint32_t TimeoutMs, unsigned int *pXtalkPerSpad, + uint8_t *pAmbientTooHigh) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented on VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformXTalkCalibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_xtalk_calibration(Dev, XTalkCalDistance, + pXTalkCompensationRateMegaCps); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformOffsetCalibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, int32_t *pOffsetMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_offset_calibration(Dev, CalDistanceMilliMeter, + pOffsetMicroMeter); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_CheckAndLoadInterruptSettings(struct vl_data *Dev, + uint8_t StartNotStopFlag) +{ + uint8_t InterruptConfig; + unsigned int ThresholdLow; + unsigned int ThresholdHigh; + int8_t Status = VL_ERROR_NONE; + + InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev, + Pin0GpioFunctionality); + + if ((InterruptConfig == + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW) || + (InterruptConfig == + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH) || + (InterruptConfig == + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT)) { + + Status = VL_GetInterruptThresholds(Dev, + VL_DEVICEMODE_CONTINUOUS_RANGING, + &ThresholdLow, &ThresholdHigh); + + if (((ThresholdLow > 255*65536) || + (ThresholdHigh > 255*65536)) && + (Status == VL_ERROR_NONE)) { + + if (StartNotStopFlag != 0) { + Status = VL_load_tuning_settings(Dev, + InterruptThresholdSettings); + } else { + Status |= VL_WrByte(Dev, 0xFF, 0x04); + Status |= VL_WrByte(Dev, 0x70, 0x00); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x00); + } + + } + + + } + + return Status; + +} + + +int8_t VL_StartMeasurement(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t DeviceMode; + uint8_t Byte; + uint8_t StartStopByte = VL_REG_SYSRANGE_MODE_START_STOP; + uint32_t LoopNb; + + LOG_FUNCTION_START(""); + + /* Get Current DeviceMode */ + VL_GetDeviceMode(Dev, &DeviceMode); + + Status = VL_WrByte(Dev, 0x80, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status = VL_WrByte(Dev, 0x00, 0x00); + Status = VL_WrByte(Dev, 0x91, PALDevDataGet(Dev, StopVariable)); + Status = VL_WrByte(Dev, 0x00, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x00); + Status = VL_WrByte(Dev, 0x80, 0x00); + + switch (DeviceMode) { + case VL_DEVICEMODE_SINGLE_RANGING: + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x01); + + Byte = StartStopByte; + if (Status == VL_ERROR_NONE) { + /* Wait until start bit has been cleared */ + LoopNb = 0; + do { + if (LoopNb > 0) + Status = VL_RdByte(Dev, + VL_REG_SYSRANGE_START, &Byte); + LoopNb = LoopNb + 1; + } while (((Byte & StartStopByte) == StartStopByte) + && (Status == VL_ERROR_NONE) + && (LoopNb < VL_DEFAULT_MAX_LOOP)); + + if (LoopNb >= VL_DEFAULT_MAX_LOOP) + Status = VL_ERROR_TIME_OUT; + + } + + break; + case VL_DEVICEMODE_CONTINUOUS_RANGING: + /* Back-to-back mode */ + + /* Check if need to apply interrupt settings */ + if (Status == VL_ERROR_NONE) + Status = VL_CheckAndLoadInterruptSettings(Dev, 1); + + Status = VL_WrByte(Dev, + VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_BACKTOBACK); + if (Status == VL_ERROR_NONE) { + /* Set PAL State to Running */ + PALDevDataSet(Dev, PalState, VL_STATE_RUNNING); + } + break; + case VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING: + /* Continuous mode */ + /* Check if need to apply interrupt settings */ + if (Status == VL_ERROR_NONE) + Status = VL_CheckAndLoadInterruptSettings(Dev, 1); + + Status = VL_WrByte(Dev, + VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_TIMED); + + if (Status == VL_ERROR_NONE) { + /* Set PAL State to Running */ + PALDevDataSet(Dev, PalState, VL_STATE_RUNNING); + } + break; + default: + /* Selected mode not supported */ + Status = VL_ERROR_MODE_NOT_SUPPORTED; + } + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_StopMeasurement(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_SINGLESHOT); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status = VL_WrByte(Dev, 0x00, 0x00); + Status = VL_WrByte(Dev, 0x91, 0x00); + Status = VL_WrByte(Dev, 0x00, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x00); + + if (Status == VL_ERROR_NONE) { + /* Set PAL State to Idle */ + PALDevDataSet(Dev, PalState, VL_STATE_IDLE); + } + + /* Check if need to apply interrupt settings */ + if (Status == VL_ERROR_NONE) + Status = VL_CheckAndLoadInterruptSettings(Dev, 0); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetMeasurementDataReady(struct vl_data *Dev, + uint8_t *pMeasurementDataReady) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SysRangeStatusRegister; + uint8_t InterruptConfig; + uint32_t InterruptMask; + + LOG_FUNCTION_START(""); + + InterruptConfig = VL_GETDEVICESPECIFICPARAMETER(Dev, + Pin0GpioFunctionality); + + if (InterruptConfig == + VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) { + Status = VL_GetInterruptMaskStatus(Dev, &InterruptMask); + if (InterruptMask == + VL_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) + *pMeasurementDataReady = 1; + else + *pMeasurementDataReady = 0; + } else { + Status = VL_RdByte(Dev, VL_REG_RESULT_RANGE_STATUS, + &SysRangeStatusRegister); + if (Status == VL_ERROR_NONE) { + if (SysRangeStatusRegister & 0x01) + *pMeasurementDataReady = 1; + else + *pMeasurementDataReady = 0; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_WaitDeviceReadyForNewMeasurement(struct vl_data *Dev, + uint32_t MaxLoop) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented for VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + + +int8_t VL_GetRangingMeasurementData(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t DeviceRangeStatus; + uint8_t RangeFractionalEnable; + uint8_t PalRangeStatus; + uint8_t XTalkCompensationEnable; + uint16_t AmbientRate; + unsigned int SignalRate; + uint16_t XTalkCompensationRateMegaCps; + uint16_t EffectiveSpadRtnCount; + uint16_t tmpuint16; + uint16_t XtalkRangeMilliMeter; + uint16_t LinearityCorrectiveGain; + uint8_t localBuffer[12]; + struct VL_RangingMeasurementData_t LastRangeDataBuffer; + + LOG_FUNCTION_START(""); + + /* + * use multi read even if some registers are not useful, result will + * be more efficient + * start reading at 0x14 dec20 + * end reading at 0x21 dec33 total 14 bytes to read + */ + Status = VL_ReadMulti(Dev, 0x14, localBuffer, 12); + + if (Status == VL_ERROR_NONE) { + + pRangingMeasurementData->ZoneId = 0; /* Only one zone */ + pRangingMeasurementData->TimeStamp = 0; /* Not Implemented */ + + tmpuint16 = VL_MAKEUINT16(localBuffer[11], + localBuffer[10]); + /* cut1.1 if SYSTEM__RANGE_CONFIG if 1 range is 2bits fractional + *(format 11.2) else no fractional + */ + + pRangingMeasurementData->MeasurementTimeUsec = 0; + + SignalRate = VL_FIXPOINT97TOFIXPOINT1616( + VL_MAKEUINT16(localBuffer[7], localBuffer[6])); + /* peak_signal_count_rate_rtn_mcps */ + pRangingMeasurementData->SignalRateRtnMegaCps = SignalRate; + + AmbientRate = VL_MAKEUINT16(localBuffer[9], + localBuffer[8]); + pRangingMeasurementData->AmbientRateRtnMegaCps = + VL_FIXPOINT97TOFIXPOINT1616(AmbientRate); + + EffectiveSpadRtnCount = VL_MAKEUINT16(localBuffer[3], + localBuffer[2]); + /* EffectiveSpadRtnCount is 8.8 format */ + pRangingMeasurementData->EffectiveSpadRtnCount = + EffectiveSpadRtnCount; + + DeviceRangeStatus = localBuffer[0]; + + /* Get Linearity Corrective Gain */ + LinearityCorrectiveGain = PALDevDataGet(Dev, + LinearityCorrectiveGain); + + /* Get ranging configuration */ + RangeFractionalEnable = PALDevDataGet(Dev, + RangeFractionalEnable); + + if (LinearityCorrectiveGain != 1000) { + + tmpuint16 = (uint16_t)((LinearityCorrectiveGain + * tmpuint16 + 500) / 1000); + + /* Implement Xtalk */ + VL_GETPARAMETERFIELD(Dev, + XTalkCompensationRateMegaCps, + XTalkCompensationRateMegaCps); + VL_GETPARAMETERFIELD(Dev, XTalkCompensationEnable, + XTalkCompensationEnable); + + if (XTalkCompensationEnable) { + + if ((SignalRate + - ((XTalkCompensationRateMegaCps + * EffectiveSpadRtnCount) >> 8)) + <= 0) { + if (RangeFractionalEnable) + XtalkRangeMilliMeter = 8888; + else + XtalkRangeMilliMeter = 8888 + << 2; + } else { + XtalkRangeMilliMeter = + (tmpuint16 * SignalRate) + / (SignalRate + - ((XTalkCompensationRateMegaCps + * EffectiveSpadRtnCount) + >> 8)); + } + + tmpuint16 = XtalkRangeMilliMeter; + } + + } + + if (RangeFractionalEnable) { + pRangingMeasurementData->RangeMilliMeter = + (uint16_t)((tmpuint16) >> 2); + pRangingMeasurementData->RangeFractionalPart = + (uint8_t)((tmpuint16 & 0x03) << 6); + } else { + pRangingMeasurementData->RangeMilliMeter = tmpuint16; + pRangingMeasurementData->RangeFractionalPart = 0; + } + + /* + * For a standard definition of RangeStatus, this should + * return 0 in case of good result after a ranging + * The range status depends on the device so call a device + * specific function to obtain the right Status. + */ + Status |= VL_get_pal_range_status(Dev, DeviceRangeStatus, + SignalRate, EffectiveSpadRtnCount, + pRangingMeasurementData, &PalRangeStatus); + + if (Status == VL_ERROR_NONE) + pRangingMeasurementData->RangeStatus = PalRangeStatus; + + } + + if (Status == VL_ERROR_NONE) { + /* Copy last read data into Dev buffer */ + LastRangeDataBuffer = PALDevDataGet(Dev, LastRangeMeasure); + + LastRangeDataBuffer.RangeMilliMeter = + pRangingMeasurementData->RangeMilliMeter; + LastRangeDataBuffer.RangeFractionalPart = + pRangingMeasurementData->RangeFractionalPart; + LastRangeDataBuffer.RangeDMaxMilliMeter = + pRangingMeasurementData->RangeDMaxMilliMeter; + LastRangeDataBuffer.MeasurementTimeUsec = + pRangingMeasurementData->MeasurementTimeUsec; + LastRangeDataBuffer.SignalRateRtnMegaCps = + pRangingMeasurementData->SignalRateRtnMegaCps; + LastRangeDataBuffer.AmbientRateRtnMegaCps = + pRangingMeasurementData->AmbientRateRtnMegaCps; + LastRangeDataBuffer.EffectiveSpadRtnCount = + pRangingMeasurementData->EffectiveSpadRtnCount; + LastRangeDataBuffer.RangeStatus = + pRangingMeasurementData->RangeStatus; + + PALDevDataSet(Dev, LastRangeMeasure, LastRangeDataBuffer); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetMeasurementRefSignal(struct vl_data *Dev, + unsigned int *pMeasurementRefSignal) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SignalRefClipLimitCheckEnable = 0; + + LOG_FUNCTION_START(""); + + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + &SignalRefClipLimitCheckEnable); + if (SignalRefClipLimitCheckEnable != 0) + *pMeasurementRefSignal = PALDevDataGet(Dev, LastSignalRefMcps); + else + Status = VL_ERROR_INVALID_COMMAND; + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetHistogramMeasurementData(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_PerformSingleRangingMeasurement(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + /* This function will do a complete single ranging */ + /* Here we fix the mode! */ + Status = VL_SetDeviceMode(Dev, VL_DEVICEMODE_SINGLE_RANGING); + + if (Status == VL_ERROR_NONE) + Status = VL_PerformSingleMeasurement(Dev); + + + if (Status == VL_ERROR_NONE) + Status = VL_GetRangingMeasurementData(Dev, + pRangingMeasurementData); + + + if (Status == VL_ERROR_NONE) + Status = VL_ClearInterruptMask(Dev, 0); + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetNumberOfROIZones(struct vl_data *Dev, + uint8_t NumberOfROIZones) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + if (NumberOfROIZones != 1) + Status = VL_ERROR_INVALID_PARAMS; + + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetNumberOfROIZones(struct vl_data *Dev, + uint8_t *pNumberOfROIZones) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pNumberOfROIZones = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetMaxNumberOfROIZones(struct vl_data *Dev, + uint8_t *pMaxNumberOfROIZones) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + *pMaxNumberOfROIZones = 1; + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL Measurement Functions */ + +int8_t VL_SetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t DeviceMode, uint8_t Functionality, + uint8_t Polarity) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t data; + + LOG_FUNCTION_START(""); + + if (Pin != 0) { + Status = VL_ERROR_GPIO_NOT_EXISTING; + } else if (DeviceMode == VL_DEVICEMODE_GPIO_DRIVE) { + if (Polarity == VL_INTERRUPTPOLARITY_LOW) + data = 0x10; + else + data = 1; + + Status = VL_WrByte(Dev, + VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, data); + + } else if (DeviceMode == VL_DEVICEMODE_GPIO_OSC) { + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + + Status |= VL_WrByte(Dev, 0xff, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x01); + Status |= VL_WrByte(Dev, 0x85, 0x02); + + Status |= VL_WrByte(Dev, 0xff, 0x04); + Status |= VL_WrByte(Dev, 0xcd, 0x00); + Status |= VL_WrByte(Dev, 0xcc, 0x11); + + Status |= VL_WrByte(Dev, 0xff, 0x07); + Status |= VL_WrByte(Dev, 0xbe, 0x00); + + Status |= VL_WrByte(Dev, 0xff, 0x06); + Status |= VL_WrByte(Dev, 0xcc, 0x09); + + Status |= VL_WrByte(Dev, 0xff, 0x00); + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + + } else { + + if (Status == VL_ERROR_NONE) { + switch (Functionality) { + case VL_GPIOFUNCTIONALITY_OFF: + data = 0x00; + break; + case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW: + data = 0x01; + break; + case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH: + data = 0x02; + break; + case VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT: + data = 0x03; + break; + case VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY: + data = 0x04; + break; + default: + Status = + VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED; + } + } + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, data); + + if (Status == VL_ERROR_NONE) { + if (Polarity == VL_INTERRUPTPOLARITY_LOW) + data = 0; + else + data = (uint8_t)(1 << 4); + + Status = VL_UpdateByte(Dev, + VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, 0xEF, data); + } + + if (Status == VL_ERROR_NONE) + VL_SETDEVICESPECIFICPARAMETER(Dev, + Pin0GpioFunctionality, Functionality); + + if (Status == VL_ERROR_NONE) + Status = VL_ClearInterruptMask(Dev, 0); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetGpioConfig(struct vl_data *Dev, uint8_t Pin, + uint8_t *pDeviceMode, + uint8_t *pFunctionality, + uint8_t *pPolarity) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t GpioFunctionality; + uint8_t data; + + LOG_FUNCTION_START(""); + + /* pDeviceMode not managed by Ewok it return the current mode */ + + Status = VL_GetDeviceMode(Dev, pDeviceMode); + + if (Status == VL_ERROR_NONE) { + if (Pin != 0) { + Status = VL_ERROR_GPIO_NOT_EXISTING; + } else { + Status = VL_RdByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, &data); + } + } + + if (Status == VL_ERROR_NONE) { + switch (data & 0x07) { + case 0x00: + GpioFunctionality = VL_GPIOFUNCTIONALITY_OFF; + break; + case 0x01: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW; + break; + case 0x02: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH; + break; + case 0x03: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT; + break; + case 0x04: + GpioFunctionality = + VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY; + break; + default: + Status = VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED; + } + } + + if (Status == VL_ERROR_NONE) + Status = VL_RdByte(Dev, + VL_REG_GPIO_HV_MUX_ACTIVE_HIGH, &data); + + if (Status == VL_ERROR_NONE) { + if ((data & (uint8_t)(1 << 4)) == 0) + *pPolarity = VL_INTERRUPTPOLARITY_LOW; + else + *pPolarity = VL_INTERRUPTPOLARITY_HIGH; + } + + if (Status == VL_ERROR_NONE) { + *pFunctionality = GpioFunctionality; + VL_SETDEVICESPECIFICPARAMETER(Dev, Pin0GpioFunctionality, + GpioFunctionality); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int ThresholdLow, + unsigned int ThresholdHigh) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t Threshold16; + + LOG_FUNCTION_START(""); + + /* no dependency on DeviceMode for Ewok */ + /* Need to divide by 2 because the FW will apply a x2 */ + Threshold16 = (uint16_t)((ThresholdLow >> 17) & 0x00fff); + Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_LOW, + Threshold16); + + if (Status == VL_ERROR_NONE) { + /* Need to divide by 2 because the FW will apply a x2 */ + Threshold16 = (uint16_t)((ThresholdHigh >> 17) & 0x00fff); + Status = VL_WrWord(Dev, VL_REG_SYSTEM_THRESH_HIGH, + Threshold16); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetInterruptThresholds(struct vl_data *Dev, + uint8_t DeviceMode, unsigned int *pThresholdLow, + unsigned int *pThresholdHigh) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t Threshold16; + + LOG_FUNCTION_START(""); + + /* no dependency on DeviceMode for Ewok */ + + Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_LOW, + &Threshold16); + /* Need to multiply by 2 because the FW will apply a x2 */ + *pThresholdLow = (unsigned int)((0x00fff & Threshold16) << 17); + + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, VL_REG_SYSTEM_THRESH_HIGH, + &Threshold16); + /* Need to multiply by 2 because the FW will apply a x2 */ + *pThresholdHigh = + (unsigned int)((0x00fff & Threshold16) << 17); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetStopCompletedStatus(struct vl_data *Dev, + uint32_t *pStopStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte = 0; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_RdByte(Dev, 0x04, &Byte); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x0); + + *pStopStatus = Byte; + + if (Byte == 0) { + Status = VL_WrByte(Dev, 0x80, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status = VL_WrByte(Dev, 0x00, 0x00); + Status = VL_WrByte(Dev, 0x91, + PALDevDataGet(Dev, StopVariable)); + Status = VL_WrByte(Dev, 0x00, 0x01); + Status = VL_WrByte(Dev, 0xFF, 0x00); + Status = VL_WrByte(Dev, 0x80, 0x00); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +/* Group PAL Interrupt Functions */ +int8_t VL_ClearInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t LoopCount; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + /* clear bit 0 range interrupt, bit 1 error interrupt */ + LoopCount = 0; + do { + Status = VL_WrByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_SYSTEM_INTERRUPT_CLEAR, 0x00); + Status |= VL_RdByte(Dev, + VL_REG_RESULT_INTERRUPT_STATUS, &Byte); + LoopCount++; + } while (((Byte & 0x07) != 0x00) + && (LoopCount < 3) + && (Status == VL_ERROR_NONE)); + + + if (LoopCount >= 3) + Status = VL_ERROR_INTERRUPT_NOT_CLEARED; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetInterruptMaskStatus(struct vl_data *Dev, + uint32_t *pInterruptMaskStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + Status = VL_RdByte(Dev, VL_REG_RESULT_INTERRUPT_STATUS, + &Byte); + *pInterruptMaskStatus = Byte & 0x07; + + if (Byte & 0x18) + Status = VL_ERROR_RANGE_ERROR; + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_EnableInterruptMask(struct vl_data *Dev, + uint32_t InterruptMask) +{ + int8_t Status = VL_ERROR_NOT_IMPLEMENTED; + + LOG_FUNCTION_START(""); + + /* not implemented for VL53L0X */ + + LOG_FUNCTION_END(Status); + return Status; +} + +/* End Group PAL Interrupt Functions */ + +/* Group SPAD functions */ + +int8_t VL_SetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t SpadAmbientDamperThreshold) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrWord(Dev, 0x40, SpadAmbientDamperThreshold); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSpadAmbientDamperThreshold(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperThreshold) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_RdWord(Dev, 0x40, pSpadAmbientDamperThreshold); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_SetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t SpadAmbientDamperFactor) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + Byte = (uint8_t)(SpadAmbientDamperFactor & 0x00FF); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x42, Byte); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_GetSpadAmbientDamperFactor(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperFactor) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t Byte; + + LOG_FUNCTION_START(""); + + Status = VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_RdByte(Dev, 0x42, &Byte); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + *pSpadAmbientDamperFactor = (uint16_t)Byte; + + LOG_FUNCTION_END(Status); + return Status; +} + +/* END Group SPAD functions */ + +/***************************************************************************** + * Internal functions + *****************************************************************************/ + +int8_t VL_SetReferenceSpads(struct vl_data *Dev, uint32_t count, + uint8_t isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_set_reference_spads(Dev, count, isApertureSpads); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_GetReferenceSpads(struct vl_data *Dev, uint32_t *pSpadCount, + uint8_t *pIsApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_get_reference_spads(Dev, pSpadCount, pIsApertureSpads); + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_PerformRefSpadManagement(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + Status = VL_perform_ref_spad_management(Dev, refSpadCount, + isApertureSpads); + + LOG_FUNCTION_END(Status); + + return Status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c new file mode 100644 index 000000000000..08b5ce23fe79 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_calibration.c @@ -0,0 +1,1266 @@ +/* + * vl53l0x_api_calibration.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_calibration.h" + +#ifndef __KERNEL__ +#include +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + +#define REF_ARRAY_SPAD_0 0 +#define REF_ARRAY_SPAD_5 5 +#define REF_ARRAY_SPAD_10 10 + +uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5, + REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5 }; + +int8_t VL_perform_xtalk_calibration(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t sum_ranging = 0; + uint16_t sum_spads = 0; + unsigned int sum_signalRate = 0; + unsigned int total_count = 0; + uint8_t xtalk_meas = 0; + struct VL_RangingMeasurementData_t RangingMeasurementData; + unsigned int xTalkStoredMeanSignalRate; + unsigned int xTalkStoredMeanRange; + unsigned int xTalkStoredMeanRtnSpads; + uint32_t signalXTalkTotalPerSpad; + uint32_t xTalkStoredMeanRtnSpadsAsInt; + uint32_t xTalkCalDistanceAsInt; + unsigned int XTalkCompensationRateMegaCps; + + if (XTalkCalDistance <= 0) + Status = VL_ERROR_INVALID_PARAMS; + + /* Disable the XTalk compensation */ + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationEnable(Dev, 0); + + /* Disable the RIT */ + if (Status == VL_ERROR_NONE) { + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0); + } + + /* Perform 50 measurements and compute the averages */ + if (Status == VL_ERROR_NONE) { + sum_ranging = 0; + sum_spads = 0; + sum_signalRate = 0; + total_count = 0; + for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) { + Status = VL_PerformSingleRangingMeasurement(Dev, + &RangingMeasurementData); + + if (Status != VL_ERROR_NONE) + break; + + /* The range is valid when RangeStatus = 0 */ + if (RangingMeasurementData.RangeStatus == 0) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + sum_signalRate = sum_signalRate + + RangingMeasurementData.SignalRateRtnMegaCps; + sum_spads = sum_spads + + RangingMeasurementData.EffectiveSpadRtnCount + / 256; + total_count = total_count + 1; + } + } + + /* no valid values found */ + if (total_count == 0) + Status = VL_ERROR_RANGE_ERROR; + + } + + + if (Status == VL_ERROR_NONE) { + /* unsigned int / uint16_t = unsigned int */ + xTalkStoredMeanSignalRate = sum_signalRate / total_count; + xTalkStoredMeanRange = (unsigned int)((uint32_t)( + sum_ranging << 16) / total_count); + xTalkStoredMeanRtnSpads = (unsigned int)((uint32_t)( + sum_spads << 16) / total_count); + + /* Round Mean Spads to Whole Number. + * Typically the calculated mean SPAD count is a whole number + * or very close to a whole + * number, therefore any truncation will not result in a + * significant loss in accuracy. + * Also, for a grey target at a typical distance of around + * 400mm, around 220 SPADs will + * be enabled, therefore, any truncation will result in a loss + * of accuracy of less than + * 0.5%. + */ + xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads + + 0x8000) >> 16; + + /* Round Cal Distance to Whole Number. */ + /* Note that the cal distance is in mm, */ + /* therefore no resolution is lost.*/ + xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16; + + if (xTalkStoredMeanRtnSpadsAsInt == 0 || + xTalkCalDistanceAsInt == 0 || + xTalkStoredMeanRange >= XTalkCalDistance) { + XTalkCompensationRateMegaCps = 0; + } else { + /* Round Cal Distance to Whole Number. */ + /* Note that the cal distance is in mm, therefore no */ + /* resolution is lost.*/ + xTalkCalDistanceAsInt = (XTalkCalDistance + + 0x8000) >> 16; + + /* Apply division by mean spad count early in the */ + /* calculation to keep the numbers small. */ + /* This ensures we can maintain a 32bit calculation. */ + /* Fixed1616 / int := Fixed1616 */ + signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) / + xTalkStoredMeanRtnSpadsAsInt; + + /* Complete the calculation for total Signal */ + /* XTalk per SPAD */ + /* Fixed1616 * (Fixed1616 - Fixed1616/int) := */ + /* (2^16 * Fixed1616) */ + + signalXTalkTotalPerSpad *= ((1 << 16) - + (xTalkStoredMeanRange / xTalkCalDistanceAsInt)); + + /* Round from 2^16 * Fixed1616, to Fixed1616. */ + XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad + + 0x8000) >> 16; + } + + *pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps; + + /* Enable the XTalk compensation */ + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationEnable(Dev, 1); + + /* Enable the XTalk compensation */ + if (Status == VL_ERROR_NONE) + Status = VL_SetXTalkCompensationRateMegaCps(Dev, + XTalkCompensationRateMegaCps); + + } + + return Status; +} + +int8_t VL_perform_offset_calibration(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, + int32_t *pOffsetMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t sum_ranging = 0; + unsigned int total_count = 0; + struct VL_RangingMeasurementData_t RangingMeasurementData; + unsigned int StoredMeanRange; + uint32_t StoredMeanRangeAsInt; + uint32_t CalDistanceAsInt_mm; + uint8_t SequenceStepEnabled; + int meas = 0; + + if (CalDistanceMilliMeter <= 0) + Status = VL_ERROR_INVALID_PARAMS; + + if (Status == VL_ERROR_NONE) + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, 0); + + + /* Get the value of the TCC */ + if (Status == VL_ERROR_NONE) + Status = VL_GetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, &SequenceStepEnabled); + + + /* Disable the TCC */ + if (Status == VL_ERROR_NONE) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, 0); + + + /* Disable the RIT */ + if (Status == VL_ERROR_NONE) + Status = VL_SetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0); + + /* Perform 50 measurements and compute the averages */ + if (Status == VL_ERROR_NONE) { + sum_ranging = 0; + total_count = 0; + for (meas = 0; meas < 50; meas++) { + Status = VL_PerformSingleRangingMeasurement(Dev, + &RangingMeasurementData); + + if (Status != VL_ERROR_NONE) + break; + + /* The range is valid when RangeStatus = 0 */ + if (RangingMeasurementData.RangeStatus == 0) { + sum_ranging = sum_ranging + + RangingMeasurementData.RangeMilliMeter; + total_count = total_count + 1; + } + } + + /* no valid values found */ + if (total_count == 0) + Status = VL_ERROR_RANGE_ERROR; + } + + + if (Status == VL_ERROR_NONE) { + /* unsigned int / uint16_t = unsigned int */ + StoredMeanRange = (unsigned int)((uint32_t)(sum_ranging << 16) + / total_count); + + StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16; + + /* Round Cal Distance to Whole Number. */ + /* Note that the cal distance is in mm, */ + /* therefore no resolution is lost.*/ + CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16; + + *pOffsetMicroMeter = (CalDistanceAsInt_mm - + StoredMeanRangeAsInt) * 1000; + + /* Apply the calculated offset */ + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters, + *pOffsetMicroMeter); + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, + *pOffsetMicroMeter); + } + + } + + /* Restore the TCC */ + if (Status == VL_ERROR_NONE) { + if (SequenceStepEnabled != 0) + Status = VL_SetSequenceStepEnable(Dev, + VL_SEQUENCESTEP_TCC, 1); + } + + return Status; +} + + +int8_t VL_set_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + int32_t cMaxOffsetMicroMeter = 511000; + int32_t cMinOffsetMicroMeter = -512000; + int16_t cOffsetRange = 4096; + uint32_t encodedOffsetVal; + + LOG_FUNCTION_START(""); + + if (OffsetCalibrationDataMicroMeter > cMaxOffsetMicroMeter) + OffsetCalibrationDataMicroMeter = cMaxOffsetMicroMeter; + else if (OffsetCalibrationDataMicroMeter < cMinOffsetMicroMeter) + OffsetCalibrationDataMicroMeter = cMinOffsetMicroMeter; + + /* The offset register is 10.2 format and units are mm + * therefore conversion is applied by a division of + * 250. + */ + if (OffsetCalibrationDataMicroMeter >= 0) { + encodedOffsetVal = + OffsetCalibrationDataMicroMeter/250; + } else { + encodedOffsetVal = + cOffsetRange + + OffsetCalibrationDataMicroMeter/250; + } + + Status = VL_WrWord(Dev, + VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM, + encodedOffsetVal); + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_offset_calibration_data_micro_meter(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter) +{ + int8_t Status = VL_ERROR_NONE; + uint16_t RangeOffsetRegister; + int16_t cMaxOffset = 2047; + int16_t cOffsetRange = 4096; + + /* Note that offset has 10.2 format */ + + Status = VL_RdWord(Dev, + VL_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM, + &RangeOffsetRegister); + + if (Status == VL_ERROR_NONE) { + RangeOffsetRegister = (RangeOffsetRegister & 0x0fff); + + /* Apply 12 bit 2's compliment conversion */ + if (RangeOffsetRegister > cMaxOffset) + *pOffsetCalibrationDataMicroMeter = + (int16_t)(RangeOffsetRegister - cOffsetRange) + * 250; + else + *pOffsetCalibrationDataMicroMeter = + (int16_t)RangeOffsetRegister * 250; + + } + + return Status; +} + + +int8_t VL_apply_offset_adjustment(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + int32_t CorrectedOffsetMicroMeters; + int32_t CurrentOffsetMicroMeters; + + /* if we run on this function we can read all the NVM info */ + /* used by the API */ + Status = VL_get_info_from_device(Dev, 7); + + /* Read back current device offset */ + if (Status == VL_ERROR_NONE) { + Status = VL_GetOffsetCalibrationDataMicroMeter(Dev, + &CurrentOffsetMicroMeters); + } + + /* Apply Offset Adjustment derived from 400mm measurements */ + if (Status == VL_ERROR_NONE) { + + /* Store initial device offset */ + PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter, + CurrentOffsetMicroMeters); + + CorrectedOffsetMicroMeters = CurrentOffsetMicroMeters + + (int32_t)PALDevDataGet(Dev, + Part2PartOffsetAdjustmentNVMMicroMeter); + + Status = VL_SetOffsetCalibrationDataMicroMeter(Dev, + CorrectedOffsetMicroMeters); + + /* store current, adjusted offset */ + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters, + CorrectedOffsetMicroMeters); + } + } + + return Status; +} + +void get_next_good_spad(uint8_t goodSpadArray[], uint32_t size, + uint32_t curr, int32_t *next) +{ + uint32_t startIndex; + uint32_t fineOffset; + uint32_t cSpadsPerByte = 8; + uint32_t coarseIndex; + uint32_t fineIndex; + uint8_t dataByte; + uint8_t success = 0; + + /* + * Starting with the current good spad, loop through the array to find + * the next. i.e. the next bit set in the sequence. + * + * The coarse index is the byte index of the array and the fine index is + * the index of the bit within each byte. + */ + + *next = -1; + + startIndex = curr / cSpadsPerByte; + fineOffset = curr % cSpadsPerByte; + + for (coarseIndex = startIndex; ((coarseIndex < size) && !success); + coarseIndex++) { + fineIndex = 0; + dataByte = goodSpadArray[coarseIndex]; + + if (coarseIndex == startIndex) { + /* locate the bit position of the provided current */ + /* spad bit before iterating */ + dataByte >>= fineOffset; + fineIndex = fineOffset; + } + + while (fineIndex < cSpadsPerByte) { + if ((dataByte & 0x1) == 1) { + success = 1; + *next = coarseIndex * cSpadsPerByte + fineIndex; + break; + } + dataByte >>= 1; + fineIndex++; + } + } +} + + +uint8_t is_aperture(uint32_t spadIndex) +{ + /* + * This function reports if a given spad index is an aperture SPAD by + * deriving the quadrant. + */ + uint32_t quadrant; + uint8_t isAperture = 1; + + quadrant = spadIndex >> 6; + if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0) + isAperture = 0; + + return isAperture; +} + + +int8_t enable_spad_bit(uint8_t spadArray[], uint32_t size, + uint32_t spadIndex) +{ + int8_t status = VL_ERROR_NONE; + uint32_t cSpadsPerByte = 8; + uint32_t coarseIndex; + uint32_t fineIndex; + + coarseIndex = spadIndex / cSpadsPerByte; + fineIndex = spadIndex % cSpadsPerByte; + if (coarseIndex >= size) + status = VL_ERROR_REF_SPAD_INIT; + else + spadArray[coarseIndex] |= (1 << fineIndex); + + return status; +} + +int8_t count_enabled_spads(uint8_t spadArray[], + uint32_t byteCount, uint32_t maxSpads, + uint32_t *pTotalSpadsEnabled, uint8_t *pIsAperture) +{ + int8_t status = VL_ERROR_NONE; + uint32_t cSpadsPerByte = 8; + uint32_t lastByte; + uint32_t lastBit; + uint32_t byteIndex = 0; + uint32_t bitIndex = 0; + uint8_t tempByte; + uint8_t spadTypeIdentified = 0; + + /* The entire array will not be used for spads, therefore the last + * byte and last bit is determined from the max spads value. + */ + + lastByte = maxSpads / cSpadsPerByte; + lastBit = maxSpads % cSpadsPerByte; + + /* Check that the max spads value does not exceed the array bounds. */ + if (lastByte >= byteCount) + status = VL_ERROR_REF_SPAD_INIT; + + *pTotalSpadsEnabled = 0; + + /* Count the bits enabled in the whole bytes */ + for (byteIndex = 0; byteIndex <= (lastByte - 1); byteIndex++) { + tempByte = spadArray[byteIndex]; + + for (bitIndex = 0; bitIndex <= cSpadsPerByte; bitIndex++) { + if ((tempByte & 0x01) == 1) { + (*pTotalSpadsEnabled)++; + if (!spadTypeIdentified) { + *pIsAperture = 1; + if ((byteIndex < 2) && (bitIndex < 4)) + *pIsAperture = 0; + spadTypeIdentified = 1; + } + } + tempByte >>= 1; + } + } + + /* Count the number of bits enabled in the last byte accounting + * for the fact that not all bits in the byte may be used. + */ + tempByte = spadArray[lastByte]; + + for (bitIndex = 0; bitIndex <= lastBit; bitIndex++) { + if ((tempByte & 0x01) == 1) + (*pTotalSpadsEnabled)++; + } + + return status; +} + +int8_t set_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray) +{ + int8_t status = VL_WriteMulti(Dev, + VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0, + refSpadArray, 6); + return status; +} + +int8_t get_ref_spad_map(struct vl_data *Dev, uint8_t *refSpadArray) +{ + int8_t status = VL_ReadMulti(Dev, + VL_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0, + refSpadArray, + 6); + return status; +} + +int8_t enable_ref_spads(struct vl_data *Dev, + uint8_t apertureSpads, + uint8_t goodSpadArray[], + uint8_t spadArray[], + uint32_t size, + uint32_t start, + uint32_t offset, + uint32_t spadCount, + uint32_t *lastSpad) +{ + int8_t status = VL_ERROR_NONE; + uint32_t index; + uint32_t i; + int32_t nextGoodSpad = offset; + uint32_t currentSpad; + uint8_t checkSpadArray[6]; + + /* + * This function takes in a spad array which may or may not have SPADS + * already enabled and appends from a given offset a requested number + * of new SPAD enables. The 'good spad map' is applied to + * determine the next SPADs to enable. + * + * This function applies to only aperture or only non-aperture spads. + * Checks are performed to ensure this. + */ + + currentSpad = offset; + for (index = 0; index < spadCount; index++) { + get_next_good_spad(goodSpadArray, size, currentSpad, + &nextGoodSpad); + + if (nextGoodSpad == -1) { + status = VL_ERROR_REF_SPAD_INIT; + break; + } + + /* Confirm that the next good SPAD is non-aperture */ + if (is_aperture(start + nextGoodSpad) != apertureSpads) { + /* if we can't get the required number of good aperture + * spads from the current quadrant then this is an error + */ + status = VL_ERROR_REF_SPAD_INIT; + break; + } + currentSpad = (uint32_t)nextGoodSpad; + enable_spad_bit(spadArray, size, currentSpad); + currentSpad++; + } + *lastSpad = currentSpad; + + if (status == VL_ERROR_NONE) + status = set_ref_spad_map(Dev, spadArray); + + + if (status == VL_ERROR_NONE) { + status = get_ref_spad_map(Dev, checkSpadArray); + + i = 0; + + /* Compare spad maps. If not equal report error. */ + while (i < size) { + if (spadArray[i] != checkSpadArray[i]) { + status = VL_ERROR_REF_SPAD_INIT; + break; + } + i++; + } + } + return status; +} + + +int8_t perform_ref_signal_measurement(struct vl_data *Dev, + uint16_t *refSignalRate) +{ + int8_t status = VL_ERROR_NONE; + struct VL_RangingMeasurementData_t rangingMeasurementData; + + uint8_t SequenceConfig = 0; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* + * This function performs a reference signal rate measurement. + */ + if (status == VL_ERROR_NONE) + status = VL_WrByte(Dev, + VL_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0); + + if (status == VL_ERROR_NONE) + status = VL_PerformSingleRangingMeasurement(Dev, + &rangingMeasurementData); + + if (status == VL_ERROR_NONE) + status = VL_WrByte(Dev, 0xFF, 0x01); + + if (status == VL_ERROR_NONE) + status = VL_RdWord(Dev, + VL_REG_RESULT_PEAK_SIGNAL_RATE_REF, + refSignalRate); + + if (status == VL_ERROR_NONE) + status = VL_WrByte(Dev, 0xFF, 0x00); + + if (status == VL_ERROR_NONE) { + /* restore the previous Sequence Config */ + status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + } + + return status; +} + +int8_t VL_perform_ref_spad_management(struct vl_data *Dev, + uint32_t *refSpadCount, + uint8_t *isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t lastSpadArray[6]; + uint8_t startSelect = 0xB4; + uint32_t minimumSpadCount = 3; + uint32_t maxSpadCount = 44; + uint32_t currentSpadIndex = 0; + uint32_t lastSpadIndex = 0; + int32_t nextGoodSpad = 0; + uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */ + uint16_t peakSignalRateRef; + uint32_t needAptSpads = 0; + uint32_t index = 0; + uint32_t spadArraySize = 6; + uint32_t signalRateDiff = 0; + uint32_t lastSignalRateDiff = 0; + uint8_t complete = 0; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + uint32_t refSpadCount_int = 0; + uint8_t isApertureSpads_int = 0; + + /* + * The reference SPAD initialization procedure determines the minimum + * amount of reference spads to be enables to achieve a target reference + * signal rate and should be performed once during initialization. + * + * Either aperture or non-aperture spads are applied but never both. + * Firstly non-aperture spads are set, beginning with 5 spads, and + * increased one spad at a time until the closest measurement to the + * target rate is achieved. + * + * If the target rate is exceeded when 5 non-aperture spads are enabled, + * initialization is performed instead with aperture spads. + * + * When setting spads, a 'Good Spad Map' is applied. + * + * This procedure operates within a SPAD window of interest of a maximum + * 44 spads. + * The start point is currently fixed to 180, which lies towards the end + * of the non-aperture quadrant and runs in to the adjacent aperture + * quadrant. + */ + + + targetRefRate = PALDevDataGet(Dev, targetRefRate); + + /* + * Initialize Spad arrays. + * Currently the good spad map is initialised to 'All good'. + * This is a short term implementation. The good spad map will be + * provided as an input. + * Note that there are 6 bytes. Only the first 44 bits will be used to + * represent spads. + */ + for (index = 0; index < spadArraySize; index++) + Dev->Data.SpadData.RefSpadEnables[index] = 0; + + + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT, + startSelect); + + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0); + + /* Perform ref calibration */ + if (Status == VL_ERROR_NONE) + Status = VL_perform_ref_calibration(Dev, &VhvSettings, + &PhaseCal, 0); + + if (Status == VL_ERROR_NONE) { + /* Enable Minimum NON-APERTURE Spads */ + currentSpadIndex = 0; + lastSpadIndex = currentSpadIndex; + needAptSpads = 0; + Status = enable_ref_spads(Dev, + needAptSpads, + Dev->Data.SpadData.RefGoodSpadMap, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, + startSelect, + currentSpadIndex, + minimumSpadCount, + &lastSpadIndex); + } + + if (Status == VL_ERROR_NONE) { + currentSpadIndex = lastSpadIndex; + + Status = perform_ref_signal_measurement(Dev, + &peakSignalRateRef); + if ((Status == VL_ERROR_NONE) && + (peakSignalRateRef > targetRefRate)) { + /* Signal rate measurement too high, */ + /* switch to APERTURE SPADs */ + + for (index = 0; index < spadArraySize; index++) + Dev->Data.SpadData.RefSpadEnables[index] = 0; + + + /* Increment to the first APERTURE spad */ + while ((is_aperture(startSelect + currentSpadIndex) + == 0) && (currentSpadIndex < maxSpadCount)) { + currentSpadIndex++; + } + + needAptSpads = 1; + + Status = enable_ref_spads(Dev, + needAptSpads, + Dev->Data.SpadData.RefGoodSpadMap, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, + startSelect, + currentSpadIndex, + minimumSpadCount, + &lastSpadIndex); + + if (Status == VL_ERROR_NONE) { + currentSpadIndex = lastSpadIndex; + Status = perform_ref_signal_measurement(Dev, + &peakSignalRateRef); + + if ((Status == VL_ERROR_NONE) && + (peakSignalRateRef > targetRefRate)) { + /* Signal rate still too high after + * setting the minimum number of + * APERTURE spads. Can do no more + * therefore set the min number of + * aperture spads as the result. + */ + isApertureSpads_int = 1; + refSpadCount_int = minimumSpadCount; + } + } + } else { + needAptSpads = 0; + } + } + + if ((Status == VL_ERROR_NONE) && + (peakSignalRateRef < targetRefRate)) { + /* At this point, the minimum number of either aperture + * or non-aperture spads have been set. Proceed to add + * spads and perform measurements until the target + * reference is reached. + */ + isApertureSpads_int = needAptSpads; + refSpadCount_int = minimumSpadCount; + + memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables, + spadArraySize); + lastSignalRateDiff = abs(peakSignalRateRef - + targetRefRate); + complete = 0; + + while (!complete) { + get_next_good_spad( + Dev->Data.SpadData.RefGoodSpadMap, + spadArraySize, currentSpadIndex, + &nextGoodSpad); + + if (nextGoodSpad == -1) { + Status = VL_ERROR_REF_SPAD_INIT; + break; + } + + /* Cannot combine Aperture and Non-Aperture spads, so + * ensure the current spad is of the correct type. + */ + if (is_aperture((uint32_t)startSelect + nextGoodSpad) != + needAptSpads) { + /* At this point we have enabled the maximum + * number of Aperture spads. + */ + complete = 1; + break; + } + + (refSpadCount_int)++; + + currentSpadIndex = nextGoodSpad; + Status = enable_spad_bit( + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, currentSpadIndex); + + if (Status == VL_ERROR_NONE) { + currentSpadIndex++; + /* Proceed to apply the additional spad and */ + /* perform measurement. */ + Status = set_ref_spad_map(Dev, + Dev->Data.SpadData.RefSpadEnables); + } + + if (Status != VL_ERROR_NONE) + break; + + Status = perform_ref_signal_measurement(Dev, + &peakSignalRateRef); + + if (Status != VL_ERROR_NONE) + break; + + signalRateDiff = abs(peakSignalRateRef - targetRefRate); + + if (peakSignalRateRef > targetRefRate) { + /* Select the spad map that provides the */ + /* measurement closest to the target rate, */ + /* either above or below it. */ + + if (signalRateDiff > lastSignalRateDiff) { + /* Previous spad map produced a closer */ + /* measurement, so choose this. */ + Status = set_ref_spad_map(Dev, + lastSpadArray); + memcpy( + Dev->Data.SpadData.RefSpadEnables, + lastSpadArray, spadArraySize); + + (refSpadCount_int)--; + } + complete = 1; + } else { + /* Continue to add spads */ + lastSignalRateDiff = signalRateDiff; + memcpy(lastSpadArray, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize); + } + + } /* while */ + } + + if (Status == VL_ERROR_NONE) { + *refSpadCount = refSpadCount_int; + *isApertureSpads = isApertureSpads_int; + + VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, (uint8_t)(*refSpadCount)); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, *isApertureSpads); + } + + return Status; +} + +int8_t VL_set_reference_spads(struct vl_data *Dev, + uint32_t count, uint8_t isApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + uint32_t currentSpadIndex = 0; + uint8_t startSelect = 0xB4; + uint32_t spadArraySize = 6; + uint32_t maxSpadCount = 44; + uint32_t lastSpadIndex; + uint32_t index; + + /* + * This function applies a requested number of reference spads, either + * aperture or + * non-aperture, as requested. + * The good spad map will be applied. + */ + + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x00); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_REF_EN_START_SELECT, + startSelect); + + for (index = 0; index < spadArraySize; index++) + Dev->Data.SpadData.RefSpadEnables[index] = 0; + + if (isApertureSpads) { + /* Increment to the first APERTURE spad */ + while ((is_aperture(startSelect + currentSpadIndex) == 0) && + (currentSpadIndex < maxSpadCount)) { + currentSpadIndex++; + } + } + Status = enable_ref_spads(Dev, + isApertureSpads, + Dev->Data.SpadData.RefGoodSpadMap, + Dev->Data.SpadData.RefSpadEnables, + spadArraySize, + startSelect, + currentSpadIndex, + count, + &lastSpadIndex); + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, (uint8_t)(count)); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, isApertureSpads); + } + + return Status; +} + +int8_t VL_get_reference_spads(struct vl_data *Dev, + uint32_t *pSpadCount, uint8_t *pIsApertureSpads) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t refSpadsInitialised; + uint8_t refSpadArray[6]; + uint32_t cMaxSpadCount = 44; + uint32_t cSpadArraySize = 6; + uint32_t spadsEnabled; + uint8_t isApertureSpads = 0; + + refSpadsInitialised = VL_GETDEVICESPECIFICPARAMETER(Dev, + RefSpadsInitialised); + + if (refSpadsInitialised == 1) { + + *pSpadCount = (uint32_t)VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount); + *pIsApertureSpads = VL_GETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType); + } else { + + /* obtain spad info from device.*/ + Status = get_ref_spad_map(Dev, refSpadArray); + + if (Status == VL_ERROR_NONE) { + /* count enabled spads within spad map array and + * determine if Aperture or Non-Aperture. + */ + Status = count_enabled_spads(refSpadArray, + cSpadArraySize, + cMaxSpadCount, + &spadsEnabled, + &isApertureSpads); + + if (Status == VL_ERROR_NONE) { + + *pSpadCount = spadsEnabled; + *pIsApertureSpads = isApertureSpads; + + VL_SETDEVICESPECIFICPARAMETER(Dev, + RefSpadsInitialised, 1); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, + (uint8_t)spadsEnabled); + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, isApertureSpads); + } + } + } + + return Status; +} + + +int8_t VL_perform_single_ref_calibration(struct vl_data *Dev, + uint8_t vhv_init_byte) +{ + int8_t Status = VL_ERROR_NONE; + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, + VL_REG_SYSRANGE_MODE_START_STOP | + vhv_init_byte); + + if (Status == VL_ERROR_NONE) + Status = VL_measurement_poll_for_completion(Dev); + + if (Status == VL_ERROR_NONE) + Status = VL_ClearInterruptMask(Dev, 0); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, VL_REG_SYSRANGE_START, 0x00); + + return Status; +} + + +int8_t VL_ref_calibration_io(struct vl_data *Dev, + uint8_t read_not_write, uint8_t VhvSettings, uint8_t PhaseCal, + uint8_t *pVhvSettings, uint8_t *pPhaseCal, + const uint8_t vhv_enable, const uint8_t phase_enable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t PhaseCalint = 0; + + /* Read VHV from device */ + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + if (read_not_write) { + if (vhv_enable) + Status |= VL_RdByte(Dev, 0xCB, pVhvSettings); + if (phase_enable) + Status |= VL_RdByte(Dev, 0xEE, &PhaseCalint); + } else { + if (vhv_enable) + Status |= VL_WrByte(Dev, 0xCB, VhvSettings); + if (phase_enable) + Status |= VL_UpdateByte(Dev, 0xEE, 0x80, PhaseCal); + } + + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x00); + + *pPhaseCal = (uint8_t)(PhaseCalint&0xEF); + + return Status; +} + + +int8_t VL_perform_vhv_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, const uint8_t get_data_enable, + const uint8_t restore_config) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + uint8_t PhaseCalInt = 0; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + if (restore_config) + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* Run VHV */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_perform_single_ref_calibration(Dev, 0x40); + + /* Read VHV from device */ + if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) { + Status = VL_ref_calibration_io(Dev, 1, + VhvSettings, PhaseCal, /* Not used here */ + pVhvSettings, &PhaseCalInt, + 1, 0); + } else + *pVhvSettings = 0; + + + if ((Status == VL_ERROR_NONE) && restore_config) { + /* restore the previous Sequence Config */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + + } + + return Status; +} + +int8_t VL_perform_phase_calibration(struct vl_data *Dev, + uint8_t *pPhaseCal, const uint8_t get_data_enable, + const uint8_t restore_config) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + uint8_t VhvSettingsint; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + if (restore_config) + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* Run PhaseCal */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, 0x02); + + if (Status == VL_ERROR_NONE) + Status = VL_perform_single_ref_calibration(Dev, 0x0); + + /* Read PhaseCal from device */ + if ((Status == VL_ERROR_NONE) && (get_data_enable == 1)) { + Status = VL_ref_calibration_io(Dev, 1, + VhvSettings, PhaseCal, /* Not used here */ + &VhvSettingsint, pPhaseCal, + 0, 1); + } else + *pPhaseCal = 0; + + + if ((Status == VL_ERROR_NONE) && restore_config) { + /* restore the previous Sequence Config */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + + } + + return Status; +} + +int8_t VL_perform_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t SequenceConfig = 0; + + /* store the value of the sequence config, + * this will be reset before the end of the function + */ + + SequenceConfig = PALDevDataGet(Dev, SequenceConfig); + + /* In the following function we don't save the config to optimize */ + /* writes on device. Config is saved and restored only once. */ + Status = VL_perform_vhv_calibration( + Dev, pVhvSettings, get_data_enable, 0); + + + if (Status == VL_ERROR_NONE) + Status = VL_perform_phase_calibration( + Dev, pPhaseCal, get_data_enable, 0); + + + if (Status == VL_ERROR_NONE) { + /* restore the previous Sequence Config */ + Status = VL_WrByte(Dev, VL_REG_SYSTEM_SEQUENCE_CONFIG, + SequenceConfig); + if (Status == VL_ERROR_NONE) + PALDevDataSet(Dev, SequenceConfig, SequenceConfig); + + } + + return Status; +} + +int8_t VL_set_ref_calibration(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t pVhvSettings; + uint8_t pPhaseCal; + + Status = VL_ref_calibration_io(Dev, 0, + VhvSettings, PhaseCal, + &pVhvSettings, &pPhaseCal, + 1, 1); + + return Status; +} + +int8_t VL_get_ref_calibration(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t VhvSettings = 0; + uint8_t PhaseCal = 0; + + Status = VL_ref_calibration_io(Dev, 1, + VhvSettings, PhaseCal, + pVhvSettings, pPhaseCal, + 1, 1); + + return Status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c new file mode 100644 index 000000000000..ceb3585b20e7 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_core.c @@ -0,0 +1,2220 @@ +/* + * vl53l0x_api_core.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_calibration.h" + + +#ifndef __KERNEL__ +#include +#endif +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + +int8_t VL_reverse_bytes(uint8_t *data, uint32_t size) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t tempData; + uint32_t mirrorIndex; + uint32_t middle = size/2; + uint32_t index; + + for (index = 0; index < middle; index++) { + mirrorIndex = size - index - 1; + tempData = data[index]; + data[index] = data[mirrorIndex]; + data[mirrorIndex] = tempData; + } + return Status; +} + +int8_t VL_measurement_poll_for_completion(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t NewDataReady = 0; + uint32_t LoopNb; + + LOG_FUNCTION_START(""); + + LoopNb = 0; + + do { + Status = VL_GetMeasurementDataReady(Dev, &NewDataReady); + if (Status != 0) + break; /* the error is set */ + + if (NewDataReady == 1) + break; /* done note that status == 0 */ + + LoopNb++; + if (LoopNb >= VL_DEFAULT_MAX_LOOP) { + Status = VL_ERROR_TIME_OUT; + break; + } + + VL_PollingDelay(Dev); + } while (1); + + LOG_FUNCTION_END(Status); + + return Status; +} + + +uint8_t VL_decode_vcsel_period(uint8_t vcsel_period_reg) +{ + /*! + * Converts the encoded VCSEL period register value into the real + * period in PLL clocks + */ + + uint8_t vcsel_period_pclks = 0; + + vcsel_period_pclks = (vcsel_period_reg + 1) << 1; + + return vcsel_period_pclks; +} + +uint8_t VL_encode_vcsel_period(uint8_t vcsel_period_pclks) +{ + /*! + * Converts the encoded VCSEL period register value into the real period + * in PLL clocks + */ + + uint8_t vcsel_period_reg = 0; + + vcsel_period_reg = (vcsel_period_pclks >> 1) - 1; + + return vcsel_period_reg; +} + + +uint32_t VL_isqrt(uint32_t num) +{ + /* + * Implements an integer square root + * + * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots + */ + + uint32_t res = 0; + uint32_t bit = 1 << 30; + /* The second-to-top bit is set: */ + /* 1 << 14 for 16-bits, 1 << 30 for 32 bits */ + + /* "bit" starts at the highest power of four <= the argument. */ + while (bit > num) + bit >>= 2; + + + while (bit != 0) { + if (num >= res + bit) { + num -= res + bit; + res = (res >> 1) + bit; + } else + res >>= 1; + + bit >>= 2; + } + + return res; +} + + +uint32_t VL_quadrature_sum(uint32_t a, uint32_t b) +{ + /* + * Implements a quadrature sum + * + * rea = sqrt(a^2 + b^2) + * + * Trap overflow case max input value is 65535 (16-bit value) + * as internal calc are 32-bit wide + * + * If overflow then seta output to maximum + */ + uint32_t res = 0; + + if (a > 65535 || b > 65535) + res = 65535; + else + res = VL_isqrt(a * a + b * b); + + return res; +} + + +int8_t VL_device_read_strobe(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t strobe; + uint32_t LoopNb; + + LOG_FUNCTION_START(""); + + Status |= VL_WrByte(Dev, 0x83, 0x00); + + /* polling use timeout to avoid deadlock*/ + if (Status == VL_ERROR_NONE) { + LoopNb = 0; + do { + Status = VL_RdByte(Dev, 0x83, &strobe); + if ((strobe != 0x00) || Status != VL_ERROR_NONE) + break; + LoopNb = LoopNb + 1; + } while (LoopNb < VL_DEFAULT_MAX_LOOP); + + if (LoopNb >= VL_DEFAULT_MAX_LOOP) + Status = VL_ERROR_TIME_OUT; + + } + + Status |= VL_WrByte(Dev, 0x83, 0x01); + + LOG_FUNCTION_END(Status); + return Status; + +} + +int8_t VL_get_info_from_device(struct vl_data *Dev, uint8_t option) +{ + + int8_t Status = VL_ERROR_NONE; + uint8_t byte; + uint32_t TmpDWord; + uint8_t ModuleId; + uint8_t Revision; + uint8_t ReferenceSpadCount = 0; + uint8_t ReferenceSpadType = 0; + uint32_t PartUIDUpper = 0; + uint32_t PartUIDLower = 0; + uint32_t OffsetFixed1104_mm = 0; + int16_t OffsetMicroMeters = 0; + uint32_t DistMeasTgtFixed1104_mm = 400 << 4; + uint32_t DistMeasFixed1104_400_mm = 0; + uint32_t SignalRateMeasFixed1104_400_mm = 0; + char ProductId[19]; + char *ProductId_tmp; + uint8_t ReadDataFromDeviceDone; + unsigned int SignalRateMeasFixed400mmFix = 0; + uint8_t NvmRefGoodSpadMap[VL_REF_SPAD_BUFFER_SIZE]; + int i; + + + LOG_FUNCTION_START(""); + + ReadDataFromDeviceDone = VL_GETDEVICESPECIFICPARAMETER(Dev, + ReadDataFromDeviceDone); + + /* This access is done only once after that a GetDeviceInfo or */ + /* datainit is done*/ + if (ReadDataFromDeviceDone != 7) { + + Status |= VL_WrByte(Dev, 0x80, 0x01); + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x00); + + Status |= VL_WrByte(Dev, 0xFF, 0x06); + Status |= VL_RdByte(Dev, 0x83, &byte); + Status |= VL_WrByte(Dev, 0x83, byte|4); + Status |= VL_WrByte(Dev, 0xFF, 0x07); + Status |= VL_WrByte(Dev, 0x81, 0x01); + + Status |= VL_PollingDelay(Dev); + + Status |= VL_WrByte(Dev, 0x80, 0x01); + + if (((option & 1) == 1) && + ((ReadDataFromDeviceDone & 1) == 0)) { + Status |= VL_WrByte(Dev, 0x94, 0x6b); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ReferenceSpadCount = (uint8_t)((TmpDWord >> 8) & 0x07f); + ReferenceSpadType = (uint8_t)((TmpDWord >> 15) & 0x01); + + Status |= VL_WrByte(Dev, 0x94, 0x24); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + + NvmRefGoodSpadMap[0] = (uint8_t)((TmpDWord >> 24) + & 0xff); + NvmRefGoodSpadMap[1] = (uint8_t)((TmpDWord >> 16) + & 0xff); + NvmRefGoodSpadMap[2] = (uint8_t)((TmpDWord >> 8) + & 0xff); + NvmRefGoodSpadMap[3] = (uint8_t)(TmpDWord & 0xff); + + Status |= VL_WrByte(Dev, 0x94, 0x25); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + NvmRefGoodSpadMap[4] = (uint8_t)((TmpDWord >> 24) + & 0xff); + NvmRefGoodSpadMap[5] = (uint8_t)((TmpDWord >> 16) + & 0xff); + } + + if (((option & 2) == 2) && + ((ReadDataFromDeviceDone & 2) == 0)) { + + Status |= VL_WrByte(Dev, 0x94, 0x02); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdByte(Dev, 0x90, &ModuleId); + + Status |= VL_WrByte(Dev, 0x94, 0x7B); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdByte(Dev, 0x90, &Revision); + + Status |= VL_WrByte(Dev, 0x94, 0x77); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[0] = (char)((TmpDWord >> 25) & 0x07f); + ProductId[1] = (char)((TmpDWord >> 18) & 0x07f); + ProductId[2] = (char)((TmpDWord >> 11) & 0x07f); + ProductId[3] = (char)((TmpDWord >> 4) & 0x07f); + + byte = (uint8_t)((TmpDWord & 0x00f) << 3); + + Status |= VL_WrByte(Dev, 0x94, 0x78); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[4] = (char)(byte + + ((TmpDWord >> 29) & 0x07f)); + ProductId[5] = (char)((TmpDWord >> 22) & 0x07f); + ProductId[6] = (char)((TmpDWord >> 15) & 0x07f); + ProductId[7] = (char)((TmpDWord >> 8) & 0x07f); + ProductId[8] = (char)((TmpDWord >> 1) & 0x07f); + + byte = (uint8_t)((TmpDWord & 0x001) << 6); + + Status |= VL_WrByte(Dev, 0x94, 0x79); + + Status |= VL_device_read_strobe(Dev); + + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[9] = (char)(byte + + ((TmpDWord >> 26) & 0x07f)); + ProductId[10] = (char)((TmpDWord >> 19) & 0x07f); + ProductId[11] = (char)((TmpDWord >> 12) & 0x07f); + ProductId[12] = (char)((TmpDWord >> 5) & 0x07f); + + byte = (uint8_t)((TmpDWord & 0x01f) << 2); + + Status |= VL_WrByte(Dev, 0x94, 0x7A); + + Status |= VL_device_read_strobe(Dev); + + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + ProductId[13] = (char)(byte + + ((TmpDWord >> 30) & 0x07f)); + ProductId[14] = (char)((TmpDWord >> 23) & 0x07f); + ProductId[15] = (char)((TmpDWord >> 16) & 0x07f); + ProductId[16] = (char)((TmpDWord >> 9) & 0x07f); + ProductId[17] = (char)((TmpDWord >> 2) & 0x07f); + ProductId[18] = '\0'; + + } + + if (((option & 4) == 4) && + ((ReadDataFromDeviceDone & 4) == 0)) { + + Status |= VL_WrByte(Dev, 0x94, 0x7B); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &PartUIDUpper); + + Status |= VL_WrByte(Dev, 0x94, 0x7C); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &PartUIDLower); + + Status |= VL_WrByte(Dev, 0x94, 0x73); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + SignalRateMeasFixed1104_400_mm = (TmpDWord & + 0x0000000ff) << 8; + + Status |= VL_WrByte(Dev, 0x94, 0x74); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + SignalRateMeasFixed1104_400_mm |= ((TmpDWord & + 0xff000000) >> 24); + + Status |= VL_WrByte(Dev, 0x94, 0x75); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + DistMeasFixed1104_400_mm = (TmpDWord & 0x0000000ff) + << 8; + + Status |= VL_WrByte(Dev, 0x94, 0x76); + Status |= VL_device_read_strobe(Dev); + Status |= VL_RdDWord(Dev, 0x90, &TmpDWord); + + DistMeasFixed1104_400_mm |= ((TmpDWord & 0xff000000) + >> 24); + } + + Status |= VL_WrByte(Dev, 0x81, 0x00); + Status |= VL_WrByte(Dev, 0xFF, 0x06); + Status |= VL_RdByte(Dev, 0x83, &byte); + Status |= VL_WrByte(Dev, 0x83, byte&0xfb); + Status |= VL_WrByte(Dev, 0xFF, 0x01); + Status |= VL_WrByte(Dev, 0x00, 0x01); + + Status |= VL_WrByte(Dev, 0xFF, 0x00); + Status |= VL_WrByte(Dev, 0x80, 0x00); + } + + if ((Status == VL_ERROR_NONE) && + (ReadDataFromDeviceDone != 7)) { + /* Assign to variable if status is ok */ + if (((option & 1) == 1) && + ((ReadDataFromDeviceDone & 1) == 0)) { + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadCount, ReferenceSpadCount); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + ReferenceSpadType, ReferenceSpadType); + + for (i = 0; i < VL_REF_SPAD_BUFFER_SIZE; i++) { + Dev->Data.SpadData.RefGoodSpadMap[i] = + NvmRefGoodSpadMap[i]; + } + } + + if (((option & 2) == 2) && + ((ReadDataFromDeviceDone & 2) == 0)) { + VL_SETDEVICESPECIFICPARAMETER(Dev, + ModuleId, ModuleId); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + Revision, Revision); + + ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev, + ProductId); + VL_COPYSTRING(ProductId_tmp, ProductId); + + } + + if (((option & 4) == 4) && + ((ReadDataFromDeviceDone & 4) == 0)) { + VL_SETDEVICESPECIFICPARAMETER(Dev, + PartUIDUpper, PartUIDUpper); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + PartUIDLower, PartUIDLower); + + SignalRateMeasFixed400mmFix = + VL_FIXPOINT97TOFIXPOINT1616( + SignalRateMeasFixed1104_400_mm); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + SignalRateMeasFixed400mm, + SignalRateMeasFixed400mmFix); + + OffsetMicroMeters = 0; + if (DistMeasFixed1104_400_mm != 0) { + OffsetFixed1104_mm = DistMeasFixed1104_400_mm - + DistMeasTgtFixed1104_mm; + OffsetMicroMeters = (OffsetFixed1104_mm + * 1000) >> 4; + OffsetMicroMeters *= -1; + } + + PALDevDataSet(Dev, + Part2PartOffsetAdjustmentNVMMicroMeter, + OffsetMicroMeters); + } + byte = (uint8_t)(ReadDataFromDeviceDone|option); + VL_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone, + byte); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +uint32_t VL_calc_macro_period_ps(struct vl_data *Dev, + uint8_t vcsel_period_pclks) +{ + uint64_t PLL_period_ps; + uint32_t macro_period_vclks; + uint32_t macro_period_ps; + + LOG_FUNCTION_START(""); + + /* The above calculation will produce rounding errors, */ + /* therefore set fixed value */ + PLL_period_ps = 1655; + + macro_period_vclks = 2304; + macro_period_ps = (uint32_t)(macro_period_vclks + * vcsel_period_pclks * PLL_period_ps); + + LOG_FUNCTION_END(""); + return macro_period_ps; +} + +uint16_t VL_encode_timeout(uint32_t timeout_macro_clks) +{ + /*! + * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format + */ + + uint16_t encoded_timeout = 0; + uint32_t ls_byte = 0; + uint16_t ms_byte = 0; + + if (timeout_macro_clks > 0) { + ls_byte = timeout_macro_clks - 1; + + while ((ls_byte & 0xFFFFFF00) > 0) { + ls_byte = ls_byte >> 1; + ms_byte++; + } + + encoded_timeout = (ms_byte << 8) + + (uint16_t) (ls_byte & 0x000000FF); + } + + return encoded_timeout; + +} + +uint32_t VL_decode_timeout(uint16_t encoded_timeout) +{ + /*! + * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1 + */ + + uint32_t timeout_macro_clks = 0; + + timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF) + << (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1; + + return timeout_macro_clks; +} + + +/* To convert ms into register value */ +uint32_t VL_calc_timeout_mclks(struct vl_data *Dev, + uint32_t timeout_period_us, + uint8_t vcsel_period_pclks) +{ + uint32_t macro_period_ps; + uint32_t macro_period_ns; + uint32_t timeout_period_mclks = 0; + + macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks); + macro_period_ns = (macro_period_ps + 500) / 1000; + + timeout_period_mclks = + (uint32_t) (((timeout_period_us * 1000) + + (macro_period_ns / 2)) / macro_period_ns); + + return timeout_period_mclks; +} + +/* To convert register value into us */ +uint32_t VL_calc_timeout_us(struct vl_data *Dev, + uint16_t timeout_period_mclks, + uint8_t vcsel_period_pclks) +{ + uint32_t macro_period_ps; + uint32_t macro_period_ns; + uint32_t actual_timeout_period_us = 0; + + macro_period_ps = VL_calc_macro_period_ps(Dev, vcsel_period_pclks); + macro_period_ns = (macro_period_ps + 500) / 1000; + + actual_timeout_period_us = + ((timeout_period_mclks * macro_period_ns) + 500) / 1000; + + return actual_timeout_period_us; +} + + +int8_t get_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t *pTimeOutMicroSecs) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t CurrentVCSELPulsePeriodPClk; + uint8_t EncodedTimeOutByte = 0; + uint32_t TimeoutMicroSeconds = 0; + uint16_t PreRangeEncodedTimeOut = 0; + uint16_t MsrcTimeOutMClks; + uint16_t PreRangeTimeOutMClks; + uint16_t FinalRangeTimeOutMClks = 0; + uint16_t FinalRangeEncodedTimeOut; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + + if ((SequenceStepId == VL_SEQUENCESTEP_TCC) || + (SequenceStepId == VL_SEQUENCESTEP_DSS) || + (SequenceStepId == VL_SEQUENCESTEP_MSRC)) { + + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_MSRC_CONFIG_TIMEOUT_MACROP, + &EncodedTimeOutByte); + } + MsrcTimeOutMClks = VL_decode_timeout(EncodedTimeOutByte); + + TimeoutMicroSeconds = VL_calc_timeout_us(Dev, + MsrcTimeOutMClks, + CurrentVCSELPulsePeriodPClk); + } else if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) { + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + /* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */ + if (Status == VL_ERROR_NONE) { + + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, + VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, + &PreRangeEncodedTimeOut); + } + + PreRangeTimeOutMClks = VL_decode_timeout( + PreRangeEncodedTimeOut); + + TimeoutMicroSeconds = VL_calc_timeout_us(Dev, + PreRangeTimeOutMClks, + CurrentVCSELPulsePeriodPClk); + } + } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) { + + VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps); + PreRangeTimeOutMClks = 0; + + if (SchedulerSequenceSteps.PreRangeOn) { + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + /* Retrieve PRE-RANGE Timeout in Macro periods */ + /* (MCLKS) */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, + VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, + &PreRangeEncodedTimeOut); + PreRangeTimeOutMClks = VL_decode_timeout( + PreRangeEncodedTimeOut); + } + } + + if (Status == VL_ERROR_NONE) { + /* Retrieve FINAL-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_FINAL_RANGE, + &CurrentVCSELPulsePeriodPClk); + } + + /* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, + VL_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI, + &FinalRangeEncodedTimeOut); + FinalRangeTimeOutMClks = VL_decode_timeout( + FinalRangeEncodedTimeOut); + } + + FinalRangeTimeOutMClks -= PreRangeTimeOutMClks; + TimeoutMicroSeconds = VL_calc_timeout_us(Dev, + FinalRangeTimeOutMClks, + CurrentVCSELPulsePeriodPClk); + } + + *pTimeOutMicroSecs = TimeoutMicroSeconds; + + return Status; +} + + +int8_t set_sequence_step_timeout(struct vl_data *Dev, + uint8_t SequenceStepId, + uint32_t TimeOutMicroSecs) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t CurrentVCSELPulsePeriodPClk; + uint8_t MsrcEncodedTimeOut; + uint16_t PreRangeEncodedTimeOut; + uint16_t PreRangeTimeOutMClks; + uint16_t MsrcRangeTimeOutMClks; + uint32_t FinalRangeTimeOutMClks; + uint16_t FinalRangeEncodedTimeOut; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + + if ((SequenceStepId == VL_SEQUENCESTEP_TCC) || + (SequenceStepId == VL_SEQUENCESTEP_DSS) || + (SequenceStepId == VL_SEQUENCESTEP_MSRC)) { + + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + if (Status == VL_ERROR_NONE) { + MsrcRangeTimeOutMClks = VL_calc_timeout_mclks(Dev, + TimeOutMicroSecs, + (uint8_t)CurrentVCSELPulsePeriodPClk); + + if (MsrcRangeTimeOutMClks > 256) + MsrcEncodedTimeOut = 255; + else + MsrcEncodedTimeOut = + (uint8_t)MsrcRangeTimeOutMClks - 1; + + VL_SETDEVICESPECIFICPARAMETER(Dev, + LastEncodedTimeout, + MsrcEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_WrByte(Dev, + VL_REG_MSRC_CONFIG_TIMEOUT_MACROP, + MsrcEncodedTimeOut); + } + } else { + + if (SequenceStepId == VL_SEQUENCESTEP_PRE_RANGE) { + + if (Status == VL_ERROR_NONE) { + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + PreRangeTimeOutMClks = + VL_calc_timeout_mclks(Dev, + TimeOutMicroSecs, + (uint8_t)CurrentVCSELPulsePeriodPClk); + PreRangeEncodedTimeOut = VL_encode_timeout( + PreRangeTimeOutMClks); + + VL_SETDEVICESPECIFICPARAMETER(Dev, + LastEncodedTimeout, + PreRangeEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_WrWord(Dev, + VL_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI, + PreRangeEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + PreRangeTimeoutMicroSecs, + TimeOutMicroSecs); + } + } else if (SequenceStepId == VL_SEQUENCESTEP_FINAL_RANGE) { + + /* For the final range timeout, the pre-range timeout + * must be added. To do this both final and pre-range + * timeouts must be expressed in macro periods MClks + * because they have different vcsel periods. + */ + + VL_GetSequenceStepEnables(Dev, + &SchedulerSequenceSteps); + PreRangeTimeOutMClks = 0; + if (SchedulerSequenceSteps.PreRangeOn) { + + /* Retrieve PRE-RANGE VCSEL Period */ + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_PRE_RANGE, + &CurrentVCSELPulsePeriodPClk); + + /* Retrieve PRE-RANGE Timeout in Macro */ + /* periods (MCLKS) */ + if (Status == VL_ERROR_NONE) { + Status = VL_RdWord(Dev, 0x51, + &PreRangeEncodedTimeOut); + PreRangeTimeOutMClks = + VL_decode_timeout( + PreRangeEncodedTimeOut); + } + } + + /* Calculate FINAL RANGE Timeout in Macro Periods */ + /* (MCLKS) and add PRE-RANGE value */ + if (Status == VL_ERROR_NONE) { + + Status = VL_GetVcselPulsePeriod(Dev, + VL_VCSEL_PERIOD_FINAL_RANGE, + &CurrentVCSELPulsePeriodPClk); + } + if (Status == VL_ERROR_NONE) { + + FinalRangeTimeOutMClks = + VL_calc_timeout_mclks(Dev, + TimeOutMicroSecs, + (uint8_t) CurrentVCSELPulsePeriodPClk); + + FinalRangeTimeOutMClks += PreRangeTimeOutMClks; + + FinalRangeEncodedTimeOut = + VL_encode_timeout(FinalRangeTimeOutMClks); + + if (Status == VL_ERROR_NONE) { + Status = VL_WrWord(Dev, 0x71, + FinalRangeEncodedTimeOut); + } + + if (Status == VL_ERROR_NONE) { + VL_SETDEVICESPECIFICPARAMETER( + Dev, + FinalRangeTimeoutMicroSecs, + TimeOutMicroSecs); + } + } + } else + Status = VL_ERROR_INVALID_PARAMS; + + } + return Status; +} + +int8_t VL_set_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t VCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t vcsel_period_reg; + uint8_t MinPreVcselPeriodPCLK = 12; + uint8_t MaxPreVcselPeriodPCLK = 18; + uint8_t MinFinalVcselPeriodPCLK = 8; + uint8_t MaxFinalVcselPeriodPCLK = 14; + uint32_t MeasurementTimingBudgetMicroSeconds; + uint32_t FinalRangeTimeoutMicroSeconds; + uint32_t PreRangeTimeoutMicroSeconds; + uint32_t MsrcTimeoutMicroSeconds; + uint8_t PhaseCalInt = 0; + + /* Check if valid clock period requested */ + + if ((VCSELPulsePeriodPCLK % 2) != 0) { + /* Value must be an even number */ + Status = VL_ERROR_INVALID_PARAMS; + } else if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE && + (VCSELPulsePeriodPCLK < MinPreVcselPeriodPCLK || + VCSELPulsePeriodPCLK > MaxPreVcselPeriodPCLK)) { + Status = VL_ERROR_INVALID_PARAMS; + } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE && + (VCSELPulsePeriodPCLK < MinFinalVcselPeriodPCLK || + VCSELPulsePeriodPCLK > MaxFinalVcselPeriodPCLK)) { + + Status = VL_ERROR_INVALID_PARAMS; + } + + /* Apply specific settings for the requested clock period */ + + if (Status != VL_ERROR_NONE) + return Status; + + + if (VcselPeriodType == VL_VCSEL_PERIOD_PRE_RANGE) { + + /* Set phase check limits */ + if (VCSELPulsePeriodPCLK == 12) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x18); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } else if (VCSELPulsePeriodPCLK == 14) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x30); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } else if (VCSELPulsePeriodPCLK == 16) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x40); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } else if (VCSELPulsePeriodPCLK == 18) { + + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x50); + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + } + } else if (VcselPeriodType == VL_VCSEL_PERIOD_FINAL_RANGE) { + + if (VCSELPulsePeriodPCLK == 8) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x10); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x30); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } else if (VCSELPulsePeriodPCLK == 10) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x28); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x20); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } else if (VCSELPulsePeriodPCLK == 12) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x38); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x20); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } else if (VCSELPulsePeriodPCLK == 14) { + + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, + 0x048); + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW, + 0x08); + + Status |= VL_WrByte(Dev, + VL_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07); + + Status |= VL_WrByte(Dev, 0xff, 0x01); + Status |= VL_WrByte(Dev, + VL_REG_ALGO_PHASECAL_LIM, + 0x20); + Status |= VL_WrByte(Dev, 0xff, 0x00); + } + } + + + /* Re-calculate and apply timeouts, in macro periods */ + + if (Status == VL_ERROR_NONE) { + vcsel_period_reg = VL_encode_vcsel_period((uint8_t) + VCSELPulsePeriodPCLK); + + /* When the VCSEL period for the pre or final range is changed, */ + /* the corresponding timeout must be read from the device using */ + /* the current VCSEL period, then the new VCSEL period can be */ + /* applied. The timeout then must be written back to the device */ + /* using the new VCSEL period. */ + /* For the MSRC timeout, the same applies - this timeout being */ + /* dependent on the pre-range vcsel period. */ + switch (VcselPeriodType) { + case VL_VCSEL_PERIOD_PRE_RANGE: + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &PreRangeTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + &MsrcTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD, + vcsel_period_reg); + + + if (Status == VL_ERROR_NONE) + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + PreRangeTimeoutMicroSeconds); + + + if (Status == VL_ERROR_NONE) + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + MsrcTimeoutMicroSeconds); + + VL_SETDEVICESPECIFICPARAMETER( + Dev, + PreRangeVcselPulsePeriod, + VCSELPulsePeriodPCLK); + break; + case VL_VCSEL_PERIOD_FINAL_RANGE: + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + &FinalRangeTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD, + vcsel_period_reg); + + + if (Status == VL_ERROR_NONE) + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + FinalRangeTimeoutMicroSeconds); + + VL_SETDEVICESPECIFICPARAMETER( + Dev, + FinalRangeVcselPulsePeriod, + VCSELPulsePeriodPCLK); + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + } + + /* Finally, the timing budget must be re-applied */ + if (Status == VL_ERROR_NONE) { + VL_GETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + + Status = VL_SetMeasurementTimingBudgetMicroSeconds(Dev, + MeasurementTimingBudgetMicroSeconds); + } + + /* Perform the phase calibration. This is needed after changing on */ + /* vcsel period. */ + /* get_data_enable = 0, restore_config = 1 */ + if (Status == VL_ERROR_NONE) + Status = VL_perform_phase_calibration( + Dev, &PhaseCalInt, 0, 1); + + return Status; +} + +int8_t VL_get_vcsel_pulse_period(struct vl_data *Dev, + uint8_t VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t vcsel_period_reg; + + switch (VcselPeriodType) { + case VL_VCSEL_PERIOD_PRE_RANGE: + Status = VL_RdByte(Dev, + VL_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD, + &vcsel_period_reg); + break; + case VL_VCSEL_PERIOD_FINAL_RANGE: + Status = VL_RdByte(Dev, + VL_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD, + &vcsel_period_reg); + break; + default: + Status = VL_ERROR_INVALID_PARAMS; + } + + if (Status == VL_ERROR_NONE) + *pVCSELPulsePeriodPCLK = + VL_decode_vcsel_period(vcsel_period_reg); + + return Status; +} + + + +int8_t VL_set_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t MeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + uint32_t FinalRangeTimingBudgetMicroSeconds; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + uint32_t MsrcDccTccTimeoutMicroSeconds = 2000; + uint32_t StartOverheadMicroSeconds = 1910; + uint32_t EndOverheadMicroSeconds = 960; + uint32_t MsrcOverheadMicroSeconds = 660; + uint32_t TccOverheadMicroSeconds = 590; + uint32_t DssOverheadMicroSeconds = 690; + uint32_t PreRangeOverheadMicroSeconds = 660; + uint32_t FinalRangeOverheadMicroSeconds = 550; + uint32_t PreRangeTimeoutMicroSeconds = 0; + uint32_t cMinTimingBudgetMicroSeconds = 20000; + uint32_t SubTimeout = 0; + + LOG_FUNCTION_START(""); + + if (MeasurementTimingBudgetMicroSeconds + < cMinTimingBudgetMicroSeconds) { + Status = VL_ERROR_INVALID_PARAMS; + return Status; + } + + FinalRangeTimingBudgetMicroSeconds = + MeasurementTimingBudgetMicroSeconds - + (StartOverheadMicroSeconds + EndOverheadMicroSeconds); + + Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps); + + if (Status == VL_ERROR_NONE && + (SchedulerSequenceSteps.TccOn || + SchedulerSequenceSteps.MsrcOn || + SchedulerSequenceSteps.DssOn)) { + + /* TCC, MSRC and DSS all share the same timeout */ + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + &MsrcDccTccTimeoutMicroSeconds); + + /* Subtract the TCC, MSRC and DSS timeouts if they are */ + /* enabled. */ + + if (Status != VL_ERROR_NONE) + return Status; + + /* TCC */ + if (SchedulerSequenceSteps.TccOn) { + + SubTimeout = MsrcDccTccTimeoutMicroSeconds + + TccOverheadMicroSeconds; + + if (SubTimeout < + FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds -= + SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + /* DSS */ + if (SchedulerSequenceSteps.DssOn) { + + SubTimeout = 2 * (MsrcDccTccTimeoutMicroSeconds + + DssOverheadMicroSeconds); + + if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds + -= SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } else if (SchedulerSequenceSteps.MsrcOn) { + /* MSRC */ + SubTimeout = MsrcDccTccTimeoutMicroSeconds + + MsrcOverheadMicroSeconds; + + if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds + -= SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } + + } + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + if (SchedulerSequenceSteps.PreRangeOn) { + + /* Subtract the Pre-range timeout if enabled. */ + + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &PreRangeTimeoutMicroSeconds); + + SubTimeout = PreRangeTimeoutMicroSeconds + + PreRangeOverheadMicroSeconds; + + if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) { + FinalRangeTimingBudgetMicroSeconds -= SubTimeout; + } else { + /* Requested timeout too big. */ + Status = VL_ERROR_INVALID_PARAMS; + } + } + + + if (Status == VL_ERROR_NONE && + SchedulerSequenceSteps.FinalRangeOn) { + + FinalRangeTimingBudgetMicroSeconds -= + FinalRangeOverheadMicroSeconds; + + /* Final Range Timeout + * Note that the final range timeout is determined by the timing + * budget and the sum of all other timeouts within the sequence. + * If there is no room for the final range timeout,then an error + * will be set. Otherwise the remaining time will be applied to + * the final range. + */ + Status = set_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + FinalRangeTimingBudgetMicroSeconds); + + VL_SETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + MeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + + return Status; +} + +int8_t VL_get_measurement_timing_budget_micro_seconds( + struct vl_data *Dev, uint32_t *pMeasurementTimingBudgetMicroSeconds) +{ + int8_t Status = VL_ERROR_NONE; + struct VL_SchedulerSequenceSteps_t SchedulerSequenceSteps; + uint32_t FinalRangeTimeoutMicroSeconds; + uint32_t MsrcDccTccTimeoutMicroSeconds = 2000; + uint32_t StartOverheadMicroSeconds = 1910; + uint32_t EndOverheadMicroSeconds = 960; + uint32_t MsrcOverheadMicroSeconds = 660; + uint32_t TccOverheadMicroSeconds = 590; + uint32_t DssOverheadMicroSeconds = 690; + uint32_t PreRangeOverheadMicroSeconds = 660; + uint32_t FinalRangeOverheadMicroSeconds = 550; + uint32_t PreRangeTimeoutMicroSeconds = 0; + + LOG_FUNCTION_START(""); + + /* Start and end overhead times always present */ + *pMeasurementTimingBudgetMicroSeconds + = StartOverheadMicroSeconds + EndOverheadMicroSeconds; + + Status = VL_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps); + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + + if (SchedulerSequenceSteps.TccOn || + SchedulerSequenceSteps.MsrcOn || + SchedulerSequenceSteps.DssOn) { + + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_MSRC, + &MsrcDccTccTimeoutMicroSeconds); + + if (Status == VL_ERROR_NONE) { + if (SchedulerSequenceSteps.TccOn) { + *pMeasurementTimingBudgetMicroSeconds += + MsrcDccTccTimeoutMicroSeconds + + TccOverheadMicroSeconds; + } + + if (SchedulerSequenceSteps.DssOn) { + *pMeasurementTimingBudgetMicroSeconds += + 2 * (MsrcDccTccTimeoutMicroSeconds + + DssOverheadMicroSeconds); + } else if (SchedulerSequenceSteps.MsrcOn) { + *pMeasurementTimingBudgetMicroSeconds += + MsrcDccTccTimeoutMicroSeconds + + MsrcOverheadMicroSeconds; + } + } + } + + if (Status == VL_ERROR_NONE) { + if (SchedulerSequenceSteps.PreRangeOn) { + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_PRE_RANGE, + &PreRangeTimeoutMicroSeconds); + *pMeasurementTimingBudgetMicroSeconds += + PreRangeTimeoutMicroSeconds + + PreRangeOverheadMicroSeconds; + } + } + + if (Status == VL_ERROR_NONE) { + if (SchedulerSequenceSteps.FinalRangeOn) { + Status = get_sequence_step_timeout(Dev, + VL_SEQUENCESTEP_FINAL_RANGE, + &FinalRangeTimeoutMicroSeconds); + *pMeasurementTimingBudgetMicroSeconds += + (FinalRangeTimeoutMicroSeconds + + FinalRangeOverheadMicroSeconds); + } + } + + if (Status == VL_ERROR_NONE) { + VL_SETPARAMETERFIELD(Dev, + MeasurementTimingBudgetMicroSeconds, + *pMeasurementTimingBudgetMicroSeconds); + } + + LOG_FUNCTION_END(Status); + return Status; +} + + + +int8_t VL_load_tuning_settings(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer) +{ + int8_t Status = VL_ERROR_NONE; + int i; + int Index; + uint8_t msb; + uint8_t lsb; + uint8_t SelectParam; + uint8_t NumberOfWrites; + uint8_t Address; + uint8_t localBuffer[4]; /* max */ + uint16_t Temp16; + + LOG_FUNCTION_START(""); + + Index = 0; + + while ((*(pTuningSettingBuffer + Index) != 0) && + (Status == VL_ERROR_NONE)) { + NumberOfWrites = *(pTuningSettingBuffer + Index); + Index++; + if (NumberOfWrites == 0xFF) { + /* internal parameters */ + SelectParam = *(pTuningSettingBuffer + Index); + Index++; + switch (SelectParam) { + case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, SigmaEstRefArray, Temp16); + break; + case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, SigmaEstEffPulseWidth, + Temp16); + break; + case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, SigmaEstEffAmbWidth, Temp16); + break; + case 3: /* uint16_t targetRefRate -> 2 bytes */ + msb = *(pTuningSettingBuffer + Index); + Index++; + lsb = *(pTuningSettingBuffer + Index); + Index++; + Temp16 = VL_MAKEUINT16(lsb, msb); + PALDevDataSet(Dev, targetRefRate, Temp16); + break; + default: /* invalid parameter */ + Status = VL_ERROR_INVALID_PARAMS; + } + + } else if (NumberOfWrites <= 4) { + Address = *(pTuningSettingBuffer + Index); + Index++; + + for (i = 0; i < NumberOfWrites; i++) { + localBuffer[i] = *(pTuningSettingBuffer + + Index); + Index++; + } + + Status = VL_WriteMulti(Dev, Address, localBuffer, + NumberOfWrites); + + } else { + Status = VL_ERROR_INVALID_PARAMS; + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_total_xtalk_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_xtalk_rate_mcps) +{ + int8_t Status = VL_ERROR_NONE; + + uint8_t xtalkCompEnable; + unsigned int totalXtalkMegaCps; + unsigned int xtalkPerSpadMegaCps; + + *ptotal_xtalk_rate_mcps = 0; + + Status = VL_GetXTalkCompensationEnable(Dev, &xtalkCompEnable); + if (Status == VL_ERROR_NONE) { + + if (xtalkCompEnable) { + + VL_GETPARAMETERFIELD( + Dev, + XTalkCompensationRateMegaCps, + xtalkPerSpadMegaCps); + + /* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */ + totalXtalkMegaCps = + pRangingMeasurementData->EffectiveSpadRtnCount * + xtalkPerSpadMegaCps; + + /* FixPoint0824 >> 8 = FixPoint1616 */ + *ptotal_xtalk_rate_mcps = + (totalXtalkMegaCps + 0x80) >> 8; + } + } + + return Status; +} + +int8_t VL_get_total_signal_rate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *ptotal_signal_rate_mcps) +{ + int8_t Status = VL_ERROR_NONE; + unsigned int totalXtalkMegaCps; + + LOG_FUNCTION_START(""); + + *ptotal_signal_rate_mcps = + pRangingMeasurementData->SignalRateRtnMegaCps; + + Status = VL_get_total_xtalk_rate( + Dev, pRangingMeasurementData, &totalXtalkMegaCps); + + if (Status == VL_ERROR_NONE) + *ptotal_signal_rate_mcps += totalXtalkMegaCps; + + return Status; +} + +int8_t VL_calc_dmax( + struct vl_data *Dev, + unsigned int totalSignalRate_mcps, + unsigned int totalCorrSignalRate_mcps, + unsigned int pwMult, + uint32_t sigmaEstimateP1, + unsigned int sigmaEstimateP2, + uint32_t peakVcselDuration_us, + uint32_t *pdmax_mm) +{ + const uint32_t cSigmaLimit = 18; + const unsigned int cSignalLimit = 0x4000; /* 0.25 */ + const unsigned int cSigmaEstRef = 0x00000042; /* 0.001 */ + const uint32_t cAmbEffWidthSigmaEst_ns = 6; + const uint32_t cAmbEffWidthDMax_ns = 7; + uint32_t dmaxCalRange_mm; + unsigned int dmaxCalSignalRateRtn_mcps; + unsigned int minSignalNeeded; + unsigned int minSignalNeeded_p1; + unsigned int minSignalNeeded_p2; + unsigned int minSignalNeeded_p3; + unsigned int minSignalNeeded_p4; + unsigned int sigmaLimitTmp; + unsigned int sigmaEstSqTmp; + unsigned int signalLimitTmp; + unsigned int SignalAt0mm; + unsigned int dmaxDark; + unsigned int dmaxAmbient; + unsigned int dmaxDarkTmp; + unsigned int sigmaEstP2Tmp; + uint32_t signalRateTemp_mcps; + + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + dmaxCalRange_mm = + PALDevDataGet(Dev, DmaxCalRangeMilliMeter); + + dmaxCalSignalRateRtn_mcps = + PALDevDataGet(Dev, DmaxCalSignalRateRtnMegaCps); + + /* uint32 * FixPoint1616 = FixPoint1616 */ + SignalAt0mm = dmaxCalRange_mm * dmaxCalSignalRateRtn_mcps; + + /* FixPoint1616 >> 8 = FixPoint2408 */ + SignalAt0mm = (SignalAt0mm + 0x80) >> 8; + SignalAt0mm *= dmaxCalRange_mm; + + minSignalNeeded_p1 = 0; + if (totalCorrSignalRate_mcps > 0) { + + /* Shift by 10 bits to increase resolution prior to the */ + /* division */ + signalRateTemp_mcps = totalSignalRate_mcps << 10; + + /* Add rounding value prior to division */ + minSignalNeeded_p1 = signalRateTemp_mcps + + (totalCorrSignalRate_mcps/2); + + /* FixPoint0626/FixPoint1616 = FixPoint2210 */ + minSignalNeeded_p1 /= totalCorrSignalRate_mcps; + + /* Apply a factored version of the speed of light. */ + /* Correction to be applied at the end */ + minSignalNeeded_p1 *= 3; + + /* FixPoint2210 * FixPoint2210 = FixPoint1220 */ + minSignalNeeded_p1 *= minSignalNeeded_p1; + + /* FixPoint1220 >> 16 = FixPoint2804 */ + minSignalNeeded_p1 = (minSignalNeeded_p1 + 0x8000) >> 16; + } + + minSignalNeeded_p2 = pwMult * sigmaEstimateP1; + + /* FixPoint1616 >> 16 = uint32 */ + minSignalNeeded_p2 = (minSignalNeeded_p2 + 0x8000) >> 16; + + /* uint32 * uint32 = uint32 */ + minSignalNeeded_p2 *= minSignalNeeded_p2; + + /* Check sigmaEstimateP2 + * If this value is too high there is not enough signal rate + * to calculate dmax value so set a suitable value to ensure + * a very small dmax. + */ + sigmaEstP2Tmp = (sigmaEstimateP2 + 0x8000) >> 16; + sigmaEstP2Tmp = (sigmaEstP2Tmp + cAmbEffWidthSigmaEst_ns/2)/ + cAmbEffWidthSigmaEst_ns; + sigmaEstP2Tmp *= cAmbEffWidthDMax_ns; + + if (sigmaEstP2Tmp > 0xffff) { + minSignalNeeded_p3 = 0xfff00000; + } else { + + /* DMAX uses a different ambient width from sigma, so apply + * correction. + * Perform division before multiplication to prevent overflow. + */ + sigmaEstimateP2 = (sigmaEstimateP2 + cAmbEffWidthSigmaEst_ns/2)/ + cAmbEffWidthSigmaEst_ns; + sigmaEstimateP2 *= cAmbEffWidthDMax_ns; + + /* FixPoint1616 >> 16 = uint32 */ + minSignalNeeded_p3 = (sigmaEstimateP2 + 0x8000) >> 16; + + minSignalNeeded_p3 *= minSignalNeeded_p3; + + } + + /* FixPoint1814 / uint32 = FixPoint1814 */ + sigmaLimitTmp = ((cSigmaLimit << 14) + 500) / 1000; + + /* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */ + sigmaLimitTmp *= sigmaLimitTmp; + + /* FixPoint1616 * FixPoint1616 = FixPoint3232 */ + sigmaEstSqTmp = cSigmaEstRef * cSigmaEstRef; + + /* FixPoint3232 >> 4 = FixPoint0428 */ + sigmaEstSqTmp = (sigmaEstSqTmp + 0x08) >> 4; + + /* FixPoint0428 - FixPoint0428 = FixPoint0428 */ + sigmaLimitTmp -= sigmaEstSqTmp; + + /* uint32_t * FixPoint0428 = FixPoint0428 */ + minSignalNeeded_p4 = 4 * 12 * sigmaLimitTmp; + + /* FixPoint0428 >> 14 = FixPoint1814 */ + minSignalNeeded_p4 = (minSignalNeeded_p4 + 0x2000) >> 14; + + /* uint32 + uint32 = uint32 */ + minSignalNeeded = (minSignalNeeded_p2 + minSignalNeeded_p3); + + /* uint32 / uint32 = uint32 */ + minSignalNeeded += (peakVcselDuration_us/2); + minSignalNeeded /= peakVcselDuration_us; + + /* uint32 << 14 = FixPoint1814 */ + minSignalNeeded <<= 14; + + /* FixPoint1814 / FixPoint1814 = uint32 */ + minSignalNeeded += (minSignalNeeded_p4/2); + minSignalNeeded /= minSignalNeeded_p4; + + /* FixPoint3200 * FixPoint2804 := FixPoint2804*/ + minSignalNeeded *= minSignalNeeded_p1; + + /* Apply correction by dividing by 1000000. + * This assumes 10E16 on the numerator of the equation + * and 10E-22 on the denominator. + * We do this because 32bit fix point calculation can't + * handle the larger and smaller elements of this equation, + * i.e. speed of light and pulse widths. + */ + minSignalNeeded = (minSignalNeeded + 500) / 1000; + minSignalNeeded <<= 4; + + minSignalNeeded = (minSignalNeeded + 500) / 1000; + + /* FixPoint1616 >> 8 = FixPoint2408 */ + signalLimitTmp = (cSignalLimit + 0x80) >> 8; + + /* FixPoint2408/FixPoint2408 = uint32 */ + if (signalLimitTmp != 0) + dmaxDarkTmp = (SignalAt0mm + (signalLimitTmp / 2)) + / signalLimitTmp; + else + dmaxDarkTmp = 0; + + dmaxDark = VL_isqrt(dmaxDarkTmp); + + /* FixPoint2408/FixPoint2408 = uint32 */ + if (minSignalNeeded != 0) + dmaxAmbient = (SignalAt0mm + minSignalNeeded/2) + / minSignalNeeded; + else + dmaxAmbient = 0; + + dmaxAmbient = VL_isqrt(dmaxAmbient); + + *pdmax_mm = dmaxDark; + if (dmaxDark > dmaxAmbient) + *pdmax_mm = dmaxAmbient; + + LOG_FUNCTION_END(Status); + + return Status; +} + + +int8_t VL_calc_sigma_estimate(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + unsigned int *pSigmaEstimate, + uint32_t *pDmax_mm) +{ + /* Expressed in 100ths of a ns, i.e. centi-ns */ + const uint32_t cPulseEffectiveWidth_centi_ns = 800; + /* Expressed in 100ths of a ns, i.e. centi-ns */ + const uint32_t cAmbientEffectiveWidth_centi_ns = 600; + /* 25ms */ + const unsigned int cDfltFinalRangeIntegrationTimeMilliSecs = + 0x00190000; + const uint32_t cVcselPulseWidth_ps = 4700; /* pico secs */ + const unsigned int cSigmaEstMax = 0x028F87AE; + const unsigned int cSigmaEstRtnMax = 0xF000; + const unsigned int cAmbToSignalRatioMax = 0xF0000000/ + cAmbientEffectiveWidth_centi_ns; + /* Time Of Flight per mm (6.6 pico secs) */ + const unsigned int cTOF_per_mm_ps = 0x0006999A; + const uint32_t c16BitRoundingParam = 0x00008000; + const unsigned int cMaxXTalk_kcps = 0x00320000; + const uint32_t cPllPeriod_ps = 1655; + + uint32_t vcselTotalEventsRtn; + uint32_t finalRangeTimeoutMicroSecs; + uint32_t preRangeTimeoutMicroSecs; + uint32_t finalRangeIntegrationTimeMilliSecs; + unsigned int sigmaEstimateP1; + unsigned int sigmaEstimateP2; + unsigned int sigmaEstimateP3; + unsigned int deltaT_ps; + unsigned int pwMult; + unsigned int sigmaEstRtn; + unsigned int sigmaEstimate; + unsigned int xTalkCorrection; + unsigned int ambientRate_kcps; + unsigned int peakSignalRate_kcps; + unsigned int xTalkCompRate_mcps; + uint32_t xTalkCompRate_kcps; + int8_t Status = VL_ERROR_NONE; + unsigned int diff1_mcps; + unsigned int diff2_mcps; + unsigned int sqr1; + unsigned int sqr2; + unsigned int sqrSum; + unsigned int sqrtResult_centi_ns; + unsigned int sqrtResult; + unsigned int totalSignalRate_mcps; + unsigned int correctedSignalRate_mcps; + unsigned int sigmaEstRef; + uint32_t vcselWidth; + uint32_t finalRangeMacroPCLKS; + uint32_t preRangeMacroPCLKS; + uint32_t peakVcselDuration_us; + uint8_t finalRangeVcselPCLKS; + uint8_t preRangeVcselPCLKS; + /*! \addtogroup calc_sigma_estimate + * @{ + * + * Estimates the range sigma + */ + + LOG_FUNCTION_START(""); + + VL_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps, + xTalkCompRate_mcps); + + /* + * We work in kcps rather than mcps as this helps keep within the + * confines of the 32 Fix1616 type. + */ + + ambientRate_kcps = + (pRangingMeasurementData->AmbientRateRtnMegaCps * 1000) >> 16; + + correctedSignalRate_mcps = + pRangingMeasurementData->SignalRateRtnMegaCps; + + + Status = VL_get_total_signal_rate( + Dev, pRangingMeasurementData, &totalSignalRate_mcps); + Status = VL_get_total_xtalk_rate( + Dev, pRangingMeasurementData, &xTalkCompRate_mcps); + + + /* Signal rate measurement provided by device is the + * peak signal rate, not average. + */ + peakSignalRate_kcps = (totalSignalRate_mcps * 1000); + peakSignalRate_kcps = (peakSignalRate_kcps + 0x8000) >> 16; + + xTalkCompRate_kcps = xTalkCompRate_mcps * 1000; + + if (xTalkCompRate_kcps > cMaxXTalk_kcps) + xTalkCompRate_kcps = cMaxXTalk_kcps; + + if (Status == VL_ERROR_NONE) { + + /* Calculate final range macro periods */ + finalRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER( + Dev, FinalRangeTimeoutMicroSecs); + + finalRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER( + Dev, FinalRangeVcselPulsePeriod); + + finalRangeMacroPCLKS = VL_calc_timeout_mclks( + Dev, finalRangeTimeoutMicroSecs, finalRangeVcselPCLKS); + + /* Calculate pre-range macro periods */ + preRangeTimeoutMicroSecs = VL_GETDEVICESPECIFICPARAMETER( + Dev, PreRangeTimeoutMicroSecs); + + preRangeVcselPCLKS = VL_GETDEVICESPECIFICPARAMETER( + Dev, PreRangeVcselPulsePeriod); + + preRangeMacroPCLKS = VL_calc_timeout_mclks( + Dev, preRangeTimeoutMicroSecs, preRangeVcselPCLKS); + + vcselWidth = 3; + if (finalRangeVcselPCLKS == 8) + vcselWidth = 2; + + + peakVcselDuration_us = vcselWidth * 2048 * + (preRangeMacroPCLKS + finalRangeMacroPCLKS); + peakVcselDuration_us = (peakVcselDuration_us + 500)/1000; + peakVcselDuration_us *= cPllPeriod_ps; + peakVcselDuration_us = (peakVcselDuration_us + 500)/1000; + + /* Fix1616 >> 8 = Fix2408 */ + totalSignalRate_mcps = (totalSignalRate_mcps + 0x80) >> 8; + + /* Fix2408 * uint32 = Fix2408 */ + vcselTotalEventsRtn = totalSignalRate_mcps * + peakVcselDuration_us; + + /* Fix2408 >> 8 = uint32 */ + vcselTotalEventsRtn = (vcselTotalEventsRtn + 0x80) >> 8; + + /* Fix2408 << 8 = Fix1616 = */ + totalSignalRate_mcps <<= 8; + } + + if (Status != VL_ERROR_NONE) { + LOG_FUNCTION_END(Status); + return Status; + } + + if (peakSignalRate_kcps == 0) { + *pSigmaEstimate = cSigmaEstMax; + PALDevDataSet(Dev, SigmaEstimate, cSigmaEstMax); + *pDmax_mm = 0; + } else { + if (vcselTotalEventsRtn < 1) + vcselTotalEventsRtn = 1; + + sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns; + + /* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */ + sigmaEstimateP2 = (ambientRate_kcps << 16)/peakSignalRate_kcps; + if (sigmaEstimateP2 > cAmbToSignalRatioMax) { + /* Clip to prevent overflow. Will ensure safe */ + /* max result. */ + sigmaEstimateP2 = cAmbToSignalRatioMax; + } + sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns; + + sigmaEstimateP3 = 2 * VL_isqrt(vcselTotalEventsRtn * 12); + + /* uint32 * FixPoint1616 = FixPoint1616 */ + deltaT_ps = pRangingMeasurementData->RangeMilliMeter * + cTOF_per_mm_ps; + + /* vcselRate - xtalkCompRate */ + /* (uint32 << 16) - FixPoint1616 = FixPoint1616. */ + /* Divide result by 1000 to convert to mcps. */ + /* 500 is added to ensure rounding when integer division */ + /* truncates. */ + diff1_mcps = (((peakSignalRate_kcps << 16) - + 2 * xTalkCompRate_kcps) + 500)/1000; + + /* vcselRate + xtalkCompRate */ + diff2_mcps = ((peakSignalRate_kcps << 16) + 500)/1000; + + /* Shift by 8 bits to increase resolution prior to the */ + /* division */ + diff1_mcps <<= 8; + + /* FixPoint0824/FixPoint1616 = FixPoint2408 */ + xTalkCorrection = abs(diff1_mcps/diff2_mcps); + + /* FixPoint2408 << 8 = FixPoint1616 */ + xTalkCorrection <<= 8; + + if (pRangingMeasurementData->RangeStatus != 0) { + pwMult = 1 << 16; + } else { + /* FixPoint1616/uint32 = FixPoint1616 *i */ + /* smaller than 1.0f */ + pwMult = deltaT_ps/cVcselPulseWidth_ps; + + /* FixPoint1616 * FixPoint1616 = FixPoint3232, however both */ + /* values are small enough such that32 bits will not be */ + /* exceeded. */ + pwMult *= ((1 << 16) - xTalkCorrection); + + /* (FixPoint3232 >> 16) = FixPoint1616 */ + pwMult = (pwMult + c16BitRoundingParam) >> 16; + + /* FixPoint1616 + FixPoint1616 = FixPoint1616 */ + pwMult += (1 << 16); + + /* At this point the value will be 1.xx, */ + /* therefore if we square */ + /* the value this will exceed 32 bits. */ + /* To address this perform */ + /* a single shift to the right before the multiplication. */ + pwMult >>= 1; + /* FixPoint1715 * FixPoint1715 = FixPoint3430 */ + pwMult = pwMult * pwMult; + + /* (FixPoint3430 >> 14) = Fix1616 */ + pwMult >>= 14; + } + + /* FixPoint1616 * uint32 = FixPoint1616 */ + sqr1 = pwMult * sigmaEstimateP1; + + /* (FixPoint1616 >> 16) = FixPoint3200 */ + sqr1 = (sqr1 + 0x8000) >> 16; + + /* FixPoint3200 * FixPoint3200 = FixPoint6400 */ + sqr1 *= sqr1; + + sqr2 = sigmaEstimateP2; + + /* (FixPoint1616 >> 16) = FixPoint3200 */ + sqr2 = (sqr2 + 0x8000) >> 16; + + /* FixPoint3200 * FixPoint3200 = FixPoint6400 */ + sqr2 *= sqr2; + + /* FixPoint64000 + FixPoint6400 = FixPoint6400 */ + sqrSum = sqr1 + sqr2; + + /* SQRT(FixPoin6400) = FixPoint3200 */ + sqrtResult_centi_ns = VL_isqrt(sqrSum); + + /* (FixPoint3200 << 16) = FixPoint1616 */ + sqrtResult_centi_ns <<= 16; + + /* + * Note that the Speed Of Light is expressed in um per 1E-10 + * seconds (2997) Therefore to get mm/ns we have to divide by + * 10000 + */ + sigmaEstRtn = (((sqrtResult_centi_ns+50)/100) / + sigmaEstimateP3); + sigmaEstRtn *= VL_SPEED_OF_LIGHT_IN_AIR; + + /* Add 5000 before dividing by 10000 to ensure rounding. */ + sigmaEstRtn += 5000; + sigmaEstRtn /= 10000; + + if (sigmaEstRtn > cSigmaEstRtnMax) { + /* Clip to prevent overflow. Will ensure safe */ + /* max result. */ + sigmaEstRtn = cSigmaEstRtnMax; + } + finalRangeIntegrationTimeMilliSecs = + (finalRangeTimeoutMicroSecs + + preRangeTimeoutMicroSecs + 500)/1000; + + /* sigmaEstRef = 1mm * 25ms/final range integration time */ + /* (inc pre-range) sqrt(FixPoint1616/int) = FixPoint2408) */ + sigmaEstRef = + VL_isqrt((cDfltFinalRangeIntegrationTimeMilliSecs + + finalRangeIntegrationTimeMilliSecs/2)/ + finalRangeIntegrationTimeMilliSecs); + + /* FixPoint2408 << 8 = FixPoint1616 */ + sigmaEstRef <<= 8; + sigmaEstRef = (sigmaEstRef + 500)/1000; + + /* FixPoint1616 * FixPoint1616 = FixPoint3232 */ + sqr1 = sigmaEstRtn * sigmaEstRtn; + /* FixPoint1616 * FixPoint1616 = FixPoint3232 */ + sqr2 = sigmaEstRef * sigmaEstRef; + + /* sqrt(FixPoint3232) = FixPoint1616 */ + sqrtResult = VL_isqrt((sqr1 + sqr2)); + /* Note that the Shift by 4 bits increases */ + /*resolution prior to */ + /* the sqrt, therefore the result must be */ + /* shifted by 2 bits to */ + /* the right to revert back to the FixPoint1616 format. */ + + sigmaEstimate = 1000 * sqrtResult; + + if ((peakSignalRate_kcps < 1) || (vcselTotalEventsRtn < 1) || + (sigmaEstimate > cSigmaEstMax)) { + sigmaEstimate = cSigmaEstMax; + } + + *pSigmaEstimate = (uint32_t)(sigmaEstimate); + PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate); + Status = VL_calc_dmax( + Dev, + totalSignalRate_mcps, + correctedSignalRate_mcps, + pwMult, + sigmaEstimateP1, + sigmaEstimateP2, + peakVcselDuration_us, + pDmax_mm); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_pal_range_status(struct vl_data *Dev, + uint8_t DeviceRangeStatus, + unsigned int SignalRate, + uint16_t EffectiveSpadRtnCount, + struct VL_RangingMeasurementData_t *pRangingMeasurementData, + uint8_t *pPalRangeStatus) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t NoneFlag; + uint8_t SigmaLimitflag = 0; + uint8_t SignalRefClipflag = 0; + uint8_t RangeIgnoreThresholdflag = 0; + uint8_t SigmaLimitCheckEnable = 0; + uint8_t SignalRateFinalRangeLimitCheckEnable = 0; + uint8_t SignalRefClipLimitCheckEnable = 0; + uint8_t RangeIgnoreThresholdLimitCheckEnable = 0; + unsigned int SigmaEstimate; + unsigned int SigmaLimitValue; + unsigned int SignalRefClipValue; + unsigned int RangeIgnoreThresholdValue; + unsigned int SignalRatePerSpad; + uint8_t DeviceRangeStatusInternal = 0; + uint16_t tmpWord = 0; + uint8_t Temp8; + uint32_t Dmax_mm = 0; + unsigned int LastSignalRefMcps; + + LOG_FUNCTION_START(""); + + + /* + * VL53L0X has a good ranging when the value of the + * DeviceRangeStatus = 11. This function will replace the value 0 with + * the value 11 in the DeviceRangeStatus. + * In addition, the SigmaEstimator is not included in the VL53L0X + * DeviceRangeStatus, this will be added in the PalRangeStatus. + */ + + DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3); + + if (DeviceRangeStatusInternal == 0 || + DeviceRangeStatusInternal == 5 || + DeviceRangeStatusInternal == 7 || + DeviceRangeStatusInternal == 12 || + DeviceRangeStatusInternal == 13 || + DeviceRangeStatusInternal == 14 || + DeviceRangeStatusInternal == 15 + ) { + NoneFlag = 1; + } else { + NoneFlag = 0; + } + + /* + * Check if Sigma limit is enabled, if yes then do comparison with limit + * value and put the result back into pPalRangeStatus. + */ + if (Status == VL_ERROR_NONE) + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + &SigmaLimitCheckEnable); + + if ((SigmaLimitCheckEnable != 0) && (Status == VL_ERROR_NONE)) { + /* compute the Sigma and check with limit */ + Status = VL_calc_sigma_estimate( + Dev, + pRangingMeasurementData, + &SigmaEstimate, + &Dmax_mm); + if (Status == VL_ERROR_NONE) + pRangingMeasurementData->RangeDMaxMilliMeter = Dmax_mm; + + if (Status == VL_ERROR_NONE) { + Status = VL_GetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + &SigmaLimitValue); + + if ((SigmaLimitValue > 0) && + (SigmaEstimate > SigmaLimitValue)) + /* Limit Fail */ + SigmaLimitflag = 1; + } + } + + /* Check if Signal ref clip limit is enabled, */ + /* if yes then do comparison */ + /* with limit value and put the result back into pPalRangeStatus. */ + if (Status == VL_ERROR_NONE) + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + &SignalRefClipLimitCheckEnable); + + if ((SignalRefClipLimitCheckEnable != 0) && + (Status == VL_ERROR_NONE)) { + + Status = VL_GetLimitCheckValue(Dev, + VL_CHECKENABLE_SIGNAL_REF_CLIP, + &SignalRefClipValue); + + /* Read LastSignalRefMcps from device */ + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x01); + + if (Status == VL_ERROR_NONE) + Status = VL_RdWord(Dev, + VL_REG_RESULT_PEAK_SIGNAL_RATE_REF, + &tmpWord); + + if (Status == VL_ERROR_NONE) + Status = VL_WrByte(Dev, 0xFF, 0x00); + + LastSignalRefMcps = VL_FIXPOINT97TOFIXPOINT1616(tmpWord); + PALDevDataSet(Dev, LastSignalRefMcps, LastSignalRefMcps); + + if ((SignalRefClipValue > 0) && + (LastSignalRefMcps > SignalRefClipValue)) { + /* Limit Fail */ + SignalRefClipflag = 1; + } + } + + /* + * Check if Signal ref clip limit is enabled, if yes then do comparison + * with limit value and put the result back into pPalRangeStatus. + * EffectiveSpadRtnCount has a format 8.8 + * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL + */ + if (Status == VL_ERROR_NONE) + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + &RangeIgnoreThresholdLimitCheckEnable); + + if ((RangeIgnoreThresholdLimitCheckEnable != 0) && + (Status == VL_ERROR_NONE)) { + + /* Compute the signal rate per spad */ + if (EffectiveSpadRtnCount == 0) { + SignalRatePerSpad = 0; + } else { + SignalRatePerSpad = (unsigned int)((256 * SignalRate) + / EffectiveSpadRtnCount); + } + + Status = VL_GetLimitCheckValue(Dev, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + &RangeIgnoreThresholdValue); + + if ((RangeIgnoreThresholdValue > 0) && + (SignalRatePerSpad < RangeIgnoreThresholdValue)) { + /* Limit Fail add 2^6 to range status */ + RangeIgnoreThresholdflag = 1; + } + } + + if (Status == VL_ERROR_NONE) { + if (NoneFlag == 1) { + *pPalRangeStatus = 255; /* NONE */ + } else if (DeviceRangeStatusInternal == 1 || + DeviceRangeStatusInternal == 2 || + DeviceRangeStatusInternal == 3) { + *pPalRangeStatus = 5; /* HW fail */ + } else if (DeviceRangeStatusInternal == 6 || + DeviceRangeStatusInternal == 9) { + *pPalRangeStatus = 4; /* Phase fail */ + } else if (DeviceRangeStatusInternal == 8 || + DeviceRangeStatusInternal == 10 || + SignalRefClipflag == 1) { + *pPalRangeStatus = 3; /* Min range */ + } else if (DeviceRangeStatusInternal == 4 || + RangeIgnoreThresholdflag == 1) { + *pPalRangeStatus = 2; /* Signal Fail */ + } else if (SigmaLimitflag == 1) { + *pPalRangeStatus = 1; /* Sigma Fail */ + } else { + *pPalRangeStatus = 0; /* Range Valid */ + } + } + + /* DMAX only relevant during range error */ + if (*pPalRangeStatus == 0) + pRangingMeasurementData->RangeDMaxMilliMeter = 0; + + /* fill the Limit Check Status */ + + Status = VL_GetLimitCheckEnable(Dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + &SignalRateFinalRangeLimitCheckEnable); + + if (Status == VL_ERROR_NONE) { + if ((SigmaLimitCheckEnable == 0) || (SigmaLimitflag == 1)) + Temp8 = 1; + else + Temp8 = 0; + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8); + + if ((DeviceRangeStatusInternal == 4) || + (SignalRateFinalRangeLimitCheckEnable == 0)) + Temp8 = 1; + else + Temp8 = 0; + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + Temp8); + + if ((SignalRefClipLimitCheckEnable == 0) || + (SignalRefClipflag == 1)) + Temp8 = 1; + else + Temp8 = 0; + + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_SIGNAL_REF_CLIP, Temp8); + + if ((RangeIgnoreThresholdLimitCheckEnable == 0) || + (RangeIgnoreThresholdflag == 1)) + Temp8 = 1; + else + Temp8 = 0; + + VL_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus, + VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD, + Temp8); + } + + LOG_FUNCTION_END(Status); + return Status; + +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c new file mode 100644 index 000000000000..a1f4683d6787 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_ranging.c @@ -0,0 +1,32 @@ +/* + * vl53l0x_api_ranging.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" + + +#ifndef __KERNEL__ +#include +#endif +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c new file mode 100644 index 000000000000..71fec10d1afd --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_api_strings.c @@ -0,0 +1,455 @@ +/* + * vl53l0x_api_strings.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "vl53l0x_api.h" +#include "vl53l0x_api_core.h" +#include "vl53l0x_api_strings.h" + +#ifndef __KERNEL__ +#include +#endif + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...) \ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__) + + +int8_t VL_check_part_used(struct vl_data *Dev, + uint8_t *Revision, + struct VL_DeviceInfo_t *pVL_DeviceInfo) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t ModuleIdInt; + char *ProductId_tmp; + + LOG_FUNCTION_START(""); + + Status = VL_get_info_from_device(Dev, 2); + + if (Status == VL_ERROR_NONE) { + ModuleIdInt = VL_GETDEVICESPECIFICPARAMETER(Dev, ModuleId); + + if (ModuleIdInt == 0) { + *Revision = 0; + VL_COPYSTRING(pVL_DeviceInfo->ProductId, ""); + } else { + *Revision = VL_GETDEVICESPECIFICPARAMETER(Dev, Revision); + ProductId_tmp = VL_GETDEVICESPECIFICPARAMETER(Dev, + ProductId); + VL_COPYSTRING(pVL_DeviceInfo->ProductId, + ProductId_tmp); + } + } + + LOG_FUNCTION_END(Status); + return Status; +} + + +int8_t VL_get_device_info(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo) +{ + int8_t Status = VL_ERROR_NONE; + uint8_t revision_id; + uint8_t Revision; + + Status = VL_check_part_used(Dev, &Revision, pVL_DeviceInfo); + + if (Status == VL_ERROR_NONE) { + if (Revision == 0) { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_TS0); + } else if ((Revision <= 34) && (Revision != 32)) { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_TS1); + } else if (Revision < 39) { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_TS2); + } else { + VL_COPYSTRING(pVL_DeviceInfo->Name, + VL_STRING_DEVICE_INFO_NAME_ES1); + } + + VL_COPYSTRING(pVL_DeviceInfo->Type, + VL_STRING_DEVICE_INFO_TYPE); + + } + + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_MODEL_ID, + &pVL_DeviceInfo->ProductType); + } + + if (Status == VL_ERROR_NONE) { + Status = VL_RdByte(Dev, + VL_REG_IDENTIFICATION_REVISION_ID, + &revision_id); + pVL_DeviceInfo->ProductRevisionMajor = 1; + pVL_DeviceInfo->ProductRevisionMinor = + (revision_id & 0xF0) >> 4; + } + + return Status; +} + + +int8_t VL_get_device_error_string(uint8_t ErrorCode, + char *pDeviceErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (ErrorCode) { + case VL_DEVICEERROR_NONE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_NONE); + break; + case VL_DEVICEERROR_VCSELCONTINUITYTESTFAILURE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_VCSELCONTINUITYTESTFAILURE); + break; + case VL_DEVICEERROR_VCSELWATCHDOGTESTFAILURE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_VCSELWATCHDOGTESTFAILURE); + break; + case VL_DEVICEERROR_NOVHVVALUEFOUND: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_NOVHVVALUEFOUND); + break; + case VL_DEVICEERROR_MSRCNOTARGET: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_MSRCNOTARGET); + break; + case VL_DEVICEERROR_SNRCHECK: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_SNRCHECK); + break; + case VL_DEVICEERROR_RANGEPHASECHECK: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_RANGEPHASECHECK); + break; + case VL_DEVICEERROR_SIGMATHRESHOLDCHECK: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_SIGMATHRESHOLDCHECK); + break; + case VL_DEVICEERROR_TCC: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_TCC); + break; + case VL_DEVICEERROR_PHASECONSISTENCY: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_PHASECONSISTENCY); + break; + case VL_DEVICEERROR_MINCLIP: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_MINCLIP); + break; + case VL_DEVICEERROR_RANGECOMPLETE: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_RANGECOMPLETE); + break; + case VL_DEVICEERROR_ALGOUNDERFLOW: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_ALGOUNDERFLOW); + break; + case VL_DEVICEERROR_ALGOOVERFLOW: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_ALGOOVERFLOW); + break; + case VL_DEVICEERROR_RANGEIGNORETHRESHOLD: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_DEVICEERROR_RANGEIGNORETHRESHOLD); + break; + + default: + VL_COPYSTRING(pDeviceErrorString, + VL_STRING_UNKNOWN_ERROR_CODE); + + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_range_status_string(uint8_t RangeStatus, + char *pRangeStatusString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (RangeStatus) { + case 0: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_RANGEVALID); + break; + case 1: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_SIGMA); + break; + case 2: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_SIGNAL); + break; + case 3: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_MINRANGE); + break; + case 4: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_PHASE); + break; + case 5: + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_HW); + break; + + default: /**/ + VL_COPYSTRING(pRangeStatusString, + VL_STRING_RANGESTATUS_NONE); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_pal_error_string(int8_t PalErrorCode, + char *pPalErrorString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (PalErrorCode) { + case VL_ERROR_NONE: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_NONE); + break; + case VL_ERROR_CALIBRATION_WARNING: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_CALIBRATION_WARNING); + break; + case VL_ERROR_MIN_CLIPPED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_MIN_CLIPPED); + break; + case VL_ERROR_UNDEFINED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_UNDEFINED); + break; + case VL_ERROR_INVALID_PARAMS: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_INVALID_PARAMS); + break; + case VL_ERROR_NOT_SUPPORTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_NOT_SUPPORTED); + break; + case VL_ERROR_INTERRUPT_NOT_CLEARED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_INTERRUPT_NOT_CLEARED); + break; + case VL_ERROR_RANGE_ERROR: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_RANGE_ERROR); + break; + case VL_ERROR_TIME_OUT: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_TIME_OUT); + break; + case VL_ERROR_MODE_NOT_SUPPORTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_MODE_NOT_SUPPORTED); + break; + case VL_ERROR_BUFFER_TOO_SMALL: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_BUFFER_TOO_SMALL); + break; + case VL_ERROR_GPIO_NOT_EXISTING: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_GPIO_NOT_EXISTING); + break; + case VL_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED); + break; + case VL_ERROR_CONTROL_INTERFACE: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_CONTROL_INTERFACE); + break; + case VL_ERROR_INVALID_COMMAND: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_INVALID_COMMAND); + break; + case VL_ERROR_DIVISION_BY_ZERO: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_DIVISION_BY_ZERO); + break; + case VL_ERROR_REF_SPAD_INIT: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_REF_SPAD_INIT); + break; + case VL_ERROR_NOT_IMPLEMENTED: + VL_COPYSTRING(pPalErrorString, + VL_STRING_ERROR_NOT_IMPLEMENTED); + break; + + default: + VL_COPYSTRING(pPalErrorString, + VL_STRING_UNKNOWN_ERROR_CODE); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_pal_state_string(uint8_t PalStateCode, + char *pPalStateString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (PalStateCode) { + case VL_STATE_POWERDOWN: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_POWERDOWN); + break; + case VL_STATE_WAIT_STATICINIT: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_WAIT_STATICINIT); + break; + case VL_STATE_STANDBY: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_STANDBY); + break; + case VL_STATE_IDLE: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_IDLE); + break; + case VL_STATE_RUNNING: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_RUNNING); + break; + case VL_STATE_UNKNOWN: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_UNKNOWN); + break; + case VL_STATE_ERROR: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_ERROR); + break; + + default: + VL_COPYSTRING(pPalStateString, + VL_STRING_STATE_UNKNOWN); + } + + LOG_FUNCTION_END(Status); + return Status; +} + +int8_t VL_get_sequence_steps_info( + uint8_t SequenceStepId, + char *pSequenceStepsString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (SequenceStepId) { + case VL_SEQUENCESTEP_TCC: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_TCC); + break; + case VL_SEQUENCESTEP_DSS: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_DSS); + break; + case VL_SEQUENCESTEP_MSRC: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_MSRC); + break; + case VL_SEQUENCESTEP_PRE_RANGE: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_PRE_RANGE); + break; + case VL_SEQUENCESTEP_FINAL_RANGE: + VL_COPYSTRING(pSequenceStepsString, + VL_STRING_SEQUENCESTEP_FINAL_RANGE); + break; + + default: + Status = VL_ERROR_INVALID_PARAMS; + } + + LOG_FUNCTION_END(Status); + + return Status; +} + + +int8_t VL_get_limit_check_info(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString) +{ + int8_t Status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + + switch (LimitCheckId) { + case VL_CHECKENABLE_SIGMA_FINAL_RANGE: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGMA_FINAL_RANGE); + break; + case VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE); + break; + case VL_CHECKENABLE_SIGNAL_REF_CLIP: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_REF_CLIP); + break; + case VL_CHECKENABLE_RANGE_IGNORE_THRESHOLD: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_RANGE_IGNORE_THRESHOLD); + break; + + case VL_CHECKENABLE_SIGNAL_RATE_MSRC: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_RATE_MSRC); + break; + + case VL_CHECKENABLE_SIGNAL_RATE_PRE_RANGE: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_CHECKENABLE_SIGNAL_RATE_PRE_RANGE); + break; + + default: + VL_COPYSTRING(pLimitCheckString, + VL_STRING_UNKNOWN_ERROR_CODE); + + } + + LOG_FUNCTION_END(Status); + return Status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c new file mode 100644 index 000000000000..edc4b5c8c3ef --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_i2c_platform.c @@ -0,0 +1,384 @@ +/* + * vl53l0x_i2c_platform.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/*! + * \file VL_platform.c + * \brief Code function definitions for EWOK Platform Layer + * + */ + + +#include +#include +#include +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" + +#include "vl53l0x_platform.h" +#include "vl53l0x_i2c_platform.h" +#include "vl53l0x_def.h" + +#include "vl53l0x_platform_log.h" + +#ifdef VL_LOG_ENABLE +#define trace_print(level, ...) \ + trace_print_module_function(TRACE_MODULE_PLATFORM, level,\ + TRACE_FUNCTION_NONE, ##__VA_ARGS__) +#define trace_i2c(...) \ + trace_print_module_function(TRACE_MODULE_NONE, \ + TRACE_LEVEL_NONE, TRACE_FUNCTION_I2C, ##__VA_ARGS__) +#endif + +/** + * @def I2C_BUFFER_CONFIG + * + * @brief Configure Device register I2C access + * + * @li 0 : one GLOBAL buffer \n + * Use one global buffer of MAX_I2C_XFER_SIZE byte in data space \n + * This solution is not multi-Device compliant nor multi-thread cpu safe \n + * It can be the best option for small 8/16 bit MCU without stack and limited + * ram (STM8s, 80C51 ...) + * + * @li 1 : ON_STACK/local \n + * Use local variable (on stack) buffer \n + * This solution is multi-thread with use of i2c resource lock or mutex see + * VL6180x_GetI2CAccess() \n + * + * @li 2 : User defined \n + * Per Device potentially dynamic allocated. Requires VL6180x_GetI2cBuffer() + * to be implemented. + * @ingroup Configuration + */ +#define I2C_BUFFER_CONFIG 1 + +#if I2C_BUFFER_CONFIG == 0 + /* GLOBAL config buffer */ + uint8_t i2c_global_buffer[VL_MAX_I2C_XFER_SIZE]; + + #define DECL_I2C_BUFFER + #define VL_GetLocalBuffer(Dev, n_byte) i2c_global_buffer + +#elif I2C_BUFFER_CONFIG == 1 + /* ON STACK */ + uint8_t LocBuffer[VL_MAX_I2C_XFER_SIZE]; + #define VL_GetLocalBuffer(Dev, n_byte) LocBuffer +#elif I2C_BUFFER_CONFIG == 2 + /* user define buffer type declare DECL_I2C_BUFFER as access via */ + /* VL_GetLocalBuffer */ + #define DECL_I2C_BUFFER +#else +#error "invalid I2C_BUFFER_CONFIG " +#endif + + +#define VL_I2C_USER_VAR /* none but could be for a flag var to */ + /* get/pass to mutex interruptible return flags and try again */ +#define VL_GetI2CAccess(Dev) /* todo mutex acquire */ +#define VL_DoneI2CAcces(Dev) /* todo mutex release */ + + +char debug_string[VL_MAX_STRING_LENGTH_PLT]; + + +#define MIN_COMMS_VERSION_MAJOR 1 +#define MIN_COMMS_VERSION_MINOR 8 +#define MIN_COMMS_VERSION_BUILD 1 +#define MIN_COMMS_VERSION_REVISION 0 + +#define STATUS_OK 0x00 +#define STATUS_FAIL 0x01 + +bool _check_min_version(void) +{ + bool min_version_comms_dll = false; + + min_version_comms_dll = true; + + return min_version_comms_dll; +} + +int32_t VL_comms_initialise(uint8_t comms_type, uint16_t comms_speed_khz) +{ + int32_t status = STATUS_OK; + + return status; +} + +int32_t VL_comms_close(void) +{ + int32_t status = STATUS_OK; + + + return status; +} + +int32_t VL_set_page(struct vl_data *dev, uint8_t page_data) +{ + int32_t status = STATUS_OK; + uint16_t page_index = 0xFF; + uint8_t *buffer; + + buffer = VL_GetLocalBuffer(dev, 3); + buffer[0] = page_index >> 8; + buffer[1] = page_index & 0xff; + buffer[2] = page_data; + + status = VL_I2CWrite(dev, buffer, (uint8_t) 3); + return status; +} + +int32_t VL_write_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count) +{ + int32_t status = STATUS_OK; + uint8_t *buffer; + +#ifdef VL_LOG_ENABLE + int32_t i = 0; + char value_as_str[VL_MAX_STRING_LENGTH_PLT]; + char *pvalue_as_str; + + pvalue_as_str = value_as_str; + + for (i = 0 ; i < count ; i++) { + snprintf(pvalue_as_str, sizeof(pvalue_as_str), + "%02X", *(pdata + i)); + + pvalue_as_str += 2; + } + trace_i2c("Write reg : 0x%04X, Val : 0x%s\n", index, value_as_str); +#endif + if ((count + 1) > VL_MAX_I2C_XFER_SIZE) + return STATUS_FAIL; + buffer = VL_GetLocalBuffer(dev, (count+1)); + buffer[0] = index; + memcpy(&buffer[1], pdata, count); + status = VL_I2CWrite(dev, buffer, (count+1)); + + return status; +} + +int32_t VL_read_multi(struct vl_data *dev, uint8_t index, uint8_t *pdata, + int32_t count) +{ + int32_t status = STATUS_OK; + uint8_t *buffer; + +#ifdef VL_LOG_ENABLE + int32_t i = 0; + char value_as_str[VL_MAX_STRING_LENGTH_PLT]; + char *pvalue_as_str; +#endif + + if ((count + 1) > VL_MAX_I2C_XFER_SIZE) + return STATUS_FAIL; + + buffer = VL_GetLocalBuffer(dev, 1); + buffer[0] = index; + status = VL_I2CWrite(dev, (uint8_t *)buffer, (uint8_t)1); + if (!status) { + pdata[0] = index; + status = VL_I2CRead(dev, pdata, count); + } + +#ifdef VL_LOG_ENABLE + pvalue_as_str = value_as_str; + + for (i = 0 ; i < count ; i++) { + snprintf(pvalue_as_str, sizeof(value_as_str), + "%02X", *(pdata+i)); + pvalue_as_str += 2; + } + + trace_i2c("Read reg : 0x%04X, Val : 0x%s\n", index, value_as_str); +#endif + + return status; +} + + +int32_t VL_write_byte(struct vl_data *dev, uint8_t index, uint8_t data) +{ + int32_t status = STATUS_OK; + const int32_t cbyte_count = 1; + + status = VL_write_multi(dev, index, &data, cbyte_count); + + return status; + +} + + +int32_t VL_write_word(struct vl_data *dev, uint8_t index, uint16_t data) +{ + int32_t status = STATUS_OK; + + uint8_t buffer[BYTES_PER_WORD]; + + /* Split 16-bit word into MS and LS uint8_t */ + buffer[0] = (uint8_t)(data >> 8); + buffer[1] = (uint8_t)(data & 0x00FF); + + status = VL_write_multi(dev, index, buffer, BYTES_PER_WORD); + + return status; + +} + + +int32_t VL_write_dword(struct vl_data *dev, uint8_t index, uint32_t data) +{ + int32_t status = STATUS_OK; + uint8_t buffer[BYTES_PER_DWORD]; + + /* Split 32-bit word into MS ... LS bytes */ + buffer[0] = (uint8_t) (data >> 24); + buffer[1] = (uint8_t)((data & 0x00FF0000) >> 16); + buffer[2] = (uint8_t)((data & 0x0000FF00) >> 8); + buffer[3] = (uint8_t) (data & 0x000000FF); + + status = VL_write_multi(dev, index, buffer, BYTES_PER_DWORD); + + return status; + +} + + +int32_t VL_read_byte(struct vl_data *dev, uint8_t index, uint8_t *pdata) +{ + int32_t status = STATUS_OK; + int32_t cbyte_count = 1; + + status = VL_read_multi(dev, index, pdata, cbyte_count); + + return status; + +} + + +int32_t VL_read_word(struct vl_data *dev, uint8_t index, uint16_t *pdata) +{ + int32_t status = STATUS_OK; + uint8_t buffer[BYTES_PER_WORD]; + + status = VL_read_multi(dev, index, buffer, BYTES_PER_WORD); + *pdata = ((uint16_t)buffer[0]<<8) + (uint16_t)buffer[1]; + + return status; + +} + +int32_t VL_read_dword(struct vl_data *dev, uint8_t index, uint32_t *pdata) +{ + int32_t status = STATUS_OK; + uint8_t buffer[BYTES_PER_DWORD]; + + status = VL_read_multi(dev, index, buffer, BYTES_PER_DWORD); + *pdata = ((uint32_t)buffer[0]<<24) + ((uint32_t)buffer[1]<<16) + + ((uint32_t)buffer[2]<<8) + (uint32_t)buffer[3]; + + return status; + +} + +int32_t VL_platform_wait_us(int32_t wait_us) +{ + int32_t status = STATUS_OK; + + msleep((wait_us/1000)); + +#ifdef VL_LOG_ENABLE + trace_i2c("Wait us : %6d\n", wait_us); +#endif + + return status; + +} + + +int32_t VL_wait_ms(int32_t wait_ms) +{ + int32_t status = STATUS_OK; + + msleep(wait_ms); + +#ifdef VL_LOG_ENABLE + trace_i2c("Wait ms : %6d\n", wait_ms); +#endif + + return status; + +} + + +int32_t VL_set_gpio(uint8_t level) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// Set GPIO = %d;\n", level); +#endif + + return status; + +} + + +int32_t VL_get_gpio(uint8_t *plevel) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// Get GPIO = %d;\n", *plevel); +#endif + return status; +} + + +int32_t VL_release_gpio(void) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// Releasing force on GPIO\n"); +#endif + return status; + +} + +int32_t VL_cycle_power(void) +{ + int32_t status = STATUS_OK; +#ifdef VL_LOG_ENABLE + trace_i2c("// cycle sensor power\n"); +#endif + + return status; +} + + +int32_t VL_get_timer_frequency(int32_t *ptimer_freq_hz) +{ + *ptimer_freq_hz = 0; + return STATUS_FAIL; +} + + +int32_t VL_get_timer_value(int32_t *ptimer_count) +{ + *ptimer_count = 0; + return STATUS_FAIL; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c new file mode 100644 index 000000000000..79df3db288f3 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_platform.c @@ -0,0 +1,232 @@ +/* + * vl53l0x_platform.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/** + * @file VL_i2c.c + * + * Copyright (C) 2014 ST MicroElectronics + * + * provide variable word size byte/Word/dword VL6180x register access via i2c + * + */ +#include "vl53l0x_platform.h" +#include "vl53l0x_i2c_platform.h" +#include "vl53l0x_api.h" + +#define LOG_FUNCTION_START(fmt, ...) \ + _LOG_FUNCTION_START(TRACE_MODULE_PLATFORM, fmt, ##__VA_ARGS__) +#define LOG_FUNCTION_END(status, ...) \ + _LOG_FUNCTION_END(TRACE_MODULE_PLATFORM, status, ##__VA_ARGS__) +#define LOG_FUNCTION_END_FMT(status, fmt, ...)\ + _LOG_FUNCTION_END_FMT(TRACE_MODULE_PLATFORM, status,\ + fmt, ##__VA_ARGS__) + + + +int8_t VL_LockSequenceAccess(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + + return Status; +} + +int8_t VL_UnlockSequenceAccess(struct vl_data *Dev) +{ + int8_t Status = VL_ERROR_NONE; + + return Status; +} + +/* the ranging_sensor_comms.dll will take care of the page selection */ +int8_t VL_WriteMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count) +{ + + int8_t Status = VL_ERROR_NONE; + int32_t status_int = 0; + uint8_t deviceAddress; + + if (count >= VL_MAX_I2C_XFER_SIZE) + Status = VL_ERROR_INVALID_PARAMS; + + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_multi(Dev, index, pdata, count); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +/* the ranging_sensor_comms.dll will take care of the page selection */ +int8_t VL_ReadMulti(struct vl_data *Dev, uint8_t index, + uint8_t *pdata, uint32_t count) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + if (count >= VL_MAX_I2C_XFER_SIZE) + Status = VL_ERROR_INVALID_PARAMS; + + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_multi(Dev, index, pdata, count); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + + +int8_t VL_WrByte(struct vl_data *Dev, uint8_t index, uint8_t data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_byte(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_WrWord(struct vl_data *Dev, uint8_t index, uint16_t data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_word(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_WrDWord(struct vl_data *Dev, uint8_t index, uint32_t data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_write_dword(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_UpdateByte(struct vl_data *Dev, uint8_t index, + uint8_t AndData, uint8_t OrData) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + uint8_t data; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_byte(Dev, index, &data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + if (Status == VL_ERROR_NONE) { + data = (data & AndData) | OrData; + status_int = VL_write_byte(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + } + + return Status; +} + +int8_t VL_RdByte(struct vl_data *Dev, uint8_t index, uint8_t *data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_byte(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_RdWord(struct vl_data *Dev, uint8_t index, uint16_t *data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_word(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +int8_t VL_RdDWord(struct vl_data *Dev, uint8_t index, uint32_t *data) +{ + int8_t Status = VL_ERROR_NONE; + int32_t status_int; + uint8_t deviceAddress; + + deviceAddress = Dev->I2cDevAddr; + + status_int = VL_read_dword(Dev, index, data); + + if (status_int != 0) + Status = VL_ERROR_CONTROL_INTERFACE; + + return Status; +} + +#define VL_POLLINGDELAY_LOOPNB 250 +int8_t VL_PollingDelay(struct vl_data *Dev) +{ + int8_t status = VL_ERROR_NONE; + + LOG_FUNCTION_START(""); + usleep_range(1000, 1001); + LOG_FUNCTION_END(status); + return status; +} diff --git a/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c new file mode 100644 index 000000000000..9e14f7915b16 --- /dev/null +++ b/drivers/input/misc/vl53l0x/src/vl53l0x_port_i2c.c @@ -0,0 +1,168 @@ +/* + * vl53l0x_port_i2c.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" +#include "vl53l0x_platform.h" +#include "vl53l0x_i2c_platform.h" +#include "stmvl53l0x.h" + +#define I2C_M_WR 0x00 +#define STATUS_OK 0x00 +#define STATUS_FAIL (-1) +/** int VL_I2CWrite(VL_Dev_t dev, void *buff, uint8_t len); + * @brief Write data buffer to VL53L0 device via i2c + * @param dev The device to write to + * @param buff The data buffer + * @param len The length of the transaction in byte + * @return 0 on success + */ +int VL_I2CWrite(struct vl_data *dev, uint8_t *buff, uint8_t len) +{ + + + int err = 0; + + if (dev->bus_type == CCI_BUS) { +#ifdef CAMERA_CCI + uint16_t index; + struct cci_data *cci_client_obj = + (struct cci_data *)dev->client_object; + struct msm_camera_i2c_client *client = cci_client_obj->client; + + index = buff[0]; + /*dbg("%s: index: %d len: %d\n", __func__, index, len); */ + + if (len == 2) { + uint8_t data; + + data = buff[1]; + /* for byte access */ + err = client->i2c_func_tbl->i2c_write(client, index, + data, MSM_CAMERA_I2C_BYTE_DATA); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } + } else if (len == 3) { + uint16_t data; + + data = ((uint16_t)buff[1] << 8) | (uint16_t)buff[2]; + err = client->i2c_func_tbl->i2c_write(client, index, + data, MSM_CAMERA_I2C_WORD_DATA); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } + } else if (len >= 5) { + err = client->i2c_func_tbl->i2c_write_seq(client, + index, &buff[1], (len-1)); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } + + } +#endif +#ifndef CAMERA_CCI + } else { + struct i2c_msg msg[1]; + struct i2c_data *i2c_client_obj = + (struct i2c_data *)dev->client_object; + struct i2c_client *client = + (struct i2c_client *)i2c_client_obj->client; + + msg[0].addr = client->addr; + msg[0].flags = I2C_M_WR; + msg[0].buf = buff; + msg[0].len = len; + + err = i2c_transfer(client->adapter, msg, 1); + /* return the actual messages transfer */ + if (err != 1) { + dbg("%s: i2c_transfer err:%d, addr:0x%x, reg:0x%x\n", + __func__, err, client->addr, + (buff[0] << 8 | buff[1])); + return STATUS_FAIL; + } +#endif + } + + return 0; +} + + +/** int VL_I2CRead(VL_Dev_t dev, void *buff, uint8_t len); + * @brief Read data buffer from VL53L0 device via i2c + * @param dev The device to read from + * @param buff The data buffer to fill + * @param len The length of the transaction in byte + * @return transaction status + */ +int VL_I2CRead(struct vl_data *dev, uint8_t *buff, uint8_t len) +{ + + int err = 0; + + if (dev->bus_type == CCI_BUS) { +#ifdef CAMERA_CCI + uint16_t index; + struct cci_data *cci_client_obj = + (struct cci_data *)dev->client_object; + struct msm_camera_i2c_client *client = cci_client_obj->client; + + index = buff[0]; + /* dbg("%s: index: %d\n", __func__, index); */ + err = client->i2c_func_tbl->i2c_read_seq(client, + index, buff, len); + if (err < 0) { + dbg("%s:%d failed status=%d\n", + __func__, __LINE__, err); + return err; + } +#endif + } else { +#ifndef CAMERA_CCI + struct i2c_msg msg[1]; + struct i2c_data *i2c_client_obj = + (struct i2c_data *)dev->client_object; + struct i2c_client *client = + (struct i2c_client *) i2c_client_obj->client; + + msg[0].addr = client->addr; + msg[0].flags = I2C_M_RD|client->flags; + msg[0].buf = buff; + msg[0].len = len; + + err = i2c_transfer(client->adapter, &msg[0], 1); + /* return the actual message transfer */ + if (err != 1) { + dbg("%s: Read i2c_transfer err:%d, addr:0x%x\n", + __func__, err, client->addr); + return STATUS_FAIL; + } +#endif + } + + return 0; +} diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h new file mode 100644 index 000000000000..5476ef9241a3 --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x-cci.h @@ -0,0 +1,57 @@ +/* + * stmvl53l0x-cci.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef STMVL_CCI_H +#define STMVL_CCI_H +#include + +#ifdef CAMERA_CCI +#include +#include "msm_camera_i2c.h" +#include "msm_camera_dt_util.h" +#include "msm_camera_io_util.h" +#include "msm_cci.h" + +#define MSM_TOF_MAX_VREGS (10) + +struct msm_tof_vreg { + struct camera_vreg_t *cam_vreg; + void *data[MSM_TOF_MAX_VREGS]; + int num_vreg; +}; + +struct cci_data { + struct msm_camera_i2c_client g_client; + struct msm_camera_i2c_client *client; + struct platform_device *pdev; + enum msm_camera_device_type_t device_type; + enum cci_i2c_master_t cci_master; + struct msm_tof_vreg vreg_cfg; + struct msm_sd_subdev msm_sd; + struct v4l2_subdev sdev; + struct v4l2_subdev_ops *subdev_ops; + char subdev_initialized; + uint32_t subdev_id; + uint8_t power_up; +}; +int stmvl53l0x_init_cci(void); +void stmvl53l0x_exit_cci(void *cci_object); +int stmvl53l0x_power_down_cci(void *cci_object); +int stmvl53l0x_power_up_cci(void *cci_object, unsigned int *preset_flag); +#endif /* CAMERA_CCI */ +#endif /* STMVL_CCI_H */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h new file mode 100644 index 000000000000..68f7d37349ea --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x-i2c.h @@ -0,0 +1,35 @@ +/* + * stmvl53l0x-i2c.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef STMVL_I2C_H +#define STMVL_I2C_H +#include + +#ifndef CAMERA_CCI +struct i2c_data { + struct i2c_client *client; + struct regulator *vana; + uint8_t power_up; +}; +int stmvl53l0x_init_i2c(void); +void stmvl53l0x_exit_i2c(void *i2c_object); +int stmvl53l0x_power_up_i2c(void *i2c_object, unsigned int *preset_flag); +int stmvl53l0x_power_down_i2c(void *i2c_object); + +#endif /* NOT CAMERA_CCI */ +#endif /* STMVL_I2C_H */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x.h b/drivers/input/misc/vl53l0x/stmvl53l0x.h new file mode 100644 index 000000000000..1f15278d5418 --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x.h @@ -0,0 +1,186 @@ +/* + * stmvl53l0x.h - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef STMVL_H +#define STMVL_H + +#include +#include +#include +#include +#include + + +#define STMVL_DRV_NAME "stmvl53l0" +#define STMVL_SLAVE_ADDR (0x52>>1) + +#define DRIVER_VERSION "1.0.5" +#define I2C_M_WR 0x00 +/* #define INT_POLLING_DELAY 20 */ + +/* if don't want to have output from dbg, comment out #DEBUG macro */ +#ifdef DEBUG +#define dbg(fmt, ...) \ + printk(fmt, ##__VA_ARGS__) +#else +#define dbg(fmt, ...) +#endif + +#define err(fmt, ...) \ + printk(fmt, ##__VA_ARGS__) + +#define VL_VDD_MIN 2600000 +#define VL_VDD_MAX 3000000 + +enum init_mode_e { + NORMAL_MODE = 0, + OFFSETCALIB_MODE = 1, + XTALKCALIB_MODE = 2, +}; + +enum parameter_name_e { + OFFSET_PAR = 0, + XTALKRATE_PAR = 1, + XTALKENABLE_PAR = 2, + GPIOFUNC_PAR = 3, + LOWTHRESH_PAR = 4, + HIGHTHRESH_PAR = 5, + DEVICEMODE_PAR = 6, + INTERMEASUREMENT_PAR = 7, + REFERENCESPADS_PAR = 8, + REFCALIBRATION_PAR = 9, +}; + +enum { + CCI_BUS = 0, + I2C_BUS = 1, +}; + +/* + * IOCTL register data structs + */ +struct stmvl53l0x_register { + uint32_t is_read; /*1: read 0: write*/ + uint32_t reg_index; + uint32_t reg_bytes; + uint32_t reg_data; + int32_t status; +}; + +/* + * IOCTL parameter structs + */ +struct stmvl53l0x_parameter { + uint32_t is_read; /*1: Get 0: Set*/ + enum parameter_name_e name; + int32_t value; + int32_t value2; + int32_t status; +}; + +/* + * driver data structs + */ +struct vl_data { + + struct VL_DevData_t Data; /* ! +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * power specific includes + */ +#include +#include +#include +#include +#include +/* + * API includes + */ +#include "vl53l0x_api.h" +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" +#include "stmvl53l0x-cci.h" +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x.h" + +#ifdef CAMERA_CCI +/* + * Global data + */ +static struct v4l2_file_operations msm_tof_v4l2_subdev_fops; +static struct msm_camera_i2c_fn_t msm_sensor_cci_func_tbl = { + .i2c_read = msm_camera_cci_i2c_read, + .i2c_read_seq = msm_camera_cci_i2c_read_seq, + .i2c_write = msm_camera_cci_i2c_write, + .i2c_write_seq = msm_camera_cci_i2c_write_seq, + .i2c_write_table = msm_camera_cci_i2c_write_table, + .i2c_write_seq_table = msm_camera_cci_i2c_write_seq_table, + .i2c_write_table_w_microdelay = + msm_camera_cci_i2c_write_table_w_microdelay, + .i2c_util = msm_sensor_cci_i2c_util, + .i2c_poll = msm_camera_cci_i2c_poll, +}; +static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data); + +/* + * QCOM specific functions + */ +static int stmvl53l0x_get_dt_data(struct device *dev, struct cci_data *data) +{ + int rc = 0; + + dbg("Enter\n"); + + if (dev->of_node) { + struct device_node *of_node = dev->of_node; + struct msm_tof_vreg *vreg_cfg; + + if (!of_node) { + err("failed %d\n", __LINE__); + return -EINVAL; + } + + rc = of_property_read_u32(of_node, + "cell-index", &data->pdev->id); + if (rc < 0) { + err("failed %d\n", __LINE__); + return rc; + } + dbg("cell-index: %d\n", data->pdev->id); + rc = of_property_read_u32(of_node, "qcom,cci-master", + &data->cci_master); + if (rc < 0) { + err("failed %d\n", __LINE__); + /* Set default master 0 */ + data->cci_master = MASTER_0; + rc = 0; + } + dbg("cci_master: %d\n", data->cci_master); + if (of_find_property(of_node, "qcom,cam-vreg-name", NULL)) { + vreg_cfg = &data->vreg_cfg; + rc = msm_camera_get_dt_vreg_data(of_node, + &vreg_cfg->cam_vreg, &vreg_cfg->num_vreg); + if (rc < 0) { + err("failed %d\n", __LINE__); + return rc; + } + } + dbg("vreg-name: %s min_volt: %d max_volt: %d", + vreg_cfg->cam_vreg->reg_name, + vreg_cfg->cam_vreg->min_voltage, + vreg_cfg->cam_vreg->max_voltage); + } + dbg("End rc =%d\n", rc); + + return rc; +} + +static int32_t stmvl53l0x_vreg_control(struct cci_data *data, int config) +{ + int rc = 0, i, cnt; + struct msm_tof_vreg *vreg_cfg; + + dbg("Enter\n"); + + vreg_cfg = &data->vreg_cfg; + cnt = vreg_cfg->num_vreg; + dbg("num_vreg: %d\n", cnt); + if (!cnt) { + err("failed %d\n", __LINE__); + return 0; + } + + if (cnt >= MSM_TOF_MAX_VREGS) { + err("failed %d cnt %d\n", __LINE__, cnt); + return -EINVAL; + } + + for (i = 0; i < cnt; i++) { + rc = msm_camera_config_single_vreg(&(data->pdev->dev), + &vreg_cfg->cam_vreg[i], + (struct regulator **)&vreg_cfg->data[i], + config); + } + + dbg("EXIT rc =%d\n", rc); + return rc; +} + + +static int msm_tof_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + return 0; +} + + +static const struct v4l2_subdev_internal_ops msm_tof_internal_ops = { + .close = msm_tof_close, +}; + +static long msm_tof_subdev_ioctl(struct v4l2_subdev *sd, + unsigned int cmd, void *arg) +{ + dbg("Subdev_ioctl not handled\n"); + return 0; +} + +static int32_t msm_tof_power(struct v4l2_subdev *sd, int on) +{ + dbg("TOF power called\n"); + return 0; +} + +static struct v4l2_subdev_core_ops msm_tof_subdev_core_ops = { + .ioctl = msm_tof_subdev_ioctl, + .s_power = msm_tof_power, +}; + +static struct v4l2_subdev_ops msm_tof_subdev_ops = { + .core = &msm_tof_subdev_core_ops, +}; + +static int stmvl53l0x_cci_init(struct cci_data *data) +{ + int rc = 0; + struct msm_camera_cci_client *cci_client = data->client->cci_client; + + if (data->subdev_initialized == FALSE) { + data->client->i2c_func_tbl = &msm_sensor_cci_func_tbl; + data->client->cci_client = + kzalloc(sizeof(struct msm_camera_cci_client), + GFP_KERNEL); + if (!data->client->cci_client) { + err("%d, failed no memory\n", __LINE__); + return -ENOMEM; + } + cci_client = data->client->cci_client; + cci_client->cci_subdev = msm_cci_get_subdev(); + cci_client->cci_i2c_master = data->cci_master; + v4l2_subdev_init(&data->msm_sd.sd, data->subdev_ops); + v4l2_set_subdevdata(&data->msm_sd.sd, data); + data->msm_sd.sd.internal_ops = &msm_tof_internal_ops; + data->msm_sd.sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(data->msm_sd.sd.name, ARRAY_SIZE(data->msm_sd.sd.name), + "msm_tof"); + media_entity_init(&data->msm_sd.sd.entity, 0, NULL, 0); + data->msm_sd.sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV; + data->msm_sd.sd.entity.group_id = MSM_CAMERA_SUBDEV_TOF; + data->msm_sd.close_seq = MSM_SD_CLOSE_2ND_CATEGORY | 0x2; + msm_sd_register(&data->msm_sd); + msm_tof_v4l2_subdev_fops = v4l2_subdev_fops; + data->msm_sd.sd.devnode->fops = &msm_tof_v4l2_subdev_fops; + data->subdev_initialized = TRUE; + } + + cci_client->sid = 0x29; + cci_client->retries = 3; + cci_client->id_map = 0; + cci_client->cci_i2c_master = data->cci_master; + rc = data->client->i2c_func_tbl->i2c_util(data->client, MSM_CCI_INIT); + if (rc < 0) { + err("%d: CCI Init failed\n", __LINE__); + return rc; + } + dbg("CCI Init Succeeded\n"); + + data->client->addr_type = MSM_CAMERA_I2C_BYTE_ADDR; + + return 0; +} + +static int32_t stmvl53l0x_platform_probe(struct platform_device *pdev) +{ + struct vl_data *vl53l0x_data = NULL; + struct cci_data *cci_object = NULL; + int32_t rc = 0; + + dbg("Enter\n"); + + if (!pdev->dev.of_node) { + err("of_node NULL\n"); + return -EINVAL; + } + + vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL); + if (!vl53l0x_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l0x_data) { + vl53l0x_data->client_object = + kzalloc(sizeof(struct cci_data), GFP_KERNEL); + cci_object = (struct cci_data *)vl53l0x_data->client_object; + } + cci_object->client = + (struct msm_camera_i2c_client *)&cci_object->g_client; + + /* setup bus type */ + vl53l0x_data->bus_type = CCI_BUS; + + /* Set platform device handle */ + cci_object->subdev_ops = &msm_tof_subdev_ops; + cci_object->pdev = pdev; + rc = stmvl53l0x_get_dt_data(&pdev->dev, cci_object); + if (rc < 0) { + err("%d, failed rc %d\n", __LINE__, rc); + return rc; + } + cci_object->subdev_id = pdev->id; + + /* Set device type as platform device */ + cci_object->device_type = MSM_CAMERA_PLATFORM_DEVICE; + cci_object->subdev_initialized = FALSE; + + /* setup device name */ + vl53l0x_data->dev_name = dev_name(&pdev->dev); + + /* setup device data */ + dev_set_drvdata(&pdev->dev, vl53l0x_data); + + /* setup other stuff */ + rc = stmvl53l0x_setup(vl53l0x_data); + + /* init default value */ + cci_object->power_up = 0; + + dbg("End\n"); + + return rc; + +} + +static int32_t stmvl53l0x_platform_remove(struct platform_device *pdev) +{ + struct vl_data *vl53l0x_data = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + kfree(vl53l0x_data->client_object); + kfree(vl53l0x_data); + + return 0; +} + +static const struct of_device_id st_stmvl53l0x_dt_match[] = { + { .compatible = "st,stmvl53l0", }, + { }, +}; + +static struct platform_driver stmvl53l0x_platform_driver = { + .probe = stmvl53l0x_platform_probe, + .remove = stmvl53l0x_platform_remove, + .driver = { + .name = STMVL_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l0x_dt_match, + }, +}; + +int stmvl53l0x_power_up_cci(void *cci_object, unsigned int *preset_flag) +{ + int ret = 0; + struct cci_data *data = (struct cci_data *)cci_object; + + dbg("Enter"); + + /* need to init cci first */ + ret = stmvl53l0x_cci_init(data); + if (ret) { + err("stmvl53l0x_cci_init failed %d\n", __LINE__); + return ret; + } + /* actual power up */ + if (data && data->device_type == MSM_CAMERA_PLATFORM_DEVICE) { + ret = stmvl53l0x_vreg_control(data, 1); + if (ret < 0) { + err("stmvl53l0x_vreg_control failed %d\n", + __LINE__); + return ret; + } + } + data->power_up = 1; + *preset_flag = 1; + dbg("End\n"); + + return ret; +} + +int stmvl53l0x_power_down_cci(void *cci_object) +{ + int ret = 0; + struct cci_data *data = (struct cci_data *)cci_object; + + dbg("Enter\n"); + if (data->power_up) { + /* need to release cci first */ + ret = data->client->i2c_func_tbl->i2c_util(data->client, + MSM_CCI_RELEASE); + if (ret < 0) + err("CCI Release failed rc %d\n", ret); + + /* actual power down */ + if (data->device_type == MSM_CAMERA_PLATFORM_DEVICE) { + ret = stmvl53l0x_vreg_control(data, 0); + if (ret < 0) { + err( + "stmvl53l0x_vreg_control failed %d\n", + __LINE__); + return ret; + } + } + } + data->power_up = 0; + dbg("End\n"); + return ret; +} + +int stmvl53l0x_init_cci(void) +{ + int ret = 0; + + dbg("Enter\n"); + + /* register as a platform device */ + ret = platform_driver_register(&stmvl53l0x_platform_driver); + if (ret) + err("%d, error ret:%d\n", __LINE__, ret); + + dbg("End\n"); + + return ret; +} + +void stmvl53l0x_exit_cci(void *cci_object) +{ + struct cci_data *data = (struct cci_data *)cci_object; + + dbg("Enter\n"); + + if (data && data->client->cci_client) + kfree(data->client->cci_client); + + dbg("End\n"); +} +#endif /* end of CAMERA_CCI */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c new file mode 100644 index 000000000000..7e0cc152a67a --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module-i2c.c @@ -0,0 +1,246 @@ +/* + * stmvl53l0x_module-i2c.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * power specific includes + */ +#include +#include +#include +#include +#include +/* + * API includes + */ +#include "vl53l0x_api.h" +#include "vl53l0x_def.h" +#include "vl53l0x_platform.h" +#include "stmvl53l0x-i2c.h" +#include "stmvl53l0x-cci.h" +#include "stmvl53l0x.h" +#ifndef CAMERA_CCI + +/* + * Global data + */ +static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data); + +/* + * QCOM specific functions + */ +static int stmvl53l0x_parse_vdd(struct device *dev, struct i2c_data *data) +{ + int ret = 0; + + dbg("Enter\n"); + + if (dev->of_node) { + data->vana = regulator_get(dev, "vdd"); + if (IS_ERR(data->vana)) { + err("vdd supply is not provided\n"); + ret = -1; + } + } + dbg("End\n"); + + return ret; +} + +static int stmvl53l0x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int rc = 0; + struct vl_data *vl53l0x_data = NULL; + struct i2c_data *i2c_object = NULL; + + dbg("Enter\n"); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + rc = -EIO; + return rc; + } + + vl53l0x_data = kzalloc(sizeof(struct vl_data), GFP_KERNEL); + if (!vl53l0x_data) { + rc = -ENOMEM; + return rc; + } + if (vl53l0x_data) { + vl53l0x_data->client_object = + kzalloc(sizeof(struct i2c_data), GFP_KERNEL); + i2c_object = (struct i2c_data *)vl53l0x_data->client_object; + } + i2c_object->client = client; + + /* setup bus type */ + vl53l0x_data->bus_type = I2C_BUS; + + /* setup regulator */ + stmvl53l0x_parse_vdd(&i2c_object->client->dev, i2c_object); + + /* setup device name */ + vl53l0x_data->dev_name = dev_name(&client->dev); + + /* setup device data */ + dev_set_drvdata(&client->dev, vl53l0x_data); + + /* setup client data */ + i2c_set_clientdata(client, vl53l0x_data); + + /* setup other stuff */ + rc = stmvl53l0x_setup(vl53l0x_data); + + /* init default value */ + i2c_object->power_up = 0; + + dbg("End\n"); + return rc; +} + +static int stmvl53l0x_remove(struct i2c_client *client) +{ + struct vl_data *data = i2c_get_clientdata(client); + + dbg("Enter\n"); + + /* Power down the device */ + stmvl53l0x_power_down_i2c(data->client_object); + kfree(data->client_object); + kfree(data); + dbg("End\n"); + return 0; +} + +static const struct i2c_device_id stmvl53l0x_id[] = { + { STMVL_DRV_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, stmvl53l0x_id); + +static const struct of_device_id st_stmvl53l0x_dt_match[] = { + { .compatible = "st,stmvl53l0", }, + { }, +}; + +static struct i2c_driver stmvl53l0x_driver = { + .driver = { + .name = STMVL_DRV_NAME, + .owner = THIS_MODULE, + .of_match_table = st_stmvl53l0x_dt_match, + }, + .probe = stmvl53l0x_probe, + .remove = stmvl53l0x_remove, + .id_table = stmvl53l0x_id, + +}; + +int stmvl53l0x_power_up_i2c(void *i2c_object, unsigned int *preset_flag) +{ + int ret = 0; +#ifndef STM_TEST + struct i2c_data *data = (struct i2c_data *)i2c_object; +#endif + + dbg("Enter\n"); + + /* actual power on */ +#ifndef STM_TEST + ret = regulator_set_voltage(data->vana, + VL_VDD_MIN, VL_VDD_MAX); + if (ret < 0) { + err("set_vol(%p) fail %d\n", data->vana, ret); + return ret; + } + ret = regulator_enable(data->vana); + usleep_range(3000, 3001); + if (ret < 0) { + err("reg enable(%p) failed.rc=%d\n", + data->vana, ret); + return ret; + } + data->power_up = 1; + *preset_flag = 1; +#endif + + dbg("End\n"); + return ret; +} + +int stmvl53l0x_power_down_i2c(void *i2c_object) +{ + int ret = 0; +#ifndef STM_TEST + struct i2c_data *data = (struct i2c_data *)i2c_object; +#endif + + dbg("Enter\n"); +#ifndef STM_TEST + msleep(30); + ret = regulator_disable(data->vana); + if (ret < 0) + err("reg disable(%p) failed.rc=%d\n", + data->vana, ret); + + data->power_up = 0; +#endif + + dbg("End\n"); + return ret; +} + +int stmvl53l0x_init_i2c(void) +{ + int ret = 0; + + dbg("Enter\n"); + + /* register as a i2c client device */ + ret = i2c_add_driver(&stmvl53l0x_driver); + if (ret) + err("%d erro ret:%d\n", __LINE__, ret); + + dbg("End with rc:%d\n", ret); + + return ret; +} + +void stmvl53l0x_exit_i2c(void *i2c_object) +{ + dbg("Enter\n"); + i2c_del_driver(&stmvl53l0x_driver); + + dbg("End\n"); +} + +#endif /* end of NOT CAMERA_CCI */ diff --git a/drivers/input/misc/vl53l0x/stmvl53l0x_module.c b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c new file mode 100644 index 000000000000..ece245f24111 --- /dev/null +++ b/drivers/input/misc/vl53l0x/stmvl53l0x_module.c @@ -0,0 +1,1893 @@ +/* + * stmvl53l0x_module.c - Linux kernel modules for + * STM VL53L0 FlightSense TOF sensor + * + * Copyright (C) 2016 STMicroelectronics Imaging Division. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* + * API includes + */ +#include "vl53l0x_api.h" + +#define IRQ_NUM 59 +#ifdef DEBUG_TIME_LOG +struct timeval start_tv, stop_tv; +#endif + +/* + * Global data + */ + +#ifdef CAMERA_CCI +static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = { + .init = stmvl53l0x_init_cci, + .deinit = stmvl53l0x_exit_cci, + .power_up = stmvl53l0x_power_up_cci, + .power_down = stmvl53l0x_power_down_cci, +}; +#else +static struct stmvl53l0x_module_fn_t stmvl53l0x_module_func_tbl = { + .init = stmvl53l0x_init_i2c, + .deinit = stmvl53l0x_exit_i2c, + .power_up = stmvl53l0x_power_up_i2c, + .power_down = stmvl53l0x_power_down_i2c, +}; +#endif +struct stmvl53l0x_module_fn_t *pmodule_func_tbl; +struct stmvl53l0x_api_fn_t { + int8_t (*GetVersion)(struct VL_Version_t *pVersion); + int8_t (*GetPalSpecVersion)(struct VL_Version_t *pPalSpecVersion); + + int8_t (*GetProductRevision)(struct vl_data *Dev, + uint8_t *pProductRevisionMajor, + uint8_t *pProductRevisionMinor); + int8_t (*GetDeviceInfo)(struct vl_data *Dev, + struct VL_DeviceInfo_t *pVL_DeviceInfo); + int8_t (*GetDeviceErrorStatus)(struct vl_data *Dev, + uint8_t *pDeviceErrorStatus); + int8_t (*GetRangeStatusString)(uint8_t RangeStatus, + char *pRangeStatusString); + int8_t (*GetDeviceErrorString)(uint8_t ErrorCode, + char *pDeviceErrorString); + int8_t (*GetPalErrorString)(int8_t PalErrorCode, + char *pPalErrorString); + int8_t (*GetPalStateString)(uint8_t PalStateCode, + char *pPalStateString); + int8_t (*GetPalState)(struct vl_data *Dev, uint8_t *pPalState); + int8_t (*SetPowerMode)(struct vl_data *Dev, + uint8_t PowerMode); + int8_t (*GetPowerMode)(struct vl_data *Dev, + uint8_t *pPowerMode); + int8_t (*SetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev, + int32_t OffsetCalibrationDataMicroMeter); + int8_t (*GetOffsetCalibrationDataMicroMeter)(struct vl_data *Dev, + int32_t *pOffsetCalibrationDataMicroMeter); + int8_t (*SetLinearityCorrectiveGain)(struct vl_data *Dev, + int16_t LinearityCorrectiveGain); + int8_t (*GetLinearityCorrectiveGain)(struct vl_data *Dev, + uint16_t *pLinearityCorrectiveGain); + int8_t (*SetGroupParamHold)(struct vl_data *Dev, + uint8_t GroupParamHold); + int8_t (*GetUpperLimitMilliMeter)(struct vl_data *Dev, + uint16_t *pUpperLimitMilliMeter); + int8_t (*SetDeviceAddress)(struct vl_data *Dev, + uint8_t DeviceAddress); + int8_t (*DataInit)(struct vl_data *Dev); + int8_t (*SetTuningSettingBuffer)(struct vl_data *Dev, + uint8_t *pTuningSettingBuffer, + uint8_t UseInternalTuningSettings); + int8_t (*GetTuningSettingBuffer)(struct vl_data *Dev, + uint8_t **pTuningSettingBuffer, + uint8_t *pUseInternalTuningSettings); + int8_t (*StaticInit)(struct vl_data *Dev); + int8_t (*WaitDeviceBooted)(struct vl_data *Dev); + int8_t (*ResetDevice)(struct vl_data *Dev); + int8_t (*SetDeviceParameters)(struct vl_data *Dev, + const struct VL_DeviceParameters_t *pDeviceParameters); + int8_t (*GetDeviceParameters)(struct vl_data *Dev, + struct VL_DeviceParameters_t *pDeviceParameters); + int8_t (*SetDeviceMode)(struct vl_data *Dev, + uint8_t DeviceMode); + int8_t (*GetDeviceMode)(struct vl_data *Dev, + uint8_t *pDeviceMode); + int8_t (*SetHistogramMode)(struct vl_data *Dev, + uint8_t HistogramMode); + int8_t (*GetHistogramMode)(struct vl_data *Dev, + uint8_t *pHistogramMode); + int8_t (*SetMeasurementTimingBudgetMicroSeconds)(struct vl_data *Dev, + uint32_t MeasurementTimingBudgetMicroSeconds); + int8_t (*GetMeasurementTimingBudgetMicroSeconds)( + struct vl_data *Dev, + uint32_t *pMeasurementTimingBudgetMicroSeconds); + int8_t (*GetVcselPulsePeriod)(struct vl_data *Dev, + uint8_t VcselPeriodType, + uint8_t *pVCSELPulsePeriod); + int8_t (*SetVcselPulsePeriod)(struct vl_data *Dev, + uint8_t VcselPeriodType, + uint8_t VCSELPulsePeriod); + int8_t (*SetSequenceStepEnable)(struct vl_data *Dev, + uint8_t SequenceStepId, + uint8_t SequenceStepEnabled); + int8_t (*GetSequenceStepEnable)(struct vl_data *Dev, + uint8_t SequenceStepId, + uint8_t *pSequenceStepEnabled); + int8_t (*GetSequenceStepEnables)(struct vl_data *Dev, + struct VL_SchedulerSequenceSteps_t *pSchedulerSequenceSteps); + int8_t (*SetSequenceStepTimeout)(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int TimeOutMilliSecs); + int8_t (*GetSequenceStepTimeout)(struct vl_data *Dev, + uint8_t SequenceStepId, + unsigned int *pTimeOutMilliSecs); + int8_t (*GetNumberOfSequenceSteps)(struct vl_data *Dev, + uint8_t *pNumberOfSequenceSteps); + int8_t (*GetSequenceStepsInfo)( + uint8_t SequenceStepId, + char *pSequenceStepsString); + int8_t (*SetInterMeasurementPeriodMilliSeconds)( + struct vl_data *Dev, + uint32_t InterMeasurementPeriodMilliSeconds); + int8_t (*GetInterMeasurementPeriodMilliSeconds)( + struct vl_data *Dev, + uint32_t *pInterMeasurementPeriodMilliSeconds); + int8_t (*SetXTalkCompensationEnable)(struct vl_data *Dev, + uint8_t XTalkCompensationEnable); + int8_t (*GetXTalkCompensationEnable)(struct vl_data *Dev, + uint8_t *pXTalkCompensationEnable); + int8_t (*SetXTalkCompensationRateMegaCps)( + struct vl_data *Dev, + unsigned int XTalkCompensationRateMegaCps); + int8_t (*GetXTalkCompensationRateMegaCps)( + struct vl_data *Dev, + unsigned int *pXTalkCompensationRateMegaCps); + int8_t (*GetNumberOfLimitCheck)( + uint16_t *pNumberOfLimitCheck); + int8_t (*GetLimitCheckInfo)(struct vl_data *Dev, + uint16_t LimitCheckId, char *pLimitCheckString); + int8_t (*SetLimitCheckEnable)(struct vl_data *Dev, + uint16_t LimitCheckId, + uint8_t LimitCheckEnable); + int8_t (*GetLimitCheckEnable)(struct vl_data *Dev, + uint16_t LimitCheckId, uint8_t *pLimitCheckEnable); + int8_t (*SetLimitCheckValue)(struct vl_data *Dev, + uint16_t LimitCheckId, + unsigned int LimitCheckValue); + int8_t (*GetLimitCheckValue)(struct vl_data *Dev, + uint16_t LimitCheckId, + unsigned int *pLimitCheckValue); + int8_t (*GetLimitCheckCurrent)(struct vl_data *Dev, + uint16_t LimitCheckId, unsigned int *pLimitCheckCurrent); + int8_t (*SetWrapAroundCheckEnable)(struct vl_data *Dev, + uint8_t WrapAroundCheckEnable); + int8_t (*GetWrapAroundCheckEnable)(struct vl_data *Dev, + uint8_t *pWrapAroundCheckEnable); + int8_t (*PerformSingleMeasurement)(struct vl_data *Dev); + int8_t (*PerformRefCalibration)(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + int8_t (*SetRefCalibration)(struct vl_data *Dev, + uint8_t VhvSettings, uint8_t PhaseCal); + int8_t (*GetRefCalibration)(struct vl_data *Dev, + uint8_t *pVhvSettings, uint8_t *pPhaseCal); + int8_t (*PerformXTalkCalibration)(struct vl_data *Dev, + unsigned int XTalkCalDistance, + unsigned int *pXTalkCompensationRateMegaCps); + int8_t (*PerformOffsetCalibration)(struct vl_data *Dev, + unsigned int CalDistanceMilliMeter, + int32_t *pOffsetMicroMeter); + int8_t (*StartMeasurement)(struct vl_data *Dev); + int8_t (*StopMeasurement)(struct vl_data *Dev); + int8_t (*GetMeasurementDataReady)(struct vl_data *Dev, + uint8_t *pMeasurementDataReady); + int8_t (*WaitDeviceReadyForNewMeasurement)(struct vl_data *Dev, + uint32_t MaxLoop); + int8_t (*GetRangingMeasurementData)(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + int8_t (*GetHistogramMeasurementData)(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + int8_t (*PerformSingleRangingMeasurement)(struct vl_data *Dev, + struct VL_RangingMeasurementData_t *pRangingMeasurementData); + int8_t (*PerformSingleHistogramMeasurement)(struct vl_data *Dev, + struct VL_HistogramMeasurementData_t *pHistogramMeasurementData); + int8_t (*SetNumberOfROIZones)(struct vl_data *Dev, + uint8_t NumberOfROIZones); + int8_t (*GetNumberOfROIZones)(struct vl_data *Dev, + uint8_t *pNumberOfROIZones); + int8_t (*GetMaxNumberOfROIZones)(struct vl_data *Dev, + uint8_t *pMaxNumberOfROIZones); + int8_t (*SetGpioConfig)(struct vl_data *Dev, + uint8_t Pin, + uint8_t DeviceMode, + uint8_t Functionality, + uint8_t Polarity); + int8_t (*GetGpioConfig)(struct vl_data *Dev, + uint8_t Pin, + uint8_t *pDeviceMode, + uint8_t *pFunctionality, + uint8_t *pPolarity); + int8_t (*SetInterruptThresholds)(struct vl_data *Dev, + uint8_t DeviceMode, + unsigned int ThresholdLow, + unsigned int ThresholdHigh); + int8_t (*GetInterruptThresholds)(struct vl_data *Dev, + uint8_t DeviceMode, + unsigned int *pThresholdLow, + unsigned int *pThresholdHigh); + int8_t (*ClearInterruptMask)(struct vl_data *Dev, + uint32_t InterruptMask); + int8_t (*GetInterruptMaskStatus)(struct vl_data *Dev, + uint32_t *pInterruptMaskStatus); + int8_t (*EnableInterruptMask)(struct vl_data *Dev, + uint32_t InterruptMask); + int8_t (*SetSpadAmbientDamperThreshold)(struct vl_data *Dev, + uint16_t SpadAmbientDamperThreshold); + int8_t (*GetSpadAmbientDamperThreshold)(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperThreshold); + int8_t (*SetSpadAmbientDamperFactor)(struct vl_data *Dev, + uint16_t SpadAmbientDamperFactor); + int8_t (*GetSpadAmbientDamperFactor)(struct vl_data *Dev, + uint16_t *pSpadAmbientDamperFactor); + int8_t (*PerformRefSpadManagement)(struct vl_data *Dev, + uint32_t *refSpadCount, uint8_t *isApertureSpads); + int8_t (*SetReferenceSpads)(struct vl_data *Dev, + uint32_t count, uint8_t isApertureSpads); + int8_t (*GetReferenceSpads)(struct vl_data *Dev, + uint32_t *pSpadCount, uint8_t *pIsApertureSpads); +}; + +static struct stmvl53l0x_api_fn_t stmvl53l0x_api_func_tbl = { + .GetVersion = VL_GetVersion, + .GetPalSpecVersion = VL_GetPalSpecVersion, + .GetProductRevision = VL_GetProductRevision, + .GetDeviceInfo = VL_GetDeviceInfo, + .GetDeviceErrorStatus = VL_GetDeviceErrorStatus, + .GetRangeStatusString = VL_GetRangeStatusString, + .GetDeviceErrorString = VL_GetDeviceErrorString, + .GetPalErrorString = VL_GetPalErrorString, + .GetPalState = VL_GetPalState, + .SetPowerMode = VL_SetPowerMode, + .GetPowerMode = VL_GetPowerMode, + .SetOffsetCalibrationDataMicroMeter = + VL_SetOffsetCalibrationDataMicroMeter, + .SetLinearityCorrectiveGain = + VL_SetLinearityCorrectiveGain, + .GetLinearityCorrectiveGain = + VL_GetLinearityCorrectiveGain, + .GetOffsetCalibrationDataMicroMeter = + VL_GetOffsetCalibrationDataMicroMeter, + .SetGroupParamHold = VL_SetGroupParamHold, + .GetUpperLimitMilliMeter = VL_GetUpperLimitMilliMeter, + .SetDeviceAddress = VL_SetDeviceAddress, + .DataInit = VL_DataInit, + .SetTuningSettingBuffer = VL_SetTuningSettingBuffer, + .GetTuningSettingBuffer = VL_GetTuningSettingBuffer, + .StaticInit = VL_StaticInit, + .WaitDeviceBooted = VL_WaitDeviceBooted, + .ResetDevice = VL_ResetDevice, + .SetDeviceParameters = VL_SetDeviceParameters, + .SetDeviceMode = VL_SetDeviceMode, + .GetDeviceMode = VL_GetDeviceMode, + .SetHistogramMode = VL_SetHistogramMode, + .GetHistogramMode = VL_GetHistogramMode, + .SetMeasurementTimingBudgetMicroSeconds = + VL_SetMeasurementTimingBudgetMicroSeconds, + .GetMeasurementTimingBudgetMicroSeconds = + VL_GetMeasurementTimingBudgetMicroSeconds, + .GetVcselPulsePeriod = VL_GetVcselPulsePeriod, + .SetVcselPulsePeriod = VL_SetVcselPulsePeriod, + .SetSequenceStepEnable = VL_SetSequenceStepEnable, + .GetSequenceStepEnable = VL_GetSequenceStepEnable, + .GetSequenceStepEnables = VL_GetSequenceStepEnables, + .SetSequenceStepTimeout = VL_SetSequenceStepTimeout, + .GetSequenceStepTimeout = VL_GetSequenceStepTimeout, + .GetNumberOfSequenceSteps = VL_GetNumberOfSequenceSteps, + .GetSequenceStepsInfo = VL_GetSequenceStepsInfo, + .SetInterMeasurementPeriodMilliSeconds = + VL_SetInterMeasurementPeriodMilliSeconds, + .GetInterMeasurementPeriodMilliSeconds = + VL_GetInterMeasurementPeriodMilliSeconds, + .SetXTalkCompensationEnable = VL_SetXTalkCompensationEnable, + .GetXTalkCompensationEnable = VL_GetXTalkCompensationEnable, + .SetXTalkCompensationRateMegaCps = + VL_SetXTalkCompensationRateMegaCps, + .GetXTalkCompensationRateMegaCps = + VL_GetXTalkCompensationRateMegaCps, + .GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck, + .GetLimitCheckInfo = VL_GetLimitCheckInfo, + .SetLimitCheckEnable = VL_SetLimitCheckEnable, + .GetLimitCheckEnable = VL_GetLimitCheckEnable, + .SetLimitCheckValue = VL_SetLimitCheckValue, + .GetLimitCheckValue = VL_GetLimitCheckValue, + .GetLimitCheckCurrent = VL_GetLimitCheckCurrent, + .SetWrapAroundCheckEnable = VL_SetWrapAroundCheckEnable, + .GetWrapAroundCheckEnable = VL_GetWrapAroundCheckEnable, + .PerformSingleMeasurement = VL_PerformSingleMeasurement, + .PerformRefCalibration = VL_PerformRefCalibration, + .SetRefCalibration = VL_SetRefCalibration, + .GetRefCalibration = VL_GetRefCalibration, + .PerformXTalkCalibration = VL_PerformXTalkCalibration, + .PerformOffsetCalibration = VL_PerformOffsetCalibration, + .StartMeasurement = VL_StartMeasurement, + .StopMeasurement = VL_StopMeasurement, + .GetMeasurementDataReady = VL_GetMeasurementDataReady, + .WaitDeviceReadyForNewMeasurement = + VL_WaitDeviceReadyForNewMeasurement, + .GetRangingMeasurementData = VL_GetRangingMeasurementData, + .GetHistogramMeasurementData = VL_GetHistogramMeasurementData, + .PerformSingleRangingMeasurement = + VL_PerformSingleRangingMeasurement, + .PerformSingleHistogramMeasurement = + VL_PerformSingleHistogramMeasurement, + .SetNumberOfROIZones = VL_SetNumberOfROIZones, + .GetNumberOfROIZones = VL_GetNumberOfROIZones, + .GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones, + .SetGpioConfig = VL_SetGpioConfig, + .GetGpioConfig = VL_GetGpioConfig, + .SetInterruptThresholds = VL_SetInterruptThresholds, + .GetInterruptThresholds = VL_GetInterruptThresholds, + .ClearInterruptMask = VL_ClearInterruptMask, + .GetInterruptMaskStatus = VL_GetInterruptMaskStatus, + .EnableInterruptMask = VL_EnableInterruptMask, + .SetSpadAmbientDamperThreshold = VL_SetSpadAmbientDamperThreshold, + .GetSpadAmbientDamperThreshold = VL_GetSpadAmbientDamperThreshold, + .SetSpadAmbientDamperFactor = VL_SetSpadAmbientDamperFactor, + .GetSpadAmbientDamperFactor = VL_GetSpadAmbientDamperFactor, + .PerformRefSpadManagement = VL_PerformRefSpadManagement, + .SetReferenceSpads = VL_SetReferenceSpads, + .GetReferenceSpads = VL_GetReferenceSpads, + +}; +struct stmvl53l0x_api_fn_t *papi_func_tbl; + +/* + * IOCTL definitions + */ +#define VL_IOCTL_INIT _IO('p', 0x01) +#define VL_IOCTL_XTALKCALB _IOW('p', 0x02, unsigned int) +#define VL_IOCTL_OFFCALB _IOW('p', 0x03, unsigned int) +#define VL_IOCTL_STOP _IO('p', 0x05) +#define VL_IOCTL_SETXTALK _IOW('p', 0x06, unsigned int) +#define VL_IOCTL_SETOFFSET _IOW('p', 0x07, int8_t) +#define VL_IOCTL_GETDATAS \ + _IOR('p', 0x0b, struct VL_RangingMeasurementData_t) +#define VL_IOCTL_REGISTER \ + _IOWR('p', 0x0c, struct stmvl53l0x_register) +#define VL_IOCTL_PARAMETER \ + _IOWR('p', 0x0d, struct stmvl53l0x_parameter) + +static long stmvl53l0x_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +/*static int stmvl53l0x_flush(struct file *file, fl_owner_t id);*/ +static int stmvl53l0x_open(struct inode *inode, struct file *file); +static int stmvl53l0x_init_client(struct vl_data *data); +static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling, + enum init_mode_e mode); +static int stmvl53l0x_stop(struct vl_data *data); + +#ifdef DEBUG_TIME_LOG +static void stmvl53l0x_DebugTimeGet(struct timeval *ptv) +{ + do_gettimeofday(ptv); +} + +static void stmvl53l0x_DebugTimeDuration(struct timeval *pstart_tv, + struct timeval *pstop_tv) +{ + long total_sec, total_msec; + + total_sec = pstop_tv->tv_sec - pstart_tv->tv_sec; + total_msec = (pstop_tv->tv_usec - pstart_tv->tv_usec)/1000; + total_msec += total_sec * 1000; + dbg("elapsedTime:%ld\n", total_msec); +} +#endif + +static void stmvl53l0x_setupAPIFunctions(void) +{ + + /*cut 1.1*/ + err("to setup API cut 1.1\n"); + papi_func_tbl->GetVersion = VL_GetVersion; + papi_func_tbl->GetPalSpecVersion = VL_GetPalSpecVersion; + papi_func_tbl->GetProductRevision = VL_GetProductRevision; + papi_func_tbl->GetDeviceInfo = VL_GetDeviceInfo; + papi_func_tbl->GetDeviceErrorStatus = VL_GetDeviceErrorStatus; + papi_func_tbl->GetRangeStatusString = VL_GetRangeStatusString; + papi_func_tbl->GetDeviceErrorString = VL_GetDeviceErrorString; + papi_func_tbl->GetPalErrorString = VL_GetPalErrorString; + papi_func_tbl->GetPalState = VL_GetPalState; + papi_func_tbl->SetPowerMode = VL_SetPowerMode; + papi_func_tbl->GetPowerMode = VL_GetPowerMode; + papi_func_tbl->SetOffsetCalibrationDataMicroMeter = + VL_SetOffsetCalibrationDataMicroMeter; + papi_func_tbl->GetOffsetCalibrationDataMicroMeter = + VL_GetOffsetCalibrationDataMicroMeter; + papi_func_tbl->SetLinearityCorrectiveGain = + VL_SetLinearityCorrectiveGain; + papi_func_tbl->GetLinearityCorrectiveGain = + VL_GetLinearityCorrectiveGain; + papi_func_tbl->SetGroupParamHold = VL_SetGroupParamHold; + papi_func_tbl->GetUpperLimitMilliMeter = + VL_GetUpperLimitMilliMeter; + papi_func_tbl->SetDeviceAddress = VL_SetDeviceAddress; + papi_func_tbl->DataInit = VL_DataInit; + papi_func_tbl->SetTuningSettingBuffer = VL_SetTuningSettingBuffer; + papi_func_tbl->GetTuningSettingBuffer = VL_GetTuningSettingBuffer; + papi_func_tbl->StaticInit = VL_StaticInit; + papi_func_tbl->WaitDeviceBooted = VL_WaitDeviceBooted; + papi_func_tbl->ResetDevice = VL_ResetDevice; + papi_func_tbl->SetDeviceParameters = VL_SetDeviceParameters; + papi_func_tbl->SetDeviceMode = VL_SetDeviceMode; + papi_func_tbl->GetDeviceMode = VL_GetDeviceMode; + papi_func_tbl->SetHistogramMode = VL_SetHistogramMode; + papi_func_tbl->GetHistogramMode = VL_GetHistogramMode; + papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds = + VL_SetMeasurementTimingBudgetMicroSeconds; + papi_func_tbl->GetMeasurementTimingBudgetMicroSeconds = + VL_GetMeasurementTimingBudgetMicroSeconds; + papi_func_tbl->GetVcselPulsePeriod = VL_GetVcselPulsePeriod; + papi_func_tbl->SetVcselPulsePeriod = VL_SetVcselPulsePeriod; + papi_func_tbl->SetSequenceStepEnable = VL_SetSequenceStepEnable; + papi_func_tbl->GetSequenceStepEnable = VL_GetSequenceStepEnable; + papi_func_tbl->GetSequenceStepEnables = VL_GetSequenceStepEnables; + papi_func_tbl->SetSequenceStepTimeout = VL_SetSequenceStepTimeout; + papi_func_tbl->GetSequenceStepTimeout = VL_GetSequenceStepTimeout; + papi_func_tbl->GetNumberOfSequenceSteps = + VL_GetNumberOfSequenceSteps; + papi_func_tbl->GetSequenceStepsInfo = VL_GetSequenceStepsInfo; + papi_func_tbl->SetInterMeasurementPeriodMilliSeconds = + VL_SetInterMeasurementPeriodMilliSeconds; + papi_func_tbl->GetInterMeasurementPeriodMilliSeconds = + VL_GetInterMeasurementPeriodMilliSeconds; + papi_func_tbl->SetXTalkCompensationEnable = + VL_SetXTalkCompensationEnable; + papi_func_tbl->GetXTalkCompensationEnable = + VL_GetXTalkCompensationEnable; + papi_func_tbl->SetXTalkCompensationRateMegaCps = + VL_SetXTalkCompensationRateMegaCps; + papi_func_tbl->GetXTalkCompensationRateMegaCps = + VL_GetXTalkCompensationRateMegaCps; + papi_func_tbl->GetNumberOfLimitCheck = VL_GetNumberOfLimitCheck; + papi_func_tbl->GetLimitCheckInfo = VL_GetLimitCheckInfo; + papi_func_tbl->SetLimitCheckEnable = VL_SetLimitCheckEnable; + papi_func_tbl->GetLimitCheckEnable = VL_GetLimitCheckEnable; + papi_func_tbl->SetLimitCheckValue = VL_SetLimitCheckValue; + papi_func_tbl->GetLimitCheckValue = VL_GetLimitCheckValue; + papi_func_tbl->GetLimitCheckCurrent = VL_GetLimitCheckCurrent; + papi_func_tbl->SetWrapAroundCheckEnable = + VL_SetWrapAroundCheckEnable; + papi_func_tbl->GetWrapAroundCheckEnable = + VL_GetWrapAroundCheckEnable; + papi_func_tbl->PerformSingleMeasurement = + VL_PerformSingleMeasurement; + papi_func_tbl->PerformRefCalibration = VL_PerformRefCalibration; + papi_func_tbl->SetRefCalibration = VL_SetRefCalibration; + papi_func_tbl->GetRefCalibration = VL_GetRefCalibration; + papi_func_tbl->PerformXTalkCalibration = + VL_PerformXTalkCalibration; + papi_func_tbl->PerformOffsetCalibration = + VL_PerformOffsetCalibration; + papi_func_tbl->StartMeasurement = VL_StartMeasurement; + papi_func_tbl->StopMeasurement = VL_StopMeasurement; + papi_func_tbl->GetMeasurementDataReady = + VL_GetMeasurementDataReady; + papi_func_tbl->WaitDeviceReadyForNewMeasurement = + VL_WaitDeviceReadyForNewMeasurement; + papi_func_tbl->GetRangingMeasurementData = + VL_GetRangingMeasurementData; + papi_func_tbl->GetHistogramMeasurementData = + VL_GetHistogramMeasurementData; + papi_func_tbl->PerformSingleRangingMeasurement = + VL_PerformSingleRangingMeasurement; + papi_func_tbl->PerformSingleHistogramMeasurement = + VL_PerformSingleHistogramMeasurement; + papi_func_tbl->SetNumberOfROIZones = VL_SetNumberOfROIZones; + papi_func_tbl->GetNumberOfROIZones = VL_GetNumberOfROIZones; + papi_func_tbl->GetMaxNumberOfROIZones = VL_GetMaxNumberOfROIZones; + papi_func_tbl->SetGpioConfig = VL_SetGpioConfig; + papi_func_tbl->GetGpioConfig = VL_GetGpioConfig; + papi_func_tbl->SetInterruptThresholds = VL_SetInterruptThresholds; + papi_func_tbl->GetInterruptThresholds = VL_GetInterruptThresholds; + papi_func_tbl->ClearInterruptMask = VL_ClearInterruptMask; + papi_func_tbl->GetInterruptMaskStatus = VL_GetInterruptMaskStatus; + papi_func_tbl->EnableInterruptMask = VL_EnableInterruptMask; + papi_func_tbl->SetSpadAmbientDamperThreshold = + VL_SetSpadAmbientDamperThreshold; + papi_func_tbl->GetSpadAmbientDamperThreshold = + VL_GetSpadAmbientDamperThreshold; + papi_func_tbl->SetSpadAmbientDamperFactor = + VL_SetSpadAmbientDamperFactor; + papi_func_tbl->GetSpadAmbientDamperFactor = + VL_GetSpadAmbientDamperFactor; + papi_func_tbl->PerformRefSpadManagement = + VL_PerformRefSpadManagement; + papi_func_tbl->SetReferenceSpads = VL_SetReferenceSpads; + papi_func_tbl->GetReferenceSpads = VL_GetReferenceSpads; + +} + +static void stmvl53l0x_ps_read_measurement(struct vl_data *data) +{ + struct timeval tv; + struct vl_data *vl53l0x_dev = data; + int8_t Status = VL_ERROR_NONE; + unsigned int LimitCheckCurrent; + + do_gettimeofday(&tv); + + data->ps_data = data->rangeData.RangeMilliMeter; + input_report_abs(data->input_dev_ps, ABS_DISTANCE, + (int)(data->ps_data + 5) / 10); + input_report_abs(data->input_dev_ps, ABS_HAT0X, tv.tv_sec); + input_report_abs(data->input_dev_ps, ABS_HAT0Y, tv.tv_usec); + input_report_abs(data->input_dev_ps, ABS_HAT1X, + data->rangeData.RangeMilliMeter); + input_report_abs(data->input_dev_ps, ABS_HAT1Y, + data->rangeData.RangeStatus); + input_report_abs(data->input_dev_ps, ABS_HAT2X, + data->rangeData.SignalRateRtnMegaCps); + input_report_abs(data->input_dev_ps, ABS_HAT2Y, + data->rangeData.AmbientRateRtnMegaCps); + input_report_abs(data->input_dev_ps, ABS_HAT3X, + data->rangeData.MeasurementTimeUsec); + input_report_abs(data->input_dev_ps, ABS_HAT3Y, + data->rangeData.RangeDMaxMilliMeter); + Status = papi_func_tbl->GetLimitCheckCurrent(vl53l0x_dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + &LimitCheckCurrent); + if (Status == VL_ERROR_NONE) { + input_report_abs(data->input_dev_ps, ABS_WHEEL, + LimitCheckCurrent); + } + input_report_abs(data->input_dev_ps, ABS_PRESSURE, + data->rangeData.EffectiveSpadRtnCount); + input_sync(data->input_dev_ps); + + if (data->enableDebug) + err("range:%d, RtnRateMcps:%d,err:0x%x\n", + data->rangeData.RangeMilliMeter, + data->rangeData.SignalRateRtnMegaCps, + data->rangeData.RangeStatus); + err("Dmax:%d,rtnambr:%d,time:%d,Spad:%d,SigmaLimit:%d\n", + data->rangeData.RangeDMaxMilliMeter, + data->rangeData.AmbientRateRtnMegaCps, + data->rangeData.MeasurementTimeUsec, + data->rangeData.EffectiveSpadRtnCount, + LimitCheckCurrent); + + +} + +static void stmvl53l0x_cancel_handler(struct vl_data *data) +{ + unsigned long flags; + bool ret; + + spin_lock_irqsave(&data->update_lock.wait_lock, flags); + /* + * If work is already scheduled then subsequent schedules will not + * change the scheduled time that's why we have to cancel it first. + */ + ret = cancel_delayed_work(&data->dwork); + if (ret == 0) + err("cancel_delayed_work return FALSE\n"); + + spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); + +} + +void stmvl53l0x_schedule_handler(struct vl_data *data) +{ + unsigned long flags; + + spin_lock_irqsave(&data->update_lock.wait_lock, flags); + /* + * If work is already scheduled then subsequent schedules will not + * change the scheduled time that's why we have to cancel it first. + */ + cancel_delayed_work(&data->dwork); + schedule_delayed_work(&data->dwork, 0); + spin_unlock_irqrestore(&data->update_lock.wait_lock, flags); + +} + +/* Flag used to exit the thread when kthread_stop() is invoked */ +static int poll_thread_exit; +int stmvl53l0x_poll_thread(void *data) +{ + struct vl_data *vl53l0x_dev = data; + int8_t Status = VL_ERROR_NONE; + uint32_t sleep_time = 0; + uint32_t interruptStatus = 0; + + dbg("Starting Polling thread\n"); + + while (!kthread_should_stop()) { + /* Check if enable_ps_sensor is true or */ + /* exit request is made. If not block */ + wait_event(vl53l0x_dev->poll_thread_wq, + (vl53l0x_dev->enable_ps_sensor || poll_thread_exit)); + if (poll_thread_exit) { + dbg("Exiting the poll thread\n"); + break; + } + + mutex_lock(&vl53l0x_dev->work_mutex); + + sleep_time = vl53l0x_dev->delay_ms; + Status = VL_GetInterruptMaskStatus(vl53l0x_dev, + &interruptStatus); + if (Status == VL_ERROR_NONE && + interruptStatus && + interruptStatus != vl53l0x_dev->interruptStatus) { + vl53l0x_dev->interruptStatus = interruptStatus; + vl53l0x_dev->noInterruptCount = 0; + stmvl53l0x_schedule_handler(vl53l0x_dev); + + } else { + vl53l0x_dev->noInterruptCount++; + } + + /* Force Clear interrupt mask and restart if no interrupt */ + /* after twice the timingBudget */ + if ((vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms) > + (vl53l0x_dev->timingBudget * 2)) { + dbg("No interrupt after (%u) msec(TimingBudget = %u)\n", + (vl53l0x_dev->noInterruptCount * vl53l0x_dev->delay_ms), + vl53l0x_dev->timingBudget); + Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0); + if (vl53l0x_dev->deviceMode == + VL_DEVICEMODE_SINGLE_RANGING) { + Status = papi_func_tbl->StartMeasurement(vl53l0x_dev); + if (Status != VL_ERROR_NONE) + dbg("Status = %d\n", Status); + } + } + + mutex_unlock(&vl53l0x_dev->work_mutex); + + msleep(sleep_time); + } + + return 0; +} + +/* work handler */ +static void stmvl53l0x_work_handler(struct work_struct *work) +{ + struct vl_data *data = container_of(work, + struct vl_data, dwork.work); + + struct vl_data *vl53l0x_dev = data; + + int8_t Status = VL_ERROR_NONE; + + mutex_lock(&data->work_mutex); + /* dbg("Enter\n"); */ + + + if (vl53l0x_dev->enable_ps_sensor == 1) { +#ifdef DEBUG_TIME_LOG + stmvl53l0x_DebugTimeGet(&stop_tv); + stmvl53l0x_DebugTimeDuration(&start_tv, &stop_tv); +#endif + /* ISR has scheduled this function */ + if (vl53l0x_dev->interrupt_received == 1) { + Status = papi_func_tbl->GetInterruptMaskStatus( + vl53l0x_dev, &vl53l0x_dev->interruptStatus); + if (Status != VL_ERROR_NONE) { + dbg("%s(%d) : Status = %d\n", + __func__, __LINE__, Status); + } + vl53l0x_dev->interrupt_received = 0; + } + if (data->enableDebug) + dbg("interruptStatus:0x%x, interrupt_received:%d\n", + vl53l0x_dev->interruptStatus, + vl53l0x_dev->interrupt_received); + + if (vl53l0x_dev->interruptStatus == + vl53l0x_dev->gpio_function) { + Status = papi_func_tbl->ClearInterruptMask(vl53l0x_dev, + 0); + if (Status != VL_ERROR_NONE) { + dbg("%s(%d) : Status = %d\n", + __func__, __LINE__, Status); + } else { + Status = + papi_func_tbl->GetRangingMeasurementData( + vl53l0x_dev, &(data->rangeData)); + /* to push the measurement */ + if (Status == VL_ERROR_NONE) + stmvl53l0x_ps_read_measurement(data); + else + dbg("%s(%d) : Status = %d\n", + __func__, __LINE__, Status); + + dbg("Measured range:%d\n", + data->rangeData.RangeMilliMeter); + + if (data->enableDebug) + dbg("Measured range:%d\n", + data->rangeData.RangeMilliMeter); + + if (data->deviceMode == + VL_DEVICEMODE_SINGLE_RANGING) + Status = + papi_func_tbl->StartMeasurement( + vl53l0x_dev); + } + } +#ifdef DEBUG_TIME_LOG + stmvl53l0x_DebugTimeGet(&start_tv); +#endif + + } + + + vl53l0x_dev->interruptStatus = 0; + + mutex_unlock(&data->work_mutex); + +} + + +/* + * SysFS support + */ +static ssize_t stmvl53l0x_show_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enable_ps_sensor); +} + +static ssize_t stmvl53l0x_store_enable_ps_sensor(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + + unsigned int val; + + kstrtoint(buf, 10, &val); + if ((val != 0) && (val != 1)) { + err("store unvalid value=%ld\n", val); + return count; + } + mutex_lock(&data->work_mutex); + dbg("Enter, enable_ps_sensor flag:%d\n", + data->enable_ps_sensor); + dbg("enable ps senosr ( %ld)\n", val); + + if (val == 1) { + /* turn on tof sensor */ + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, NORMAL_MODE); + } else { + err("Already enabled. Skip !"); + } + } else { + /* turn off tof sensor */ + if (data->enable_ps_sensor == 1) { + data->enable_ps_sensor = 0; + /* to stop */ + stmvl53l0x_stop(data); + } + } + dbg("End\n"); + mutex_unlock(&data->work_mutex); + + return count; +} + +static DEVICE_ATTR(enable_ps_sensor, 0664/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_enable_ps_sensor, + stmvl53l0x_store_enable_ps_sensor); + +static ssize_t stmvl53l0x_show_enable_debug(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->enableDebug); +} + +/* for debug */ +static ssize_t stmvl53l0x_store_enable_debug(struct device *dev, + struct device_attribute *attr, const + char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int on; + + kstrtoint(buf, 10, &on); + if ((on != 0) && (on != 1)) { + err("set debug=%ld\n", on); + return count; + } + data->enableDebug = on; + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(enable_debug, 0660/*S_IWUSR | S_IRUGO*/, + stmvl53l0x_show_enable_debug, + stmvl53l0x_store_enable_debug); + +static ssize_t stmvl53l0x_show_set_delay_ms(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->delay_ms); +} + +/* for work handler scheduler time */ +static ssize_t stmvl53l0x_store_set_delay_ms(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int delay_ms; + + kstrtoint(buf, 10, &delay_ms); + if (delay_ms == 0) { + err("set delay_ms=%ld\n", delay_ms); + return count; + } + mutex_lock(&data->work_mutex); + data->delay_ms = delay_ms; + mutex_unlock(&data->work_mutex); + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_delay_ms, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_set_delay_ms, + stmvl53l0x_store_set_delay_ms); + +/* Timing Budget */ +static ssize_t stmvl53l0x_show_timing_budget(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 10, "%d\n", data->timingBudget); +} + +static ssize_t stmvl53l0x_store_set_timing_budget(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int timingBudget; + + kstrtoint(buf, 10, &timingBudget); + if (timingBudget == 0) { + err("set timingBudget=%ld\n", timingBudget); + return count; + } + mutex_lock(&data->work_mutex); + data->timingBudget = timingBudget; + mutex_unlock(&data->work_mutex); + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_timing_budget, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_timing_budget, + stmvl53l0x_store_set_timing_budget); + + +/* Long Range */ +static ssize_t stmvl53l0x_show_long_range(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + + return snprintf(buf, 5, "%d\n", data->useLongRange); +} + +static ssize_t stmvl53l0x_store_set_long_range(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + int useLongRange; + + kstrtoint(buf, 10, &useLongRange); + if ((useLongRange != 0) && (useLongRange != 1)) { + err("set useLongRange=%ld\n", useLongRange); + return count; + } + + mutex_lock(&data->work_mutex); + data->useLongRange = useLongRange; + if (useLongRange) + data->timingBudget = 26000; + else + data->timingBudget = 200000; + + mutex_unlock(&data->work_mutex); + + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(set_long_range, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_long_range, + stmvl53l0x_store_set_long_range); + +static ssize_t stmvl53l0x_show_meter(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + struct VL_RangingMeasurementData_t Measure; + + papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); + dbg("Measure = %d\n", Measure.RangeMilliMeter); + return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(show_meter, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_meter, + NULL); + +static ssize_t stmvl53l0x_show_xtalk(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + struct VL_RangingMeasurementData_t Measure; + + dbg("Measure = %d\n", Measure.RangeMilliMeter); + return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); +} + +static ssize_t stmvl53l0x_set_xtalk(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + unsigned int targetDistance; + + kstrtoint(buf, 10, &targetDistance); + data->xtalkCalDistance = targetDistance; + stmvl53l0x_start(data, 3, XTALKCALIB_MODE); + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(xtalk_cal, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_xtalk, + stmvl53l0x_set_xtalk); + +static ssize_t stmvl53l0x_show_offset(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct vl_data *data = dev_get_drvdata(dev); + struct VL_RangingMeasurementData_t Measure; + + papi_func_tbl->PerformSingleRangingMeasurement(data, &Measure); + dbg("Measure = %d\n", Measure.RangeMilliMeter); + return snprintf(buf, 4, "%d\n", Measure.RangeMilliMeter); +} + +static ssize_t stmvl53l0x_set_offset(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct vl_data *data = dev_get_drvdata(dev); + unsigned int targetDistance; + + kstrtoint(buf, 10, &targetDistance); + data->offsetCalDistance = targetDistance; + stmvl53l0x_start(data, 3, OFFSETCALIB_MODE); + return count; +} + +/* DEVICE_ATTR(name,mode,show,store) */ +static DEVICE_ATTR(offset_cal, 0660/*S_IWUGO | S_IRUGO*/, + stmvl53l0x_show_offset, + stmvl53l0x_set_offset); + +static struct attribute *stmvl53l0x_attributes[] = { + &dev_attr_enable_ps_sensor.attr, + &dev_attr_enable_debug.attr, + &dev_attr_set_delay_ms.attr, + &dev_attr_set_timing_budget.attr, + &dev_attr_set_long_range.attr, + &dev_attr_show_meter.attr, + &dev_attr_xtalk_cal.attr, + &dev_attr_offset_cal.attr, + NULL, +}; + + +static const struct attribute_group stmvl53l0x_attr_group = { + .attrs = stmvl53l0x_attributes, +}; + +/* + * misc device file operation functions + */ +static int stmvl53l0x_ioctl_handler(struct file *file, + unsigned int cmd, unsigned long arg, + void __user *p) +{ + int rc = 0; + unsigned int xtalkint = 0; + unsigned int targetDistance = 0; + int8_t offsetint = 0; + struct vl_data *data = + container_of(file->private_data, + struct vl_data, miscdev); + struct stmvl53l0x_register reg; + struct stmvl53l0x_parameter parameter; + struct vl_data *vl53l0x_dev = data; + uint8_t deviceMode; + uint8_t page_num = 0; + + if (!data) + return -EINVAL; + + dbg("Enter enable_ps_sensor:%d\n", data->enable_ps_sensor); + switch (cmd) { + /* enable */ + case VL_IOCTL_INIT: + dbg("VL_IOCTL_INIT\n"); + /* turn on tof sensor only if it's not enabled by other */ + /* client */ + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, NORMAL_MODE); + } else + rc = -EINVAL; + break; + /* crosstalk calibration */ + case VL_IOCTL_XTALKCALB: + dbg("VL_IOCTL_XTALKCALB\n"); + data->xtalkCalDistance = 100; + if (copy_from_user(&targetDistance, (unsigned int *)p, + sizeof(unsigned int))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + data->xtalkCalDistance = targetDistance; + + /* turn on tof sensor only if it's not enabled by other */ + /* client */ + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, XTALKCALIB_MODE); + } else + rc = -EINVAL; + break; + /* set up Xtalk value */ + case VL_IOCTL_SETXTALK: + dbg("VL_IOCTL_SETXTALK\n"); + if (copy_from_user(&xtalkint, (unsigned int *)p, + sizeof(unsigned int))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + dbg("SETXTALK as 0x%x\n", xtalkint); +/* later + * SetXTalkCompensationRate(vl53l0x_dev, xtalkint); + */ + break; + /* offset calibration */ + case VL_IOCTL_OFFCALB: + dbg("VL_IOCTL_OFFCALB\n"); + data->offsetCalDistance = 50; + if (copy_from_user(&targetDistance, (unsigned int *)p, + sizeof(unsigned int))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + data->offsetCalDistance = targetDistance; + if (data->enable_ps_sensor == 0) { + /* to start */ + stmvl53l0x_start(data, 3, OFFSETCALIB_MODE); + } else + rc = -EINVAL; + break; + /* set up offset value */ + case VL_IOCTL_SETOFFSET: + dbg("VL_IOCTL_SETOFFSET\n"); + if (copy_from_user(&offsetint, (int8_t *)p, sizeof(int8_t))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + dbg("SETOFFSET as %d\n", offsetint); + /* later SetOffsetCalibrationData(vl53l0x_dev, offsetint); */ + break; + /* disable */ + case VL_IOCTL_STOP: + dbg("VL_IOCTL_STOP\n"); + /* turn off tof sensor only if it's enabled by other client */ + if (data->enable_ps_sensor == 1) { + data->enable_ps_sensor = 0; + /* to stop */ + stmvl53l0x_stop(data); + } + break; + /* Get all range data */ + case VL_IOCTL_GETDATAS: + dbg("VL_IOCTL_GETDATAS\n"); + if (copy_to_user((struct VL_RangingMeasurementData_t *)p, + &(data->rangeData), + sizeof(struct VL_RangingMeasurementData_t))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + break; + /* Register tool */ + case VL_IOCTL_REGISTER: + dbg("VL_IOCTL_REGISTER\n"); + if (copy_from_user(®, (struct stmvl53l0x_register *)p, + sizeof(struct stmvl53l0x_register))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + reg.status = 0; + page_num = (uint8_t)((reg.reg_index & 0x0000ff00) >> 8); + dbg( +"VL_IOCTL_REGISTER, page number:%d\n", page_num); + if (page_num != 0) + reg.status = VL_WrByte(vl53l0x_dev, + 0xFF, page_num); + + switch (reg.reg_bytes) { + case(4): + if (reg.is_read) + reg.status = VL_RdDWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + ®.reg_data); + else + reg.status = VL_WrDWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + reg.reg_data); + break; + case(2): + if (reg.is_read) + reg.status = VL_RdWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint16_t *)®.reg_data); + else + reg.status = VL_WrWord(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint16_t)reg.reg_data); + break; + case(1): + if (reg.is_read) + reg.status = VL_RdByte(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint8_t *)®.reg_data); + else + reg.status = VL_WrByte(vl53l0x_dev, + (uint8_t)reg.reg_index, + (uint8_t)reg.reg_data); + break; + default: + reg.status = -1; + + } + if (page_num != 0) + reg.status = VL_WrByte(vl53l0x_dev, 0xFF, 0); + + + if (copy_to_user((struct stmvl53l0x_register *)p, ®, + sizeof(struct stmvl53l0x_register))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + break; + /* parameter access */ + case VL_IOCTL_PARAMETER: + dbg("VL_IOCTL_PARAMETER\n"); + if (copy_from_user(¶meter, (struct stmvl53l0x_parameter *)p, + sizeof(struct stmvl53l0x_parameter))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + parameter.status = 0; + if (data->enableDebug) + dbg("VL_IOCTL_PARAMETER Name = %d\n", + parameter.name); + switch (parameter.name) { + case (OFFSET_PAR): + if (parameter.is_read) + parameter.status = + papi_func_tbl->GetOffsetCalibrationDataMicroMeter( + vl53l0x_dev, ¶meter.value); + else + parameter.status = + papi_func_tbl->SetOffsetCalibrationDataMicroMeter( + vl53l0x_dev, parameter.value); + dbg("get parameter value as %d\n", + parameter.value); + break; + + case (REFERENCESPADS_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetReferenceSpads(vl53l0x_dev, + (uint32_t *)&(parameter.value), + (uint8_t *)&(parameter.value2)); + if (data->enableDebug) + dbg("Get RefSpad: Count:%u, Type:%u\n", + parameter.value, (uint8_t)parameter.value2); + } else { + if (data->enableDebug) + dbg("Set RefSpad: Count:%u, Type:%u\n", + parameter.value, (uint8_t)parameter.value2); + + parameter.status = + papi_func_tbl->SetReferenceSpads( + vl53l0x_dev, + (uint32_t)(parameter.value), + (uint8_t)(parameter.value2)); + } + break; + + case (REFCALIBRATION_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetRefCalibration(vl53l0x_dev, + (uint8_t *)&(parameter.value), + (uint8_t *)&(parameter.value2)); + if (data->enableDebug) + dbg("Get Ref: Vhv:%u, PhaseCal:%u\n", + (uint8_t)parameter.value, + (uint8_t)parameter.value2); + } else { + if (data->enableDebug) + dbg("Set Ref: Vhv:%u, PhaseCal:%u\n", + (uint8_t)parameter.value, + (uint8_t)parameter.value2); + parameter.status = + papi_func_tbl->SetRefCalibration( + vl53l0x_dev, (uint8_t)(parameter.value), + (uint8_t)(parameter.value2)); + } + break; + case (XTALKRATE_PAR): + if (parameter.is_read) + parameter.status = + papi_func_tbl->GetXTalkCompensationRateMegaCps( + vl53l0x_dev, (unsigned int *) + ¶meter.value); + else + parameter.status = + papi_func_tbl->SetXTalkCompensationRateMegaCps( + vl53l0x_dev, + (unsigned int) + parameter.value); + + break; + case (XTALKENABLE_PAR): + if (parameter.is_read) + parameter.status = + papi_func_tbl->GetXTalkCompensationEnable( + vl53l0x_dev, + (uint8_t *) ¶meter.value); + else + parameter.status = + papi_func_tbl->SetXTalkCompensationEnable( + vl53l0x_dev, + (uint8_t) parameter.value); + break; + case (GPIOFUNC_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetGpioConfig(vl53l0x_dev, 0, + &deviceMode, + &data->gpio_function, + &data->gpio_polarity); + parameter.value = data->gpio_function; + } else { + data->gpio_function = parameter.value; + parameter.status = + papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0, + data->gpio_function, + data->gpio_polarity); + } + break; + case (LOWTHRESH_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetInterruptThresholds( + vl53l0x_dev, 0, &(data->low_threshold), + &(data->high_threshold)); + parameter.value = data->low_threshold >> 16; + } else { + data->low_threshold = parameter.value << 16; + parameter.status = + papi_func_tbl->SetInterruptThresholds( + vl53l0x_dev, 0, data->low_threshold, + data->high_threshold); + } + break; + case (HIGHTHRESH_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetInterruptThresholds( + vl53l0x_dev, 0, &(data->low_threshold), + &(data->high_threshold)); + parameter.value = data->high_threshold >> 16; + } else { + data->high_threshold = parameter.value << 16; + parameter.status = + papi_func_tbl->SetInterruptThresholds( + vl53l0x_dev, 0, data->low_threshold, + data->high_threshold); + } + break; + case (DEVICEMODE_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetDeviceMode( + vl53l0x_dev, + (uint8_t *)& + (parameter.value)); + } else { + parameter.status = + papi_func_tbl->SetDeviceMode( + vl53l0x_dev, + (uint8_t)(parameter.value)); + data->deviceMode = + (uint8_t)(parameter.value); + } + break; + + + + case (INTERMEASUREMENT_PAR): + if (parameter.is_read) { + parameter.status = + papi_func_tbl->GetInterMeasurementPeriodMilliSeconds( + vl53l0x_dev, (uint32_t *)&(parameter.value)); + } else { + parameter.status = + papi_func_tbl->SetInterMeasurementPeriodMilliSeconds( + vl53l0x_dev, (uint32_t)(parameter.value)); + data->interMeasurems = parameter.value; + } + break; + + } + + if (copy_to_user((struct stmvl53l0x_parameter *)p, ¶meter, + sizeof(struct stmvl53l0x_parameter))) { + err("%d, fail\n", __LINE__); + return -EFAULT; + } + break; + default: + rc = -EINVAL; + break; + } + + return rc; +} + +static int stmvl53l0x_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int stmvl53l0x_flush(struct file *file, fl_owner_t id) +{ + struct vl_data *data = container_of(file->private_data, + struct vl_data, miscdev); + (void) file; + (void) id; + + if (data) { + if (data->enable_ps_sensor == 1) { + /* turn off tof sensor if it's enabled */ + data->enable_ps_sensor = 0; + /* to stop */ + stmvl53l0x_stop(data); + } + } + return 0; +} + +static long stmvl53l0x_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long ret; + struct vl_data *data = + container_of(file->private_data, + struct vl_data, miscdev); + mutex_lock(&data->work_mutex); + ret = stmvl53l0x_ioctl_handler(file, cmd, arg, (void __user *)arg); + mutex_unlock(&data->work_mutex); + + return ret; +} + +/* + * Initialization function + */ +static int stmvl53l0x_init_client(struct vl_data *data) +{ + + int8_t Status = VL_ERROR_NONE; + struct VL_DeviceInfo_t DeviceInfo; + struct vl_data *vl53l0x_dev = data; + + uint32_t refSpadCount; + uint8_t isApertureSpads; + uint8_t VhvSettings; + uint8_t PhaseCal; + + dbg("Enter\n"); + + vl53l0x_dev->I2cDevAddr = 0x52; + vl53l0x_dev->comms_type = 1; + vl53l0x_dev->comms_speed_khz = 400; + + /* Setup API functions based on revision */ + stmvl53l0x_setupAPIFunctions(); + + if (Status == VL_ERROR_NONE && data->reset) { + dbg("Call of VL_DataInit\n"); + /* Data initialization */ + Status = papi_func_tbl->DataInit(vl53l0x_dev); + } + + if (Status == VL_ERROR_NONE) { + dbg("VL_GetDeviceInfo:\n"); + Status = papi_func_tbl->GetDeviceInfo(vl53l0x_dev, &DeviceInfo); + if (Status == VL_ERROR_NONE) { + dbg("Device Name : %s\n", DeviceInfo.Name); + dbg("Device Type : %s\n", DeviceInfo.Type); + dbg("Device ID : %s\n", DeviceInfo.ProductId); + dbg("Product type: %d\n", DeviceInfo.ProductType); + dbg("ProductRevisionMajor : %d\n", + DeviceInfo.ProductRevisionMajor); + dbg("ProductRevisionMinor : %d\n", + DeviceInfo.ProductRevisionMinor); + } + } + + if (Status == VL_ERROR_NONE) { + dbg("Call of VL_StaticInit\n"); + Status = papi_func_tbl->StaticInit(vl53l0x_dev); + /* Device Initialization */ + } + + if (Status == VL_ERROR_NONE && data->reset) { + if (papi_func_tbl->PerformRefCalibration != NULL) { + dbg("Call of VL_PerformRefCalibration\n"); + Status = papi_func_tbl->PerformRefCalibration( + vl53l0x_dev, &VhvSettings, &PhaseCal); + /* Ref calibration */ + } + } + + if (Status == VL_ERROR_NONE && data->reset) { + if (papi_func_tbl->PerformRefSpadManagement != NULL) { + dbg("Call of VL_PerformRefSpadManagement\n"); + Status = papi_func_tbl->PerformRefSpadManagement( + vl53l0x_dev, &refSpadCount, &isApertureSpads); + /* Ref Spad Management */ + } + data->reset = 0; + /* needed, even the function is NULL */ + } + + if (Status == VL_ERROR_NONE) { + + dbg("Call of VL_SetDeviceMode\n"); + Status = papi_func_tbl->SetDeviceMode(vl53l0x_dev, + VL_DEVICEMODE_SINGLE_RANGING); + /* Setup in single ranging mode */ + } + if (Status == VL_ERROR_NONE) + Status = papi_func_tbl->SetWrapAroundCheckEnable( + vl53l0x_dev, 1); + + dbg("End\n"); + + return 0; +} + +static int stmvl53l0x_start(struct vl_data *data, uint8_t scaling, + enum init_mode_e mode) +{ + int rc = 0; + struct vl_data *vl53l0x_dev = data; + int8_t Status = VL_ERROR_NONE; + + dbg("Enter\n"); + + /* Power up */ + rc = pmodule_func_tbl->power_up(data->client_object, &data->reset); + if (rc) { + err("%d,error rc %d\n", __LINE__, rc); + return rc; + } + /* init */ + rc = stmvl53l0x_init_client(data); + if (rc) { + err("%d, error rc %d\n", __LINE__, rc); + pmodule_func_tbl->power_down(data->client_object); + return -EINVAL; + } + + /* check mode */ + if (mode != NORMAL_MODE) + papi_func_tbl->SetXTalkCompensationEnable(vl53l0x_dev, 1); + + if (mode == OFFSETCALIB_MODE) { + /*VL_SetOffsetCalibrationDataMicroMeter(vl53l0x_dev, 0);*/ + unsigned int OffsetMicroMeter; + + papi_func_tbl->PerformOffsetCalibration(vl53l0x_dev, + (data->offsetCalDistance<<16), + &OffsetMicroMeter); + dbg("Offset calibration:%u\n", OffsetMicroMeter); + return rc; + } else if (mode == XTALKCALIB_MODE) { + unsigned int XTalkCompensationRateMegaCps; + /*caltarget distance : 100mm and convert to */ + /* fixed point 16 16 format */ + papi_func_tbl->PerformXTalkCalibration(vl53l0x_dev, + (data->xtalkCalDistance<<16), + &XTalkCompensationRateMegaCps); + dbg("Xtalk calibration:%u\n", XTalkCompensationRateMegaCps); + return rc; + } + /* set up device parameters */ + data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW; + + /* Following two calls are made from IOCTL as well */ + papi_func_tbl->SetGpioConfig(vl53l0x_dev, 0, 0, + data->gpio_function, + VL_INTERRUPTPOLARITY_LOW); + + papi_func_tbl->SetInterruptThresholds(vl53l0x_dev, 0, + data->low_threshold, data->high_threshold); + + if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING) { + papi_func_tbl->SetInterMeasurementPeriodMilliSeconds( + vl53l0x_dev, data->interMeasurems); + } + + dbg("DeviceMode:0x%x, interMeasurems:%d==\n", data->deviceMode, + data->interMeasurems); + papi_func_tbl->SetDeviceMode(vl53l0x_dev, + data->deviceMode); + papi_func_tbl->ClearInterruptMask(vl53l0x_dev, + 0); + + if (vl53l0x_dev->useLongRange) { + dbg("Configure Long Ranging\n"); + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (unsigned int)(65536/10)); /* 0.1 * 65536 */ + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + (unsigned int)(60*65536)); + } else { + dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + dbg("Set Timing Budget = %u\n", + vl53l0x_dev->timingBudget); + Status = + papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds( + vl53l0x_dev, vl53l0x_dev->timingBudget); + } else { + dbg("SetLimitCheckValue failed err =%d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_PRE_RANGE, 18); + } else { + dbg("SetMeasurementTimingBudget failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_FINAL_RANGE, 14); + } else { + dbg("SetVcselPulsePeriod(PRE, 18) failed err = %d\n", + Status); + } + + if (Status != VL_ERROR_NONE) { + dbg("SetVcselPulsePeriod(FINAL, 14) failed err = %d\n", + Status); + } + } else { + dbg("Configure High Accuracy\n"); + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, + (unsigned int)(25 * 65536 / 100)); /* 0.25 * 65536 */ + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetLimitCheckValue(vl53l0x_dev, + VL_CHECKENABLE_SIGMA_FINAL_RANGE, + (unsigned int)(18*65536)); + } else { + dbg("SIGNAL_RATE_FINAL_RANGE failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + dbg("Set Timing Budget = %u\n", + vl53l0x_dev->timingBudget); + Status = + papi_func_tbl->SetMeasurementTimingBudgetMicroSeconds( + vl53l0x_dev, vl53l0x_dev->timingBudget); + } else { + dbg("SetLimitCheckValue failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_PRE_RANGE, 14); + } else { + dbg("SetMeasurementTimingBudget failed err = %d\n", + Status); + } + + if (Status == VL_ERROR_NONE) { + Status = papi_func_tbl->SetVcselPulsePeriod(vl53l0x_dev, + VL_VCSEL_PERIOD_FINAL_RANGE, 10); + } else { + dbg("SetVcselPulsePeriod failed err = %d\n", + Status); + } + + if (Status != VL_ERROR_NONE) { + dbg("SetVcselPulsePeriod failed err = %d\n", + Status); + } + + } + + /* start the ranging */ + papi_func_tbl->StartMeasurement(vl53l0x_dev); + data->enable_ps_sensor = 1; + + + dbg("End\n"); + + return rc; +} + +static int stmvl53l0x_stop(struct vl_data *data) +{ + int rc = 0; + struct vl_data *vl53l0x_dev = data; + + dbg("Enter\n"); + + /* stop - if continuous mode */ + if (data->deviceMode == VL_DEVICEMODE_CONTINUOUS_RANGING || + data->deviceMode == VL_DEVICEMODE_CONTINUOUS_TIMED_RANGING) + papi_func_tbl->StopMeasurement(vl53l0x_dev); + + /* clean interrupt */ + papi_func_tbl->ClearInterruptMask(vl53l0x_dev, 0); + + /* cancel work handler */ + stmvl53l0x_cancel_handler(data); + /* power down */ + rc = pmodule_func_tbl->power_down(data->client_object); + if (rc) { + err("%d, error rc %d\n", __LINE__, rc); + return rc; + } + dbg("End\n"); + + return rc; +} + +/* + * I2C init/probing/exit functions + */ +static const struct file_operations stmvl53l0x_ranging_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = stmvl53l0x_ioctl, + .open = stmvl53l0x_open, + .flush = stmvl53l0x_flush, +}; + +int stmvl53l0x_setup(struct vl_data *data) +{ + int rc = 0; + + dbg("Enter\n"); + + /* init mutex */ + mutex_init(&data->update_lock); + mutex_init(&data->work_mutex); + + init_waitqueue_head(&data->poll_thread_wq); + + data->poll_thread = kthread_run(&stmvl53l0x_poll_thread, + (void *)data, "STM-VL53L0"); + if (data->poll_thread == NULL) { + dbg("%s(%d) - Failed to create Polling thread\n", + __func__, __LINE__); + goto exit_free_irq; + } + + /* init work handler */ + INIT_DELAYED_WORK(&data->dwork, stmvl53l0x_work_handler); + + /* Register to Input Device */ + data->input_dev_ps = input_allocate_device(); + if (!data->input_dev_ps) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + + goto exit_free_irq; + } + set_bit(EV_ABS, data->input_dev_ps->evbit); + /* range in cm*/ + input_set_abs_params(data->input_dev_ps, ABS_DISTANCE, 0, 76, 0, 0); + /* tv_sec */ + input_set_abs_params(data->input_dev_ps, ABS_HAT0X, 0, 0xffffffff, + 0, 0); + /* tv_usec */ + input_set_abs_params(data->input_dev_ps, ABS_HAT0Y, 0, 0xffffffff, + 0, 0); + /* range in_mm */ + input_set_abs_params(data->input_dev_ps, ABS_HAT1X, 0, 765, 0, 0); + /* error code change maximum to 0xff for more flexibility */ + input_set_abs_params(data->input_dev_ps, ABS_HAT1Y, 0, 0xff, 0, 0); + /* rtnRate */ + input_set_abs_params(data->input_dev_ps, ABS_HAT2X, 0, 0xffffffff, + 0, 0); + /* rtn_amb_rate */ + input_set_abs_params(data->input_dev_ps, ABS_HAT2Y, 0, 0xffffffff, + 0, 0); + /* rtn_conv_time */ + input_set_abs_params(data->input_dev_ps, ABS_HAT3X, 0, 0xffffffff, + 0, 0); + /* dmax */ + input_set_abs_params(data->input_dev_ps, ABS_HAT3Y, 0, 0xffffffff, + 0, 0); + + input_set_abs_params(data->input_dev_ps, ABS_PRESSURE, 0, 0xffffffff, + 0, 0); + + input_set_abs_params(data->input_dev_ps, ABS_WHEEL, 0, 0xffffffff, + 0, 0); + + data->input_dev_ps->name = "STM VL53L0 proximity sensor"; + + rc = input_register_device(data->input_dev_ps); + if (rc) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + goto exit_free_dev_ps; + } + /* setup drv data */ + input_set_drvdata(data->input_dev_ps, data); + + /* Register sysfs hooks */ + data->range_kobj = kobject_create_and_add("range", kernel_kobj); + if (!data->range_kobj) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps; + } + rc = sysfs_create_group(&data->input_dev_ps->dev.kobj, + &stmvl53l0x_attr_group); + if (rc) { + rc = -ENOMEM; + err("%d error:%d\n", __LINE__, rc); + goto exit_unregister_dev_ps_1; + } + /* init default device parameter value */ + data->enable_ps_sensor = 0; + data->reset = 1; + data->delay_ms = 30; /* delay time to 30ms */ + data->enableDebug = 0; + data->gpio_polarity = VL_INTERRUPTPOLARITY_LOW; + data->gpio_function = VL_GPIOFUNCTIONALITY_NEW_MEASURE_READY; + data->low_threshold = 60; + data->high_threshold = 200; + data->deviceMode = VL_DEVICEMODE_SINGLE_RANGING; + data->interMeasurems = 30; + data->timingBudget = 26000; + data->useLongRange = 1; + + dbg("support ver. %s enabled\n", DRIVER_VERSION); + dbg("End"); + + return 0; +exit_unregister_dev_ps_1: + kobject_put(data->range_kobj); +exit_unregister_dev_ps: + input_unregister_device(data->input_dev_ps); +exit_free_dev_ps: + input_free_device(data->input_dev_ps); +exit_free_irq: + kfree(data); + return rc; +} + +static int __init stmvl53l0x_init(void) +{ + int ret = -1; + + dbg("Enter\n"); + + /* assign function table */ + pmodule_func_tbl = &stmvl53l0x_module_func_tbl; + papi_func_tbl = &stmvl53l0x_api_func_tbl; + + /* client specific init function */ + ret = pmodule_func_tbl->init(); + + if (ret) + err("%d failed with %d\n", __LINE__, ret); + + dbg("End\n"); + + return ret; +} + +static void __exit stmvl53l0x_exit(void) +{ + dbg("Enter\n"); + + dbg("End\n"); +} + +MODULE_DESCRIPTION("ST FlightSense Time-of-Flight sensor driver"); +MODULE_LICENSE("GPL v2"); + +module_init(stmvl53l0x_init); +module_exit(stmvl53l0x_exit); -- GitLab From 4ce7d7bad5a6d85619fe9be1c694233354f2ca4f Mon Sep 17 00:00:00 2001 From: Tim Jiang Date: Tue, 8 May 2018 13:34:56 +0800 Subject: [PATCH 1794/1834] bluetooth: Add QCA9379 power contorl support To support QCA9379 chipset. Change-Id: I13451de3a491473e04bb9fda6960fc46c62400a6 Signed-off-by: Tim Jiang --- drivers/bluetooth/bluetooth-power.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/bluetooth-power.c b/drivers/bluetooth/bluetooth-power.c index f92775650754..7f7c9421c8c3 100644 --- a/drivers/bluetooth/bluetooth-power.c +++ b/drivers/bluetooth/bluetooth-power.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2009-2010, 2013-2017 The Linux Foundation. All rights reserved. +/* Copyright (c) 2009-2010, 2013-2018 The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -43,6 +43,7 @@ static const struct of_device_id bt_power_match_table[] = { { .compatible = "qca,ar3002" }, { .compatible = "qca,qca6174" }, + { .compatible = "qca,qca9379" }, { .compatible = "qca,wcn3990" }, {} }; -- GitLab From 9a59a47bc9b6f21846ccaf94c46ae192726d258b Mon Sep 17 00:00:00 2001 From: Ramesh Yadav Javadi Date: Wed, 9 May 2018 16:51:31 +0530 Subject: [PATCH 1795/1834] iommu/arm-smmu: add scm_call for secure page table memory for armv7 Add scm_call call support for secure page table allocation and initialization on ARMv7 architectures.These page tables are used by secure use cases for mapping and unmapping of secure buffers. Change-Id: Id6f29cb318cb3d6e6e36bf8e8ee3a87123119a4c Signed-off-by: Ramesh Yadav Javadi --- drivers/iommu/io-pgtable-msm-secure.c | 65 +++++++++++++++++---------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/drivers/iommu/io-pgtable-msm-secure.c b/drivers/iommu/io-pgtable-msm-secure.c index d0a8a792050b..e0314f9ebc3b 100644 --- a/drivers/iommu/io-pgtable-msm-secure.c +++ b/drivers/iommu/io-pgtable-msm-secure.c @@ -47,6 +47,11 @@ struct msm_secure_io_pgtable { int msm_iommu_sec_pgtbl_init(void) { + struct msm_scm_ptbl_init { + unsigned int paddr; + unsigned int size; + unsigned int spare; + } pinit = {0}; int psize[2] = {0, 0}; unsigned int spare = 0; int ret, ptbl_ret = 0; @@ -55,7 +60,12 @@ int msm_iommu_sec_pgtbl_init(void) dma_addr_t paddr; unsigned long attrs = 0; - if (is_scm_armv8()) { + struct scm_desc desc = {0}; + + if (!is_scm_armv8()) { + ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_SIZE, &spare, + sizeof(spare), psize, sizeof(psize)); + } else { struct scm_desc desc = {0}; desc.args[0] = spare; @@ -64,12 +74,11 @@ int msm_iommu_sec_pgtbl_init(void) IOMMU_SECURE_PTBL_SIZE), &desc); psize[0] = desc.ret[0]; psize[1] = desc.ret[1]; - if (ret || psize[1]) { - pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n"); - return ret; - } } - + if (ret || psize[1]) { + pr_err("scm call IOMMU_SECURE_PTBL_SIZE failed\n"); + goto fail; + } /* Now allocate memory for the secure page tables */ attrs = DMA_ATTR_NO_KERNEL_MAPPING; dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8); @@ -78,34 +87,42 @@ int msm_iommu_sec_pgtbl_init(void) if (!cpu_addr) { pr_err("%s: Failed to allocate %d bytes for PTBL\n", __func__, psize[0]); - return -ENOMEM; + ret = -ENOMEM; + goto fail; } - if (is_scm_armv8()) { - struct scm_desc desc = {0}; - - desc.args[0] = paddr; - desc.args[1] = psize[0]; - desc.args[2] = 0; - desc.arginfo = SCM_ARGS(3, SCM_RW, SCM_VAL, SCM_VAL); + pinit.paddr = (unsigned int)paddr; + /* paddr may be a physical address > 4GB */ + desc.args[0] = paddr; + desc.args[1] = pinit.size = psize[0]; + desc.args[2] = pinit.spare; + desc.arginfo = SCM_ARGS(3, SCM_RW, SCM_VAL, SCM_VAL); + if (!is_scm_armv8()) { + ret = scm_call(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT, &pinit, + sizeof(pinit), &ptbl_ret, sizeof(ptbl_ret)); + } else { ret = scm_call2(SCM_SIP_FNID(SCM_SVC_MP, IOMMU_SECURE_PTBL_INIT), &desc); ptbl_ret = desc.ret[0]; - - if (ret) { - pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n"); - return ret; - } - - if (ptbl_ret) { - pr_err("scm call IOMMU_SECURE_PTBL_INIT extended ret fail\n"); - return ret; - } + } + if (ret) { + pr_err("scm call IOMMU_SECURE_PTBL_INIT failed\n"); + goto fail_mem; + } + if (ptbl_ret) { + pr_err("scm call IOMMU_SECURE_PTBL_INIT extended ret fail\n"); + goto fail_mem; } return 0; + +fail_mem: + dma_free_attrs(&dev, psize[0], cpu_addr, paddr, attrs); +fail: + return ret; } + EXPORT_SYMBOL(msm_iommu_sec_pgtbl_init); static int msm_secure_map(struct io_pgtable_ops *ops, unsigned long iova, -- GitLab From 505be8e898825c4ac7a8214ad1a65f2ff57cf0ef Mon Sep 17 00:00:00 2001 From: Lingutla Chandrasekhar Date: Tue, 8 May 2018 15:25:06 +0530 Subject: [PATCH 1796/1834] trace: irqsoff: fix irqs disabled tracking Current tracking for irqs disabled is between calls of hardirqs_on to hardirqs_off, it should be reverse. fix the issue by correcting the tracking. Change-Id: I84bbe7fb906a04cfa5f779fa111e2aef9844969a Signed-off-by: Lingutla Chandrasekhar --- kernel/trace/trace_irqsoff.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c index 79bbaf0002ea..59b482f7eba7 100644 --- a/kernel/trace/trace_irqsoff.c +++ b/kernel/trace/trace_irqsoff.c @@ -478,14 +478,11 @@ static inline void tracer_hardirqs_on(void) #ifdef CONFIG_PREEMPTIRQ_EVENTS struct irqsoff_store *is = &per_cpu(the_irqsoff, raw_smp_processor_id()); + u64 delta = sched_clock() - is->ts; - if (!is->ts) { - is->ts = sched_clock(); - is->caddr[0] = CALLER_ADDR0; - is->caddr[1] = CALLER_ADDR1; - is->caddr[2] = CALLER_ADDR2; - is->caddr[3] = CALLER_ADDR3; - } + if (delta > sysctl_irqsoff_tracing_threshold_ns) + trace_irqs_disable(delta, is->caddr[0], is->caddr[1], + is->caddr[2], is->caddr[3]); #endif /* CONFIG_PREEMPTIRQ_EVENTS */ if (!preempt_trace() && irq_trace()) @@ -497,15 +494,12 @@ static inline void tracer_hardirqs_off(void) #ifdef CONFIG_PREEMPTIRQ_EVENTS struct irqsoff_store *is = &per_cpu(the_irqsoff, raw_smp_processor_id()); - u64 delta = 0; - if (is->ts) { - delta = sched_clock() - is->ts; - is->ts = 0; - } - if (delta > sysctl_irqsoff_tracing_threshold_ns) - trace_irqs_disable(delta, is->caddr[0], is->caddr[1], - is->caddr[2], is->caddr[3]); + is->ts = sched_clock(); + is->caddr[0] = CALLER_ADDR0; + is->caddr[1] = CALLER_ADDR1; + is->caddr[2] = CALLER_ADDR2; + is->caddr[3] = CALLER_ADDR3; #endif /* CONFIG_PREEMPTIRQ_EVENTS */ if (!preempt_trace() && irq_trace()) -- GitLab From 53c2124036b76d9f930308659aa9c2fd60a39616 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Wed, 16 May 2018 10:42:15 +0530 Subject: [PATCH 1797/1834] thermal: tsens: Update order of members in TSENS device structure Last member of TSENS device structure should be pointer to sensor array of variable size. Move the mtcsys member above to avoid corrupting the array of sensor structs. Change-Id: I41b814af4a28e9de2c09b92623b010b835e56c1d Signed-off-by: Jishnu Prakash --- drivers/thermal/tsens.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/tsens.h b/drivers/thermal/tsens.h index 730d1243bf03..d35b867d92fd 100644 --- a/drivers/thermal/tsens.h +++ b/drivers/thermal/tsens.h @@ -153,8 +153,8 @@ struct tsens_device { spinlock_t tsens_crit_lock; spinlock_t tsens_upp_low_lock; const struct tsens_data *ctrl_data; + struct tsens_mtc_sysfs mtcsys; struct tsens_sensor sensor[0]; - struct tsens_mtc_sysfs mtcsys; }; extern const struct tsens_data data_tsens2xxx, data_tsens23xx, data_tsens24xx; -- GitLab From caadcd53e9342192dd6e5db6e30107b6b141c91e Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Mon, 14 May 2018 15:11:10 +0530 Subject: [PATCH 1798/1834] ARM: dts: msm: Add 8909w video driver dtsi Add video device nodes for venus secured and non-secured. Change-Id: I6bc0f7ada6769b0c7b31e521cdacccf7a49e7de2 Signed-off-by: Arun kumar --- arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi | 163 +++++++++++++++++++++ arch/arm64/boot/dts/qcom/msm8909.dtsi | 1 + 2 files changed, 164 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi b/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi new file mode 100644 index 000000000000..5eeaa210be62 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8909-vidc.dtsi @@ -0,0 +1,163 @@ +/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,vidc@1d00000 { + compatible = "qcom,msm-vidc"; + reg = <0x01d00000 0xff000>; + interrupts = <0 44 0>; + qcom,hfi-version = "3xx"; + venus-supply = <&gdsc_venus>; + venus-core0-supply = <&gdsc_venus_core0>; + clocks = <&clock_gcc clk_gcc_venus0_vcodec0_clk>, + <&clock_gcc clk_gcc_venus0_core0_vcodec0_clk>, + <&clock_gcc clk_gcc_venus0_ahb_clk>, + <&clock_gcc clk_gcc_venus0_axi_clk>; + clock-names = "core_clk", "core0_clk", "iface_clk", "bus_clk"; + qcom,clock-configs = <0x1 0x0 0x0 0x0>; + qcom,sw-power-collapse; + qcom,slave-side-cp; + qcom,hfi = "venus"; + qcom,reg-presets = <0xe0020 0x05555556>, + <0xe0024 0x05555556>, + <0x80124 0x00000003>; + qcom,qdss-presets = <0x826000 0x1000>, + <0x827000 0x1000>, + <0x822000 0x1000>, + <0x803000 0x1000>, + <0x9180000 0x1000>, + <0x9181000 0x1000>; + qcom,max-hw-load = <244800>; /* 1080p@30 + 720p@30 */ + qcom,firmware-name = "venus"; + qcom,allowed-clock-rates = <307200000 266670000 133330000>; + qcom,clock-freq-tbl { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,cycles-per-mb = <2316>; + qcom,low-power-mode-factor = <32768>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xf3ffffff>; + qcom,cycles-per-mb = <788>; + }; + qcom,profile-hevcdec { + qcom,codec-mask = <0x0c000000>; + qcom,cycles-per-mb = <1015>; + }; + }; + + /* MMUs */ + non_secure_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_ns"; + iommus = <&apps_iommu 0x800 0x00>, + <&apps_iommu 0x807 0x00>, + <&apps_iommu 0x808 0x27>, + <&apps_iommu 0x811 0x0>; + buffer-types = <0xfff>; + virtual-addr-pool = <0x5dc00000 0x8f000000>; + }; + + secure_bitstream_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_bitstream"; + iommus = <&apps_iommu 0x90c 0x20>; + buffer-types = <0x241>; + virtual-addr-pool = <0x4b000000 0x12c00000>; + qcom,secure-context-bank; + }; + + secure_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_pixel"; + iommus = <&apps_iommu 0x900 0x00>, + <&apps_iommu 0x909 0x20>, + <&apps_iommu 0x90a 0x00>, + <&apps_iommu 0x90b 0x20>, + <&apps_iommu 0x90e 0x00>; + buffer-types = <0x106>; + virtual-addr-pool = <0x25800000 0x25800000>; + qcom,secure-context-bank; + }; + + secure_non_pixel_cb { + compatible = "qcom,msm-vidc,context-bank"; + label = "venus_sec_non_pixel"; + iommus = <&apps_iommu 0x9c0 0x00>, + <&apps_iommu 0x907 0x00>, + <&apps_iommu 0x908 0x20>, + <&apps_iommu 0x90d 0x20>, + <&apps_iommu 0x90f 0x00>; + buffer-types = <0x480>; + virtual-addr-pool = <0x1000000 0x24800000>; + qcom,secure-context-bank; + }; + + /* Buses */ + venus_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "venus-ddr-gov"; + qcom,bus-range-kbps = <1000 917000>; + }; + + arm9_bus_ddr { + compatible = "qcom,msm-vidc,bus"; + label = "venus-arm9-ddr"; + qcom,bus-master = ; + qcom,bus-slave = ; + qcom,bus-governor = "performance"; + qcom,bus-range-kbps = <1 1>; + }; + }; + + venus-ddr-gov { + compatible = "qcom,msm-vidc,governor,table"; + name = "venus-ddr-gov"; + status = "ok"; + qcom,bus-freq-table { + qcom,profile-enc { + qcom,codec-mask = <0x55555555>; + qcom,load-busfreq-tbl = + <244800 841000>, /* 1080p30E */ + <216000 740000>, /* 720p60E */ + <194400 680000>, /* FWVGA120E */ + <144000 496000>, /* VGA120E */ + <108000 370000>, /* 720p30E */ + <97200 340000>, /* FWVGA60E */ + <48600 170000>, /* FWVGA30E */ + <72000 248000>, /* VGA60E */ + <36000 124000>, /* VGA30E */ + <18000 70000>, /* QVGA60E */ + <9000 35000>, /* QVGA30E */ + <0 0>; + }; + qcom,profile-dec { + qcom,codec-mask = <0xffffffff>; + qcom,load-busfreq-tbl = + <244800 605000>, /* 1080p30D */ + <216000 540000>, /* 720p60D */ + <194400 484000>, /* FWVGA120D */ + <144000 360000>, /* VGA120D */ + <108000 270000>, /* 720p30D */ + <97200 242000>, /* FWVGA60D */ + <48600 121000>, /* FWVGA30D */ + <72000 180000>, /* VGA60D */ + <36000 90000>, /* VGA30D */ + <18000 45000>, /* HVGA30D */ + <0 0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8909.dtsi b/arch/arm64/boot/dts/qcom/msm8909.dtsi index a6d42f1c6ec8..7450f280703f 100644 --- a/arch/arm64/boot/dts/qcom/msm8909.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8909.dtsi @@ -239,6 +239,7 @@ #include "msm8909-gpu.dtsi" #include "msm8909-coresight.dtsi" #include "msm8909-bus.dtsi" +#include "msm8909-vidc.dtsi" #include "msm8909-mdss.dtsi" #include "msm8909-mdss-pll.dtsi" -- GitLab From f5d477c61827f060e2efb6dd43236549529cd934 Mon Sep 17 00:00:00 2001 From: Tharun Raj Soma Date: Wed, 9 May 2018 10:38:39 +0530 Subject: [PATCH 1799/1834] drm/msm/dsi-staging: add lp11-init support for DRM DSI driver Some panels have requirement to toggle the reset gpio pin before sending panel init command. This change provides support to parse this lp11-init property from panel dtsi file. When there is power off, lp11-init logic is disabled so that panel off sequence is not changed. Change-Id: I1f01b65010a00cba593f94c71dcab134cb1dd758 Signed-off-by: Tharun Raj Soma --- drivers/gpu/drm/msm/dsi-staging/dsi_panel.c | 23 +++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 79df63152ac4..e60743c6e30d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -1771,6 +1771,9 @@ static int dsi_panel_parse_misc_features(struct dsi_panel *panel, panel->sync_broadcast_en = of_property_read_bool(of_node, "qcom,cmd-sync-wait-broadcast"); + + panel->lp11_init = of_property_read_bool(of_node, + "qcom,mdss-dsi-lp11-init"); return 0; } @@ -3746,14 +3749,6 @@ int dsi_panel_unprepare(struct dsi_panel *panel) goto error; } - if (panel->lp11_init) { - rc = dsi_panel_power_off(panel); - if (rc) { - pr_err("[%s] panel power_Off failed, rc=%d\n", - panel->name, rc); - goto error; - } - } error: mutex_unlock(&panel->panel_lock); return rc; @@ -3773,13 +3768,11 @@ int dsi_panel_post_unprepare(struct dsi_panel *panel) mutex_lock(&panel->panel_lock); - if (!panel->lp11_init) { - rc = dsi_panel_power_off(panel); - if (rc) { - pr_err("[%s] panel power_Off failed, rc=%d\n", - panel->name, rc); - goto error; - } + rc = dsi_panel_power_off(panel); + if (rc) { + pr_err("[%s] panel power_Off failed, rc=%d\n", + panel->name, rc); + goto error; } error: mutex_unlock(&panel->panel_lock); -- GitLab From 402b8ff4a18dbcacc58fe8e18411b32b9820d71b Mon Sep 17 00:00:00 2001 From: Manaf Meethalavalappu Pallikunhi Date: Tue, 15 May 2018 16:49:51 +0530 Subject: [PATCH 1800/1834] defconfig: msm: enable thermal framework related drivers for MSM8937/sdm439 Enable thermal framework related drivers like cpu thermal, devfreq thermal, QMI TM, virtual sensor, regulator cooling device etc. for MSM8937/SDM439 32 bit mode. Change-Id: I79e3e69019efdc933d410b45377c26ad4c7502fb Signed-off-by: Manaf Meethalavalappu Pallikunhi --- arch/arm/configs/msm8953-perf_defconfig | 12 ++++++++++-- arch/arm/configs/msm8953_defconfig | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/arm/configs/msm8953-perf_defconfig b/arch/arm/configs/msm8953-perf_defconfig index 2ba24d9f84b1..d1b19c02cb9a 100644 --- a/arch/arm/configs/msm8953-perf_defconfig +++ b/arch/arm/configs/msm8953-perf_defconfig @@ -352,11 +352,19 @@ CONFIG_QPNP_QG=y CONFIG_MSM_APM=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_THERMAL_TSENS=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y diff --git a/arch/arm/configs/msm8953_defconfig b/arch/arm/configs/msm8953_defconfig index 829901843a3f..c2feafce8559 100644 --- a/arch/arm/configs/msm8953_defconfig +++ b/arch/arm/configs/msm8953_defconfig @@ -359,11 +359,19 @@ CONFIG_QPNP_QG=y CONFIG_MSM_APM=y CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y CONFIG_THERMAL_QPNP=y CONFIG_THERMAL_QPNP_ADC_TM=y CONFIG_THERMAL_TSENS=y -CONFIG_MSM_BCL_PERIPHERAL_CTL=y -CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y CONFIG_MFD_SPMI_PMIC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y -- GitLab From c5fca96014a5b92e3dcb6500e5bfab1bd3af6fb8 Mon Sep 17 00:00:00 2001 From: bings Date: Tue, 8 May 2018 14:42:14 +0800 Subject: [PATCH 1801/1834] ARM: dts: msm: Add wlan naples support to apq8009 robot-som variant Add wlan naples dts support for apq8009 robot-som variant Change-Id: Ifd5512baea5e18cf4b0f34d554a7eaae967659f2 CRs-Fixed: 2242714 Signed-off-by: bings --- .../dts/qcom/apq8009-robot-som-refboard.dts | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts index 72486b208141..958f7c86082c 100644 --- a/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts +++ b/arch/arm64/boot/dts/qcom/apq8009-robot-som-refboard.dts @@ -71,12 +71,89 @@ compatible = "qca,qca9379"; qca,bt-reset-gpio = <&msm_gpio 47 0>; /* BT_EN */ }; + cnss_sdio: qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + subsys-name = "AR6320"; + /** + * There is no vdd-wlan on board and this is not for DSRC. + * IO and XTAL share the same vreg. + */ + vdd-wlan-io-supply = <&pm8916_l5>; + qcom,cap-tsf-gpio = <&msm_gpio 42 1>; + qcom,wlan-ramdump-dynamic = <0x200000>; + qcom,msm-bus,name = "msm-cnss"; + qcom,msm-bus,num-cases = <4>; + qcom,msm-bus,num-paths = <1>; + qcom,msm-bus,vectors-KBps = + <79 512 0 0>, /* No vote */ + <79 512 6250 200000>, /* 50 Mbps */ + <79 512 25000 200000>, /* 200 Mbps */ + <79 512 2048000 4096000>; /* MAX */ + }; }; -&sdhc_2 { +&wcnss { status = "disabled"; }; +&msm_gpio { + sdc2_wlan_gpio_on: sdc2_wlan_gpio_on { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <10>; + bias-pull-up; + output-high; + }; + }; + + sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { + mux { + pins = "gpio43"; + function = "gpio"; + }; + config { + pins = "gpio43"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; +}; + +&sdhc_2 { + /delete-property/cd-gpios; + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &msm_gpio 38 0>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + qcom,vdd-voltage-level = <1800000 2950000>; + qcom,vdd-current-level = <15000 400000>; + + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 50000>; + qcom,clk-rates = <400000 25000000 50000000 100000000 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_off>; + qcom,nonremovable; + qcom,core_3_0v_support; + status = "ok"; +}; + &usb_otg { interrupts = <0 134 0>,<0 140 0>,<0 136 0>; interrupt-names = "core_irq", "async_irq", "phy_irq"; -- GitLab From b0d88b711612e2c754cadd913681461aecce7642 Mon Sep 17 00:00:00 2001 From: Prakash Gupta Date: Tue, 15 May 2018 16:08:08 +0530 Subject: [PATCH 1802/1834] iommu: ignore scm_call return if SMC_ID not supported Not all targets support hyp_assign. Ignore the return error if scm_call return indicate that SMC_ID is not supported. Change-Id: Ia3e25b1c7d1f4b24f6da0143901aa1cb9a8ea3e2 Signed-off-by: Prakash Gupta --- drivers/iommu/arm-smmu-errata.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/iommu/arm-smmu-errata.c b/drivers/iommu/arm-smmu-errata.c index 2ee2028bdcef..e1cb1a435358 100644 --- a/drivers/iommu/arm-smmu-errata.c +++ b/drivers/iommu/arm-smmu-errata.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -41,7 +41,7 @@ struct page *arm_smmu_errata_get_guard_page(int vmid) ret = hyp_assign_phys(page_to_phys(page), PAGE_ALIGN(size), &source_vm, 1, &dest_vm, &dest_perm, 1); - if (ret) { + if (ret && (ret != -EIO)) { __free_pages(page, get_order(size)); page = NULL; } -- GitLab From 91d63f4887b00c56407ad5848a0d84dfbc251e52 Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Wed, 16 May 2018 11:30:40 +0530 Subject: [PATCH 1803/1834] power: smb5: add legacy-cable detection logic Charger h/w legacy-cable detection fails if the device is rebooted with charger connected. Fix this by resetting TypeC state machine by disabling/enabling TypeC module. Change-Id: I26e78123f7a60adbeceeaa7acd5dc9b83306b19f Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 32 +++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 462e55fb57b1..133b985357a0 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1431,11 +1431,39 @@ static int smb5_init_vconn_regulator(struct smb5 *chip) static int smb5_configure_typec(struct smb_charger *chg) { int rc; + u8 val = 0; + + rc = smblib_read(chg, LEGACY_CABLE_STATUS_REG, &val); + if (rc < 0) { + dev_err(chg->dev, "Couldn't read Legacy status rc=%d\n", rc); + return rc; + } + /* + * If Legacy cable is detected re-trigger Legacy detection + * by disabling/enabling typeC mode. + */ + if (val & TYPEC_LEGACY_CABLE_STATUS_BIT) { + rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, + TYPEC_DISABLE_CMD_BIT, TYPEC_DISABLE_CMD_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable TYPEC rc=%d\n", rc); + return rc; + } + + /* delay before enabling typeC */ + msleep(500); + + rc = smblib_masked_write(chg, TYPE_C_MODE_CFG_REG, + TYPEC_DISABLE_CMD_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable TYPEC rc=%d\n", rc); + return rc; + } + } /* disable apsd */ rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, - 0); + HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, 0); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return rc; -- GitLab From c96380de12b31e33cdd18886da8a3d2458e7627a Mon Sep 17 00:00:00 2001 From: Ashay Jaiswal Date: Wed, 16 May 2018 12:02:36 +0530 Subject: [PATCH 1804/1834] power: smb5: add minor fixes to SMB5 charger Fix some minor bugs in charger driver: - Return from OTG work if there is no change in OTG state. - Update Power role mask. - Skip AICL ADC configuration for PMI632. - Fix OTG reporting via extcon. Change-Id: I6afdd9bc63dc97c562a8c480be896114c295c578 Signed-off-by: Ashay Jaiswal --- drivers/power/supply/qcom/qpnp-smb5.c | 24 +++++++---- drivers/power/supply/qcom/smb5-lib.c | 60 +++++++++++++++++---------- drivers/power/supply/qcom/smb5-lib.h | 1 + drivers/power/supply/qcom/smb5-reg.h | 4 +- 4 files changed, 55 insertions(+), 34 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 133b985357a0..6a2a6be480fd 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -243,6 +243,8 @@ static int smb5_chg_config_init(struct smb5 *chip) chg->param = smb5_pmi632_params; chg->use_extcon = true; chg->name = "pmi632_charger"; + /* PMI632 does not support PD */ + __pd_disabled = 1; chg->hw_max_icl_ua = (chip->dt.usb_icl_ua > 0) ? chip->dt.usb_icl_ua : PMI632_MAX_ICL_UA; @@ -1462,8 +1464,7 @@ static int smb5_configure_typec(struct smb_charger *chg) } /* disable apsd */ - rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, 0); + rc = smblib_configure_hvdcp_apsd(chg, false); if (rc < 0) { dev_err(chg->dev, "Couldn't disable APSD rc=%d\n", rc); return rc; @@ -1576,7 +1577,6 @@ static int smb5_init_hw(struct smb5 *chip) if (type) { chg->connector_type = POWER_SUPPLY_CONNECTOR_MICRO_USB; - smblib_rerun_apsd_if_required(chg); rc = smb5_configure_micro_usb(chg); } else { chg->connector_type = POWER_SUPPLY_CONNECTOR_TYPEC; @@ -1590,10 +1590,14 @@ static int smb5_init_hw(struct smb5 *chip) /* * PMI632 based hw init: + * - Rerun APSD to ensure proper charger detection if device + * boots with charger connected. * - Initialize flash module for PMI632 */ - if (chg->smb_version == PMI632_SUBTYPE) + if (chg->smb_version == PMI632_SUBTYPE) { schgm_flash_init(chg); + smblib_rerun_apsd_if_required(chg); + } /* vote 0mA on usb_icl for non battery platforms */ vote(chg->usb_icl_votable, @@ -1617,13 +1621,15 @@ static int smb5_init_hw(struct smb5 *chip) /* * AICL configuration: - * start from min and AICL ADC disable + * AICL ADC disable */ - rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, + if (chg->smb_version != PMI632_SUBTYPE) { + rc = smblib_masked_write(chg, USBIN_AICL_OPTIONS_CFG_REG, USBIN_AICL_ADC_EN_BIT, 0); - if (rc < 0) { - dev_err(chg->dev, "Couldn't configure AICL rc=%d\n", rc); - return rc; + if (rc < 0) { + dev_err(chg->dev, "Couldn't config AICL rc=%d\n", rc); + return rc; + } } /* enable the charging path */ diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index 9d7bb8326352..0410964a254a 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -512,6 +512,23 @@ static int smblib_set_usb_pd_allowed_voltage(struct smb_charger *chg, /******************** * HELPER FUNCTIONS * ********************/ +int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable) +{ + int rc; + u8 mask = HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT; + + if (chg->pd_disabled) + return 0; + + rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, mask, + enable ? mask : 0); + if (rc < 0) + smblib_err(chg, "failed to write USBIN_OPTIONS_1_CFG rc=%d\n", + rc); + + return rc; +} + static int smblib_request_dpdm(struct smb_charger *chg, bool enable) { int rc = 0; @@ -2320,15 +2337,13 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, /* PD hard resets failed, rerun apsd */ if (chg->ok_to_pd) { chg->ok_to_pd = false; - rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); + rc = smblib_configure_hvdcp_apsd(chg, true); if (rc < 0) { dev_err(chg->dev, - "Couldn't disable APSD rc=%d\n", rc); + "Couldn't enable APSD rc=%d\n", rc); return rc; } - smblib_rerun_apsd(chg); + smblib_rerun_apsd_if_required(chg); } } @@ -3003,7 +3018,7 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) * charger-mis-detection. */ chg->uusb_apsd_rerun_done = true; - smblib_rerun_apsd(chg); + smblib_rerun_apsd_if_required(chg); return IRQ_HANDLED; } @@ -3072,21 +3087,25 @@ static void typec_src_insertion(struct smb_charger *chg) chg->ok_to_pd = !(chg->typec_legacy || *chg->pd_disabled) || chg->early_usb_attach; if (!chg->ok_to_pd) { - rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT); + rc = smblib_configure_hvdcp_apsd(chg, true); if (rc < 0) { dev_err(chg->dev, - "Couldn't disable APSD rc=%d\n", rc); + "Couldn't enable APSD rc=%d\n", rc); return; } - smblib_rerun_apsd(chg); + smblib_rerun_apsd_if_required(chg); } } static void typec_sink_removal(struct smb_charger *chg) { vote(chg->usb_icl_votable, OTG_VOTER, false, 0); + + if (chg->use_extcon) { + if (chg->otg_present) + smblib_notify_usb_host(chg, false); + chg->otg_present = false; + } } static void typec_src_removal(struct smb_charger *chg) @@ -3096,12 +3115,9 @@ static void typec_src_removal(struct smb_charger *chg) struct storm_watch *wdata; /* disable apsd */ - rc = smblib_masked_write(chg, USBIN_OPTIONS_1_CFG_REG, - HVDCP_EN_BIT | BC1P2_SRC_DETECT_BIT, - 0); + rc = smblib_configure_hvdcp_apsd(chg, false); if (rc < 0) - smblib_err(chg, - "Couldn't disable APSD rc=%d\n", rc); + smblib_err(chg, "Couldn't disable APSD rc=%d\n", rc); smblib_update_usb_type(chg); @@ -3158,14 +3174,9 @@ static void typec_src_removal(struct smb_charger *chg) smblib_err(chg, "Couldn't set USBIN_ADAPTER_ALLOW_5V_OR_9V_TO_12V rc=%d\n", rc); - if (chg->use_extcon) { - if (chg->otg_present) - smblib_notify_usb_host(chg, false); - else - smblib_notify_device_mode(chg, false); - } + if (chg->use_extcon) + smblib_notify_device_mode(chg, false); - chg->otg_present = false; chg->typec_legacy = false; } @@ -3495,6 +3506,9 @@ static void smblib_uusb_otg_work(struct work_struct *work) otg = !!(stat & U_USB_GROUND_NOVBUS_BIT); if (chg->otg_present != otg) smblib_notify_usb_host(chg, otg); + else + goto out; + chg->otg_present = otg; if (!otg) chg->boost_current_ua = 0; diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 7e2558cc48b8..6bdef29a9b2e 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -536,6 +536,7 @@ int smblib_set_prop_pr_swap_in_progress(struct smb_charger *chg, int smblib_stat_sw_override_cfg(struct smb_charger *chg, bool override); int smblib_configure_wdog(struct smb_charger *chg, bool enable); int smblib_force_vbus_voltage(struct smb_charger *chg, u8 val); +int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable); int smblib_init(struct smb_charger *chg); int smblib_deinit(struct smb_charger *chg); diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 4fdf866eae98..79a8bd0c61cb 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -283,7 +283,7 @@ enum { #define U_USB_GROUND_BIT BIT(4) #define TYPE_C_MODE_CFG_REG (TYPEC_BASE + 0x44) -#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 0) +#define TYPEC_POWER_ROLE_CMD_MASK GENMASK(2, 1) #define EN_SRC_ONLY_BIT BIT(2) #define EN_SNK_ONLY_BIT BIT(1) #define TYPEC_DISABLE_CMD_BIT BIT(0) @@ -327,7 +327,7 @@ enum { #define TYPEC_U_USB_CFG_REG (TYPEC_BASE + 0x70) #define EN_MICRO_USB_MODE_BIT BIT(0) -#define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x70) +#define TYPEC_MICRO_USB_MODE_REG (TYPEC_BASE + 0x73) #define MICRO_USB_MODE_ONLY_BIT BIT(0) /******************************** * MISC Peripheral Registers * -- GitLab From 7fe2c98efa65f8136a9904c40f5fa7c55b24c855 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Tue, 15 May 2018 16:17:21 -0700 Subject: [PATCH 1805/1834] msm: ipa4: Remove enable/disable clock on send_cmd_timeout Remove enable/disable clk macros on ipa3_send_cmd_timeout to prevent deadlock since the callers of this function already enables clk and locks the same mutex. Change-Id: Ibe7bf95332029e7af8e1d34036152cfa3dbf264e Crs-fixed: 2242056 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_dp.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 9a0f44a950c6..e73349a2104b 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -646,7 +646,6 @@ int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout) atomic_set(&comp->cnt, 2); sys = ipa3_ctx->ep[ep_idx].sys; - IPA_ACTIVE_CLIENTS_INC_SIMPLE(); if (num_desc == 1) { if (descr->callback || descr->user1) @@ -685,7 +684,6 @@ int ipa3_send_cmd_timeout(u16 num_desc, struct ipa3_desc *descr, u32 timeout) kfree(comp); bail: - IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return result; } -- GitLab From 00d3399afd921a342c6dd5b1930bfd4f730e898c Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Thu, 26 Apr 2018 20:13:07 +0300 Subject: [PATCH 1806/1834] cfg80211: Call reg_notifier for self managed hints conditionally Currently the regulatory core does not call the regulatory callback reg_notifier for self managed wiphys, but regulatory_hint_user() call is independent of wiphy and is meant for all wiphys in the system. Even a self managed wiphy may be interested in regulatory_hint_user() to know the country code from a trusted regulatory domain change like a cellular base station. Therefore, for the regulatory source NL80211_REGDOM_SET_BY_USER and the user hint type NL80211_USER_REG_HINT_CELL_BASE, call the regulatory notifier. No current wlan driver uses the REGULATORY_WIPHY_SELF_MANAGED flag while also registering the reg_notifier regulatory callback, therefore there will be no impact on existing drivers without them being explicitly modified to take advantage of this new possibility. Change-Id: Ibd700eae551840c94daa8b721add74a8e744c748 CRs-Fixed: 2201959 Git-commit: aced43ce780dc5e683b3de00ce9fb3db7d28e1d3 Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-testing.git Signed-off-by: Jouni Malinen Signed-off-by: Johannes Berg Signed-off-by: Amar Singhal --- net/wireless/reg.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index bc0ebd475fc4..9195f23c0b9b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2142,6 +2142,21 @@ static void reg_process_hint(struct regulatory_request *reg_request) reg_free_request(reg_request); } +static void notify_self_managed_wiphys(struct regulatory_request *request) +{ + struct cfg80211_registered_device *rdev; + struct wiphy *wiphy; + + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + wiphy = &rdev->wiphy; + if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED && + request->initiator == NL80211_REGDOM_SET_BY_USER && + request->user_reg_hint_type == + NL80211_USER_REG_HINT_CELL_BASE) + reg_call_notifier(wiphy, request); + } +} + static bool reg_only_self_managed_wiphys(void) { struct cfg80211_registered_device *rdev; @@ -2193,6 +2208,7 @@ static void reg_process_pending_hints(void) spin_unlock(®_requests_lock); + notify_self_managed_wiphys(reg_request); if (reg_only_self_managed_wiphys()) { reg_free_request(reg_request); return; @@ -3073,17 +3089,26 @@ EXPORT_SYMBOL(regulatory_set_wiphy_regd_sync_rtnl); void wiphy_regulatory_register(struct wiphy *wiphy) { - struct regulatory_request *lr; + struct regulatory_request *lr = get_last_request(); - /* self-managed devices ignore external hints */ - if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) + /* self-managed devices ignore beacon hints and country IE */ + if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) { wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS | REGULATORY_COUNTRY_IE_IGNORE; + /* + * The last request may have been received before this + * registration call. Call the driver notifier if + * initiator is USER and user type is CELL_BASE. + */ + if (lr->initiator == NL80211_REGDOM_SET_BY_USER && + lr->user_reg_hint_type == NL80211_USER_REG_HINT_CELL_BASE) + reg_call_notifier(wiphy, lr); + } + if (!reg_dev_ignore_cell_hint(wiphy)) reg_num_devs_support_basehint++; - lr = get_last_request(); wiphy_update_regulatory(wiphy, lr->initiator); } -- GitLab From 1769bedf0c24de3871e6eb9c73dacb5839b201c6 Mon Sep 17 00:00:00 2001 From: Aravind Venkateswaran Date: Mon, 14 May 2018 17:15:17 -0700 Subject: [PATCH 1807/1834] drm/msm/dsi-staging: fix idle power collapse exit sequence for PHY v3 Ensure that the escape clock is turned on prior to reinitializing the DSI PHY when exiting idle power collapse. This will ensure that there are no spurious transitions on the lanes after the PHY clamps are removed. Change-Id: Ic7ce1af62581b71d2a610b18381c9c57eb80696c Signed-off-by: Aravind Venkateswaran --- drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c | 1 + drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h | 1 + drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 45 ++++++++++++++----- drivers/gpu/drm/msm/dsi-staging/dsi_phy.c | 20 +++++++++ drivers/gpu/drm/msm/dsi-staging/dsi_phy.h | 9 ++++ drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h | 8 ++++ .../gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c | 27 +++++++++-- 7 files changed, 97 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c index d083e72cbaa7..a457070137c4 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.c @@ -214,6 +214,7 @@ static void dsi_catalog_phy_3_0_init(struct dsi_phy_hw *phy) phy->ops.ulps_ops.is_lanes_in_ulps = dsi_phy_hw_v3_0_is_lanes_in_ulps; phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v3_0; + phy->ops.clamp_ctrl = dsi_phy_hw_v3_0_clamp_ctrl; phy->ops.phy_lane_reset = dsi_phy_hw_v3_0_lane_reset; phy->ops.toggle_resync_fifo = dsi_phy_hw_v3_0_toggle_resync_fifo; } diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h index 0e2db4304a0d..144ccd909cab 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_catalog.h @@ -102,6 +102,7 @@ u32 dsi_phy_hw_v3_0_get_lanes_in_ulps(struct dsi_phy_hw *phy); bool dsi_phy_hw_v3_0_is_lanes_in_ulps(u32 lanes, u32 ulps_lanes); int dsi_phy_hw_timing_val_v3_0(struct dsi_phy_per_lane_cfgs *timing_cfg, u32 *timing_val, u32 size); +void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable); int dsi_phy_hw_v3_0_lane_reset(struct dsi_phy_hw *phy); void dsi_phy_hw_v3_0_toggle_resync_fifo(struct dsi_phy_hw *phy); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index de9162af8d83..4efaaa353f57 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -1582,9 +1582,19 @@ static int dsi_display_set_clamp(struct dsi_display *display, bool enable) m_ctrl = &display->ctrl[display->cmd_master_idx]; ulps_enabled = display->ulps_enabled; + /* + * Clamp control can be either through the DSI controller or + * the DSI PHY depending on hardware variation + */ rc = dsi_ctrl_set_clamp_state(m_ctrl->ctrl, enable, ulps_enabled); if (rc) { - pr_err("DSI Clamp state change(%d) failed\n", enable); + pr_err("DSI ctrl clamp state change(%d) failed\n", enable); + return rc; + } + + rc = dsi_phy_set_clamp_state(m_ctrl->phy, enable); + if (rc) { + pr_err("DSI phy clamp state change(%d) failed\n", enable); return rc; } @@ -1598,7 +1608,18 @@ static int dsi_display_set_clamp(struct dsi_display *display, bool enable) pr_err("DSI Clamp state change(%d) failed\n", enable); return rc; } + + rc = dsi_phy_set_clamp_state(ctrl->phy, enable); + if (rc) { + pr_err("DSI phy clamp state change(%d) failed\n", + enable); + return rc; + } + + pr_debug("Clamps %s for ctrl%d\n", + enable ? "enabled" : "disabled", i); } + display->clamp_enabled = enable; return 0; } @@ -3009,7 +3030,8 @@ int dsi_pre_clkoff_cb(void *priv, int rc = 0; struct dsi_display *display = priv; - if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) { + if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF) && + (l_type && DSI_LINK_LP_CLK)) { /* * If ULPS feature is enabled, enter ULPS first. * However, when blanking the panel, we should enter ULPS @@ -3068,7 +3090,7 @@ int dsi_post_clkon_cb(void *priv, struct dsi_display *display = priv; bool mmss_clamp = false; - if (clk & DSI_CORE_CLK) { + if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_LP_CLK)) { mmss_clamp = display->clamp_enabled; /* * controller setup is needed if coming out of idle @@ -3077,6 +3099,13 @@ int dsi_post_clkon_cb(void *priv, if (mmss_clamp) dsi_display_ctrl_setup(display); + /* + * Phy setup is needed if coming out of idle + * power collapse with clamps enabled. + */ + if (display->phy_idle_power_off || mmss_clamp) + dsi_display_phy_idle_on(display, mmss_clamp); + if (display->ulps_enabled && mmss_clamp) { /* * ULPS Entry Request. This is needed if the lanes were @@ -3115,17 +3144,11 @@ int dsi_post_clkon_cb(void *priv, goto error; } - /* - * Phy setup is needed if coming out of idle - * power collapse with clamps enabled. - */ - if (display->phy_idle_power_off || mmss_clamp) - dsi_display_phy_idle_on(display, mmss_clamp); - /* enable dsi to serve irqs */ dsi_display_ctrl_irq_update(display, true); } - if (clk & DSI_LINK_CLK) { + + if ((clk & DSI_LINK_CLK) && (l_type & DSI_LINK_HS_CLK)) { /* * Toggle the resync FIFO everytime clock changes, except * when cont-splash screen transition is going on. diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c index 6a7a84c0858c..2e2d0d81d643 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c @@ -901,6 +901,26 @@ int dsi_phy_disable(struct msm_dsi_phy *phy) return rc; } +/** + * dsi_phy_set_clamp_state() - configure clamps for DSI lanes + * @phy: DSI PHY handle. + * @enable: boolean to specify clamp enable/disable. + * + * Return: error code. + */ +int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable) +{ + if (!phy) + return -EINVAL; + + pr_debug("[%s] enable=%d\n", phy->name, enable); + + if (phy->hw.ops.clamp_ctrl) + phy->hw.ops.clamp_ctrl(&phy->hw, enable); + + return 0; +} + /** * dsi_phy_idle_ctrl() - enable/disable DSI PHY during idle screen * @phy: DSI PHY handle diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h index 56d5ee3bd5d4..41634116f897 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.h @@ -217,6 +217,15 @@ int dsi_phy_clk_cb_register(struct msm_dsi_phy *phy, */ int dsi_phy_idle_ctrl(struct msm_dsi_phy *phy, bool enable); +/** + * dsi_phy_set_clamp_state() - configure clamps for DSI lanes + * @phy: DSI PHY handle. + * @enable: boolean to specify clamp enable/disable. + * + * Return: error code. + */ +int dsi_phy_set_clamp_state(struct msm_dsi_phy *phy, bool enable); + /** * dsi_phy_set_clk_freq() - set DSI PHY clock frequency setting * @phy: DSI PHY handle diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h index e31899d4f664..d24a61380cfe 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw.h @@ -233,6 +233,14 @@ struct dsi_phy_hw_ops { int (*phy_timing_val)(struct dsi_phy_per_lane_cfgs *timing_val, u32 *timing, u32 size); + /** + * clamp_ctrl() - configure clamps for DSI lanes + * @phy: DSI PHY handle. + * @enable: boolean to specify clamp enable/disable. + * Return: error code. + */ + void (*clamp_ctrl)(struct dsi_phy_hw *phy, bool enable); + /** * phy_lane_reset() - Reset dsi phy lanes in case of error. * @phy: Pointer to DSI PHY hardware object. diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c index b078231e70e3..5015806c17e5 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy_hw_v3_0.c @@ -196,10 +196,31 @@ static void dsi_phy_hw_v3_0_lane_settings(struct dsi_phy_hw *phy, DSI_W32(phy, DSIPHY_LNX_OFFSET_BOT_CTRL(i), 0x0); DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(i), tx_dctrl[i]); } +} + +void dsi_phy_hw_v3_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable) +{ + u32 reg; - /* Toggle BIT 0 to release freeze I/0 */ - DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x05); - DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), 0x04); + pr_debug("enable=%s\n", enable ? "true" : "false"); + + /* + * DSI PHY lane clamps, also referred to as PHY FreezeIO is + * enalbed by default as part of the initialization sequnce. + * This would get triggered anytime the chip FreezeIO is asserted. + */ + if (enable) + return; + + /* + * Toggle BIT 0 to exlplictly release PHY freeze I/0 to disable + * the clamps. + */ + reg = DSI_R32(phy, DSIPHY_LNX_TX_DCTRL(3)); + DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg | BIT(0)); + wmb(); /* Ensure that the freezeio bit is toggled */ + DSI_W32(phy, DSIPHY_LNX_TX_DCTRL(3), reg & ~BIT(0)); + wmb(); /* Ensure that the freezeio bit is toggled */ } /** -- GitLab From fe5844bb9409da763ce04d0680e85745ab69e2b0 Mon Sep 17 00:00:00 2001 From: Viswanath Kraleti Date: Thu, 10 May 2018 08:37:05 +0530 Subject: [PATCH 1808/1834] defconfig: arm: msm: Add config files for msm8953 batcam Define new defconfigs to support batcam based on msm8953 Change-Id: Ic3d33983ec807a6a3704366a8204441d03805248 Signed-off-by: Viswanath Kraleti --- .../arm/configs/msm8953-batcam-perf_defconfig | 268 +++++++++++++++++ arch/arm/configs/msm8953-batcam_defconfig | 269 ++++++++++++++++++ 2 files changed, 537 insertions(+) create mode 100644 arch/arm/configs/msm8953-batcam-perf_defconfig create mode 100644 arch/arm/configs/msm8953-batcam_defconfig diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig new file mode 100644 index 000000000000..c898654eb73e --- /dev/null +++ b/arch/arm/configs/msm8953-batcam-perf_defconfig @@ -0,0 +1,268 @@ +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SCHED_WALT=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8953=y +# CONFIG_VDSO is not set +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_VMSPLIT_3G_OPT=y +CONFIG_NR_CPUS=8 +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_IMG_DTB=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_IMAGE_REUSE=y +CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49" +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_NET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_DMA_CMA=y +CONFIG_QSEECOM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_NETDEVICES=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM_SMD=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8953=y +CONFIG_PINCTRL_MSM8917=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_QPNP_FG=y +CONFIG_SMB135X_CHARGER=y +CONFIG_QPNP_SMB5=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_TYPEC=y +CONFIG_QPNP_QG=y +CONFIG_MSM_APM=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_CPR4_APSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_FB=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_MMC=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QTI_MPM=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_DWARF4=y +CONFIG_FRAME_WARN=2048 +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_STACKTRACE=y +# CONFIG_FTRACE is not set +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y +CONFIG_QMI_ENCDEC=y diff --git a/arch/arm/configs/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig new file mode 100644 index 000000000000..2c7c1920ae5a --- /dev/null +++ b/arch/arm/configs/msm8953-batcam_defconfig @@ -0,0 +1,269 @@ +# CONFIG_LOCALVERSION_AUTO is not set +CONFIG_AUDIT=y +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_SCHED_WALT=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_SCHEDTUNE=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_BPF=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_BPF_SYSCALL=y +# CONFIG_COMPAT_BRK is not set +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SIG=y +CONFIG_MODULE_SIG_FORCE=y +CONFIG_MODULE_SIG_SHA512=y +CONFIG_PARTITION_ADVANCED=y +# CONFIG_IOSCHED_DEADLINE is not set +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_MSM8953=y +# CONFIG_VDSO is not set +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_VMSPLIT_3G_OPT=y +CONFIG_NR_CPUS=8 +CONFIG_ARM_PSCI=y +CONFIG_PREEMPT=y +CONFIG_AEABI=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_BUILD_ARM_APPENDED_DTB_IMAGE=y +CONFIG_IMG_DTB=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_CPU_FREQ_MSM=y +CONFIG_CPU_IDLE=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_HIBERNATION=y +CONFIG_HIBERNATION_IMAGE_REUSE=y +CONFIG_PM_STD_PARTITION="/dev/mmcblk0p49" +CONFIG_PM_AUTOSLEEP=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_NET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_DMA_CMA=y +CONFIG_QSEECOM=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_NETDEVICES=y +CONFIG_INPUT_EVDEV=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_UINPUT=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_LEGACY_PTYS is not set +CONFIG_SERIAL_MSM=y +CONFIG_SERIAL_MSM_CONSOLE=y +CONFIG_SERIAL_MSM_SMD=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +CONFIG_MSM_SMD_PKT=y +CONFIG_MSM_ADSPRPC=y +CONFIG_MSM_RDBG=m +CONFIG_I2C_CHARDEV=y +CONFIG_SPI=y +CONFIG_SPI_QUP=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_PINCTRL_MSM8953=y +CONFIG_PINCTRL_MSM8917=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_QPNP_PIN=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_SUPPLY=y +CONFIG_QPNP_FG=y +CONFIG_SMB135X_CHARGER=y +CONFIG_QPNP_SMB5=y +CONFIG_QPNP_SMBCHARGER=y +CONFIG_QPNP_TYPEC=y +CONFIG_QPNP_QG=y +CONFIG_MSM_APM=y +CONFIG_SENSORS_QPNP_ADC_VOLTAGE=y +CONFIG_THERMAL=y +CONFIG_THERMAL_QPNP=y +CONFIG_THERMAL_QPNP_ADC_TM=y +CONFIG_THERMAL_TSENS=y +CONFIG_MSM_BCL_PERIPHERAL_CTL=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_CPR=y +CONFIG_REGULATOR_CPR4_APSS=y +CONFIG_REGULATOR_CPRH_KBSS=y +CONFIG_REGULATOR_MEM_ACC=y +CONFIG_REGULATOR_MSM_GFX_LDO=y +CONFIG_REGULATOR_QPNP_LABIBB=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_QPNP=y +CONFIG_REGULATOR_RPM_SMD=y +CONFIG_REGULATOR_SPM=y +CONFIG_REGULATOR_STUB=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_FB=y +CONFIG_FB_MSM=y +CONFIG_FB_MSM_MDSS=y +CONFIG_FB_MSM_MDSS_WRITEBACK=y +CONFIG_FB_MSM_MDSS_DSI_CTRL_STATUS=y +CONFIG_FB_MSM_MDSS_XLOG_DEBUG=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_MMC=y +CONFIG_MMC_PARANOID_SD_INIT=y +CONFIG_MMC_CLKGATE=y +CONFIG_MMC_BLOCK_MINORS=32 +CONFIG_MMC_BLOCK_DEFERRED_RESUME=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_MSM=y +CONFIG_MMC_CQ_HCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_QPNP=y +CONFIG_LEDS_QPNP_FLASH=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_WLED=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QPNP_VIBRATOR_LDO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_MM_EDAC=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_SPS_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_ION_MSM=y +CONFIG_IPA=y +CONFIG_RNDIS_IPA=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_QPNP_COINCELL=y +CONFIG_QPNP_REVID=y +CONFIG_MSM_MDSS_PLL=y +CONFIG_REMOTE_SPINLOCK_MSM=y +CONFIG_MAILBOX=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_MSM_SPM=y +CONFIG_MSM_L2_SPM=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_MSM_RPM_SMD=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SMEM=y +CONFIG_MSM_SMD=y +CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_SMP2P=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_MSM_PIL_MSS_QDSP6V5=y +CONFIG_ICNSS=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_MSM_BAM_DMUX=y +CONFIG_WCNSS_CORE=y +CONFIG_WCNSS_CORE_PRONTO=y +CONFIG_WCNSS_REGISTER_DUMP_ON_BITE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_SPDM_SCM=y +CONFIG_DEVFREQ_SPDM=y +CONFIG_PWM=y +CONFIG_PWM_QPNP=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QTI_MPM=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_SENSORS_SSC=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT3_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +# CONFIG_NETWORK_FILESYSTEMS is not set +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO_DWARF4=y +CONFIG_FRAME_WARN=2048 +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +CONFIG_PANIC_TIMEOUT=5 +CONFIG_STACKTRACE=y +# CONFIG_FTRACE is not set +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_ARM_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM_NEON=y +CONFIG_CRYPTO_SHA2_ARM_CE=y +CONFIG_CRYPTO_AES_ARM_BS=y +CONFIG_CRYPTO_AES_ARM_CE=y +CONFIG_QMI_ENCDEC=y -- GitLab From 9ec22990e53424f1f1618dfca8221304c6011ad1 Mon Sep 17 00:00:00 2001 From: Michael Adisumarta Date: Mon, 14 May 2018 17:12:48 -0700 Subject: [PATCH 1809/1834] msm: ipa4: Do not notify clk state starting at IPAv4.1 Add an if check to not send GATE/UNGATE notifications to IPA uC starting at IPAv4.1. Change-Id: I03595217ea7655997428738c2bfbef47aa4c68fd CRs-fixed: 2240786 Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_uc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c index f5ef141caf84..e746229db92e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -818,6 +818,11 @@ int ipa3_uc_notify_clk_state(bool enabled) { u32 opcode; + if (ipa3_ctx->ipa_hw_type > IPA_HW_v4_0) { + IPADBG_LOW("not supported past IPA v4.0\n"); + return 0; + } + /* * If the uC interface has not been initialized yet, * don't notify the uC on the enable/disable -- GitLab From 7c1d463d57e8fe40f71fa17018c2fb5e7fa372ab Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Wed, 16 May 2018 18:35:59 -0700 Subject: [PATCH 1810/1834] defconfig: msm8953-batcam: Enable iommu Enable the config options for iommu on this target. Change-Id: I6495020726de2314c6e8bf491dfeb7fe6e99cb3e Signed-off-by: Patrick Daly --- arch/arm/configs/msm8953-batcam-perf_defconfig | 3 +++ arch/arm/configs/msm8953-batcam_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/configs/msm8953-batcam-perf_defconfig b/arch/arm/configs/msm8953-batcam-perf_defconfig index c898654eb73e..1610d29ec009 100644 --- a/arch/arm/configs/msm8953-batcam-perf_defconfig +++ b/arch/arm/configs/msm8953-batcam-perf_defconfig @@ -193,6 +193,8 @@ CONFIG_QPNP_REVID=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y @@ -206,6 +208,7 @@ CONFIG_QCOM_EARLY_RANDOM=y CONFIG_MSM_SMEM=y CONFIG_MSM_SMD=y CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_TZ_SMMU=y CONFIG_MSM_SMP2P=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y diff --git a/arch/arm/configs/msm8953-batcam_defconfig b/arch/arm/configs/msm8953-batcam_defconfig index 2c7c1920ae5a..1ba9d96ca93b 100644 --- a/arch/arm/configs/msm8953-batcam_defconfig +++ b/arch/arm/configs/msm8953-batcam_defconfig @@ -194,6 +194,8 @@ CONFIG_QPNP_REVID=y CONFIG_MSM_MDSS_PLL=y CONFIG_REMOTE_SPINLOCK_MSM=y CONFIG_MAILBOX=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y CONFIG_QCOM_RUN_QUEUE_STATS=y CONFIG_MSM_SPM=y CONFIG_MSM_L2_SPM=y @@ -207,6 +209,7 @@ CONFIG_QCOM_EARLY_RANDOM=y CONFIG_MSM_SMEM=y CONFIG_MSM_SMD=y CONFIG_MSM_SMD_DEBUG=y +CONFIG_MSM_TZ_SMMU=y CONFIG_MSM_SMP2P=y CONFIG_MSM_SUBSYSTEM_RESTART=y CONFIG_MSM_PIL=y -- GitLab From 1b34fe7a3f4c5eaaf4c34523c0e9faeee9d4d6aa Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Tue, 8 May 2018 15:12:11 -0700 Subject: [PATCH 1811/1834] ARM: qcom: Add CONFIG_ARCH_MSM8953_BOOT_ORDERING Populate the devicetree at late init, after all platform device drivers are registered. Devices are probed in the order they are listed in devicetree, allowing greater flexibility for optimization. Change-Id: I2b49bba49d8a36d26a6f53d517125af0cdc5656a Signed-off-by: Patrick Daly --- arch/arm/mach-qcom/Kconfig | 11 +++++++++++ arch/arm/mach-qcom/board-msm8953.c | 17 +++++++++++++++++ drivers/of/platform.c | 2 +- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-qcom/Kconfig b/arch/arm/mach-qcom/Kconfig index 1ab1fbbe2721..b055b60ef9e3 100644 --- a/arch/arm/mach-qcom/Kconfig +++ b/arch/arm/mach-qcom/Kconfig @@ -65,6 +65,17 @@ config ARCH_MSM8953 select HAVE_CLK_PREPARE select COMMON_CLK_MSM +config ARCH_MSM8953_BOOT_ORDERING + bool "Enable support for MSM8953 device boot ordering" + default n + help + Populate devices from devicetree at late_init, after + drivers for all platform devices have been registered. + This causes devices to be probed in the order they are + listed in devicetree. Thus it is possible to have + greater control over the probe ordering such that + overall boot time can be reduced. + config ARCH_MSM8937 bool "Enable support for MSM8937" select CPU_V7 diff --git a/arch/arm/mach-qcom/board-msm8953.c b/arch/arm/mach-qcom/board-msm8953.c index 04b0bcc44603..de4538fb0e71 100644 --- a/arch/arm/mach-qcom/board-msm8953.c +++ b/arch/arm/mach-qcom/board-msm8953.c @@ -14,6 +14,7 @@ #include "board-dt.h" #include #include +#include static const char *msm8953_dt_match[] __initconst = { "qcom,msm8953", @@ -23,9 +24,25 @@ static const char *msm8953_dt_match[] __initconst = { static void __init msm8953_init(void) { + if (IS_ENABLED(CONFIG_ARCH_MSM8953_BOOT_ORDERING)) + return; board_dt_populate(NULL); } +#ifdef CONFIG_ARCH_MSM8953_BOOT_ORDERING +static int __init msm8953_dt_populate(void) +{ + of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + + /* Explicitly parent the /soc devices to the root node to preserve + * the kernel ABI (sysfs structure, etc) until userspace is updated + */ + of_platform_populate(of_find_node_by_path("/soc"), + of_default_bus_match_table, NULL, NULL); +} +late_initcall(msm8953_dt_populate); +#endif + DT_MACHINE_START(MSM8953_DT, "Qualcomm Technologies, Inc. MSM8953 (Flattened Device Tree)") .init_machine = msm8953_init, diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 4aba42f92359..8d8e4c5ea5c0 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -502,7 +502,7 @@ int of_platform_default_populate(struct device_node *root, } EXPORT_SYMBOL_GPL(of_platform_default_populate); -#ifndef CONFIG_PPC +#if !defined(CONFIG_PPC) && !defined(CONFIG_ARCH_MSM8953_BOOT_ORDERING) static int __init of_platform_default_populate_init(void) { struct device_node *node; -- GitLab From f891f37a8dce07a39e4665fbcc80962e60985415 Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Fri, 27 Apr 2018 18:09:23 -0700 Subject: [PATCH 1812/1834] ARM: dts: msm: Optimize boot order for msm8953 iot of_platform_populate adds devices in the order they are listed in devicetree. If the relevant device_driver is also registered, this is the order the devices are probed in. For this particular target, the sdhci driver and its dependencies has the longest probe time, so start it first, as it can run asynchronously. Change-Id: Ife9609400354c2707ebb80b995dac3b5bc7044f3 Signed-off-by: Patrick Daly --- arch/arm64/boot/dts/qcom/msm8953.dtsi | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/msm8953.dtsi b/arch/arm64/boot/dts/qcom/msm8953.dtsi index cd0afec0c638..331d074ff521 100644 --- a/arch/arm64/boot/dts/qcom/msm8953.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8953.dtsi @@ -17,6 +17,7 @@ #include #include #include +#include / { model = "Qualcomm Technologies, Inc. MSM8953"; @@ -168,7 +169,18 @@ spi3 = &spi_3; }; - soc: soc { }; + soc: soc { + /* + * The ordering of these devices is important to boot time + * for iot projects. + */ + smem: qcom,smem@86300000 {}; + rpm_bus: qcom,rpm-smd {}; + clock_gcc: qcom,gcc@1800000 {}; + ad_hoc_bus: ad-hoc-bus@580000 {}; + tlmm: pinctrl@1000000 {}; + sdhc_1: sdhci@7824900 {}; + }; }; -- GitLab From 050f257a00714b85b591c201e5ed9f5eca392c8d Mon Sep 17 00:00:00 2001 From: Patrick Daly Date: Mon, 7 May 2018 13:07:50 -0700 Subject: [PATCH 1813/1834] PM/Hibernate: Add Config option to skip crc check Some filesystem devices may have hw support for integrity checks. Repeating the check in software is unnecessary. Change-Id: I3a487e1714aecd57124f9b032751ee71d6d6dc37 Signed-off-by: Patrick Daly --- kernel/power/Kconfig | 10 ++++++++++ kernel/power/swap.c | 10 ++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index a29eaee3789d..bf60b37f1df1 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -94,6 +94,16 @@ config HIBERNATION_IMAGE_REUSE For more details, refer to the description of CONFIG_HIBERNATION for booting without resuming. +config HIBERNATION_SKIP_CRC + bool "Skip LZO image CRC check" + default n + depends on HIBERNATION + ---help--- + Some filesystem devices may have hw based integrity checks. In this + scenario, repeating the integrity check in software is unnecessary + and wasteful. This config option has no effect if uncompressed + hibernation images are used. + config ARCH_SAVE_PAGE_KEYS bool diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 95db6b79f6fa..1f6aef2e2131 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -606,9 +606,10 @@ static int crc32_threadfn(void *data) } atomic_set(&d->ready, 0); - for (i = 0; i < d->run_threads; i++) - *d->crc32 = crc32_le(*d->crc32, - d->unc[i], *d->unc_len[i]); + if (!IS_ENABLED(CONFIG_HIBERNATION_SKIP_CRC)) + for (i = 0; i < d->run_threads; i++) + *d->crc32 = crc32_le(*d->crc32, + d->unc[i], *d->unc_len[i]); atomic_set(&d->stop, 1); wake_up(&d->done); } @@ -1455,7 +1456,8 @@ static int load_image_lzo(struct swap_map_handle *handle, if (!snapshot_image_loaded(snapshot)) ret = -ENODATA; if (!ret) { - if (swsusp_header->flags & SF_CRC32_MODE) { + if ((swsusp_header->flags & SF_CRC32_MODE) && + (!IS_ENABLED(CONFIG_HIBERNATION_SKIP_CRC))) { if(handle->crc32 != swsusp_header->crc32) { printk(KERN_ERR "PM: Invalid image CRC32!\n"); -- GitLab From 29eb0b7140ef7c9fcf798122b9b51747ccfc01db Mon Sep 17 00:00:00 2001 From: Jasleen Kalsi Date: Tue, 8 May 2018 18:54:56 +0530 Subject: [PATCH 1814/1834] soc: qcom: fix broken modem event notification chain Change the microdump notify return status as NOTIFY_OK to let other registered client receive notifications Change-Id: Ibf2afad707d381f981b679803634bff9e70ad556 Signed-off-by: Jasleen Kalsi --- drivers/soc/qcom/microdump_collector.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/soc/qcom/microdump_collector.c b/drivers/soc/qcom/microdump_collector.c index 4a22b4dc6c4e..6e9da60ed118 100644 --- a/drivers/soc/qcom/microdump_collector.c +++ b/drivers/soc/qcom/microdump_collector.c @@ -48,9 +48,9 @@ static int microdump_modem_notifier_nb(struct notifier_block *nb, crash_reason = smem_get_entry(SMEM_SSR_REASON_MSS0, &size_reason , 0, SMEM_ANY_HOST_FLAG); if (IS_ERR_OR_NULL(crash_reason)) { - pr_err("%s: Error in getting SMEM_reason pointer\n", - __func__); - return -ENODEV; + pr_info("%s: smem %d not available\n", + __func__, SMEM_SSR_REASON_MSS0); + goto out; } segment[0].v_address = crash_reason; @@ -58,9 +58,9 @@ static int microdump_modem_notifier_nb(struct notifier_block *nb, crash_data = smem_get_entry(smem_id, &size_data, SMEM_MODEM, 0); if (IS_ERR_OR_NULL(crash_data)) { - pr_err("%s: Error in getting SMEM_data pointer\n", - __func__); - return -ENODEV; + pr_info("%s: smem %d not available\n ", + __func__, smem_id); + goto out; } segment[1].v_address = crash_data; @@ -68,10 +68,11 @@ static int microdump_modem_notifier_nb(struct notifier_block *nb, ret = do_ramdump(drv->microdump_dev, segment, 2); if (ret) - pr_err("%s: do_ramdump() failed\n", __func__); + pr_info("%s: do_ramdump() failed\n", __func__); } - return ret; +out: + return NOTIFY_OK; } static int microdump_modem_ssr_register_notifier(struct microdump_data *drv) -- GitLab From 9cd7f312d9b129caeaf669d28ced14ad0b6060a9 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 16 May 2018 17:35:51 +0530 Subject: [PATCH 1815/1834] serial: msm_geni_serial: use correct API to free memory Uart driver uses devm* callback to allocate memory but uses non devm* callback to free the same allocated memory. This leads to memory leak. Use the right callback to free memory. Change-Id: Ia80603d09bf7a59fc2e0467ca33df0a618eabe4e Signed-off-by: Alok Chauhan --- drivers/tty/serial/msm_geni_serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index f76b3dba0bc0..8e5d1000ff12 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -1660,7 +1660,7 @@ static int msm_geni_serial_port_setup(struct uart_port *uport) msm_port->rx_buf = devm_kzalloc(uport->dev, DMA_RX_BUF_SIZE, GFP_KERNEL); if (!msm_port->rx_buf) { - kfree(msm_port->rx_fifo); + devm_kfree(uport->dev, msm_port->rx_fifo); msm_port->rx_fifo = NULL; ret = -ENOMEM; goto exit_portsetup; -- GitLab From ffb434063b625ffa919a1df6205096d6c6f3c112 Mon Sep 17 00:00:00 2001 From: Manoj Prabhu B Date: Thu, 17 May 2018 12:08:51 +0530 Subject: [PATCH 1816/1834] diag: Add new log codes to diag mask The patch adds new requested log codes to diag mask. Change-Id: I4124e55077ae63b9c0c349feed409851108261d3 Signed-off-by: Manoj Prabhu B --- include/linux/diagchar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/diagchar.h b/include/linux/diagchar.h index a3d9563e7f4e..d9912e07b7a9 100644 --- a/include/linux/diagchar.h +++ b/include/linux/diagchar.h @@ -896,7 +896,7 @@ static const uint32_t msg_bld_masks_25[] = { /* LOG CODES */ static const uint32_t log_code_last_tbl[] = { 0x0, /* EQUIP ID 0 */ - 0x1C68, /* EQUIP ID 1 */ + 0x1C6A, /* EQUIP ID 1 */ 0x0, /* EQUIP ID 2 */ 0x0, /* EQUIP ID 3 */ 0x4910, /* EQUIP ID 4 */ -- GitLab From 317d9a5ee9ada73f35a16446f0d21edb75219930 Mon Sep 17 00:00:00 2001 From: Shrey Vijay Date: Wed, 9 May 2018 15:11:49 +0530 Subject: [PATCH 1817/1834] qcom-geni-se: Disable FIFO watermark irq in DMA mode Disable RX and TX FIFO watermark interrupts in SE_DMA mode of transfer, as these interrupts are not required. Signed-off-by: Shrey Vijay Change-Id: I48b83d31b1eb2c651807bcd5b1052908b941dff2 --- drivers/platform/msm/qcom-geni-se.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/platform/msm/qcom-geni-se.c b/drivers/platform/msm/qcom-geni-se.c index 6ce21613d5ce..ed4b837017fe 100644 --- a/drivers/platform/msm/qcom-geni-se.c +++ b/drivers/platform/msm/qcom-geni-se.c @@ -317,7 +317,9 @@ static int geni_se_select_fifo_mode(void __iomem *base) static int geni_se_select_dma_mode(void __iomem *base) { + int proto = get_se_proto(base); unsigned int geni_dma_mode = 0; + unsigned int common_geni_m_irq_en; geni_write_reg(0, base, SE_GSI_EVENT_EN); geni_write_reg(0xFFFFFFFF, base, SE_GENI_M_IRQ_CLEAR); @@ -326,6 +328,12 @@ static int geni_se_select_dma_mode(void __iomem *base) geni_write_reg(0xFFFFFFFF, base, SE_DMA_RX_IRQ_CLR); geni_write_reg(0xFFFFFFFF, base, SE_IRQ_EN); + common_geni_m_irq_en = geni_read_reg(base, SE_GENI_M_IRQ_EN); + if (proto != UART) + common_geni_m_irq_en &= + ~(M_TX_FIFO_WATERMARK_EN | M_RX_FIFO_WATERMARK_EN); + + geni_write_reg(common_geni_m_irq_en, base, SE_GENI_M_IRQ_EN); geni_dma_mode = geni_read_reg(base, SE_GENI_DMA_MODE_EN); geni_dma_mode |= GENI_DMA_MODE_EN; geni_write_reg(geni_dma_mode, base, SE_GENI_DMA_MODE_EN); -- GitLab From 26afe2b68ab2c0f7997df646d956c1f0df3ca443 Mon Sep 17 00:00:00 2001 From: Sarada Prasanna Garnayak Date: Tue, 1 May 2018 18:44:44 +0530 Subject: [PATCH 1818/1834] wcnss: enable ipc logging for the wcnss wlan module Enable IPC logging in the wcnss platform driver for runtime debugging and wlan hardware register dump during subsystem restart. CRs-Fixed: 2243709 Change-Id: I05619b62e3c78e7df992698de813d7bfb976b55a Signed-off-by: Sarada Prasanna Garnayak --- drivers/soc/qcom/wcnss/wcnss_vreg.c | 81 ++-- drivers/soc/qcom/wcnss/wcnss_wlan.c | 599 ++++++++++++++++------------ include/linux/wcnss_wlan.h | 8 + 3 files changed, 392 insertions(+), 296 deletions(-) diff --git a/drivers/soc/qcom/wcnss/wcnss_vreg.c b/drivers/soc/qcom/wcnss/wcnss_vreg.c index 9d24ce114a0b..1e61250f6ddb 100644 --- a/drivers/soc/qcom/wcnss/wcnss_vreg.c +++ b/drivers/soc/qcom/wcnss/wcnss_vreg.c @@ -206,7 +206,7 @@ wcnss_dt_parse_vreg_level(struct device *dev, int index, voltage_levels, ARRAY_SIZE(voltage_levels)); if (ret) { - dev_err(dev, "error reading %s property\n", vreg_name); + wcnss_log(ERR, "error reading %s property\n", vreg_name); return ret; } @@ -217,7 +217,8 @@ wcnss_dt_parse_vreg_level(struct device *dev, int index, ret = of_property_read_u32(dev->of_node, current_vreg_name, ¤t_vreg); if (ret) { - dev_err(dev, "error reading %s property\n", current_vreg_name); + wcnss_log(ERR, "error reading %s property\n", + current_vreg_name); return ret; } @@ -240,12 +241,14 @@ wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config, if (IS_ERR(pronto_vregs[vreg_i].regulator)) { if (pronto_vregs[vreg_i].required) { rc = PTR_ERR(pronto_vregs[vreg_i].regulator); - dev_err(dev, "regulator get of %s failed (%d)\n", + wcnss_log(ERR, + "regulator get of %s failed (%d)\n", pronto_vregs[vreg_i].name, rc); return rc; } else { - dev_dbg(dev, "Skip optional regulator configuration: %s\n", - pronto_vregs[vreg_i].name); + wcnss_log(DBG, + "Skip optional regulator configuration: %s\n", + pronto_vregs[vreg_i].name); continue; } } @@ -255,7 +258,8 @@ wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config, pronto_vregs[vreg_i].volt, wlan_config->pronto_vlevel); if (rc) { - dev_err(dev, "error reading voltage-level property\n"); + wcnss_log(ERR, + "error reading voltage-level property\n"); return rc; } pronto_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK; @@ -269,12 +273,14 @@ wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config, if (IS_ERR(iris_vregs[vreg_i].regulator)) { if (iris_vregs[vreg_i].required) { rc = PTR_ERR(iris_vregs[vreg_i].regulator); - dev_err(dev, "regulator get of %s failed (%d)\n", + wcnss_log(ERR, + "regulator get of %s failed (%d)\n", iris_vregs[vreg_i].name, rc); return rc; } else { - dev_dbg(dev, "Skip optional regulator configuration: %s\n", - iris_vregs[vreg_i].name); + wcnss_log(DBG, + "Skip optional regulator configuration: %s\n", + iris_vregs[vreg_i].name); continue; } } @@ -284,7 +290,8 @@ wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config, iris_vregs[vreg_i].volt, wlan_config->iris_vlevel); if (rc) { - dev_err(dev, "error reading voltage-level property\n"); + wcnss_log(ERR, + "error reading voltage-level property\n"); return rc; } iris_vregs[vreg_i].state |= VREG_GET_REGULATOR_MASK; @@ -334,7 +341,7 @@ configure_iris_xo(struct device *dev, clk = clk_get(dev, "xo"); if (IS_ERR(clk)) { - pr_err("Couldn't get xo clock\n"); + wcnss_log(ERR, "Couldn't get xo clock\n"); return PTR_ERR(clk); } @@ -344,7 +351,7 @@ configure_iris_xo(struct device *dev, clk = clk_get(dev, "cxo"); if (IS_ERR(clk)) { - pr_err("Couldn't get cxo clock\n"); + wcnss_log(ERR, "Couldn't get cxo clock\n"); return PTR_ERR(clk); } } @@ -352,21 +359,21 @@ configure_iris_xo(struct device *dev, if (on) { msm_wcnss_base = cfg->msm_wcnss_base; if (!msm_wcnss_base) { - pr_err("ioremap wcnss physical failed\n"); + wcnss_log(ERR, "ioremap wcnss physical failed\n"); goto fail; } /* Enable IRIS XO */ rc = clk_prepare_enable(clk); if (rc) { - pr_err("clk enable failed\n"); + wcnss_log(ERR, "clk enable failed\n"); goto fail; } /* NV bit is set to indicate that platform driver is capable * of doing NV download. */ - pr_debug("wcnss: Indicate NV bin download\n"); + wcnss_log(DBG, "Indicate NV bin download\n"); spare_reg = msm_wcnss_base + spare_offset; reg = readl_relaxed(spare_reg); reg |= NVBIN_DLND_BIT; @@ -403,10 +410,11 @@ configure_iris_xo(struct device *dev, cpu_relax(); iris_reg = readl_relaxed(iris_read_reg); - pr_info("wcnss: IRIS Reg: %08x\n", iris_reg); + wcnss_log(INFO, "IRIS Reg: %08x\n", iris_reg); if (validate_iris_chip_id(iris_reg) && i >= 4) { - pr_info("wcnss: IRIS Card absent/invalid\n"); + wcnss_log(INFO, + "IRIS Card absent/invalid\n"); auto_detect = WCNSS_XO_INVALID; /* Reset iris read bit */ reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ; @@ -416,7 +424,8 @@ configure_iris_xo(struct device *dev, reg &= ~(WCNSS_PMU_CFG_IRIS_XO_MODE); goto xo_configure; } else if (!validate_iris_chip_id(iris_reg)) { - pr_debug("wcnss: IRIS Card is present\n"); + wcnss_log(DBG, + "IRIS Card is present\n"); break; } reg &= ~WCNSS_PMU_CFG_IRIS_XO_READ; @@ -472,13 +481,13 @@ configure_iris_xo(struct device *dev, auto_detect == WCNSS_XO_19MHZ) { clk_rf = clk_get(dev, "rf_clk"); if (IS_ERR(clk_rf)) { - pr_err("Couldn't get rf_clk\n"); + wcnss_log(ERR, "Couldn't get rf_clk\n"); goto fail; } rc = clk_prepare_enable(clk_rf); if (rc) { - pr_err("clk_rf enable failed\n"); + wcnss_log(ERR, "clk_rf enable failed\n"); goto fail; } if (iris_xo_set) @@ -489,7 +498,7 @@ configure_iris_xo(struct device *dev, auto_detect == WCNSS_XO_19MHZ) { clk_rf = clk_get(dev, "rf_clk"); if (IS_ERR(clk_rf)) { - pr_err("Couldn't get rf_clk\n"); + wcnss_log(ERR, "Couldn't get rf_clk\n"); goto fail; } clk_disable_unprepare(clk_rf); @@ -517,7 +526,7 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size, cfg = wcnss_get_wlan_config(); if (!cfg) { - pr_err("Failed to get WLAN configuration\n"); + wcnss_log(ERR, "Failed to get WLAN configuration\n"); return; } @@ -530,7 +539,8 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size, if (regulators[i].state & VREG_OPTIMUM_MODE_MASK) { rc = regulator_set_load(regulators[i].regulator, 0); if (rc < 0) { - pr_err("regulator set load(%s) failed (%d)\n", + wcnss_log(ERR, + "regulator set load(%s) failed (%d)\n", regulators[i].name, rc); } } @@ -553,15 +563,16 @@ static void wcnss_vregs_off(struct vregs_info regulators[], uint size, max_voltage); if (rc) - pr_err("regulator_set_voltage(%s) failed (%d)\n", - regulators[i].name, rc); + wcnss_log(ERR, + "regulator_set_voltage(%s) failed (%d)\n", + regulators[i].name, rc); } /* Disable regulator */ if (regulators[i].state & VREG_ENABLE_MASK) { rc = regulator_disable(regulators[i].regulator); if (rc < 0) - pr_err("vreg %s disable failed (%d)\n", + wcnss_log(ERR, "vreg %s disable failed (%d)\n", regulators[i].name, rc); } } @@ -579,7 +590,7 @@ static int wcnss_vregs_on(struct device *dev, cfg = wcnss_get_wlan_config(); if (!cfg) { - pr_err("Failed to get WLAN configuration\n"); + wcnss_log(ERR, "Failed to get WLAN configuration\n"); return -EINVAL; } @@ -608,7 +619,8 @@ static int wcnss_vregs_on(struct device *dev, max_voltage); if (rc) { - pr_err("regulator_set_voltage(%s) failed (%d)\n", + wcnss_log(ERR, + "regulator_set_voltage(%s) failed (%d)\n", regulators[i].name, rc); goto fail; } @@ -620,7 +632,8 @@ static int wcnss_vregs_on(struct device *dev, rc = regulator_set_load(regulators[i].regulator, voltage_level[i].uA_load); if (rc < 0) { - pr_err("regulator set load(%s) failed (%d)\n", + wcnss_log(ERR, + "regulator set load(%s) failed (%d)\n", regulators[i].name, rc); goto fail; } @@ -630,7 +643,7 @@ static int wcnss_vregs_on(struct device *dev, /* Enable the regulator */ rc = regulator_enable(regulators[i].regulator); if (rc) { - pr_err("vreg %s enable failed (%d)\n", + wcnss_log(ERR, "vreg %s enable failed (%d)\n", regulators[i].name, rc); goto fail; } @@ -653,7 +666,7 @@ static void wcnss_iris_vregs_off(enum wcnss_hw_type hw_type, cfg->iris_vlevel); break; default: - pr_err("%s invalid hardware %d\n", __func__, hw_type); + wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type); } } @@ -669,7 +682,7 @@ static int wcnss_iris_vregs_on(struct device *dev, cfg->iris_vlevel); break; default: - pr_err("%s invalid hardware %d\n", __func__, hw_type); + wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type); } return ret; } @@ -683,7 +696,7 @@ static void wcnss_core_vregs_off(enum wcnss_hw_type hw_type, ARRAY_SIZE(pronto_vregs), cfg->pronto_vlevel); break; default: - pr_err("%s invalid hardware %d\n", __func__, hw_type); + wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type); } } @@ -700,7 +713,7 @@ static int wcnss_core_vregs_on(struct device *dev, cfg->pronto_vlevel); break; default: - pr_err("%s invalid hardware %d\n", __func__, hw_type); + wcnss_log(ERR, "%s invalid hardware %d\n", __func__, hw_type); } return ret; diff --git a/drivers/soc/qcom/wcnss/wcnss_wlan.c b/drivers/soc/qcom/wcnss/wcnss_wlan.c index c3fb30b3a715..08bd78b55364 100644 --- a/drivers/soc/qcom/wcnss/wcnss_wlan.c +++ b/drivers/soc/qcom/wcnss/wcnss_wlan.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -452,6 +453,53 @@ static struct { struct cdev ctrl_dev, node_dev; } *penv = NULL; +static void *wcnss_ipc_log; + +#define IPC_NUM_LOG_PAGES 12 +#define wcnss_ipc_log_string(_x...) do { \ + if (wcnss_ipc_log) \ + ipc_log_string(wcnss_ipc_log, _x); \ + } while (0) + +void wcnss_log(enum wcnss_log_type type, const char *_fmt, ...) +{ + struct va_format vaf = { + .fmt = _fmt, + }; + va_list args; + + va_start(args, _fmt); + vaf.va = &args; + switch (type) { + case ERR: + pr_err("wcnss: %pV", &vaf); + wcnss_ipc_log_string("wcnss: %pV", &vaf); + break; + case WARN: + pr_warn("wcnss: %pV", &vaf); + wcnss_ipc_log_string("wcnss: %pV", &vaf); + break; + case INFO: + pr_info("wcnss: %pV", &vaf); + wcnss_ipc_log_string("wcnss: %pV", &vaf); + break; + case DBG: +#if defined(CONFIG_DYNAMIC_DEBUG) + pr_debug("wcnss: %pV", &vaf); + wcnss_ipc_log_string("wcnss: %pV", &vaf); +#elif defined(DEBUG) + pr_debug("wcnss: %pV", &vaf); + wcnss_ipc_log_string("wcnss: %pV", &vaf); +#else + pr_devel("wcnss: %pV", &vaf); + wcnss_ipc_log_string("wcnss: %pV", &vaf); +#endif + break; + } + va_end(args); +} +EXPORT_SYMBOL(wcnss_log); + static ssize_t wcnss_wlan_macaddr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -463,14 +511,14 @@ static ssize_t wcnss_wlan_macaddr_store(struct device *dev, return -ENODEV; if (strlen(buf) != WCNSS_USER_MAC_ADDR_LENGTH) { - dev_err(dev, "%s: Invalid MAC addr length\n", __func__); + wcnss_log(ERR, "%s: Invalid MAC addr length\n", __func__); return -EINVAL; } if (sscanf(buf, MAC_ADDRESS_STR, &mac_addr[0], &mac_addr[1], &mac_addr[2], &mac_addr[3], &mac_addr[4], &mac_addr[5]) != WLAN_MAC_ADDR_SIZE) { - pr_err("%s: Failed to Copy MAC\n", __func__); + wcnss_log(ERR, "%s: Failed to Copy MAC\n", __func__); return -EINVAL; } @@ -479,7 +527,7 @@ static ssize_t wcnss_wlan_macaddr_store(struct device *dev, (char *)&mac_addr[index], sizeof(char)); } - pr_info("%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__, + wcnss_log(INFO, "%s: Write MAC Addr:" MAC_ADDRESS_STR "\n", __func__, penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1], penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3], penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]); @@ -555,19 +603,19 @@ void wcnss_riva_log_debug_regs(void) ccu_reg = penv->riva_ccu_base + CCU_RIVA_INVALID_ADDR_OFFSET; reg = readl_relaxed(ccu_reg); - pr_info_ratelimited("%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg); + wcnss_log(INFO, "%s: CCU_CCPU_INVALID_ADDR %08x\n", __func__, reg); ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR0_OFFSET; reg = readl_relaxed(ccu_reg); - pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg); + wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR0 %08x\n", __func__, reg); ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR1_OFFSET; reg = readl_relaxed(ccu_reg); - pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg); + wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR1 %08x\n", __func__, reg); ccu_reg = penv->riva_ccu_base + CCU_RIVA_LAST_ADDR2_OFFSET; reg = readl_relaxed(ccu_reg); - pr_info_ratelimited("%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg); + wcnss_log(INFO, "%s: CCU_CCPU_LAST_ADDR2 %08x\n", __func__, reg); } EXPORT_SYMBOL(wcnss_riva_log_debug_regs); @@ -586,13 +634,12 @@ void wcnss_pronto_is_a2xb_bus_stall(void *tst_addr, u32 fifo_mask, char *type) break; } - if (iter == A2XB_FIFO_COUNTER) { - pr_err("%s data FIFO testbus possibly stalled reg%08x\n", - type, reg); - } else { - pr_err("%s data FIFO tstbus not stalled reg%08x\n", - type, reg); - } + if (iter == A2XB_FIFO_COUNTER) + wcnss_log(ERR, + "%s data FIFO testbus possibly stalled reg%08x\n", type, reg); + else + wcnss_log(ERR, + "%s data FIFO tstbus not stalled reg%08x\n", type, reg); } int wcnss_get_dual_band_capability_info(struct platform_device *pdev) @@ -627,71 +674,72 @@ void wcnss_pronto_log_debug_regs(void) reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SPARE_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_SPARE %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_SPARE %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CPU_CBCR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_COM_CPU_CBCR %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_COM_CPU_CBCR %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_AHB_CBCR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_COM_AHB_CBCR %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_COM_AHB_CBCR %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CFG_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_CFG %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_CFG %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_CSR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_COM_CSR %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_COM_CSR %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_SOFT_RESET_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_SOFT_RESET %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_SOFT_RESET %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WDOG_CTL; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_WDOG_CTL %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_WDOG_CTL %08x\n", reg); reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_STS_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_SAW2_SPM_STS %08x\n", reg); + wcnss_log(ERR, "PRONTO_SAW2_SPM_STS %08x\n", reg); reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SPM_CTL; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_SAW2_SPM_CTL %08x\n", reg); + wcnss_log(ERR, "PRONTO_SAW2_SPM_CTL %08x\n", reg); if (penv->is_a2xb_split_reg) { reg_addr = penv->msm_wcnss_base + PMU_A2XB_CFG_HSPLIT_RESP_LIMIT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PMU_A2XB_CFG_HSPLIT_RESP_LIMIT %08x\n", reg); + wcnss_log(ERR, "PMU_A2XB_CFG_HSPLIT_RESP_LIMIT %08x\n", reg); } reg_addr = penv->pronto_saw2_base + PRONTO_SAW2_SAW2_VERSION; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_SAW2_SAW2_VERSION %08x\n", reg); + wcnss_log(ERR, "PRONTO_SAW2_SAW2_VERSION %08x\n", reg); reg >>= PRONTO_SAW2_MAJOR_VER_OFFSET; reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CCPU_BOOT_REMAP_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_CCPU_BOOT_REMAP %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_CCPU_BOOT_REMAP %08x\n", reg); reg_addr = penv->pronto_pll_base + PRONTO_PLL_STATUS_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PLL_STATUS %08x\n", reg); + wcnss_log(ERR, "PRONTO_PLL_STATUS %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_CPU_AHB_CMD_RCGR_OFFSET; reg4 = readl_relaxed(reg_addr); - pr_err("PMU_CPU_CMD_RCGR %08x\n", reg4); + wcnss_log(ERR, "PMU_CPU_CMD_RCGR %08x\n", reg4); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_COM_GDSCR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("PRONTO_PMU_COM_GDSCR %08x\n", reg); + wcnss_log(ERR, "PRONTO_PMU_COM_GDSCR %08x\n", reg); reg >>= 31; if (!reg) { - pr_err("Cannot log, Pronto common SS is power collapsed\n"); + wcnss_log(ERR, + "Cannot log, Pronto common SS is power collapsed\n"); return; } reg &= ~(PRONTO_PMU_COM_GDSCR_SW_COLLAPSE @@ -705,47 +753,47 @@ void wcnss_pronto_log_debug_regs(void) reg_addr = penv->pronto_a2xb_base + A2XB_CFG_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("A2XB_CFG_OFFSET %08x\n", reg); + wcnss_log(ERR, "A2XB_CFG_OFFSET %08x\n", reg); reg_addr = penv->pronto_a2xb_base + A2XB_INT_SRC_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("A2XB_INT_SRC_OFFSET %08x\n", reg); + wcnss_log(ERR, "A2XB_INT_SRC_OFFSET %08x\n", reg); reg_addr = penv->pronto_a2xb_base + A2XB_ERR_INFO_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("A2XB_ERR_INFO_OFFSET %08x\n", reg); + wcnss_log(ERR, "A2XB_ERR_INFO_OFFSET %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_INVALID_ADDR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_CCPU_INVALID_ADDR %08x\n", reg); + wcnss_log(ERR, "CCU_CCPU_INVALID_ADDR %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR0_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_CCPU_LAST_ADDR0 %08x\n", reg); + wcnss_log(ERR, "CCU_CCPU_LAST_ADDR0 %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR1_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_CCPU_LAST_ADDR1 %08x\n", reg); + wcnss_log(ERR, "CCU_CCPU_LAST_ADDR1 %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_LAST_ADDR2_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_CCPU_LAST_ADDR2 %08x\n", reg); + wcnss_log(ERR, "CCU_CCPU_LAST_ADDR2 %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET %08x\n", reg); + wcnss_log(ERR, "CCU_PRONTO_AOWBR_ERR_ADDR_OFFSET %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET %08x\n", reg); + wcnss_log(ERR, "CCU_PRONTO_AOWBR_TIMEOUT_REG_OFFSET %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET %08x\n", reg); + wcnss_log(ERR, "CCU_PRONTO_AOWBR_ERR_TIMEOUT_OFFSET %08x\n", reg); reg_addr = penv->pronto_ccpu_base + CCU_PRONTO_A2AB_ERR_ADDR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("CCU_PRONTO_A2AB_ERR_ADDR_OFFSET %08x\n", reg); + wcnss_log(ERR, "CCU_PRONTO_A2AB_ERR_ADDR_OFFSET %08x\n", reg); tst_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_OFFSET; tst_ctrl_addr = penv->pronto_a2xb_base + A2XB_TSTBUS_CTRL_OFFSET; @@ -760,7 +808,7 @@ void wcnss_pronto_log_debug_regs(void) A2XB_READ_FIFO_FILL_MASK, "Read"); } else { - pr_err("Read data FIFO testbus %08x\n", reg); + wcnss_log(ERR, "Read data FIFO testbus %08x\n", reg); } /* command FIFO */ reg = 0; @@ -771,7 +819,7 @@ void wcnss_pronto_log_debug_regs(void) wcnss_pronto_is_a2xb_bus_stall(tst_addr, A2XB_CMD_FIFO_FILL_MASK, "Cmd"); } else { - pr_err("Command FIFO testbus %08x\n", reg); + wcnss_log(ERR, "Command FIFO testbus %08x\n", reg); } /* write data FIFO */ @@ -784,7 +832,7 @@ void wcnss_pronto_log_debug_regs(void) A2XB_WRITE_FIFO_FILL_MASK, "Write"); } else { - pr_err("Write data FIFO testbus %08x\n", reg); + wcnss_log(ERR, "Write data FIFO testbus %08x\n", reg); } /* AXIM SEL CFG0 */ @@ -793,7 +841,7 @@ void wcnss_pronto_log_debug_regs(void) WCNSS_TSTBUS_CTRL_AXIM_CFG0; writel_relaxed(reg, tst_ctrl_addr); reg = readl_relaxed(tst_addr); - pr_err("AXIM SEL CFG0 testbus %08x\n", reg); + wcnss_log(ERR, "AXIM SEL CFG0 testbus %08x\n", reg); /* AXIM SEL CFG1 */ reg = 0; @@ -801,7 +849,7 @@ void wcnss_pronto_log_debug_regs(void) WCNSS_TSTBUS_CTRL_AXIM_CFG1; writel_relaxed(reg, tst_ctrl_addr); reg = readl_relaxed(tst_addr); - pr_err("AXIM SEL CFG1 testbus %08x\n", reg); + wcnss_log(ERR, "AXIM SEL CFG1 testbus %08x\n", reg); /* CTRL SEL CFG0 */ reg = 0; @@ -809,7 +857,7 @@ void wcnss_pronto_log_debug_regs(void) WCNSS_TSTBUS_CTRL_CTRL_CFG0; writel_relaxed(reg, tst_ctrl_addr); reg = readl_relaxed(tst_addr); - pr_err("CTRL SEL CFG0 testbus %08x\n", reg); + wcnss_log(ERR, "CTRL SEL CFG0 testbus %08x\n", reg); /* CTRL SEL CFG1 */ reg = 0; @@ -817,7 +865,7 @@ void wcnss_pronto_log_debug_regs(void) WCNSS_TSTBUS_CTRL_CTRL_CFG1; writel_relaxed(reg, tst_ctrl_addr); reg = readl_relaxed(tst_addr); - pr_err("CTRL SEL CFG1 testbus %08x\n", reg); + wcnss_log(ERR, "CTRL SEL CFG1 testbus %08x\n", reg); reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_BCR_OFFSET; reg = readl_relaxed(reg_addr); @@ -827,7 +875,7 @@ void wcnss_pronto_log_debug_regs(void) reg_addr = penv->msm_wcnss_base + PRONTO_PMU_WLAN_AHB_CBCR_OFFSET; reg3 = readl_relaxed(reg_addr); - pr_err("PMU_WLAN_AHB_CBCR %08x\n", reg3); + wcnss_log(ERR, "PMU_WLAN_AHB_CBCR %08x\n", reg3); msleep(50); @@ -836,76 +884,76 @@ void wcnss_pronto_log_debug_regs(void) (!(reg4 & PRONTO_PMU_CPU_AHB_CMD_RCGR_ROOT_EN)) || (reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_OFF) || (!(reg3 & PRONTO_PMU_WLAN_AHB_CBCR_CLK_EN))) { - pr_err("Cannot log, wlan domain is power collapsed\n"); + wcnss_log(ERR, "Cannot log, wlan domain is power collapsed\n"); return; } reg = readl_relaxed(penv->wlan_tx_phy_aborts); - pr_err("WLAN_TX_PHY_ABORTS %08x\n", reg); + wcnss_log(ERR, "WLAN_TX_PHY_ABORTS %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_APB2PHY_STATUS_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_APB2PHY_STATUS %08x\n", reg); + wcnss_log(ERR, "MCU_APB2PHY_STATUS %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_ERR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_CBR_CCAHB_ERR %08x\n", reg); + wcnss_log(ERR, "MCU_CBR_CCAHB_ERR %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_ERR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_CBR_CAHB_ERR %08x\n", reg); + wcnss_log(ERR, "MCU_CBR_CAHB_ERR %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_CBR_CCAHB_TIMEOUT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_CBR_CCAHB_TIMEOUT %08x\n", reg); + wcnss_log(ERR, "MCU_CBR_CCAHB_TIMEOUT %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_CBR_CAHB_TIMEOUT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_CBR_CAHB_TIMEOUT %08x\n", reg); + wcnss_log(ERR, "MCU_CBR_CAHB_TIMEOUT %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_ERR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_DBR_CDAHB_ERR %08x\n", reg); + wcnss_log(ERR, "MCU_DBR_CDAHB_ERR %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_ERR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_DBR_DAHB_ERR %08x\n", reg); + wcnss_log(ERR, "MCU_DBR_DAHB_ERR %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_DBR_CDAHB_TIMEOUT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_DBR_CDAHB_TIMEOUT %08x\n", reg); + wcnss_log(ERR, "MCU_DBR_CDAHB_TIMEOUT %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_DBR_DAHB_TIMEOUT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_DBR_DAHB_TIMEOUT %08x\n", reg); + wcnss_log(ERR, "MCU_DBR_DAHB_TIMEOUT %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_ERR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_FDBR_CDAHB_ERR %08x\n", reg); + wcnss_log(ERR, "MCU_FDBR_CDAHB_ERR %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_ERR_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_FDBR_FDAHB_ERR %08x\n", reg); + wcnss_log(ERR, "MCU_FDBR_FDAHB_ERR %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_FDBR_CDAHB_TIMEOUT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg); + wcnss_log(ERR, "MCU_FDBR_CDAHB_TIMEOUT %08x\n", reg); reg_addr = penv->pronto_mcu_base + MCU_FDBR_FDAHB_TIMEOUT_OFFSET; reg = readl_relaxed(reg_addr); - pr_err("MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg); + wcnss_log(ERR, "MCU_FDBR_FDAHB_TIMEOUT %08x\n", reg); reg = readl_relaxed(penv->wlan_brdg_err_source); - pr_err("WLAN_BRDG_ERR_SOURCE %08x\n", reg); + wcnss_log(ERR, "WLAN_BRDG_ERR_SOURCE %08x\n", reg); reg = readl_relaxed(penv->wlan_tx_status); - pr_err("WLAN_TXP_STATUS %08x\n", reg); + wcnss_log(ERR, "WLAN_TXP_STATUS %08x\n", reg); reg = readl_relaxed(penv->alarms_txctl); - pr_err("ALARMS_TXCTL %08x\n", reg); + wcnss_log(ERR, "ALARMS_TXCTL %08x\n", reg); reg = readl_relaxed(penv->alarms_tactl); - pr_err("ALARMS_TACTL %08x\n", reg); + wcnss_log(ERR, "ALARMS_TACTL %08x\n", reg); } EXPORT_SYMBOL(wcnss_pronto_log_debug_regs); @@ -930,13 +978,13 @@ static int wcnss_gpio_set_state(bool is_enable) if (!IS_ERR_OR_NULL(pin_state)) { ret = pinctrl_select_state(penv->pinctrl, pin_state); if (ret < 0) { - pr_err("%s: can not set gpio pins err: %d\n", + wcnss_log(ERR, "%s: can not set gpio pins err: %d\n", __func__, ret); goto pinctrl_set_err; } } else { - pr_err("%s: invalid gpio pinstate err: %lu\n", + wcnss_log(ERR, "%s: invalid gpio pinstate err: %lu\n", __func__, PTR_ERR(pin_state)); goto pinctrl_set_err; } @@ -945,7 +993,7 @@ static int wcnss_gpio_set_state(bool is_enable) ret = gpio_request_one(penv->gpios[i], GPIOF_DIR_IN, NULL); if (ret) { - pr_err("%s: request failed for gpio:%d\n", + wcnss_log(ERR, "%s: request failed for gpio:%d\n", __func__, penv->gpios[i]); i--; goto gpio_req_err; @@ -956,7 +1004,7 @@ static int wcnss_gpio_set_state(bool is_enable) ret = gpio_request_one(penv->gpios[i], GPIOF_OUT_INIT_LOW, NULL); if (ret) { - pr_err("%s: request failed for gpio:%d\n", + wcnss_log(ERR, "%s: request failed for gpio:%d\n", __func__, penv->gpios[i]); i--; goto gpio_req_err; @@ -1072,12 +1120,13 @@ static void wcnss_log_iris_regs(void) 0x04, 0x05, 0x11, 0x1e, 0x40, 0x48, 0x49, 0x4b, 0x00, 0x01, 0x4d}; - pr_info("%s: IRIS Registers [address] : value\n", __func__); + wcnss_log(INFO, "%s: IRIS Registers [address] : value\n", __func__); for (i = 0; i < ARRAY_SIZE(regs_array); i++) { reg_val = wcnss_rf_read_reg(regs_array[i]); - pr_info("[0x%08x] : 0x%08x\n", regs_array[i], reg_val); + wcnss_log(INFO, "IRIS Reg Addr: [0x%08x] : Reg val: 0x%08x\n", + regs_array[i], reg_val); } } @@ -1111,24 +1160,25 @@ void wcnss_log_debug_regs_on_bite(void) if (!IS_ERR(measure) && !IS_ERR(wcnss_debug_mux)) { if (clk_set_parent(measure, wcnss_debug_mux)) { - pr_err("Setting measure clk parent failed\n"); + wcnss_log(ERR, "Setting measure clk parent failed\n"); return; } if (clk_prepare_enable(measure)) { - pr_err("measure clk enable failed\n"); + wcnss_log(ERR, "measure clk enable failed\n"); return; } clk_rate = clk_get_rate(measure); - pr_debug("wcnss: clock frequency is: %luHz\n", clk_rate); + wcnss_log(DBG, "clock frequency is: %luHz\n", clk_rate); if (clk_rate) { wcnss_pronto_log_debug_regs(); if (wcnss_get_mux_control()) wcnss_log_iris_regs(); } else { - pr_err("clock frequency is zero, cannot access PMU or other registers\n"); + wcnss_log(ERR, "clock frequency is zero, cannot"); + wcnss_log(ERR, " access PMU or other registers\n"); wcnss_log_iris_regs(); } @@ -1153,8 +1203,8 @@ void wcnss_reset_fiq(bool clk_chk_en) wmb(); __raw_writel(1 << 16, penv->fiq_reg); } else { - pr_info("%s: Block FIQ during power up sequence\n", - __func__); + wcnss_log(INFO, + "%s: Block FIQ during power up sequence\n", __func__); } } else { wcnss_riva_log_debug_regs(); @@ -1202,20 +1252,20 @@ static void wcnss_remove_sysfs(struct device *dev) static void wcnss_pm_qos_add_request(void) { - pr_info("%s: add request\n", __func__); + wcnss_log(INFO, "%s: add request\n", __func__); pm_qos_add_request(&penv->wcnss_pm_qos_request, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); } static void wcnss_pm_qos_remove_request(void) { - pr_info("%s: remove request\n", __func__); + wcnss_log(INFO, "%s: remove request\n", __func__); pm_qos_remove_request(&penv->wcnss_pm_qos_request); } void wcnss_pm_qos_update_request(int val) { - pr_info("%s: update request %d\n", __func__, val); + wcnss_log(INFO, "%s: update request %d\n", __func__, val); pm_qos_update_request(&penv->wcnss_pm_qos_request, val); } @@ -1248,21 +1298,21 @@ static void wcnss_smd_notify_event(void *data, unsigned int event) int len = 0; if (penv != data) { - pr_err("wcnss: invalid env pointer in smd callback\n"); + wcnss_log(ERR, "invalid env pointer in smd callback\n"); return; } switch (event) { case SMD_EVENT_DATA: len = smd_read_avail(penv->smd_ch); if (len < 0) { - pr_err("wcnss: failed to read from smd %d\n", len); + wcnss_log(ERR, "failed to read from smd %d\n", len); return; } schedule_work(&penv->wcnssctrl_rx_work); break; case SMD_EVENT_OPEN: - pr_debug("wcnss: opening WCNSS SMD channel :%s", + wcnss_log(DBG, "opening WCNSS SMD channel :%s", WCNSS_CTRL_CHANNEL); schedule_work(&penv->wcnssctrl_version_work); schedule_work(&penv->wcnss_pm_config_work); @@ -1273,7 +1323,7 @@ static void wcnss_smd_notify_event(void *data, unsigned int event) break; case SMD_EVENT_CLOSE: - pr_debug("wcnss: closing WCNSS SMD channel :%s", + wcnss_log(DBG, "closing WCNSS SMD channel :%s", WCNSS_CTRL_CHANNEL); penv->nv_downloaded = 0; penv->is_cbc_done = 0; @@ -1290,7 +1340,7 @@ wcnss_pinctrl_set_state(bool active) struct pinctrl_state *pin_state; int ret; - pr_debug("%s: Set GPIO state : %d\n", __func__, active); + wcnss_log(DBG, "%s: Set GPIO state : %d\n", __func__, active); pin_state = active ? penv->wcnss_5wire_active : penv->wcnss_5wire_suspend; @@ -1298,13 +1348,13 @@ wcnss_pinctrl_set_state(bool active) if (!IS_ERR_OR_NULL(pin_state)) { ret = pinctrl_select_state(penv->pinctrl, pin_state); if (ret < 0) { - pr_err("%s: can not set %s pins\n", __func__, + wcnss_log(ERR, "%s: can not set %s pins\n", __func__, active ? WCNSS_PINCTRL_STATE_DEFAULT : WCNSS_PINCTRL_STATE_SLEEP); return ret; } } else { - pr_err("%s: invalid '%s' pinstate\n", __func__, + wcnss_log(ERR, "%s: invalid '%s' pinstate\n", __func__, active ? WCNSS_PINCTRL_STATE_DEFAULT : WCNSS_PINCTRL_STATE_SLEEP); return PTR_ERR(pin_state); @@ -1323,7 +1373,7 @@ wcnss_pinctrl_init(struct platform_device *pdev) penv->pinctrl = devm_pinctrl_get(&pdev->dev); if (IS_ERR_OR_NULL(penv->pinctrl)) { - pr_err("%s: failed to get pinctrl\n", __func__); + wcnss_log(ERR, "%s: failed to get pinctrl\n", __func__); return PTR_ERR(penv->pinctrl); } @@ -1332,7 +1382,7 @@ wcnss_pinctrl_init(struct platform_device *pdev) WCNSS_PINCTRL_STATE_DEFAULT); if (IS_ERR_OR_NULL(penv->wcnss_5wire_active)) { - pr_err("%s: can not get default pinstate\n", __func__); + wcnss_log(ERR, "%s: can not get default pinstate\n", __func__); return PTR_ERR(penv->wcnss_5wire_active); } @@ -1341,19 +1391,20 @@ wcnss_pinctrl_init(struct platform_device *pdev) WCNSS_PINCTRL_STATE_SLEEP); if (IS_ERR_OR_NULL(penv->wcnss_5wire_suspend)) { - pr_warn("%s: can not get sleep pinstate\n", __func__); + wcnss_log(WARN, "%s: can not get sleep pinstate\n", __func__); return PTR_ERR(penv->wcnss_5wire_suspend); } penv->wcnss_gpio_active = pinctrl_lookup_state(penv->pinctrl, WCNSS_PINCTRL_GPIO_STATE_DEFAULT); if (IS_ERR_OR_NULL(penv->wcnss_gpio_active)) - pr_warn("%s: can not get gpio default pinstate\n", __func__); + wcnss_log(WARN, "%s: can not get gpio default pinstate\n", + __func__); for (i = 0; i < WCNSS_WLAN_MAX_GPIO; i++) { penv->gpios[i] = of_get_gpio(node, i); if (penv->gpios[i] < 0) - pr_warn("%s: Fail to get 5wire gpio: %d\n", + wcnss_log(WARN, "%s: Fail to get 5wire gpio: %d\n", __func__, i); } @@ -1370,13 +1421,13 @@ wcnss_pronto_gpios_config(struct platform_device *pdev, bool enable) /* Use Pinctrl to configure 5 wire GPIOs */ rc = wcnss_pinctrl_init(pdev); if (rc) { - pr_err("%s: failed to get pin resources\n", __func__); + wcnss_log(ERR, "%s: failed to get pin resources\n", __func__); penv->pinctrl = NULL; goto gpio_probe; } else { rc = wcnss_pinctrl_set_state(true); if (rc) - pr_err("%s: failed to set pin state\n", + wcnss_log(ERR, "%s: failed to set pin state\n", __func__); penv->use_pinctrl = true; return rc; @@ -1389,7 +1440,7 @@ wcnss_pronto_gpios_config(struct platform_device *pdev, bool enable) if (enable) { rc = gpio_request(gpio, "wcnss_wlan"); if (rc) { - pr_err("WCNSS gpio_request %d err %d\n", + wcnss_log(ERR, "WCNSS gpio_request %d err %d\n", gpio, rc); goto fail; } @@ -1418,7 +1469,8 @@ wcnss_gpios_config(struct resource *gpios_5wire, bool enable) if (enable) { rc = gpio_request(i, gpios_5wire->name); if (rc) { - pr_err("WCNSS gpio_request %d err %d\n", i, rc); + wcnss_log(ERR, + "gpio_request %d err %d\n", i, rc); goto fail; } } else { @@ -1442,7 +1494,7 @@ wcnss_wlan_ctrl_probe(struct platform_device *pdev) penv->smd_channel_ready = 1; - pr_info("%s: SMD ctrl channel up\n", __func__); + wcnss_log(INFO, "%s: SMD ctrl channel up\n", __func__); return 0; } @@ -1452,7 +1504,7 @@ wcnss_wlan_ctrl_remove(struct platform_device *pdev) if (penv) penv->smd_channel_ready = 0; - pr_info("%s: SMD ctrl channel down\n", __func__); + wcnss_log(INFO, "%s: SMD ctrl channel down\n", __func__); return 0; } @@ -1487,7 +1539,7 @@ wcnss_ctrl_probe(struct platform_device *pdev) &penv->smd_ch, penv, wcnss_smd_notify_event); if (ret < 0) { - pr_err("wcnss: cannot open the smd command channel %s: %d\n", + wcnss_log(ERR, "cannot open the smd command channel %s: %d\n", WCNSS_CTRL_CHANNEL, ret); return -ENODEV; } @@ -1611,14 +1663,15 @@ void wcnss_wlan_unregister_pm_ops(struct device *dev, { if (penv && dev && (dev == &penv->pdev->dev) && pm_ops) { if (!penv->pm_ops) { - pr_err("%s: pm_ops is already unregistered.\n", + wcnss_log(ERR, "%s: pm_ops is already unregistered.\n", __func__); return; } if (pm_ops->suspend != penv->pm_ops->suspend || pm_ops->resume != penv->pm_ops->resume) - pr_err("PM APIs dont match with registered APIs\n"); + wcnss_log(ERR, + "PM APIs dont match with registered APIs\n"); penv->pm_ops = NULL; } } @@ -1637,7 +1690,7 @@ void wcnss_unregister_thermal_mitigation( { if (penv && tm_notify) { if (tm_notify != penv->tm_notify) - pr_err("tm_notify doesn't match registered\n"); + wcnss_log(ERR, "tm_notify doesn't match registered\n"); penv->tm_notify = NULL; } } @@ -1647,7 +1700,7 @@ unsigned int wcnss_get_serial_number(void) { if (penv) { penv->serial_number = socinfo_get_serial_number(); - pr_info("%s: Device serial number: %u\n", + wcnss_log(INFO, "%s: Device serial number: %u\n", __func__, penv->serial_number); return penv->serial_number; } @@ -1662,7 +1715,7 @@ int wcnss_get_wlan_mac_address(char mac_addr[WLAN_MAC_ADDR_SIZE]) return -ENODEV; memcpy(mac_addr, penv->wlan_nv_mac_addr, WLAN_MAC_ADDR_SIZE); - pr_debug("%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__, + wcnss_log(DBG, "%s: Get MAC Addr:" MAC_ADDRESS_STR "\n", __func__, penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1], penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3], penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]); @@ -1682,7 +1735,7 @@ static int enable_wcnss_suspend_notify_set(const char *val, return ret; if (enable_wcnss_suspend_notify) - pr_debug("Suspend notification activated for wcnss\n"); + wcnss_log(DBG, "Suspend notification activated for wcnss\n"); return 0; } @@ -1875,12 +1928,12 @@ static int wcnss_smd_tx(void *data, int len) ret = smd_write_avail(penv->smd_ch); if (ret < len) { - pr_err("wcnss: no space available for smd frame\n"); + wcnss_log(ERR, "no space available for smd frame\n"); return -ENOSPC; } ret = smd_write(penv->smd_ch, data, len); if (ret < len) { - pr_err("wcnss: failed to write Command %d", len); + wcnss_log(ERR, "failed to write Command %d", len); ret = -ENODEV; } return ret; @@ -1892,19 +1945,19 @@ static int wcnss_get_battery_volt(int *result_uv) struct qpnp_vadc_result adc_result; if (!penv->vadc_dev) { - pr_err("wcnss: not setting up vadc\n"); + wcnss_log(ERR, "not setting up vadc\n"); return rc; } rc = qpnp_vadc_read(penv->vadc_dev, VBAT_SNS, &adc_result); if (rc) { - pr_err("error reading adc channel = %d, rc = %d\n", + wcnss_log(ERR, "error reading adc channel = %d, rc = %d\n", VBAT_SNS, rc); return rc; } - pr_info("Battery mvolts phy=%lld meas=0x%llx\n", adc_result.physical, - adc_result.measurement); + wcnss_log(INFO, "Battery mvolts phy=%lld meas=0x%llx\n", + adc_result.physical, adc_result.measurement); *result_uv = (int)adc_result.physical; return 0; @@ -1918,7 +1971,7 @@ static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) cancel_delayed_work_sync(&penv->vbatt_work); if (state == ADC_TM_LOW_STATE) { - pr_debug("wcnss: low voltage notification triggered\n"); + wcnss_log(DBG, "low voltage notification triggered\n"); penv->vbat_monitor_params.state_request = ADC_TM_HIGH_THR_ENABLE; penv->vbat_monitor_params.high_thr = WCNSS_VBATT_THRESHOLD + @@ -1930,14 +1983,14 @@ static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD - WCNSS_VBATT_GUARD; penv->vbat_monitor_params.high_thr = 0; - pr_debug("wcnss: high voltage notification triggered\n"); + wcnss_log(DBG, "high voltage notification triggered\n"); } else { - pr_debug("wcnss: unknown voltage notification state: %d\n", + wcnss_log(DBG, "unknown voltage notification state: %d\n", state); mutex_unlock(&penv->vbat_monitor_mutex); return; } - pr_debug("wcnss: set low thr to %d and high to %d\n", + wcnss_log(DBG, "set low thr to %d and high to %d\n", penv->vbat_monitor_params.low_thr, penv->vbat_monitor_params.high_thr); @@ -1945,7 +1998,7 @@ static void wcnss_notify_vbat(enum qpnp_tm_state state, void *ctx) &penv->vbat_monitor_params); if (rc) - pr_err("%s: tm setup failed: %d\n", __func__, rc); + wcnss_log(ERR, "%s: tm setup failed: %d\n", __func__, rc); else schedule_delayed_work(&penv->vbatt_work, msecs_to_jiffies(2000)); @@ -1958,7 +2011,7 @@ static int wcnss_setup_vbat_monitoring(void) int rc = -1; if (!penv->adc_tm_dev) { - pr_err("wcnss: not setting up vbatt\n"); + wcnss_log(ERR, "not setting up vbatt\n"); return rc; } penv->vbat_monitor_params.low_thr = WCNSS_VBATT_THRESHOLD; @@ -1973,14 +2026,14 @@ static int wcnss_setup_vbat_monitoring(void) penv->vbat_monitor_params.btm_ctx = (void *)penv; penv->vbat_monitor_params.timer_interval = ADC_MEAS1_INTERVAL_1S; penv->vbat_monitor_params.threshold_notification = &wcnss_notify_vbat; - pr_debug("wcnss: set low thr to %d and high to %d\n", + wcnss_log(DBG, "set low thr to %d and high to %d\n", penv->vbat_monitor_params.low_thr, penv->vbat_monitor_params.high_thr); rc = qpnp_adc_tm_channel_measure(penv->adc_tm_dev, &penv->vbat_monitor_params); if (rc) - pr_err("%s: tm setup failed: %d\n", __func__, rc); + wcnss_log(ERR, "%s: tm setup failed: %d\n", __func__, rc); return rc; } @@ -1997,12 +2050,12 @@ static void wcnss_send_vbatt_indication(struct work_struct *work) mutex_lock(&penv->vbat_monitor_mutex); vbatt_msg.vbatt.curr_volt = penv->wlan_config.vbatt; mutex_unlock(&penv->vbat_monitor_mutex); - pr_debug("wcnss: send curr_volt: %d to FW\n", + wcnss_log(DBG, "send curr_volt: %d to FW\n", vbatt_msg.vbatt.curr_volt); ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); if (ret < 0) - pr_err("wcnss: smd tx failed\n"); + wcnss_log(ERR, "smd tx failed\n"); } static void wcnss_update_vbatt(struct work_struct *work) @@ -2020,13 +2073,13 @@ static void wcnss_update_vbatt(struct work_struct *work) penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)) { vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_HIGH; penv->fw_vbatt_state = WCNSS_VBATT_HIGH; - pr_debug("wcnss: send HIGH BATT to FW\n"); + wcnss_log(DBG, "send HIGH BATT to FW\n"); } else if (!penv->vbat_monitor_params.low_thr && (penv->fw_vbatt_state == WCNSS_VBATT_HIGH || penv->fw_vbatt_state == WCNSS_CONFIG_UNSPECIFIED)){ vbatt_msg.vbatt.curr_volt = WCNSS_VBATT_LOW; penv->fw_vbatt_state = WCNSS_VBATT_LOW; - pr_debug("wcnss: send LOW BATT to FW\n"); + wcnss_log(DBG, "send LOW BATT to FW\n"); } else { mutex_unlock(&penv->vbat_monitor_mutex); return; @@ -2034,7 +2087,7 @@ static void wcnss_update_vbatt(struct work_struct *work) mutex_unlock(&penv->vbat_monitor_mutex); ret = wcnss_smd_tx(&vbatt_msg, vbatt_msg.hdr.msg_len); if (ret < 0) - pr_err("wcnss: smd tx failed\n"); + wcnss_log(ERR, "smd tx failed\n"); } static unsigned char wcnss_fw_status(void) @@ -2046,13 +2099,13 @@ static unsigned char wcnss_fw_status(void) len = smd_read_avail(penv->smd_ch); if (len < 1) { - pr_err("%s: invalid firmware status", __func__); + wcnss_log(ERR, "%s: invalid firmware status", __func__); return fw_status; } rc = smd_read(penv->smd_ch, &fw_status, 1); if (rc < 0) { - pr_err("%s: incomplete data read from smd\n", __func__); + wcnss_log(ERR, "%s: incomplete data read from smd\n", __func__); return fw_status; } return fw_status; @@ -2075,7 +2128,7 @@ static void wcnss_send_cal_rsp(unsigned char fw_status) rc = wcnss_smd_tx(msg, rsphdr->msg_len); if (rc < 0) - pr_err("wcnss: smd tx failed\n"); + wcnss_log(ERR, "smd tx failed\n"); kfree(msg); } @@ -2088,7 +2141,7 @@ void extract_cal_data(int len) unsigned char fw_status = WCNSS_RESP_FAIL; if (len < sizeof(struct cal_data_params)) { - pr_err("wcnss: incomplete cal header length\n"); + wcnss_log(ERR, "incomplete cal header length\n"); return; } @@ -2096,18 +2149,18 @@ void extract_cal_data(int len) rc = smd_read(penv->smd_ch, (unsigned char *)&calhdr, sizeof(struct cal_data_params)); if (rc < sizeof(struct cal_data_params)) { - pr_err("wcnss: incomplete cal header read from smd\n"); + wcnss_log(ERR, "incomplete cal header read from smd\n"); mutex_unlock(&penv->dev_lock); return; } if (penv->fw_cal_exp_frag != calhdr.frag_number) { - pr_err("wcnss: Invalid frgament"); + wcnss_log(ERR, "Invalid frgament"); goto unlock_exit; } if (calhdr.frag_size > WCNSS_MAX_FRAME_SIZE) { - pr_err("wcnss: Invalid fragment size"); + wcnss_log(ERR, "Invalid fragment size"); goto unlock_exit; } @@ -2125,7 +2178,7 @@ void extract_cal_data(int len) if (calhdr.frag_number == 0) { if (calhdr.total_size > MAX_CALIBRATED_DATA_SIZE) { - pr_err("wcnss: Invalid cal data size %d", + wcnss_log(ERR, "Invalid cal data size %d", calhdr.total_size); goto unlock_exit; } @@ -2141,7 +2194,7 @@ void extract_cal_data(int len) if (penv->fw_cal_rcvd + calhdr.frag_size > MAX_CALIBRATED_DATA_SIZE) { - pr_err("calibrated data size is more than expected %d", + wcnss_log(ERR, "calibrated data size is more than expected %d", penv->fw_cal_rcvd + calhdr.frag_size); penv->fw_cal_exp_frag = 0; penv->fw_cal_rcvd = 0; @@ -2160,7 +2213,7 @@ void extract_cal_data(int len) if (calhdr.msg_flags & LAST_FRAGMENT) { penv->fw_cal_exp_frag = 0; penv->fw_cal_available = true; - pr_info("wcnss: cal data collection completed\n"); + wcnss_log(INFO, "cal data collection completed\n"); } mutex_unlock(&penv->dev_lock); wake_up(&penv->read_wait); @@ -2190,18 +2243,18 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) len = smd_read_avail(penv->smd_ch); if (len > WCNSS_MAX_FRAME_SIZE) { - pr_err("wcnss: frame larger than the allowed size\n"); + wcnss_log(ERR, "frame larger than the allowed size\n"); smd_read(penv->smd_ch, NULL, len); return; } if (len < sizeof(struct smd_msg_hdr)) { - pr_debug("wcnss: incomplete header available len = %d\n", len); + wcnss_log(DBG, "incomplete header available len = %d\n", len); return; } rc = smd_read(penv->smd_ch, buf, sizeof(struct smd_msg_hdr)); if (rc < sizeof(struct smd_msg_hdr)) { - pr_err("wcnss: incomplete header read from smd\n"); + wcnss_log(ERR, "incomplete header read from smd\n"); return; } len -= sizeof(struct smd_msg_hdr); @@ -2212,14 +2265,14 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) case WCNSS_VERSION_RSP: if (len != sizeof(struct wcnss_version) - sizeof(struct smd_msg_hdr)) { - pr_err("wcnss: invalid version data from wcnss %d\n", + wcnss_log(ERR, "invalid version data from wcnss %d\n", len); return; } rc = smd_read(penv->smd_ch, buf + sizeof(struct smd_msg_hdr), len); if (rc < len) { - pr_err("wcnss: incomplete data read from smd\n"); + wcnss_log(ERR, "incomplete data read from smd\n"); return; } pversion = (struct wcnss_version *)buf; @@ -2228,14 +2281,15 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) snprintf(penv->wcnss_version, WCNSS_VERSION_LEN, "%02x%02x%02x%02x", pversion->major, pversion->minor, pversion->version, pversion->revision); - pr_info("wcnss: version %s\n", penv->wcnss_version); + wcnss_log(INFO, "version %s\n", penv->wcnss_version); /* schedule work to download nvbin to ccpu */ hw_type = wcnss_hardware_type(); switch (hw_type) { case WCNSS_RIVA_HW: /* supported only if riva major >= 1 and minor >= 4 */ if ((pversion->major >= 1) && (pversion->minor >= 4)) { - pr_info("wcnss: schedule dnld work for riva\n"); + wcnss_log(INFO, + "schedule download work for riva\n"); schedule_work(&penv->wcnssctrl_nvbin_dnld_work); } break; @@ -2245,41 +2299,43 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) smd_msg.msg_len = sizeof(smd_msg); rc = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); if (rc < 0) - pr_err("wcnss: smd tx failed: %s\n", __func__); + wcnss_log(ERR, "smd tx failed: %s\n", __func__); /* supported only if pronto major >= 1 and minor >= 4 */ if ((pversion->major >= 1) && (pversion->minor >= 4)) { - pr_info("wcnss: schedule dnld work for pronto\n"); + wcnss_log(INFO, + "schedule dnld work for pronto\n"); schedule_work(&penv->wcnssctrl_nvbin_dnld_work); } break; default: - pr_info("wcnss: unknown hw type (%d), will not schedule dnld work\n", - hw_type); + wcnss_log(INFO, + "unknown hw type (%d) will not schedule dnld work\n", + hw_type); break; } break; case WCNSS_BUILD_VER_RSP: if (len > WCNSS_MAX_BUILD_VER_LEN) { - pr_err("wcnss: invalid build version data from wcnss %d\n", - len); + wcnss_log(ERR, + "invalid build version data from wcnss %d\n", len); return; } rc = smd_read(penv->smd_ch, build, len); if (rc < len) { - pr_err("wcnss: incomplete data read from smd\n"); + wcnss_log(ERR, "incomplete data read from smd\n"); return; } build[len] = 0; - pr_info("wcnss: build version %s\n", build); + wcnss_log(INFO, "build version %s\n", build); break; case WCNSS_NVBIN_DNLD_RSP: penv->nv_downloaded = true; fw_status = wcnss_fw_status(); - pr_debug("wcnss: received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n", + wcnss_log(DBG, "received WCNSS_NVBIN_DNLD_RSP from ccpu %u\n", fw_status); if (fw_status != WAIT_FOR_CBC_IND) penv->is_cbc_done = 1; @@ -2289,12 +2345,12 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) case WCNSS_CALDATA_DNLD_RSP: penv->nv_downloaded = true; fw_status = wcnss_fw_status(); - pr_debug("wcnss: received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n", + wcnss_log(DBG, "received WCNSS_CALDATA_DNLD_RSP from ccpu %u\n", fw_status); break; case WCNSS_CBC_COMPLETE_IND: penv->is_cbc_done = 1; - pr_debug("wcnss: received WCNSS_CBC_COMPLETE_IND from FW\n"); + wcnss_log(DBG, "received WCNSS_CBC_COMPLETE_IND from FW\n"); break; case WCNSS_CALDATA_UPLD_REQ: @@ -2302,7 +2358,7 @@ static void wcnssctrl_rx_handler(struct work_struct *worker) break; default: - pr_err("wcnss: invalid message type %d\n", phdr->msg_type); + wcnss_log(ERR, "invalid message type %d\n", phdr->msg_type); } } @@ -2315,7 +2371,7 @@ static void wcnss_send_version_req(struct work_struct *worker) smd_msg.msg_len = sizeof(smd_msg); ret = wcnss_smd_tx(&smd_msg, smd_msg.msg_len); if (ret < 0) - pr_err("wcnss: smd tx failed\n"); + wcnss_log(ERR, "smd tx failed\n"); } static void wcnss_send_pm_config(struct work_struct *worker) @@ -2340,12 +2396,12 @@ static void wcnss_send_pm_config(struct work_struct *worker) rc = of_property_read_u32_array(penv->pdev->dev.of_node, "qcom,wcnss-pm", payload, prop_len); if (rc < 0) { - pr_err("wcnss: property read failed\n"); + wcnss_log(ERR, "property read failed\n"); kfree(msg); return; } - pr_debug("%s:size=%d: <%d, %d, %d, %d, %d %d>\n", __func__, + wcnss_log(DBG, "%s:size=%d: <%d, %d, %d, %d, %d %d>\n", __func__, prop_len, *payload, *(payload + 1), *(payload + 2), *(payload + 3), *(payload + 4), *(payload + 5)); @@ -2355,7 +2411,7 @@ static void wcnss_send_pm_config(struct work_struct *worker) rc = wcnss_smd_tx(msg, hdr->msg_len); if (rc < 0) - pr_err("wcnss: smd tx failed\n"); + wcnss_log(ERR, "smd tx failed\n"); kfree(msg); } @@ -2386,7 +2442,8 @@ static void wcnss_nvbin_dnld(void) ret = request_firmware(&nv, NVBIN_FILE, dev); if (ret || !nv || !nv->data || !nv->size) { - pr_err("wcnss: %s: request_firmware failed for %s (ret = %d)\n", + wcnss_log(ERR, + "%s: request_firmware failed for %s (ret = %d)\n", __func__, NVBIN_FILE, ret); goto out; } @@ -2399,7 +2456,7 @@ static void wcnss_nvbin_dnld(void) total_fragments = TOTALFRAGMENTS(nv_blob_size); - pr_info("wcnss: NV bin size: %d, total_fragments: %d\n", + wcnss_log(INFO, "NV bin size: %d, total_fragments: %d\n", nv_blob_size, total_fragments); /* get buffer for nv bin dnld req message */ @@ -2447,11 +2504,12 @@ static void wcnss_nvbin_dnld(void) retry_count = 0; while ((ret == -ENOSPC) && (retry_count <= 3)) { - pr_debug("wcnss: %s: smd tx failed, ENOSPC\n", + wcnss_log(DBG, "%s: smd tx failed, ENOSPC\n", __func__); - pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n", - count, dnld_req_msg->hdr.msg_len, - total_fragments, retry_count); + wcnss_log(DBG, "fragment %d, len: %d,", count, + dnld_req_msg->hdr.msg_len); + wcnss_log(DBG, "TotFragments: %d, retry_count: %d\n", + total_fragments, retry_count); /* wait and try again */ msleep(20); @@ -2461,10 +2519,11 @@ static void wcnss_nvbin_dnld(void) } if (ret < 0) { - pr_err("wcnss: %s: smd tx failed\n", __func__); - pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n", - count, dnld_req_msg->hdr.msg_len, - total_fragments, retry_count); + wcnss_log(ERR, "%s: smd tx failed\n", __func__); + wcnss_log(ERR, "fragment %d, len: %d,", count, + dnld_req_msg->hdr.msg_len); + wcnss_log(ERR, "TotFragments: %d, retry_count: %d\n", + total_fragments, retry_count); goto err_dnld; } } @@ -2538,11 +2597,12 @@ static void wcnss_caldata_dnld(const void *cal_data, retry_count = 0; while ((ret == -ENOSPC) && (retry_count <= 3)) { - pr_debug("wcnss: %s: smd tx failed, ENOSPC\n", + wcnss_log(DBG, "%s: smd tx failed, ENOSPC\n", __func__); - pr_debug("fragment: %d, len: %d, TotFragments: %d, retry_count: %d\n", - count, cal_msg->hdr.msg_len, - total_fragments, retry_count); + wcnss_log(DBG, "fragment: %d, len: %d", + count, cal_msg->hdr.msg_len); + wcnss_log(DBG, " TotFragments: %d, retry_count: %d\n", + total_fragments, retry_count); /* wait and try again */ msleep(20); @@ -2552,10 +2612,10 @@ static void wcnss_caldata_dnld(const void *cal_data, } if (ret < 0) { - pr_err("wcnss: %s: smd tx failed\n", __func__); - pr_err("fragment %d, len: %d, TotFragments: %d, retry_count: %d\n", - count, cal_msg->hdr.msg_len, - total_fragments, retry_count); + wcnss_log(ERR, "%s: smd tx failed: fragment %d, len:%d", + count, cal_msg->hdr.msg_len, __func__); + wcnss_log(ERR, " TotFragments: %d, retry_count: %d\n", + total_fragments, retry_count); goto err_dnld; } } @@ -2578,17 +2638,17 @@ static void wcnss_nvbin_dnld_main(struct work_struct *worker) msleep(500); } if (penv->fw_cal_available) { - pr_info_ratelimited("wcnss: cal download, using fw cal"); + wcnss_log(INFO, "cal download, using fw cal"); wcnss_caldata_dnld(penv->fw_cal_data, penv->fw_cal_rcvd, true); } else if (penv->user_cal_available) { - pr_info_ratelimited("wcnss: cal download, using user cal"); + wcnss_log(INFO, "cal download, using user cal"); wcnss_caldata_dnld(penv->user_cal_data, penv->user_cal_rcvd, true); } nv_download: - pr_info_ratelimited("wcnss: NV download"); + wcnss_log(INFO, "NV download"); wcnss_nvbin_dnld(); } @@ -2631,20 +2691,20 @@ void process_usr_ctrl_cmd(u8 *buf, size_t len) switch (cmd) { case WCNSS_USR_HAS_CAL_DATA: if (buf[2] > 1) - pr_err("%s: Invalid data for cal %d\n", __func__, - buf[2]); + wcnss_log(ERR, "%s: Invalid data for cal %d\n", + __func__, buf[2]); has_calibrated_data = buf[2]; break; case WCNSS_USR_WLAN_MAC_ADDR: memcpy(&penv->wlan_nv_mac_addr, &buf[2], sizeof(penv->wlan_nv_mac_addr)); - pr_debug("%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__, + wcnss_log(DBG, "%s: MAC Addr:" MAC_ADDRESS_STR "\n", __func__, penv->wlan_nv_mac_addr[0], penv->wlan_nv_mac_addr[1], penv->wlan_nv_mac_addr[2], penv->wlan_nv_mac_addr[3], penv->wlan_nv_mac_addr[4], penv->wlan_nv_mac_addr[5]); break; default: - pr_err("%s: Invalid command %d\n", __func__, cmd); + wcnss_log(ERR, "%s: Invalid command %d\n", __func__, cmd); break; } } @@ -2703,7 +2763,7 @@ wcnss_trigger_config(struct platform_device *pdev) rc = wcnss_parse_voltage_regulator(&penv->wlan_config, &pdev->dev); if (rc) { - dev_err(&pdev->dev, "Failed to parse voltage regulators\n"); + wcnss_log(ERR, "Failed to parse voltage regulators\n"); goto fail; } @@ -2742,7 +2802,7 @@ wcnss_trigger_config(struct platform_device *pdev) /* allocate 5-wire GPIO resources */ if (!penv->gpios_5wire) { - dev_err(&pdev->dev, "insufficient IO resources\n"); + wcnss_log(ERR, "insufficient IO resources\n"); ret = -ENOENT; goto fail_gpio_res; } @@ -2752,7 +2812,7 @@ wcnss_trigger_config(struct platform_device *pdev) } if (ret) { - dev_err(&pdev->dev, "WCNSS gpios config failed.\n"); + wcnss_log(ERR, "gpios config failed.\n"); goto fail_gpio_res; } @@ -2765,7 +2825,7 @@ wcnss_trigger_config(struct platform_device *pdev) "wcnss_wlanrx_irq"); if (!(penv->mmio_res && penv->tx_irq_res && penv->rx_irq_res)) { - dev_err(&pdev->dev, "insufficient resources\n"); + wcnss_log(ERR, "insufficient resources\n"); ret = -ENOENT; goto fail_res; } @@ -2785,7 +2845,7 @@ wcnss_trigger_config(struct platform_device *pdev) "pronto_phy_base"); if (!res) { ret = -EIO; - pr_err("%s: resource pronto_phy_base failed\n", + wcnss_log(ERR, "%s: resource pronto_phy_base failed\n", __func__); goto fail_ioremap; } @@ -2797,7 +2857,7 @@ wcnss_trigger_config(struct platform_device *pdev) "riva_phy_base"); if (!res) { ret = -EIO; - pr_err("%s: resource riva_phy_base failed\n", + wcnss_log(ERR, "%s: resource riva_phy_base failed\n", __func__); goto fail_ioremap; } @@ -2807,7 +2867,7 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->msm_wcnss_base) { ret = -ENOMEM; - pr_err("%s: ioremap wcnss physical failed\n", __func__); + wcnss_log(ERR, "%s: ioremap wcnss physical failed\n", __func__); goto fail_ioremap; } @@ -2818,7 +2878,7 @@ wcnss_trigger_config(struct platform_device *pdev) "riva_ccu_base"); if (!res) { ret = -EIO; - pr_err("%s: resource riva_ccu_base failed\n", + wcnss_log(ERR, "%s: resource riva_ccu_base failed\n", __func__); goto fail_ioremap; } @@ -2827,7 +2887,7 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->riva_ccu_base) { ret = -ENOMEM; - pr_err("%s: ioremap riva ccu physical failed\n", + wcnss_log(ERR, "%s: ioremap riva ccu physical failed\n", __func__); goto fail_ioremap; } @@ -2837,7 +2897,7 @@ wcnss_trigger_config(struct platform_device *pdev) "pronto_a2xb_base"); if (!res) { ret = -EIO; - pr_err("%s: resource pronto_a2xb_base failed\n", + wcnss_log(ERR, "%s: resource pronto_a2xb_base failed\n", __func__); goto fail_ioremap; } @@ -2846,8 +2906,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->pronto_a2xb_base) { ret = -ENOMEM; - pr_err("%s: ioremap pronto a2xb physical failed\n", - __func__); + wcnss_log(ERR, + "%s: ioremap pronto a2xb physical failed\n", __func__); goto fail_ioremap; } @@ -2856,7 +2916,7 @@ wcnss_trigger_config(struct platform_device *pdev) "pronto_ccpu_base"); if (!res) { ret = -EIO; - pr_err("%s: resource pronto_ccpu_base failed\n", + wcnss_log(ERR, "%s: resource pronto_ccpu_base failed\n", __func__); goto fail_ioremap; } @@ -2865,8 +2925,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->pronto_ccpu_base) { ret = -ENOMEM; - pr_err("%s: ioremap pronto ccpu physical failed\n", - __func__); + wcnss_log(ERR, + "%s: ioremap pronto ccpu physical failed\n", __func__); goto fail_ioremap; } @@ -2874,14 +2934,15 @@ wcnss_trigger_config(struct platform_device *pdev) res = platform_get_resource_byname(penv->pdev, IORESOURCE_MEM, "wcnss_fiq"); if (!res) { - dev_err(&pdev->dev, "insufficient irq mem resources\n"); + wcnss_log(ERR, "insufficient irq mem resources\n"); ret = -ENOENT; goto fail_ioremap; } penv->fiq_reg = ioremap_nocache(res->start, resource_size(res)); if (!penv->fiq_reg) { - pr_err("wcnss: %s: ioremap_nocache() failed fiq_reg addr:%pr\n", - __func__, &res->start); + wcnss_log(ERR, "%s", __func__, + "ioremap_nocache() failed fiq_reg addr:%pr\n", + &res->start); ret = -ENOMEM; goto fail_ioremap; } @@ -2891,7 +2952,7 @@ wcnss_trigger_config(struct platform_device *pdev) "pronto_saw2_base"); if (!res) { ret = -EIO; - pr_err("%s: resource pronto_saw2_base failed\n", + wcnss_log(ERR, "%s: resource pronto_saw2_base failed\n", __func__); goto fail_ioremap2; } @@ -2899,8 +2960,8 @@ wcnss_trigger_config(struct platform_device *pdev) devm_ioremap_resource(&pdev->dev, res); if (!penv->pronto_saw2_base) { - pr_err("%s: ioremap wcnss physical(saw2) failed\n", - __func__); + wcnss_log(ERR, + "%s: ioremap wcnss physical(saw2) failed\n", __func__); ret = -ENOMEM; goto fail_ioremap2; } @@ -2908,8 +2969,8 @@ wcnss_trigger_config(struct platform_device *pdev) penv->pronto_pll_base = penv->msm_wcnss_base + PRONTO_PLL_MODE_OFFSET; if (!penv->pronto_pll_base) { - pr_err("%s: ioremap wcnss physical(pll) failed\n", - __func__); + wcnss_log(ERR, + "%s: ioremap wcnss physical(pll) failed\n", __func__); ret = -ENOMEM; goto fail_ioremap2; } @@ -2919,8 +2980,8 @@ wcnss_trigger_config(struct platform_device *pdev) "wlan_tx_phy_aborts"); if (!res) { ret = -EIO; - pr_err("%s: resource wlan_tx_phy_aborts failed\n", - __func__); + wcnss_log(ERR, + "%s: resource wlan_tx_phy_aborts failed\n", __func__); goto fail_ioremap2; } penv->wlan_tx_phy_aborts = @@ -2928,7 +2989,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->wlan_tx_phy_aborts) { ret = -ENOMEM; - pr_err("%s: ioremap wlan TX PHY failed\n", __func__); + wcnss_log(ERR, "%s: ioremap wlan TX PHY failed\n", + __func__); goto fail_ioremap2; } @@ -2937,8 +2999,8 @@ wcnss_trigger_config(struct platform_device *pdev) "wlan_brdg_err_source"); if (!res) { ret = -EIO; - pr_err("%s: resource wlan_brdg_err_source failed\n", - __func__); + wcnss_log(ERR, + "%s: get wlan_brdg_err_source res failed\n", __func__); goto fail_ioremap2; } penv->wlan_brdg_err_source = @@ -2946,7 +3008,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->wlan_brdg_err_source) { ret = -ENOMEM; - pr_err("%s: ioremap wlan BRDG ERR failed\n", __func__); + wcnss_log(ERR, "%s: ioremap wlan BRDG ERR failed\n", + __func__); goto fail_ioremap2; } @@ -2955,7 +3018,7 @@ wcnss_trigger_config(struct platform_device *pdev) "wlan_tx_status"); if (!res) { ret = -EIO; - pr_err("%s: resource wlan_tx_status failed\n", + wcnss_log(ERR, "%s: resource wlan_tx_status failed\n", __func__); goto fail_ioremap2; } @@ -2964,7 +3027,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->wlan_tx_status) { ret = -ENOMEM; - pr_err("%s: ioremap wlan TX STATUS failed\n", __func__); + wcnss_log(ERR, "%s: ioremap wlan TX STATUS failed\n", + __func__); goto fail_ioremap2; } @@ -2973,8 +3037,8 @@ wcnss_trigger_config(struct platform_device *pdev) "alarms_txctl"); if (!res) { ret = -EIO; - pr_err("%s: resource alarms_txctl failed\n", - __func__); + wcnss_log(ERR, + "%s: resource alarms_txctl failed\n", __func__); goto fail_ioremap2; } penv->alarms_txctl = @@ -2982,7 +3046,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->alarms_txctl) { ret = -ENOMEM; - pr_err("%s: ioremap alarms TXCTL failed\n", __func__); + wcnss_log(ERR, + "%s: ioremap alarms TXCTL failed\n", __func__); goto fail_ioremap2; } @@ -2991,8 +3056,8 @@ wcnss_trigger_config(struct platform_device *pdev) "alarms_tactl"); if (!res) { ret = -EIO; - pr_err("%s: resource alarms_tactl failed\n", - __func__); + wcnss_log(ERR, + "%s: resource alarms_tactl failed\n", __func__); goto fail_ioremap2; } penv->alarms_tactl = @@ -3000,7 +3065,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->alarms_tactl) { ret = -ENOMEM; - pr_err("%s: ioremap alarms TACTL failed\n", __func__); + wcnss_log(ERR, + "%s: ioremap alarms TACTL failed\n", __func__); goto fail_ioremap2; } @@ -3009,8 +3075,8 @@ wcnss_trigger_config(struct platform_device *pdev) "pronto_mcu_base"); if (!res) { ret = -EIO; - pr_err("%s: resource pronto_mcu_base failed\n", - __func__); + wcnss_log(ERR, + "%s: resource pronto_mcu_base failed\n", __func__); goto fail_ioremap2; } penv->pronto_mcu_base = @@ -3018,8 +3084,8 @@ wcnss_trigger_config(struct platform_device *pdev) if (!penv->pronto_mcu_base) { ret = -ENOMEM; - pr_err("%s: ioremap pronto mcu physical failed\n", - __func__); + wcnss_log(ERR, + "%s: ioremap pronto mcu physical failed\n", __func__); goto fail_ioremap2; } @@ -3027,8 +3093,8 @@ wcnss_trigger_config(struct platform_device *pdev) "qcom,is-dual-band-disabled")) { ret = wcnss_get_dual_band_capability_info(pdev); if (ret) { - pr_err("%s: failed to get dual band info\n", - __func__); + wcnss_log(ERR, + "%s: failed to get dual band info\n", __func__); goto fail_ioremap2; } } @@ -3036,7 +3102,7 @@ wcnss_trigger_config(struct platform_device *pdev) penv->adc_tm_dev = qpnp_get_adc_tm(&penv->pdev->dev, "wcnss"); if (IS_ERR(penv->adc_tm_dev)) { - pr_err("%s: adc get failed\n", __func__); + wcnss_log(ERR, "%s: adc get failed\n", __func__); penv->adc_tm_dev = NULL; } else { INIT_DELAYED_WORK(&penv->vbatt_work, wcnss_update_vbatt); @@ -3045,14 +3111,14 @@ wcnss_trigger_config(struct platform_device *pdev) penv->snoc_wcnss = devm_clk_get(&penv->pdev->dev, "snoc_wcnss"); if (IS_ERR(penv->snoc_wcnss)) { - pr_err("%s: couldn't get snoc_wcnss\n", __func__); + wcnss_log(ERR, "%s: couldn't get snoc_wcnss\n", __func__); penv->snoc_wcnss = NULL; } else { if (of_property_read_u32(pdev->dev.of_node, "qcom,snoc-wcnss-clock-freq", &penv->snoc_wcnss_clock_freq)) { - pr_debug("%s: wcnss snoc clock frequency is not defined\n", - __func__); + wcnss_log(DBG, + "%s: snoc clock frequency is not defined\n", __func__); devm_clk_put(&penv->pdev->dev, penv->snoc_wcnss); penv->snoc_wcnss = NULL; } @@ -3062,7 +3128,7 @@ wcnss_trigger_config(struct platform_device *pdev) penv->vadc_dev = qpnp_get_vadc(&penv->pdev->dev, "wcnss"); if (IS_ERR(penv->vadc_dev)) { - pr_debug("%s: vadc get failed\n", __func__); + wcnss_log(DBG, "%s: vadc get failed\n", __func__); penv->vadc_dev = NULL; } else { rc = wcnss_get_battery_volt(&penv->wlan_config.vbatt); @@ -3070,8 +3136,8 @@ wcnss_trigger_config(struct platform_device *pdev) wcnss_send_vbatt_indication); if (rc < 0) - pr_err("Failed to get battery voltage with error= %d\n", - rc); + wcnss_log(ERR, + "battery voltage get failed:err=%d\n", rc); } } @@ -3079,7 +3145,7 @@ wcnss_trigger_config(struct platform_device *pdev) /* trigger initialization of the WCNSS */ penv->pil = subsystem_get(WCNSS_PIL_DEVICE); if (IS_ERR(penv->pil)) { - dev_err(&pdev->dev, "Peripheral Loader failed on WCNSS.\n"); + wcnss_log(ERR, "Peripheral Loader failed on WCNSS.\n"); ret = PTR_ERR(penv->pil); wcnss_disable_pc_add_req(); wcnss_pronto_log_debug_regs(); @@ -3129,7 +3195,7 @@ void wcnss_snoc_vote(bool clk_chk_en) int rc; if (!penv->snoc_wcnss) { - pr_err("%s: couldn't get clk snoc_wcnss\n", __func__); + wcnss_log(ERR, "%s: couldn't get clk snoc_wcnss\n", __func__); return; } @@ -3137,13 +3203,15 @@ void wcnss_snoc_vote(bool clk_chk_en) rc = clk_set_rate(penv->snoc_wcnss, penv->snoc_wcnss_clock_freq); if (rc) { - pr_err("%s: snoc_wcnss_clk-clk_set_rate failed =%d\n", - __func__, rc); + wcnss_log(ERR, + "%s: snoc_wcnss_clk-clk_set_rate failed=%d\n", + __func__, rc); return; } if (clk_prepare_enable(penv->snoc_wcnss)) { - pr_err("%s: snoc_wcnss clk enable failed\n", __func__); + wcnss_log(ERR, "%s: snoc_wcnss clk enable failed\n", + __func__); return; } } else { @@ -3219,7 +3287,7 @@ static int wcnss_node_open(struct inode *inode, struct file *file) return -EFAULT; if (!penv->triggered) { - pr_info(DEVICE " triggered by userspace\n"); + wcnss_log(INFO, DEVICE " triggered by userspace\n"); pdev = penv->pdev; rc = wcnss_trigger_config(pdev); if (rc) @@ -3282,8 +3350,8 @@ static ssize_t wcnss_wlan_write(struct file *fp, const char __user user_buffer, 4); if (!penv->user_cal_exp_size || penv->user_cal_exp_size > MAX_CALIBRATED_DATA_SIZE) { - pr_err(DEVICE " invalid size to write %d\n", - penv->user_cal_exp_size); + wcnss_log(ERR, DEVICE " invalid size to write %d\n", + penv->user_cal_exp_size); penv->user_cal_exp_size = 0; mutex_unlock(&penv->dev_lock); return -EFAULT; @@ -3297,8 +3365,8 @@ static ssize_t wcnss_wlan_write(struct file *fp, const char __user mutex_lock(&penv->dev_lock); if ((UINT32_MAX - count < penv->user_cal_rcvd) || (penv->user_cal_exp_size < count + penv->user_cal_rcvd)) { - pr_err(DEVICE " invalid size to write %zu\n", count + - penv->user_cal_rcvd); + wcnss_log(ERR, DEVICE " invalid size to write %zu\n", + count + penv->user_cal_rcvd); mutex_unlock(&penv->dev_lock); return -ENOMEM; } @@ -3320,7 +3388,7 @@ static ssize_t wcnss_wlan_write(struct file *fp, const char __user kfree(cal_data); if (penv->user_cal_rcvd == penv->user_cal_exp_size) { penv->user_cal_available = true; - pr_info_ratelimited("wcnss: user cal written"); + wcnss_log(INFO, "user cal written"); } mutex_unlock(&penv->dev_lock); @@ -3342,12 +3410,12 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, if (!(code >= SUBSYS_NOTIF_MIN_INDEX) && (code <= SUBSYS_NOTIF_MAX_INDEX)) { - pr_debug("%s: Invaild subsystem notification code: %lu\n", - __func__, code); + wcnss_log(DBG, "%s: Invaild subsystem notification code: %lu\n", + __func__, code); return NOTIFY_DONE; } - pr_info("%s: wcnss notification event: %lu : %s\n", + wcnss_log(INFO, "%s: notification event: %lu : %s\n", __func__, code, wcnss_subsys_notif_type[code]); if (code == SUBSYS_PROXY_VOTE) { @@ -3356,7 +3424,7 @@ static int wcnss_notif_cb(struct notifier_block *this, unsigned long code, WCNSS_WLAN_SWITCH_ON, &xo_mode); wcnss_set_iris_xo_mode(xo_mode); if (ret) - pr_err("Failed to execute wcnss_wlan_power\n"); + wcnss_log(ERR, "wcnss_wlan_power failed\n"); } } else if (code == SUBSYS_PROXY_UNVOTE) { if (pdev && pwlanconfig) { @@ -3407,30 +3475,30 @@ static int wcnss_cdev_register(struct platform_device *pdev) ret = alloc_chrdev_region(&penv->dev_ctrl, 0, 1, CTRL_DEVICE); if (ret < 0) { - dev_err(&pdev->dev, "CTRL Device Registration failed\n"); + wcnss_log(ERR, "CTRL Device Registration failed\n"); goto alloc_region_ctrl; } ret = alloc_chrdev_region(&penv->dev_node, 0, 1, DEVICE); if (ret < 0) { - dev_err(&pdev->dev, "NODE Device Registration failed\n"); + wcnss_log(ERR, "NODE Device Registration failed\n"); goto alloc_region_node; } penv->node_class = class_create(THIS_MODULE, "wcnss"); if (!penv->node_class) { - dev_err(&pdev->dev, "NODE Device Class Creation failed\n"); + wcnss_log(ERR, "NODE Device Class Creation failed\n"); goto class_create_node; } if (device_create(penv->node_class, NULL, penv->dev_ctrl, NULL, CTRL_DEVICE) == NULL) { - dev_err(&pdev->dev, "CTRL Device Creation failed\n"); + wcnss_log(ERR, "CTRL Device Creation failed\n"); goto device_create_ctrl; } if (device_create(penv->node_class, NULL, penv->dev_node, NULL, DEVICE) == NULL) { - dev_err(&pdev->dev, "NODE Device Creation failed\n"); + wcnss_log(ERR, "NODE Device Creation failed\n"); goto device_create_node; } @@ -3438,11 +3506,11 @@ static int wcnss_cdev_register(struct platform_device *pdev) cdev_init(&penv->node_dev, &wcnss_node_fops); if (cdev_add(&penv->ctrl_dev, penv->dev_ctrl, 1) == -1) { - dev_err(&pdev->dev, "CTRL Device addition failed\n"); + wcnss_log(ERR, "CTRL Device addition failed\n"); goto cdev_add_ctrl; } if (cdev_add(&penv->node_dev, penv->dev_node, 1) == -1) { - dev_err(&pdev->dev, "NODE Device addition failed\n"); + wcnss_log(ERR, "NODE Device addition failed\n"); goto cdev_add_node; } @@ -3466,7 +3534,7 @@ static int wcnss_cdev_register(struct platform_device *pdev) static void wcnss_cdev_unregister(struct platform_device *pdev) { - dev_err(&pdev->dev, "Unregistering cdev devices\n"); + wcnss_log(ERR, "Unregistering cdev devices\n"); cdev_del(&penv->ctrl_dev); cdev_del(&penv->node_dev); device_destroy(penv->node_class, penv->dev_ctrl); @@ -3483,7 +3551,7 @@ wcnss_wlan_probe(struct platform_device *pdev) /* verify we haven't been called more than once */ if (penv) { - dev_err(&pdev->dev, "cannot handle multiple devices.\n"); + wcnss_log(ERR, "cannot handle multiple devices.\n"); return -ENODEV; } @@ -3497,7 +3565,7 @@ wcnss_wlan_probe(struct platform_device *pdev) penv->user_cal_data = devm_kzalloc(&pdev->dev, MAX_CALIBRATED_DATA_SIZE, GFP_KERNEL); if (!penv->user_cal_data) { - dev_err(&pdev->dev, "Failed to alloc memory for cal data.\n"); + wcnss_log(ERR, "Failed to alloc memory for cal data.\n"); return -ENOMEM; } @@ -3511,7 +3579,7 @@ wcnss_wlan_probe(struct platform_device *pdev) /* register wcnss event notification */ penv->wcnss_notif_hdle = subsys_notif_register_notifier("wcnss", &wnb); if (IS_ERR(penv->wcnss_notif_hdle)) { - pr_err("wcnss: register event notification failed!\n"); + wcnss_log(ERR, "register event notification failed!\n"); return PTR_ERR(penv->wcnss_notif_hdle); } @@ -3534,7 +3602,7 @@ wcnss_wlan_probe(struct platform_device *pdev) * device so that we know that WCNSS configuration can take * place */ - pr_info(DEVICE " probed in built-in mode\n"); + wcnss_log(INFO, DEVICE " probed in built-in mode\n"); return wcnss_cdev_register(pdev); } @@ -3579,6 +3647,11 @@ static struct platform_driver wcnss_wlan_driver = { static int __init wcnss_wlan_init(void) { + + wcnss_ipc_log = ipc_log_context_create(IPC_NUM_LOG_PAGES, "wcnss", 0); + if (!wcnss_ipc_log) + wcnss_log(ERR, "Unable to create log context\n"); + platform_driver_register(&wcnss_wlan_driver); platform_driver_register(&wcnss_wlan_ctrl_driver); platform_driver_register(&wcnss_ctrl_driver); @@ -3599,6 +3672,8 @@ static void __exit wcnss_wlan_exit(void) platform_driver_unregister(&wcnss_ctrl_driver); platform_driver_unregister(&wcnss_wlan_ctrl_driver); platform_driver_unregister(&wcnss_wlan_driver); + ipc_log_context_destroy(wcnss_ipc_log); + wcnss_ipc_log = NULL; } module_init(wcnss_wlan_init); diff --git a/include/linux/wcnss_wlan.h b/include/linux/wcnss_wlan.h index b37f8dfe94cd..05fb7b57c9f0 100644 --- a/include/linux/wcnss_wlan.h +++ b/include/linux/wcnss_wlan.h @@ -63,6 +63,13 @@ enum { WCNSS_WLAN_MAX_GPIO, }; +enum wcnss_log_type { + ERR, + WARN, + INFO, + DBG, +}; + #define WCNSS_VBATT_THRESHOLD 3500000 #define WCNSS_VBATT_GUARD 20000 #define WCNSS_VBATT_HIGH 3700000 @@ -145,6 +152,7 @@ void wcnss_dump_stack(struct task_struct *task); void wcnss_snoc_vote(bool clk_chk_en); int wcnss_parse_voltage_regulator(struct wcnss_wlan_config *wlan_config, struct device *dev); +void wcnss_log(enum wcnss_log_type type, const char *_fmt, ...); #ifdef CONFIG_WCNSS_REGISTER_DUMP_ON_BITE void wcnss_log_debug_regs_on_bite(void); -- GitLab From 2b798d627ed7b8160fca282b77166bd354b3c260 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Thu, 17 May 2018 11:15:14 +0530 Subject: [PATCH 1819/1834] regulator: cpr3: Configure CPR4 to keep thread vote Configure CPR4 controller to always keep thread vote when both HW threads enabled so that the controller does not consider MID/DN recommendations from other thread when all sensors mapped to a thread collapsed. CRs-Fixed: 2233565 Change-Id: I4c6a78b9b7e161da0be9b65bacfc601bde9f5c7a Signed-off-by: Tirupathi Reddy --- .../devicetree/bindings/regulator/cpr3-regulator.txt | 9 +++++++++ drivers/regulator/cpr3-regulator.c | 8 +++++++- drivers/regulator/cpr3-regulator.h | 9 ++++++++- drivers/regulator/cpr3-util.c | 12 +++++++++++- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt index 846bd22e5fcb..b02d759b1cf7 100644 --- a/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/cpr3-regulator.txt @@ -241,6 +241,15 @@ Platform independent properties: time in order to allow hardware closed-loop CPR voltage change requests to reach the PMIC regulator. +- qcom,cpr-thread-has-always-vote-en + Usage: optional; only meaningful for CPR4 controller + Value type: + Definition: Boolean value which indicates that the CPR controller should + be configured to keep thread vote always enabled. This + configuration allows the CPR controller to not consider + MID/DN recommendations from other thread when all sensors + mapped to a thread collapsed. + ================================================= Second Level Nodes - CPR Threads for a Controller ================================================= diff --git a/drivers/regulator/cpr3-regulator.c b/drivers/regulator/cpr3-regulator.c index 95100168f391..2eff0cff234e 100644 --- a/drivers/regulator/cpr3-regulator.c +++ b/drivers/regulator/cpr3-regulator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -178,6 +178,7 @@ #define CPR4_REG_MISC 0x700 #define CPR4_MISC_RESET_STEP_QUOT_LOOP_EN BIT(2) +#define CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN BIT(3) #define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_MASK GENMASK(23, 20) #define CPR4_MISC_MARGIN_TABLE_ROW_SELECT_SHIFT 20 #define CPR4_MISC_TEMP_SENSOR_ID_START_MASK GENMASK(27, 24) @@ -733,6 +734,11 @@ static int cpr3_regulator_init_cpr4(struct cpr3_controller *ctrl) CPR4_MISC_RESET_STEP_QUOT_LOOP_EN, CPR4_MISC_RESET_STEP_QUOT_LOOP_EN); + if (ctrl->thread_has_always_vote_en) + cpr3_masked_write(ctrl, CPR4_REG_MISC, + CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN, + CPR4_MISC_THREAD_HAS_ALWAYS_VOTE_EN); + if (ctrl->supports_hw_closed_loop) { if (ctrl->saw_use_unit_mV) pmic_step_size = ctrl->step_volt / 1000; diff --git a/drivers/regulator/cpr3-regulator.h b/drivers/regulator/cpr3-regulator.h index 778f4824bdf6..39d3f820c153 100644 --- a/drivers/regulator/cpr3-regulator.h +++ b/drivers/regulator/cpr3-regulator.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -766,6 +766,12 @@ struct cpr3_panic_regs_info { * the CPR controller to first use the default step_quot * and then later switch to the run-time calibrated * step_quot. + * @thread_has_always_vote_en: Boolean value which indicates that this CPR + * controller should be configured to keep thread vote + * always enabled. This configuration allows the CPR + * controller to not consider MID/DN recommendations from + * other thread when all sensors mapped to a thread + * collapsed. * * This structure contains both configuration and runtime state data. The * elements cpr_allowed_sw, use_hw_closed_loop, aggr_corner, cpr_enabled, @@ -879,6 +885,7 @@ struct cpr3_controller { struct notifier_block panic_notifier; bool support_ldo300_vreg; bool reset_step_quot_loop_en; + bool thread_has_always_vote_en; }; /* Used for rounding voltages to the closest physically available set point. */ diff --git a/drivers/regulator/cpr3-util.c b/drivers/regulator/cpr3-util.c index 39ee3c551e02..9e138ce28944 100644 --- a/drivers/regulator/cpr3-util.c +++ b/drivers/regulator/cpr3-util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1240,6 +1240,16 @@ int cpr3_parse_common_ctrl_data(struct cpr3_controller *ctrl) = of_property_read_bool(ctrl->dev->of_node, "qcom,cpr-reset-step-quot-loop-en"); + /* + * Configure CPR controller to not consider MID/DN recommendations + * from other thread when all sensors mapped to a thread collapsed + * in a multi-thread configuration. + */ + if (ctrl->thread_count > 1) + ctrl->thread_has_always_vote_en + = of_property_read_bool(ctrl->dev->of_node, + "qcom,cpr-thread-has-always-vote-en"); + /* * Regulator device handles are not necessary for CPRh controllers * since communication with the regulators is completely managed -- GitLab From 271ecf24c3a5c62cefbb751df58dc7a9e021dd41 Mon Sep 17 00:00:00 2001 From: Tirupathi Reddy Date: Tue, 8 May 2018 15:42:16 +0530 Subject: [PATCH 1820/1834] ARM: dts: msm: enable APC CPR closed-loop operation for sdm632 Enable APC CPR HW closed-loop operation with multi-thread configuration. Silver cluster and CCI sensors are mapped to thread-0 and Gold cluster sensors are mapped to Thread-1. CPR controller aggregates the individual thread recommendations and update the rail voltage through CCI-SAW4 AVS interface. Also, configure CPR consecutive down parameter to 0 for both the threads to fix the thread aggregation logic. Also, configure CPR controller to keep thread vote always enabled. CRs-Fixed: 2233565 Change-Id: Ib6a781f1e919b022585960cd9baf32013314a2f4 Signed-off-by: Tirupathi Reddy --- .../arm64/boot/dts/qcom/sdm632-regulator.dtsi | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi index a7580e07fd76..a50c9cfcff14 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632-regulator.dtsi @@ -114,6 +114,8 @@ qcom,cpr-count-repeat = <14>; qcom,cpr-down-error-step-limit = <1>; qcom,cpr-up-error-step-limit = <1>; + qcom,cpr-reset-step-quot-loop-en; + qcom,cpr-thread-has-always-vote-en; qcom,apm-ctrl = <&apc_apm>; qcom,apm-threshold-voltage = <875000>; @@ -131,10 +133,13 @@ "APCS_ALIAS0_APM_CTLER_STATUS", "APCS0_CPR_CORE_ADJ_MODE_REG"; + qcom,cpr-enable; + qcom,cpr-hw-closed-loop; + thread@0 { qcom,cpr-thread-id = <0>; qcom,cpr-consecutive-up = <0>; - qcom,cpr-consecutive-down = <2>; + qcom,cpr-consecutive-down = <0>; qcom,cpr-up-threshold = <2>; qcom,cpr-down-threshold = <1>; @@ -156,6 +161,10 @@ <500000 500000 500000 500000 500000 500000 500000>; + qcom,cpr-floor-to-ceiling-max-range = + <50000 50000 50000 50000 50000 + 50000 50000>; + qcom,mem-acc-voltage = <1 1 2 2 2 2 3>; qcom,corner-frequencies = @@ -176,13 +185,19 @@ qcom,allow-voltage-interpolation; qcom,allow-quotient-interpolation; qcom,cpr-scaled-open-loop-voltage-as-ceiling; + + qcom,cpr-open-loop-voltage-fuse-adjustment = + < 0 0 0 10000>; + + qcom,cpr-closed-loop-voltage-fuse-adjustment = + <(-10000) 0 0 10000>; }; }; thread@1 { qcom,cpr-thread-id = <1>; qcom,cpr-consecutive-up = <0>; - qcom,cpr-consecutive-down = <2>; + qcom,cpr-consecutive-down = <0>; qcom,cpr-up-threshold = <2>; qcom,cpr-down-threshold = <1>; @@ -204,6 +219,10 @@ <500000 500000 500000 500000 500000 500000 500000>; + qcom,cpr-floor-to-ceiling-max-range = + <50000 50000 50000 50000 50000 + 50000 50000>; + qcom,mem-acc-voltage = <1 1 2 2 2 2 3>; qcom,corner-frequencies = @@ -227,9 +246,9 @@ qcom,cpr-open-loop-voltage-fuse-adjustment = /* Speed bin 0; CPR rev 0..7 */ - < 30000 0 0 0>, - < 30000 0 0 0>, - < 0 0 0 0>, + < 30000 0 10000 20000>, + < 30000 0 10000 20000>, + < 0 0 10000 20000>, < 0 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, @@ -247,9 +266,9 @@ < 0 0 0 0>, /* Speed bin 2; CPR rev 0..7 */ - < 30000 0 0 0>, - < 30000 0 0 0>, - < 0 0 0 0>, + < 30000 0 10000 20000>, + < 30000 0 10000 20000>, + < 0 0 10000 20000>, < 0 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, @@ -287,9 +306,9 @@ < 0 0 0 0>, /* Speed bin 6; CPR rev 0..7 */ - < 30000 0 0 0>, - < 30000 0 0 0>, - < 0 0 0 0>, + < 30000 0 10000 20000>, + < 30000 0 10000 20000>, + < 0 0 10000 20000>, < 0 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, @@ -310,7 +329,7 @@ /* Speed bin 0; CPR rev 0..7 */ < 30000 0 0 0>, < 30000 0 0 0>, - < 0 0 0 0>, + <(-10000) 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, @@ -330,7 +349,7 @@ /* Speed bin 2; CPR rev 0..7 */ < 30000 0 0 0>, < 30000 0 0 0>, - < 0 0 0 0>, + <(-10000) 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, @@ -370,7 +389,7 @@ /* Speed bin 6; CPR rev 0..7 */ < 30000 0 0 0>, < 30000 0 0 0>, - < 0 0 0 0>, + <(-10000) 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, < 0 0 0 0>, -- GitLab From 86d80deab29d170962d2efa499235d224e549e81 Mon Sep 17 00:00:00 2001 From: blong Date: Wed, 16 May 2018 13:38:04 +0800 Subject: [PATCH 1821/1834] ARM: dts: msm: Update correct frequency in energy-costs for sdm632 Correct freq from 1036800 to 1094400 in gold cluster energy-costs for sdm632. Change-Id: I14852c82cc3d923018ed8953ab4cd8575f6b159f CRs-Fixed: 2242834 Signed-off-by: Biao long --- arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi index de1bd1f1d8d8..c37750a3ee1f 100644 --- a/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632-cpu.dtsi @@ -258,7 +258,7 @@ busy-cost-data = < 633600 722 902400 1287 - 1036800 1739 + 1094400 1739 1401600 2819 1555200 3532 1804800 5038 @@ -287,7 +287,7 @@ busy-cost-data = < 633600 68 902400 103 - 1036800 132 + 1094400 132 1401600 193 1555200 233 1804800 292 -- GitLab From 1dd640895a50e95736d354517c826633293b429d Mon Sep 17 00:00:00 2001 From: Taniya Das Date: Fri, 23 Mar 2018 16:51:36 +0530 Subject: [PATCH 1822/1834] clk: msm: gcc: Add support for GPU clock 700/725MHz SDM632 requires gfx client requires to vote on the new frequencies of 700 & 725MHz, so add support for these new frequencies. Change-Id: I47332ed4467a02b6b01ea6bb69e96a74e4c26932 Signed-off-by: Taniya Das --- arch/arm64/boot/dts/qcom/sdm632.dtsi | 11 +++++++++++ drivers/clk/msm/clock-gcc-8953.c | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sdm632.dtsi b/arch/arm64/boot/dts/qcom/sdm632.dtsi index b54e8315528c..67efe0f85d96 100644 --- a/arch/arm64/boot/dts/qcom/sdm632.dtsi +++ b/arch/arm64/boot/dts/qcom/sdm632.dtsi @@ -40,6 +40,17 @@ &clock_gcc_gfx { compatible = "qcom,gcc-gfx-sdm632"; + qcom,gfxfreq-corner = + < 0 0 >, + < 133330000 1 >, /* Min SVS */ + < 216000000 2 >, /* Low SVS */ + < 320000000 3 >, /* SVS */ + < 400000000 4 >, /* SVS Plus */ + < 510000000 5 >, /* NOM */ + < 560000000 6 >, /* Nom Plus */ + < 650000000 7 >, /* Turbo */ + < 700000000 7 >, /* Turbo */ + < 725000000 7 >; /* Turbo */ }; &thermal_zones { diff --git a/drivers/clk/msm/clock-gcc-8953.c b/drivers/clk/msm/clock-gcc-8953.c index 57adebf4d4b8..0e8665c1f5d4 100644 --- a/drivers/clk/msm/clock-gcc-8953.c +++ b/drivers/clk/msm/clock-gcc-8953.c @@ -411,6 +411,27 @@ static struct clk_freq_tbl ftbl_gfx3d_clk_src_sdm450[] = { F_END }; +static struct clk_freq_tbl ftbl_gfx3d_clk_src_sdm632[] = { + F_MM( 19200000, FIXED_CLK_SRC, xo, 1, 0, 0), + F_MM( 50000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 8, 0, 0), + F_MM( 80000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 5, 0, 0), + F_MM( 100000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 4, 0, 0), + F_MM( 133330000, FIXED_CLK_SRC, gpll0_main_div2_mm, 3, 0, 0), + F_MM( 160000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2.5, 0, 0), + F_MM( 200000000, FIXED_CLK_SRC, gpll0_main_div2_mm, 2, 0, 0), + F_MM( 216000000, FIXED_CLK_SRC, gpll6_main_div2_gfx, 2.5, 0, 0), + F_MM( 266670000, FIXED_CLK_SRC, gpll0, 3, 0, 0), + F_MM( 320000000, FIXED_CLK_SRC, gpll0, 2.5, 0, 0), + F_MM( 400000000, FIXED_CLK_SRC, gpll0, 2, 0, 0), + F_MM( 460800000, FIXED_CLK_SRC, gpll4_out_aux, 2.5, 0, 0), + F_MM( 510000000, 1020000000, gpll3, 1, 0, 0), + F_MM( 560000000, 1120000000, gpll3, 1, 0, 0), + F_MM( 650000000, 1300000000, gpll3, 1, 0, 0), + F_MM( 700000000, 1400000000, gpll3, 1, 0, 0), + F_MM( 725000000, 1450000000, gpll3, 1, 0, 0), + + F_END +}; static struct rcg_clk gfx3d_clk_src = { .cmd_rcgr_reg = GFX3D_CMD_RCGR, .set_rate = set_rate_hid, @@ -4104,6 +4125,11 @@ static int msm_gcc_gfx_probe(struct platform_device *pdev) if (compat_bin) gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_sdm450; + compat_bin = of_device_is_compatible(pdev->dev.of_node, + "qcom,gcc-gfx-sdm632"); + if (compat_bin) + gfx3d_clk_src.freq_tbl = ftbl_gfx3d_clk_src_sdm632; + ret = of_get_fmax_vdd_class(pdev, &gcc_oxili_gfx3d_clk.c, "qcom,gfxfreq-corner"); if (ret) { -- GitLab From 4519cc36b1a396dc55c9b43ab6e8736ae4a6f4cf Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Fri, 11 May 2018 10:21:22 +0530 Subject: [PATCH 1823/1834] lpm-levels: Remove kfree for memory allocated with devm_kzalloc Do not use kfree for memory allocated with devm_kzalloc during failures as device memory will get freed in device release. Change-Id: I6c4d3f8ed55ab02e3e70a1fe65452a8817c8b64e Signed-off-by: Maulik Shah --- drivers/cpuidle/lpm-levels-of.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/drivers/cpuidle/lpm-levels-of.c b/drivers/cpuidle/lpm-levels-of.c index fe3ef48b886d..7a653c6c2035 100644 --- a/drivers/cpuidle/lpm-levels-of.c +++ b/drivers/cpuidle/lpm-levels-of.c @@ -708,7 +708,7 @@ static int parse_cpu(struct device_node *node, struct lpm_cpu *cpu) static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) { - int ret, i; + int ret; char *key; struct lpm_cpu *cpu; @@ -724,12 +724,12 @@ static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) key = "qcom,psci-mode-shift"; ret = of_property_read_u32(node, key, &cpu->psci_mode_shift); if (ret) - goto failed_parse_params; + goto failed; key = "qcom,psci-mode-mask"; ret = of_property_read_u32(node, key, &cpu->psci_mode_mask); if (ret) - goto failed_parse_params; + goto failed; key = "qcom,disable-prediction"; cpu->lpm_prediction = !(of_property_read_bool(node, key)); @@ -757,20 +757,14 @@ static int parse_cpu_levels(struct device_node *node, struct lpm_cluster *c) key = "parse_cpu"; ret = parse_cpu(node, cpu); if (ret) - goto failed_parse_cpu; + goto failed; cpumask_or(&c->child_cpus, &c->child_cpus, &cpu->related_cpus); list_add(&cpu->list, &c->cpu); return ret; -failed_parse_cpu: - for (i = 0; i < cpu->nlevels; i++) { - kfree(cpu->levels[i].name); - cpu->levels[i].name = NULL; - } - -failed_parse_params: +failed: pr_err("Failed to read key: %s node: %s\n", key, node->name); return ret; } @@ -785,15 +779,8 @@ void free_cluster_node(struct lpm_cluster *cluster) free_cluster_node(cl); }; - list_for_each_entry_safe(cpu, n, &cluster->cpu, list) { - int i; - + list_for_each_entry_safe(cpu, n, &cluster->cpu, list) list_del(&cpu->list); - for (i = 0; i < cpu->nlevels; i++) { - kfree(cpu->levels[i].name); - cpu->levels[i].name = NULL; - } - } } /* @@ -886,7 +873,6 @@ struct lpm_cluster *parse_cluster(struct device_node *node, list_del(&c->list); free_cluster_node(c); failed_parse_params: - c->parent = NULL; pr_err("Failed parse params\n"); return NULL; } -- GitLab From 570fa783df7ea0eb2ce319729061bfa7e4fbc037 Mon Sep 17 00:00:00 2001 From: Mao Jinlong Date: Mon, 14 May 2018 18:31:49 +0800 Subject: [PATCH 1824/1834] coresight: add the authentication logic for coresight etm Add the authentication logic that depends on the CoreSight AUTHSTATUS register rather than the fuses that helps in collecting the CPU trace on the secure device if ETM is functional. CRs-Fixed: 2236496 Change-Id: I7ca410cc7b72a98235101f64f090c65e37603d27 Signed-off-by: Charan Teja Reddy Signed-off-by: Mao Jinlong --- drivers/hwtracing/coresight/coresight-etm3x.c | 8 +++++++- drivers/hwtracing/coresight/coresight-etm4x.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-etm3x.c b/drivers/hwtracing/coresight/coresight-etm3x.c index f57ad2e0d32e..3bbcc957740c 100644 --- a/drivers/hwtracing/coresight/coresight-etm3x.c +++ b/drivers/hwtracing/coresight/coresight-etm3x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2012, 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2011-2012, 2016, 2018, The Linux Foundation. All rights reserved. * * Description: CoreSight Program Flow Trace driver * @@ -39,6 +39,7 @@ #include "coresight-etm.h" #include "coresight-etm-perf.h" +#include "coresight-priv.h" /* * Not really modular but using module_param is the easiest way to @@ -711,6 +712,10 @@ static void etm_init_arch_data(void *info) CS_UNLOCK(drvdata->base); + /* check the state of the fuse */ + if (!coresight_authstatus_enabled(drvdata->base)) + goto out; + /* First dummy read */ (void)etm_readl(drvdata, ETMPDSR); /* Provide power to ETM: ETMPDCR[3] == 1 */ @@ -742,6 +747,7 @@ static void etm_init_arch_data(void *info) etm_set_pwrdwn(drvdata); etm_clr_pwrup(drvdata); +out: CS_LOCK(drvdata->base); } diff --git a/drivers/hwtracing/coresight/coresight-etm4x.c b/drivers/hwtracing/coresight/coresight-etm4x.c index a4bf109c401e..5db74f0e9ec3 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x.c +++ b/drivers/hwtracing/coresight/coresight-etm4x.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014, 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014, 2016-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -38,6 +38,7 @@ #include "coresight-etm4x.h" #include "coresight-etm-perf.h" +#include "coresight-priv.h" static int boot_enable; module_param_named(boot_enable, boot_enable, int, 0444); @@ -436,6 +437,9 @@ static void etm4_init_arch_data(void *info) CS_UNLOCK(drvdata->base); + if (!coresight_authstatus_enabled(drvdata->base)) + goto out; + /* find all capabilities of the tracing unit */ etmidr0 = readl_relaxed(drvdata->base + TRCIDR0); @@ -582,6 +586,8 @@ static void etm4_init_arch_data(void *info) drvdata->nrseqstate = BMVAL(etmidr5, 25, 27); /* NUMCNTR, bits[30:28] number of counters available for tracing */ drvdata->nr_cntr = BMVAL(etmidr5, 28, 30); + +out: CS_LOCK(drvdata->base); } -- GitLab From 13785cd57d965956c525213433c18d40e39adf32 Mon Sep 17 00:00:00 2001 From: Amar Singhal Date: Wed, 16 May 2018 12:20:18 -0700 Subject: [PATCH 1825/1834] cfg80211: Add backport flag for user cellular base hint Upstream commit aced43ce780dc5e6 ("cfg80211: Call reg_notifier for self managed hints conditionally") adds support for processing user cell_base hints when wiphy is self managed. Add backport flag for the same. Change-Id: I44e083f4346cc95eb2f80eeec7d56f305e7ecce0 CRs-Fixed: 2201959 Signed-off-by: Amar Singhal --- include/net/cfg80211.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 520c4c36885d..716b3e2989dc 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -64,6 +64,9 @@ /* Indicate backport support for external authentication*/ #define CFG80211_EXTERNAL_AUTH_SUPPORT 1 +/* Indicate backport support for processing user cell base hint */ +#define CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED 1 + /** * DOC: Introduction * -- GitLab From e66e9ba7e68c22adeaedf727b4ee24a8e8fcdde6 Mon Sep 17 00:00:00 2001 From: Azam Sadiq Pasha Kapatrala Syed Date: Tue, 15 May 2018 17:36:28 -0700 Subject: [PATCH 1826/1834] ARM: dts: msm: Configure gpio to avoid external subsystem reset on 8953 For 8953 battery camera platform, gpio75 is used to control external wifi subsystem. For battery camera application this GPIO should always remain low except in the case where it needs to be explicitly set high through software interface to reset external wifi subsystem. Change-Id: Ie360fba443cef2ba4f113dc4605d48cfeb94896c Signed-off-by: Azam Sadiq Pasha Kapatrala Syed --- arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi index 5e3ddce4f481..7bfb81efa6c5 100644 --- a/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi +++ b/arch/arm64/boot/dts/qcom/apq8053-lite-dragon.dtsi @@ -270,7 +270,7 @@ pins = "gpio75"; drive-strength = <10>; bias-pull-up; - output-high; + output-low; }; }; sdc2_wlan_gpio_off: sdc2_wlan_gpio_off { -- GitLab From 6d9ba9354e0d0289461b8b956bd84410d65be731 Mon Sep 17 00:00:00 2001 From: Anirudh Ghayal Date: Mon, 7 May 2018 13:57:26 +0530 Subject: [PATCH 1827/1834] power: qpnp-qg: Update CURRENT_NOW for parallel charging The last_fifo_i alternately samples the current from internal BAT_FET and parallel charger. Instead use the FIFO_I average while reporting CURRENT_NOW when parallel charging is enabled. While at it, use the RTC time as the FIFO timestamp for better co-relation during debug. Change-Id: Iaaf445809b1b0096cc74b5d62c2510640f0482ad Signed-off-by: Anirudh Ghayal --- drivers/power/supply/qcom/qpnp-qg.c | 38 ++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c index 09705ade7b30..c386cbfb47b9 100644 --- a/drivers/power/supply/qcom/qpnp-qg.c +++ b/drivers/power/supply/qcom/qpnp-qg.c @@ -261,8 +261,13 @@ static int qg_process_fifo(struct qpnp_qg *chip, u32 fifo_length) int rc = 0, i, j = 0, temp; u8 v_fifo[MAX_FIFO_LENGTH * 2], i_fifo[MAX_FIFO_LENGTH * 2]; u32 sample_interval = 0, sample_count = 0, fifo_v = 0, fifo_i = 0; + unsigned long rtc_sec = 0; + + rc = get_rtc_time(&rtc_sec); + if (rc < 0) + pr_err("Failed to get RTC time, rc=%d\n", rc); - chip->kdata.fifo_time = (u32)ktime_get_seconds(); + chip->kdata.fifo_time = (u32)rtc_sec; if (!fifo_length) { pr_debug("No FIFO data\n"); @@ -1097,17 +1102,36 @@ static const char *qg_get_battery_type(struct qpnp_qg *chip) static int qg_get_battery_current(struct qpnp_qg *chip, int *ibat_ua) { int rc = 0, last_ibat = 0; + u32 fifo_length = 0; if (chip->battery_missing) { *ibat_ua = 0; return 0; } - rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG, - (u8 *)&last_ibat, 2); - if (rc < 0) { - pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc); - return rc; + if (chip->parallel_enabled) { + /* read the last real-time FIFO */ + rc = get_fifo_length(chip, &fifo_length, true); + if (rc < 0) { + pr_err("Failed to read RT FIFO length, rc=%d\n", rc); + return rc; + } + fifo_length = (fifo_length == 0) ? 0 : fifo_length - 1; + fifo_length *= 2; + rc = qg_read(chip, chip->qg_base + QG_I_FIFO0_DATA0_REG + + fifo_length, (u8 *)&last_ibat, 2); + if (rc < 0) { + pr_err("Failed to read FIFO_I_%d reg, rc=%d\n", + fifo_length / 2, rc); + return rc; + } + } else { + rc = qg_read(chip, chip->qg_base + QG_LAST_ADC_I_DATA0_REG, + (u8 *)&last_ibat, 2); + if (rc < 0) { + pr_err("Failed to read LAST_ADV_I reg, rc=%d\n", rc); + return rc; + } } last_ibat = sign_extend32(last_ibat, 15); @@ -2742,7 +2766,9 @@ static int process_resume(struct qpnp_qg *chip) chip->kdata.param[QG_GOOD_OCV_UV].data = ocv_uv; chip->kdata.param[QG_GOOD_OCV_UV].valid = true; /* Clear suspend data as there has been a GOOD OCV */ + memset(&chip->kdata, 0, sizeof(chip->kdata)); chip->suspend_data = false; + qg_dbg(chip, QG_DEBUG_PM, "GOOD OCV @ resume good_ocv=%d uV\n", ocv_uv); } -- GitLab From 4cfd68ee5a7ca74d58ccb8d80f957eeb9ff68393 Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Mon, 7 May 2018 11:52:39 +0530 Subject: [PATCH 1828/1834] ARM: dts: msm: add device tree support for msm8917 Add device tree support for msm8917 device. This implementation is based on snapshot of the msm8917 device tree from msm-3.18 commit 4ad309b7a8c47 ("ARM: dts: msm: add the CoreSight componenets for msmgold"). Change-Id: I6d75cd38ea61e79ba8befb46711a9bd811f46e0b Signed-off-by: Swetha Chikkaboraiah --- .../boot/dts/qcom/msm8917-coresight.dtsi | 1039 +++++++++++++++++ arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi | 43 + arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi | 14 + arch/arm64/boot/dts/qcom/msm8917-pm.dtsi | 204 ++++ arch/arm64/boot/dts/qcom/msm8917.dtsi | 136 +++ 5 files changed, 1436 insertions(+) create mode 100644 arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi diff --git a/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi b/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi new file mode 100644 index 000000000000..87303c5ad4c7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-coresight.dtsi @@ -0,0 +1,1039 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + tmc_etr: tmc@6028000 { + compatible = "arm,primecell"; + reg = <0x6028000 0x1000>, + <0x6044000 0x15000>; + reg-names = "tmc-base", "bam-base"; + + interrupts = <0 166 0>; + interrupt-names = "byte-cntr-irq"; + + arm,buffer-size = <0x100000>; + arm,sg-enable; + qcom,force-reg-dump; + + coresight-name = "coresight-tmc-etr"; + coresight-csr = <&csr>; + coresight-ctis = <&cti0 &cti8>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + tmc_etr_in_replicator: endpoint { + slave-mode; + remote-endpoint = <&replicator_out_tmc_etr>; + }; + }; + }; + + replicator: replicator@6026000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b909>; + + reg = <0x6026000 0x1000>; + reg-names = "replicator-base"; + + coresight-name = "coresight-replicator"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + replicator_out_tmc_etr: endpoint { + remote-endpoint = + <&tmc_etr_in_replicator>; + }; + }; + + port@1 { + reg = <0>; + replicator_in_tmc_etf: endpoint { + slave-mode; + remote-endpoint = + <&tmc_etf_out_replicator>; + }; + }; + }; + }; + + tmc_etf: tmc@6027000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b961>; + + reg = <0x6027000 0x1000>; + reg-names = "tmc-base"; + + coresight-name = "coresight-tmc-etf"; + coresight-csr = <&csr>; + + arm,default-sink; + qcom,force-reg-dump; + + coresight-ctis = <&cti0 &cti8>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + tmc_etf_out_replicator:endpoint { + remote-endpoint = + <&replicator_in_tmc_etf>; + }; + }; + + port@1 { + reg = <0>; + tmc_etf_in_funnel_in0: endpoint { + slave-mode; + remote-endpoint = + <&funnel_in0_out_tmc_etf>; + }; + }; + }; + }; + + funnel_in0: funnel@6021000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6021000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-in0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_in0_out_tmc_etf: endpoint { + remote-endpoint = + <&tmc_etf_in_funnel_in0>; + }; + }; + + port@1 { + reg = <7>; + funnel_in0_in_stm: endpoint { + slave-mode; + remote-endpoint = <&stm_out_funnel_in0>; + }; + }; + + port@2 { + reg = <6>; + funnel_in0_in_tpda: endpoint { + slave-mode; + remote-endpoint = + <&tpda_out_funnel_in0>; + }; + }; + + port@3 { + reg = <3>; + funnel_in0_in_funnel_center: endpoint { + slave-mode; + remote-endpoint = + <&funnel_center_out_funnel_in0>; + }; + }; + + port@4 { + reg = <4>; + funnel_in0_in_funnel_right: endpoint { + slave-mode; + remote-endpoint = + <&funnel_right_out_funnel_in0>; + }; + }; + + port@5 { + reg = <5>; + funnel_in0_in_funnel_mm: endpoint { + slave-mode; + remote-endpoint = + <&funnel_mm_out_funnel_in0>; + }; + }; + }; + }; + + funnel_mm: funnel@6130000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6130000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-mm"; + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_mm_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_mm>; + }; + }; + + port@1 { + reg = <0>; + funnel_mm_in_wcn_etm0: endpoint { + slave-mode; + remote-endpoint = + <&wcn_etm0_out_funnel_mm>; + }; + }; + + port@2 { + reg = <4>; + funnel_mm_in_funnel_cam: endpoint { + slave-mode; + remote-endpoint = + <&funnel_cam_out_funnel_mm>; + }; + }; + + port@3 { + reg = <5>; + funnel_mm_in_audio_etm0: endpoint { + slave-mode; + remote-endpoint = + <&audio_etm0_out_funnel_mm>; + }; + }; + }; + }; + + funnel_center: funnel@6100000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6100000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-center"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_center_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_center>; + }; + }; + + port@1 { + reg = <0>; + funnel_center_in_rpm_etm0: endpoint { + slave-mode; + remote-endpoint = + <&rpm_etm0_out_funnel_center>; + }; + }; + + port@2 { + reg = <2>; + funnel_center_in_dbgui: endpoint { + slave-mode; + remote-endpoint = + <&dbgui_out_funnel_center>; + }; + }; + }; + }; + + funnel_right: funnel@6120000 { + compatible = "arm,primecell"; + + reg = <0x6120000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-right"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_right_out_funnel_in0: endpoint { + remote-endpoint = + <&funnel_in0_in_funnel_right>; + }; + }; + + port@1 { + reg = <1>; + funnel_right_in_modem_etm0: endpoint { + slave-mode; + remote-endpoint = + <&modem_etm0_out_funnel_right>; + }; + }; + + port@2 { + reg = <2>; + funnel_right_in_funnel_apss: endpoint { + slave-mode; + remote-endpoint = + <&funnel_apss_out_funnel_right>; + }; + }; + }; + }; + + funnel_cam: funnel@6132000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x6132000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-cam"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + funnel_cam_out_funnel_mm: endpoint { + remote-endpoint = <&funnel_mm_in_funnel_cam>; + }; + }; + }; + + funnel_apss: funnel@61a1000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b908>; + + reg = <0x61a1000 0x1000>; + reg-names = "funnel-base"; + + coresight-name = "coresight-funnel-apss"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + funnel_apss_out_funnel_right: endpoint { + remote-endpoint = + <&funnel_right_in_funnel_apss>; + }; + }; + + port@1 { + reg = <0>; + funnel_apss0_in_etm0: endpoint { + slave-mode; + remote-endpoint = + <&etm0_out_funnel_apss0>; + }; + }; + + port@2 { + reg = <1>; + funnel_apss0_in_etm1: endpoint { + slave-mode; + remote-endpoint = + <&etm1_out_funnel_apss0>; + }; + }; + + port@3 { + reg = <2>; + funnel_apss0_in_etm2: endpoint { + slave-mode; + remote-endpoint = + <&etm2_out_funnel_apss0>; + }; + }; + + port@4 { + reg = <3>; + funnel_apss0_in_etm3: endpoint { + slave-mode; + remote-endpoint = + <&etm3_out_funnel_apss0>; + }; + }; + }; + }; + + etm0: etm@61bc000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bc000 0x1000>; + cpu = <&CPU0>; + reg-names = "etm-base"; + + coresight-name = "coresight-etm0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + port { + etm0_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm0>; + }; + }; + }; + + etm1: etm@61bd000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bd000 0x1000>; + cpu = <&CPU1>; + coresight-name = "coresight-etm1"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm1_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm1>; + }; + }; + }; + + etm2: etm@61be000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61be000 0x1000>; + cpu = <&CPU2>; + coresight-name = "coresight-etm2"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm2_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm2>; + }; + }; + }; + + etm3: etm@61bf000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x000bb95d>; + + reg = <0x61bf000 0x1000>; + cpu = <&CPU3>; + coresight-name = "coresight-etm3"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + etm3_out_funnel_apss0: endpoint { + remote-endpoint = <&funnel_apss0_in_etm3>; + }; + }; + }; + + stm: stm@6002000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b962>; + + reg = <0x6002000 0x1000>, + <0x9280000 0x180000>; + reg-names = "stm-base", "stm-data-base"; + + coresight-name = "coresight-stm"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + stm_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_stm>; + }; + }; + }; + + cti0: cti@6010000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6010000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti1: cti@6011000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6011000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti1"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti2: cti@6012000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6012000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti2"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti3: cti@6013000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6013000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti3"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti4: cti@6014000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6014000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti4"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti5: cti@6015000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6015000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti5"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti6: cti@6016000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6016000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti6"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti7: cti@6017000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6017000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti7"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti8: cti@6018000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6018000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti8"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti9: cti@6019000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6019000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti9"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti10: cti@601a000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601a000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti10"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti11: cti@601b000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601b000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti11"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti12: cti@601c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti12"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti13: cti@601d000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601d000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti13"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti14: cti@601e000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601e000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti14"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti15: cti@601f000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x601f000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti15"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu0: cti@61b8000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61b8000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu0"; + cpu = <&CPU0>; + qcom,cti-save; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu1: cti@61b9000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61b9000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu1"; + cpu = <&CPU1>; + qcom,cti-save; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu2: cti@61ba000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61ba000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu2"; + cpu = <&CPU2>; + qcom,cti-save; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_cpu3: cti@61bb000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x61bb000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-cpu3"; + cpu = <&CPU3>; + qcom,cti-save; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + cti_modem_cpu0: cti@6124000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6124000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-modem-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* Proto CTI */ + cti_wcn_cpu0: cti@6139000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6139000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-wcn-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* Venus CTI */ + cti_video_cpu0: cti@6134000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x6134000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-video-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* LPASS CTI */ + cti_audio_cpu0: cti@613c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x613c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-audio-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* RPM CTI */ + cti_rpm_cpu0: cti@610c000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b966>; + + reg = <0x610c000 0x1000>; + reg-names = "cti-base"; + + coresight-name = "coresight-cti-rpm-cpu0"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + /* Proto ETM */ + wcn_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-wcn-etm0"; + qcom,inst-id = <3>; + + port { + wcn_etm0_out_funnel_mm: endpoint { + remote-endpoint = <&funnel_mm_in_wcn_etm0>; + }; + }; + }; + + rpm_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-rpm-etm0"; + qcom,inst-id = <4>; + + port { + rpm_etm0_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_rpm_etm0>; + }; + }; + }; + + /* LPASS ETM */ + audio_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-audio-etm0"; + qcom,inst-id = <5>; + + port { + audio_etm0_out_funnel_mm: endpoint { + remote-endpoint = <&funnel_mm_in_audio_etm0>; + }; + }; + }; + + modem_etm0 { + compatible = "qcom,coresight-remote-etm"; + coresight-name = "coresight-modem-etm0"; + qcom,inst-id = <11>; + + port { + modem_etm0_out_funnel_right: endpoint { + remote-endpoint = <&funnel_right_in_modem_etm0>; + }; + }; + }; + + csr: csr@6001000 { + compatible = "qcom,coresight-csr"; + reg = <0x6001000 0x1000>; + reg-names = "csr-base"; + + coresight-name = "coresight-csr"; + + qcom,usb-bam-support; + qcom,hwctrl-set-support; + qcom,set-byte-cntr-support; + + qcom,blk-size = <1>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; + + dbgui: dbgui@6108000 { + compatible = "qcom,coresight-dbgui"; + reg = <0x6108000 0x1000>; + reg-names = "dbgui-base"; + + coresight-name = "coresight-dbgui"; + + qcom,dbgui-addr-offset = <0x30>; + qcom,dbgui-data-offset = <0x130>; + qcom,dbgui-size = <32>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + dbgui_out_funnel_center: endpoint { + remote-endpoint = <&funnel_center_in_dbgui>; + }; + }; + }; + + tpda: tpda@6003000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b969>; + + reg = <0x6003000 0x1000>; + reg-names = "tpda-base"; + + coresight-name = "coresight-tpda"; + + qcom,tpda-atid = <64>; + qcom,cmb-elem-size = <0 32>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + tpda_out_funnel_in0: endpoint { + remote-endpoint = <&funnel_in0_in_tpda>; + }; + }; + + port@1 { + reg = <0>; + tpda_in_tpdm_dcc: endpoint { + slave-mode; + remote-endpoint = + <&tpdm_dcc_out_tpda>; + }; + }; + }; + }; + + tpdm_dcc: tpdm@6110000 { + compatible = "arm,primecell"; + arm,primecell-periphid = <0x0003b968>; + + reg = <0x6110000 0x1000>; + reg-names = "tpdm-base"; + + coresight-name = "coresight-tpdm-dcc"; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + + port { + tpdm_dcc_out_tpda: endpoint { + remote-endpoint = <&tpda_in_tpdm_dcc>; + }; + }; + }; + + hwevent: hwevent@6101000 { + compatible = "qcom,coresight-hwevent"; + reg = <0x6101000 0x148>, + <0x6101fb0 0x4>, + <0x6121000 0x148>, + <0x6121fb0 0x4>, + <0x6131000 0x148>, + <0x6131fb0 0x4>, + <0x78c5010 0x4>, + <0x7885010 0x4>; + reg-names = "center-wrapper-mux", "center-wrapper-lockaccess", + "right-wrapper-mux", "right-wrapper-lockaccess", + "mm-wrapper-mux", "mm-wrapper-lockaccess", + "usbbam-mux", "blsp-mux"; + + coresight-name = "coresight-hwevent"; + coresight-csr = <&csr>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "apb_pclk"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi index 792d5d123848..5a242db555ea 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-cpu.dtsi @@ -117,3 +117,46 @@ }; }; + +&soc { + cpuss_dump { + compatible = "qcom,cpuss-dump"; + qcom,l2_dump1 { + /* L2 cache dump for A53 cluster */ + qcom,dump-node = <&L2_1>; + qcom,dump-id = <0xC1>; + }; + qcom,l1_i_cache100 { + qcom,dump-node = <&L1_I_100>; + qcom,dump-id = <0x60>; + }; + qcom,l1_i_cache101 { + qcom,dump-node = <&L1_I_101>; + qcom,dump-id = <0x61>; + }; + qcom,l1_i_cache102 { + qcom,dump-node = <&L1_I_102>; + qcom,dump-id = <0x62>; + }; + qcom,l1_i_cache103 { + qcom,dump-node = <&L1_I_103>; + qcom,dump-id = <0x63>; + }; + qcom,l1_d_cache100 { + qcom,dump-node = <&L1_D_100>; + qcom,dump-id = <0x80>; + }; + qcom,l1_d_cache101 { + qcom,dump-node = <&L1_D_101>; + qcom,dump-id = <0x81>; + }; + qcom,l1_d_cache102 { + qcom,dump-node = <&L1_D_102>; + qcom,dump-id = <0x82>; + }; + qcom,l1_d_cache103 { + qcom,dump-node = <&L1_D_103>; + qcom,dump-id = <0x83>; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi index 800ea1cd6c69..164b7816234e 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-mtp.dtsi @@ -68,6 +68,20 @@ status = "ok"; }; +&soc { + hbtp { + compatible = "qcom,hbtp-input"; + vcc_ana-supply = <&pm8937_l10>; + vcc_dig-supply = <&pm8937_l5>; + qcom,afe-load = <50000>; + qcom,afe-vtg-min = <2850000>; + qcom,afe-vtg-max = <2850000>; + qcom,dig-load = <15000>; + qcom,dig-vtg-min = <1800000>; + qcom,dig-vtg-max = <1800000>; + }; +}; + #include "msm8937-mdss-panels.dtsi" &mdss_mdp { diff --git a/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi index 6200b4ee7129..575d1b5d684f 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917-pm.dtsi @@ -125,7 +125,211 @@ }; }; + qcom,mpm@601d0 { + compatible = "qcom,mpm-v2"; + reg = <0x601d0 0x1000>, /* MSM_RPM_MPM_BASE 4K */ + <0xb011008 0x4>; + reg-names = "vmpm", "ipc"; + interrupts = <0 171 1>; + clocks = <&clock_gcc clk_xo_lpm_clk>; + clock-names = "xo"; + qcom,ipc-bit-offset = <1>; + qcom,gic-parent = <&intc>; + qcom,gic-map = <2 216>, /* tsens_upper_lower_int */ + <49 172>, /* usb1_hs_async_wakeup_irq */ + <58 166>, /* usb_hs_irq */ + <53 104>, /* mdss_irq */ + <62 222>, /* ee0_krait_hlos_spmi_periph_irq */ + <0xff 18>, /* APC_qgicQTmrSecPhysIrptReq */ + <0xff 19>, /* APC_qgicQTmrNonSecPhysIrptReq */ + <0xff 20>, /* qgicQTmrVirtIrptReq */ + <0xff 35>, /* WDT_barkInt */ + <0xff 39>, /* arch_mem_timer */ + <0xff 40>, /* qtmr_phy_irq[0] */ + <0xff 47>, /* rbif_irq[0] */ + <0xff 56>, /* q6_wdog_expired_irq */ + <0xff 57>, /* mss_to_apps_irq(0) */ + <0xff 58>, /* mss_to_apps_irq(1) */ + <0xff 59>, /* mss_to_apps_irq(2) */ + <0xff 60>, /* mss_to_apps_irq(3) */ + <0xff 61>, /* mss_a2_bam_irq */ + <0xff 65>, /* o_gc_sys_irq[0] */ + <0xff 69>, /* vbif_irpt */ + <0xff 73>, /* smmu_intr_bus[1] */ + <0xff 74>, /* smmu_bus_intr[2] */ + <0xff 75>, /* smmu_bus_intr[3] */ + <0xff 76>, /* venus_irq */ + <0xff 78>, /* smmu_bus_intr[5] */ + <0xff 79>, /* smmu_bus_intr[6] */ + <0xff 85>, /* smmu_bus_intr[31] */ + <0xff 86>, /* smmu_bus_intr[32] */ + <0xff 90>, /* smmu_bus_intr[33] */ + <0xff 92>, /* smmu_bus_intr[34] */ + <0xff 93>, /* smmu_bus_intr[35] */ + <0xff 97>, /* smmu_bus_intr[10] */ + <0xff 102>, /* smmu_bus_intr[14] */ + <0xff 108>, /* smmu_bus_intr[36] */ + <0xff 109>, /* smmu_bus_intr[37] */ + <0xff 112>, /* smmu_bus_intr[38] */ + <0xff 114>, /* qdsd_intr_out */ + <0xff 126>, /* smmu_bus_intr[39] */ + <0xff 128>, /* blsp1_peripheral_irq[3] */ + <0xff 129>, /* blsp1_peripheral_irq[4] */ + <0xff 131>, /* qup_irq */ + <0xff 136>, /* smmu_bus_intr[43] */ + <0xff 137>, /* smmu_intr_bus[44] */ + <0xff 138>, /* smmu_intr_bus[45] */ + <0xff 140>, /* uart_dm_intr */ + <0xff 141>, /* smmu_bus_intr[46] */ + <0xff 142>, /* smmu_bus_intr[47] */ + <0xff 143>, /* smmu_bus_intr[48] */ + <0xff 144>, /* smmu_bus_intr[49] */ + <0xff 145>, /* smmu_bus_intr[50] */ + <0xff 146>, /* smmu_bus_intr[51] */ + <0xff 147>, /* smmu_bus_intr[52] */ + <0xff 148>, /* smmu_bus_intr[53] */ + <0xff 149>, /* smmu_bus_intr[54] */ + <0xff 150>, /* smmu_bus_intr[55] */ + <0xff 151>, /* smmu_bus_intr[56] */ + <0xff 152>, /* smmu_bus_intr[57] */ + <0xff 153>, /* smmu_bus_intr[58] */ + <0xff 155>, /* sdc1_irq(0) */ + <0xff 157>, /* sdc2_irq(0) */ + <0xff 167>, /* bam_irq(0) */ + <0xff 170>, /* sdc1_pwr_cmd_irq */ + <0xff 173>, /* o_wcss_apss_smd_hi */ + <0xff 174>, /* o_wcss_apss_smd_med */ + <0xff 175>, /* o_wcss_apss_smd_low */ + <0xff 176>, /* o_wcss_apss_smsm_irq */ + <0xff 177>, /* o_wcss_apss_wlan_data_xfer_done */ + <0xff 178>, /* o_wcss_apss_wlan_rx_data_avail */ + <0xff 179>, /* o_wcss_apss_asic_intr */ + <0xff 181>, /* o_wcss_apss_wdog_bite_and_reset_rdy */ + <0xff 188>, /* lpass_irq_out_apcs(0) */ + <0xff 189>, /* lpass_irq_out_apcs(1) */ + <0xff 190>, /* lpass_irq_out_apcs(2) */ + <0xff 191>, /* lpass_irq_out_apcs(3) */ + <0xff 192>, /* lpass_irq_out_apcs(4) */ + <0xff 193>, /* lpass_irq_out_apcs(5) */ + <0xff 194>, /* lpass_irq_out_apcs(6) */ + <0xff 195>, /* lpass_irq_out_apcs(7) */ + <0xff 196>, /* lpass_irq_out_apcs(8) */ + <0xff 197>, /* lpass_irq_out_apcs(9) */ + <0xff 198>, /* coresight-tmc-etr interrupt */ + <0xff 200>, /* rpm_ipc(4) */ + <0xff 201>, /* rpm_ipc(5) */ + <0xff 202>, /* rpm_ipc(6) */ + <0xff 203>, /* rpm_ipc(7) */ + <0xff 204>, /* rpm_ipc(24) */ + <0xff 205>, /* rpm_ipc(25) */ + <0xff 206>, /* rpm_ipc(26) */ + <0xff 207>, /* rpm_ipc(27) */ + <0xff 215>, /* o_bimc_intr[0] */ + <0xff 224>, /* SPDM interrupt */ + <0xff 239>, /* crypto_bam_irq[1]*/ + <0xff 240>, /* summary_irq_kpss */ + <0xff 253>, /* sdcc_pwr_cmd_irq */ + <0xff 260>, /* ipa_irq[0] */ + <0xff 261>, /* ipa_irq[2] */ + <0xff 262>, /* ipa_bam_irq[0] */ + <0xff 263>, /* ipa_bam_irq[2] */ + <0xff 269>, /* rpm_wdog_expired_irq */ + <0xff 270>, /* blsp1_bam_irq[0] */ + <0xff 272>, /* smmu_intr_bus[17] */ + <0xff 273>, /* smmu_bus_intr[18] */ + <0xff 274>, /* smmu_bus_intr[19] */ + <0xff 275>, /* rpm_ipc(30) */ + <0xff 276>, /* rpm_ipc(31) */ + <0xff 277>, /* smmu_intr_bus[20] */ + <0xff 285>, /* smmu_bus_intr[28] */ + <0xff 286>, /* smmu_bus_intr[29] */ + <0xff 287>, /* smmu_bus_intr[30] */ + <0xff 321>, /* q6ss_irq_out(4) */ + <0xff 322>, /* q6ss_irq_out(5) */ + <0xff 323>, /* q6ss_irq_out(6) */ + <0xff 325>, /* q6ss_wdog_exp_irq */ + <0xff 344>; /* sdcc1ice */ + + qcom,gpio-parent = <&tlmm>; + qcom,gpio-map = <3 38 >, + <4 1 >, + <5 5 >, + <6 9 >, + <8 37>, + <9 36>, + <10 13>, + <11 35>, + <12 17>, + <13 21>, + <14 54>, + <15 34>, + <16 31>, + <17 58>, + <18 28>, + <19 42>, + <20 25>, + <21 12>, + <22 43>, + <23 44>, + <24 45>, + <25 46>, + <26 48>, + <27 65>, + <28 93>, + <29 97>, + <30 63>, + <31 70>, + <32 71>, + <33 72>, + <34 81>, + <35 126>, + <36 90>, + <37 128>, + <38 91>, + <39 41>, + <40 127>, + <41 86>, + <50 67>, + <51 73>, + <52 74>, + <53 62>, + <54 124>, + <55 61>, + <56 130>, + <57 59>, + <59 50>; + }; + qcom,cpu-sleep-status { compatible = "qcom,cpu-sleep-status"; }; + + qcom,rpm-log@29dc00 { + compatible = "qcom,rpm-log"; + reg = <0x29dc00 0x4000>; + qcom,rpm-addr-phys = <0x200000>; + qcom,offset-version = <4>; + qcom,offset-page-buffer-addr = <36>; + qcom,offset-log-len = <40>; + qcom,offset-log-len-mask = <44>; + qcom,offset-page-indices = <56>; + }; + + qcom,rpm-stats@29dba0 { + compatible = "qcom,rpm-stats"; + reg = <0x200000 0x1000>, + <0x290014 0x4>, + <0x29001c 0x4>; + reg-names = "phys_addr_base", "offset_addr", + "heap_phys_addrbase"; + qcom,sleep-stats-version = <2>; + }; + + qcom,rpm-master-stats@60150 { + compatible = "qcom,rpm-master-stats"; + reg = <0x60150 0x5000>; + qcom,masters = "APSS", "MPSS", "PRONTO", "TZ", "LPASS"; + qcom,master-stats-version = <2>; + qcom,master-offset = <4096>; + }; }; diff --git a/arch/arm64/boot/dts/qcom/msm8917.dtsi b/arch/arm64/boot/dts/qcom/msm8917.dtsi index 36db486b8de8..a28511085c83 100644 --- a/arch/arm64/boot/dts/qcom/msm8917.dtsi +++ b/arch/arm64/boot/dts/qcom/msm8917.dtsi @@ -161,6 +161,7 @@ #include "msm8917-pm.dtsi" #include "msm8917-ion.dtsi" #include "msm8917-smp2p.dtsi" +#include "msm8917-coresight.dtsi" #include "msm8917-bus.dtsi" #include "msm8917-mdss.dtsi" #include "msm8917-mdss-pll.dtsi" @@ -183,6 +184,18 @@ <0x0b002000 0x1000>; }; + dcc: dcc@b3000 { + compatible = "qcom,dcc"; + reg = <0xb3000 0x1000>, + <0xb4000 0x2000>; + reg-names = "dcc-base", "dcc-ram-base"; + + clocks = <&clock_gcc clk_gcc_dcc_clk>; + clock-names = "apb_pclk"; + + qcom,save-reg; + }; + wakegic: wake-gic { compatible = "qcom,mpm-gic", "qcom,mpm-gic-msm8937"; interrupts = ; @@ -482,6 +495,23 @@ #clock-cells = <1>; }; + msm_cpufreq: qcom,msm-cpufreq { + compatible = "qcom,msm-cpufreq"; + clock-names = "cpu0_clk", "cpu1_clk", "cpu2_clk", + "cpu3_clk"; + clocks = <&clock_cpu clk_a53_bc_clk>, + <&clock_cpu clk_a53_bc_clk>, + <&clock_cpu clk_a53_bc_clk>, + <&clock_cpu clk_a53_bc_clk>; + + qcom,cpufreq-table = + < 960000 >, + < 1094400 >, + < 1248000 >, + < 1401000 >, + < 1497600 >; + }; + i2c_2: i2c@78b6000 { /* BLSP1 QUP2 */ compatible = "qcom,i2c-msm-v2"; #address-cells = <1>; @@ -713,6 +743,24 @@ qcom,target-dev = <&cpubw>; }; + devfreq-cpufreq { + cpubw-cpufreq { + target-dev = <&cpubw>; + cpu-to-dev-map = + < 998400 4248 >, + < 1094400 4541 >, + < 1497600 5645 >; + }; + + mincpubw-cpufreq { + target-dev = <&mincpubw>; + cpu-to-dev-map = + < 998400 2270 >, + < 1094400 4248 >, + < 1497600 4248 >; + }; + }; + qcom,wdt@b017000 { compatible = "qcom,msm-watchdog"; reg = <0xb017000 0x1000>; @@ -724,6 +772,32 @@ qcom,wakeup-enable; }; + qcom,memshare { + compatible = "qcom,memshare"; + + qcom,client_1 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x200000>; + qcom,client-id = <0>; + qcom,allocate-boot-time; + label = "modem"; + }; + + qcom,client_2 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x300000>; + qcom,client-id = <2>; + label = "modem"; + }; + + mem_client_3_size: qcom,client_3 { + compatible = "qcom,memshare-peripheral"; + qcom,peripheral-size = <0x0>; + qcom,client-id = <1>; + label = "modem"; + }; + }; + spmi_bus: qcom,spmi@200f000 { compatible = "qcom,spmi-pmic-arb"; reg = <0x200f000 0x1000>, @@ -782,6 +856,64 @@ }; + jtag_fuse: jtagfuse@a601c { + compatible = "qcom,jtag-fuse-v2"; + reg = <0xa601c 0x8>; + reg-names = "fuse-base"; + }; + + jtag_mm0: jtagmm@61bc000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bc000 0x1000>, + <0x61b0000 0x1000>; + reg-names = "etm-base", "debug-base"; + + qcom,coresight-jtagmm-cpu = <&CPU0>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk", "core_a_clk"; + }; + + jtag_mm1: jtagmm@61bd000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bd000 0x1000>, + <0x61b2000 0x1000>; + reg-names = "etm-base", "debug-base"; + + qcom,coresight-jtagmm-cpu = <&CPU1>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk", "core_a_clk"; + }; + + jtag_mm2: jtagmm@61be000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61be000 0x1000>, + <0x61b4000 0x1000>; + reg-names = "etm-base", "debug-base"; + + qcom,coresight-jtagmm-cpu = <&CPU2>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk", "core_a_clk"; + }; + + jtag_mm3: jtagmm@61bf000 { + compatible = "qcom,jtagv8-mm"; + reg = <0x61bf000 0x1000>, + <0x61b6000 0x1000>; + reg-names = "etm-base", "debug-base"; + + qcom,coresight-jtagmm-cpu = <&CPU3>; + + clocks = <&clock_gcc clk_qdss_clk>, + <&clock_gcc clk_qdss_a_clk>; + clock-names = "core_clk", "core_a_clk"; + }; + qcom,ipc-spinlock@1905000 { compatible = "qcom,ipc-spinlock-sfpb"; reg = <0x1905000 0x8000>; @@ -1141,6 +1273,10 @@ qcom,ce-opp-freq = <100000000>; }; + qcom,iris-fm { + compatible = "qcom,iris_fm"; + }; + qcom,mss@4080000 { compatible = "qcom,pil-q6v55-mss"; reg = <0x04080000 0x100>, -- GitLab From da05f3bf8a190b7cba7dcb0c59229ae4ac20a0ca Mon Sep 17 00:00:00 2001 From: Swetha Chikkaboraiah Date: Wed, 9 May 2018 11:14:36 +0530 Subject: [PATCH 1829/1834] ARM: dts: msm: add device tree support for 8917 Add device tree support for msm8917 and apq8017 using pmi8950/pmi8937/pmi8940. This implementation is based on snapshot of the msm8917 device tree from msm-3.18 commit 1e588c1cbd492 ("ARM: dts: msm: Add msmgold CDP, MTP and RCM device tree files"). Change-Id: Ia198e5a1a4510882f68f5d3ba05336f4238b552b Signed-off-by: Swetha Chikkaboraiah --- arch/arm64/boot/dts/qcom/Makefile | 16 +- arch/arm64/boot/dts/qcom/apq8017-audio.dtsi | 345 ++++++++++++++++++ .../dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts | 98 +++++ .../boot/dts/qcom/apq8017-pmi8937-cdp.dts | 25 ++ .../boot/dts/qcom/apq8017-pmi8937-mtp.dts | 45 +++ .../dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts | 309 ++++++++++++++++ .../qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi | 52 +++ .../boot/dts/qcom/apq8017-pmi8950-cdp.dts | 31 ++ .../boot/dts/qcom/apq8017-pmi8950-mtp.dts | 81 ++++ arch/arm64/boot/dts/qcom/apq8017-rome.dtsi | 33 ++ arch/arm64/boot/dts/qcom/apq8017.dtsi | 77 ++++ .../boot/dts/qcom/msm8917-audio-cdp.dtsi | 32 ++ .../qcom/msm8917-cdp-mirror-lake-touch.dtsi | 250 +++++++++++++ arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi | 205 +++++++++++ .../boot/dts/qcom/msm8917-pmi8937-cdp.dts | 25 ++ .../boot/dts/qcom/msm8917-pmi8937-rcm.dts | 25 ++ .../boot/dts/qcom/msm8917-pmi8940-cdp.dts | 25 ++ .../boot/dts/qcom/msm8917-pmi8940-rcm.dts | 25 ++ .../msm8917-pmi8950-cdp-mirror-lake-touch.dts | 24 ++ ...msm8917-pmi8950-cdp-mirror-lake-touch.dtsi | 104 ++++++ .../boot/dts/qcom/msm8917-pmi8950-cdp.dts | 25 ++ .../qcom/msm8917-pmi8950-ext-codec-cdp.dts | 83 +++++ .../boot/dts/qcom/msm8917-pmi8950-mtp.dts | 23 +- .../boot/dts/qcom/msm8917-pmi8950-rcm.dts | 25 ++ arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi | 24 ++ 25 files changed, 2005 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/boot/dts/qcom/apq8017-audio.dtsi create mode 100644 arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi create mode 100644 arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts create mode 100644 arch/arm64/boot/dts/qcom/apq8017-rome.dtsi create mode 100644 arch/arm64/boot/dts/qcom/apq8017.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts create mode 100644 arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index 31d4b0d5bc0f..98cefbacd664 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -414,9 +414,23 @@ dtb-$(CONFIG_ARCH_MSM8937) += msm8937-pmi8950-mtp.dtb \ msm8937-interposer-sdm429-mtp.dtb dtb-$(CONFIG_ARCH_MSM8917) += msm8917-pmi8950-mtp.dtb \ + msm8917-pmi8950-cdp.dtb \ + msm8917-pmi8950-rcm.dtb \ + msm8917-pmi8950-ext-codec-cdp.dtb \ + msm8917-pmi8950-cdp-mirror-lake-touch.dtb \ + apq8017-pmi8950-cdp-wcd-rome.dtb \ + apq8017-pmi8950-mtp.dtb \ + apq8017-pmi8950-cdp.dtb \ msm8917-pmi8937-qrd-sku5.dtb \ + msm8917-pmi8937-mtp.dtb \ + msm8917-pmi8937-cdp.dtb \ + msm8917-pmi8937-rcm.dtb \ + apq8017-pmi8937-mtp.dtb \ + apq8017-pmi8937-cdp.dtb \ + apq8017-pmi8937-cdp-wcd-rome.dtb \ msm8917-pmi8940-mtp.dtb \ - msm8917-pmi8937-mtp.dtb + msm8917-pmi8940-cdp.dtb \ + msm8917-pmi8940-rcm.dtb dtb-$(CONFIG_ARCH_MSM8909) += msm8909w-bg-wtp-v2.dtb \ apq8009w-bg-wtp-v2.dtb \ diff --git a/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi b/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi new file mode 100644 index 000000000000..56f69ad66320 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-audio.dtsi @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&wsa881x_211 { + qcom,spkr-sd-n-gpio = <&tlmm 92 0>; +}; + +&wsa881x_212 { + qcom,spkr-sd-n-gpio = <&tlmm 92 0>; +}; + +&wsa881x_213 { + qcom,spkr-sd-n-gpio = <&tlmm 92 0>; +}; + +&wsa881x_214 { + qcom,spkr-sd-n-gpio = <&tlmm 92 0>; +}; + +&pm8937_gpios { + gpio@c000 { + status = "ok"; + qcom,mode = <1>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,src-sel = <2>; + qcom,master-en = <1>; + qcom,out-strength = <2>; + }; + + gpio@c600 { + status = "ok"; + qcom,mode = <1>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,src-sel = <0>; + qcom,master-en = <1>; + qcom,out-strength = <2>; + }; +}; + +&slim_msm { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; + +&wcd9335 { + status = "okay"; + cdc-vdd-mic-bias-supply = <&pm8937_l9>; + qcom,cdc-vdd-mic-bias-voltage = <3300000 3300000>; + qcom,cdc-vdd-mic-bias-current = <15000>; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; + qcom,msm-mbhc-hphl-swh = <1>; + qcom,msm-mbhc-gnd-swh = <1>; + qcom,tdm-audio-intf; + qcom,afe-rxtx-lb; + reg = <0xc051000 0x4>, + <0xc051004 0x4>, + <0xc055000 0x4>, + <0xc052000 0x4>, + <0x0c056000 0x4>, + <0x0c054000 0x4>, + <0x0c053000 0x4>; + reg-names = "csr_gp_io_mux_mic_ctl", + "csr_gp_io_mux_spkr_ctl", + "csr_gp_io_lpaif_pri_pcm_pri_mode_muxsel", + "csr_gp_io_mux_quin_ctl", + "csr_gp_io_lpaif_qui_pcm_sec_mode_muxsel", + "csr_gp_io_mux_mic_ext_clk_ctl", + "csr_gp_io_mux_sec_tlmm_ctl"; + qcom,audio-routing = + "AIF4 VI", "MCLK", + "AIF4 VI", "MICBIAS_REGULATOR", + "RX_BIAS", "MCLK", + "BRIDGE RX OUT", "MCLK", + "BRIDGE TX IN", "MCLK", + "MADINPUT", "MCLK", + "AIF4 MAD", "MICBIAS_REGULATOR", + "AMIC1", "MIC BIAS3", + "MIC BIAS3", "Handset Mic", + "AMIC2", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "Secondary Mic", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "Analog Mic4", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic7", + "AMIC6", "MIC BIAS4", + "MIC BIAS4", "Analog Mic6", + "DMIC0", "MIC BIAS1", + "MIC BIAS1", "Digital Mic0", + "DMIC1", "MIC BIAS1", + "MIC BIAS1", "Digital Mic1", + "DMIC2", "MIC BIAS3", + "MIC BIAS3", "Digital Mic2", + "DMIC3", "MIC BIAS3", + "MIC BIAS3", "Digital Mic3", + "DMIC4", "MIC BIAS4", + "MIC BIAS4", "Digital Mic4", + "DMIC5", "MIC BIAS4", + "MIC BIAS4", "Digital Mic5", + "MIC BIAS3", "MICBIAS_REGULATOR", + "MIC BIAS4", "MICBIAS_REGULATOR", + "SpkrLeft IN", "SPK1 OUT", + "SpkrRight IN", "SPK2 OUT"; + asoc-cpu = <&dai_pri_auxpcm>, + <&dai_mi2s2>, <&dai_mi2s3>, <&dai_mi2s5>, + <&sb_0_rx>, <&sb_0_tx>, <&sb_1_rx>, <&sb_1_tx>, + <&sb_2_rx>, <&sb_2_tx>, <&sb_3_rx>, <&sb_3_tx>, + <&sb_4_rx>, <&sb_4_tx>, <&sb_5_tx>, + <&afe_pcm_rx>, <&afe_pcm_tx>, + <&afe_proxy_rx>, <&afe_proxy_tx>, + <&incall_record_rx>, <&incall_record_tx>, + <&incall_music_rx>, <&incall_music_2_rx>, + <&sb_5_rx>, <&bt_sco_rx>, + <&bt_sco_tx>, <&int_fm_rx>, <&int_fm_tx>, + <&sb_6_rx>, <&dai_pri_tdm_rx_0>, <&dai_pri_tdm_tx_0>, + <&dai_sec_tdm_rx_0>, <&dai_sec_tdm_tx_0>, <&afe_loopback_tx>; + asoc-cpu-names = "msm-dai-q6-auxpcm.1", + "msm-dai-q6-mi2s.2", + "msm-dai-q6-mi2s.3", "msm-dai-q6-mi2s.5", + "msm-dai-q6-dev.16384", "msm-dai-q6-dev.16385", + "msm-dai-q6-dev.16386", "msm-dai-q6-dev.16387", + "msm-dai-q6-dev.16388", "msm-dai-q6-dev.16389", + "msm-dai-q6-dev.16390", "msm-dai-q6-dev.16391", + "msm-dai-q6-dev.16392", "msm-dai-q6-dev.16393", + "msm-dai-q6-dev.16395", "msm-dai-q6-dev.224", + "msm-dai-q6-dev.225", "msm-dai-q6-dev.241", + "msm-dai-q6-dev.240", "msm-dai-q6-dev.32771", + "msm-dai-q6-dev.32772", "msm-dai-q6-dev.32773", + "msm-dai-q6-dev.32770", "msm-dai-q6-dev.16394", + "msm-dai-q6-dev.12288", "msm-dai-q6-dev.12289", + "msm-dai-q6-dev.12292", "msm-dai-q6-dev.12293", + "msm-dai-q6-dev.16396", "msm-dai-q6-tdm.36864", + "msm-dai-q6-tdm.36865", "msm-dai-q6-tdm.36880", + "msm-dai-q6-tdm.36881", "msm-dai-q6-dev.24577"; + qcom,msm-gpios = + "quin_i2s", + "us_eu_gpio", + "quat_i2s"; + qcom,pinctrl-names = + "all_off", + "quin_i2s_act", + "us_eu_gpio_act", + "quin_i2s_us_eu_gpio_act", + "quat_i2s_act", + "quat_i2s_quin_i2s_act", + "quat_i2s_us_eu_gpio_act", + "quat_i2s_us_eu_gpio_quin_i2s_act"; + pinctrl-names = + "all_off", + "quin_i2s_act", + "us_eu_gpio_act", + "quin_i2s_us_eu_gpio_act", + "quat_i2s_act", + "quat_i2s_quin_i2s_act", + "quat_i2s_us_eu_gpio_act", + "quat_i2s_us_eu_gpio_quin_i2s_act"; + + pinctrl-0 = <&pri_tlmm_ws_sus + &cross_conn_det_sus &pri_mi2s_sd0_sleep + &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep + &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep + &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>; + pinctrl-1 = <&pri_tlmm_ws_act + &cross_conn_det_sus &pri_mi2s_sd0_active + &pri_mi2s_sck_active &pri_mi2s_sd1_active + &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep + &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>; + pinctrl-2 = <&pri_tlmm_ws_sus + &cross_conn_det_act &pri_mi2s_sd0_sleep + &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep + &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep + &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>; + pinctrl-3 = <&pri_tlmm_ws_act + &cross_conn_det_act &pri_mi2s_sd0_active + &pri_mi2s_sck_active &pri_mi2s_sd1_active + &sec_mi2s_ws_sleep &sec_mi2s_sck_sleep + &sec_mi2s_sd1_sleep &sec_mi2s_sd0_sleep>; + pinctrl-4 = <&pri_tlmm_ws_sus + &cross_conn_det_sus &pri_mi2s_sd0_sleep + &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep + &sec_mi2s_ws_active &sec_mi2s_sck_active + &sec_mi2s_sd1_active &sec_mi2s_sd0_active>; + pinctrl-5 = <&pri_tlmm_ws_act + &cross_conn_det_sus &pri_mi2s_sd0_active + &pri_mi2s_sck_active &pri_mi2s_sd1_active + &sec_mi2s_ws_active &sec_mi2s_sck_active + &sec_mi2s_sd1_active &sec_mi2s_sd0_active>; + pinctrl-6 = <&pri_tlmm_ws_sus + &cross_conn_det_act &pri_mi2s_sd0_sleep + &pri_mi2s_sck_sleep &pri_mi2s_sd1_sleep + &sec_mi2s_ws_active &sec_mi2s_sck_active + &sec_mi2s_sd1_active &sec_mi2s_sd0_active>; + pinctrl-7 = <&pri_tlmm_ws_act + &cross_conn_det_act &pri_mi2s_sd0_active + &pri_mi2s_sck_active &pri_mi2s_sd1_active + &sec_mi2s_ws_active &sec_mi2s_sck_active + &sec_mi2s_sd1_active &sec_mi2s_sd0_active>; +}; + +&int_codec { + status = "disabled"; +}; + +&wsa881x_i2c_f { + status = "disabled"; +}; + +&wsa881x_i2c_45 { + status = "disabled"; +}; + +&soc { + qcom,msm-dai-tdm-pri-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37120>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36864>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_rx_0: qcom,msm-dai-q6-tdm-pri-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36864>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-pri-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37121>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36865>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_pri_tdm_tx_0: qcom,msm-dai-q6-tdm-pri-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36865>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-rx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37136>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36880>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_sec_tdm_rx_0: qcom,msm-dai-q6-tdm-sec-rx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36880>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; + + qcom,msm-dai-tdm-sec-tx { + compatible = "qcom,msm-dai-tdm"; + qcom,msm-cpudai-tdm-group-id = <37137>; + qcom,msm-cpudai-tdm-group-num-ports = <1>; + qcom,msm-cpudai-tdm-group-port-id = <36881>; + qcom,msm-cpudai-tdm-clk-rate = <12288000>; + qcom,msm-cpudai-tdm-clk-attribute = /bits/ 16 <1>; + dai_sec_tdm_tx_0: qcom,msm-dai-q6-tdm-sec-tx-0 { + compatible = "qcom,msm-dai-q6-tdm"; + qcom,msm-cpudai-tdm-dev-id = <36881>; + qcom,msm-cpudai-tdm-sync-mode = <0>; + qcom,msm-cpudai-tdm-sync-src = <1>; + qcom,msm-cpudai-tdm-data-out = <0>; + qcom,msm-cpudai-tdm-invert-sync = <0>; + qcom,msm-cpudai-tdm-data-delay = <1>; + qcom,msm-cpudai-tdm-data-align = <0>; + }; + }; +}; + +&dai_pri_auxpcm { + qcom,msm-cpudai-afe-clk-ver = <2>; +}; + +&tlmm { + tlmm_gpio_key { + gpio_key_active: gpio_key_active { + mux { + pins = "gpio91", "gpio127", "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio91", "gpio127", "gpio128"; + }; + }; + + gpio_key_suspend: gpio_key_suspend { + mux { + pins = "gpio91", "gpio127", "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio91", "gpio127", "gpio128"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts new file mode 100644 index 000000000000..19c24f8e3086 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp-wcd-rome.dts @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8017.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8937.dtsi" +#include "apq8017-rome.dtsi" +#include "apq8017-audio.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 CDP \ + with WCD codec/Rome card"; + compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp"; + qcom,board-id= <1 2>; + qcom,pmic-id = <0x10019 0x020037 0x0 0x0>; +}; + +&blsp1_uart1 { + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + /delete-property/vdd-supply; + /delete-property/qcom,vdd-voltage-level; + /delete-property/qcom,vdd-current-level; + + /* device communication power supply */ + vdd-io-supply = <&pm8937_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + qcom,core_3_0v_support; + qcom,nonremovable; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_active>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_sleep>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &tlmm 124 0x4>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + /delete-property/cd-gpios; + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; + +}; + +&mdss_fb0 { + /delete-node/ qcom,cont-splash-memory; +}; + +/delete-node/ &cont_splash_mem; + +&soc { + gpio_keys { + /delete-node/ home; + }; +}; + +&modem_mem { + reg = <0x0 0x86800000 0x0 0x1500000>; +}; + +&adsp_fw_mem { + reg = <0x0 0x87d00000 0x0 0x1100000>; +}; + +&wcnss_fw_mem { + reg = <0x0 0x88e00000 0x0 0x700000>; +}; + +&secure_mem { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts new file mode 100644 index 000000000000..6faa41317cdf --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-cdp.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8017.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 CDP"; + compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x10019 0x020037 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts new file mode 100644 index 000000000000..01305e6bfa49 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8937-mtp.dts @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8017.dtsi" +#include "msm8917-mtp.dtsi" +#include "msm8917-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8017-PMI8937 MTP"; + compatible = "qcom,apq8017-mtp", "qcom,apq8017", "qcom,mtp"; + qcom,board-id= <8 0>; + qcom,pmic-id = <0x10019 0x020037 0x0 0x0>; +}; + +&blsp1_uart1 { + status = "ok"; +}; + +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "batterydata-itech-3000mah.dtsi" + #include "batterydata-ascent-3450mAh.dtsi" + }; +}; + +&qpnp_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&qpnp_smbcharger { + qcom,battery-data = <&mtp_batterydata>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts new file mode 100644 index 000000000000..8ddb1fcc2a0e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dts @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8017.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8950.dtsi" +#include "apq8017-rome.dtsi" +#include "apq8017-audio.dtsi" +#include "apq8017-pmi8950-cdp-wcd-rome.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP \ + with WCD codec/Rome card"; + compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp"; + qcom,board-id= <1 2>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; +}; + +&blsp1_uart1 { + status = "ok"; +}; + +&wcd9335 { + qcom,cdc-mic-unmute-delay = <50>; +}; + +&sdhc_2 { + /* device core power supply */ + /delete-property/vdd-supply; + /delete-property/qcom,vdd-voltage-level; + /delete-property/qcom,vdd-current-level; + + /* device communication power supply */ + vdd-io-supply = <&pm8937_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + qcom,core_3_0v_support; + qcom,nonremovable; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on + &sdc2_wlan_gpio_active>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off + &sdc2_wlan_gpio_sleep>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &tlmm 124 0x4>; + interrupt-names = "hc_irq", "pwr_irq", "sdiowakeup_irq"; + + /delete-property/cd-gpios; + /delete-property/qcom,devfreq,freq-table; + + status = "ok"; + +}; + +&mdss_fb0 { + /delete-node/ qcom,cont-splash-memory; +}; + +/delete-node/ &cont_splash_mem; + +&soc { + gpio_keys { + /delete-node/ home; + }; +}; + +&usb_otg { + vbus_otg-supply = <0>; + qcom,vbus-low-as-hostmode; +}; + +&i2c_4 { + usb2533@2c { + status = "ok"; + }; +}; + +&i2c_2 { + /* DSI_TO_HDMI I2C configuration */ + adv7533@39 { + compatible = "adv7533"; + reg = <0x39>; + instance_id = <0>; + adi,video-mode = <3>; /* 3 = 1080p */ + adi,main-addr = <0x39>; + adi,cec-dsi-addr = <0x3C>; + adi,enable-audio; + adi,irq-gpio = <&tlmm 0x29 0x2002>; + adi,power-down-gpio = <&tlmm 0x7D 0x0>; + adi,switch-gpio = <&pm8937_gpios 0x8 0x1>; + pinctrl-names = "pmx_adv7533_active", + "pmx_adv7533_suspend"; + pinctrl-0 = <&adv7533_int_active>; + pinctrl-1 = <&adv7533_int_suspend>; + }; + + pericom-type-c@1d { + status = "disabled"; + }; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>; + qcom,platform-intf-mux-gpio = <&tlmm 115 0>; + status = "ok"; + qcom,bridge-index = <0>; + qcom,pluggable; +}; + +&dsi_adv7533_1080p { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; + +&modem_mem { + reg = <0x0 0x86800000 0x0 0x1500000>; +}; + +&adsp_fw_mem { + reg = <0x0 0x87d00000 0x0 0x1100000>; +}; + +&wcnss_fw_mem { + reg = <0x0 0x88e00000 0x0 0x700000>; +}; + +&other_ext_mem { + reg = <0x0 0x84f00000 0x0 0x1900000>; +}; + +&qcom_seecom { + reg = <0x84f00000 0x1400000>; +}; + +&secure_mem { + status = "disabled"; +}; + +/* Warning, SPI6 & I2C6 cannot be enabled at the same time due to pin usage. */ +&spi_6 { + status = "disabled"; +}; + +&i2c_6 { + status = "ok"; + qcom,clk-freq-out = <100000>; + + /* TI591XX LED Drivers */ + tlc59116@60 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tlc59116"; + reg = <0x60>; + out0@0 { + label = "ledsec1_g"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec1_r"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec1_b"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec2_g"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec2_r"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec2_b"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec3_g"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec3_r"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec3_b"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec4_g"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec4_r"; + reg = <0xa>; + }; + out11@11 { + label = "ledsec4_b"; + reg = <0xb>; + }; + out12@12 { + label = "ledsec5_g"; + reg = <0xc>; + }; + out13@13 { + label = "ledsec5_r"; + reg = <0xd>; + }; + out14@14 { + label = "ledsec5_b"; + reg = <0xe>; + }; + }; + + tlc59116@61 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "ti,tlc59116"; + reg = <0x61>; + out0@0 { + label = "ledsec6_g"; + reg = <0x0>; + }; + out1@1 { + label = "ledsec6_r"; + reg = <0x1>; + }; + out2@2 { + label = "ledsec6_b"; + reg = <0x2>; + }; + out3@3 { + label = "ledsec7_g"; + reg = <0x3>; + }; + out4@4 { + label = "ledsec7_r"; + reg = <0x4>; + }; + out5@5 { + label = "ledsec7_b"; + reg = <0x5>; + }; + out6@6 { + label = "ledsec8_g"; + reg = <0x6>; + }; + out7@7 { + label = "ledsec8_r"; + reg = <0x7>; + }; + out8@8 { + label = "ledsec8_b"; + reg = <0x8>; + }; + out9@9 { + label = "ledsec9_g"; + reg = <0x9>; + }; + out10@10 { + label = "ledsec9_r"; + reg = <0xa>; + }; + out11@11 { + label = "ledsec9_b"; + reg = <0xb>; + }; + }; +}; + +&soc { + pinctrl@1000000 { + i2c6{ + tlc59116_reset: tlc59116_reset { + config { + pins = "gpio20"; + drive-strength = <16>; + bias-pull-up; + }; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi new file mode 100644 index 000000000000..3337add3fae7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp-wcd-rome.dtsi @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/ { + model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP \ + with WCD codec/Rome card"; + compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp"; + qcom,board-id= <1 2>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; + + aliases { + i2c6 = &i2c_6; + }; +}; + +&soc { + i2c_6: i2c@7af6000 { /* BLSP2 QUP2 */ + compatible = "qcom,i2c-msm-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg-names = "qup_phys_addr"; + reg = <0x7af6000 0x600>; + interrupt-names = "qup_irq"; + interrupts = <0 300 0>; + qcom,clk-freq-out = <400000>; + qcom,clk-freq-in = <19200000>; + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp2_ahb_clk>, + <&clock_gcc clk_gcc_blsp2_qup2_i2c_apps_clk>; + + pinctrl-names = "i2c_active", "i2c_sleep"; + pinctrl-0 = <&i2c_6_active>; + pinctrl-1 = <&i2c_6_sleep>; + qcom,noise-rjct-scl = <0>; + qcom,noise-rjct-sda = <0>; + qcom,master-id = <84>; + dmas = <&dma_blsp2 6 64 0x20000020 0x20>, + <&dma_blsp2 7 32 0x20000020 0x20>; + dma-names = "tx", "rx"; + status = "disabled"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts new file mode 100644 index 000000000000..5c8ef83f5ae6 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-cdp.dts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8017.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 CDP"; + compatible = "qcom,apq8017-cdp", "qcom,apq8017", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; +}; + +&mdss_fb0 { + /delete-node/ qcom,cont-splash-memory; +}; + +/delete-node/ &cont_splash_mem; diff --git a/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts new file mode 100644 index 000000000000..b5b766769fc7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-pmi8950-mtp.dts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "apq8017.dtsi" +#include "msm8917-mtp.dtsi" +#include "msm8917-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. APQ8017-PMI8950 MTP"; + compatible = "qcom,apq8017-mtp", "qcom,apq8017", "qcom,mtp"; + qcom,board-id= <8 0>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; +}; + +&blsp1_uart1 { + status = "ok"; +}; + +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "batterydata-itech-3000mah.dtsi" + #include "batterydata-ascent-3450mAh.dtsi" + }; +}; + +&qpnp_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&qpnp_smbcharger { + qcom,battery-data = <&mtp_batterydata>; +}; + +&i2c_2 { + /* DSI_TO_HDMI I2C configuration */ + adv7533@39 { + compatible = "adv7533"; + reg = <0x39>; + instance_id = <0>; + adi,video-mode = <3>; /* 3 = 1080p */ + adi,main-addr = <0x39>; + adi,cec-dsi-addr = <0x3C>; + adi,enable-audio; + adi,irq-gpio = <&tlmm 0x29 0x2002>; + adi,power-down-gpio = <&tlmm 0x7D 0x0>; + adi,switch-gpio = <&pm8937_gpios 0x8 0x1>; + pinctrl-names = "pmx_adv7533_active", + "pmx_adv7533_suspend"; + pinctrl-0 = <&adv7533_int_active>; + pinctrl-1 = <&adv7533_int_suspend>; + }; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_adv7533_1080p>; + qcom,platform-intf-mux-gpio = <&tlmm 115 0>; + status = "ok"; + qcom,bridge-index = <0>; + qcom,pluggable; +}; + +&dsi_adv7533_1080p { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi b/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi new file mode 100644 index 000000000000..7dfa95271184 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017-rome.dtsi @@ -0,0 +1,33 @@ +/* + * copyright (c) 2016-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&soc { + qcom,cnss_sdio { + compatible = "qcom,cnss_sdio"; + qcom,wlan-ramdump-dynamic = <0x200000>; + subsys-name = "AR6320"; + qcom,cap-tsf-gpio = <&tlmm 126 1>; + }; +}; + +&pm8937_gpios { + gpio@c100 { /* GPIO 2 - Rome Sleep Clock */ + qcom,mode = <1>; /* Digital output */ + qcom,vin-sel = <3>; /* VIN 3 */ + qcom,src-sel = <2>; /* Function 2 */ + qcom,out-strength = <2>; /* Medium */ + qcom,pull = <4>; + qcom,master-en = <1>; /* Enable GPIO */ + status = "okay"; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/apq8017.dtsi b/arch/arm64/boot/dts/qcom/apq8017.dtsi new file mode 100644 index 000000000000..fecc7ce8d08f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/apq8017.dtsi @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm8917.dtsi" +/ { + model = "Qualcomm Technologies, Inc. APQ8017"; + compatible = "qcom,apq8017"; + qcom,msm-id = <307 0x0>; +}; + +&tlmm { + pmx_adv7533_int: pmx_adv7533_int { + adv7533_int_active: adv7533_int_active { + mux { + pins = "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio41"; + function = "gpio"; + drive-strength = <16>; + bias-pull-up; /* pull up */ + }; + }; + + adv7533_int_suspend: adv7533_int_suspend { + mux { + pins = "gpio41"; + function = "gpio"; + }; + + config { + pins = "gpio41"; + drive-strength = <16>; + bias-disable; + }; + }; + }; +}; + +&mdss_dsi_active { + mux { + pins = "gpio60", "gpio98", "gpio115", "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio60", "gpio98", "gpio115", "gpio133"; + drive-strength = <8>; /* 8 mA */ + bias-disable = <0>; /* no pull */ + output-high; + }; +}; + +&mdss_dsi_suspend { + mux { + pins = "gpio60", "gpio98", "gpio115", "gpio133"; + function = "gpio"; + }; + + config { + pins = "gpio60", "gpio98", "gpio115", "gpio133"; + drive-strength = <2>; /* 2 mA */ + bias-pull-down; /* pull down */ + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi new file mode 100644 index 000000000000..465859aeab5f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-audio-cdp.dtsi @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +&int_codec { + status = "okay"; + qcom,msm-hs-micbias-type = "external"; + + asoc-wsa-codec-names = "wsa881x-i2c-codec.2-000f"; + asoc-wsa-codec-prefixes = "SpkrMono"; + + msm-vdd-wsa-switch-supply = <&pm8937_l13>; + qcom,msm-vdd-wsa-switch-voltage = <3075000>; + qcom,msm-vdd-wsa-switch-current = <5000>; +}; + +&wsa881x_i2c_f { + status = "okay"; +}; + +&wsa881x_i2c_45 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi new file mode 100644 index 000000000000..d6d85fa7fdea --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp-mirror-lake-touch.dtsi @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "msm8917-pinctrl.dtsi" +/* #include "msm8917-camera-sensor-cdp.dtsi"*/ + +&soc { + gpio_keys { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "tlmm_gpio_key_active", "tlmm_gpio_key_suspend"; + pinctrl-0 = <&gpio_key_active>; + pinctrl-1 = <&gpio_key_suspend>; + + camera_focus { + label = "camera_focus"; + gpios = <&tlmm 128 0x1>; + linux,input-type = <1>; + linux,code = <0x210>; + debounce-interval = <15>; + }; + + camera_snapshot { + label = "camera_snapshot"; + gpios = <&tlmm 127 0x1>; + linux,input-type = <1>; + linux,code = <0x2fe>; + debounce-interval = <15>; + }; + + vol_up { + label = "volume_up"; + gpios = <&tlmm 91 0x1>; + linux,input-type = <1>; + linux,code = <115>; + debounce-interval = <15>; + }; + + home { + label = "home"; + gpios = <&tlmm 86 0x1>; + linux,input-type = <1>; + linux,code = <102>; + debounce-interval = <15>; + }; + }; + + hbtp { + compatible = "qcom,hbtp-input"; + vcc_ana-supply = <&pm8937_l10>; + vcc_dig-supply = <&pm8937_l5>; + qcom,afe-load = <50000>; + qcom,afe-vtg-min = <2850000>; + qcom,afe-vtg-max = <2850000>; + qcom,dig-load = <15000>; + qcom,dig-vtg-min = <1800000>; + qcom,dig-vtg-max = <1800000>; + }; + + usb_detect { + compatible = "qcom,gpio-usbdetect"; + interrupt-names = "vbus_det_irq"; + interrupt-parent = <&tlmm>; + interrupts = <130 0>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_mode_select>; + qcom,gpio-mode-sel = <&tlmm 130 0>; + qcom,notify-host-mode; + status = "disabled"; + }; +}; + +&flash_led { + compatible = "qcom,qpnp-flash-led"; + reg = <0xd300 0x100>; + pinctrl-names = "flash_led_enable","flash_led_disable"; + pinctrl-0 = <&rear_flash_led_enable>; + pinctrl-1 = <&rear_flash_led_disable>; + qcom,follow-otst2-rb-disabled; +}; + +&wled { + qcom,cons-sync-write-delay-us = <1000>; +}; + +&pmi_haptic{ + qcom,actuator-type = "lra"; + qcom,wave-play-rate-us = <4165>; + qcom,lra-auto-res-mode = "qwd"; + qcom,lra-high-z = "opt1"; + qcom,lra-res-cal-period = <0>; +}; + +&blsp1_uart2 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +#include "msm8937-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_truly_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; + qcom,platform-bklight-en-gpio = <&tlmm 98 0>; +}; + +&dsi_truly_720_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; +}; + +&dsi_truly_720_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,ulps-enabled; + qcom,partial-update-enabled; + qcom,panel-roi-alignment = <2 2 2 2 2 2>; +}; + +&tlmm { + tlmm_gpio_key { + gpio_key_active: gpio_key_active { + mux { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + }; + }; + + gpio_key_suspend: gpio_key_suspend { + mux { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + }; + }; + }; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm8937_l8>; + qcom,vdd-voltage-level = <2900000 2900000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8937_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 + 384000000>; + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm8937_l11>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8937_l12>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &tlmm 67 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 67 0x1>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + status = "ok"; +}; + +&i2c_3 { + status = "okay"; + synaptics@22 { + compatible = "synaptics,dsx"; + reg = <0x22>; + interrupt-parent = <&tlmm>; + interrupts = <65 0x2008>; + avdd-supply = <&pm8937_l10>; + vdd-supply = <&pm8937_l5>; + synaptics,vdd-voltage = <1880000 1880000>; + synaptics,avdd-voltage = <3008000 3008000>; + synaptics,vdd-current = <40000>; + synaptics,avdd-current = <20000>; + pinctrl-names = "pmx_ts_active","pmx_ts_suspend"; + pinctrl-0 = <&ts_int_active &ts_reset_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + synaptics,display-coords = <0 0 719 1439>; + synaptics,panel-coords = <0 0 719 1439>; + synaptics,reset-gpio = <&tlmm 64 0x00>; + synaptics,irq-gpio = <&tlmm 65 0x2008>; + synaptics,disable-gpios; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi new file mode 100644 index 000000000000..fde4847f2a1f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-cdp.dtsi @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include "msm8917-pinctrl.dtsi" +/* #include "msm8917-camera-sensor-cdp.dtsi"*/ + +&soc { + gpio_keys { + compatible = "gpio-keys"; + input-name = "gpio-keys"; + pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend"; + pinctrl-0 = <&gpio_key_active>; + pinctrl-1 = <&gpio_key_suspend>; + + camera_focus { + label = "camera_focus"; + gpios = <&tlmm 128 0x1>; + linux,input-type = <1>; + linux,code = <0x210>; + debounce-interval = <15>; + }; + + camera_snapshot { + label = "camera_snapshot"; + gpios = <&tlmm 127 0x1>; + linux,input-type = <1>; + linux,code = <0x2fe>; + debounce-interval = <15>; + }; + + vol_up { + label = "volume_up"; + gpios = <&tlmm 91 0x1>; + linux,input-type = <1>; + linux,code = <115>; + debounce-interval = <15>; + }; + + home { + label = "home"; + gpios = <&tlmm 86 0x1>; + linux,input-type = <1>; + linux,code = <102>; + debounce-interval = <15>; + }; + }; + + hbtp { + compatible = "qcom,hbtp-input"; + vcc_ana-supply = <&pm8937_l10>; + vcc_dig-supply = <&pm8937_l5>; + qcom,afe-load = <50000>; + qcom,afe-vtg-min = <2850000>; + qcom,afe-vtg-max = <2850000>; + qcom,dig-load = <15000>; + qcom,dig-vtg-min = <1800000>; + qcom,dig-vtg-max = <1800000>; + }; + + usb_detect { + compatible = "qcom,gpio-usbdetect"; + interrupt-names = "vbus_det_irq"; + interrupt-parent = <&tlmm>; + interrupts = <130 0>; + pinctrl-names = "default"; + pinctrl-0 = <&usb_mode_select>; + qcom,gpio-mode-sel = <&tlmm 130 0>; + qcom,notify-host-mode; + status = "disabled"; + }; +}; + +&blsp1_uart2 { + status = "ok"; + pinctrl-names = "default"; + pinctrl-0 = <&uart_console_active>; +}; + +#include "msm8937-mdss-panels.dtsi" + +&mdss_mdp { + qcom,mdss-pref-prim-intf = "dsi"; +}; + +&mdss_dsi { + hw-config = "single_dsi"; +}; + +&mdss_dsi0 { + qcom,dsi-pref-prim-pan = <&dsi_truly_720_vid>; + pinctrl-names = "mdss_default", "mdss_sleep"; + pinctrl-0 = <&mdss_dsi_active &mdss_te_active>; + pinctrl-1 = <&mdss_dsi_suspend &mdss_te_suspend>; + + qcom,platform-te-gpio = <&tlmm 24 0>; + qcom,platform-reset-gpio = <&tlmm 60 0>; + qcom,platform-bklight-en-gpio = <&tlmm 98 0>; +}; + +&dsi_truly_720_vid { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,mdss-dsi-pan-enable-dynamic-fps; + qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; +}; + +&dsi_truly_720_cmd { + qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; + qcom,ulps-enabled; + qcom,partial-update-enabled; + qcom,panel-roi-alignment = <2 2 2 2 2 2>; +}; + +&tlmm { + tlmm_gpio_key { + gpio_key_active: gpio_key_active { + mux { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + }; + }; + + gpio_key_suspend: gpio_key_suspend { + mux { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + function = "gpio"; + }; + + config { + pins = "gpio86", "gpio91", "gpio127", "gpio128"; + }; + }; + }; +}; + +&sdhc_1 { + /* device core power supply */ + vdd-supply = <&pm8937_l8>; + qcom,vdd-voltage-level = <2900000 2900000>; + qcom,vdd-current-level = <200 570000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8937_l5>; + qcom,vdd-io-always-on; + qcom,vdd-io-lpm-sup; + qcom,vdd-io-voltage-level = <1800000 1800000>; + qcom,vdd-io-current-level = <200 325000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc1_clk_on &sdc1_cmd_on &sdc1_data_on &sdc1_rclk_on>; + pinctrl-1 = <&sdc1_clk_off &sdc1_cmd_off &sdc1_data_off &sdc1_rclk_off>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 192000000 + 384000000>; + qcom,nonremovable; + qcom,bus-speed-mode = "HS400_1p8v", "HS200_1p8v", "DDR_1p8v"; + + status = "ok"; +}; + +&sdhc_2 { + /* device core power supply */ + vdd-supply = <&pm8937_l11>; + qcom,vdd-voltage-level = <2950000 2950000>; + qcom,vdd-current-level = <15000 800000>; + + /* device communication power supply */ + vdd-io-supply = <&pm8937_l12>; + qcom,vdd-io-voltage-level = <1800000 2950000>; + qcom,vdd-io-current-level = <200 22000>; + + pinctrl-names = "active", "sleep"; + pinctrl-0 = <&sdc2_clk_on &sdc2_cmd_on &sdc2_data_on &sdc2_cd_on>; + pinctrl-1 = <&sdc2_clk_off &sdc2_cmd_off &sdc2_data_off>; + + #address-cells = <0>; + interrupt-parent = <&sdhc_2>; + interrupts = <0 1 2>; + #interrupt-cells = <1>; + interrupt-map-mask = <0xffffffff>; + interrupt-map = <0 &intc 0 125 0 + 1 &intc 0 221 0 + 2 &tlmm 67 0>; + interrupt-names = "hc_irq", "pwr_irq", "status_irq"; + cd-gpios = <&tlmm 67 0x1>; + + qcom,clk-rates = <400000 20000000 25000000 50000000 100000000 + 200000000>; + qcom,bus-speed-mode = "SDR12", "SDR25", "SDR50", "DDR50", "SDR104"; + + status = "ok"; +}; + diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts new file mode 100644 index 000000000000..9d8a2ebce6cb --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-cdp.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917-PMI8937 CDP"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x10019 0x020037 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts new file mode 100644 index 000000000000..c7fe1151dbb0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8937-rcm.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8937.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917-PMI8937 RCM"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id= <21 0>; + qcom,pmic-id = <0x10019 0x020037 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts new file mode 100644 index 000000000000..9785a4f8e7f4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-cdp.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8940.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917-PMI8940 CDP"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id = <1 0>; + qcom,pmic-id = <0x10019 0x020040 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts new file mode 100644 index 000000000000..2cab7160b5e7 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8940-rcm.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8940.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917-PMI8940 RCM"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id = <21 0>; + qcom,pmic-id = <0x10019 0x020040 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts new file mode 100644 index 000000000000..ea6b24a51bef --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dts @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-pmi8950-cdp-mirror-lake-touch.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 CDP ML Touch"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id = <1 4>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi new file mode 100644 index 000000000000..47011013e0f0 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp-mirror-lake-touch.dtsi @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "pmi8950.dtsi" +#include "msm8917-cdp-mirror-lake-touch.dtsi" +#include "msm8917-audio-cdp.dtsi" + +&soc { + led_flash0: qcom,camera-flash { + cell-index = <0>; + compatible = "qcom,camera-flash"; + qcom,flash-type = <1>; + qcom,flash-source = <&pmi8950_flash0 &pmi8950_flash1>; + qcom,torch-source = <&pmi8950_torch0 &pmi8950_torch1>; + qcom,switch-source = <&pmi8950_switch>; + }; + + bluetooth: bt_qca6174 { + compatible = "qca,qca6174"; + qca,bt-reset-gpio = <&tlmm 129 0>; /* BT_EN */ + }; +}; + +&qpnp_smbcharger { + /delete-property/ dpdm-supply; +}; + +&pm8937_gpios { + gpio@c400 { + qcom,mode = <0>; + qcom,output-type = <0>; + qcom,pull = <0>; + qcom,vin-sel = <2>; + qcom,out-strength = <3>; + qcom,src-sel = <0>; + qcom,master-en = <1>; + status = "okay"; + }; +}; + +&i2c_5 { /* BLSP2 QUP1 */ + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 17 0x00>; + qcom,nq-ven = <&tlmm 16 0x00>; + qcom,nq-firm = <&tlmm 130 0x00>; + qcom,nq-clkreq = <&pm8937_gpios 5 0x00>; + interrupt-parent = <&tlmm>; + qcom,clk-src = "BBCLK2"; + interrupts = <17 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_disable_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_disable_suspend>; + clocks = <&clock_gcc clk_bb_clk2_pin>; + clock-names = "ref_clk"; + }; +}; + +&mdss_dsi0 { + lab-supply = <&lab_regulator>; + ibb-supply = <&ibb_regulator>; +}; + +&labibb { + status = "ok"; + qpnp,qpnp-labibb-mode = "lcd"; +}; + +&ibb_regulator { + qcom,qpnp-ibb-discharge-resistor = <32>; +}; + +&dsi_panel_pwr_supply { + qcom,panel-supply-entry@2 { + reg = <2>; + qcom,supply-name = "lab"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + }; + + qcom,panel-supply-entry@3 { + reg = <3>; + qcom,supply-name = "ibb"; + qcom,supply-min-voltage = <4600000>; + qcom,supply-max-voltage = <6000000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-post-on-sleep = <20>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts new file mode 100644 index 000000000000..a32e2b3ceb8a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-cdp.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 CDP"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id= <1 0>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts new file mode 100644 index 000000000000..91c4f3ac6b91 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-ext-codec-cdp.dts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917 External Audio Codec CDP"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id= <1 1>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; +}; + +&pm8937_gpios { + gpio@c000 { + status = "ok"; + qcom,mode = <1>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,src-sel = <2>; + qcom,master-en = <1>; + qcom,out-strength = <2>; + }; + + gpio@c600 { + status = "ok"; + qcom,mode = <1>; + qcom,pull = <5>; + qcom,vin-sel = <0>; + qcom,src-sel = <0>; + qcom,master-en = <1>; + qcom,out-strength = <2>; + }; +}; + +&slim_msm { + status = "okay"; +}; + +&wcd9xxx_intc { + status = "okay"; +}; + +&clock_audio { + status = "okay"; +}; + +&wcd9335 { + status = "okay"; +}; + +&wcd_rst_gpio { + status = "okay"; +}; + +&ext_codec { + status = "okay"; +}; + +&int_codec { + status = "disabled"; +}; + +&wsa881x_i2c_f { + status = "disabled"; +}; + +&wsa881x_i2c_45 { + status = "disabled"; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts index 3fe60a302fea..5b458b22541d 100644 --- a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-mtp.dts @@ -14,7 +14,8 @@ /dts-v1/; #include "msm8917.dtsi" -#include "msm8917-pmi8950-mtp.dtsi" +#include "msm8917-mtp.dtsi" +#include "msm8917-pmi8950.dtsi" / { model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 MTP"; @@ -22,3 +23,23 @@ qcom,board-id= <8 0>; qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; }; + +&blsp1_uart1 { + status = "ok"; +}; + +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "batterydata-itech-3000mah.dtsi" + #include "batterydata-ascent-3450mAh.dtsi" + }; +}; + +&qpnp_fg { + qcom,battery-data = <&mtp_batterydata>; +}; + +&qpnp_smbcharger { + qcom,battery-data = <&mtp_batterydata>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts new file mode 100644 index 000000000000..a91bea1cf95f --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950-rcm.dts @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/dts-v1/; + +#include "msm8917.dtsi" +#include "msm8917-cdp.dtsi" +#include "msm8917-pmi8950.dtsi" + +/ { + model = "Qualcomm Technologies, Inc. MSM8917-PMI8950 RCM"; + compatible = "qcom,msm8917-cdp", "qcom,msm8917", "qcom,cdp"; + qcom,board-id= <21 0>; + qcom,pmic-id = <0x10019 0x010011 0x0 0x0>; +}; diff --git a/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi new file mode 100644 index 000000000000..9543133096ee --- /dev/null +++ b/arch/arm64/boot/dts/qcom/msm8917-pmi8950.dtsi @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "pmi8950.dtsi" + +&qpnp_smbcharger { + qcom,chg-led-sw-controls; + qcom,chg-led-support; + /delete-property/ dpdm-supply; +}; + +&usb_otg { + extcon = <&qpnp_smbcharger>; +}; -- GitLab From 728c474912a11ce4f38b22b35a1ec2ebc8a0f61d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 20 Apr 2018 14:56:20 -0700 Subject: [PATCH 1830/1834] mm/filemap.c: fix NULL pointer in page_cache_tree_insert() commit abc1be13fd113ddef5e2d807a466286b864caed3 upstream. f2fs specifies the __GFP_ZERO flag for allocating some of its pages. Unfortunately, the page cache also uses the mapping's GFP flags for allocating radix tree nodes. It always masked off the __GFP_HIGHMEM flag, and masks off __GFP_ZERO in some paths, but not all. That causes radix tree nodes to be allocated with a NULL list_head, which causes backtraces like: __list_del_entry+0x30/0xd0 list_lru_del+0xac/0x1ac page_cache_tree_insert+0xd8/0x110 The __GFP_DMA and __GFP_DMA32 flags would also be able to sneak through if they are ever used. Fix them all by using GFP_RECLAIM_MASK at the innermost location, and remove it from earlier in the callchain. Change-Id: I6b91267ad49104d3b6d6fcc84159d24fa96eec6e Link: http://lkml.kernel.org/r/20180411060320.14458-2-willy@infradead.org Fixes: 449dd6984d0e ("mm: keep page cache radix tree nodes in check") Signed-off-by: Matthew Wilcox Reported-by: Chris Fries Debugged-by: Minchan Kim Acked-by: Johannes Weiner Acked-by: Michal Hocko Reviewed-by: Jan Kara Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman Git-Repo: git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git Git-Commit: f4c86fa0e2c3ed3eb4fbbb145ce9dabeec12c2c7 Signed-off-by: Vinayak Menon --- mm/filemap.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 03c79ef9a3ea..211df83fef6f 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -618,7 +618,7 @@ int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask) VM_BUG_ON_PAGE(!PageLocked(new), new); VM_BUG_ON_PAGE(new->mapping, new); - error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); + error = radix_tree_preload(gfp_mask & GFP_RECLAIM_MASK); if (!error) { struct address_space *mapping = old->mapping; void (*freepage)(struct page *); @@ -674,7 +674,7 @@ static int __add_to_page_cache_locked(struct page *page, return error; } - error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM); + error = radix_tree_maybe_preload(gfp_mask & GFP_RECLAIM_MASK); if (error) { if (!huge) mem_cgroup_cancel_charge(page, memcg, false); @@ -1249,8 +1249,7 @@ struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset, if (fgp_flags & FGP_ACCESSED) __SetPageReferenced(page); - err = add_to_page_cache_lru(page, mapping, offset, - gfp_mask & GFP_RECLAIM_MASK); + err = add_to_page_cache_lru(page, mapping, offset, gfp_mask); if (unlikely(err)) { put_page(page); page = NULL; @@ -1998,7 +1997,7 @@ static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask) if (!page) return -ENOMEM; - ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL); + ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask); if (ret == 0) ret = mapping->a_ops->readpage(file, page); else if (ret == -EEXIST) -- GitLab From 3ae5c7659b4550aa915e5070f565859b859a162f Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Thu, 17 May 2018 12:03:52 +0530 Subject: [PATCH 1831/1834] ARM: dts: msm: add support for DDR bw vote on sdxpoorwills target To scale ddr based on the effective frequency of core enable cpubw node, cpubw node will scale ddr based on the cpu core frequency. Change-Id: Iad5e98d60caa5516d98820b9d4563c7d2200ae94 Signed-off-by: Santosh Mardi --- arch/arm/boot/dts/qcom/sdxpoorwills.dtsi | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi index c6608a87bf47..f18d5e6a7674 100644 --- a/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi +++ b/arch/arm/boot/dts/qcom/sdxpoorwills.dtsi @@ -19,6 +19,8 @@ #include #include +#define MHZ_TO_MBPS(mhz, w) ((mhz * 1000000 * w) / (1024 * 1024)) + / { model = "Qualcomm Technologies, Inc. SDX POORWILLS"; compatible = "qcom,sdxpoorwills"; @@ -218,6 +220,31 @@ < 1497600 >; }; + cpubw: qcom,cpubw { + compatible = "qcom,devbw"; + governor = "cpufreq"; + qcom,src-dst-ports = <1 512>; + qcom,active-only; + qcom,bw-tbl = + < MHZ_TO_MBPS(200, 2) >, /* 381 MB/s */ + < MHZ_TO_MBPS(470, 2) >, /* 896 MB/s */ + < MHZ_TO_MBPS(547, 2) >, /* 1043 MB/s */ + < MHZ_TO_MBPS(691, 2) >, /* 1317 MB/s */ + < MHZ_TO_MBPS(806, 2) >, /* 1537 MB/s */ + < MHZ_TO_MBPS(940, 2) >, /* 1792 MB/s */ + < MHZ_TO_MBPS(1383, 2) >; /* 2637 MB/s */ + }; + + devfreq_compute: qcom,devfreq-compute { + compatible = "qcom,arm-cpu-mon"; + qcom,cpulist = <&CPU0>; + qcom,target-dev = <&cpubw>; + qcom,core-dev-table = + < 153600 MHZ_TO_MBPS(200, 2) >, + < 576000 MHZ_TO_MBPS(691, 2) >, + < 1497600 MHZ_TO_MBPS(1383, 2)>; + }; + clock_gcc: qcom,gcc@100000 { compatible = "qcom,gcc-sdxpoorwills", "syscon"; reg = <0x100000 0x1f0000>; -- GitLab From 49eea524bebea0d2b7dfa1c709a6694de808eb8a Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Thu, 17 May 2018 12:04:23 +0530 Subject: [PATCH 1832/1834] devfreq: update freq variable in compute_freq function Update freq variable from unsigned long to uint64_t of compute_freq function to be in compliance with 32 bit environment. Change-Id: Ia9183b0e593daf3780135a8e1ae8ddb36db16f86 Signed-off-by: Santosh Mardi --- drivers/devfreq/arm-memlat-mon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index 1dca479fd8ba..81f7c162b069 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -82,7 +82,7 @@ static unsigned long compute_freq(struct cpu_pmu_stats *cpustats, { ktime_t ts; unsigned int diff; - unsigned long freq = 0; + uint64_t freq = 0; ts = ktime_get(); diff = ktime_to_us(ktime_sub(ts, cpustats->prev_ts)); -- GitLab From 2dbbee6ee6f95ed0c863fbc70f6898448ff9ff0d Mon Sep 17 00:00:00 2001 From: Santosh Mardi Date: Wed, 16 May 2018 14:34:16 +0530 Subject: [PATCH 1833/1834] defconfig: enable compute governor on sdxpoorwills target To enable compute governor on sdxpoorwills target enable memlat monitor and governor. Change-Id: Id123aaeaeac29223d22936eaab25e2c16f273697 Signed-off-by: Santosh Mardi --- arch/arm/configs/sdxpoorwills-perf_defconfig | 3 +++ arch/arm/configs/sdxpoorwills_defconfig | 2 ++ 2 files changed, 5 insertions(+) diff --git a/arch/arm/configs/sdxpoorwills-perf_defconfig b/arch/arm/configs/sdxpoorwills-perf_defconfig index 0e971d2df2f6..6c8f3858a119 100644 --- a/arch/arm/configs/sdxpoorwills-perf_defconfig +++ b/arch/arm/configs/sdxpoorwills-perf_defconfig @@ -381,6 +381,9 @@ CONFIG_QCOM_DCC_V2=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON_QCOM_SPMI_MISC=y CONFIG_IIO=y CONFIG_PWM=y diff --git a/arch/arm/configs/sdxpoorwills_defconfig b/arch/arm/configs/sdxpoorwills_defconfig index 52f3fdaad803..b259dc7ae54b 100644 --- a/arch/arm/configs/sdxpoorwills_defconfig +++ b/arch/arm/configs/sdxpoorwills_defconfig @@ -386,6 +386,8 @@ CONFIG_QCOM_DCC_V2=y CONFIG_QTI_RPM_STATS_LOG=y CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y CONFIG_QCOM_DEVFREQ_DEVBW=y CONFIG_EXTCON_QCOM_SPMI_MISC=y CONFIG_IIO=y -- GitLab From 29488293e377b5f51cb08ace1567d75cde0ef9dd Mon Sep 17 00:00:00 2001 From: Arun kumar Date: Tue, 15 May 2018 19:48:42 +0530 Subject: [PATCH 1834/1834] defconfig: msm8909w: Mandatory config for msm8909w Removing configs related virtual memory,fhandle syscalls and added USB configs to fix manufacturer error after bootup. Change-Id: Ic343f0d8a0109020fe384089355cfbe9a92f9a77 Signed-off-by: Arun kumar --- arch/arm/configs/msm8909w-perf_defconfig | 10 ++++++++++ arch/arm/configs/msm8909w_defconfig | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/arch/arm/configs/msm8909w-perf_defconfig b/arch/arm/configs/msm8909w-perf_defconfig index 3862b8a0c928..5a56d638d3c3 100644 --- a/arch/arm/configs/msm8909w-perf_defconfig +++ b/arch/arm/configs/msm8909w-perf_defconfig @@ -1,9 +1,13 @@ +# CONFIG_FHANDLE is not set CONFIG_AUDIT=y # CONFIG_AUDITSYSCALL is not set CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_IRQ_TIME_ACCOUNTING=y CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y CONFIG_RCU_EXPERT=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_NOCB_CPU=y @@ -214,6 +218,7 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_HDCP_QSEECOM=y CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y CONFIG_MEMORY_STATE_TIME=y CONFIG_QPNP_MISC=y CONFIG_SCSI=y @@ -260,6 +265,8 @@ CONFIG_TOUCHSCREEN_FTS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set CONFIG_SERIAL_MSM_HS=y CONFIG_SERIAL_MSM_SMD=y CONFIG_DIAG_CHAR=y @@ -357,9 +364,12 @@ CONFIG_USB_CONFIGFS_RMNET_BAM=y CONFIG_USB_CONFIGFS_EEM=y CONFIG_USB_CONFIGFS_MASS_STORAGE=y CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_F_ACC=y CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y diff --git a/arch/arm/configs/msm8909w_defconfig b/arch/arm/configs/msm8909w_defconfig index e94ef35e1437..af47269436b8 100644 --- a/arch/arm/configs/msm8909w_defconfig +++ b/arch/arm/configs/msm8909w_defconfig @@ -1,3 +1,4 @@ +# CONFIG_FHANDLE is not set CONFIG_AUDIT=y # CONFIG_AUDITSYSCALL is not set CONFIG_NO_HZ=y @@ -270,6 +271,8 @@ CONFIG_TOUCHSCREEN_FTS=y CONFIG_INPUT_MISC=y CONFIG_INPUT_QPNP_POWER_ON=y CONFIG_INPUT_UINPUT=y +# CONFIG_DEVMEM is not set +# CONFIG_DEVKMEM is not set CONFIG_SERIAL_MSM=y CONFIG_SERIAL_MSM_CONSOLE=y CONFIG_SERIAL_MSM_HS=y @@ -378,6 +381,7 @@ CONFIG_USB_CONFIGFS_F_PTP=y CONFIG_USB_CONFIGFS_F_ACC=y CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_MIDI=y CONFIG_USB_CONFIGFS_F_HID=y CONFIG_USB_CONFIGFS_F_DIAG=y CONFIG_USB_CONFIGFS_F_CDEV=y -- GitLab