* [PATCH 01/10] soc: qcom: Separate kryo l2 accessors from PMU driver
From: Mark Rutland @ 2017-12-12 14:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-2-git-send-email-ilialin@codeaurora.org>
Hi,
On Tue, Dec 12, 2017 at 02:31:28PM +0200, Ilia Lin wrote:
> The driver provides kernel level API for other drivers
> to access the MSM8996 L2 cache registers.
> Separating the L2 access code from the PMU driver and
> making it public to allow other drivers use it.
> The accesses must be separated with a single spinlock,
> maintained in this driver.
> -static void set_l2_indirect_reg(u64 reg, u64 val)
> -{
> - unsigned long flags;
> -
> - raw_spin_lock_irqsave(&l2_access_lock, flags);
> - write_sysreg_s(reg, L2CPUSRSELR_EL1);
> - isb();
> - write_sysreg_s(val, L2CPUSRDR_EL1);
> - isb();
> - raw_spin_unlock_irqrestore(&l2_access_lock, flags);
> -}
> +/**
> + * set_l2_indirect_reg: write value to an L2 register
> + * @reg: Address of L2 register.
> + * @value: Value to be written to register.
> + *
> + * Use architecturally required barriers for ordering between system register
> + * accesses, and system registers with respect to device memory
> + */
> +void set_l2_indirect_reg(u64 reg, u64 val)
> +{
> + unsigned long flags;
> + mb();
We didn't need this for the PMU driver, so it's unfortuante that it now
has to pay the cost.
Can we please factor this mb() into the callers that need it?
> + raw_spin_lock_irqsave(&l2_access_lock, flags);
> + write_sysreg_s(reg, L2CPUSRSELR_EL1);
> + isb();
> + write_sysreg_s(val, L2CPUSRDR_EL1);
> + isb();
> + raw_spin_unlock_irqrestore(&l2_access_lock, flags);
> +}
> +EXPORT_SYMBOL(set_l2_indirect_reg);
[...]
> +#ifdef CONFIG_ARCH_QCOM
> +void set_l2_indirect_reg(u64 reg_addr, u64 val);
> +u64 get_l2_indirect_reg(u64 reg_addr);
> +#else
> +static inline void set_l2_indirect_reg(u32 reg_addr, u32 val) {}
> +static inline u32 get_l2_indirect_reg(u32 reg_addr)
> +{
> + return 0;
> +}
> +#endif
> +#endif
Are there any drivers that will bne built for !CONFIG_ARCH_QCOM that
reference this?
It might be better to not have the stub versions, so that we get a
build-error if they are erroneously used.
Thannks,
Mark.
^ permalink raw reply
* [PATCH 1/6] ARM: stm32: prepare stm32 family to welcome armv7 architecture
From: Ludovic BARRE @ 2017-12-12 13:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171212110315.GA4118@afzalpc>
Hi all
-This patch serie hasn't goal to create a platform with
asymmetric linux processor (like vf610).
-Today, STM32 family have several boards with mcu microcontroler
Cortex-M like stm32f429, stm32f746...
And this patch serie prepare new board with support of Cortex-A
instead-of Cortex-M. (that's all)
BR
Ludo
On 12/12/2017 12:03 PM, afzal mohammed wrote:
> Hi,
>
> On Mon, Dec 11, 2017 at 02:40:43PM +0100, Arnd Bergmann wrote:
>> On Mon, Dec 11, 2017 at 11:25 AM, Linus Walleij
>
>>>> This patch prepares the STM32 machine for the integration of Cortex-A
>>>> based microprocessor (MPU), on top of the existing Cortex-M
>>>> microcontroller family (MCU). Since both MCUs and MPUs are sharing
>>>> common hardware blocks we can keep using ARCH_STM32 flag for most of
>>>> them. If a hardware block is specific to one family we can use either
>>>> ARCH_STM32_MCU or ARCH_STM32_MPU flag.
>
>> To what degree do we need to treat them as separate families
>> at all then? I wonder if the MCU/MPU distinction is always that
>> clear along the Cortex-M/Cortex-A separation,
>
>> What
>> exactly would we miss if we do away with the ARCH_STM32_MCU
>> symbol here?
>
> Based on this patch series, the only difference seems to be w.r.t ARM
> components, not peripherals outside ARM subystem. Vybrid VF610 is a
> similar case, though not identical (it can have both instead of
> either), deals w/o extra symbols,
>
> 8064887e02fd6 (ARM: vf610: enable Cortex-M4 configuration on Vybrid SoC)
>
>> especially if
>> we ever get to a chip that has both types of cores.
>
> Your wish fulfilled, Vybrid VF610 has both A5 & M4F and mainline Linux
> boots on both (simultaneously as well), and the second Linux support,
> i.e. on M4 went thr' your keyboard, see above commit :)
>
> There are quite a few others as well, TI's AM335x (A8 + M3), AM437x
> (A9 + M3), AM57x (A15 + M4), but of these Cortex M's, the one in AM57x
> only can be Linux'able. On others they are meant for PM with limited
> resources.
>
>>> So yesterdays application processors are todays MCU processors.
>>>
>>> I said this on a lecture for control systems a while back and
>>> stated it as a reason I think RTOSes are not really seeing a bright
>>> future compared to Linux.
>
>> I think there is still lots of room for smaller RTOS in the long run,
>
> Me being an electrical engineer & worked to some extent in motor
> control on RTOS/no OS (the value of my opinion is questionable
> though), the thought of handling the same in Linux (even RT) sends
> shivers down my spine. Here, case being considered is the type of
> motor (like permanent magnet ones) where each phase of the motor has
> to be properly excited during every PWM period (say every 100us,
> depending on the feedback, algorithm, other synchronization) w/o which
> the motor that has been told to run might try to fly. This is
> different from stepper motor where if control misbehaves/stops nothing
> harmful normally happens.
>
> But my opinion is a kind of knee-jerk reaction and based on prevalent
> atitude in that field, hmm.., probably i should attempt it first.
>
> Regards
> afzal
>
^ permalink raw reply
* [PATCH v2 22/36] KVM: arm64: Prepare to handle traps on deferred VM sysregs
From: Marc Zyngier @ 2017-12-12 13:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171211112436.GH910@cbox>
On 11/12/17 11:24, Christoffer Dall wrote:
> On Mon, Dec 11, 2017 at 11:10:36AM +0000, Marc Zyngier wrote:
>> On 07/12/17 17:06, Christoffer Dall wrote:
>>> When we defer the save/restore of system registers to vcpu_load and
>>> vcpu_put, we need to take care of the emulation code that handles traps
>>> to these registers, since simply reading the memory array will return
>>> stale data.
>>>
>>> Therefore, introduce two functions to directly read/write the registers
>>> from the physical CPU when we're on a VHE system that has loaded the
>>> system registers onto the physical CPU.
>>>
>>> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
>>> ---
>>>
>>> Notes:
>>> Changes since v1:
>>> - Removed spurious white space
>>>
>>> arch/arm64/include/asm/kvm_host.h | 4 +++
>>> arch/arm64/kvm/sys_regs.c | 53 +++++++++++++++++++++++++++++++++++++--
>>> 2 files changed, 55 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>>> index de0d55b30b61..f6afe685a280 100644
>>> --- a/arch/arm64/include/asm/kvm_host.h
>>> +++ b/arch/arm64/include/asm/kvm_host.h
>>> @@ -279,6 +279,10 @@ struct kvm_vcpu_arch {
>>>
>>> /* Detect first run of a vcpu */
>>> bool has_run_once;
>>> +
>>> + /* True when deferrable sysregs are loaded on the physical CPU,
>>> + * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
>>> + bool sysregs_loaded_on_cpu;
>>> };
>>>
>>> #define vcpu_gp_regs(v) (&(v)->arch.ctxt.gp_regs)
>>> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
>>> index 62c12ab9e6c4..80adbec933de 100644
>>> --- a/arch/arm64/kvm/sys_regs.c
>>> +++ b/arch/arm64/kvm/sys_regs.c
>>> @@ -35,6 +35,7 @@
>>> #include <asm/kvm_coproc.h>
>>> #include <asm/kvm_emulate.h>
>>> #include <asm/kvm_host.h>
>>> +#include <asm/kvm_hyp.h>
>>> #include <asm/kvm_mmu.h>
>>> #include <asm/perf_event.h>
>>> #include <asm/sysreg.h>
>>> @@ -111,6 +112,54 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
>>> return true;
>>> }
>>>
>>> +static u64 read_deferrable_vm_reg(struct kvm_vcpu *vcpu, int reg)
>>> +{
>>> + if (vcpu->arch.sysregs_loaded_on_cpu) {
>>> + switch (reg) {
>>> + case SCTLR_EL1: return read_sysreg_el1(sctlr);
>>> + case TTBR0_EL1: return read_sysreg_el1(ttbr0);
>>> + case TTBR1_EL1: return read_sysreg_el1(ttbr1);
>>> + case TCR_EL1: return read_sysreg_el1(tcr);
>>> + case ESR_EL1: return read_sysreg_el1(esr);
>>> + case FAR_EL1: return read_sysreg_el1(far);
>>> + case AFSR0_EL1: return read_sysreg_el1(afsr0);
>>> + case AFSR1_EL1: return read_sysreg_el1(afsr1);
>>> + case MAIR_EL1: return read_sysreg_el1(mair);
>>> + case AMAIR_EL1: return read_sysreg_el1(amair);
>>> + case CONTEXTIDR_EL1: return read_sysreg_el1(contextidr);
>>> + case DACR32_EL2: return read_sysreg(dacr32_el2);
>>> + case IFSR32_EL2: return read_sysreg(ifsr32_el2);
>>> + default: BUG();
>>> + }
>>> + }
>>> +
>>> + return vcpu_sys_reg(vcpu, reg);
>>> +}
>>> +
>>> +static void write_deferrable_vm_reg(struct kvm_vcpu *vcpu, int reg, u64 val)
>>> +{
>>> + if (vcpu->arch.sysregs_loaded_on_cpu) {
>>> + switch (reg) {
>>> + case SCTLR_EL1: write_sysreg_el1(val, sctlr); return;
>>> + case TTBR0_EL1: write_sysreg_el1(val, ttbr0); return;
>>> + case TTBR1_EL1: write_sysreg_el1(val, ttbr1); return;
>>> + case TCR_EL1: write_sysreg_el1(val, tcr); return;
>>> + case ESR_EL1: write_sysreg_el1(val, esr); return;
>>> + case FAR_EL1: write_sysreg_el1(val, far); return;
>>> + case AFSR0_EL1: write_sysreg_el1(val, afsr0); return;
>>> + case AFSR1_EL1: write_sysreg_el1(val, afsr1); return;
>>> + case MAIR_EL1: write_sysreg_el1(val, mair); return;
>>> + case AMAIR_EL1: write_sysreg_el1(val, amair); return;
>>> + case CONTEXTIDR_EL1: write_sysreg_el1(val, contextidr); return;
>>> + case DACR32_EL2: write_sysreg(val, dacr32_el2); return;
>>> + case IFSR32_EL2: write_sysreg(val, ifsr32_el2); return;
>>> + default: BUG();
>>> + }
>>> + }
>>> +
>>> + vcpu_sys_reg(vcpu, reg) = val;
>>> +}
>>> +
>>> /*
>>> * Generic accessor for VM registers. Only called as long as HCR_TVM
>>> * is set. If the guest enables the MMU, we stop trapping the VM
>>> @@ -133,14 +182,14 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
>>> if (!p->is_aarch32 || !p->is_32bit) {
>>> val = p->regval;
>>> } else {
>>> - val = vcpu_sys_reg(vcpu, reg);
>>> + val = read_deferrable_vm_reg(vcpu, reg);
>>> if (r->reg % 2)
>>> val = (p->regval << 32) | (u64)lower_32_bits(val);
>>> else
>>> val = ((u64)upper_32_bits(val) << 32) |
>>> (u64)lower_32_bits(p->regval);
>>> }
>>> - vcpu_sys_reg(vcpu, reg) = val;
>>> + write_deferrable_vm_reg(vcpu, reg, val);
>>>
>>> kvm_toggle_cache(vcpu, was_enabled);
>>> return true;
>>>
>>
>> I'm slightly uneasy with this. It means that the rest of the KVM code
>> has to know whether a given register is deferrable or not (or face the
>> wrath of the BUG). I'd be more inclined to hide the "loaded on cpu"
>> magic in the vcpu_sys_reg() accessors.
>>
>> Thoughts?
>>
>
> Yes, this is the main reservation I also have with the series.
>
> I did start out with a giant "rewrite everything to vcpu_get_sys_reg and
> vcpu_get_sys_reg" which hides this logic, and we may want to go back to
> that.
>
> That does mean that we need a giant switch statement which knows how to
> read any deferrable EL1 (and EL0) system register from hardware, and
> still BUG/WARN if someone adds a system register but forgets to add that
> handler and test on VHE. Unless there's some fantastic auto-gen
> mechanism that can take a hash define and figure out which sysreg
> instruction to use - I couldn't think of that.
Coming back to this, as I'm currently prototyping something.
What is the rational for the BUG()? It is not like we can add a random
sysreg and expect it to be deferred. It is a conscious decision to do
so, and I feel that the default should be that the sysreg should be
save/restored. What am I missing?
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH][next] net: phy: meson-gxl: make function meson_gxl_read_status static
From: Colin King @ 2017-12-12 13:03 UTC (permalink / raw)
To: linux-arm-kernel
From: Colin Ian King <colin.king@canonical.com>
The function meson_gxl_read_status is local to the source and does
not need to be in global scope, so make it static.
Cleans up sparse warning:
symbol 'meson_gxl_read_status' was not declared. Should it be static?
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
drivers/net/phy/meson-gxl.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/phy/meson-gxl.c b/drivers/net/phy/meson-gxl.c
index c64b81e50f60..4ee630afe43a 100644
--- a/drivers/net/phy/meson-gxl.c
+++ b/drivers/net/phy/meson-gxl.c
@@ -67,7 +67,7 @@ static int meson_gxl_config_init(struct phy_device *phydev)
* When this failure happens, the first retry is usually successful but,
* in some cases, it may take up to 6 retries to get a decent result
*/
-int meson_gxl_read_status(struct phy_device *phydev)
+static int meson_gxl_read_status(struct phy_device *phydev)
{
int ret, wol, lpa, exp;
--
2.14.1
^ permalink raw reply related
* [PATCH V7 0/7] dmaengine: qcom_hidma: add support for bugfixed HW
From: Rafael J. Wysocki @ 2017-12-12 12:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171212053845.GB18649@localhost>
On Tue, Dec 12, 2017 at 6:38 AM, Vinod Koul <vinod.koul@intel.com> wrote:
> On Thu, Dec 07, 2017 at 04:10:24PM -0500, Sinan Kaya wrote:
>> Introduce new ACPI and OF device ids for thw HW along with the helper
>> functions.
>>
>> Changes from v6:
>> * add const to the device callback parameter in fwnode.
>> * reorganize the callbacks in the code
>> * rename get_match_data() as device_get_match_data()
>> * place pointer checks into acpi_get_match_data()
>
> This fails for me at 3rd patch. I am on -rc1 is there a dependency?
There shouldn't be any.
According to git, all changes to the files touched by the [3/7] are in
-rc1 already.
^ permalink raw reply
* [PATCH 03/41] drm/rockchip: support prime import sg table
From: Heiko Stuebner @ 2017-12-12 12:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170310043305.17216-4-seanpaul@chromium.org>
Am Donnerstag, 9. M?rz 2017, 23:32:18 CET schrieb Sean Paul:
> From: Haixia Shi <hshi@chromium.org>
>
> The prime fd to handle ioctl was not used with rockchip before. Support
> was added in order to pass graphics_Gbm and to support potential uses
> within Chrome OS (e.g. zero-copy video decode, camera).
>
> Signed-off-by: Haixia Shi <hshi@chromium.org>
missing a further Signed-off from Sean Paul as the sender.
I've tested this on the rk3328 together with the wip Lima driver and my wip
Mesa Rockchip Pipe and the kmscube improved from a failure about importing
the buffer to producing actual output, so
Tested-by: Heiko Stuebner <heiko@sntech.de>
^ permalink raw reply
* [PATCH 10/10] DT: QCOM: Add thermal mitigation to msm8996
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
Add thermal mitigation configuration to msm8996.
With the cpufreq-dt OPP table the CPU frequency may be
scaled and therefore throttled by the thermal config.
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
arch/arm64/boot/dts/qcom/msm8996.dtsi | 98 +++++++++++++++++++++++++++++++----
1 file changed, 87 insertions(+), 11 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 8beea7e..6fa061f 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -14,6 +14,7 @@
#include <dt-bindings/clock/qcom,gcc-msm8996.h>
#include <dt-bindings/clock/qcom,mmcc-msm8996.h>
#include <dt-bindings/clock/qcom,rpmcc.h>
+#include <dt-bindings/thermal/thermal.h>
/ {
model = "Qualcomm Technologies, Inc. MSM8996";
@@ -88,6 +89,10 @@
enable-method = "psci";
clocks = <&kryocc 0>;
operating-points-v2 = <&cluster0_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
compatible = "cache";
@@ -102,6 +107,10 @@
enable-method = "psci";
clocks = <&kryocc 0>;
operating-points-v2 = <&cluster0_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_0>;
};
@@ -112,6 +121,10 @@
enable-method = "psci";
clocks = <&kryocc 1>;
operating-points-v2 = <&cluster1_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
compatible = "cache";
@@ -126,6 +139,10 @@
enable-method = "psci";
clocks = <&kryocc 1>;
operating-points-v2 = <&cluster1_opp>;
+ /* cooling options */
+ cooling-min-level = <0>;
+ cooling-max-level = <15>;
+ #cooling-cells = <2>;
next-level-cache = <&L2_1>;
};
@@ -336,18 +353,33 @@
thermal-sensors = <&tsens0 3>;
trips {
- cpu_alert0: trip0 {
+ cpu_alert0: cpu_alert0 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn0: cpu_warn0 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
- cpu_crit0: trip1 {
+ cpu_crit0: cpu_crit0 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn0>;
+ cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal1 {
@@ -357,18 +389,33 @@
thermal-sensors = <&tsens0 5>;
trips {
- cpu_alert1: trip0 {
+ cpu_alert1: cpu_alert1 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn1: cpu_warn1 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
- cpu_crit1: trip1 {
+ cpu_crit1: cpu_crit1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&CPU0 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn1>;
+ cooling-device = <&CPU0 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal2 {
@@ -378,18 +425,32 @@
thermal-sensors = <&tsens0 8>;
trips {
- cpu_alert2: trip0 {
+ cpu_alert2: cpu_alert2 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn2: cpu_warn2 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
- cpu_crit2: trip1 {
+ cpu_crit2: cpu_crit2 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert2>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn2>;
+ cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
cpu-thermal3 {
@@ -399,18 +460,33 @@
thermal-sensors = <&tsens0 10>;
trips {
- cpu_alert3: trip0 {
+ cpu_alert3: cpu_alert3 {
temperature = <75000>;
hysteresis = <2000>;
+ type = "active";
+ };
+ cpu_warn3: cpu_warn3 {
+ temperature = <90000>;
+ hysteresis = <2000>;
type = "passive";
};
-
cpu_crit3: trip1 {
temperature = <110000>;
hysteresis = <2000>;
type = "critical";
};
};
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert3>;
+ cooling-device = <&CPU2 THERMAL_NO_LIMIT 7>;
+ };
+ map1 {
+ trip = <&cpu_warn3>;
+ cooling-device = <&CPU2 8 THERMAL_NO_LIMIT>;
+ };
+ };
};
};
--
1.9.1
^ permalink raw reply related
* [PATCH 09/10] DT: QCOM: Add cpufreq-dt to msm8996
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
Add device tree frequency table for the MSM8996 to be
used by the upstream cpufreq-dt driver with the clk-cpu-8996
driver as infrastructure.
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
arch/arm64/boot/dts/qcom/apq8096-db820c.dts | 2 +-
arch/arm64/boot/dts/qcom/msm8996.dtsi | 184 ++++++++++++++++++++++++++++
drivers/cpufreq/cpufreq-dt-platdev.c | 3 +
3 files changed, 188 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
index 230e9c8..da23bda 100644
--- a/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
+++ b/arch/arm64/boot/dts/qcom/apq8096-db820c.dts
@@ -17,5 +17,5 @@
/ {
model = "Qualcomm Technologies, Inc. DB820c";
- compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc";
+ compatible = "arrow,apq8096-db820c", "qcom,apq8096-sbc", "qcom,apq8096";
};
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 4b2afcc..8beea7e 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -86,6 +86,8 @@
compatible = "qcom,kryo";
reg = <0x0 0x0>;
enable-method = "psci";
+ clocks = <&kryocc 0>;
+ operating-points-v2 = <&cluster0_opp>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
compatible = "cache";
@@ -98,6 +100,8 @@
compatible = "qcom,kryo";
reg = <0x0 0x1>;
enable-method = "psci";
+ clocks = <&kryocc 0>;
+ operating-points-v2 = <&cluster0_opp>;
next-level-cache = <&L2_0>;
};
@@ -106,6 +110,8 @@
compatible = "qcom,kryo";
reg = <0x0 0x100>;
enable-method = "psci";
+ clocks = <&kryocc 1>;
+ operating-points-v2 = <&cluster1_opp>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
compatible = "cache";
@@ -118,6 +124,8 @@
compatible = "qcom,kryo";
reg = <0x0 0x101>;
enable-method = "psci";
+ clocks = <&kryocc 1>;
+ operating-points-v2 = <&cluster1_opp>;
next-level-cache = <&L2_1>;
};
@@ -144,6 +152,182 @@
};
};
+ cluster0_opp: opp_table0 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp at 307200000 {
+ opp-hz = /bits/ 64 < 307200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 422400000 {
+ opp-hz = /bits/ 64 < 422400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 480000000 {
+ opp-hz = /bits/ 64 < 480000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 556800000 {
+ opp-hz = /bits/ 64 < 556800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 652800000 {
+ opp-hz = /bits/ 64 < 652800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 729600000 {
+ opp-hz = /bits/ 64 < 729600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 844800000 {
+ opp-hz = /bits/ 64 < 844800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 960000000 {
+ opp-hz = /bits/ 64 < 960000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1036800000 {
+ opp-hz = /bits/ 64 < 1036800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1113600000 {
+ opp-hz = /bits/ 64 < 1113600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1190400000 {
+ opp-hz = /bits/ 64 < 1190400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1228800000 {
+ opp-hz = /bits/ 64 < 1228800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1324800000 {
+ opp-hz = /bits/ 64 < 1324800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1401600000 {
+ opp-hz = /bits/ 64 < 1401600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1478400000 {
+ opp-hz = /bits/ 64 < 1478400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1593600000 {
+ opp-hz = /bits/ 64 < 1593600000 >;
+ clock-latency-ns = <200000>;
+ };
+ };
+
+ cluster1_opp: opp_table1 {
+ compatible = "operating-points-v2";
+ opp-shared;
+
+ opp at 307200000 {
+ opp-hz = /bits/ 64 < 307200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 403200000 {
+ opp-hz = /bits/ 64 < 403200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 480000000 {
+ opp-hz = /bits/ 64 < 480000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 556800000 {
+ opp-hz = /bits/ 64 < 556800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 652800000 {
+ opp-hz = /bits/ 64 < 652800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 729600000 {
+ opp-hz = /bits/ 64 < 729600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 806400000 {
+ opp-hz = /bits/ 64 < 806400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 883200000 {
+ opp-hz = /bits/ 64 < 883200000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 940800000 {
+ opp-hz = /bits/ 64 < 940800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1036800000 {
+ opp-hz = /bits/ 64 < 1036800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1113600000 {
+ opp-hz = /bits/ 64 < 1113600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1190400000 {
+ opp-hz = /bits/ 64 < 1190400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1248000000 {
+ opp-hz = /bits/ 64 < 1248000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1324800000 {
+ opp-hz = /bits/ 64 < 1324800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1401600000 {
+ opp-hz = /bits/ 64 < 1401600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1478400000 {
+ opp-hz = /bits/ 64 < 1478400000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1552000000 {
+ opp-hz = /bits/ 64 < 1552000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1632000000 {
+ opp-hz = /bits/ 64 < 1632000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1708800000 {
+ opp-hz = /bits/ 64 < 1708800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1785600000 {
+ opp-hz = /bits/ 64 < 1785600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1824000000 {
+ opp-hz = /bits/ 64 < 1824000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1920000000 {
+ opp-hz = /bits/ 64 < 1920000000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 1996800000 {
+ opp-hz = /bits/ 64 < 1996800000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 2073600000 {
+ opp-hz = /bits/ 64 < 2073600000 >;
+ clock-latency-ns = <200000>;
+ };
+ opp at 2150400000 {
+ opp-hz = /bits/ 64 < 2150400000 >;
+ clock-latency-ns = <200000>;
+ };
+
+ };
thermal-zones {
cpu-thermal0 {
polling-delay-passive = <250>;
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index ecc56e2..0feca0e 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -95,6 +95,9 @@
{ .compatible = "xlnx,zynq-7000", },
{ .compatible = "xlnx,zynqmp", },
+ { .compatible = "qcom,msm8996", },
+ { .compatible = "qcom,apq8096", },
+
{ }
};
--
1.9.1
^ permalink raw reply related
* [PATCH 08/10] clk: qcom: Add ACD path to CPU clock driver for msm8996
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
The PMUX for each duplex allows for selection of ACD clock source.
The DVM (Dynamic Variation Monitor) will flag an error
when a voltage droop event is detected. This flagged error
enables ACD to provide a div-by-2 clock, sourced from the primary PLL.
The duplex will be provided the divided clock
until a pre-programmed delay has expired.
This change configures ACD during the probe and switches
the PMUXes to the ACD clock source.
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
drivers/clk/qcom/clk-cpu-8996.c | 122 ++++++++++++++++++++++++++++++++++------
1 file changed, 106 insertions(+), 16 deletions(-)
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
index 0d41fa9..6f89471 100644
--- a/drivers/clk/qcom/clk-cpu-8996.c
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -17,6 +17,7 @@
#include <linux/regmap.h>
#include <linux/clk-provider.h>
#include "clk-alpha-pll.h"
+#include <soc/qcom/kryo-l2-accessors.h>
#define VCO(a, b, c) { \
.val = a,\
@@ -29,6 +30,27 @@
#define ACD_INDEX 2
#define ALT_INDEX 3
#define DIV_2_THRESHOLD 600000000
+#define PWRCL_REG_OFFSET 0x0
+#define PERFCL_REG_OFFSET 0x80000
+#define MUX_OFFSET 0x40
+#define ALT_PLL_OFFSET 0x100
+#define SSSCTL_OFFSET 0x160
+/*
+APCy_QLL_SSSCTL value:
+SACDRCLEN=1
+SSWEN=1
+SSTRTEN=1
+SSTPAPMSWEN=1
+*/
+#define SSSCTL_VAL 0xF
+
+enum {
+ APC_BASE,
+ EFUSE_BASE,
+ NUM_BASES
+};
+
+static void __iomem *vbases[NUM_BASES];
/* PLLs */
@@ -43,7 +65,7 @@
};
static struct clk_alpha_pll perfcl_pll = {
- .offset = 0x80000,
+ .offset = PERFCL_REG_OFFSET,
.min_rate = 600000000,
.max_rate = 3000000000,
.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_16BIT_ALPHA
@@ -57,7 +79,7 @@
};
static struct clk_alpha_pll pwrcl_pll = {
- .offset = 0x0,
+ .offset = PWRCL_REG_OFFSET,
.min_rate = 600000000,
.max_rate = 3000000000,
.flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_16BIT_ALPHA
@@ -89,7 +111,7 @@
};
static struct clk_alpha_pll perfcl_alt_pll = {
- .offset = 0x80100,
+ .offset = PERFCL_REG_OFFSET + ALT_PLL_OFFSET,
.vco_table = alt_pll_vco_modes,
.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
.flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
@@ -102,7 +124,7 @@
};
static struct clk_alpha_pll pwrcl_alt_pll = {
- .offset = 0x100,
+ .offset = PWRCL_REG_OFFSET + ALT_PLL_OFFSET,
.vco_table = alt_pll_vco_modes,
.num_vco = ARRAY_SIZE(alt_pll_vco_modes),
.flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
@@ -113,6 +135,7 @@
.ops = &clk_alpha_pll_hwfsm_ops,
},
};
+static void qcom_cpu_clk_msm8996_acd_init(void);
/* Mux'es */
@@ -196,6 +219,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
switch (event) {
case PRE_RATE_CHANGE:
ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
+ qcom_cpu_clk_msm8996_acd_init();
break;
case POST_RATE_CHANGE:
if (cnd->new_rate < DIV_2_THRESHOLD)
@@ -203,7 +227,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
DIV_2_INDEX);
else
ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
- PLL_INDEX);
+ ACD_INDEX);
break;
default:
ret = 0;
@@ -220,7 +244,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
};
static struct clk_cpu_8996_mux pwrcl_smux = {
- .reg = 0x40,
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
.shift = 2,
.width = 2,
.clkr.hw.init = &(struct clk_init_data) {
@@ -236,7 +260,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
};
static struct clk_cpu_8996_mux perfcl_smux = {
- .reg = 0x80040,
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
.shift = 2,
.width = 2,
.clkr.hw.init = &(struct clk_init_data) {
@@ -252,7 +276,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
};
static struct clk_cpu_8996_mux pwrcl_pmux = {
- .reg = 0x40,
+ .reg = PWRCL_REG_OFFSET + MUX_OFFSET,
.shift = 0,
.width = 2,
.pll = &pwrcl_pll.clkr.hw,
@@ -273,7 +297,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
};
static struct clk_cpu_8996_mux perfcl_pmux = {
- .reg = 0x80040,
+ .reg = PERFCL_REG_OFFSET + MUX_OFFSET,
.shift = 0,
.width = 2,
.pll = &perfcl_pll.clkr.hw,
@@ -341,7 +365,17 @@ struct clk_hw_clks {
CLK_SET_RATE_PARENT, 1, 2);
pwrcl_smux.pll = hws->hws[1];
- hws->num = 2;
+ hws->hws[2] = clk_hw_register_fixed_factor(dev, "perfcl_pll_acd",
+ "perfcl_pll",
+ CLK_SET_RATE_PARENT, 1, 1);
+ perfcl_pmux.pll = hws->hws[2];
+
+ hws->hws[3] = clk_hw_register_fixed_factor(dev, "pwrcl_pll_acd",
+ "pwrcl_pll",
+ CLK_SET_RATE_PARENT, 1, 1);
+ pwrcl_pmux.pll = hws->hws[3];
+
+ hws->num = 4;
for (i = 0; i < ARRAY_SIZE(clks); i++) {
ret = devm_clk_register_regmap(dev, clks[i]);
@@ -377,10 +411,65 @@ struct clk_hw_clks {
return ret;
}
+#define CPU_AFINITY_MASK 0xFFF
+#define PWRCL_CPU_REG_MASK 0x3
+#define PERFCL_CPU_REG_MASK 0x103
+
+/* ACD static settings (HMSS HPG 7.2.2) */
+#define L2ACDCR_REG 0x580ULL
+#define L2ACDTD_REG 0x581ULL
+#define L2ACDDVMRC_REG 0x584ULL
+#define L2ACDSSCR_REG 0x589ULL
+#define ACDTD_VAL 0x00006A11
+#define ACDCR_VAL 0x002C5FFD
+#define ACDSSCR_VAL 0x00000601
+#define ACDDVMRC_VAL 0x000E0F0F
+
+static DEFINE_SPINLOCK(acd_lock);
+
+static void qcom_cpu_clk_msm8996_acd_init(void)
+{
+ u64 hwid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&acd_lock, flags);
+
+ hwid = read_cpuid_mpidr() & CPU_AFINITY_MASK;
+
+ /* Program ACD Tunable-Length Delay (TLD) */
+ set_l2_indirect_reg(L2ACDTD_REG, ACDTD_VAL);
+ /* Initial ACD for *this* cluster */
+ set_l2_indirect_reg(L2ACDDVMRC_REG, ACDDVMRC_VAL);
+ /* Program ACD soft start control bits. */
+ set_l2_indirect_reg(L2ACDSSCR_REG, ACDSSCR_VAL);
+
+ if (PWRCL_CPU_REG_MASK == (hwid | PWRCL_CPU_REG_MASK)) {
+ /* Enable Soft Stop/Start */
+ if (vbases[APC_BASE])
+ writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+ PWRCL_REG_OFFSET + SSSCTL_OFFSET);
+ /* Ensure SSSCTL config goes through before enabling ACD. */
+ mb();
+ /* Program ACD control bits */
+ set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+ }
+ if (PERFCL_CPU_REG_MASK == (hwid | PERFCL_CPU_REG_MASK)) { //else {
+ /* Program ACD control bits */
+ set_l2_indirect_reg(L2ACDCR_REG, ACDCR_VAL);
+ /* Enable Soft Stop/Start */
+ if (vbases[APC_BASE])
+ writel_relaxed(SSSCTL_VAL, vbases[APC_BASE] +
+ PERFCL_REG_OFFSET + SSSCTL_OFFSET);
+ /* Ensure SSSCTL config goes through before enabling ACD. */
+ mb();
+ }
+
+ spin_unlock_irqrestore(&acd_lock, flags);
+}
+
static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
{
int ret;
- void __iomem *base;
struct resource *res;
struct regmap *regmap_cpu;
struct clk_hw_clks *hws;
@@ -393,17 +482,17 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
- hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+ hws = devm_kzalloc(dev, sizeof(*hws) + 4 * sizeof(struct clk_hw *),
GFP_KERNEL);
if (!hws)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- base = devm_ioremap_resource(dev, res);
- if (IS_ERR(base))
- return PTR_ERR(base);
+ vbases[APC_BASE] = devm_ioremap_resource(dev, res);
+ if (IS_ERR(vbases[APC_BASE]))
+ return PTR_ERR(vbases[APC_BASE]);
- regmap_cpu = devm_regmap_init_mmio(dev, base,
+ regmap_cpu = devm_regmap_init_mmio(dev, vbases[APC_BASE],
&cpu_msm8996_regmap_config);
if (IS_ERR(regmap_cpu))
return PTR_ERR(regmap_cpu);
@@ -411,6 +500,7 @@ static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
if (ret)
return ret;
+ qcom_cpu_clk_msm8996_acd_init();
data->hws[0] = &pwrcl_pmux.clkr.hw;
data->hws[1] = &perfcl_pmux.clkr.hw;
--
1.9.1
^ permalink raw reply related
* [PATCH 07/10] clk: qcom: clk-cpu-8996: Prepare PLLs on probe
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
The PLLs must be prepared enabled during the probe to be
accessible by the OPPs. Otherwise an OPP may switch
to non-enabled clock.
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
drivers/clk/qcom/clk-cpu-8996.c | 22 +++++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
index 79db4e8..0d41fa9 100644
--- a/drivers/clk/qcom/clk-cpu-8996.c
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-
+#include <linux/clk-provider.h>
#include "clk-alpha-pll.h"
#define VCO(a, b, c) { \
@@ -159,7 +159,7 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
cpuclk->shift);
val = index;
- val = cpuclk->shift;
+ val <<= cpuclk->shift;
return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val);
}
@@ -268,7 +268,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
},
.num_parents = 4,
.ops = &clk_cpu_8996_mux_ops,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
},
};
@@ -284,12 +284,12 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
.parent_names = (const char *[]){
"perfcl_smux",
"perfcl_pll",
- "pwrcl_pll_acd",
+ "perfcl_pll_acd",
"perfcl_alt_pll",
},
.num_parents = 4,
.ops = &clk_cpu_8996_mux_ops,
- .flags = CLK_SET_RATE_PARENT,
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
},
};
@@ -354,6 +354,18 @@ struct clk_hw_clks {
clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
+ /* Enable all PLLs and alt PLLs */
+ clk_prepare_enable(pwrcl_alt_pll.clkr.hw.clk);
+ clk_prepare_enable(perfcl_alt_pll.clkr.hw.clk);
+ clk_prepare_enable(pwrcl_pll.clkr.hw.clk);
+ clk_prepare_enable(perfcl_pll.clkr.hw.clk);
+
+ /* Set initial boot frequencies for power/perf PLLs */
+ clk_set_rate(pwrcl_alt_pll.clkr.hw.clk, 652800000);
+ clk_set_rate(perfcl_alt_pll.clkr.hw.clk, 652800000);
+ clk_set_rate(pwrcl_pll.clkr.hw.clk, 652800000);
+ clk_set_rate(perfcl_pll.clkr.hw.clk, 652800000);
+
ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
if (ret)
return ret;
--
1.9.1
^ permalink raw reply related
* [PATCH 06/10] clk: qcom: cpu-8996: Add support to switch below 600Mhz
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
From: Rajendra Nayak <rnayak@codeaurora.org>
The CPU clock controllers primary PLL operates on a single VCO range,
between 600Mhz and 3Ghz. However the CPUs do support OPPs with
frequencies between 300Mhz and 600Mhz. In order to support running the
CPUs at those frequencies we end up having to lock the PLL at twice the
rate and drive the CPU clk via the PLL/2 output and SMUX.
So for frequencies above 600Mhz we follow the following path
Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
and for frequencies between 300Mhz and 600Mhz we follow
Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
drivers/clk/qcom/clk-cpu-8996.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
index 9bb25be..79db4e8 100644
--- a/drivers/clk/qcom/clk-cpu-8996.c
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -28,6 +28,7 @@
#define PLL_INDEX 1
#define ACD_INDEX 2
#define ALT_INDEX 3
+#define DIV_2_THRESHOLD 600000000
/* PLLs */
@@ -121,6 +122,7 @@ struct clk_cpu_8996_mux {
u32 width;
struct notifier_block nb;
struct clk_hw *pll;
+ struct clk_hw *pll_div_2;
struct clk_regmap clkr;
};
@@ -171,6 +173,13 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
if (!cpuclk->pll)
return -EINVAL;
+ if (cpuclk->pll_div_2 && req->rate < DIV_2_THRESHOLD) {
+ if (req->rate < (DIV_2_THRESHOLD / 2))
+ return -EINVAL;
+
+ parent = cpuclk->pll_div_2;
+ }
+
req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
req->best_parent_hw = parent;
@@ -182,13 +191,19 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
{
int ret;
struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+ struct clk_notifier_data *cnd = data;
switch (event) {
case PRE_RATE_CHANGE:
ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
break;
case POST_RATE_CHANGE:
- ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, PLL_INDEX);
+ if (cnd->new_rate < DIV_2_THRESHOLD)
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+ DIV_2_INDEX);
+ else
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw,
+ PLL_INDEX);
break;
default:
ret = 0;
@@ -241,6 +256,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
.shift = 0,
.width = 2,
.pll = &pwrcl_pll.clkr.hw,
+ .pll_div_2 = &pwrcl_smux.clkr.hw,
.nb.notifier_call = cpu_clk_notifier_cb,
.clkr.hw.init = &(struct clk_init_data) {
.name = "pwrcl_pmux",
@@ -261,6 +277,7 @@ int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
.shift = 0,
.width = 2,
.pll = &perfcl_pll.clkr.hw,
+ .pll_div_2 = &perfcl_smux.clkr.hw,
.nb.notifier_call = cpu_clk_notifier_cb,
.clkr.hw.init = &(struct clk_init_data) {
.name = "perfcl_pmux",
--
1.9.1
^ permalink raw reply related
* [PATCH 05/10] clk: qcom: cpu-8996: Add support to switch to alternate PLL
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
From: Rajendra Nayak <rnayak@codeaurora.org>
Each of the CPU clusters on msm8996 and powered via a primary
PLL and a secondary PLL. The primary PLL is what drivers the
CPU clk, except for times when we are reprogramming the PLL
itself, when we temporarily switch to an alternate PLL.
Use clock rate change notifiers to support this.
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
drivers/clk/qcom/clk-cpu-8996.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
index bc60111..9bb25be 100644
--- a/drivers/clk/qcom/clk-cpu-8996.c
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -119,10 +119,14 @@ struct clk_cpu_8996_mux {
u32 reg;
u32 shift;
u32 width;
+ struct notifier_block nb;
struct clk_hw *pll;
struct clk_regmap clkr;
};
+#define to_clk_cpu_8996_mux_nb(_nb) \
+ container_of(_nb, struct clk_cpu_8996_mux, nb)
+
static inline
struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
{
@@ -173,6 +177,27 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
return 0;
}
+int cpu_clk_notifier_cb(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ int ret;
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_nb(nb);
+
+ switch (event) {
+ case PRE_RATE_CHANGE:
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, ALT_INDEX);
+ break;
+ case POST_RATE_CHANGE:
+ ret = clk_cpu_8996_mux_set_parent(&cpuclk->clkr.hw, PLL_INDEX);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return notifier_from_errno(ret);
+};
+
const struct clk_ops clk_cpu_8996_mux_ops = {
.set_parent = clk_cpu_8996_mux_set_parent,
.get_parent = clk_cpu_8996_mux_get_parent,
@@ -216,6 +241,7 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
.shift = 0,
.width = 2,
.pll = &pwrcl_pll.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
.clkr.hw.init = &(struct clk_init_data) {
.name = "pwrcl_pmux",
.parent_names = (const char *[]){
@@ -235,6 +261,7 @@ static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
.shift = 0,
.width = 2,
.pll = &perfcl_pll.clkr.hw,
+ .nb.notifier_call = cpu_clk_notifier_cb,
.clkr.hw.init = &(struct clk_init_data) {
.name = "perfcl_pmux",
.parent_names = (const char *[]){
@@ -310,6 +337,14 @@ struct clk_hw_clks {
clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
+ ret = clk_notifier_register(pwrcl_pmux.clkr.hw.clk, &pwrcl_pmux.nb);
+ if (ret)
+ return ret;
+
+ ret = clk_notifier_register(perfcl_pmux.clkr.hw.clk, &perfcl_pmux.nb);
+ if (ret)
+ return ret;
+
return ret;
}
--
1.9.1
^ permalink raw reply related
* [PATCH 04/10] clk: qcom: Add CPU clock driver for msm8996
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
From: Rajendra Nayak <rnayak@codeaurora.org>
Each of the CPU clusters (Power and Perf) on msm8996 are
clocked via 2 PLLs, a primary and alternate. There are also
2 Mux'es, a primary and secondary all connected together
as shown below
+-------+
XO | |
+------------------>0 |
| |
PLL/2 | SMUX +----+
+------->1 | |
| | | |
| +-------+ | +-------+
| +---->0 |
| | |
+---------------+ | +----------->1 | CPU clk
|Primary PLL +----+ PLL_EARLY | | +------>
| +------+-----------+ +------>2 PMUX |
+---------------+ | | | |
| +------+ | +-->3 |
+--^+ ACD +-----+ | +-------+
+---------------+ +------+ |
|Alt PLL | |
| +---------------------------+
+---------------+ PLL_EARLY
The primary PLL is what drives the CPU clk, except for times
when we are reprogramming the PLL itself (for rate changes) when
we temporarily switch to an alternate PLL. A subsequent patch adds
support to switch between primary and alternate PLL during rate
changes.
The primary PLL operates on a single VCO range, between 600Mhz
and 3Ghz. However the CPUs do support OPPs with frequencies
between 300Mhz and 600Mhz. In order to support running the CPUs
at those frequencies we end up having to lock the PLL at twice
the rate and drive the CPU clk via the PLL/2 output and SMUX.
So for frequencies above 600Mhz we follow the following path
Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
and for frequencies between 300Mhz and 600Mhz we follow
Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
Support for this is added in a subsequent patch as well.
ACD stands for Adaptive Clock Distribution and is used to
detect voltage droops. We do not add support for ACD as yet.
This can be added at a later point as needed.
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
.../devicetree/bindings/clock/qcom,kryocc.txt | 17 +
drivers/clk/qcom/Kconfig | 8 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/clk-cpu-8996.c | 388 +++++++++++++++++++++
4 files changed, 414 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/qcom,kryocc.txt
create mode 100644 drivers/clk/qcom/clk-cpu-8996.c
diff --git a/Documentation/devicetree/bindings/clock/qcom,kryocc.txt b/Documentation/devicetree/bindings/clock/qcom,kryocc.txt
new file mode 100644
index 0000000..c45de03
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/qcom,kryocc.txt
@@ -0,0 +1,17 @@
+Qualcomm CPUSS clock controller for Kryo CPUs
+----------------------------------------------------
+
+Required properties :
+- compatible : shall contain only one of the following:
+
+ "qcom,apcc-msm8996"
+
+- reg : shall contain base register location and length
+- #clock-cells : shall contain 1
+
+Example:
+ kryocc: clock-controller at 6400000 {
+ compatible = "qcom,apcc-msm8996";
+ reg = <0x6400000 0x90000>;
+ #clock-cells = <1>;
+ };
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 9f6c278..124fb9a4 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -196,3 +196,11 @@ config MSM_MMCC_8996
Support for the multimedia clock controller on msm8996 devices.
Say Y if you want to support multimedia devices such as display,
graphics, video encode/decode, camera, etc.
+
+config MSM_APCC_8996
+ tristate "MSM8996 CPU Clock Controller"
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the CPU clock controller on msm8996 devices.
+ Say Y if you want to support CPU clock scaling using CPUfreq
+ drivers for dyanmic power management.
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 26410d3..b964f43 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -32,5 +32,6 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8996) += mmcc-msm8996.o
+obj-$(CONFIG_MSM_APCC_8996) += clk-cpu-8996.o
obj-$(CONFIG_QCOM_CLK_RPM) += clk-rpm.o
obj-$(CONFIG_QCOM_CLK_SMD_RPM) += clk-smd-rpm.o
diff --git a/drivers/clk/qcom/clk-cpu-8996.c b/drivers/clk/qcom/clk-cpu-8996.c
new file mode 100644
index 0000000..bc60111
--- /dev/null
+++ b/drivers/clk/qcom/clk-cpu-8996.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2017, 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 <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include "clk-alpha-pll.h"
+
+#define VCO(a, b, c) { \
+ .val = a,\
+ .min_freq = b,\
+ .max_freq = c,\
+}
+
+#define DIV_2_INDEX 0
+#define PLL_INDEX 1
+#define ACD_INDEX 2
+#define ALT_INDEX 3
+
+/* PLLs */
+
+static const struct alpha_pll_config hfpll_config = {
+ .l = 60,
+ .config_ctl_val = 0x200d4828,
+ .config_ctl_hi_val = 0x006,
+ .pre_div_mask = BIT(12),
+ .post_div_mask = 0x3 << 8,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_pll = {
+ .offset = 0x80000,
+ .min_rate = 600000000,
+ .max_rate = 3000000000,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_16BIT_ALPHA
+ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "perfcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_pll = {
+ .offset = 0x0,
+ .min_rate = 600000000,
+ .max_rate = 3000000000,
+ .flags = SUPPORTS_DYNAMIC_UPDATE | SUPPORTS_16BIT_ALPHA
+ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pwrcl_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static const struct pll_vco alt_pll_vco_modes[] = {
+ VCO(3, 250000000, 500000000),
+ VCO(2, 500000000, 750000000),
+ VCO(1, 750000000, 1000000000),
+ VCO(0, 1000000000, 2150400000),
+};
+
+static const struct alpha_pll_config altpll_config = {
+ .l = 16,
+ .vco_val = 0x3 << 20,
+ .vco_mask = 0x3 << 20,
+ .config_ctl_val = 0x4001051b,
+ .post_div_mask = 0x3 << 8,
+ .post_div_val = 0x1,
+ .main_output_mask = BIT(0),
+ .early_output_mask = BIT(3),
+};
+
+static struct clk_alpha_pll perfcl_alt_pll = {
+ .offset = 0x80100,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+static struct clk_alpha_pll pwrcl_alt_pll = {
+ .offset = 0x100,
+ .vco_table = alt_pll_vco_modes,
+ .num_vco = ARRAY_SIZE(alt_pll_vco_modes),
+ .flags = SUPPORTS_OFFLINE_REQ | SUPPORTS_FSM_MODE,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_alt_pll",
+ .parent_names = (const char *[]){ "xo" },
+ .num_parents = 1,
+ .ops = &clk_alpha_pll_hwfsm_ops,
+ },
+};
+
+/* Mux'es */
+
+struct clk_cpu_8996_mux {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct clk_hw *pll;
+ struct clk_regmap clkr;
+};
+
+static inline
+struct clk_cpu_8996_mux *to_clk_cpu_8996_mux_hw(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_cpu_8996_mux, clkr);
+}
+
+static u8 clk_cpu_8996_mux_get_parent(struct clk_hw *hw)
+{
+ unsigned int val;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ unsigned int mask = GENMASK(cpuclk->width - 1, 0);
+
+ regmap_read(clkr->regmap, cpuclk->reg, &val);
+
+ val >>= cpuclk->shift;
+ val &= mask;
+
+ return val;
+}
+
+static int clk_cpu_8996_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ unsigned int val;
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ unsigned int mask = GENMASK(cpuclk->width + cpuclk->shift - 1,
+ cpuclk->shift);
+
+ val = index;
+ val = cpuclk->shift;
+
+ return regmap_update_bits(clkr->regmap, cpuclk->reg, mask, val);
+}
+
+static int
+clk_cpu_8996_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ struct clk_cpu_8996_mux *cpuclk = to_clk_cpu_8996_mux_hw(hw);
+ struct clk_hw *parent = cpuclk->pll;
+
+ if (!cpuclk->pll)
+ return -EINVAL;
+
+ req->best_parent_rate = clk_hw_round_rate(parent, req->rate);
+ req->best_parent_hw = parent;
+
+ return 0;
+}
+
+const struct clk_ops clk_cpu_8996_mux_ops = {
+ .set_parent = clk_cpu_8996_mux_set_parent,
+ .get_parent = clk_cpu_8996_mux_get_parent,
+ .determine_rate = clk_cpu_8996_mux_determine_rate,
+};
+
+static struct clk_cpu_8996_mux pwrcl_smux = {
+ .reg = 0x40,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "pwrcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_smux = {
+ .reg = 0x80040,
+ .shift = 2,
+ .width = 2,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_smux",
+ .parent_names = (const char *[]){
+ "xo",
+ "perfcl_pll_main",
+ },
+ .num_parents = 2,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux pwrcl_pmux = {
+ .reg = 0x40,
+ .shift = 0,
+ .width = 2,
+ .pll = &pwrcl_pll.clkr.hw,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "pwrcl_pmux",
+ .parent_names = (const char *[]){
+ "pwrcl_smux",
+ "pwrcl_pll",
+ "pwrcl_pll_acd",
+ "pwrcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_cpu_8996_mux perfcl_pmux = {
+ .reg = 0x80040,
+ .shift = 0,
+ .width = 2,
+ .pll = &perfcl_pll.clkr.hw,
+ .clkr.hw.init = &(struct clk_init_data) {
+ .name = "perfcl_pmux",
+ .parent_names = (const char *[]){
+ "perfcl_smux",
+ "perfcl_pll",
+ "pwrcl_pll_acd",
+ "perfcl_alt_pll",
+ },
+ .num_parents = 4,
+ .ops = &clk_cpu_8996_mux_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct regmap_config cpu_msm8996_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0x80210,
+ .fast_io = true,
+ .val_format_endian = REGMAP_ENDIAN_LITTLE,
+};
+
+static const struct of_device_id match_table[] = {
+ { .compatible = "qcom,apcc-msm8996" },
+ {}
+};
+
+struct clk_regmap *clks[] = {
+ /* PLLs */
+ &perfcl_pll.clkr,
+ &pwrcl_pll.clkr,
+ &perfcl_alt_pll.clkr,
+ &pwrcl_alt_pll.clkr,
+ /* MUXs */
+ &perfcl_smux.clkr,
+ &pwrcl_smux.clkr,
+ &perfcl_pmux.clkr,
+ &pwrcl_pmux.clkr,
+};
+
+struct clk_hw_clks {
+ unsigned int num;
+ struct clk_hw *hws[];
+};
+
+static int
+qcom_cpu_clk_msm8996_register_clks(struct device *dev, struct clk_hw_clks *hws,
+ struct regmap *regmap)
+{
+ int i, ret;
+
+ hws->hws[0] = clk_hw_register_fixed_factor(dev, "perfcl_pll_main",
+ "perfcl_pll",
+ CLK_SET_RATE_PARENT, 1, 2);
+ perfcl_smux.pll = hws->hws[0];
+
+ hws->hws[1] = clk_hw_register_fixed_factor(dev, "pwrcl_pll_main",
+ "pwrcl_pll",
+ CLK_SET_RATE_PARENT, 1, 2);
+ pwrcl_smux.pll = hws->hws[1];
+
+ hws->num = 2;
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ ret = devm_clk_register_regmap(dev, clks[i]);
+ if (ret)
+ return ret;
+ }
+
+ clk_alpha_pll_configure(&perfcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&pwrcl_pll, regmap, &hfpll_config);
+ clk_alpha_pll_configure(&perfcl_alt_pll, regmap, &altpll_config);
+ clk_alpha_pll_configure(&pwrcl_alt_pll, regmap, &altpll_config);
+
+ return ret;
+}
+
+static int qcom_cpu_clk_msm8996_driver_probe(struct platform_device *pdev)
+{
+ int ret;
+ void __iomem *base;
+ struct resource *res;
+ struct regmap *regmap_cpu;
+ struct clk_hw_clks *hws;
+ struct clk_hw_onecell_data *data;
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+
+ data = devm_kzalloc(dev, sizeof(*data) + 2 * sizeof(struct clk_hw *),
+ GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ hws = devm_kzalloc(dev, sizeof(*hws) + 2 * sizeof(struct clk_hw *),
+ GFP_KERNEL);
+ if (!hws)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ regmap_cpu = devm_regmap_init_mmio(dev, base,
+ &cpu_msm8996_regmap_config);
+ if (IS_ERR(regmap_cpu))
+ return PTR_ERR(regmap_cpu);
+
+ ret = qcom_cpu_clk_msm8996_register_clks(dev, hws, regmap_cpu);
+ if (ret)
+ return ret;
+
+ data->hws[0] = &pwrcl_pmux.clkr.hw;
+ data->hws[1] = &perfcl_pmux.clkr.hw;
+
+ data->num = 2;
+
+ platform_set_drvdata(pdev, hws);
+
+ return of_clk_add_hw_provider(node, of_clk_hw_onecell_get, data);
+}
+
+static int qcom_cpu_clk_msm8996_driver_remove(struct platform_device *pdev)
+{
+ int i;
+ struct device *dev = &pdev->dev;
+ struct clk_hw_clks *hws = platform_get_drvdata(pdev);
+
+ for (i = 0; i < hws->num; i++)
+ clk_hw_unregister_fixed_rate(hws->hws[i]);
+
+ of_clk_del_provider(dev->of_node);
+
+ return 0;
+}
+
+static struct platform_driver qcom_cpu_clk_msm8996_driver = {
+ .probe = qcom_cpu_clk_msm8996_driver_probe,
+ .remove = qcom_cpu_clk_msm8996_driver_remove,
+ .driver = {
+ .name = "qcom-apcc-msm8996",
+ .of_match_table = match_table,
+ },
+};
+
+module_platform_driver(qcom_cpu_clk_msm8996_driver);
+
+MODULE_ALIAS("platform:apcc-msm8996");
+MODULE_DESCRIPTION("QCOM MSM8996 CPU clock Driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH 03/10] clk: qcom: Make clk_alpha_pll_configure available to modules
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
From: Rajendra Nayak <rnayak@codeaurora.org>
Allow clk_alpha_pll_configure to be called from loadable
kernel modules.
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
drivers/clk/qcom/clk-alpha-pll.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index ecb9e7f..7b06e21 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -141,6 +141,7 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
if (pll->flags & SUPPORTS_FSM_MODE)
qcom_pll_set_fsm_mode(regmap, off + PLL_MODE, 6, 0);
}
+EXPORT_SYMBOL_GPL(clk_alpha_pll_configure);
static int clk_alpha_pll_hwfsm_enable(struct clk_hw *hw)
{
--
1.9.1
^ permalink raw reply related
* [PATCH 02/10] clk: qcom: Fix .set_rate to handle alpha PLLs w/wo dynamic update
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
From: Taniya Das <tdas@codeaurora.org>
From: Taniya Das <tdas@codeaurora.org>
Alpha PLLs which do not support dynamic update feature
need to be explicitly disabled before a rate change.
The ones which do support dynamic update do so within a
single vco range, so add a min/max freq check for such
PLLs so they fall in the vco range.
Signed-off-by: Taniya Das <tdas@codeaurora.org>
Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
drivers/clk/qcom/clk-alpha-pll.c | 71 +++++++++++++++++++++++++++++++++-------
drivers/clk/qcom/clk-alpha-pll.h | 5 +++
2 files changed, 65 insertions(+), 11 deletions(-)
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c
index 47a1da3..ecb9e7f 100644
--- a/drivers/clk/qcom/clk-alpha-pll.c
+++ b/drivers/clk/qcom/clk-alpha-pll.c
@@ -376,19 +376,46 @@ static unsigned long alpha_pll_calc_rate(u64 prate, u32 l, u32 a)
return alpha_pll_calc_rate(prate, l, a);
}
-static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long prate)
+static int alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate,
+ int (*enable)(struct clk_hw *hw),
+ void (*disable)(struct clk_hw *hw))
{
+ bool enabled;
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
const struct pll_vco *vco;
u32 l, off = pll->offset;
u64 a;
rate = alpha_pll_round_rate(rate, prate, &l, &a);
- vco = alpha_pll_find_vco(pll, rate);
- if (!vco) {
- pr_err("alpha pll not in a valid vco range\n");
- return -EINVAL;
+ enabled = clk_hw_is_enabled(hw);
+
+ if (pll->flags & SUPPORTS_DYNAMIC_UPDATE) {
+ /*
+ * PLLs which support dynamic updates support one single
+ * vco range, between min_rate and max_rate supported
+ */
+ if (rate < pll->min_rate || rate > pll->max_rate) {
+ pr_err("alpha pll rate outside supported min/max range\n");
+ return -EINVAL;
+ }
+ } else {
+ /*
+ * All alpha PLLs which do not support dynamic update,
+ * should be disabled before a vco update.
+ */
+ if (enabled)
+ disable(hw);
+
+ vco = alpha_pll_find_vco(pll, rate);
+ if (!vco) {
+ pr_err("alpha pll not in a valid vco range\n");
+ return -EINVAL;
+ }
+
+ regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL,
+ PLL_VCO_MASK << PLL_VCO_SHIFT,
+ vco->val << PLL_VCO_SHIFT);
}
regmap_write(pll->clkr.regmap, off + PLL_L_VAL, l);
@@ -401,16 +428,29 @@ static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
regmap_write(pll->clkr.regmap, off + PLL_ALPHA_VAL_U, a >> 32);
}
- regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL,
- PLL_VCO_MASK << PLL_VCO_SHIFT,
- vco->val << PLL_VCO_SHIFT);
-
regmap_update_bits(pll->clkr.regmap, off + PLL_USER_CTL, PLL_ALPHA_EN,
PLL_ALPHA_EN);
+ if (!(pll->flags & SUPPORTS_DYNAMIC_UPDATE) && enabled)
+ enable(hw);
+
return 0;
}
+static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ return alpha_pll_set_rate(hw, rate, prate, clk_alpha_pll_enable,
+ clk_alpha_pll_disable);
+}
+
+static int clk_alpha_pll_hwfsm_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long prate)
+{
+ return alpha_pll_set_rate(hw, rate, prate, clk_alpha_pll_hwfsm_enable,
+ clk_alpha_pll_hwfsm_disable);
+}
+
static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
@@ -420,6 +460,15 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long min_freq, max_freq;
rate = alpha_pll_round_rate(rate, *prate, &l, &a);
+
+ if (pll->flags & SUPPORTS_DYNAMIC_UPDATE) {
+ if (rate < pll->min_rate)
+ rate = pll->min_rate;
+ else if (rate > pll->max_rate)
+ rate = pll->max_rate;
+ return rate;
+ }
+
if (alpha_pll_find_vco(pll, rate))
return rate;
@@ -445,7 +494,7 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
.is_enabled = clk_alpha_pll_hwfsm_is_enabled,
.recalc_rate = clk_alpha_pll_recalc_rate,
.round_rate = clk_alpha_pll_round_rate,
- .set_rate = clk_alpha_pll_set_rate,
+ .set_rate = clk_alpha_pll_hwfsm_set_rate,
};
EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);
diff --git a/drivers/clk/qcom/clk-alpha-pll.h b/drivers/clk/qcom/clk-alpha-pll.h
index d6e1ee2..7aaa11c 100644
--- a/drivers/clk/qcom/clk-alpha-pll.h
+++ b/drivers/clk/qcom/clk-alpha-pll.h
@@ -27,6 +27,8 @@ struct pll_vco {
* struct clk_alpha_pll - phase locked loop (PLL)
* @offset: base address of registers
* @vco_table: array of VCO settings
+ * @min_rate: Minimim rate for PLLs with single VCO range
+ * @max_rate: Maximun rate for PLLs with single VCO range
* @clkr: regmap clock handle
*/
struct clk_alpha_pll {
@@ -37,8 +39,11 @@ struct clk_alpha_pll {
#define SUPPORTS_OFFLINE_REQ BIT(0)
#define SUPPORTS_16BIT_ALPHA BIT(1)
#define SUPPORTS_FSM_MODE BIT(2)
+#define SUPPORTS_DYNAMIC_UPDATE BIT(3)
u8 flags;
+ unsigned long min_rate;
+ unsigned long max_rate;
struct clk_regmap clkr;
};
--
1.9.1
^ permalink raw reply related
* [PATCH 01/10] soc: qcom: Separate kryo l2 accessors from PMU driver
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513081897-31612-1-git-send-email-ilialin@codeaurora.org>
The driver provides kernel level API for other drivers
to access the MSM8996 L2 cache registers.
Separating the L2 access code from the PMU driver and
making it public to allow other drivers use it.
The accesses must be separated with a single spinlock,
maintained in this driver.
Signed-off-by: Ilia Lin <ilialin@codeaurora.org>
---
arch/arm64/Kconfig.platforms | 7 ++++
drivers/perf/qcom_l2_pmu.c | 48 +--------------------------
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/kryo-l2-accessors.c | 64 ++++++++++++++++++++++++++++++++++++
include/soc/qcom/kryo-l2-accessors.h | 27 +++++++++++++++
5 files changed, 100 insertions(+), 47 deletions(-)
create mode 100644 drivers/soc/qcom/kryo-l2-accessors.c
create mode 100644 include/soc/qcom/kryo-l2-accessors.h
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 2401373..a6a6504 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -144,6 +144,13 @@ config ARCH_REALTEK
This enables support for the ARMv8 based Realtek chipsets,
like the RTD1295.
+config ARCH_MSM8996
+ bool "Enable Support for Qualcomm Technologies, Inc. MSM8996"
+ depends on ARCH_QCOM
+ help
+ This enables support for the MSM8996 chipset. If you do not
+ wish to build a kernel that runs on this chipset, say 'N' here.
+
config ARCH_ROCKCHIP
bool "Rockchip Platforms"
select ARCH_HAS_RESET_CONTROLLER
diff --git a/drivers/perf/qcom_l2_pmu.c b/drivers/perf/qcom_l2_pmu.c
index 4fdc848..ba5f241 100644
--- a/drivers/perf/qcom_l2_pmu.c
+++ b/drivers/perf/qcom_l2_pmu.c
@@ -30,7 +30,7 @@
#include <asm/barrier.h>
#include <asm/local64.h>
-#include <asm/sysreg.h>
+#include <soc/qcom/kryo-l2-accessors.h>
#define MAX_L2_CTRS 9
@@ -87,9 +87,6 @@
#define L2_COUNTER_RELOAD BIT_ULL(31)
#define L2_CYCLE_COUNTER_RELOAD BIT_ULL(63)
-#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
-#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
-
#define reg_idx(reg, i) (((i) * IA_L2_REG_OFFSET) + reg##_BASE)
/*
@@ -107,49 +104,6 @@
#define L2_EVENT_STREX 0x421
#define L2_EVENT_CLREX 0x422
-static DEFINE_RAW_SPINLOCK(l2_access_lock);
-
-/**
- * set_l2_indirect_reg: write value to an L2 register
- * @reg: Address of L2 register.
- * @value: Value to be written to register.
- *
- * Use architecturally required barriers for ordering between system register
- * accesses
- */
-static void set_l2_indirect_reg(u64 reg, u64 val)
-{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&l2_access_lock, flags);
- write_sysreg_s(reg, L2CPUSRSELR_EL1);
- isb();
- write_sysreg_s(val, L2CPUSRDR_EL1);
- isb();
- raw_spin_unlock_irqrestore(&l2_access_lock, flags);
-}
-
-/**
- * get_l2_indirect_reg: read an L2 register value
- * @reg: Address of L2 register.
- *
- * Use architecturally required barriers for ordering between system register
- * accesses
- */
-static u64 get_l2_indirect_reg(u64 reg)
-{
- u64 val;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&l2_access_lock, flags);
- write_sysreg_s(reg, L2CPUSRSELR_EL1);
- isb();
- val = read_sysreg_s(L2CPUSRDR_EL1);
- raw_spin_unlock_irqrestore(&l2_access_lock, flags);
-
- return val;
-}
-
struct cluster_pmu;
/*
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index 40c56f6..2bf8d93 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o
obj-$(CONFIG_QCOM_SMP2P) += smp2p.o
obj-$(CONFIG_QCOM_SMSM) += smsm.o
obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o
+obj-$(CONFIG_ARCH_MSM8996) += kryo-l2-accessors.o
diff --git a/drivers/soc/qcom/kryo-l2-accessors.c b/drivers/soc/qcom/kryo-l2-accessors.c
new file mode 100644
index 0000000..6be57e6
--- /dev/null
+++ b/drivers/soc/qcom/kryo-l2-accessors.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014-2015, 2017, 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 <linux/spinlock.h>
+#include <asm/sysreg.h>
+#include <soc/qcom/kryo-l2-accessors.h>
+
+#define L2CPUSRSELR_EL1 sys_reg(3, 3, 15, 0, 6)
+#define L2CPUSRDR_EL1 sys_reg(3, 3, 15, 0, 7)
+
+static DEFINE_RAW_SPINLOCK(l2_access_lock);
+
+/**
+ * set_l2_indirect_reg: write value to an L2 register
+ * @reg: Address of L2 register.
+ * @value: Value to be written to register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+void set_l2_indirect_reg(u64 reg, u64 val)
+{
+ unsigned long flags;
+ mb();
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ write_sysreg_s(val, L2CPUSRDR_EL1);
+ isb();
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+}
+EXPORT_SYMBOL(set_l2_indirect_reg);
+
+/**
+ * get_l2_indirect_reg: read an L2 register value
+ * @reg: Address of L2 register.
+ *
+ * Use architecturally required barriers for ordering between system register
+ * accesses, and system registers with respect to device memory
+ */
+u64 get_l2_indirect_reg(u64 reg)
+{
+ u64 val;
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&l2_access_lock, flags);
+ write_sysreg_s(reg, L2CPUSRSELR_EL1);
+ isb();
+ val = read_sysreg_s(L2CPUSRDR_EL1);
+ raw_spin_unlock_irqrestore(&l2_access_lock, flags);
+
+ return val;
+}
+EXPORT_SYMBOL(get_l2_indirect_reg);
diff --git a/include/soc/qcom/kryo-l2-accessors.h b/include/soc/qcom/kryo-l2-accessors.h
new file mode 100644
index 0000000..2bebce1
--- /dev/null
+++ b/include/soc/qcom/kryo-l2-accessors.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2017, 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 __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+#define __ASM_ARCH_MSM_MSM_KRYO_L2_ACCESSORS_H
+
+#ifdef CONFIG_ARCH_QCOM
+void set_l2_indirect_reg(u64 reg_addr, u64 val);
+u64 get_l2_indirect_reg(u64 reg_addr);
+#else
+static inline void set_l2_indirect_reg(u32 reg_addr, u32 val) {}
+static inline u32 get_l2_indirect_reg(u32 reg_addr)
+{
+ return 0;
+}
+#endif
+#endif
--
1.9.1
^ permalink raw reply related
* [PATCH 00/10] clk: qcom: CPU clock driver for msm8996
From: Ilia Lin @ 2017-12-12 12:31 UTC (permalink / raw)
To: linux-arm-kernel
This series adds support for the CPU clocks on msm8996 devices.
A previous post of RFC can be found here
https://patchwork.kernel.org/patch/9662917/
Ilia Lin (5):
soc: qcom: Separate kryo l2 accessors from PMU driver
clk: qcom: clk-cpu-8996: Prepare PLLs on probe
clk: qcom: Add ACD path to CPU clock driver for msm8996
DT: QCOM: Add cpufreq-dt to msm8996
DT: QCOM: Add thermal mitigation to msm8996
Rajendra Nayak (4):
clk: qcom: Make clk_alpha_pll_configure available to modules
clk: qcom: Add CPU clock driver for msm8996
clk: qcom: cpu-8996: Add support to switch to alternate PLL
clk: qcom: cpu-8996: Add support to switch below 600Mhz
Taniya Das (1):
clk: qcom: Fix .set_rate to handle alpha PLLs w/wo dynamic update
.../devicetree/bindings/clock/qcom,kryocc.txt | 17 +
arch/arm64/Kconfig.platforms | 7 +
arch/arm64/boot/dts/qcom/apq8096-db820c.dts | 2 +-
arch/arm64/boot/dts/qcom/msm8996.dtsi | 282 ++++++++++-
drivers/clk/qcom/Kconfig | 8 +
drivers/clk/qcom/Makefile | 1 +
drivers/clk/qcom/clk-alpha-pll.c | 72 ++-
drivers/clk/qcom/clk-alpha-pll.h | 5 +
drivers/clk/qcom/clk-cpu-8996.c | 542 +++++++++++++++++++++
drivers/cpufreq/cpufreq-dt-platdev.c | 3 +
drivers/perf/qcom_l2_pmu.c | 48 +-
drivers/soc/qcom/Makefile | 1 +
drivers/soc/qcom/kryo-l2-accessors.c | 64 +++
include/soc/qcom/kryo-l2-accessors.h | 27 +
14 files changed, 1009 insertions(+), 70 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/qcom,kryocc.txt
create mode 100644 drivers/clk/qcom/clk-cpu-8996.c
create mode 100644 drivers/soc/qcom/kryo-l2-accessors.c
create mode 100644 include/soc/qcom/kryo-l2-accessors.h
--
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
--
1.9.1
^ permalink raw reply
* [PATCH 02/41] drm/rockchip: Get rid of some unnecessary code
From: Heiko Stuebner @ 2017-12-12 12:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20170310043305.17216-3-seanpaul@chromium.org>
Am Donnerstag, 9. M?rz 2017, 23:32:17 CET schrieb Sean Paul:
> From: Tomasz Figa <tfiga@chromium.org>
>
> Current code implements prepare_fb and cleanup_fb callbacks only to
> grab/release fb references, which is already done by atomic framework
> when creating/destryoing plane state. Also there are some unused fields
> vop and vop_win structs. Let's remove these unused bits.
>
> Signed-off-by: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
There seems to be a slight discrepancy between patch message and code.
The commit message talks about *_fb-callbacks, while the patch removes
a seemingly unsused mutex, which I guess falls under the "some unused fields"
part.
In any case, I didn't see any ill effects when testing this patch, so
Tested-by: Heiko Stuebner <heiko@sntech.de>
> ---
> drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 -----
> 1 file changed, 5 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index 2151e1cee4b4..0539afb6b7c8 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -108,9 +108,6 @@ struct vop {
> struct drm_device *drm_dev;
> bool is_enabled;
>
> - /* mutex vsync_ work */
> - struct mutex vsync_mutex;
> - bool vsync_work_pending;
> struct completion dsp_hold_completion;
>
> /* protected by dev->event_lock */
> @@ -1592,8 +1589,6 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
> spin_lock_init(&vop->reg_lock);
> spin_lock_init(&vop->irq_lock);
>
> - mutex_init(&vop->vsync_mutex);
> -
> ret = devm_request_irq(dev, vop->irq, vop_isr,
> IRQF_SHARED, dev_name(dev), vop);
> if (ret)
>
^ permalink raw reply
* [PATCH 01/12] KVM: arm/arm64: vgic: Remove spurious call to kern_hyp_va
From: Steve Capper @ 2017-12-12 11:53 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <d8a26134-52e2-0800-542f-603c6e8347c7@arm.com>
On Mon, Dec 04, 2017 at 02:30:28PM +0000, Suzuki K Poulose wrote:
> On 04/12/17 14:13, Steve Capper wrote:
> > In save_elrsr(.), we use the following technique to ascertain the
> > address of the vgic global state:
> > (kern_hyp_va(&kvm_vgic_global_state))->nr_lr
> >
> > For arm, kern_hyp_va(va) == va, and this call effectively compiles out.
> >
> > For arm64, this call can be spurious as the address of kvm_vgic_global_state
> > will usually be determined by relative page/absolute page offset relocation
> > at link time. As the function is idempotent, having the call for arm64 does
> > not cause any problems.
> >
> > Unfortunately, this is about to change for arm64 as we need to change
> > the logic of kern_hyp_va to allow for kernel addresses that are outside
> > the direct linear map.
> >
> > This patch removes the call to kern_hyp_va, and ensures that correct
> > HYP addresses are computed via relative page offset addressing on arm64.
> > This is achieved by a custom accessor, hyp_address(.), which on arm is a
> > simple reference operator.
>
> minor nit: I somehow feel that there word "symbol" should be part of the name of
> the macro, to make it implicit that it can only be used on a symbol and not any
> generic variable.
>
> > diff --git a/arch/arm64/include/asm/kvm_hyp.h b/arch/arm64/include/asm/kvm_hyp.h
> > index 08d3bb66c8b7..34a4ae906a97 100644
> > --- a/arch/arm64/include/asm/kvm_hyp.h
> > +++ b/arch/arm64/include/asm/kvm_hyp.h
> > @@ -25,6 +25,16 @@
> > #define __hyp_text __section(.hyp.text) notrace
> > +#define hyp_address(symbol) \
> > +({ \
> > + typeof(&symbol) __ret; \
> > + asm volatile( \
> > + "adrp %[ptr], " #symbol "\n" \
> > + "add %[ptr], %[ptr], :lo12:" #symbol "\n" \
> > + : [ptr] "=r"(__ret)); \
> > + __ret; \
> > +})
> > +
>
> > - addr = kern_hyp_va((kern_hyp_va(&kvm_vgic_global_state))->vcpu_base_va);
> > + addr = kern_hyp_va(hyp_address(kvm_vgic_global_state)->vcpu_base_va);
>
> e.g, Like here, why do we use hyp_address only for the kvm_vgic_global_state and not
> the dereferenced value. Having a name, say, hyp_symbol_address() makes it clear.
>
> Otherwise, looks good to me.
>
Thanks Suzuki,
Marc Zyngier has a similar patch in his series:
KVM/arm64: Randomise EL2 mappings
I'll refactor my series to apply on top of Marc's
(and take advantage of the simiplified HYP logic)
Cheers,
--
Steve
^ permalink raw reply
* [PATCH v10 1/3] ACPI/IORT: Add msi address regions reservation helper
From: Shameerali Kolothum Thodi @ 2017-12-12 11:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20171211144504.GA4123@red-moon>
> -----Original Message-----
> From: Lorenzo Pieralisi [mailto:lorenzo.pieralisi at arm.com]
> Sent: Monday, December 11, 2017 2:45 PM
> To: Shameerali Kolothum Thodi <shameerali.kolothum.thodi@huawei.com>
> Cc: will.deacon at arm.com; robin.murphy at arm.com; marc.zyngier at arm.com;
> joro at 8bytes.org; John Garry <john.garry@huawei.com>; xuwei (O)
> <xuwei5@hisilicon.com>; Guohanjun (Hanjun Guo) <guohanjun@huawei.com>;
> iommu at lists.linux-foundation.org; linux-arm-kernel at lists.infradead.org; linux-
> acpi at vger.kernel.org; devicetree at vger.kernel.org; Linuxarm
> <linuxarm@huawei.com>
> Subject: Re: [PATCH v10 1/3] ACPI/IORT: Add msi address regions reservation
> helper
>
> On Wed, Nov 29, 2017 at 02:14:47PM +0000, Shameer Kolothum wrote:
> > On some platforms msi parent address regions have to be excluded from
> > normal IOVA allocation in that they are detected and decoded in a HW
> > specific way by system components and so they cannot be considered normal
> > IOVA address space.
> >
> > Add a helper function that retrieves ITS address regions - the msi
> > parent - through IORT device <-> ITS mappings and reserves it so that
> > these regions will not be translated by IOMMU and will be excluded from
> > IOVA allocations. The function checks for the smmu model number and
> > only applies the msi reservation if the platform requires it.
> >
> > Signed-off-by: Shameer Kolothum <shameerali.kolothum.thodi@huawei.com>
> > ---
> > drivers/acpi/arm64/iort.c | 133
> ++++++++++++++++++++++++++++++++++++++-
> > drivers/irqchip/irq-gic-v3-its.c | 3 +-
> > include/linux/acpi_iort.h | 7 ++-
> > 3 files changed, 138 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> > index 95255ec..1c5fc36 100644
> > --- a/drivers/acpi/arm64/iort.c
> > +++ b/drivers/acpi/arm64/iort.c
> > @@ -39,6 +39,7 @@
> > struct iort_its_msi_chip {
> > struct list_head list;
> > struct fwnode_handle *fw_node;
> > + phys_addr_t base_addr;
> > u32 translation_id;
> > };
> >
> > @@ -161,14 +162,16 @@ typedef acpi_status (*iort_find_node_callback)
> > static DEFINE_SPINLOCK(iort_msi_chip_lock);
> >
> > /**
> > - * iort_register_domain_token() - register domain token and related ITS ID
> > - * to the list from where we can get it back later on.
> > + * iort_register_domain_token() - register domain token along with related
> > + * ITS ID and base address to the list from where we can get it back later on.
> > * @trans_id: ITS ID.
> > + * @base: ITS base address.
> > * @fw_node: Domain token.
> > *
> > * Returns: 0 on success, -ENOMEM if no memory when allocating list
> element
> > */
> > -int iort_register_domain_token(int trans_id, struct fwnode_handle
> *fw_node)
> > +int iort_register_domain_token(int trans_id, phys_addr_t base,
> > + struct fwnode_handle *fw_node)
> > {
> > struct iort_its_msi_chip *its_msi_chip;
> >
> > @@ -178,6 +181,7 @@ int iort_register_domain_token(int trans_id, struct
> fwnode_handle *fw_node)
> >
> > its_msi_chip->fw_node = fw_node;
> > its_msi_chip->translation_id = trans_id;
> > + its_msi_chip->base_addr = base;
> >
> > spin_lock(&iort_msi_chip_lock);
> > list_add(&its_msi_chip->list, &iort_msi_chip_list);
> > @@ -581,6 +585,24 @@ int iort_pmsi_get_dev_id(struct device *dev, u32
> *dev_id)
> > return -ENODEV;
> > }
> >
> > +static int __maybe_unused iort_find_its_base(u32 its_id, phys_addr_t *base)
> > +{
> > + struct iort_its_msi_chip *its_msi_chip;
> > + bool match = false;
> > +
> > + spin_lock(&iort_msi_chip_lock);
> > + list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
> > + if (its_msi_chip->translation_id == its_id) {
> > + *base = its_msi_chip->base_addr;
> > + match = true;
> > + break;
> > + }
> > + }
> > + spin_unlock(&iort_msi_chip_lock);
> > +
> > + return match ? 0 : -ENODEV;
>
> Nit: if you need to return an int, use it as the "match" variable,
> there is no point in using a bool.
>
> int ret = -ENODEV;
>
> if (its_msi_chip->translation_id == its_id) {
> ...
> ret = 0;
> break;
> }
>
> return ret;
>
> > +}
> > +
> > /**
> > * iort_dev_find_its_id() - Find the ITS identifier for a device
> > * @dev: The device.
> > @@ -740,6 +762,38 @@ static int __maybe_unused __get_pci_rid(struct
> pci_dev *pdev, u16 alias,
> > return 0;
> > }
> >
> > +static bool __maybe_unused iort_hw_msi_resv_enable(struct device *dev,
> > + struct acpi_iort_node *node)
> > +{
> > + struct iort_fwnode *curr;
> > + struct acpi_iort_node *iommu = NULL;
> > + struct iommu_fwspec *fwspec = dev->iommu_fwspec;
> > +
> > + if (WARN_ON(!fwspec || !fwspec->iommu_fwnode))
>
> Remove WARN_ON() here, it seems excessive.
>
> > + return false;
> > +
> > + spin_lock(&iort_fwnode_lock);
> > + list_for_each_entry(curr, &iort_fwnode_list, list) {
> > + if (curr->fwnode == fwspec->iommu_fwnode) {
> > + iommu = curr->iort_node;
> > + break;
> > + }
> > + }
> > + spin_unlock(&iort_fwnode_lock);
>
> iort_get_iort_node() ?
>
> > + if (iommu && (iommu->type == ACPI_IORT_NODE_SMMU_V3)) {
> > + struct acpi_iort_smmu_v3 *smmu;
> > +
> > + smmu = (struct acpi_iort_smmu_v3 *)iommu->node_data;
> > + if (smmu->model ==
> ACPI_IORT_SMMU_V3_HISILICON_HI161X) {
> > + dev_notice(dev, "Enabling HiSilicon erratum
> 161010801\n");
> > + return true;
> > + }
> > + }
> > +
> > + return false;
> > +}
> > +
> > static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
> > struct fwnode_handle *fwnode,
> > const struct iommu_ops *ops)
> > @@ -782,6 +836,77 @@ static inline int iort_add_device_replay(const struct
> iommu_ops *ops,
> >
> > return err;
> > }
> > +
> > +/**
> > + * iort_iommu_msi_get_resv_regions - Reserved region driver helper
> > + * @dev: Device from iommu_get_resv_regions()
> > + * @head: Reserved region list from iommu_get_resv_regions()
> > + *
> > + * Returns: Number of msi reserved regions on success (0 if platform
> > + * doesn't require the reservation or no associated msi regions),
> > + * appropriate error value otherwise. The ITS interrupt translation
> > + * space (ITS_base + 0x010000) associated with the device are the
> > + * msi reserved regions.
> > + */
> > +int iort_iommu_msi_get_resv_regions(struct device *dev, struct list_head
> *head)
> > +{
> > + struct acpi_iort_its_group *its;
> > + struct acpi_iort_node *node, *its_node = NULL;
> > + int i, resv = 0;
> > +
> > + node = iort_find_dev_node(dev);
> > + if (!node)
> > + return -ENODEV;
>
> You may not need node, see below.
>
> > + if (!iort_hw_msi_resv_enable(dev, node))
>
> node is passed but effectively not used by the function.
>
> > + return 0;
> > +
> > + /*
> > + * Current logic to reserve ITS regions relies on HW topologies
> > + * where a given PCI or named component maps its IDs to only one
> > + * ITS group; if a PCI or named component can map its IDs to
> > + * different ITS groups through IORT mappings this function has
> > + * to be reworked to ensure we reserve regions for all ITS groups
> > + * a given PCI or named component may map IDs to.
> > + */
> > + if (dev_is_pci(dev)) {
> > + u32 rid;
> > +
> > + pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid, &rid);
> > + its_node = iort_node_map_id(node, rid, NULL,
> IORT_MSI_TYPE);
> > + } else {
> > + for (i = 0; i < node->mapping_count; i++) {
> > + its_node = iort_node_map_platform_id(node, NULL,
> > + IORT_MSI_TYPE, i);
> > + if (its_node)
> > + break;
> > + }
> > + }
>
> Ok. So, how about doing:
>
> for (i = 0; i < dev->iommu_fwspec->num_ids; i++) {
> its_node = iort_node_map_id(iommu_iort_node, dev->iommu_fwspec-
> >ids[i],
> NULL, IORT_MSI_TYPE);
> if (its_node)
> break;
> }
>
> which removes the need for dev_is_pci() check and simplifies a bit, is
> there any issue with that ?
>
> iommu_iort_node can be returned by iort_hw_msi_resv_enable(), that
> you can rename accordingly.
Thanks Lorenzo. I will address the comments and send the revised patch
after testing.
Much appreciated,
Shameer
^ permalink raw reply
* [PATCH 2/2] ARM: dts: vf610-zii-dev: use XAUI for DSA link ports
From: Andrew Lunn @ 2017-12-12 11:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <E1eOgsp-0001Ab-9x@rmk-PC.armlinux.org.uk>
On Tue, Dec 12, 2017 at 09:29:51AM +0000, Russell King wrote:
> Use XAUI rather than XGMII for DSA link ports, as this is the interface
> mode that the switches actually use. XAUI is the 4 lane bus with clock
> per direction, whereas XGMII is a 32 bit bus with clock.
>
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* [PATCH 1/2] net: dsa: allow XAUI phy interface mode
From: Andrew Lunn @ 2017-12-12 11:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <E1eOgsk-0001AU-5z@rmk-PC.armlinux.org.uk>
On Tue, Dec 12, 2017 at 09:29:46AM +0000, Russell King wrote:
> XGMII is a 32-bit bus plus two clock signals per direction. XAUI is
> four serial lanes per direction. The 88e6190 supports XAUI but not
> XGMII as it doesn't have enough pins. The same is true of 88e6176.
>
> Match on PHY_INTERFACE_MODE_XAUI for the XAUI port type, but keep
> accepting XGMII for backwards compatibility.
>
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* [PATCH] arm64: mm: Fix false positives in set_pte_at access/dirty race detection
From: Will Deacon @ 2017-12-12 11:43 UTC (permalink / raw)
To: linux-arm-kernel
Jiankang reports that our race detection in set_pte_at is firing when
copying the page tables in dup_mmap as a result of a fork(). In this
situation, the page table isn't actually live and so there is no way
that we can race with a concurrent update from the hardware page table
walker.
This patch reworks the race detection so that we require either the
mm to match the current active_mm (i.e. currently installed in our TTBR0)
or the mm_users count to be greater than 1, implying that the page table
could be live in another CPU. The mm_users check might still be racy,
but we'll avoid false positives and it's not realistic to validate that
all the necessary locks are held as part of this assertion.
Cc: Yisheng Xie <xieyisheng1@huawei.com>
Reported-by: Jiankang Chen <chenjiankang1@huawei.com>
Tested-by: Jiankang Chen <chenjiankang1@huawei.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
---
arch/arm64/include/asm/pgtable.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 3ff03a755c32..bdcc7f1c9d06 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -42,6 +42,8 @@
#include <asm/cmpxchg.h>
#include <asm/fixmap.h>
#include <linux/mmdebug.h>
+#include <linux/mm_types.h>
+#include <linux/sched.h>
extern void __pte_error(const char *file, int line, unsigned long val);
extern void __pmd_error(const char *file, int line, unsigned long val);
@@ -215,9 +217,6 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
}
}
-struct mm_struct;
-struct vm_area_struct;
-
extern void __sync_icache_dcache(pte_t pteval, unsigned long addr);
/*
@@ -246,7 +245,8 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
* hardware updates of the pte (ptep_set_access_flags safely changes
* valid ptes without going through an invalid entry).
*/
- if (pte_valid(*ptep) && pte_valid(pte)) {
+ if (IS_ENABLED(CONFIG_DEBUG_VM) && pte_valid(*ptep) && pte_valid(pte) &&
+ (mm == current->active_mm || atomic_read(&mm->mm_users) > 1)) {
VM_WARN_ONCE(!pte_young(pte),
"%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
__func__, pte_val(*ptep), pte_val(pte));
--
2.1.4
^ permalink raw reply related
* mainline/master boot bisection: v4.15-rc3 on peach-pi #3228-staging
From: Marek Szyprowski @ 2017-12-12 11:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CABxcv=mUHgTxvYpOYstE7rQn8fKS3QGiTT=FzBUc8DREvVuTeQ@mail.gmail.com>
Hi All,
On 2017-12-11 23:28, Javier Martinez Canillas wrote:
> [adding Marek and Shuah to cc list]
>
> On Mon, Dec 11, 2017 at 6:05 PM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
>> On Mon, Dec 11, 2017 at 11:30 AM, Guillaume Tucker
>> <guillaume.tucker@collabora.com> wrote:
>>> Hi Daniel,
>>>
>>> Please see below, I've had several bisection results pointing at
>>> that commit over the week-end on mainline but also on linux-next
>>> and net-next. While the peach-pi is a bit flaky at the moment
>>> and is likely to have more than one issue, it does seem like this
>>> commit is causing some well reproducible kernel hang.
>>>
>>> Here's a re-run with v4.15-rc3 showing the issue:
>>>
>>> https://lava.collabora.co.uk/scheduler/job/1018478
>>>
>>> and here's another one with the change mentioned below reverted:
>>>
>>> https://lava.collabora.co.uk/scheduler/job/1018479
>>>
>>> They both show a warning about "unbalanced disables for lcd_vdd",
>>> I don't know if this is related as I haven't investigated any
>>> further. It does appear to reliably hang with v4.15-rc3 and
>>> boot most of the time with the commit reverted though.
>>>
>>> The automated kernelci.org bisection is still an experimental
>>> tool and it may well be a false positive, so please take this
>>> result with a pinch of salt...
>> The patch just very minimal moves the connector cleanup around (so
>> timing change), but except when you unload a driver (or maybe that
>> funny EPROBE_DEFER stuff) it shouldn't matter. So if you don't have
>> more info than "seems to hang a bit more" I have no idea what's wrong.
>> The patch itself should work, at least it survived quite some serious
>> testing we do on everything.
>> -Daniel
>>
> Marek was pointing to a different culprit [0] in this [1] thread. I
> see that both commits made it to v4.15-rc3, which is the first version
> where boot fails. So maybe is a combination of both? Or rather
> reverting one patch masks the error in the other.
>
> I've access to the machine but unfortunately not a lot of time to dig
> on this, I could try to do it in the weekend though.
After a recent discussion on the Javier's patch:
https://patchwork.kernel.org/patch/10106417/
I've managed to reproduce this issue also on Exynos5250 based Samsung
Snow Chromebook and investigate a bit.
It is caused by a deadlock in the main kernel workqueue. Here are details:
1. Exynos DRM fails to initialize due to missing regulators and gets moved
to deferred probe device list
2. Deferred probe is triggered and kernel "events" workqueue calls
deferred_probe_work_func()
3. exynos_drm_bind() is called, component_bind_all() fails due to missing
Exynos Mixer device
4. error handling path is executed in exynos_drm_bind(), which calls
drm_mode_config_cleanup()
5. drm_mode_config_cleanup() calls flush_scheduled_work(), what causes
deadlock.
Do You have idea how to fix this issue properly?
Taking a look at git blame, this indeed shows that the issue has been
introduced by the commit a703c55004e1 ("drm: safely free connectors from
connector_ite"), which added a call to flush_scheduled_work() in
drm_mode_config_cleanup().
drm_mode_config_cleanup() should avoid calling flush_scheduled_work() if
called from the workqueue, but I don't have idea how to check that. The
other way of fixing it would be to resurrect separate workqueue for DRM
related events.
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply
* [RFC PATCH][resend] pciehp: fix a race between pciehp and removing operations by sysfs
From: Xiongfeng Wang @ 2017-12-12 11:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1513067384-10914-1-git-send-email-wangxiongfeng2@huawei.com>
This patch seems to introduce another issue. pciehp_power_thread() use
'container_of' to get the 'slot' according to 'work_struct'.
If the 'slot' has been freed before that, there will be an issue.
On 2017/12/12 16:29, Xiongfeng Wang wrote:
> When the Attention button on a PCIE slot is pressed, 5 seconds later,
> pciehp_power_thread() will be scheduled on slot->wq. This function will
> get a global mutex lock 'pci_rescan_remove_lock' in
> pciehp_unconfigure_device().
>
> At the same time, we remove the pcie port by sysfs, which results in
> pci_stop_and_remove_bus_device_locked() called. This function will get
> the global mutex lock 'pci_rescan_remove_lock', and then release the
> struct 'ctrl', which will wait until the work_struct on slot->wq is
> finished.
>
> If pci_stop_and_remove_bus_device_locked() got the mutex lock, and
> before it drains workqueue slot->wq, pciehp_power_thread() is scheduled
> on slot->wq and tries to get the mutex lock. Then
> pci_stop_and_remove_bus_device_locked() tries to drain workqueue
> slot->wq and wait until work struct 'pciehp_power_thread()' is finished.
> Then a hung_task happens.
>
> This patch solve this problem by schedule 'pciehp_power_thread()' on a
> system workqueue instead of slot->wq.
>
> The Call Trace we got is as following.
>
> INFO: task kworker/0:2:4413 blocked for more than 120 seconds.
> Tainted: P W O 4.12.0-rc1 #1
> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> kworker/0:2 D 0 4413 2 0x00000000
> Workqueue: pciehp-0 pciehp_power_thread
> Call trace:
> [<ffff0000080861d4>] __switch_to+0x94/0xa8
> [<ffff000008bea9c0>] __schedule+0x1b0/0x708
> [<ffff000008beaf58>] schedule+0x40/0xa4
> [<ffff000008beb33c>] schedule_preempt_disabled+0x28/0x40
> [<ffff000008bec1dc>] __mutex_lock.isra.8+0x148/0x50c
> [<ffff000008bec5c4>] __mutex_lock_slowpath+0x24/0x30
> [<ffff000008bec618>] mutex_lock+0x48/0x54
> [<ffff0000084d8188>] pci_lock_rescan_remove+0x20/0x28
> [<ffff0000084f87c0>] pciehp_unconfigure_device+0x54/0x1cc
> [<ffff0000084f8260>] pciehp_disable_slot+0x4c/0xbc
> [<ffff0000084f8370>] pciehp_power_thread+0xa0/0xb8
> [<ffff0000080e9ce8>] process_one_work+0x13c/0x3f8
> [<ffff0000080ea004>] worker_thread+0x60/0x3e4
> [<ffff0000080f0814>] kthread+0x10c/0x138
> [<ffff0000080836c0>] ret_from_fork+0x10/0x50
> INFO: task bash:31732 blocked for more than 120 seconds.
> Tainted: P W O 4.12.0-rc1 #1
> "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
> bash D 0 31732 1 0x00000009
> Call trace:
> [<ffff0000080861d4>] __switch_to+0x94/0xa8
> [<ffff000008bea9c0>] __schedule+0x1b0/0x708
> [<ffff000008beaf58>] schedule+0x40/0xa4
> [<ffff000008bee7b4>] schedule_timeout+0x1a0/0x340
> [<ffff000008bebb88>] wait_for_common+0x108/0x1bc
> [<ffff000008bebc64>] wait_for_completion+0x28/0x34
> [<ffff0000080e7594>] flush_workqueue+0x130/0x488
> [<ffff0000080e79b0>] drain_workqueue+0xc4/0x164
> [<ffff0000080ec3cc>] destroy_workqueue+0x28/0x1f4
> [<ffff0000084fa094>] pciehp_release_ctrl+0x34/0xe0
> [<ffff0000084f75b0>] pciehp_remove+0x30/0x3c
> [<ffff0000084f24d8>] pcie_port_remove_service+0x3c/0x54
> [<ffff00000876b1e4>] device_release_driver_internal+0x150/0x1d0
> [<ffff00000876b28c>] device_release_driver+0x28/0x34
> [<ffff00000876a018>] bus_remove_device+0xe0/0x11c
> [<ffff000008766348>] device_del+0x200/0x304
> [<ffff00000876646c>] device_unregister+0x20/0x38
> [<ffff0000084f2560>] remove_iter+0x44/0x54
> [<ffff000008765230>] device_for_each_child+0x4c/0x90
> [<ffff0000084f2c98>] pcie_port_device_remove+0x2c/0x48
> [<ffff0000084f2f48>] pcie_portdrv_remove+0x60/0x6c
> [<ffff0000084e3de4>] pci_device_remove+0x48/0x110
> [<ffff00000876b1e4>] device_release_driver_internal+0x150/0x1d0
> [<ffff00000876b28c>] device_release_driver+0x28/0x34
> [<ffff0000084db028>] pci_stop_bus_device+0x9c/0xac
> [<ffff0000084db190>] pci_stop_and_remove_bus_device_locked+0x24/0x3c
> [<ffff0000084e5eb0>] remove_store+0x74/0x80
> [<ffff000008764680>] dev_attr_store+0x44/0x5c
> [<ffff0000082e7e1c>] sysfs_kf_write+0x5c/0x74
> [<ffff0000082e7014>] kernfs_fop_write+0xcc/0x1dc
> [<ffff0000082602e0>] __vfs_write+0x48/0x13c
> [<ffff00000826174c>] vfs_write+0xa8/0x198
> [<ffff000008262ce8>] SyS_write+0x54/0xb0
> [<ffff000008083730>] el0_svc_naked+0x24/0x28
>
> Signed-off-by: Xiongfeng Wang <wangxiongfeng2@huawei.com>
> ---
> drivers/pci/hotplug/pciehp_ctrl.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
> index 83f3d4a..9d39d85 100644
> --- a/drivers/pci/hotplug/pciehp_ctrl.c
> +++ b/drivers/pci/hotplug/pciehp_ctrl.c
> @@ -221,7 +221,7 @@ static void pciehp_queue_power_work(struct slot *p_slot, int req)
> info->p_slot = p_slot;
> INIT_WORK(&info->work, pciehp_power_thread);
> info->req = req;
> - queue_work(p_slot->wq, &info->work);
> + schedule_work(&info->work);
> }
>
> void pciehp_queue_pushbutton_work(struct work_struct *work)
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox