Linux Documentation
 help / color / mirror / Atom feed
* Re: [PATCH v10 2/5] arm64: KVM: export the capability to set guest SError syndrome
From: gengdongjiu @ 2018-03-18  7:33 UTC (permalink / raw)
  To: James Morse
  Cc: rkrcmar@redhat.com, corbet@lwn.net, christoffer.dall@linaro.org,
	marc.zyngier@arm.com, linux@armlinux.org.uk,
	catalin.marinas@arm.com, rjw@rjwysocki.net, bp@alien8.de,
	lenb@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	kvmarm@lists.cs.columbia.edu, linux-acpi@vger.kernel.org,
	devel@acpica.org, Huangshaoyu (Shawn), Wuquanming

Hi James,
   Thanks for your time to review and give comments.

[...]
> > +
> > +8.14 KVM_CAP_ARM_SET_SERROR_ESR
> > +
> > +Architectures: arm, arm64
> > +
> > +This capability indicates that userspace can specify syndrome value
> > +reported to guest OS when guest takes a virtual SError interrupt exception.
> 
> "when userspace triggers a virtual SError"... how?

In the user space(QEMU), it will call kvm_arch_put_registers() or kvm_arch_get_registers() to set or get KVM registers through KVM_SET_ONE_REG/ KVM_GET_ONE_REG IOCTL, at the same time the two functions will separately call kvm_arm_vcpu_get_events() and kvm_arm_vcpu_set_events() to get/set vcpu events. If user space want to trigger a virtual SError with specified ESR, it only need to setup the kvm_vcpu_events struct(exception.serror_pending = 1; exception.serror_has_esr=1; serror_esr=xxxxx), then KVM will trigger this virtual SError.

userspace can trigger it at any time, for example, for debug purpose.  Or simulate a SError after recording a CPER for guest. But before triggering a virtual SError, it needs to know whether KVM has such capability, so KVM needs to export this capability to user space. If has this capability, User space will call kvm_arm_vcpu_set_events() to trigger a virtual SError.

> 
> 
> > +If KVM has this capability, userspace can only specify the ISS field
> > +for the ESR syndrome, can not specify the EC field which is not under control by KVM.
> 
> Where do I put the ESR?
> If you re-order this after the patch that adds the API, you can describe how this can be used.

Ok, thank a lot for your suggestion.

> 
> 
> Thanks,
> 
> James
> 
> 
> 
> > +If this virtual SError is taken to EL1 using AArch64, this value will
> > +be reported into ISS filed of ESR_EL1.
> > diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index
> > 3256b92..38c8a64 100644
> > --- a/arch/arm64/kvm/reset.c
> > +++ b/arch/arm64/kvm/reset.c
> > @@ -77,6 +77,9 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
> >  	case KVM_CAP_ARM_PMU_V3:
> >  		r = kvm_arm_support_pmu_v3();
> >  		break;
> > +	case KVM_CAP_ARM_INJECT_SERROR_ESR:
> > +		r = cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
> > +		break;
> >  	case KVM_CAP_SET_GUEST_DEBUG:
> >  	case KVM_CAP_VCPU_ATTRIBUTES:
> >  		r = 1;
> > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index
> > 8fb90a0..3587b33 100644
> > --- a/include/uapi/linux/kvm.h
> > +++ b/include/uapi/linux/kvm.h
> > @@ -934,6 +934,7 @@ struct kvm_ppc_resize_hpt {  #define
> > KVM_CAP_S390_AIS_MIGRATION 150  #define KVM_CAP_PPC_GET_CPU_CHAR 151
> > #define KVM_CAP_S390_BPB 152
> > +#define KVM_CAP_ARM_INJECT_SERROR_ESR 153
> >
> >  #ifdef KVM_CAP_IRQ_ROUTING
> >
> >

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v10 3/5] arm/arm64: KVM: Introduce set and get per-vcpu event
From: gengdongjiu @ 2018-03-18  6:42 UTC (permalink / raw)
  To: James Morse
  Cc: rkrcmar@redhat.com, corbet@lwn.net, christoffer.dall@linaro.org,
	marc.zyngier@arm.com, linux@armlinux.org.uk,
	catalin.marinas@arm.com, rjw@rjwysocki.net, bp@alien8.de,
	lenb@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	kvmarm@lists.cs.columbia.edu, linux-acpi@vger.kernel.org,
	devel@acpica.org, Huangshaoyu (Shawn), Wuquanming

Hi James,
   Thanks for your review and good suggestion.

> 
> Hi Dongjiu Geng,
> 
> On 03/03/18 16:09, Dongjiu Geng wrote:
> > RAS Extension provides VSESR_EL2 register to specify virtual SError
> > syndrome value, this patch adds a new IOCTL to export user-invisible
> > states related to SError exceptions. User space can setup the
> > kvm_vcpu_events to inject specified SError, also it can support live
> > migration.
> 
> > diff --git a/Documentation/virtual/kvm/api.txt
> > b/Documentation/virtual/kvm/api.txt
> > index 8a3d708..26ae151 100644
> > --- a/Documentation/virtual/kvm/api.txt
> > +++ b/Documentation/virtual/kvm/api.txt
> > @@ -819,11 +819,13 @@ struct kvm_clock_data {
> >
> >  Capability: KVM_CAP_VCPU_EVENTS
> >  Extended by: KVM_CAP_INTR_SHADOW
> > -Architectures: x86
> > +Architectures: x86, arm, arm64
> >  Type: vm ioctl
> >  Parameters: struct kvm_vcpu_event (out)
> >  Returns: 0 on success, -1 on error
> >
> > +X86:
> > +
> >  Gets currently pending exceptions, interrupts, and NMIs as well as
> > related  states of the vcpu.
> >
> > @@ -865,15 +867,29 @@ Only two fields are defined in the flags field:
> >  - KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
> >    smi contains a valid state.
> >
> > +ARM, ARM64:
> > +
> > +Gets currently pending SError exceptions as well as related states of the vcpu.
> > +
> > +struct kvm_vcpu_events {
> > +       struct {
> > +               bool serror_pending;
> > +               bool serror_has_esr;
> > +               u64 serror_esr;
> > +       } exception;
> > +};
> 
> Don't put bool in an ABI struct. The encoding is up to the compiler.
> The compiler will insert padding in this struct to make serror_esr naturally aligned. Different compilers may do it differently. You'll see that
> the existing struct kvm_vcpu_events has 'pad' fields to ensure each element in the struct is naturally aligned.

I checked the exited x86 strut kvm_vcpu_events definition, it aligned to 32 bits, so how about using below kvm_vcpu_events struct definition for arm64?
struct kvm_vcpu_events {
       struct {
               __u8_8 serror_pending;
               __u8 serror_has_esr;
               __u8 pad[2];
               __u64 serror_esr;
       } exception;
};

> 
> serror_pending and serror_has_esr need to be in a flags field.
How about this definition?
struct kvm_vcpu_events {
       struct {
               __u8_8 serror_pending;
               __u8 serror_has_esr;
               __u8 pad[2];
               __u64 serror_esr;
       } exception;
};

> 
> I thought the logic for re-using the CAP was so user-space could re-use save/restore code to transfer whatever we put in here during
> migration. If the struct is a different size the code has to be different anyway.
> My understanding of Drew and Christoffer's comments was that we should re-use the existing struct. (but now that I look at it, its not so
> clear).
> 
> (If we reuse the struct, we can put the esr in exception.error_code, if we can get away with it: It would be good to union exception up with
> a u64, then use that. This would let us transfer anything we need in those RES0 bits of the 64bit VSESR_EL2).

It seems Drew and Christoffer's comments suggested to use the KVM_GET/SET_VCPU_EVENTS ABI, not suggested arm64 must use the same struct
kvm_vcpu_events definition with x86. 
> 
> 
> >  4.32 KVM_SET_VCPU_EVENTS
> >
> >  Capability: KVM_CAP_VCPU_EVENTS
> >  Extended by: KVM_CAP_INTR_SHADOW
> > -Architectures: x86
> > +Architectures: x86, arm, arm64
> >  Type: vm ioctl
> >  Parameters: struct kvm_vcpu_event (in)
> >  Returns: 0 on success, -1 on error
> >
> > +X86:
> > +
> >  Set pending exceptions, interrupts, and NMIs as well as related
> > states of the  vcpu.
> >
> > @@ -894,6 +910,12 @@ shall be written into the VCPU.
> >
> >  KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
> >
> > +ARM, ARM64:
> > +
> > +Set pending SError exceptions as well as related states of the vcpu.
> > +
> > +See KVM_GET_VCPU_EVENTS for the data structure.
> > +
> >
> >  4.33 KVM_GET_DEBUGREGS
> >
> 
> > diff --git a/arch/arm64/include/uapi/asm/kvm.h
> > b/arch/arm64/include/uapi/asm/kvm.h
> > index 9abbf30..32c0eae 100644
> > --- a/arch/arm64/include/uapi/asm/kvm.h
> > +++ b/arch/arm64/include/uapi/asm/kvm.h
> > @@ -39,6 +39,7 @@
> >  #define __KVM_HAVE_GUEST_DEBUG
> >  #define __KVM_HAVE_IRQ_LINE
> >  #define __KVM_HAVE_READONLY_MEM
> > +#define __KVM_HAVE_VCPU_EVENTS
> >
> >  #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
> >
> > @@ -153,6 +154,15 @@ struct kvm_sync_regs {  struct
> > kvm_arch_memory_slot {  };
> >
> > +/* for KVM_GET/SET_VCPU_EVENTS */
> > +struct kvm_vcpu_events {
> > +	struct {
> > +		bool serror_pending;
> > +		bool serror_has_esr;
> > +		u64 serror_esr;
> > +	} exception;
> > +};
> > +
> 
> >  /* If you need to interpret the index values, here is the key: */
> >  #define KVM_REG_ARM_COPROC_MASK		0x000000000FFF0000
> >  #define KVM_REG_ARM_COPROC_SHIFT	16
> > diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index
> > 5c7f657..62d49c2 100644
> > --- a/arch/arm64/kvm/guest.c
> > +++ b/arch/arm64/kvm/guest.c
> > @@ -277,6 +277,32 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
> >  	return -EINVAL;
> >  }
> >
> > +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
> > +			struct kvm_vcpu_events *events)
> > +{
> > +	events->exception.serror_pending = (vcpu_get_hcr(vcpu) & HCR_VSE);
> > +	events->exception.serror_has_esr =
> > +			cpus_have_const_cap(ARM64_HAS_RAS_EXTN) &&
> > +					(!!vcpu_get_vsesr(vcpu));
> > +	events->exception.serror_esr = vcpu_get_vsesr(vcpu);
> > +
> > +	return 0;
> 
> Nothing checks the return value. Why is it here?

"return 0" means it is always successful, I do not know in which condition it needs to "return false" for kvm_arm_vcpu_get_events()
So I let it always "return 0".
Now this function caller does not check this function return value, I can remove "return 0".

> 
> > +}
> > +
> > +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
> > +			struct kvm_vcpu_events *events)
> > +{
> > +	bool injected = events->exception.serror_pending;
> > +	bool has_esr = events->exception.serror_has_esr;
> 
> Could you validate 'events' describes something we support. What if
> cpus_have_const_cap(ARM64_HAS_RAS_EXTN) is false, we still call kvm_set_sei_esr().
> 
> Please check any parts of the struct that should be zero, are zero. This lets us add new features, and reject attempts to migrate them
> (instead of silently ignoring them).

Sure, it needs, how about something like below?

If(!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
   return -EINVAL;

if(!injected || !has_esr)
   return -EINVAL;

> 
> 
> > +	if (injected && has_esr)
> > +		kvm_set_sei_esr(vcpu, events->exception.serror_esr);
> > +	else if (injected)
> > +		kvm_inject_vabt(vcpu);
> > +
> > +	return 0;
> 
> Nothing checks the return value. Why is it here?

kvm_arch_vcpu_ioctl() will check the return value.

> 
> 
> > +}
> > +
> >  int __attribute_const__ kvm_target_cpu(void)  {
> >  	unsigned long implementor = read_cpuid_implementor();
> 
> 
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index
> > 7e3941f..30c56e0 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -1051,6 +1051,24 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
> >  			return -EFAULT;
> >  		return kvm_arm_vcpu_has_attr(vcpu, &attr);
> >  	}
> > +	case KVM_GET_VCPU_EVENTS: {
> > +		struct kvm_vcpu_events events;
> 
> Please initialise events to 0 so that padding transferred to user-space doesn't contain kernel stack.

OK, thanks a lot for the good suggestion.

> 
> 
> > +		kvm_arm_vcpu_get_events(vcpu, &events);
> > +
> > +		if (copy_to_user(argp, &events, sizeof(struct kvm_vcpu_events)))
> > +			return -EFAULT;
> > +
> > +		return 0;
> > +	}
> > +	case KVM_SET_VCPU_EVENTS: {
> > +		struct kvm_vcpu_events events;
> > +
> > +		if (copy_from_user(&events, argp, sizeof(struct kvm_vcpu_events)))
> > +			return -EFAULT;
> > +
> > +		return kvm_arm_vcpu_set_events(vcpu, &events);
> > +	}
> >  	default:
> >  		return -EINVAL;
> >  	}
> >
> 
> Thanks,
> 
> James

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v10 1/5] arm64: KVM: Prepare set virtual SEI syndrome value
From: gengdongjiu @ 2018-03-18  5:17 UTC (permalink / raw)
  To: James Morse
  Cc: rkrcmar@redhat.com, corbet@lwn.net, christoffer.dall@linaro.org,
	marc.zyngier@arm.com, linux@armlinux.org.uk,
	catalin.marinas@arm.com, rjw@rjwysocki.net, bp@alien8.de,
	lenb@kernel.org, kvm@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	kvmarm@lists.cs.columbia.edu, linux-acpi@vger.kernel.org,
	devel@acpica.org, Huangshaoyu (Shawn)

Hi James,

> 
> Hi Dongjiu Geng,
> 
> On 03/03/18 16:09, Dongjiu Geng wrote:
> > Export one API to specify virtual SEI syndrome value for guest, and
> > add a helper to get the VSESR_EL2 value.
> 
> This patch adds two helpers that nothing calls... its not big, please merge it with the patch that uses these.

OK, thanks, I will merge them.

> 
> 
> > diff --git a/arch/arm64/include/asm/kvm_emulate.h
> > b/arch/arm64/include/asm/kvm_emulate.h
> > index 413dc82..3294885 100644
> > --- a/arch/arm64/include/asm/kvm_emulate.h
> > +++ b/arch/arm64/include/asm/kvm_emulate.h
> > @@ -71,6 +71,11 @@ static inline void vcpu_set_hcr(struct kvm_vcpu *vcpu, unsigned long hcr)
> >  	vcpu->arch.hcr_el2 = hcr;
> >  }
> >
> > +static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu) {
> > +	return vcpu->arch.vsesr_el2;
> > +}
> > +
> >  static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
> > {
> >  	vcpu->arch.vsesr_el2 = vsesr;
> > diff --git a/arch/arm64/include/asm/kvm_host.h
> > b/arch/arm64/include/asm/kvm_host.h
> > index a73f63a..3dc49b7 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -354,6 +354,8 @@ void handle_exit_early(struct kvm_vcpu *vcpu,
> > struct kvm_run *run,  int kvm_perf_init(void);  int
> > kvm_perf_teardown(void);
> >
> > +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
> > +
> >  struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long
> > mpidr);
> >
> >  static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, diff
> > --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
> > index 60666a0..78ecb28 100644
> > --- a/arch/arm64/kvm/inject_fault.c
> > +++ b/arch/arm64/kvm/inject_fault.c
> > @@ -186,3 +186,8 @@ void kvm_inject_vabt(struct kvm_vcpu *vcpu)  {
> >  	pend_guest_serror(vcpu, ESR_ELx_ISV);  }
> > +
> > +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome) {
> > +	pend_guest_serror(vcpu, syndrome & ESR_ELx_ISS_MASK);
> 
> If you move the ISS_MASK into pend_guest_serror(), you wouldn't need this at all.
> 
> It would be better if any validation were in the user-space helpers so we can check user-space hasn't put something funny in the top bits.

Yes, I agree your idea, thanks for the good suggestion.

> 
> > +}
> >
> 
> 
> Thanks,
> 
> James
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v4 3/8] doc: Add doc for the Ingenic TCU hardware
From: Randy Dunlap @ 2018-03-17 23:52 UTC (permalink / raw)
  To: Paul Cercueil, Thomas Gleixner, Jason Cooper, Marc Zyngier,
	Lee Jones, Daniel Lezcano, Ralf Baechle, Rob Herring,
	Jonathan Corbet, Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc
In-Reply-To: <20180317232901.14129-4-paul@crapouillou.net>

On 03/17/2018 04:28 PM, Paul Cercueil wrote:
> Add a documentation file about the Timer/Counter Unit (TCU)
> present in the Ingenic JZ47xx SoCs.
> 
> Signed-off-by: Paul Cercueil <paul@crapouillou.net>
> ---
>  Documentation/mips/00-INDEX        |  3 +++
>  Documentation/mips/ingenic-tcu.txt | 50 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
>  create mode 100644 Documentation/mips/ingenic-tcu.txt
> 
>  v4: New patch in this series

> diff --git a/Documentation/mips/ingenic-tcu.txt b/Documentation/mips/ingenic-tcu.txt
> new file mode 100644
> index 000000000000..2508e5793da8
> --- /dev/null
> +++ b/Documentation/mips/ingenic-tcu.txt
> @@ -0,0 +1,50 @@
> +Ingenic JZ47xx SoCs Timer/Counter Unit hardware
> +-----------------------------------------------
> +
> +The Timer/Counter Unit (TCU) in Ingenic JZ47xx SoCs is a multi-function
> +hardware block. It features eight channels, that can be used as counters,

                    drop comma ............. ^

> +timers, or PWM.
> +
> +- JZ4770 introduced a separate channel, called Operating System Timer (OST).
> +  It is a 64-bit programmable timer.
> +
> +- Each one of the eight channels has its own clock, which can be reparented
> +  to three different clocks (pclk, ext, rtc), gated, and reclocked, through
> +  their TCSR register.
> +  * The watchdog and OST hardware blocks also feature a TCSR register with
> +	the same format in their register space.
> +  * The TCU registers used to gate/ungate can also gate/ungate the watchdog
> +	and OST clocks.
> +
> +- On SoCs >= JZ4770, there are two different modes:
> +  * Channels 0, 3-7 operate in TCU1 mode: they cannot work in sleep mode,
> +	but are easier to operate.
> +  * Channels 1-2 operate in TCU2 mode: they can work in sleep mode, but
> +	the operation is a bit more complicated than with TCU1 channels.
> +
> +- Each channel can generate an interrupt. Some channels share an interrupt	
> +  line, some don't, and this changes between SoC versions:
> +  * on JZ4740, timer 0 and timer 1 have their own interrupt line; others share
> +	one interrupt line.
> +  * on JZ4770 and JZ4780, timer 5 has its own interrupt; timers 0-4 and 6-7 all
> +	use one interrupt line; the OST uses the last interrupt.

"The OST uses the last interrupt." is not clear to someone who doesn't know
about this hardware. (I can read it several ways.)

Does it mean that the 4770 and 4780 have 3 interrupt lines used like so?

- timer 5 uses one interrupt line
- timers 0-4 and 6-7 use a second interrupt line
- the OST uses a third interrupt line


thanks,
-- 
~Randy
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v4 2/8] dt-bindings: ingenic: Add DT bindings for TCU clocks
From: Paul Cercueil @ 2018-03-17 23:28 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

This header provides clock numbers for the ingenic,tcu
DT binding.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Reviewed-by: Rob Herring <robh@kernel.org>
---
 include/dt-bindings/clock/ingenic,tcu.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 include/dt-bindings/clock/ingenic,tcu.h

 v2: Use SPDX identifier for the license
 v3: No change
 v4: No change

diff --git a/include/dt-bindings/clock/ingenic,tcu.h b/include/dt-bindings/clock/ingenic,tcu.h
new file mode 100644
index 000000000000..179815d7b3bb
--- /dev/null
+++ b/include/dt-bindings/clock/ingenic,tcu.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This header provides clock numbers for the ingenic,tcu DT binding.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_INGENIC_TCU_H__
+#define __DT_BINDINGS_CLOCK_INGENIC_TCU_H__
+
+#define JZ4740_CLK_TIMER0	0
+#define JZ4740_CLK_TIMER1	1
+#define JZ4740_CLK_TIMER2	2
+#define JZ4740_CLK_TIMER3	3
+#define JZ4740_CLK_TIMER4	4
+#define JZ4740_CLK_TIMER5	5
+#define JZ4740_CLK_TIMER6	6
+#define JZ4740_CLK_TIMER7	7
+#define JZ4740_CLK_WDT		8
+#define JZ4740_CLK_LAST		JZ4740_CLK_WDT
+
+#define JZ4770_CLK_OST		9
+#define JZ4770_CLK_LAST		JZ4770_CLK_OST
+
+#endif /* __DT_BINDINGS_CLOCK_INGENIC_TCU_H__ */
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 6/8] clk: ingenic: Add JZ47xx TCU clocks driver
From: Paul Cercueil @ 2018-03-17 23:28 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

The TCU (Timer Counter Unit) of the Ingenic JZ47xx SoCs features 8
channels, each one having its own clock, that can be started and
stopped, reparented, and reclocked.

This driver only modifies the bits of the registers of the TCU that are
related to clocks control. It provides one clock per TCU channel (plus
one for the watchdog and one for the OS timer) that can be used by other
drivers.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Stephen Boyd <sboyd@codeaurora.org>
---
 drivers/clk/ingenic/Makefile |   2 +-
 drivers/clk/ingenic/tcu.c    | 319 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 320 insertions(+), 1 deletion(-)
 create mode 100644 drivers/clk/ingenic/tcu.c

 v2: - Use SPDX identifier for the license
     - Fix broken build caused by typo when correcting patch
 v3: - Move documentation to its own patch
     - Get rid of ingenic_tcu structure. The "struct regmap *map" was
	   added to struct ingenic_tcu_clk, the other fields are gone.
	 - Replace clk_register / clk_register_clockdev /
	   of_clk_add_provider with their "clk_hw" variant.
 v4: No change

diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile
index 1456e4cdb562..9dcadd4fed4c 100644
--- a/drivers/clk/ingenic/Makefile
+++ b/drivers/clk/ingenic/Makefile
@@ -1,4 +1,4 @@
-obj-y				+= cgu.o
+obj-y				+= cgu.o tcu.o
 obj-$(CONFIG_MACH_JZ4740)	+= jz4740-cgu.o
 obj-$(CONFIG_MACH_JZ4770)	+= jz4770-cgu.o
 obj-$(CONFIG_MACH_JZ4780)	+= jz4780-cgu.o
diff --git a/drivers/clk/ingenic/tcu.c b/drivers/clk/ingenic/tcu.c
new file mode 100644
index 000000000000..b550b6ac8fb4
--- /dev/null
+++ b/drivers/clk/ingenic/tcu.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic JZ47xx SoC TCU clocks driver
+ * Copyright (C) 2018 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/ingenic-tcu.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/ingenic,tcu.h>
+
+enum ingenic_version {
+	ID_JZ4740,
+	ID_JZ4770,
+	ID_JZ4780,
+};
+
+struct ingenic_tcu_clk_info {
+	struct clk_init_data init_data;
+	u8 gate_bit;
+	u8 tcsr_reg;
+};
+
+struct ingenic_tcu_clk {
+	struct clk_hw hw;
+
+	struct regmap *map;
+	const struct ingenic_tcu_clk_info *info;
+
+	unsigned int idx;
+};
+
+#define to_tcu_clk(_hw) container_of(_hw, struct ingenic_tcu_clk, hw)
+
+static int ingenic_tcu_enable(struct clk_hw *hw)
+{
+	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
+	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+
+	regmap_write(tcu_clk->map, TCU_REG_TSCR, BIT(info->gate_bit));
+	return 0;
+}
+
+static void ingenic_tcu_disable(struct clk_hw *hw)
+{
+	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
+	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+
+	regmap_write(tcu_clk->map, TCU_REG_TSSR, BIT(info->gate_bit));
+}
+
+static int ingenic_tcu_is_enabled(struct clk_hw *hw)
+{
+	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
+	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+	unsigned int value;
+
+	regmap_read(tcu_clk->map, TCU_REG_TSR, &value);
+
+	return !(value & BIT(info->gate_bit));
+}
+
+static u8 ingenic_tcu_get_parent(struct clk_hw *hw)
+{
+	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
+	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_read(tcu_clk->map, info->tcsr_reg, &val);
+	WARN_ONCE(ret < 0, "Unable to read TCSR %i", tcu_clk->idx);
+
+	return ffs(val & TCU_TCSR_PARENT_CLOCK_MASK) - 1;
+}
+
+static int ingenic_tcu_set_parent(struct clk_hw *hw, u8 idx)
+{
+	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
+	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+	struct regmap *map = tcu_clk->map;
+	int ret;
+
+	/*
+	 * Our clock provider has the CLK_SET_PARENT_GATE flag set, so we know
+	 * that the clk is in unprepared state. To be able to access TCSR
+	 * we must ungate the clock supply and we gate it again when done.
+	 */
+
+	regmap_write(map, TCU_REG_TSCR, BIT(info->gate_bit));
+
+	ret = regmap_update_bits(map, info->tcsr_reg,
+			TCU_TCSR_PARENT_CLOCK_MASK, BIT(idx));
+	WARN_ONCE(ret < 0, "Unable to update TCSR %i", tcu_clk->idx);
+
+	regmap_write(map, TCU_REG_TSSR, BIT(info->gate_bit));
+
+	return 0;
+}
+
+static unsigned long ingenic_tcu_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
+	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+	unsigned int prescale;
+	int ret;
+
+	ret = regmap_read(tcu_clk->map, info->tcsr_reg, &prescale);
+	WARN_ONCE(ret < 0, "Unable to read TCSR %i", tcu_clk->idx);
+
+	prescale = (prescale & TCU_TCSR_PRESCALE_MASK) >> TCU_TCSR_PRESCALE_LSB;
+
+	return parent_rate >> (prescale * 2);
+}
+
+static long ingenic_tcu_round_rate(struct clk_hw *hw, unsigned long req_rate,
+		unsigned long *parent_rate)
+{
+	unsigned long rate = *parent_rate;
+	unsigned int shift;
+
+	if (req_rate > rate)
+		return -EINVAL;
+
+	for (shift = 0; shift < 10; shift += 2)
+		if ((rate >> shift) <= req_rate)
+			break;
+
+	return rate >> shift;
+}
+
+static int ingenic_tcu_set_rate(struct clk_hw *hw, unsigned long req_rate,
+		unsigned long parent_rate)
+{
+	struct ingenic_tcu_clk *tcu_clk = to_tcu_clk(hw);
+	const struct ingenic_tcu_clk_info *info = tcu_clk->info;
+	struct regmap *map = tcu_clk->map;
+	u8 prescale = (ffs(parent_rate / req_rate) / 2)
+			<< TCU_TCSR_PRESCALE_LSB;
+	int ret;
+
+	/*
+	 * Our clock provider has the CLK_SET_RATE_GATE flag set, so we know
+	 * that the clk is in unprepared state. To be able to access TCSR
+	 * we must ungate the clock supply and we gate it again when done.
+	 */
+
+	regmap_write(map, TCU_REG_TSCR, BIT(info->gate_bit));
+
+	ret = regmap_update_bits(map, info->tcsr_reg,
+				TCU_TCSR_PRESCALE_MASK, prescale);
+	WARN_ONCE(ret < 0, "Unable to update TCSR %i", tcu_clk->idx);
+
+	regmap_write(map, TCU_REG_TSSR, BIT(info->gate_bit));
+
+	return 0;
+}
+
+static const struct clk_ops ingenic_tcu_clk_ops = {
+	.get_parent	= ingenic_tcu_get_parent,
+	.set_parent	= ingenic_tcu_set_parent,
+
+	.recalc_rate	= ingenic_tcu_recalc_rate,
+	.round_rate	= ingenic_tcu_round_rate,
+	.set_rate	= ingenic_tcu_set_rate,
+
+	.enable		= ingenic_tcu_enable,
+	.disable	= ingenic_tcu_disable,
+	.is_enabled	= ingenic_tcu_is_enabled,
+};
+
+static const char * const ingenic_tcu_timer_parents[] = {
+	"pclk",
+	"rtc",
+	"ext",
+};
+
+static const struct ingenic_tcu_clk_info ingenic_tcu_clk_info[] = {
+#define DEF_TIMER(_name, _gate_bit, _tcsr)				\
+	{								\
+		.init_data = {						\
+			.name = _name,					\
+			.parent_names = ingenic_tcu_timer_parents,	\
+			.num_parents = ARRAY_SIZE(ingenic_tcu_timer_parents),\
+			.ops = &ingenic_tcu_clk_ops,			\
+			.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE,\
+		},							\
+		.gate_bit = _gate_bit,					\
+		.tcsr_reg = _tcsr,					\
+	}
+	[JZ4740_CLK_TIMER0] = DEF_TIMER("timer0", 0, TCU_REG_TCSRc(0)),
+	[JZ4740_CLK_TIMER1] = DEF_TIMER("timer1", 1, TCU_REG_TCSRc(1)),
+	[JZ4740_CLK_TIMER2] = DEF_TIMER("timer2", 2, TCU_REG_TCSRc(2)),
+	[JZ4740_CLK_TIMER3] = DEF_TIMER("timer3", 3, TCU_REG_TCSRc(3)),
+	[JZ4740_CLK_TIMER4] = DEF_TIMER("timer4", 4, TCU_REG_TCSRc(4)),
+	[JZ4740_CLK_TIMER5] = DEF_TIMER("timer5", 5, TCU_REG_TCSRc(5)),
+	[JZ4740_CLK_TIMER6] = DEF_TIMER("timer6", 6, TCU_REG_TCSRc(6)),
+	[JZ4740_CLK_TIMER7] = DEF_TIMER("timer7", 7, TCU_REG_TCSRc(7)),
+	[JZ4740_CLK_WDT]    = DEF_TIMER("wdt",   16, TCU_REG_WDT_TCSR),
+	[JZ4770_CLK_OST]    = DEF_TIMER("ost",   15, TCU_REG_OST_TCSR),
+#undef DEF_TIMER
+};
+
+static int ingenic_tcu_register_clock(struct regmap *map, unsigned int idx,
+		const struct ingenic_tcu_clk_info *info,
+		struct clk_hw_onecell_data *clocks)
+{
+	struct ingenic_tcu_clk *tcu_clk;
+	int err;
+
+	tcu_clk = kzalloc(sizeof(*tcu_clk), GFP_KERNEL);
+	if (!tcu_clk)
+		return -ENOMEM;
+
+	tcu_clk->hw.init = &info->init_data;
+	tcu_clk->idx = idx;
+	tcu_clk->info = info;
+	tcu_clk->map = map;
+
+	/* Set EXT as the default parent clock */
+	ingenic_tcu_set_parent(&tcu_clk->hw, 2);
+
+	ingenic_tcu_disable(&tcu_clk->hw);
+
+	err = clk_hw_register(NULL, &tcu_clk->hw);
+	if (err)
+		goto err_free_tcu_clk;
+
+	err = clk_hw_register_clkdev(&tcu_clk->hw, info->init_data.name, NULL);
+	if (err)
+		goto err_clk_unregister;
+
+	clocks->hws[idx] = &tcu_clk->hw;
+	return 0;
+
+err_clk_unregister:
+	clk_hw_unregister(&tcu_clk->hw);
+err_free_tcu_clk:
+	kfree(tcu_clk);
+	return err;
+}
+
+static void __init ingenic_tcu_init(struct device_node *np,
+		enum ingenic_version id)
+{
+	struct clk_hw_onecell_data *clocks;
+	struct regmap *map;
+	size_t i, nb_clks;
+	int ret = -ENOMEM;
+
+	if (id >= ID_JZ4770)
+		nb_clks = (JZ4770_CLK_LAST - JZ4740_CLK_TIMER0) + 1;
+	else
+		nb_clks = (JZ4740_CLK_LAST - JZ4740_CLK_TIMER0) + 1;
+
+	map = syscon_node_to_regmap(np->parent);
+	if (IS_ERR(map)) {
+		pr_err("%s: failed to map TCU registers\n", __func__);
+		return;
+	}
+
+	clocks = kzalloc(sizeof(*clocks) +
+					 sizeof(*clocks->hws) * nb_clks,
+					 GFP_KERNEL);
+	if (!clocks)
+		return;
+
+	clocks->num = nb_clks;
+
+	for (i = 0; i < nb_clks; i++) {
+		ret = ingenic_tcu_register_clock(map, i,
+				&ingenic_tcu_clk_info[JZ4740_CLK_TIMER0 + i],
+				clocks);
+		if (ret) {
+			pr_err("%s: cannot register clocks\n", __func__);
+			goto err_unregister;
+		}
+	}
+
+	ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clocks);
+	if (ret) {
+		pr_err("%s: cannot add OF clock provider\n", __func__);
+		goto err_unregister;
+	}
+
+	return;
+
+err_unregister:
+	for (i = 0; i < clocks->num; i++)
+		if (clocks->hws[i])
+			clk_hw_unregister(clocks->hws[i]);
+	kfree(clocks);
+}
+
+static void __init jz4740_tcu_init(struct device_node *np)
+{
+	ingenic_tcu_init(np, ID_JZ4740);
+}
+
+static void __init jz4770_tcu_init(struct device_node *np)
+{
+	ingenic_tcu_init(np, ID_JZ4770);
+}
+
+static void __init jz4780_tcu_init(struct device_node *np)
+{
+	ingenic_tcu_init(np, ID_JZ4780);
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+CLK_OF_DECLARE(jz4740_tcu, "ingenic,jz4740-tcu-clocks", jz4740_tcu_init);
+CLK_OF_DECLARE(jz4770_tcu, "ingenic,jz4770-tcu-clocks", jz4770_tcu_init);
+CLK_OF_DECLARE(jz4780_tcu, "ingenic,jz4780-tcu-clocks", jz4780_tcu_init);
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 4/8] dt-bindings: Add doc for the Ingenic TCU drivers
From: Paul Cercueil @ 2018-03-17 23:28 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

Add documentation about how to properly use the Ingenic TCU
(Timer/Counter Unit) drivers from devicetree.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 .../bindings/clock/ingenic,tcu-clocks.txt          | 42 ++++++++++++++++
 .../bindings/interrupt-controller/ingenic,tcu.txt  | 39 +++++++++++++++
 .../devicetree/bindings/mfd/ingenic,tcu.txt        | 56 ++++++++++++++++++++++
 .../devicetree/bindings/timer/ingenic,tcu.txt      | 41 ++++++++++++++++
 4 files changed, 178 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/ingenic,tcu-clocks.txt
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/ingenic,tcu.txt
 create mode 100644 Documentation/devicetree/bindings/mfd/ingenic,tcu.txt
 create mode 100644 Documentation/devicetree/bindings/timer/ingenic,tcu.txt

 v4: New patch in this series. Corresponds to V2 patches 3-4-5 with
 added content.

diff --git a/Documentation/devicetree/bindings/clock/ingenic,tcu-clocks.txt b/Documentation/devicetree/bindings/clock/ingenic,tcu-clocks.txt
new file mode 100644
index 000000000000..471d27078599
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ingenic,tcu-clocks.txt
@@ -0,0 +1,42 @@
+Ingenic SoC TCU binding
+
+The TCU is the Timer/Counter Unit present in all Ingenic SoCs. It features 8
+channels, each one having its own clock, that can be started and stopped,
+reparented, and reclocked.
+
+Required properties:
+- compatible : One of:
+  * ingenic,jz4740-tcu-clocks,
+  * ingenic,jz4770-tcu-clocks,
+  * ingenic,jz4780-tcu-clocks.
+- clocks : List of phandle & clock specifiers for clocks external to the TCU.
+  The "pclk", "rtc" and "ext" clocks should be provided.
+- clock-names : List of name strings for the external clocks.
+- #clock-cells: Should be 1.
+  Clock consumers specify this argument to identify a clock. The valid values
+  may be found in <dt-bindings/clock/ingenic,tcu.h>.
+
+Example:
+
+/ {
+	tcu: mfd@10002000 {
+		compatible = "ingenic,tcu", "simple-mfd", "syscon";
+		reg = <0x10002000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x10002000 0x1000>;
+
+		tcu_clk: clocks@10 {
+			compatible = "ingenic,jz4740-tcu-clocks";
+			reg = <0x10 0xff0>;
+
+			clocks = <&ext>, <&rtc>, <&pclk>;
+			clock-names = "ext", "rtc", "pclk";
+
+			#clock-cells = <1>;
+		};
+	};
+};
+
+For information about the top-level "ingenic,tcu" compatible node and other
+children nodes, see Documentation/devicetree/bindings/mfd/ingenic,tcu.txt.
diff --git a/Documentation/devicetree/bindings/interrupt-controller/ingenic,tcu.txt b/Documentation/devicetree/bindings/interrupt-controller/ingenic,tcu.txt
new file mode 100644
index 000000000000..7f3af2da77cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/ingenic,tcu.txt
@@ -0,0 +1,39 @@
+Ingenic SoCs Timer/Counter Unit Interrupt Controller
+
+Required properties:
+
+- compatible : should be "ingenic,<socname>-tcu-intc". Valid strings are:
+  * ingenic,jz4740-tcu-intc
+  * ingenic,jz4770-tcu-intc
+  * ingenic,jz4780-tcu-intc
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 1.
+- interrupt-parent : phandle of the interrupt controller.
+- interrupts : Specifies the interrupt the controller is connected to.
+
+Example:
+
+/ {
+	tcu: mfd@10002000 {
+		compatible = "ingenic,tcu", "simple-mfd", "syscon";
+		reg = <0x10002000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x10002000 0x1000>;
+
+		tcu_irq: interrupt-controller@20 {
+			compatible = "ingenic,jz4740-tcu-intc";
+			reg = <0x20 0x20>;
+
+			interrupt-controller;
+			#interrupt-cells = <1>;
+
+			interrupt-parent = <&intc>;
+			interrupts = <15>;
+		};
+	};
+};
+
+For information about the top-level "ingenic,tcu" compatible node and other
+children nodes, see Documentation/devicetree/bindings/mfd/ingenic,tcu.txt.
diff --git a/Documentation/devicetree/bindings/mfd/ingenic,tcu.txt b/Documentation/devicetree/bindings/mfd/ingenic,tcu.txt
new file mode 100644
index 000000000000..5742c3f21550
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/ingenic,tcu.txt
@@ -0,0 +1,56 @@
+Ingenic JZ47xx SoCs Timer/Counter Unit devicetree bindings
+----------------------------------------------------------
+
+For a description of the TCU hardware and drivers, have a look at
+Documentation/mips/ingenic-tcu.txt.
+
+The TCU is implemented as a parent node, whose role is to create the
+regmap, and child nodes for the various drivers listed in the aforementioned
+document.
+
+Required properties:
+
+- compatible: must be "ingenic,tcu", "simple-mfd", "syscon";
+- reg: Should be the offset/length value corresponding to the TCU registers
+- #address-cells: Should be <1>;
+- #size-cells: Should be <1>;
+- ranges: Should be one range for the full TCU registers area
+
+Accepted children nodes:
+- Documentation/devicetree/bindings/interrupt-controller/ingenic,tcu.txt
+- Documentation/devicetree/bindings/clock/ingenic,tcu-clocks.txt
+- Documentation/devicetree/bindings/timer/ingenic,tcu.txt
+
+
+Example:
+
+/ {
+	tcu: mfd@10002000 {
+		compatible = "ingenic,tcu", "simple-mfd", "syscon";
+		reg = <0x10002000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x10002000 0x1000>;
+
+		tcu_irq: interrupt-controller@20 {
+			compatible = "ingenic,jz4740-tcu-intc";
+			reg = <0x20 0x20>;
+			...
+		};
+
+		tcu_clk: clocks@10 {
+			compatible = "ingenic,jz4740-tcu-clocks";
+			reg = <0x10 0xff0>;
+			...
+		};
+
+		tcu_timer: timer@10 {
+			compatible = "ingenic,jz4740-tcu";
+			reg = <0x10 0xff0>;
+			...
+		};
+	};
+};
+
+For more information about the children node, refer to the documents listed
+above in the "Accepted children nodes" section.
diff --git a/Documentation/devicetree/bindings/timer/ingenic,tcu.txt b/Documentation/devicetree/bindings/timer/ingenic,tcu.txt
new file mode 100644
index 000000000000..f910b7e96783
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/ingenic,tcu.txt
@@ -0,0 +1,41 @@
+Ingenic JZ47xx SoCs Timer/Counter Unit driver
+---------------------------------------------
+
+Required properties:
+
+- compatible : should be "ingenic,<socname>-tcu". Valid strings are:
+  * ingenic,jz4740-tcu
+  * ingenic,jz4770-tcu
+  * ingenic,jz4780-tcu
+- interrupt-parent : phandle of the TCU interrupt controller.
+- interrupts : Specifies the interrupts the controller is connected to.
+- clocks : List of phandle & clock specifiers for the TCU clocks.
+- clock-names : List of name strings for the TCU clocks.
+
+Example:
+
+/ {
+	tcu: mfd@10002000 {
+		compatible = "ingenic,tcu", "simple-mfd", "syscon";
+		reg = <0x10002000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x10002000 0x1000>;
+
+		tcu_timer: timer@10 {
+			compatible = "ingenic,jz4740-tcu";
+			reg = <0x10 0xff0>;
+
+			clocks = <&tcu_clk 0>, <&tcu_clk 1>, <&tcu_clk 2>, <&tcu_clk 3>,
+					 <&tcu_clk 4>, <&tcu_clk 5>, <&tcu_clk 6>, <&tcu_clk 7>;
+			clock-names = "timer0", "timer1", "timer2", "timer3",
+						  "timer4", "timer5", "timer6", "timer7";
+
+			interrupt-parent = <&tcu_irq>;
+			interrupts = <0 1 2 3 4 5 6 7>;
+		};
+	};
+};
+
+For information about the top-level "ingenic,tcu" compatible node and other
+children nodes, see Documentation/devicetree/bindings/mfd/ingenic,tcu.txt.
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 3/8] doc: Add doc for the Ingenic TCU hardware
From: Paul Cercueil @ 2018-03-17 23:28 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

Add a documentation file about the Timer/Counter Unit (TCU)
present in the Ingenic JZ47xx SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 Documentation/mips/00-INDEX        |  3 +++
 Documentation/mips/ingenic-tcu.txt | 50 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 Documentation/mips/ingenic-tcu.txt

 v4: New patch in this series

diff --git a/Documentation/mips/00-INDEX b/Documentation/mips/00-INDEX
index 8ae9cffc2262..8ab8c3f83771 100644
--- a/Documentation/mips/00-INDEX
+++ b/Documentation/mips/00-INDEX
@@ -2,3 +2,6 @@
 	- this file.
 AU1xxx_IDE.README
 	- README for MIPS AU1XXX IDE driver.
+ingenic-tcu.txt
+	- Information file about the Timer/Counter Unit present
+	  in Ingenic JZ47xx SoCs.
diff --git a/Documentation/mips/ingenic-tcu.txt b/Documentation/mips/ingenic-tcu.txt
new file mode 100644
index 000000000000..2508e5793da8
--- /dev/null
+++ b/Documentation/mips/ingenic-tcu.txt
@@ -0,0 +1,50 @@
+Ingenic JZ47xx SoCs Timer/Counter Unit hardware
+-----------------------------------------------
+
+The Timer/Counter Unit (TCU) in Ingenic JZ47xx SoCs is a multi-function
+hardware block. It features eight channels, that can be used as counters,
+timers, or PWM.
+
+- JZ4770 introduced a separate channel, called Operating System Timer (OST).
+  It is a 64-bit programmable timer.
+
+- Each one of the eight channels has its own clock, which can be reparented
+  to three different clocks (pclk, ext, rtc), gated, and reclocked, through
+  their TCSR register.
+  * The watchdog and OST hardware blocks also feature a TCSR register with
+	the same format in their register space.
+  * The TCU registers used to gate/ungate can also gate/ungate the watchdog
+	and OST clocks.
+
+- On SoCs >= JZ4770, there are two different modes:
+  * Channels 0, 3-7 operate in TCU1 mode: they cannot work in sleep mode,
+	but are easier to operate.
+  * Channels 1-2 operate in TCU2 mode: they can work in sleep mode, but
+	the operation is a bit more complicated than with TCU1 channels.
+
+- Each channel can generate an interrupt. Some channels share an interrupt
+  line, some don't, and this changes between SoC versions:
+  * on JZ4740, timer 0 and timer 1 have their own interrupt line; others share
+	one interrupt line.
+  * on JZ4770 and JZ4780, timer 5 has its own interrupt; timers 0-4 and 6-7 all
+	use one interrupt line; the OST uses the last interrupt.
+
+Implementation
+--------------
+
+The functionalities of the TCU hardware are spread across multiple drivers:
+- interrupts:   drivers/irqchip/irq-ingenic-tcu.c
+- clocks:       drivers/clk/ingenic/tcu.c
+- timer:        drivers/clocksource/timer-ingenic.c
+- PWM:          drivers/pwm/pwm-jz4740.c
+- watchdog:     drivers/watchdog/jz4740_wdt.c
+- OST:			(none yet)
+
+Because various functionalities of the TCU that belong to different drivers
+and frameworks can be controlled from the same registers, all of these drivers
+access their registers through the same regmap.
+
+In practice, the devicetree nodes for all of these drivers must be children
+of a "syscon" node that defines the register area.
+For more information regarding the devicetree bindings of the TCU drivers,
+have a look at Documentation/devicetree/bindings/mfd/ingenic,tcu.txt.
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 5/8] irqchip: Add the ingenic-tcu-intc driver
From: Paul Cercueil @ 2018-03-17 23:28 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

This simple driver handles the IRQ chip of the TCU
(Timer Counter Unit) of the JZ47xx Ingenic SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/irqchip/Kconfig           |   6 ++
 drivers/irqchip/Makefile          |   1 +
 drivers/irqchip/irq-ingenic-tcu.c | 161 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 168 insertions(+)
 create mode 100644 drivers/irqchip/irq-ingenic-tcu.c

 v2: - Use SPDX identifier for the license
     - Make KConfig option select CONFIG_IRQ_DOMAIN since we depend on it
 v3: - Move documentation to its own patch
     - Add comment explaining why we only use IRQCHIP_DECLARE
 v4: - Rename variables to avoid splitting long lines
     - Add comment about the multiple IRQ parents

diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index d913aec85109..2b56587d04ed 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -267,6 +267,12 @@ config INGENIC_IRQ
 	depends on MACH_INGENIC
 	default y
 
+config INGENIC_TCU_IRQ
+	bool
+	depends on MACH_INGENIC || COMPILE_TEST
+	select IRQ_DOMAIN
+	default y
+
 config RENESAS_H8300H_INTC
         bool
 	select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index d27e3e3619e0..48b0bdf2b1a2 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -70,6 +70,7 @@ obj-$(CONFIG_RENESAS_H8300H_INTC)	+= irq-renesas-h8300h.o
 obj-$(CONFIG_RENESAS_H8S_INTC)		+= irq-renesas-h8s.o
 obj-$(CONFIG_ARCH_SA1100)		+= irq-sa11x0.o
 obj-$(CONFIG_INGENIC_IRQ)		+= irq-ingenic.o
+obj-$(CONFIG_INGENIC_TCU_IRQ)		+= irq-ingenic-tcu.o
 obj-$(CONFIG_IMX_GPCV2)			+= irq-imx-gpcv2.o
 obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
 obj-$(CONFIG_MVEBU_GICP)		+= irq-mvebu-gicp.o
diff --git a/drivers/irqchip/irq-ingenic-tcu.c b/drivers/irqchip/irq-ingenic-tcu.c
new file mode 100644
index 000000000000..add3e9cc6f82
--- /dev/null
+++ b/drivers/irqchip/irq-ingenic-tcu.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * JZ47xx SoCs TCU IRQ driver
+ * Copyright (C) 2018 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/bitops.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/syscon/ingenic-tcu.h>
+
+static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
+{
+	struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
+	struct irq_domain *domain = irq_desc_get_handler_data(desc);
+	struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
+	struct regmap *map = gc->private;
+	uint32_t irq_reg, irq_mask;
+	unsigned int i;
+
+	regmap_read(map, TCU_REG_TFR, &irq_reg);
+	regmap_read(map, TCU_REG_TMR, &irq_mask);
+
+	chained_irq_enter(irq_chip, desc);
+
+	irq_reg &= ~irq_mask;
+
+	for (i = 0; i < 32; i++) {
+		if (irq_reg & BIT(i))
+			generic_handle_irq(irq_linear_revmap(domain, i));
+	}
+
+	chained_irq_exit(irq_chip, desc);
+}
+
+static void ingenic_tcu_gc_unmask_enable_reg(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct irq_chip_type *ct = irq_data_get_chip_type(d);
+	struct regmap *map = gc->private;
+	u32 mask = d->mask;
+
+	irq_gc_lock(gc);
+	regmap_write(map, ct->regs.ack, mask);
+	regmap_write(map, ct->regs.enable, mask);
+	*ct->mask_cache |= mask;
+	irq_gc_unlock(gc);
+}
+
+static void ingenic_tcu_gc_mask_disable_reg(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct irq_chip_type *ct = irq_data_get_chip_type(d);
+	struct regmap *map = gc->private;
+	u32 mask = d->mask;
+
+	irq_gc_lock(gc);
+	regmap_write(map, ct->regs.disable, mask);
+	*ct->mask_cache &= ~mask;
+	irq_gc_unlock(gc);
+}
+
+static void ingenic_tcu_gc_mask_disable_reg_and_ack(struct irq_data *d)
+{
+	struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+	struct irq_chip_type *ct = irq_data_get_chip_type(d);
+	struct regmap *map = gc->private;
+	u32 mask = d->mask;
+
+	irq_gc_lock(gc);
+	regmap_write(map, ct->regs.ack, mask);
+	regmap_write(map, ct->regs.disable, mask);
+	irq_gc_unlock(gc);
+}
+
+static int __init ingenic_tcu_intc_of_init(struct device_node *node,
+	struct device_node *parent)
+{
+	struct irq_domain *domain;
+	struct irq_chip_generic *gc;
+	struct irq_chip_type *ct;
+	int err, i, irqs;
+	u32 parent_irqs[3];
+	struct regmap *map;
+
+	irqs = of_property_count_elems_of_size(node, "interrupts", sizeof(u32));
+	if (irqs < 0 || irqs > ARRAY_SIZE(parent_irqs))
+		return -EINVAL;
+
+	map = syscon_node_to_regmap(node->parent);
+	if (IS_ERR(map))
+		return PTR_ERR(map);
+
+	domain = irq_domain_add_linear(node, 32, &irq_generic_chip_ops, NULL);
+	if (!domain)
+		return -ENOMEM;
+
+	err = irq_alloc_domain_generic_chips(domain, 32, 1, "TCU",
+			handle_level_irq, 0, IRQ_NOPROBE | IRQ_LEVEL, 0);
+	if (err)
+		goto out_domain_remove;
+
+	gc = irq_get_domain_generic_chip(domain, 0);
+	ct = gc->chip_types;
+
+	gc->wake_enabled = IRQ_MSK(32);
+	gc->private = map;
+
+	ct->regs.disable = TCU_REG_TMSR;
+	ct->regs.enable = TCU_REG_TMCR;
+	ct->regs.ack = TCU_REG_TFCR;
+	ct->chip.irq_unmask = ingenic_tcu_gc_unmask_enable_reg;
+	ct->chip.irq_mask = ingenic_tcu_gc_mask_disable_reg;
+	ct->chip.irq_mask_ack = ingenic_tcu_gc_mask_disable_reg_and_ack;
+	ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
+
+	/* Mask all IRQs by default */
+	regmap_write(map, TCU_REG_TMSR, IRQ_MSK(32));
+
+	/* On JZ4740, timer 0 and timer 1 have their own interrupt line;
+	 * timers 2-7 share one interrupt.
+	 * On SoCs >= JZ4770, timer 5 has its own interrupt line;
+	 * timers 0-4 and 6-7 share one single interrupt.
+	 *
+	 * To keep things simple, we just register the same handler to
+	 * all parent interrupts. The handler will properly detect which
+	 * channel fired the interrupt.
+	 */
+	for (i = 0; i < irqs; i++) {
+		parent_irqs[i] = irq_of_parse_and_map(node, i);
+		if (!parent_irqs[i]) {
+			err = -EINVAL;
+			goto out_unmap_irqs;
+		}
+
+		irq_set_chained_handler_and_data(parent_irqs[i],
+				ingenic_tcu_intc_cascade, domain);
+	}
+
+	return 0;
+
+out_unmap_irqs:
+	for (; i > 0; i--)
+		irq_dispose_mapping(parent_irqs[i - 1]);
+out_domain_remove:
+	irq_domain_remove(domain);
+	return err;
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+IRQCHIP_DECLARE(jz4740_tcu_intc, "ingenic,jz4740-tcu-intc",
+		ingenic_tcu_intc_of_init);
+IRQCHIP_DECLARE(jz4770_tcu_intc, "ingenic,jz4770-tcu-intc",
+		ingenic_tcu_intc_of_init);
+IRQCHIP_DECLARE(jz4780_tcu_intc, "ingenic,jz4780-tcu-intc",
+		ingenic_tcu_intc_of_init);
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 7/8] clocksource: Add a new timer-ingenic driver
From: Paul Cercueil @ 2018-03-17 23:29 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

This driver will use the TCU (Timer Counter Unit) present on the Ingenic
JZ47xx SoCs to provide the kernel with a clocksource and timers.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 drivers/clocksource/Kconfig         |   8 ++
 drivers/clocksource/Makefile        |   1 +
 drivers/clocksource/timer-ingenic.c | 278 ++++++++++++++++++++++++++++++++++++
 3 files changed, 287 insertions(+)
 create mode 100644 drivers/clocksource/timer-ingenic.c

 v2: Use SPDX identifier for the license
 v3: - Move documentation to its own patch
     - Search the devicetree for PWM clients, and use all the TCU
	   channels that won't be used for PWM
 v4: - Add documentation about why we search for PWM clients
     - Verify that the PWM clients are for the TCU PWM driver

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index d2e5382821a4..481422145fb4 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -592,4 +592,12 @@ config CLKSRC_ST_LPC
 	  Enable this option to use the Low Power controller timer
 	  as clocksource.
 
+config INGENIC_TIMER
+	bool "Clocksource/timer using the TCU in Ingenic JZ SoCs"
+	depends on MACH_INGENIC || COMPILE_TEST
+	select CLKSRC_OF
+	default y
+	help
+	  Support for the timer/counter unit of the Ingenic JZ SoCs.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index d6dec4489d66..98691e8999fe 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -74,5 +74,6 @@ obj-$(CONFIG_ASM9260_TIMER)		+= asm9260_timer.o
 obj-$(CONFIG_H8300_TMR8)		+= h8300_timer8.o
 obj-$(CONFIG_H8300_TMR16)		+= h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)			+= h8300_tpu.o
+obj-$(CONFIG_INGENIC_TIMER)		+= timer-ingenic.o
 obj-$(CONFIG_CLKSRC_ST_LPC)		+= clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP)		+= numachip.o
diff --git a/drivers/clocksource/timer-ingenic.c b/drivers/clocksource/timer-ingenic.c
new file mode 100644
index 000000000000..8c777c0c0023
--- /dev/null
+++ b/drivers/clocksource/timer-ingenic.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ingenic JZ47xx SoC TCU clocksource driver
+ * Copyright (C) 2018 Paul Cercueil <paul@crapouillou.net>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/ingenic-tcu.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define NUM_CHANNELS	8
+
+struct ingenic_tcu;
+
+struct ingenic_tcu_channel {
+	unsigned int idx;
+	struct clk *clk;
+};
+
+struct ingenic_tcu {
+	struct ingenic_tcu_channel channels[NUM_CHANNELS];
+	unsigned long requested;
+	struct regmap *map;
+};
+
+struct ingenic_clock_event_device {
+	struct clock_event_device cevt;
+	struct ingenic_tcu_channel *channel;
+	char name[32];
+};
+
+#define ingenic_cevt(_evt) \
+	container_of(_evt, struct ingenic_clock_event_device, cevt)
+
+static inline struct ingenic_tcu *to_ingenic_tcu(struct ingenic_tcu_channel *ch)
+{
+	return container_of(ch, struct ingenic_tcu, channels[ch->idx]);
+}
+
+static int ingenic_tcu_cevt_set_state_shutdown(struct clock_event_device *evt)
+{
+	struct ingenic_clock_event_device *jzcevt = ingenic_cevt(evt);
+	struct ingenic_tcu_channel *channel = jzcevt->channel;
+	struct ingenic_tcu *tcu = to_ingenic_tcu(channel);
+	unsigned int idx = channel->idx;
+
+	regmap_write(tcu->map, TCU_REG_TECR, BIT(idx));
+	return 0;
+}
+
+static int ingenic_tcu_cevt_set_next(unsigned long next,
+		struct clock_event_device *evt)
+{
+	struct ingenic_clock_event_device *jzcevt = ingenic_cevt(evt);
+	struct ingenic_tcu_channel *channel = jzcevt->channel;
+	struct ingenic_tcu *tcu = to_ingenic_tcu(channel);
+	unsigned int idx = channel->idx;
+
+	if (next > 0xffff)
+		return -EINVAL;
+
+	regmap_write(tcu->map, TCU_REG_TDFRc(idx), (unsigned int) next);
+	regmap_write(tcu->map, TCU_REG_TCNTc(idx), 0);
+	regmap_write(tcu->map, TCU_REG_TESR, BIT(idx));
+
+	return 0;
+}
+
+static irqreturn_t ingenic_tcu_cevt_cb(int irq, void *dev_id)
+{
+	struct clock_event_device *cevt = dev_id;
+	struct ingenic_clock_event_device *jzcevt = ingenic_cevt(cevt);
+	struct ingenic_tcu_channel *channel = jzcevt->channel;
+	struct ingenic_tcu *tcu = to_ingenic_tcu(channel);
+	unsigned int idx = channel->idx;
+
+	regmap_write(tcu->map, TCU_REG_TECR, BIT(idx));
+
+	if (cevt->event_handler)
+		cevt->event_handler(cevt);
+
+	return IRQ_HANDLED;
+}
+
+static int __init ingenic_tcu_req_channel(struct ingenic_tcu_channel *channel)
+{
+	struct ingenic_tcu *tcu = to_ingenic_tcu(channel);
+	char buf[16];
+	int err;
+
+	if (test_and_set_bit(channel->idx, &tcu->requested))
+		return -EBUSY;
+
+	snprintf(buf, sizeof(buf), "timer%u", channel->idx);
+	channel->clk = clk_get(NULL, buf);
+	if (IS_ERR(channel->clk)) {
+		err = PTR_ERR(channel->clk);
+		goto out_release;
+	}
+
+	err = clk_prepare_enable(channel->clk);
+	if (err)
+		goto out_clk_put;
+
+	return 0;
+
+out_clk_put:
+	clk_put(channel->clk);
+out_release:
+	clear_bit(channel->idx, &tcu->requested);
+	return err;
+}
+
+static int __init ingenic_tcu_reset_channel(struct device_node *np,
+		struct ingenic_tcu_channel *channel)
+{
+	struct ingenic_tcu *tcu = to_ingenic_tcu(channel);
+
+	return regmap_update_bits(tcu->map, TCU_REG_TCSRc(channel->idx),
+				0xffff & ~TCU_TCSR_RESERVED_BITS, 0);
+}
+
+static void __init ingenic_tcu_free_channel(struct ingenic_tcu_channel *channel)
+{
+	struct ingenic_tcu *tcu = to_ingenic_tcu(channel);
+
+	clk_disable_unprepare(channel->clk);
+	clk_put(channel->clk);
+	clear_bit(channel->idx, &tcu->requested);
+}
+
+static const char * const ingenic_tcu_timer_names[] = {
+	"TCU0", "TCU1", "TCU2", "TCU3", "TCU4", "TCU5", "TCU6", "TCU7",
+};
+
+static int __init ingenic_tcu_setup_cevt(struct device_node *np,
+		struct ingenic_tcu *tcu, unsigned int idx)
+{
+	struct ingenic_tcu_channel *channel = &tcu->channels[idx];
+	struct ingenic_clock_event_device *jzcevt;
+	unsigned long rate;
+	int err, virq;
+
+	err = ingenic_tcu_req_channel(channel);
+	if (err)
+		return err;
+
+	err = ingenic_tcu_reset_channel(np, channel);
+	if (err)
+		goto err_out_free_channel;
+
+	rate = clk_get_rate(channel->clk);
+	if (!rate) {
+		err = -EINVAL;
+		goto err_out_free_channel;
+	}
+
+	jzcevt = kzalloc(sizeof(*jzcevt), GFP_KERNEL);
+	if (!jzcevt) {
+		err = -ENOMEM;
+		goto err_out_free_channel;
+	}
+
+	virq = irq_of_parse_and_map(np, idx);
+	if (!virq) {
+		err = -EINVAL;
+		goto err_out_kfree_jzcevt;
+	}
+
+	err = request_irq(virq, ingenic_tcu_cevt_cb, IRQF_TIMER,
+			ingenic_tcu_timer_names[idx], &jzcevt->cevt);
+	if (err)
+		goto err_out_irq_dispose_mapping;
+
+	jzcevt->channel = channel;
+	snprintf(jzcevt->name, sizeof(jzcevt->name), "ingenic-tcu-chan%u",
+		 channel->idx);
+
+	jzcevt->cevt.cpumask = cpumask_of(smp_processor_id());
+	jzcevt->cevt.features = CLOCK_EVT_FEAT_ONESHOT;
+	jzcevt->cevt.name = jzcevt->name;
+	jzcevt->cevt.rating = 200;
+	jzcevt->cevt.set_state_shutdown = ingenic_tcu_cevt_set_state_shutdown;
+	jzcevt->cevt.set_next_event = ingenic_tcu_cevt_set_next;
+
+	clockevents_config_and_register(&jzcevt->cevt, rate, 10, (1 << 16) - 1);
+
+	return 0;
+
+err_out_irq_dispose_mapping:
+	irq_dispose_mapping(virq);
+err_out_kfree_jzcevt:
+	kfree(jzcevt);
+err_out_free_channel:
+	ingenic_tcu_free_channel(channel);
+	return err;
+}
+
+static int __init ingenic_tcu_init(struct device_node *np)
+{
+	unsigned long available_channels = GENMASK(NUM_CHANNELS - 1, 0);
+	struct device_node *node, *pwm_driver_node;
+	struct ingenic_tcu *tcu;
+	unsigned int i, channel;
+	int err;
+	u32 val;
+
+	/* Parse the devicetree for clients of the TCU PWM driver;
+	 * every TCU channel not requested for PWM will be used as
+	 * a timer.
+	 */
+	for_each_node_with_property(node, "pwms") {
+		/* Get the PWM channel ID (field 1 of the "pwms" node) */
+		err = of_property_read_u32_index(node, "pwms", 1, &val);
+		if (!err && val >= NUM_CHANNELS)
+			err = -EINVAL;
+		if (err) {
+			pr_err("timer-ingenic: Unable to parse PWM nodes!");
+			break;
+		}
+
+		/* Get the PWM driver node (field 0 of the "pwms" node) */
+		pwm_driver_node = of_parse_phandle(node, "pwms", 0);
+		if (!pwm_driver_node) {
+			pr_err("timer-ingenic: Unable to find PWM driver node");
+			break;
+		}
+
+		/* Verify that the node we found is for the TCU PWM driver,
+		 * by checking that this driver and the PWM driver passed
+		 * as phandle share the same parent (the "ingenic,tcu"
+		 * compatible MFD/syscon node).
+		 */
+		if (pwm_driver_node->parent != np->parent)
+			continue;
+
+		pr_info("timer-ingenic: Reserving channel %u for PWM", val);
+		available_channels &= ~BIT(val);
+	}
+
+	tcu = kzalloc(sizeof(*tcu), GFP_KERNEL);
+	if (!tcu)
+		return -ENOMEM;
+
+	tcu->map = syscon_node_to_regmap(np->parent);
+	if (IS_ERR(tcu->map)) {
+		err = PTR_ERR(tcu->map);
+		kfree(tcu);
+		return err;
+	}
+
+	for (i = 0; i < NUM_CHANNELS; i++)
+		tcu->channels[i].idx = i;
+
+	for_each_set_bit(channel, &available_channels, NUM_CHANNELS) {
+		err = ingenic_tcu_setup_cevt(np, tcu, channel);
+		if (err) {
+			pr_warn("timer-ingenic: Unable to init TCU channel %u: %i",
+					channel, err);
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+/* We only probe via devicetree, no need for a platform driver */
+CLOCKSOURCE_OF_DECLARE(jz4740_tcu, "ingenic,jz4740-tcu", ingenic_tcu_init);
+CLOCKSOURCE_OF_DECLARE(jz4770_tcu, "ingenic,jz4770-tcu", ingenic_tcu_init);
+CLOCKSOURCE_OF_DECLARE(jz4780_tcu, "ingenic,jz4780-tcu", ingenic_tcu_init);
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 8/8] MAINTAINERS: Add myself as maintainer for Ingenic TCU drivers
From: Paul Cercueil @ 2018-03-17 23:29 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

Add myself as maintainer for the ingenic-tcu-intc interrupt controller
driver, the ingenic-tcu-clocks clock driver, and the ingenic-tcu
clocksource driver.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
---
 MAINTAINERS | 9 +++++++++
 1 file changed, 9 insertions(+)

 v2: No change
 v3: No change
 v4: No change

diff --git a/MAINTAINERS b/MAINTAINERS
index 4623caf8d72d..46d3955b92aa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6959,6 +6959,15 @@ L:	linux-mtd@lists.infradead.org
 S:	Maintained
 F:	drivers/mtd/nand/jz4780_*
 
+INGENIC JZ47xx TCU drivers
+M:	Paul Cercueil <paul@crapouillou.net>
+S:	Maintained
+F:	drivers/clk/ingenic/tcu.c
+F:	drivers/irqchip/irq-ingenic-tcu.c
+F:	drivers/clocksource/timer-ingenic.c
+F:	include/linux/mfd/syscon/ingenic-tcu.h
+F:	include/dt-bindings/clock/ingenic,tcu.h
+
 INOTIFY
 M:	Jan Kara <jack@suse.cz>
 R:	Amir Goldstein <amir73il@gmail.com>
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 1/8] mfd: syscon: Add ingenic-tcu.h header
From: Paul Cercueil @ 2018-03-17 23:28 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc, Paul Cercueil
In-Reply-To: <20180317232901.14129-1-paul@crapouillou.net>

This header contains macros for the registers that are present in the
regmap shared by all the drivers related to the TCU (Timer Counter Unit)
of the Ingenic JZ47xx SoCs.

Signed-off-by: Paul Cercueil <paul@crapouillou.net>
Acked-by: Lee Jones <lee.jones@linaro.org>
---
 include/linux/mfd/syscon/ingenic-tcu.h | 54 ++++++++++++++++++++++++++++++++++
 1 file changed, 54 insertions(+)
 create mode 100644 include/linux/mfd/syscon/ingenic-tcu.h

 v2: Use SPDX identifier for the license
 v3: - Use macros instead of enum
     - Add 'TCU_' at the beginning of each macro
	 - Remove useless include <linux/regmap.h>
 v4: No change

diff --git a/include/linux/mfd/syscon/ingenic-tcu.h b/include/linux/mfd/syscon/ingenic-tcu.h
new file mode 100644
index 000000000000..96dd59f7c3b2
--- /dev/null
+++ b/include/linux/mfd/syscon/ingenic-tcu.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Header file for the Ingenic JZ47xx TCU driver
+ */
+#ifndef __LINUX_CLK_INGENIC_TCU_H_
+#define __LINUX_CLK_INGENIC_TCU_H_
+
+#include <linux/bitops.h>
+
+#define TCU_REG_WDT_TDR		0x00
+#define TCU_REG_WDT_TCER	0x04
+#define TCU_REG_WDT_TCNT	0x08
+#define TCU_REG_WDT_TCSR	0x0c
+#define TCU_REG_TER		0x10
+#define TCU_REG_TESR		0x14
+#define TCU_REG_TECR		0x18
+#define TCU_REG_TSR		0x1c
+#define TCU_REG_TFR		0x20
+#define TCU_REG_TFSR		0x24
+#define TCU_REG_TFCR		0x28
+#define TCU_REG_TSSR		0x2c
+#define TCU_REG_TMR		0x30
+#define TCU_REG_TMSR		0x34
+#define TCU_REG_TMCR		0x38
+#define TCU_REG_TSCR		0x3c
+#define TCU_REG_TDFR0		0x40
+#define TCU_REG_TDHR0		0x44
+#define TCU_REG_TCNT0		0x48
+#define TCU_REG_TCSR0		0x4c
+#define TCU_REG_OST_DR		0xe0
+#define TCU_REG_OST_CNTL	0xe4
+#define TCU_REG_OST_CNTH	0xe8
+#define TCU_REG_OST_TCSR	0xec
+#define TCU_REG_TSTR		0xf0
+#define TCU_REG_TSTSR		0xf4
+#define TCU_REG_TSTCR		0xf8
+#define TCU_REG_OST_CNTHBUF	0xfc
+
+#define TCU_TCSR_RESERVED_BITS		0x3f
+#define TCU_TCSR_PARENT_CLOCK_MASK	0x07
+#define TCU_TCSR_PRESCALE_LSB		3
+#define TCU_TCSR_PRESCALE_MASK		0x38
+
+#define TCU_TCSR_PWM_SD		BIT(9)	/* 0: Shutdown abruptly 1: gracefully */
+#define TCU_TCSR_PWM_INITL_HIGH	BIT(8)	/* Sets the initial output level */
+#define TCU_TCSR_PWM_EN		BIT(7)	/* PWM pin output enable */
+
+#define TCU_CHANNEL_STRIDE	0x10
+#define TCU_REG_TDFRc(c)	(TCU_REG_TDFR0 + ((c) * TCU_CHANNEL_STRIDE))
+#define TCU_REG_TDHRc(c)	(TCU_REG_TDHR0 + ((c) * TCU_CHANNEL_STRIDE))
+#define TCU_REG_TCNTc(c)	(TCU_REG_TCNT0 + ((c) * TCU_CHANNEL_STRIDE))
+#define TCU_REG_TCSRc(c)	(TCU_REG_TCSR0 + ((c) * TCU_CHANNEL_STRIDE))
+
+#endif /* __LINUX_CLK_INGENIC_TCU_H_ */
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v4 0/8] Ingenic JZ47xx Timer/Counter Unit drivers
From: Paul Cercueil @ 2018-03-17 23:28 UTC (permalink / raw)
  To: Thomas Gleixner, Jason Cooper, Marc Zyngier, Lee Jones,
	Daniel Lezcano, Ralf Baechle, Rob Herring, Jonathan Corbet,
	Mark Rutland
  Cc: James Hogan, Maarten ter Huurne, linux-clk, devicetree,
	linux-kernel, linux-mips, linux-doc
In-Reply-To: <20180110224838.16711-2-paul@crapouillou.net>

Hi,

This is the 4th version of my TCU patchset.

The major change is a greatly improved documentation, both in-code
and as separate text files, to describe how the hardware works and
how the devicetree bindings should be used.

There are also cosmetic changes in the irqchip driver, and the
clocksource driver will now use as timers all TCU channels not
requested by the TCU PWM driver.

Cheers,
-Paul

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [RESEND PATCH v5] input: pxrc: new driver for PhoenixRC Flight Controller Adapter
From: Dmitry Torokhov @ 2018-03-17 18:10 UTC (permalink / raw)
  To: Marcus Folkesson; +Cc: Jonathan Corbet, linux-input, linux-doc, linux-kernel
In-Reply-To: <20180218161747.21110-1-marcus.folkesson@gmail.com>

On Sun, Feb 18, 2018 at 05:17:46PM +0100, Marcus Folkesson wrote:
> This driver let you plug in your RC controller to the adapter and
> use it as input device in various RC simulators.
> 
> Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>

Applied, thank you.

> ---
> 
> v5:
> 	- Drop autosuspend support
> 	- Use pm_mutex instead of input_dev->mutex
> 	- Use pxrc->is_open instead of input_dev->users
> v4:
> 	- Add call to usb_mark_last_busy() in irq
> 	- Move code from pxrc_resume() to pxrc_reset_resume()
> v3:
> 	- Use RUDDER and MISC instead of TILT_X and TILT_Y
> 	- Drop kref and anchor
> 	- Rework URB handling
> 	- Add PM support
> v2:
> 	- Change module license to GPLv2 to match SPDX tag
> 
> 
>  Documentation/input/devices/pxrc.rst |  57 +++++++
>  drivers/input/joystick/Kconfig       |   9 ++
>  drivers/input/joystick/Makefile      |   1 +
>  drivers/input/joystick/pxrc.c        | 303 +++++++++++++++++++++++++++++++++++
>  4 files changed, 370 insertions(+)
>  create mode 100644 Documentation/input/devices/pxrc.rst
>  create mode 100644 drivers/input/joystick/pxrc.c
> 
> diff --git a/Documentation/input/devices/pxrc.rst b/Documentation/input/devices/pxrc.rst
> new file mode 100644
> index 000000000000..ca11f646bae8
> --- /dev/null
> +++ b/Documentation/input/devices/pxrc.rst
> @@ -0,0 +1,57 @@
> +=======================================================
> +pxrc - PhoenixRC Flight Controller Adapter
> +=======================================================
> +
> +:Author: Marcus Folkesson <marcus.folkesson@gmail.com>
> +
> +This driver let you use your own RC controller plugged into the
> +adapter that comes with PhoenixRC [1]_ or other compatible adapters.
> +
> +The adapter supports 7 analog channels and 1 digital input switch.
> +
> +Notes
> +=====
> +
> +Many RC controllers is able to configure which stick goes to which channel.
> +This is also configurable in most simulators, so a matching is not necessary.
> +
> +The driver is generating the following input event for analog channels:
> +
> ++---------+----------------+
> +| Channel |      Event     |
> ++=========+================+
> +|     1   |  ABS_X         |
> ++---------+----------------+
> +|     2   |  ABS_Y         |
> ++---------+----------------+
> +|     3   |  ABS_RX        |
> ++---------+----------------+
> +|     4   |  ABS_RY        |
> ++---------+----------------+
> +|     5   |  ABS_RUDDER    |
> ++---------+----------------+
> +|     6   |  ABS_THROTTLE  |
> ++---------+----------------+
> +|     7   |  ABS_MISC      |
> ++---------+----------------+
> +
> +The digital input switch is generated as an `BTN_A` event.
> +
> +Manual Testing
> +==============
> +
> +To test this driver's functionality you may use `input-event` which is part of
> +the `input layer utilities` suite [2]_.
> +
> +For example::
> +
> +    > modprobe pxrc
> +    > input-events <devnr>
> +
> +To print all input events from input `devnr`.
> +
> +References
> +==========
> +
> +.. [1] http://www.phoenix-sim.com/
> +.. [2] https://www.kraxel.org/cgit/input/
> diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
> index f3c2f6ea8b44..332c0cc1b2ab 100644
> --- a/drivers/input/joystick/Kconfig
> +++ b/drivers/input/joystick/Kconfig
> @@ -351,4 +351,13 @@ config JOYSTICK_PSXPAD_SPI_FF
>  
>  	  To drive rumble motor a dedicated power supply is required.
>  
> +config JOYSTICK_PXRC
> +	tristate "PhoenixRC Flight Controller Adapter"
> +	depends on USB_ARCH_HAS_HCD
> +	depends on USB
> +	help
> +	  Say Y here if you want to use the PhoenixRC Flight Controller Adapter.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called pxrc.
>  endif
> diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
> index 67651efda2e1..dd0492ebbed7 100644
> --- a/drivers/input/joystick/Makefile
> +++ b/drivers/input/joystick/Makefile
> @@ -23,6 +23,7 @@ obj-$(CONFIG_JOYSTICK_JOYDUMP)		+= joydump.o
>  obj-$(CONFIG_JOYSTICK_MAGELLAN)		+= magellan.o
>  obj-$(CONFIG_JOYSTICK_MAPLE)		+= maplecontrol.o
>  obj-$(CONFIG_JOYSTICK_PSXPAD_SPI)	+= psxpad-spi.o
> +obj-$(CONFIG_JOYSTICK_PXRC)			+= pxrc.o
>  obj-$(CONFIG_JOYSTICK_SIDEWINDER)	+= sidewinder.o
>  obj-$(CONFIG_JOYSTICK_SPACEBALL)	+= spaceball.o
>  obj-$(CONFIG_JOYSTICK_SPACEORB)		+= spaceorb.o
> diff --git a/drivers/input/joystick/pxrc.c b/drivers/input/joystick/pxrc.c
> new file mode 100644
> index 000000000000..07a0dbd3ced2
> --- /dev/null
> +++ b/drivers/input/joystick/pxrc.c
> @@ -0,0 +1,303 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Driver for Phoenix RC Flight Controller Adapter
> + *
> + * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
> + *
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/uaccess.h>
> +#include <linux/usb.h>
> +#include <linux/usb/input.h>
> +#include <linux/mutex.h>
> +#include <linux/input.h>
> +
> +#define PXRC_VENDOR_ID	(0x1781)
> +#define PXRC_PRODUCT_ID	(0x0898)
> +
> +static const struct usb_device_id pxrc_table[] = {
> +	{ USB_DEVICE(PXRC_VENDOR_ID, PXRC_PRODUCT_ID) },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(usb, pxrc_table);
> +
> +struct pxrc {
> +	struct input_dev	*input;
> +	struct usb_device	*udev;
> +	struct usb_interface	*intf;
> +	struct urb		*urb;
> +	struct mutex		pm_mutex;
> +	bool			is_open;
> +	__u8			epaddr;
> +	char			phys[64];
> +	unsigned char           *data;
> +	size_t			bsize;
> +};
> +
> +static void pxrc_usb_irq(struct urb *urb)
> +{
> +	struct pxrc *pxrc = urb->context;
> +	int error;
> +
> +	switch (urb->status) {
> +	case 0:
> +		/* success */
> +		break;
> +	case -ETIME:
> +		/* this urb is timing out */
> +		dev_dbg(&pxrc->intf->dev,
> +			"%s - urb timed out - was the device unplugged?\n",
> +			__func__);
> +		return;
> +	case -ECONNRESET:
> +	case -ENOENT:
> +	case -ESHUTDOWN:
> +	case -EPIPE:
> +		/* this urb is terminated, clean up */
> +		dev_dbg(&pxrc->intf->dev, "%s - urb shutting down with status: %d\n",
> +			__func__, urb->status);
> +		return;
> +	default:
> +		dev_dbg(&pxrc->intf->dev, "%s - nonzero urb status received: %d\n",
> +			__func__, urb->status);
> +		goto exit;
> +	}
> +
> +	if (urb->actual_length == 8) {
> +		input_report_abs(pxrc->input, ABS_X, pxrc->data[0]);
> +		input_report_abs(pxrc->input, ABS_Y, pxrc->data[2]);
> +		input_report_abs(pxrc->input, ABS_RX, pxrc->data[3]);
> +		input_report_abs(pxrc->input, ABS_RY, pxrc->data[4]);
> +		input_report_abs(pxrc->input, ABS_RUDDER, pxrc->data[5]);
> +		input_report_abs(pxrc->input, ABS_THROTTLE, pxrc->data[6]);
> +		input_report_abs(pxrc->input, ABS_MISC, pxrc->data[7]);
> +
> +		input_report_key(pxrc->input, BTN_A, pxrc->data[1]);
> +	}
> +
> +exit:
> +	/* Resubmit to fetch new fresh URBs */
> +	error = usb_submit_urb(urb, GFP_ATOMIC);
> +	if (error && error != -EPERM)
> +		dev_err(&pxrc->intf->dev,
> +			"%s - usb_submit_urb failed with result: %d",
> +			__func__, error);
> +}
> +
> +static int pxrc_open(struct input_dev *input)
> +{
> +	struct pxrc *pxrc = input_get_drvdata(input);
> +	int retval;
> +
> +	mutex_lock(&pxrc->pm_mutex);
> +	retval = usb_submit_urb(pxrc->urb, GFP_KERNEL);
> +	if (retval) {
> +		dev_err(&pxrc->intf->dev,
> +			"%s - usb_submit_urb failed, error: %d\n",
> +			__func__, retval);
> +		retval = -EIO;
> +		goto out;
> +	}
> +
> +	pxrc->is_open = true;
> +
> +out:
> +	mutex_unlock(&pxrc->pm_mutex);
> +	return retval;
> +}
> +
> +static void pxrc_close(struct input_dev *input)
> +{
> +	struct pxrc *pxrc = input_get_drvdata(input);
> +
> +	mutex_lock(&pxrc->pm_mutex);
> +	usb_kill_urb(pxrc->urb);
> +	pxrc->is_open = false;
> +	mutex_unlock(&pxrc->pm_mutex);
> +}
> +
> +static int pxrc_usb_init(struct pxrc *pxrc)
> +{
> +	struct usb_endpoint_descriptor *epirq;
> +	unsigned int pipe;
> +	int retval;
> +
> +	/* Set up the endpoint information */
> +	/* This device only has an interrupt endpoint */
> +	retval = usb_find_common_endpoints(pxrc->intf->cur_altsetting,
> +			NULL, NULL, &epirq, NULL);
> +	if (retval) {
> +		dev_err(&pxrc->intf->dev,
> +			"Could not find endpoint\n");
> +		goto error;
> +	}
> +
> +	pxrc->bsize = usb_endpoint_maxp(epirq);
> +	pxrc->epaddr = epirq->bEndpointAddress;
> +	pxrc->data = devm_kmalloc(&pxrc->intf->dev, pxrc->bsize, GFP_KERNEL);
> +	if (!pxrc->data) {
> +		retval = -ENOMEM;
> +		goto error;
> +	}
> +
> +	usb_set_intfdata(pxrc->intf, pxrc);
> +	usb_make_path(pxrc->udev, pxrc->phys, sizeof(pxrc->phys));
> +	strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
> +
> +	pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
> +	if (!pxrc->urb) {
> +		retval = -ENOMEM;
> +		goto error;
> +	}
> +
> +	pipe = usb_rcvintpipe(pxrc->udev, pxrc->epaddr),
> +	usb_fill_int_urb(pxrc->urb, pxrc->udev, pipe, pxrc->data, pxrc->bsize,
> +						pxrc_usb_irq, pxrc, 1);
> +
> +error:
> +	return retval;
> +
> +
> +}
> +
> +static int pxrc_input_init(struct pxrc *pxrc)
> +{
> +	pxrc->input = devm_input_allocate_device(&pxrc->intf->dev);
> +	if (pxrc->input == NULL) {
> +		dev_err(&pxrc->intf->dev, "couldn't allocate input device\n");
> +		return -ENOMEM;
> +	}
> +
> +	pxrc->input->name = "PXRC Flight Controller Adapter";
> +	pxrc->input->phys = pxrc->phys;
> +	usb_to_input_id(pxrc->udev, &pxrc->input->id);
> +
> +	pxrc->input->open = pxrc_open;
> +	pxrc->input->close = pxrc_close;
> +
> +	input_set_capability(pxrc->input, EV_KEY, BTN_A);
> +	input_set_abs_params(pxrc->input, ABS_X, 0, 255, 0, 0);
> +	input_set_abs_params(pxrc->input, ABS_Y, 0, 255, 0, 0);
> +	input_set_abs_params(pxrc->input, ABS_RX, 0, 255, 0, 0);
> +	input_set_abs_params(pxrc->input, ABS_RY, 0, 255, 0, 0);
> +	input_set_abs_params(pxrc->input, ABS_RUDDER, 0, 255, 0, 0);
> +	input_set_abs_params(pxrc->input, ABS_THROTTLE, 0, 255, 0, 0);
> +	input_set_abs_params(pxrc->input, ABS_MISC, 0, 255, 0, 0);
> +
> +	input_set_drvdata(pxrc->input, pxrc);
> +
> +	return input_register_device(pxrc->input);
> +}
> +
> +static int pxrc_probe(struct usb_interface *intf,
> +		      const struct usb_device_id *id)
> +{
> +	struct pxrc *pxrc;
> +	int retval;
> +
> +	pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
> +	if (!pxrc)
> +		return -ENOMEM;
> +
> +	mutex_init(&pxrc->pm_mutex);
> +	pxrc->udev = usb_get_dev(interface_to_usbdev(intf));
> +	pxrc->intf = intf;
> +
> +	retval = pxrc_usb_init(pxrc);
> +	if (retval)
> +		goto error;
> +
> +	retval = pxrc_input_init(pxrc);
> +	if (retval)
> +		goto err_free_urb;
> +
> +	return 0;
> +
> +err_free_urb:
> +	usb_free_urb(pxrc->urb);
> +
> +error:
> +	return retval;
> +}
> +
> +static void pxrc_disconnect(struct usb_interface *intf)
> +{
> +	struct pxrc *pxrc = usb_get_intfdata(intf);
> +
> +	usb_free_urb(pxrc->urb);
> +	usb_set_intfdata(intf, NULL);
> +}
> +
> +static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)
> +{
> +	struct pxrc *pxrc = usb_get_intfdata(intf);
> +
> +	mutex_lock(&pxrc->pm_mutex);
> +	if (pxrc->is_open)
> +		usb_kill_urb(pxrc->urb);
> +	mutex_unlock(&pxrc->pm_mutex);
> +
> +	return 0;
> +}
> +
> +static int pxrc_resume(struct usb_interface *intf)
> +{
> +	struct pxrc *pxrc = usb_get_intfdata(intf);
> +	int retval = 0;
> +
> +	mutex_lock(&pxrc->pm_mutex);
> +	if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
> +		retval = -EIO;
> +
> +	mutex_unlock(&pxrc->pm_mutex);
> +	return retval;
> +}
> +
> +static int pxrc_pre_reset(struct usb_interface *intf)
> +{
> +	struct pxrc *pxrc = usb_get_intfdata(intf);
> +
> +	mutex_lock(&pxrc->pm_mutex);
> +	usb_kill_urb(pxrc->urb);
> +	return 0;
> +}
> +
> +static int pxrc_post_reset(struct usb_interface *intf)
> +{
> +	struct pxrc *pxrc = usb_get_intfdata(intf);
> +	int retval = 0;
> +
> +	if (pxrc->is_open && usb_submit_urb(pxrc->urb, GFP_KERNEL) < 0)
> +		retval = -EIO;
> +
> +	mutex_unlock(&pxrc->pm_mutex);
> +
> +	return retval;
> +}
> +
> +static int pxrc_reset_resume(struct usb_interface *intf)
> +{
> +	return pxrc_resume(intf);
> +}
> +
> +static struct usb_driver pxrc_driver = {
> +	.name =		"pxrc",
> +	.probe =	pxrc_probe,
> +	.disconnect =	pxrc_disconnect,
> +	.id_table =	pxrc_table,
> +	.suspend	= pxrc_suspend,
> +	.resume		= pxrc_resume,
> +	.pre_reset	= pxrc_pre_reset,
> +	.post_reset	= pxrc_post_reset,
> +	.reset_resume	= pxrc_reset_resume,
> +};
> +
> +module_usb_driver(pxrc_driver);
> +
> +MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
> +MODULE_DESCRIPTION("PhoenixRC Flight Controller Adapter");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.15.1
> 

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v5 1/9] sysctl: Add flags to support min/max range clamping
From: Luis R. Rodriguez @ 2018-03-17  1:10 UTC (permalink / raw)
  To: Waiman Long
  Cc: Luis R. Rodriguez, Kees Cook, linux-kernel, linux-fsdevel,
	linux-doc, Jonathan Corbet, Andrew Morton, Al Viro,
	Matthew Wilcox, Eric W. Biederman
In-Reply-To: <1521224030-2185-2-git-send-email-longman@redhat.com>

On Fri, Mar 16, 2018 at 02:13:42PM -0400, Waiman Long wrote:
> When the CTL_FLAGS_CLAMP_RANGE flag is set in the ctl_table
> entry, any update from the userspace will be clamped to the given
> range without error if either the proc_dointvec_minmax() or the
> proc_douintvec_minmax() handlers is used.

I don't get it.  Why define a generic range flag when we can be mores specific and
you do that in your next patch. What's the point of this flag then?

  Luis
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v5 2/9] proc/sysctl: Provide additional ctl_table.flags checks
From: Luis R. Rodriguez @ 2018-03-17  0:54 UTC (permalink / raw)
  To: Waiman Long
  Cc: Luis R. Rodriguez, Kees Cook, linux-kernel, linux-fsdevel,
	linux-doc, Jonathan Corbet, Andrew Morton, Al Viro,
	Matthew Wilcox, Eric W. Biederman
In-Reply-To: <1521224030-2185-3-git-send-email-longman@redhat.com>

On Fri, Mar 16, 2018 at 02:13:43PM -0400, Waiman Long wrote:
> Checking code is added to provide the following additional
> ctl_table.flags checks:
> 
>  1) No unknown flag is allowed.
>  2) Minimum of a range cannot be larger than the maximum value.
>  3) The signed and unsigned flags are mutually exclusive.
>  4) The proc_handler should be consistent with the signed or unsigned
>     flags.
> 
> Two new flags are added to indicate if the min/max values are signed
> or unsigned - CTL_FLAGS_SIGNED_RANGE & CTL_FLAGS_UNSIGNED_RANGE.
> These 2 flags can be optionally enabled for range checking purpose.
> But either one of them must be set with CTL_FLAGS_CLAMP_RANGE.
> 
> Signed-off-by: Waiman Long <longman@redhat.com>
> ---

> diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
> index e446e1f..088f032 100644
> --- a/include/linux/sysctl.h
> +++ b/include/linux/sysctl.h
> @@ -134,14 +134,26 @@ struct ctl_table
>   *	the input value. No lower bound or upper bound checking will be
>   *	done if the corresponding minimum or maximum value isn't provided.
>   *
> + * @CTL_FLAGS_SIGNED_RANGE: Set to indicate that the extra1 and extra2
> + *	fields are pointers to minimum and maximum signed values of
> + *	an allowable range.
> + *
> + * @CTL_FLAGS_UNSIGNED_RANGE: Set to indicate that the extra1 and extra2
> + *	fields are pointers to minimum and maximum unsigned values of
> + *	an allowable range.
> + *
>   * At most 16 different flags are allowed.
>   */
>  enum ctl_table_flags {
>  	CTL_FLAGS_CLAMP_RANGE		= BIT(0),
> -	__CTL_FLAGS_MAX			= BIT(1),
> +	CTL_FLAGS_SIGNED_RANGE		= BIT(1),
> +	CTL_FLAGS_UNSIGNED_RANGE	= BIT(2),
> +	__CTL_FLAGS_MAX			= BIT(3),
>  };

You are adding new flags which the user can set, and yet these are used
internally.

It would be best if internal flags are just that, not flags that a user can set.

This patch should be folded with the first one.

I'm starting to loose hope on these patch sets.

  Luis
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v4 6/6] arm64: dts: sdm845: Add I2C controller support
From: Doug Anderson @ 2018-03-16 23:54 UTC (permalink / raw)
  To: Karthikeyan Ramasubramanian
  Cc: Jonathan Corbet, Andy Gross, David Brown, Rob Herring,
	Mark Rutland, Wolfram Sang, Greg Kroah-Hartman, linux-doc,
	linux-arm-msm, devicetree, linux-i2c, linux-serial, Jiri Slaby,
	evgreen, acourbot, swboyd
In-Reply-To: <1521071931-9294-7-git-send-email-kramasub@codeaurora.org>

Hi,

On Wed, Mar 14, 2018 at 4:58 PM, Karthikeyan Ramasubramanian
<kramasub@codeaurora.org> wrote:
> Add I2C master controller support for a built-in test I2C slave.
>
> Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
> ---
>  arch/arm64/boot/dts/qcom/sdm845-mtp.dts | 19 +++++++++++++++++++
>  arch/arm64/boot/dts/qcom/sdm845.dtsi    | 29 +++++++++++++++++++++++++++++
>  2 files changed, 48 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
> index ea3efc5..69445f1 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
> +++ b/arch/arm64/boot/dts/qcom/sdm845-mtp.dts
> @@ -27,6 +27,10 @@
>                 serial@a84000 {
>                         status = "okay";
>                 };
> +
> +               i2c@a88000 {
> +                       status = "okay";

Any idea what clock frequency is appropriate for MTP?  You've got some
pretty beefy 2.2K external pulls I think, so presumably 400 KHz is
what you're aiming for?  It would be nice to specify one so you don't
end up the the spam in the log "Bus frequency not specified ..."


> +               };
>         };
>
>         pinctrl@3400000 {
> @@ -50,5 +54,20 @@
>                                 bias-pull-down;
>                         };
>                 };
> +
> +               qup-i2c10-default {

nit: probably in the pinctrl section we want to sort alphabetically?
We could try to sort by "lowest numbered pin", but IMHO alphabetical
makes the most sense.


> +                       pinconf {
> +                               pins = "gpio55", "gpio56";
> +                               drive-strength = <2>;
> +                               bias-disable;
> +                       };
> +               };
> +
> +               qup-i2c10-sleep {
> +                       pinconf {
> +                               pins = "gpio55", "gpio56";
> +                               bias-pull-up;

Are you sure that you want pullups enabled for sleep here?  There are
external pulls on this line (as there are on many i2c busses) so doing
this will double-enable pulls.  It probably won't hurt, but I'm
curious if there's some sort of reason here.


> +                       };
> +               };
>         };
>  };
> diff --git a/arch/arm64/boot/dts/qcom/sdm845.dtsi b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> index 59334d9..9ef056f 100644
> --- a/arch/arm64/boot/dts/qcom/sdm845.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sdm845.dtsi
> @@ -209,6 +209,21 @@
>                                         pins = "gpio4", "gpio5";
>                                 };
>                         };
> +
> +                       qup_i2c10_default: qup-i2c10-default {
> +                               pinmux {
> +                                       function = "qup10";
> +                                       pins = "gpio55", "gpio56";
> +                               };
> +                       };
> +
> +                       qup_i2c10_sleep: qup-i2c10-sleep {
> +                               pinmux {
> +                                       function = "gpio";
> +                                       pins = "gpio55", "gpio56";
> +                               };
> +                       };
> +
>                 };
>
>                 timer@17c90000 {
> @@ -309,6 +324,20 @@
>                                 interrupts = <GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>;
>                                 status = "disabled";
>                         };
> +
> +                       i2c10: i2c@a88000 {

Seems like it might be nice to add all the i2c busses into the main
sdm845.dtsi file.  Sure, most won't be enabled, but it seems like it
would avoid churn later.

...if you're sure you want to add only one i2c controller, subject of
this patch should indicate that.


> +                               compatible = "qcom,geni-i2c";
> +                               reg = <0xa88000 0x4000>;
> +                               clock-names = "se";
> +                               clocks = <&gcc GCC_QUPV3_WRAP1_S2_CLK>;
> +                               pinctrl-names = "default", "sleep";
> +                               pinctrl-0 = <&qup_i2c10_default>;
> +                               pinctrl-1 = <&qup_i2c10_sleep>;
> +                               interrupts = <GIC_SPI 355 IRQ_TYPE_LEVEL_HIGH>;
> +                               #address-cells = <1>;
> +                               #size-cells = <0>;
> +                               status = "disabled";
> +                       };
>                 };
>         };
>  };
> --
> Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
> a Linux Foundation Collaborative Project
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 1/1] Documentation: clk: enable lock is not held for clk_is_enabled API
From: Stephen Boyd @ 2018-03-16 22:44 UTC (permalink / raw)
  To: Dong Aisheng, linux-doc
  Cc: linux-clk, linux-kernel, linux-arm-kernel, linux-imx,
	Dong Aisheng, Jonathan Corbet, Stephen Boyd
In-Reply-To: <1516369035-24740-1-git-send-email-aisheng.dong@nxp.com>

Quoting Dong Aisheng (2018-01-19 05:37:15)
> The core does not need to hold enable lock for clk_is_enabled API.
> Update the doc to reflect it.
> 
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Stephen Boyd <sboyd@codeaurora.org>
> Suggested-by: Stephen Boyd <sboyd@codeaurora.org>
> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> ---

Applied to clk-next

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v12 22/22] selftests/vm: Fix deadlock in protection_keys.c
From: Dave Hansen @ 2018-03-16 22:34 UTC (permalink / raw)
  To: Ram Pai, shuahkh, linux-kselftest
  Cc: mpe, linuxppc-dev, linux-mm, x86, linux-arch, linux-doc,
	linux-kernel, mingo, akpm, benh, paulus, khandual, aneesh.kumar,
	bsingharora, hbabu, mhocko, bauerman, ebiederm, arnd
In-Reply-To: <1519264541-7621-23-git-send-email-linuxram@us.ibm.com>

On 02/21/2018 05:55 PM, Ram Pai wrote:
> From: Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
> 
> The sig_chld() handler calls dprintf2() taking care of setting
> dprint_in_signal so that sigsafe_printf() won't call printf().
> Unfortunately, this precaution is is negated by dprintf_level(), which
> has a call to fflush().
> 
> This function acquires a lock, which means that if the signal interrupts an
> ongoing fflush() the process will deadlock. At least on powerpc this is
> easy to trigger, resulting in the following backtrace when attaching to the
> frozen process:

Ugh, yeah, I've run into this too.

Acked-by: Dave Hansen <dave.hansen@intel.com>
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v12 21/22] selftests/vm: sub-page allocator
From: Dave Hansen @ 2018-03-16 22:33 UTC (permalink / raw)
  To: Ram Pai, shuahkh, linux-kselftest
  Cc: mpe, linuxppc-dev, linux-mm, x86, linux-arch, linux-doc,
	linux-kernel, mingo, akpm, benh, paulus, khandual, aneesh.kumar,
	bsingharora, hbabu, mhocko, bauerman, ebiederm, arnd
In-Reply-To: <1519264541-7621-22-git-send-email-linuxram@us.ibm.com>

On 02/21/2018 05:55 PM, Ram Pai wrote:
...
> @@ -888,6 +917,7 @@ void setup_hugetlbfs(void)
>  void *(*pkey_malloc[])(long size, int prot, u16 pkey) = {
>  
>  	malloc_pkey_with_mprotect,
> +	malloc_pkey_with_mprotect_subpage,
>  	malloc_pkey_anon_huge,
>  	malloc_pkey_hugetlb
>  /* can not do direct with the pkey_mprotect() API:


I think I'd rather have an #ifdef on the array entries than have the
malloc entry do nothing on x86.  Maybe have a ppc-specific section at
the end?
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v12 20/22] selftests/vm: testcases must restore pkey-permissions
From: Dave Hansen @ 2018-03-16 22:32 UTC (permalink / raw)
  To: Ram Pai, shuahkh, linux-kselftest
  Cc: mpe, linuxppc-dev, linux-mm, x86, linux-arch, linux-doc,
	linux-kernel, mingo, akpm, benh, paulus, khandual, aneesh.kumar,
	bsingharora, hbabu, mhocko, bauerman, ebiederm, arnd
In-Reply-To: <1519264541-7621-21-git-send-email-linuxram@us.ibm.com>

On 02/21/2018 05:55 PM, Ram Pai wrote:
> Generally the signal handler restores the state of the pkey register
> before returning. However there are times when the read/write operation
> can legitamely fail without invoking the signal handler.  Eg: A
> sys_read() operaton to a write-protected page should be disallowed.  In
> such a case the state of the pkey register is not restored to its
> original state.  The test case is responsible for restoring the key
> register state to its original value.

Oh, that's a good point.

Could we just do this in a common place, though?  Like reset the
register after each test?  Seems more foolproof.
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v12 19/22] selftests/vm: detect write violation on a mapped access-denied-key page
From: Dave Hansen @ 2018-03-16 22:31 UTC (permalink / raw)
  To: Ram Pai, shuahkh, linux-kselftest
  Cc: mpe, linuxppc-dev, linux-mm, x86, linux-arch, linux-doc,
	linux-kernel, mingo, akpm, benh, paulus, khandual, aneesh.kumar,
	bsingharora, hbabu, mhocko, bauerman, ebiederm, arnd
In-Reply-To: <1519264541-7621-20-git-send-email-linuxram@us.ibm.com>

On 02/21/2018 05:55 PM, Ram Pai wrote:
> detect write-violation on a page to which access-disabled
> key is associated much after the page is mapped.

Acked-by: Dave Hansen <dave.hansen@intel.com>

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v12 18/22] selftests/vm: associate key on a mapped page and detect write violation
From: Dave Hansen @ 2018-03-16 22:30 UTC (permalink / raw)
  To: Ram Pai, shuahkh, linux-kselftest
  Cc: mpe, linuxppc-dev, linux-mm, x86, linux-arch, linux-doc,
	linux-kernel, mingo, akpm, benh, paulus, khandual, aneesh.kumar,
	bsingharora, hbabu, mhocko, bauerman, ebiederm, arnd
In-Reply-To: <1519264541-7621-19-git-send-email-linuxram@us.ibm.com>

On 02/21/2018 05:55 PM, Ram Pai wrote:
> detect write-violation on a page to which write-disabled
> key is associated much after the page is mapped.

The more tests the merrier.

Acked-by: Dave Hansen <dave.hansen@intel.com>

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v12 17/22] selftests/vm: associate key on a mapped page and detect access violation
From: Dave Hansen @ 2018-03-16 22:30 UTC (permalink / raw)
  To: Ram Pai, shuahkh, linux-kselftest
  Cc: mpe, linuxppc-dev, linux-mm, x86, linux-arch, linux-doc,
	linux-kernel, mingo, akpm, benh, paulus, khandual, aneesh.kumar,
	bsingharora, hbabu, mhocko, bauerman, ebiederm, arnd
In-Reply-To: <1519264541-7621-18-git-send-email-linuxram@us.ibm.com>

On 02/21/2018 05:55 PM, Ram Pai wrote:
> detect access-violation on a page to which access-disabled
> key is associated much after the page is mapped.

Looks fine to me.  Did this actually find a bug for you?

Acked-by: Dave Hansen <dave.hansen@intel.com>

--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v12 16/22] selftests/vm: fix an assertion in test_pkey_alloc_exhaust()
From: Dave Hansen @ 2018-03-16 22:28 UTC (permalink / raw)
  To: Ram Pai, shuahkh, linux-kselftest
  Cc: mpe, linuxppc-dev, linux-mm, x86, linux-arch, linux-doc,
	linux-kernel, mingo, akpm, benh, paulus, khandual, aneesh.kumar,
	bsingharora, hbabu, mhocko, bauerman, ebiederm, arnd
In-Reply-To: <1519264541-7621-17-git-send-email-linuxram@us.ibm.com>

On 02/21/2018 05:55 PM, Ram Pai wrote:
> +static inline int arch_reserved_keys(void)
> +{
> +#if defined(__i386__) || defined(__x86_64__) /* arch */
> +	return NR_RESERVED_PKEYS;
> +#elif __powerpc64__ /* arch */
> +	if (sysconf(_SC_PAGESIZE) == 4096)
> +		return NR_RESERVED_PKEYS_4K;
> +	else
> +		return NR_RESERVED_PKEYS_64K;
> +#else /* arch */
> +	NOT SUPPORTED
> +#endif /* arch */
> +}

Yeah, this is hideous.

Please either do it in one header:

#ifdef x86..
static inline int arch_reserved_keys(void)
{
}
...
#elif ppc
static inline int arch_reserved_keys(void)
{
}
...
#else
#error
#endif

Or in multiple:

#ifdef x86..
#include <pkey_x86.h>
#elif ppc
#include <pkey_ppc.h>
#else
#error
#endif
--
To unsubscribe from this list: send the line "unsubscribe linux-doc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox