LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 4/4] KVM: PPC: Bookehv: Get vcpu's last instruction for emulation
From: Scott Wood @ 2014-03-26 21:17 UTC (permalink / raw)
  To: Mihai Caraman; +Cc: linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <1392913821-4520-4-git-send-email-mihai.caraman@freescale.com>

On Thu, 2014-02-20 at 18:30 +0200, Mihai Caraman wrote:
> Load external pid (lwepx) instruction faults (when called from
> KVM with guest context) needs to be handled by KVM. This implies
> additional code in DO_KVM macro to identify the source of the
> exception (which oiginate from KVM host rather than the guest).
> The hook requires to check the Exception Syndrome Register
> ESR[EPID] and External PID Load Context Register EPLC[EGS] for
> some exceptions (DTLB_MISS, DSI and LRAT). Doing this on Data TLB
> miss exception is obvious intrusive for the host.
> 
> Get rid of lwepx and acquire last instuction in kvmppc_get_last_inst()
> by searching for the physical address and kmap it. This fixes an
> infinite loop caused by lwepx's data TLB miss handled in the host
> and the TODO for TLB eviction and execute-but-not-read entries.
> 
> Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
> ---
>  arch/powerpc/kvm/bookehv_interrupts.S |   37 +++----------
>  arch/powerpc/kvm/e500_mmu_host.c      |   93 +++++++++++++++++++++++++++++++++
>  2 files changed, 102 insertions(+), 28 deletions(-)
> 
> diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
> index 20c7a54..c50490c 100644
> --- a/arch/powerpc/kvm/bookehv_interrupts.S
> +++ b/arch/powerpc/kvm/bookehv_interrupts.S
> @@ -119,38 +119,14 @@
>  1:
>  
>  	.if	\flags & NEED_EMU
> -	/*
> -	 * This assumes you have external PID support.
> -	 * To support a bookehv CPU without external PID, you'll
> -	 * need to look up the TLB entry and create a temporary mapping.
> -	 *
> -	 * FIXME: we don't currently handle if the lwepx faults.  PR-mode
> -	 * booke doesn't handle it either.  Since Linux doesn't use
> -	 * broadcast tlbivax anymore, the only way this should happen is
> -	 * if the guest maps its memory execute-but-not-read, or if we
> -	 * somehow take a TLB miss in the middle of this entry code and
> -	 * evict the relevant entry.  On e500mc, all kernel lowmem is
> -	 * bolted into TLB1 large page mappings, and we don't use
> -	 * broadcast invalidates, so we should not take a TLB miss here.
> -	 *
> -	 * Later we'll need to deal with faults here.  Disallowing guest
> -	 * mappings that are execute-but-not-read could be an option on
> -	 * e500mc, but not on chips with an LRAT if it is used.
> -	 */
> -
> -	mfspr	r3, SPRN_EPLC	/* will already have correct ELPID and EGS */
>  	PPC_STL	r15, VCPU_GPR(R15)(r4)
>  	PPC_STL	r16, VCPU_GPR(R16)(r4)
>  	PPC_STL	r17, VCPU_GPR(R17)(r4)
>  	PPC_STL	r18, VCPU_GPR(R18)(r4)
>  	PPC_STL	r19, VCPU_GPR(R19)(r4)
> -	mr	r8, r3
>  	PPC_STL	r20, VCPU_GPR(R20)(r4)
> -	rlwimi	r8, r6, EPC_EAS_SHIFT - MSR_IR_LG, EPC_EAS
>  	PPC_STL	r21, VCPU_GPR(R21)(r4)
> -	rlwimi	r8, r6, EPC_EPR_SHIFT - MSR_PR_LG, EPC_EPR
>  	PPC_STL	r22, VCPU_GPR(R22)(r4)
> -	rlwimi	r8, r10, EPC_EPID_SHIFT, EPC_EPID
>  	PPC_STL	r23, VCPU_GPR(R23)(r4)
>  	PPC_STL	r24, VCPU_GPR(R24)(r4)
>  	PPC_STL	r25, VCPU_GPR(R25)(r4)
> @@ -160,10 +136,15 @@
>  	PPC_STL	r29, VCPU_GPR(R29)(r4)
>  	PPC_STL	r30, VCPU_GPR(R30)(r4)
>  	PPC_STL	r31, VCPU_GPR(R31)(r4)
> -	mtspr	SPRN_EPLC, r8
> -	isync
> -	lwepx   r9, 0, r5
> -	mtspr	SPRN_EPLC, r3
> +
> +	/*
> +	 * We don't use external PID support. lwepx faults would need to be
> +	 * handled by KVM and this implies aditional code in DO_KVM (for
> +	 * DTB_MISS, DSI and LRAT) to check ESR[EPID] and EPLC[EGS] which
> +	 * is too intrusive for the host. Get last instuction in
> +	 * kvmppc_get_last_inst().
> +	 */
> +	li	r9, KVM_INST_FETCH_FAILED
>  	stw	r9, VCPU_LAST_INST(r4)
>  	.endif
>  
> diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
> index 6025cb7..1b4cb41 100644
> --- a/arch/powerpc/kvm/e500_mmu_host.c
> +++ b/arch/powerpc/kvm/e500_mmu_host.c
> @@ -598,9 +598,102 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
>  	}
>  }
>  
> +#ifdef CONFIG_KVM_BOOKE_HV
> +int kvmppc_ld_inst(struct kvm_vcpu *vcpu, u32 *instr)

It'd be interesting to see what the performance impact of doing this on
non-HV would be -- it would eliminate divergent code, eliminate the
MSR_DS hack, and make exec-only mappings work.

> +{
> +	gva_t geaddr;
> +	hpa_t addr;
> +	hfn_t pfn;
> +	hva_t eaddr;
> +	u32 mas0, mas1, mas2, mas3;
> +	u64 mas7_mas3;
> +	struct page *page;
> +	unsigned int addr_space, psize_shift;
> +	bool pr;
> +	unsigned long flags;
> +
> +	/* Search TLB for guest pc to get the real address */
> +	geaddr = kvmppc_get_pc(vcpu);
> +	addr_space = (vcpu->arch.shared->msr & MSR_IS) >> MSR_IR_LG;
> +
> +	local_irq_save(flags);
> +	mtspr(SPRN_MAS6, (vcpu->arch.pid << MAS6_SPID_SHIFT) | addr_space);
> +	mtspr(SPRN_MAS5, MAS5_SGS | vcpu->kvm->arch.lpid);
> +	isync();
> +	asm volatile("tlbsx 0, %[geaddr]\n" : : [geaddr] "r" (geaddr));

We can probably get away without that isync, despite what the manual
says.  We've been doing it in other contexts on e500 since forever, and
tlbsx has presync serialization which means it already waits for all
previous instructions to complete before beginning execution.

> +	mtspr(SPRN_MAS5, 0);
> +	mtspr(SPRN_MAS8, 0);
> +	mas0 = mfspr(SPRN_MAS0);
> +	mas1 = mfspr(SPRN_MAS1);
> +	mas2 = mfspr(SPRN_MAS2);
> +	mas3 = mfspr(SPRN_MAS3);
> +	mas7_mas3 = (((u64) mfspr(SPRN_MAS7)) << 32) | mfspr(SPRN_MAS3);

Why read mas3 twice?

> +	local_irq_restore(flags);
> +
> +	/*
> +	 * If the TLB entry for guest pc was evicted, return to the guest.
> +	 * There are high chances to find a valid TLB entry next time.
> +	 */
> +	if (!(mas1 & MAS1_VALID))
> +		return EMULATE_AGAIN;
> +
> +	/*
> +	 * Another thread may rewrite the TLB entry in parallel, don't
> +	 * execute from the address if the execute permission is not set
> +	 */
> +	pr = vcpu->arch.shared->msr & MSR_PR;
> +	if ((pr && (!(mas3 & MAS3_UX))) || ((!pr) && (!(mas3 & MAS3_SX)))) {
> +		kvmppc_core_queue_inst_storage(vcpu, 0);
> +		return EMULATE_AGAIN;
> +	}

s/(!foo)/!foo/g

> +	/*
> +	 * We will map the real address through a cacheable page, so we will
> +	 * not support cache-inhibited guest pages. Fortunately emulated
> +	 * instructions should not live there.
> +	 */
> +	if (mas2 & MAS2_I) {
> +		printk(KERN_CRIT "Instuction emulation from cache-inhibited "
> +				"guest pages is not supported\n");
> +		return EMULATE_FAIL;
> +	}

This message needs to be ratelimited, and use pr_err() (or maybe even
pr_debug()).

> +	/* Get page size */
> +	if (MAS0_GET_TLBSEL(mas0) == 0)
> +		psize_shift = PAGE_SHIFT;
> +	else
> +		psize_shift = MAS1_GET_TSIZE(mas1) + 10;

TSIZE should be correct when reading from TLB0, even if it was incorrect
(and ignored) when writing.

> +	/* Map a page and get guest's instruction */
> +	addr = (mas7_mas3 & (~0ULL << psize_shift)) |
> +	       (geaddr & ((1ULL << psize_shift) - 1ULL));
> +	pfn = addr >> PAGE_SHIFT;
> +
> +	if (unlikely(!pfn_valid(pfn))) {
> +		printk(KERN_CRIT "Invalid frame number\n");
> +		return EMULATE_FAIL;
> +	}
> +
> +	/* Guard us against emulation from devices area */
> +	if (unlikely(!page_is_ram(pfn))) {
> +		printk(KERN_CRIT "Instruction emulation from non-RAM host "
> +				"pages is not supported\n");
> +		return EMULATE_FAIL;
> +	}

Same comment as the cache-inhibited message, and you can probably have
one message for both pfn_valid and page_is_ram (is one of those a subset
of the other?).

-Scott

^ permalink raw reply

* Re: [PATCH 3/4] KVM: PPC: Alow kvmppc_get_last_inst() to fail
From: Scott Wood @ 2014-03-26 20:52 UTC (permalink / raw)
  To: Mihai Caraman; +Cc: linuxppc-dev, kvm, kvm-ppc
In-Reply-To: <1392913821-4520-3-git-send-email-mihai.caraman@freescale.com>

On Thu, 2014-02-20 at 18:30 +0200, Mihai Caraman wrote:
> diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
> index a59a25a..80c533e 100644
> --- a/arch/powerpc/kvm/book3s_paired_singles.c
> +++ b/arch/powerpc/kvm/book3s_paired_singles.c
> @@ -640,19 +640,24 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
>  
>  int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
>  {
> -	u32 inst = kvmppc_get_last_inst(vcpu);
> +	u32 inst;
>  	enum emulation_result emulated = EMULATE_DONE;
> -
> -	int ax_rd = inst_get_field(inst, 6, 10);
> -	int ax_ra = inst_get_field(inst, 11, 15);
> -	int ax_rb = inst_get_field(inst, 16, 20);
> -	int ax_rc = inst_get_field(inst, 21, 25);
> -	short full_d = inst_get_field(inst, 16, 31);
> -
> -	u64 *fpr_d = &vcpu->arch.fpr[ax_rd];
> -	u64 *fpr_a = &vcpu->arch.fpr[ax_ra];
> -	u64 *fpr_b = &vcpu->arch.fpr[ax_rb];
> -	u64 *fpr_c = &vcpu->arch.fpr[ax_rc];
> +	int ax_rd, ax_ra, ax_rb, ax_rc;
> +	short full_d;
> +	u64 *fpr_d, *fpr_a, *fpr_b, *fpr_c;
> +
> +	kvmppc_get_last_inst(vcpu, &inst);

Should probably check for failure here and elsewhere -- even though it
can't currently fail on book3s, the interface now allows it.

> diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
> index 5b9e906..b0d884d 100644
> --- a/arch/powerpc/kvm/book3s_pr.c
> +++ b/arch/powerpc/kvm/book3s_pr.c
> @@ -624,9 +624,10 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
>  static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
>  {
>  	ulong srr0 = kvmppc_get_pc(vcpu);
> -	u32 last_inst = kvmppc_get_last_inst(vcpu);
> +	u32 last_inst;
>  	int ret;
>  
> +	kvmppc_get_last_inst(vcpu, &last_inst);
>  	ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);

This isn't new, but this function looks odd to me -- calling
kvmppc_get_last_inst() but ignoring last_inst, then calling kvmppc_ld()
and ignoring anything but failure.  last_inst itself is never read.  And
no comments to explain the weirdness. :-)

I get that kvmppc_get_last_inst() is probably being used for the side
effect of filling in vcpu->arch.last_inst, but why store the return
value without using it?  Why pass the address of it to kvmppc_ld(),
which seems to be used only as an indirect way of determining whether
kvmppc_get_last_inst() failed?  And that whole mechanism becomes
stranger once it becomes possible for kvmppc_get_last_inst() to directly
return failure.

> diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
> index 09bfd9b..c7c60c2 100644
> --- a/arch/powerpc/kvm/booke.h
> +++ b/arch/powerpc/kvm/booke.h
> @@ -90,6 +90,9 @@ void kvmppc_vcpu_disable_spe(struct kvm_vcpu *vcpu);
>  void kvmppc_booke_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
>  void kvmppc_booke_vcpu_put(struct kvm_vcpu *vcpu);
>  
> +void kvmppc_core_queue_inst_storage(struct kvm_vcpu *vcpu,
> +                                           ulong esr_flags);

Whitespace

> +
>  enum int_class {
>  	INT_CLASS_NONCRIT,
>  	INT_CLASS_CRIT,
> @@ -123,6 +126,8 @@ extern int kvmppc_core_emulate_mtspr_e500(struct kvm_vcpu *vcpu, int sprn,
>  extern int kvmppc_core_emulate_mfspr_e500(struct kvm_vcpu *vcpu, int sprn,
>  					  ulong *spr_val);
>  
> +extern int kvmppc_ld_inst(struct kvm_vcpu *vcpu, u32 *instr) ;

Whitespace

> diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
> index ecf2247..6025cb7 100644
> --- a/arch/powerpc/kvm/e500_mmu_host.c
> +++ b/arch/powerpc/kvm/e500_mmu_host.c
> @@ -34,6 +34,7 @@
>  #include "e500.h"
>  #include "timing.h"
>  #include "e500_mmu_host.h"
> +#include "booke.h"
>  
>  #include "trace_booke.h"
>  
> @@ -597,6 +598,10 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
>  	}
>  }
>  
> +int kvmppc_ld_inst(struct kvm_vcpu *vcpu, u32 *instr) {
> +	return EMULATE_FAIL;
> +};

Brace placement

>  /************* MMU Notifiers *************/
>  
>  int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
> diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c
> index 2f9a087..24a8e50 100644
> --- a/arch/powerpc/kvm/emulate.c
> +++ b/arch/powerpc/kvm/emulate.c
> @@ -225,19 +225,26 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
>   * from opcode tables in the future. */
>  int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu)
>  {
> -	u32 inst = kvmppc_get_last_inst(vcpu);
> -	int ra = get_ra(inst);
> -	int rs = get_rs(inst);
> -	int rt = get_rt(inst);
> -	int sprn = get_sprn(inst);
> -	enum emulation_result emulated = EMULATE_DONE;
> +	u32 inst;
> +	int ra, rs, rt, sprn;
> +	enum emulation_result emulated;
>  	int advance = 1;
>  
>  	/* this default type might be overwritten by subcategories */
>  	kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS);
>  
> +	emulated = kvmppc_get_last_inst(vcpu, &inst);
> +	if (emulated != EMULATE_DONE) {
> +		return emulated;
> +	}

Unnecessary braces

-Scott

^ permalink raw reply

* Re: [PATCH 2/2] video/fsl: Fix the sleep function for FSL DIU module
From: Timur Tabi @ 2014-03-26 18:50 UTC (permalink / raw)
  To: Jason Jin; +Cc: b07421, linux-fbdev, linuxppc-dev, r58472, Wang Dongsheng
In-Reply-To: <1395855704-19908-2-git-send-email-Jason.Jin@freescale.com>

On 03/26/2014 12:41 PM, Jason Jin wrote:
> +	if (!diu_ops.set_pixel_clock) {
> +		data->saved_pixel_clock = 0;
> +		if (of_address_to_resource(ofdev->dev.of_node, 1, &res))
> +			pr_err(KERN_ERR "No pixel clock set func and no pixel node!\n");
> +		else {
> +			data->pixelclk_ptr =
> +				devm_ioremap(&ofdev->dev, res.start, resource_size(&res));
> +			if (!data->pixelclk_ptr) {
> +				pr_err(KERN_ERR "fslfb: could not map pixelclk register!\n");
> +				ret = -ENOMEM;
> +			} else
> +				data->saved_pixel_clock = in_be32(data->pixelclk_ptr);
> +		}
> +	}

This seems very hackish.  What node does ofdev point to?  I wonder if 
this code should be in the platform file instead.

Also, use dev_info() instead of pr_err, and never use exclamation marks 
in driver messages.

^ permalink raw reply

* Re: [PATCH 1/2] video/fsl: make the diu driver work without platform hooks
From: Timur Tabi @ 2014-03-26 18:46 UTC (permalink / raw)
  To: Jason Jin; +Cc: b07421, linux-fbdev, linuxppc-dev, r58472
In-Reply-To: <1395855704-19908-1-git-send-email-Jason.Jin@freescale.com>

On 03/26/2014 12:41 PM, Jason Jin wrote:
> This board sepecific initialization mechanism is not feasible i
> for corenet platform as the corenet platform file is a
> abstraction of serveral platforms.

You can't make it 100% abstract.  The DIU driver requires some sort of 
board support.  I think you can make a generic platform file for the DIU.

> However, the DIU is already initialized in u-boot and we can
> rely on the settings in u-boot for corenet platform,

I don't like that at all.

> the only
> issue is that when DIU wake up from the deepsleep, some of the
> board specific initialization will lost, such as the pixel clock
> setting.

That is a BIG issue.  This is why we have a platform file -- to handle 
the platform issues.

^ permalink raw reply

* [PATCH 2/2] video/fsl: Fix the sleep function for FSL DIU module
From: Jason Jin @ 2014-03-26 17:41 UTC (permalink / raw)
  To: b07421, timur; +Cc: linux-fbdev, linuxppc-dev, r58472, Wang Dongsheng
In-Reply-To: <1395855704-19908-1-git-send-email-Jason.Jin@freescale.com>

For sleep, The diu module will power off and when
wake up for initialization will need.

Some platform such as the corenet plafrom does not provide
the DIU board sepecific initialization, but rely on the
DIU initializtion in u-boot. then the pixel clock resume will
be an issuel on this platform, This patch save the pixel clock
for diu before enter the deepsleep and then restore it after
resume, the extra pixelclock register information will be needed
in this situation.

Signed-off-by: Jason Jin <Jason.Jin@freescale.com>
Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com>
---
v2: clean up the resume function based on Timur's comments.
Add the pixel clock saving for the platforms without board sepecific
initializaton.

 drivers/video/fsl-diu-fb.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 4640846..fbdd166 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -372,6 +372,7 @@ struct fsl_diu_data {
 	unsigned int irq;
 	enum fsl_diu_monitor_port monitor_port;
 	struct diu __iomem *diu_reg;
+	void __iomem *pixelclk_ptr;
 	spinlock_t reg_lock;
 	u8 dummy_aoi[4 * 4 * 4];
 	struct diu_ad dummy_ad __aligned(8);
@@ -383,6 +384,7 @@ struct fsl_diu_data {
 	__le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32);
 	uint8_t edid_data[EDID_LENGTH];
 	bool has_edid;
+	u32 saved_pixel_clock;
 } __aligned(32);
 
 /* Determine the DMA address of a member of the fsl_diu_data structure */
@@ -1625,19 +1627,47 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id)
 static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
 {
 	struct fsl_diu_data *data;
+	struct resource res;
+	int ret;
 
+	ret = 0;
 	data = dev_get_drvdata(&ofdev->dev);
 	disable_lcdc(data->fsl_diu_info);
 
-	return 0;
+	if (!diu_ops.set_pixel_clock) {
+		data->saved_pixel_clock = 0;
+		if (of_address_to_resource(ofdev->dev.of_node, 1, &res))
+			pr_err(KERN_ERR "No pixel clock set func and no pixel node!\n");
+		else {
+			data->pixelclk_ptr =
+				devm_ioremap(&ofdev->dev, res.start, resource_size(&res));
+			if (!data->pixelclk_ptr) {
+				pr_err(KERN_ERR "fslfb: could not map pixelclk register!\n");
+				ret = -ENOMEM;
+			} else
+				data->saved_pixel_clock = in_be32(data->pixelclk_ptr);
+		}
+	}
+
+	return ret;
 }
 
 static int fsl_diu_resume(struct platform_device *ofdev)
 {
 	struct fsl_diu_data *data;
+	unsigned int i;
 
 	data = dev_get_drvdata(&ofdev->dev);
-	enable_lcdc(data->fsl_diu_info);
+	if (!diu_ops.set_pixel_clock && data->pixelclk_ptr)
+		out_be32(data->pixelclk_ptr, data->saved_pixel_clock);
+
+	fsl_diu_enable_interrupts(data);
+	update_lcdc(data->fsl_diu_info);
+
+	for (i = 0; i < NUM_AOIS; i++) {
+		if (data->mfb[i].count)
+			fsl_diu_enable_panel(&data->fsl_diu_info[i]);
+	}
 
 	return 0;
 }
-- 
1.8.0

^ permalink raw reply related

* [PATCH 1/2] video/fsl: make the diu driver work without platform hooks
From: Jason Jin @ 2014-03-26 17:41 UTC (permalink / raw)
  To: b07421, timur; +Cc: linux-fbdev, linuxppc-dev, r58472

make the diu driver work without platform hooks.

So far the DIU driver does not have a mechanism to do the
board specific initialization. So on some platforms,
such as P1022, 8610 and 5121, The board specific initialization
is implmented in the platform file such p10222_ds.

This board sepecific initialization mechanism is not feasible i
for corenet platform as the corenet platform file is a
abstraction of serveral platforms.

However, the DIU is already initialized in u-boot and we can
rely on the settings in u-boot for corenet platform, the only
issue is that when DIU wake up from the deepsleep, some of the
board specific initialization will lost, such as the pixel clock
setting.

This patch try to make the diu work on the platform without board
specific initialization such as corenet(T1040 so far), and rely on
the board initialization in u-boot. The following patch will try to
fix the pixel clock saving issue for deepsleep.

Signed-off-by: Jason Jin <Jason.Jin@freescale.com>
---
 drivers/video/fsl-diu-fb.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index e8758b9..4640846 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -479,7 +479,10 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
 			port = FSL_DIU_PORT_DLVDS;
 	}
 
-	return diu_ops.valid_monitor_port(port);
+	if (diu_ops.valid_monitor_port)
+		return diu_ops.valid_monitor_port(port);
+	else
+		return port;
 }
 
 /*
@@ -846,7 +849,11 @@ static void update_lcdc(struct fb_info *info)
 
 	out_be32(&hw->vsyn_para, temp);
 
-	diu_ops.set_pixel_clock(var->pixclock);
+	/*if there is platform function for pixel clock setting, use it.
+	 * otherwise we rely on the settings in u-boot.
+	 */
+	if (diu_ops.set_pixel_clock)
+		diu_ops.set_pixel_clock(var->pixclock);
 
 #ifndef CONFIG_PPC_MPC512x
 	/*
-- 
1.8.0

^ permalink raw reply related

* Re: [PATCH] phy/at8031: enable at8031 to work on interrupt mode
From: Scott Wood @ 2014-03-26 18:13 UTC (permalink / raw)
  To: Zhao Qiang; +Cc: B07421, R63061, linuxppc-dev
In-Reply-To: <1395816338-3090-1-git-send-email-B45475@freescale.com>

On Wed, 2014-03-26 at 14:45 +0800, Zhao Qiang wrote:
> The at8031 can work on polling mode and interrupt mode.
> Add ack_interrupt and config intr funcs to enable
> interrupt mode for it.
> 
> Signed-off-by: Zhao Qiang <B45475@freescale.com>
> ---
>  drivers/net/phy/at803x.c | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)

This needs to go to the netdev maintainer/list.

-Scott

^ permalink raw reply

* [PATCH v4] powernv, cpufreq: cpufreq driver for powernv platform
From: Gautham R. Shenoy @ 2014-03-26 16:55 UTC (permalink / raw)
  To: Viresh Kumar, benh
  Cc: Gautham R. Shenoy, Linux PM list, linuxppc-dev, Anton Blanchard,
	srivatsa.bhat
In-Reply-To: <1395852947-22290-1-git-send-email-ego@linux.vnet.ibm.com>

From: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>

Backend driver to dynamically set voltage and frequency on
IBM POWER non-virtualized platforms.  Power management SPRs
are used to set the required PState.

This driver works in conjunction with cpufreq governors
like 'ondemand' to provide a demand based frequency and
voltage setting on IBM POWER non-virtualized platforms.

PState table is obtained from OPAL v3 firmware through device
tree.

powernv_cpufreq back-end driver would parse the relevant device-tree
nodes and initialise the cpufreq subsystem on powernv platform.

The code was originally written by svaidy@linux.vnet.ibm.com. Over
time it was modified to accomodate bug-fixes as well as updates to the
the cpu-freq core. Relevant portions of the change logs corresponding
to those modifications are noted below:

 * The policy->cpus needs to be populated in a hotplug-invariant
   manner instead of using cpu_sibling_mask() which varies with
   cpu-hotplug. This is because the cpufreq core code copies this
   content into policy->related_cpus mask which is should not vary on
   cpu-hotplug. [Authored by srivatsa.bhat@linux.vnet.ibm.com]

 * On POWER systems, the CPU frequency is controlled at a core-level
   and hence we need to serialize so that only one of the threads in
   the core switches the core's frequency at a time. Introduce
   per-core locking to enable finer-grained synchronization and
   thereby enhance the speed and responsiveness of the cpufreq driver
   to varying workload demands.

     The design of per-core locking is very simple and
   straight-forward: we first define a Per-CPU lock and use the ones
   that belongs to the first thread sibling of the core.

     cpu_first_thread_sibling() macro is used to find the *common*
   lock for all thread siblings belonging to a core. [Authored by
   srivatsa.bhat@linux.vnet.ibm.com]

 * Create a helper routine that can return the cpu-frequency for the
   corresponding pstate_id. Also, cache the values of the pstate_max,
   pstate_min and pstate_nominal and nr_pstates in a static structure
   so that they can be reused in the future to perform any
   validations. [Authored by ego@linux.vnet.ibm.com]

 * Create a driver attribute named cpuinfo_nominal_freq which creates
   a sysfs read-only file named cpuinfo_nominal_freq. Export the
   frequency corresponding to the nominal_pstate through this
   interface.

     Nominal frequency is the highest non-turbo frequency for the
   platform.  This is generally used for setting governor policies
   from user space for optimal energy efficiency. [Authored by
   ego@linux.vnet.ibm.com]

 * Implement a powernv_cpufreq_get(unsigned int cpu) method which will
   return the current operating frequency. Export this via the sysfs
   interface cpuinfo_cur_freq by setting powernv_cpufreq_driver.get to
   powernv_cpufreq_get(). [Authored by ego@linux.vnet.ibm.com]

[Change log updated by ego@linux.vnet.ibm.com]

Reviewed-by: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Signed-off-by: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com>
Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
---
 arch/powerpc/configs/pseries_defconfig    |   1 +
 arch/powerpc/configs/pseries_le_defconfig |   1 +
 arch/powerpc/include/asm/reg.h            |   4 +
 arch/powerpc/platforms/powernv/Kconfig    |   6 +
 drivers/cpufreq/Kconfig.powerpc           |   8 +
 drivers/cpufreq/Makefile                  |   1 +
 drivers/cpufreq/powernv-cpufreq.c         | 372 ++++++++++++++++++++++++++++++
 7 files changed, 393 insertions(+)
 create mode 100644 drivers/cpufreq/powernv-cpufreq.c

diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index e9a8b4e..a285d44 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -353,3 +353,4 @@ CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM_BOOK3S_64=m
 CONFIG_KVM_BOOK3S_64_HV=y
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
diff --git a/arch/powerpc/configs/pseries_le_defconfig b/arch/powerpc/configs/pseries_le_defconfig
index 62771e0..47e6161 100644
--- a/arch/powerpc/configs/pseries_le_defconfig
+++ b/arch/powerpc/configs/pseries_le_defconfig
@@ -350,3 +350,4 @@ CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_DEV_NX=y
 CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
+CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 90c06ec..84f92ca 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -271,6 +271,10 @@
 #define SPRN_HSRR1	0x13B	/* Hypervisor Save/Restore 1 */
 #define SPRN_IC		0x350	/* Virtual Instruction Count */
 #define SPRN_VTB	0x351	/* Virtual Time Base */
+#define SPRN_PMICR	0x354   /* Power Management Idle Control Reg */
+#define SPRN_PMSR	0x355   /* Power Management Status Reg */
+#define SPRN_PMCR	0x374	/* Power Management Control Register */
+
 /* HFSCR and FSCR bit numbers are the same */
 #define FSCR_TAR_LG	8	/* Enable Target Address Register */
 #define FSCR_EBB_LG	7	/* Enable Event Based Branching */
diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
index 895e8a2..c252ee9 100644
--- a/arch/powerpc/platforms/powernv/Kconfig
+++ b/arch/powerpc/platforms/powernv/Kconfig
@@ -11,6 +11,12 @@ config PPC_POWERNV
 	select PPC_UDBG_16550
 	select PPC_SCOM
 	select ARCH_RANDOM
+	select CPU_FREQ
+	select CPU_FREQ_GOV_PERFORMANCE
+	select CPU_FREQ_GOV_POWERSAVE
+	select CPU_FREQ_GOV_USERSPACE
+	select CPU_FREQ_GOV_ONDEMAND
+	select CPU_FREQ_GOV_CONSERVATIVE
 	default y
 
 config PPC_POWERNV_RTAS
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index ca0021a..72564b7 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -54,3 +54,11 @@ config PPC_PASEMI_CPUFREQ
 	help
 	  This adds the support for frequency switching on PA Semi
 	  PWRficient processors.
+
+config POWERNV_CPUFREQ
+       tristate "CPU frequency scaling for IBM POWERNV platform"
+       depends on PPC_POWERNV
+       default y
+       help
+	 This adds support for CPU frequency switching on IBM POWERNV
+	 platform
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 7494565..0dbb963 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_PPC_CORENET_CPUFREQ)   += ppc-corenet-cpufreq.o
 obj-$(CONFIG_CPU_FREQ_PMAC)		+= pmac32-cpufreq.o
 obj-$(CONFIG_CPU_FREQ_PMAC64)		+= pmac64-cpufreq.o
 obj-$(CONFIG_PPC_PASEMI_CPUFREQ)	+= pasemi-cpufreq.o
+obj-$(CONFIG_POWERNV_CPUFREQ)		+= powernv-cpufreq.o
 
 ##################################################################################
 # Other platform drivers
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
new file mode 100644
index 0000000..b35865b
--- /dev/null
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -0,0 +1,372 @@
+/*
+ * POWERNV cpufreq driver for the IBM POWER processors
+ *
+ * (C) Copyright IBM 2014
+ *
+ * Author: Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"powernv-cpufreq: " fmt
+
+#include <linux/module.h>
+#include <linux/cpufreq.h>
+#include <linux/smp.h>
+#include <linux/of.h>
+#include <asm/cputhreads.h>
+
+/* Per-Core locking for frequency transitions */
+static DEFINE_PER_CPU(struct mutex, freq_switch_lock);
+
+#define lock_core_freq(cpu)				\
+			mutex_lock(&per_cpu(freq_switch_lock,\
+				cpu_first_thread_sibling(cpu)));
+#define unlock_core_freq(cpu)				\
+			mutex_unlock(&per_cpu(freq_switch_lock,\
+				cpu_first_thread_sibling(cpu)));
+
+#define POWERNV_MAX_PSTATES	256
+
+static struct cpufreq_frequency_table powernv_freqs[POWERNV_MAX_PSTATES+1];
+static int powernv_pstate_ids[POWERNV_MAX_PSTATES+1];
+
+struct powernv_pstate_info {
+	int pstate_min_id;
+	int pstate_max_id;
+	int pstate_nominal_id;
+	int nr_pstates;
+};
+static struct powernv_pstate_info powernv_pstate_info;
+
+/*
+ * Initialize the freq table based on data obtained
+ * from the firmware passed via device-tree
+ */
+static int init_powernv_pstates(void)
+{
+	struct device_node *power_mgt;
+	int nr_pstates = 0;
+	int pstate_min, pstate_max, pstate_nominal;
+	const __be32 *pstate_ids, *pstate_freqs;
+	int i;
+	u32 len_ids, len_freqs;
+
+	power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
+	if (!power_mgt) {
+		pr_warn("power-mgt node not found\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(power_mgt, "ibm,pstate-min", &pstate_min)) {
+		pr_warn("ibm,pstate-min node not found\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(power_mgt, "ibm,pstate-max", &pstate_max)) {
+		pr_warn("ibm,pstate-max node not found\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(power_mgt, "ibm,pstate-nominal",
+				 &pstate_nominal)) {
+		pr_warn("ibm,pstate-nominal not found\n");
+		return -ENODEV;
+	}
+	pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min,
+		pstate_nominal, pstate_max);
+
+	pstate_ids = of_get_property(power_mgt, "ibm,pstate-ids", &len_ids);
+	if (!pstate_ids) {
+		pr_warn("ibm,pstate-ids not found\n");
+		return -ENODEV;
+	}
+
+	pstate_freqs = of_get_property(power_mgt, "ibm,pstate-frequencies-mhz",
+				      &len_freqs);
+	if (!pstate_freqs) {
+		pr_warn("ibm,pstate-frequencies-mhz not found\n");
+		return -ENODEV;
+	}
+
+	WARN_ON(len_ids != len_freqs);
+	nr_pstates = min(len_ids, len_freqs) / sizeof(u32);
+	if (!nr_pstates) {
+		WARN_ON(1);
+		return -ENODEV;
+	}
+
+	pr_debug("NR PStates %d\n", nr_pstates);
+	for (i = 0; i < nr_pstates; i++) {
+		u32 id = be32_to_cpu(pstate_ids[i]);
+		u32 freq = be32_to_cpu(pstate_freqs[i]);
+
+		pr_debug("PState id %d freq %d MHz\n", id, freq);
+		powernv_freqs[i].driver_data = i;
+		powernv_freqs[i].frequency = freq * 1000; /* kHz */
+		powernv_pstate_ids[i] = id;
+	}
+	/* End of list marker entry */
+	powernv_freqs[i].frequency = CPUFREQ_TABLE_END;
+
+	powernv_pstate_info.pstate_min_id = pstate_min;
+	powernv_pstate_info.pstate_max_id = pstate_max;
+	powernv_pstate_info.pstate_nominal_id = pstate_nominal;
+	powernv_pstate_info.nr_pstates = nr_pstates;
+
+	return 0;
+}
+
+/*
+ * Returns the cpu frequency corresponding to the pstate_id.
+ */
+static unsigned int pstate_id_to_freq(int pstate_id)
+{
+	int i;
+
+	i = powernv_pstate_info.pstate_max_id - pstate_id;
+
+	BUG_ON(i >= powernv_pstate_info.nr_pstates || i < 0);
+	WARN_ON(powernv_pstate_ids[i] != pstate_id);
+	return powernv_freqs[i].frequency;
+}
+
+/*
+ * cpuinfo_nominal_freq_show - Show the nominal CPU frequency as indicated by
+ * the firmware
+ */
+static ssize_t cpuinfo_nominal_freq_show(struct cpufreq_policy *policy,
+					char *buf)
+{
+	return sprintf(buf, "%u\n",
+		pstate_id_to_freq(powernv_pstate_info.pstate_nominal_id));
+}
+
+struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq =
+	__ATTR_RO(cpuinfo_nominal_freq);
+
+static struct freq_attr *powernv_cpu_freq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	&cpufreq_freq_attr_cpuinfo_nominal_freq,
+	NULL,
+};
+
+/* Helper routines */
+
+/* Access helpers to power mgt SPR */
+
+static inline unsigned long get_pmspr(unsigned long sprn)
+{
+	switch (sprn) {
+	case SPRN_PMCR:
+		return mfspr(SPRN_PMCR);
+
+	case SPRN_PMICR:
+		return mfspr(SPRN_PMICR);
+
+	case SPRN_PMSR:
+		return mfspr(SPRN_PMSR);
+	}
+	BUG();
+}
+
+static inline void set_pmspr(unsigned long sprn, unsigned long val)
+{
+	switch (sprn) {
+	case SPRN_PMCR:
+		mtspr(SPRN_PMCR, val);
+		return;
+
+	case SPRN_PMICR:
+		mtspr(SPRN_PMICR, val);
+		return;
+
+	case SPRN_PMSR:
+		mtspr(SPRN_PMSR, val);
+		return;
+	}
+	BUG();
+}
+
+/*
+ * Use objects of this type to query/update
+ * pstates on a remote cpu via smp_call_function.
+ */
+struct powernv_smp_call_data {
+	unsigned int freq;
+	int pstate_id;
+};
+
+/*
+ * powernv_read_cpu_freq: Reads the current frequency on this cpu.
+ *
+ * Called via smp_call_function.
+ *
+ * Note: The caller of the smp_call_function should pass an argument of
+ * the type 'struct powernv_smp_call_data *' along with this function.
+ *
+ * The current frequency on this cpu will be returned via
+ * ((struct powernv_smp_call_data *)arg)->freq;
+ */
+static void powernv_read_cpu_freq(void *arg)
+{
+	unsigned long pmspr_val;
+	s8 local_pstate_id;
+        struct powernv_smp_call_data *freq_data;
+
+	freq_data = (struct powernv_smp_call_data *)arg;
+
+	pmspr_val = get_pmspr(SPRN_PMSR);
+
+	/*
+         * The local pstate id corresponds bits 48..55 in the PMSR.
+         * Note: Watch out for the sign!
+         */
+	local_pstate_id = (pmspr_val >> 48) & 0xFF;
+	freq_data->pstate_id = local_pstate_id;
+	freq_data->freq = pstate_id_to_freq(freq_data->pstate_id);
+
+	pr_debug("cpu %d pmsr %lx pstate_id %d frequency %d kHz \n",
+		smp_processor_id(), pmspr_val, freq_data->pstate_id,
+		freq_data->freq);
+}
+
+/*
+ * powernv_cpufreq_get: Returns the cpu frequency as reported by the
+ * firmware for 'cpu'. This value is reported through the sysfs file
+ * cpuinfo_cur_freq.
+ */
+unsigned int powernv_cpufreq_get(unsigned int cpu)
+{
+	struct powernv_smp_call_data freq_data;
+
+	smp_call_function_any(cpu_sibling_mask(cpu), powernv_read_cpu_freq,
+			&freq_data, 1);
+
+	return freq_data.freq;
+}
+
+/*
+ * set_pstate: Sets the frequency on this cpu.
+ *
+ * This is called via an smp_call_function.
+ *
+ * The caller must ensure that freq_data is of the type
+ * (struct powernv_smp_call_data *) and the pstate_id which needs to be set
+ * on this cpu should be present in freq_data->pstate_id.
+ */
+static void set_pstate(void *freq_data)
+{
+	unsigned long val;
+	unsigned long pstate_ul =
+		((struct powernv_smp_call_data *) freq_data)->pstate_id;
+
+	val = get_pmspr(SPRN_PMCR);
+	val = val & 0x0000ffffffffffffULL;
+
+	pstate_ul = pstate_ul & 0xFF;
+
+	/* Set both global(bits 56..63) and local(bits 48..55) PStates */
+	val = val | (pstate_ul << 56) | (pstate_ul << 48);
+
+	pr_debug("Setting cpu %d pmcr to %016lX\n", smp_processor_id(), val);
+	set_pmspr(SPRN_PMCR, val);
+}
+
+/*
+ * powernv_set_freq: Sets the frequency corresponding to the cpufreq
+ * table entry indexed by new_index on the cpus in the mask 'cpus'
+ */
+static int powernv_set_freq(cpumask_var_t cpus, unsigned int new_index)
+{
+	struct powernv_smp_call_data freq_data;
+
+	freq_data.pstate_id = powernv_pstate_ids[new_index];
+
+	/*
+	 * Use smp_call_function to send IPI and execute the
+	 * mtspr on target cpu.  We could do that without IPI
+	 * if current CPU is within policy->cpus (core)
+	 */
+	smp_call_function_any(cpus, set_pstate, &freq_data, 1);
+	return 0;
+}
+
+static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+	int base, i;
+
+	base = cpu_first_thread_sibling(policy->cpu);
+
+	for (i = 0; i < threads_per_core; i++)
+		cpumask_set_cpu(base + i, policy->cpus);
+
+	policy->cpuinfo.transition_latency = 25000;
+	policy->cur = powernv_freqs[0].frequency;
+
+	return cpufreq_table_validate_and_show(policy, powernv_freqs);
+}
+
+static int powernv_cpufreq_verify(struct cpufreq_policy *policy)
+{
+	return cpufreq_generic_frequency_table_verify(policy);
+}
+
+static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
+					unsigned int new_index)
+{
+	int rc;
+
+	lock_core_freq(policy->cpu);
+	rc = powernv_set_freq(policy->cpus, new_index);
+	unlock_core_freq(policy->cpu);
+
+	return rc;
+}
+
+static struct cpufreq_driver powernv_cpufreq_driver = {
+	.name		= "powernv-cpufreq",
+	.flags		= CPUFREQ_CONST_LOOPS,
+	.init		= powernv_cpufreq_cpu_init,
+	.verify		= powernv_cpufreq_verify,
+	.target_index  	= powernv_cpufreq_target_index,
+	.get		= powernv_cpufreq_get,
+	.attr		= powernv_cpu_freq_attr,
+};
+
+static int __init powernv_cpufreq_init(void)
+{
+	int cpu, rc = 0;
+
+	/* Discover pstates from device tree and init */
+	rc = init_powernv_pstates();
+	if (rc) {
+		pr_info("powernv-cpufreq disabled\n");
+		return rc;
+	}
+
+	/* Init per-core mutex */
+	for_each_possible_cpu(cpu)
+		mutex_init(&per_cpu(freq_switch_lock, cpu));
+
+	return cpufreq_register_driver(&powernv_cpufreq_driver);
+}
+module_init(powernv_cpufreq_init);
+
+static void __exit powernv_cpufreq_exit(void)
+{
+	cpufreq_unregister_driver(&powernv_cpufreq_driver);
+}
+module_exit(powernv_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>");
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH v4] powernv: Dynamic Frequency Scaling Enablement
From: Gautham R. Shenoy @ 2014-03-26 16:55 UTC (permalink / raw)
  To: Viresh Kumar, benh
  Cc: Gautham R. Shenoy, Linux PM list, linuxppc-dev, Anton Blanchard,
	srivatsa.bhat

From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>

Hi,

This is the v4 of the patchset to enable Dynamic Frequency Scaling
on IBM PowerNV Platforms. I have incorporated the review comments
from the previous version (can be found at [1]). 

In this version, 

  * Multiple patches from the previous version have been into a single
    patch, since the higher numbered patches implemented some helper
    functions and the driver methods which should have been a part of
    the first patch to begin with.

  * Use the generic helpers provided by the cpufreq core available in
    the latest linux-next tree.

  * Fix the code to avoid casting integer pointers to void.

The patch is based on top of the commit:06ed26d1de59ce7cbbe68378b7e470be169750e5
of the linux-next tree.


[1]: https://www.mail-archive.com/linuxppc-dev@lists.ozlabs.org/msg76675.html

Vaidyanathan Srinivasan (1):
  powernv, cpufreq: cpufreq driver for powernv platform

 arch/powerpc/configs/pseries_defconfig    |   1 +
 arch/powerpc/configs/pseries_le_defconfig |   1 +
 arch/powerpc/include/asm/reg.h            |   4 +
 arch/powerpc/platforms/powernv/Kconfig    |   6 +
 drivers/cpufreq/Kconfig.powerpc           |   8 +
 drivers/cpufreq/Makefile                  |   1 +
 drivers/cpufreq/powernv-cpufreq.c         | 372 ++++++++++++++++++++++++++++++
 7 files changed, 393 insertions(+)
 create mode 100644 drivers/cpufreq/powernv-cpufreq.c

-- 
1.8.3.1

^ permalink raw reply

* [RFC PATCH] hugetlb: ensure hugepage access is denied if hugepages are not supported
From: Nishanth Aravamudan @ 2014-03-26 15:58 UTC (permalink / raw)
  To: linux-mm; +Cc: paulus, linuxppc-dev, anton, nyc
In-Reply-To: <20140324230256.GA18778@linux.vnet.ibm.com>

On 24.03.2014 [16:02:56 -0700], Nishanth Aravamudan wrote:
> In KVM guests on Power, if the guest is not backed by hugepages, we see
> the following in the guest:
> 
> AnonHugePages:         0 kB
> HugePages_Total:       0
> HugePages_Free:        0
> HugePages_Rsvd:        0
> HugePages_Surp:        0
> Hugepagesize:         64 kB
> 
> This seems like a configuration issue -- why is a hstate of 64k being
> registered?
> 
> I did some debugging and found that the following does trigger,
> mm/hugetlb.c::hugetlb_init():
> 
>         /* Some platform decide whether they support huge pages at boot
>          * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
>          * there is no such support
>          */
>         if (HPAGE_SHIFT == 0)
>                 return 0;
> 
> That check is only during init-time. So we don't support hugepages, but
> none of the hugetlb APIs actually check this condition (HPAGE_SHIFT ==
> 0), so /proc/meminfo above falsely indicates there is a valid hstate (at
> least one). But note that there is no /sys/kernel/mm/hugepages meaning
> no hstate was actually registered.
> 
> Further, it turns out that huge_page_order(default_hstate) is 0, so
> hugetlb_report_meminfo is doing:
> 
> 1UL << (huge_page_order(h) + PAGE_SHIFT - 10)
> 
> which ends up just doing 1 << (PAGE_SHIFT - 10) and since the base page
> size is 64k, we report a hugepage size of 64k... And allow the user to
> allocate hugepages via the sysctl, etc.
> 
> What's the right thing to do here?
> 
> 1) Should we add checks for HPAGE_SHIFT == 0 to all the hugetlb APIs? It
> seems like HPAGE_SHIFT == 0 should be the equivalent, functionally, of
> the config options being off. This seems like a lot of overhead, though,
> to put everywhere, so maybe I can do it in an arch-specific macro, that
> in asm-generic defaults to 0 (and so will hopefully be compiled out?).
> 
> 2) What should hugetlbfs do when HPAGE_SHIFT == 0? Should it be
> mountable? Obviously if it's mountable, we can't great files there
> (since the fs will report insufficient space). [1]

Here is my solution to this. Comments appreciated!

In KVM guests on Power, in a guest not backed by hugepages, we see the
following:

AnonHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:         64 kB

HPAGE_SHIFT == 0 in this configuration, which indicates that hugepages
are not supported at boot-time, but this is only checked in
hugetlb_init(). Extract the check to a helper function, and use it in a
few relevant places.

This does make hugetlbfs not supported in this environment. I believe
this is fine, as there are no valid hugepages and that won't change at
runtime.

Signed-off-by: Nishanth Aravamudan <nacc@linux.vnet.ibm.com>

diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index d19b30a..c7aa477 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -1017,6 +1017,11 @@ static int __init init_hugetlbfs_fs(void)
 	int error;
 	int i;
 
+	if (!hugepages_supported()) {
+		printk(KERN_ERR "hugetlbfs: Disabling because there are no supported page sizes\n");
+		return -ENOTSUPP;
+	}
+
 	error = bdi_init(&hugetlbfs_backing_dev_info);
 	if (error)
 		return error;
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 8c43cc4..0aea8de 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -450,4 +450,14 @@ static inline spinlock_t *huge_pte_lock(struct hstate *h,
 	return ptl;
 }
 
+static inline bool hugepages_supported(void)
+{
+	/*
+	 * Some platform decide whether they support huge pages at boot
+	 * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
+	 * there is no such support
+	 */
+	return HPAGE_SHIFT != 0;
+}
+
 #endif /* _LINUX_HUGETLB_H */
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index c01cb9f..1c99585 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1949,11 +1949,7 @@ module_exit(hugetlb_exit);
 
 static int __init hugetlb_init(void)
 {
-	/* Some platform decide whether they support huge pages at boot
-	 * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
-	 * there is no such support
-	 */
-	if (HPAGE_SHIFT == 0)
+	if (!hugepages_supported())
 		return 0;
 
 	if (!size_to_hstate(default_hstate_size)) {
@@ -2069,6 +2065,9 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
 	unsigned long tmp;
 	int ret;
 
+	if (!hugepages_supported())
+		return -ENOTSUPP;
+
 	tmp = h->max_huge_pages;
 
 	if (write && h->order >= MAX_ORDER)
@@ -2122,6 +2121,9 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
 	unsigned long tmp;
 	int ret;
 
+	if (!hugepages_supported())
+		return -ENOTSUPP;
+
 	tmp = h->nr_overcommit_huge_pages;
 
 	if (write && h->order >= MAX_ORDER)
@@ -2147,6 +2149,8 @@ out:
 void hugetlb_report_meminfo(struct seq_file *m)
 {
 	struct hstate *h = &default_hstate;
+	if (!hugepages_supported())
+		return;
 	seq_printf(m,
 			"HugePages_Total:   %5lu\n"
 			"HugePages_Free:    %5lu\n"
@@ -2163,6 +2167,8 @@ void hugetlb_report_meminfo(struct seq_file *m)
 int hugetlb_report_node_meminfo(int nid, char *buf)
 {
 	struct hstate *h = &default_hstate;
+	if (!hugepages_supported())
+		return 0;
 	return sprintf(buf,
 		"Node %d HugePages_Total: %5u\n"
 		"Node %d HugePages_Free:  %5u\n"
@@ -2177,6 +2183,9 @@ void hugetlb_show_meminfo(void)
 	struct hstate *h;
 	int nid;
 
+	if (!hugepages_supported())
+		return;
+
 	for_each_node_state(nid, N_MEMORY)
 		for_each_hstate(h)
 			pr_info("Node %d hugepages_total=%u hugepages_free=%u hugepages_surp=%u hugepages_size=%lukB\n",

^ permalink raw reply related

* [PATCH] bootmem/powerpc: Unify bootmem initialization
From: Emil Medve @ 2014-03-26 13:52 UTC (permalink / raw)
  To: benh, paulus, linuxppc-dev; +Cc: Emil Medve

Unify the low/highmem code path from do_init_bootmem() by using (the)
lowmem related variables/parameters even when the low/highmem split
is not needed (64-bit) or configured. In such cases the "lowmem"
variables/parameters continue to observe the definition by referring
to memory directly mapped by the kernel

Signed-off-by: Emil Medve <Emilian.Medve@Freescale.com>
---
 arch/powerpc/mm/mem.c | 36 ++++++++++++++++--------------------
 1 file changed, 16 insertions(+), 20 deletions(-)

diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 32202c9..807a950 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -188,27 +188,31 @@ EXPORT_SYMBOL_GPL(walk_system_ram_range);
 void __init do_init_bootmem(void)
 {
 	unsigned long start, bootmap_pages;
-	unsigned long total_pages;
 	struct memblock_region *reg;
 	int boot_mapsize;
+	phys_addr_t _total_lowmem;
+	phys_addr_t _lowmem_end_addr;
 
-	max_low_pfn = max_pfn = memblock_end_of_DRAM() >> PAGE_SHIFT;
-	total_pages = (memblock_end_of_DRAM() - memstart_addr) >> PAGE_SHIFT;
-#ifdef CONFIG_HIGHMEM
-	total_pages = total_lowmem >> PAGE_SHIFT;
-	max_low_pfn = lowmem_end_addr >> PAGE_SHIFT;
+#ifndef CONFIG_HIGHMEM
+	_lowmem_end_addr = memblock_end_of_DRAM();
+#else
+	_lowmem_end_addr = lowmem_end_addr;
 #endif
+	_total_lowmem = _lowmem_end_addr - memstart_addr;
+
+	max_pfn = memblock_end_of_DRAM() >> PAGE_SHIFT;
+	max_low_pfn = _lowmem_end_addr >> PAGE_SHIFT;
+	min_low_pfn = MEMORY_START >> PAGE_SHIFT;
 
 	/*
 	 * Find an area to use for the bootmem bitmap.  Calculate the size of
 	 * bitmap required as (Total Memory) / PAGE_SIZE / BITS_PER_BYTE.
 	 * Add 1 additional page in case the address isn't page-aligned.
 	 */
-	bootmap_pages = bootmem_bootmap_pages(total_pages);
+	bootmap_pages = bootmem_bootmap_pages(_total_lowmem >> PAGE_SHIFT);
 
 	start = memblock_alloc(bootmap_pages << PAGE_SHIFT, PAGE_SIZE);
 
-	min_low_pfn = MEMORY_START >> PAGE_SHIFT;
 	boot_mapsize = init_bootmem_node(NODE_DATA(0), start >> PAGE_SHIFT, min_low_pfn, max_low_pfn);
 
 	/* Place all memblock_regions in the same node and merge contiguous
@@ -219,26 +223,18 @@ void __init do_init_bootmem(void)
 	/* Add all physical memory to the bootmem map, mark each area
 	 * present.
 	 */
-#ifdef CONFIG_HIGHMEM
-	free_bootmem_with_active_regions(0, lowmem_end_addr >> PAGE_SHIFT);
+	free_bootmem_with_active_regions(0, max_low_pfn);
 
 	/* reserve the sections we're already using */
 	for_each_memblock(reserved, reg) {
-		unsigned long top = reg->base + reg->size - 1;
-		if (top < lowmem_end_addr)
+		if (reg->base + reg->size - 1 < _lowmem_end_addr)
 			reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
-		else if (reg->base < lowmem_end_addr) {
-			unsigned long trunc_size = lowmem_end_addr - reg->base;
+		else if (reg->base < _lowmem_end_addr) {
+			unsigned long trunc_size = _lowmem_end_addr - reg->base;
 			reserve_bootmem(reg->base, trunc_size, BOOTMEM_DEFAULT);
 		}
 	}
-#else
-	free_bootmem_with_active_regions(0, max_pfn);
 
-	/* reserve the sections we're already using */
-	for_each_memblock(reserved, reg)
-		reserve_bootmem(reg->base, reg->size, BOOTMEM_DEFAULT);
-#endif
 	/* XXX need to clip this if using highmem? */
 	sparse_memory_present_with_active_regions(0);
 
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH v2] powerpc/powernv: Platform dump interface
From: Vasant Hegde @ 2014-03-26 14:14 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: linuxppc-dev
In-Reply-To: <20140325165243.22c0109d@kryten>

On 03/25/2014 11:22 AM, Anton Blanchard wrote:
> Hi Vasant,
>
>> On 02/09/2014 02:50 AM, Anton Blanchard wrote:
>>>
>>> Hi Vasant,
>>>
>>>> +static void free_dump_sg_list(struct opal_sg_list *list)
>>>> +{
>>>> +	struct opal_sg_list *sg1;
>>>> +	while (list) {
>>>> +		sg1 = list->next;
>>>> +		kfree(list);
>>>> +		list = sg1;
>>>> +	}
>>>> +	list = NULL;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Build dump buffer scatter gather list
>>>> + */
>>>> +static struct opal_sg_list *dump_data_to_sglist(void)
>>>> +{
>>>> +	struct opal_sg_list *sg1, *list = NULL;
>>>> +	void *addr;
>>>> +	int64_t size;
>>>> +
>>>> +	addr = dump_record.buffer;
>>>> +	size = dump_record.size;
>>>> +
>>>> +	sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
>>>> +	if (!sg1)
>>>> +		goto nomem;
>>>> +
>>>> +	list = sg1;
>>>> +	sg1->num_entries = 0;
>>>> +	while (size > 0) {
>>>> +		/* Translate virtual address to physical address
>>>> */
>>>> +		sg1->entry[sg1->num_entries].data =
>>>> +			(void *)(vmalloc_to_pfn(addr) <<
>>>> PAGE_SHIFT); +
>>>> +		if (size > PAGE_SIZE)
>>>> +			sg1->entry[sg1->num_entries].length =
>>>> PAGE_SIZE;
>>>> +		else
>>>> +			sg1->entry[sg1->num_entries].length =
>>>> size; +
>>>> +		sg1->num_entries++;
>>>> +		if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
>>>> +			sg1->next = kzalloc(PAGE_SIZE,
>>>> GFP_KERNEL);
>>>> +			if (!sg1->next)
>>>> +				goto nomem;
>>>> +
>>>> +			sg1 = sg1->next;
>>>> +			sg1->num_entries = 0;
>>>> +		}
>>>> +		addr += PAGE_SIZE;
>>>> +		size -= PAGE_SIZE;
>>>> +	}
>>>> +	return list;
>>>> +
>>>> +nomem:
>>>> +	pr_err("%s : Failed to allocate memory\n", __func__);
>>>> +	free_dump_sg_list(list);
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Translate sg list address to absolute
>>>> + */
>>>> +static void sglist_to_phy_addr(struct opal_sg_list *list)
>>>> +{
>>>> +	struct opal_sg_list *sg, *next;
>>>> +
>>>> +	for (sg = list; sg; sg = next) {
>>>> +		next = sg->next;
>>>> +		/* Don't translate NULL pointer for last entry */
>>>> +		if (sg->next)
>>>> +			sg->next = (struct opal_sg_list
>>>> *)__pa(sg->next);
>>>> +		else
>>>> +			sg->next = NULL;
>>>> +
>>>> +		/* Convert num_entries to length */
>>>> +		sg->num_entries =
>>>> +			sg->num_entries * sizeof(struct
>>>> opal_sg_entry) + 16;
>>>> +	}
>>>> +}
>>>> +
>>>> +static void free_dump_data_buf(void)
>>>> +{
>>>> +	vfree(dump_record.buffer);
>>>> +	dump_record.size = 0;
>>>> +}
>>>
>>
>> Anton,
>>
>>> This looks identical to the code in opal-flash.c. Considering how
>>> complicated it is, can we put it somewhere common?
>>
>> Thanks for the review.. Will look into it next week.
>

Anton,

> This doesn't appear to have been fixed in the version that went into
> next.
>

Stewart rewrote dump interface.. That set of patch went into next, not my 
original patch..
Yes.. SG list separation is not yet done.. Never got a chance to look into this 
one.. Will try to
do it soon.

-Vasant

> Anton
>

^ permalink raw reply

* RE: [PATCH] ASoC: fsl_sai: Add isr to deal with error flag
From: David Laight @ 2014-03-26 11:59 UTC (permalink / raw)
  To: 'Nicolin Chen', broonie@kernel.org,
	Li.Xiubo@freescale.com
  Cc: alsa-devel@alsa-project.org, linuxppc-dev@lists.ozlabs.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <1395834517-16426-1-git-send-email-Guangyu.Chen@freescale.com>

RnJvbTogTmljb2xpbiBDaGVuDQo+IEl0J3MgcXVpdGUgY3JpY2lhbCB0byBjbGVhciBlcnJvciBm
bGFncyBiZWNhdXNlIFNBSSBtaWdodCBoYW5nIGlmIGdldHRpbmcNCj4gRklGTyB1bmRlcnJ1biBk
dXJpbmcgcGxheWJhY2sgKEkgaGF2ZW4ndCBjb25maXJtZWQgdGhlIHNhbWUgaXNzdWUgb24gUngN
Cj4gb3ZlcmZsb3cgdGhvdWdoKS4NCj4gDQo+IFNvIHRoaXMgcGF0Y2ggZW5hYmxlcyB0aG9zZSBp
cnEgYW5kIGFkZHMgaXNyKCkgdG8gY2xlYXIgdGhlIGZsYWdzIHNvIGFzIHRvDQo+IGtlZXAgcGxh
eWJhY2sgZW50aXJlbHkgc2FmZS4NCj4gDQo+IFNpZ25lZC1vZmYtYnk6IE5pY29saW4gQ2hlbiA8
R3Vhbmd5dS5DaGVuQGZyZWVzY2FsZS5jb20+DQo+IC0tLQ0KPiAgc291bmQvc29jL2ZzbC9mc2xf
c2FpLmMgfCA2OSArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr
LS0tDQo+ICBzb3VuZC9zb2MvZnNsL2ZzbF9zYWkuaCB8ICA5ICsrKysrKysNCj4gIDIgZmlsZXMg
Y2hhbmdlZCwgNzUgaW5zZXJ0aW9ucygrKSwgMyBkZWxldGlvbnMoLSkNCj4gDQo+IGRpZmYgLS1n
aXQgYS9zb3VuZC9zb2MvZnNsL2ZzbF9zYWkuYyBiL3NvdW5kL3NvYy9mc2wvZnNsX3NhaS5jDQo+
IGluZGV4IGM0YTQyMzEuLjVmOTFhZmYgMTAwNjQ0DQo+IC0tLSBhL3NvdW5kL3NvYy9mc2wvZnNs
X3NhaS5jDQo+ICsrKyBiL3NvdW5kL3NvYy9mc2wvZnNsX3NhaS5jDQo+IEBAIC0yMyw2ICsyMyw1
NSBAQA0KPiANCj4gICNpbmNsdWRlICJmc2xfc2FpLmgiDQo+IA0KPiArI2RlZmluZSBGU0xfU0FJ
X0ZMQUdTIChGU0xfU0FJX0NTUl9TRUlFIHxcDQo+ICsJCSAgICAgICBGU0xfU0FJX0NTUl9GRUlF
IHxcDQo+ICsJCSAgICAgICBGU0xfU0FJX0NTUl9GV0lFKQ0KPiArDQo+ICtzdGF0aWMgaXJxcmV0
dXJuX3QgZnNsX3NhaV9pc3IoaW50IGlycSwgdm9pZCAqZGV2aWQpDQo+ICt7DQo+ICsJc3RydWN0
IGZzbF9zYWkgKnNhaSA9IChzdHJ1Y3QgZnNsX3NhaSAqKWRldmlkOw0KPiArCXN0cnVjdCBkZXZp
Y2UgKmRldiA9ICZzYWktPnBkZXYtPmRldjsNCj4gKwl1MzIgeGNzcjsNCj4gKw0KPiArCXJlZ21h
cF9yZWFkKHNhaS0+cmVnbWFwLCBGU0xfU0FJX1RDU1IsICZ4Y3NyKTsNCj4gKwlyZWdtYXBfd3Jp
dGUoc2FpLT5yZWdtYXAsIEZTTF9TQUlfVENTUiwgeGNzcik7DQoNCkFzc3VtaW5nIHRoZXNlIGFy
ZSAnd3JpdGUgdG8gY2xlYXInIGJpdHMsIHlvdSBtaWdodCB3YW50DQp0byBtYWtlIHRoZSB3cml0
ZSAoYWJvdmUpIGFuZCBhbGwgdGhlIHRyYWNlcyAoYmVsb3cpDQpjb25kaXRpb25hbCBvbiB0aGUg
dmFsdWUgYmVpbmcgbm9uLXplcm8uDQoNCj4gKwlpZiAoeGNzciAmIEZTTF9TQUlfQ1NSX1dTRikN
Cj4gKwkJZGV2X2RiZyhkZXYsICJpc3I6IFN0YXJ0IG9mIFR4IHdvcmQgZGV0ZWN0ZWRcbiIpOw0K
PiArDQo+ICsJaWYgKHhjc3IgJiBGU0xfU0FJX0NTUl9TRUYpDQo+ICsJCWRldl9kYmcoZGV2LCAi
aXNyOiBUeCBGcmFtZSBzeW5jIGVycm9yIGRldGVjdGVkXG4iKTsNCj4gKw0KPiArCWlmICh4Y3Ny
ICYgRlNMX1NBSV9DU1JfRkVGKQ0KPiArCQlkZXZfZGJnKGRldiwgImlzcjogVHJhbnNtaXQgdW5k
ZXJydW4gZGV0ZWN0ZWRcbiIpOw0KPiArDQo+ICsJaWYgKHhjc3IgJiBGU0xfU0FJX0NTUl9GV0Yp
DQo+ICsJCWRldl9kYmcoZGV2LCAiaXNyOiBFbmFibGVkIHRyYW5zbWl0IEZJRk8gaXMgZW1wdHlc
biIpOw0KPiArDQo+ICsJaWYgKHhjc3IgJiBGU0xfU0FJX0NTUl9GUkYpDQo+ICsJCWRldl9kYmco
ZGV2LCAiaXNyOiBUcmFuc21pdCBGSUZPIHdhdGVybWFyayBoYXMgYmVlbiByZWFjaGVkXG4iKTsN
Cg0KU29tZSBvZiB0aG9zZSBsb29rIGxpa2UgJ25vcm1hbCcgaW50ZXJydXB0cywgb3RoZXJzIGFy
ZSBjbGVhcmx5DQphYm5vcm1hbCBjb25kaXRpb25zLg0KTWF5YmUgdGhlIHRyYWNpbmcgc2hvdWxk
IHJlZmxlY3QgdGhpcy4NCg0KPiArDQo+ICsJcmVnbWFwX3JlYWQoc2FpLT5yZWdtYXAsIEZTTF9T
QUlfUkNTUiwgJnhjc3IpOw0KPiArCXJlZ21hcF93cml0ZShzYWktPnJlZ21hcCwgRlNMX1NBSV9S
Q1NSLCB4Y3NyKTsNCg0KU2FtZSBjb21tZW50cyBhcHBseS4uLg0KDQoJRGF2aWQNCg0K

^ permalink raw reply

* [PATCH] ASoC: fsl_sai: Add isr to deal with error flag
From: Nicolin Chen @ 2014-03-26 11:48 UTC (permalink / raw)
  To: broonie, Li.Xiubo; +Cc: alsa-devel, linuxppc-dev, linux-kernel

It's quite cricial to clear error flags because SAI might hang if getting
FIFO underrun during playback (I haven't confirmed the same issue on Rx
overflow though).

So this patch enables those irq and adds isr() to clear the flags so as to
keep playback entirely safe.

Signed-off-by: Nicolin Chen <Guangyu.Chen@freescale.com>
---
 sound/soc/fsl/fsl_sai.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++---
 sound/soc/fsl/fsl_sai.h |  9 +++++++
 2 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index c4a4231..5f91aff 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -23,6 +23,55 @@
 
 #include "fsl_sai.h"
 
+#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
+		       FSL_SAI_CSR_FEIE |\
+		       FSL_SAI_CSR_FWIE)
+
+static irqreturn_t fsl_sai_isr(int irq, void *devid)
+{
+	struct fsl_sai *sai = (struct fsl_sai *)devid;
+	struct device *dev = &sai->pdev->dev;
+	u32 xcsr;
+
+	regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
+	regmap_write(sai->regmap, FSL_SAI_TCSR, xcsr);
+
+	if (xcsr & FSL_SAI_CSR_WSF)
+		dev_dbg(dev, "isr: Start of Tx word detected\n");
+
+	if (xcsr & FSL_SAI_CSR_SEF)
+		dev_dbg(dev, "isr: Tx Frame sync error detected\n");
+
+	if (xcsr & FSL_SAI_CSR_FEF)
+		dev_dbg(dev, "isr: Transmit underrun detected\n");
+
+	if (xcsr & FSL_SAI_CSR_FWF)
+		dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
+
+	if (xcsr & FSL_SAI_CSR_FRF)
+		dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
+
+	regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
+	regmap_write(sai->regmap, FSL_SAI_RCSR, xcsr);
+
+	if (xcsr & FSL_SAI_CSR_WSF)
+		dev_dbg(dev, "isr: Start of Rx word detected\n");
+
+	if (xcsr & FSL_SAI_CSR_SEF)
+		dev_dbg(dev, "isr: Rx Frame sync error detected\n");
+
+	if (xcsr & FSL_SAI_CSR_FEF)
+		dev_dbg(dev, "isr: Receive overflow detected\n");
+
+	if (xcsr & FSL_SAI_CSR_FWF)
+		dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
+
+	if (xcsr & FSL_SAI_CSR_FRF)
+		dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
+
+	return IRQ_HANDLED;
+}
+
 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
 		int clk_id, unsigned int freq, int fsl_dir)
 {
@@ -373,8 +422,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
 	struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
 
-	regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
-	regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+	regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS);
+	regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS);
 	regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
 			   FSL_SAI_MAXBURST_TX * 2);
 	regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -490,12 +539,14 @@ static int fsl_sai_probe(struct platform_device *pdev)
 	struct fsl_sai *sai;
 	struct resource *res;
 	void __iomem *base;
-	int ret;
+	int irq, ret;
 
 	sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
 	if (!sai)
 		return -ENOMEM;
 
+	sai->pdev = pdev;
+
 	sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
 	if (sai->big_endian_regs)
 		fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
@@ -514,6 +565,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
 		return PTR_ERR(sai->regmap);
 	}
 
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+		return irq;
+	}
+
+	ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+		return ret;
+	}
+
 	sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
 	sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
 	sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h
index e432260..05d1a1f 100644
--- a/sound/soc/fsl/fsl_sai.h
+++ b/sound/soc/fsl/fsl_sai.h
@@ -37,7 +37,15 @@
 
 /* SAI Transmit/Recieve Control Register */
 #define FSL_SAI_CSR_TERE	BIT(31)
+#define FSL_SAI_CSR_WSF		BIT(20)
+#define FSL_SAI_CSR_SEF		BIT(19)
+#define FSL_SAI_CSR_FEF		BIT(18)
 #define FSL_SAI_CSR_FWF		BIT(17)
+#define FSL_SAI_CSR_FRF		BIT(16)
+#define FSL_SAI_CSR_WSIE	BIT(12)
+#define FSL_SAI_CSR_SEIE	BIT(11)
+#define FSL_SAI_CSR_FEIE	BIT(10)
+#define FSL_SAI_CSR_FWIE	BIT(9)
 #define FSL_SAI_CSR_FRIE	BIT(8)
 #define FSL_SAI_CSR_FRDE	BIT(0)
 
@@ -99,6 +107,7 @@
 #define FSL_SAI_MAXBURST_RX 6
 
 struct fsl_sai {
+	struct platform_device *pdev;
 	struct regmap *regmap;
 
 	bool big_endian_regs;
-- 
1.8.4

^ permalink raw reply related

* Re: [PATCH 00/33] Build ppc64le kernel using ABIv2
From: Anton Blanchard @ 2014-03-26 11:20 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: mikey, amodra, rusty, mjw, paulus, linuxppc-dev
In-Reply-To: <OF5605E77F.F2B0528E-ONC1257CA6.00487EE5-C1257CA6.00491690@de.ibm.com>


Hi Uli,

> You probably should have two different macros _GLOBAL_TOC vs. _GLOBAL
> (or _GLOBAL vs. _GLOBAL_NOTOC), and use the variant that provides a
> global entry point setting up the TOC only with those functions that
> actually require a TOC.

I was worried that we might introduce subtle bugs by forgetting to use
the right version, but I agree it seems to be the only way.

> When I looked at this last time, I remarked:
> 
> >./platforms/pseries/hvCall.S:
> >./platforms/cell/beat_hvCall.S:
> >Looks safe since all functions are called via varargs prototypes
> >(or > 8 integer arguments).
> 
> Checking again, this still seems true.  These are the prototypes
> for all the functions in hvCall.S:

You are right, I forgot about your previous review. Thanks!

Anton

^ permalink raw reply

* Re: [PATCH 27/33] powerpc: Handle new ELFv2 module relocations
From: Alan Modra @ 2014-03-26 10:28 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: mikey, rusty, ulrich.weigand, mjw, paulus, linuxppc-dev
In-Reply-To: <1395747879-5948-28-git-send-email-anton@samba.org>

On Tue, Mar 25, 2014 at 10:44:33PM +1100, Anton Blanchard wrote:
> From: Rusty Russell <rusty@rustcorp.com.au>
> +		case R_PPC64_REL16_HA:
> +			/* Subtract location pointer */
> +			value -= (unsigned long)location;
> +			value = ((value + 0x8000) >> 16);
> +			*((uint16_t *) location)
> +				= (*((uint16_t *) location) & ~0xffff)
> +				| (value & 0xffff);

There's not much point reading the uint16_t.

			*(uint16_t *) location = value;

> +			break;
> +
> +		case R_PPC64_REL16_LO:
> +			/* Subtract location pointer */
> +			value -= (unsigned long)location;
> +			*((uint16_t *) location)
> +				= (*((uint16_t *) location) & ~0xffff)
> +				| (value & 0xffff);

and again.

> +			break;
> +
>  		default:
>  			printk("%s: Unknown ADD relocation: %lu\n",
>  			       me->name,

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply

* Re: [PATCH 15/33] powerpc: Fix ABIv2 issues with stack offsets in assembly code
From: Alan Modra @ 2014-03-26 10:06 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: mikey, rusty, ulrich.weigand, mjw, paulus, linuxppc-dev
In-Reply-To: <20140326100449.GN18201@bubble.grove.modra.org>

On Wed, Mar 26, 2014 at 08:34:49PM +1030, Alan Modra wrote:
> On Tue, Mar 25, 2014 at 10:44:21PM +1100, Anton Blanchard wrote:
> > Fix STK_PARAM and use it instead of hardcoding ABIv1 offsets.
> 
> >  _GLOBAL(memcpy)
> >  BEGIN_FTR_SECTION
> > -	std	r3,48(r1)	/* save destination pointer for return value */
> > +	std	r3,STK_PARAM(R3)(r1)	/* save destination pointer for return value */
> 
> Here and elsewhere you're assuming you have a parameter save area.
> That won't be true with ELFv2 for calls to functions like memcpy.

Nevermind, I see you fixed that with the next patch..

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply

* Re: [PATCH 15/33] powerpc: Fix ABIv2 issues with stack offsets in assembly code
From: Alan Modra @ 2014-03-26 10:04 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: mikey, rusty, ulrich.weigand, mjw, paulus, linuxppc-dev
In-Reply-To: <1395747879-5948-16-git-send-email-anton@samba.org>

On Tue, Mar 25, 2014 at 10:44:21PM +1100, Anton Blanchard wrote:
> Fix STK_PARAM and use it instead of hardcoding ABIv1 offsets.

>  _GLOBAL(memcpy)
>  BEGIN_FTR_SECTION
> -	std	r3,48(r1)	/* save destination pointer for return value */
> +	std	r3,STK_PARAM(R3)(r1)	/* save destination pointer for return value */

Here and elsewhere you're assuming you have a parameter save area.
That won't be true with ELFv2 for calls to functions like memcpy.

typedef __SIZE_TYPE__ size_t;
extern void *memcpy (void *dest, const void *src, size_t n);

void foo (void *dest, const void *src, size_t n)
{
  memcpy (dest, src, n);
}

foo:
0:	addis 2,12,.TOC.-0b@ha
	addi 2,2,.TOC.-0b@l
	.localentry	foo,.-foo
	mflr 0
	std 0,16(1)
	stdu 1,-32(1)   # <========
	bl memcpy
	nop
	addi 1,1,32
	ld 0,16(1)
	mtlr 0
	blr

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply

* RE: [PATCH v4 09/11] powerpc/perf: add support for the hv 24x7 interface
From: David Laight @ 2014-03-26  9:43 UTC (permalink / raw)
  To: 'Cody P Schafer', Anton Blanchard
  Cc: Peter Zijlstra, LKML, Michael Ellerman, Ingo Molnar,
	Paul Mackerras, Arnaldo Carvalho de Melo, scottwood@freescale.com,
	Linux PPC
In-Reply-To: <5331CBB0.8080500@linux.vnet.ibm.com>

RnJvbTogQ29keSBQIFNjaGFmZXINCj4gT24gMDMvMjUvMjAxNCAwMzo0MyBBTSwgQW50b24gQmxh
bmNoYXJkIHdyb3RlOg0KPiA+DQo+ID4gSGkgQ29keSwNCj4gPg0KPiA+IGh2LTI0eDc6IGNvdWxk
IG5vdCBvYnRhaW4gY2FwYWJpbGl0aWVzLCBlcnJvciAweA0KPiBmZmZmZmZmZmZmZmZmZmZlLCBu
b3QgZW5hYmxpbmcNCj4gPiBodi1ncGNpOiBjb3VsZCBub3Qgb2J0YWluIGNhcGFiaWxpdGllcywg
ZXJyb3IgMHgNCj4gZmZmZmZmZmZmZmZmZmZmZSwgbm90IGVuYWJsaW5nDQo+ID4NCj4gPj4gKwkJ
cHJfaW5mbygiY291bGQgbm90IG9idGFpbiBjYXBhYmlsaXRpZXMsIGVycm9yIDB4JTgwbHgsIG5v
dCBlbmFibGluZ1xuIiwNCj4gPg0KPiA+IFRoYXQncyBhIGxvdCBvZiBwYWRkaW5nIDopDQo+ID4N
Cj4gPiBJIHRoaW5rIHRoaXMgc2hvdWxkIGFsc28gYmUgYSBwcl9kZWJ1ZywgY29uc2lkZXJpbmcg
dGhpcyBpcyBub3QgcmVsZXZhbnQNCj4gPiB0byBtb3N0IHBwYzY0IGJveGVzLg0KPiANCj4gWWVw
LCBzL2luZm8vZGVidWcvIG1ha2VzIHNlbnNlLiBUaGUgZm9ybWF0IHNob3VsZCBoYXZlIGJlZW4g
IiUwOGx4IiBub3QNCj4gIiU4MGx4Iiwgbm90IHN1cmUgd2hlbiBJIHNjcmV3ZWQgdGhhdCB1cC4N
Cg0KVXNpbmcgIiUjeCIgaXMgYW4gYWx0ZXJuYXRpdmUgLSB1bmxlc3MgeW91IHJlYWxseSBuZWVk
IGZpeGVkIHdpZHRoLg0KDQpIb3dldmVyIGluIHRoaXMgY2FzZSAiJWxkIiBtaWdodCBiZSBtb3Jl
IGFwcHJvcHJpYXRlIQ0KSWYgdGhlIHZhbHVlIGlzIGEgLXZlIGVycm5vIG9uZSwgbWF5YmUgZXZl
biAiZXJybm8gJWQiIGFuZCBuZWdhdGUgdGhlIHZhbHVlLg0KDQoJRGF2aWQNCg0K

^ permalink raw reply

* Re: [PATCH 10/33] powerpc: Ignore TOC relocations
From: Alan Modra @ 2014-03-26  9:36 UTC (permalink / raw)
  To: Anton Blanchard; +Cc: mikey, rusty, ulrich.weigand, mjw, paulus, linuxppc-dev
In-Reply-To: <1395747879-5948-11-git-send-email-anton@samba.org>

On Tue, Mar 25, 2014 at 10:44:16PM +1100, Anton Blanchard wrote:
> The linker fixes up TOC. relocations, so prom_init_check.sh should
> ignore them.

Err, .TOC. you mean.  Presumably something strips off the leading dot
somewhere?

> -btext_setup_display"
> +btext_setup_display TOC."

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply

* Re: Build regressions/improvements in v3.14-rc8
From: Geert Uytterhoeven @ 2014-03-26  7:55 UTC (permalink / raw)
  To: linux-kernel@vger.kernel.org; +Cc: linuxppc-dev@lists.ozlabs.org, Linux-sh list
In-Reply-To: <1395820064-19148-1-git-send-email-geert@linux-m68k.org>

On Wed, Mar 26, 2014 at 8:47 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> JFYI, when comparing v3.14-rc8[1]  to v3.14-rc7[3], the summaries are:
>   - build errors: +6/-1

  + /scratch/kisskb/src/arch/powerpc/include/asm/io.h: error:
'virt_phys_offset' undeclared (first use in this function):  =>
814:16, 807:16, 770:9, 787:17
  + /scratch/kisskb/src/include/linux/mm.h: error: 'virt_phys_offset'
undeclared (first use in this function):  => 890:9, 1402:20, 494:22

powerpc-randconfig

  + /scratch/kisskb/src/arch/sh/drivers/dma/dma-sh.c: error:
'CHCR_TS_HIGH_MASK' undeclared (first use in this function):  => 98:12
  + /scratch/kisskb/src/arch/sh/drivers/dma/dma-sh.c: error:
'CHCR_TS_HIGH_SHIFT' undeclared (first use in this function):  =>
98:34, 145:10
  + /scratch/kisskb/src/arch/sh/drivers/dma/dma-sh.c: error:
'CHCR_TS_LOW_MASK' undeclared (first use in this function):  => 97:21
  + /scratch/kisskb/src/arch/sh/drivers/dma/dma-sh.c: error:
'CHCR_TS_LOW_SHIFT' undeclared (first use in this function):  =>
97:42, 145:10

sh-randconfig

> [1] http://kisskb.ellerman.id.au/kisskb/head/7303/ (all 119 configs)
> [3] http://kisskb.ellerman.id.au/kisskb/head/7277/ (all 119 configs)

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH 6/7] DMA: Freescale: use spin_lock_bh instead of spin_lock_irqsave
From: Vinod Koul @ 2014-03-26  7:01 UTC (permalink / raw)
  To: hongbo.zhang
  Cc: vinod.koul, linux-kernel, scottwood, dmaengine, dan.j.williams,
	linuxppc-dev
In-Reply-To: <1389851246-8564-7-git-send-email-hongbo.zhang@freescale.com>

On Thu, 2014-01-16 at 13:47 +0800, hongbo.zhang@freescale.com wrote:
> From: Hongbo Zhang <hongbo.zhang@freescale.com>
> 
> The usage of spin_lock_irqsave() is a stronger locking mechanism than is
> required throughout the driver. The minimum locking required should be used
> instead. Interrupts will be turned off and context will be saved, it is
> unnecessary to use irqsave.
> 
> This patch changes all instances of spin_lock_irqsave() to spin_lock_bh(). All
> manipulation of protected fields is done using tasklet context or weaker, which
> makes spin_lock_bh() the correct choice.
> 
> Signed-off-by: Hongbo Zhang <hongbo.zhang@freescale.com>
> Signed-off-by: Qiang Liu <qiang.liu@freescale.com>
> ---
>  drivers/dma/fsldma.c |   25 ++++++++++---------------
>  1 file changed, 10 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
> index bbace54..437794e 100644
> --- a/drivers/dma/fsldma.c
> +++ b/drivers/dma/fsldma.c
> @@ -396,10 +396,9 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
>  	struct fsldma_chan *chan = to_fsl_chan(tx->chan);
>  	struct fsl_desc_sw *desc = tx_to_fsl_desc(tx);
>  	struct fsl_desc_sw *child;
> -	unsigned long flags;
>  	dma_cookie_t cookie = -EINVAL;
>  
> -	spin_lock_irqsave(&chan->desc_lock, flags);
> +	spin_lock_bh(&chan->desc_lock);
>  
>  	/*
>  	 * assign cookies to all of the software descriptors
> @@ -412,7 +411,7 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
>  	/* put this transaction onto the tail of the pending queue */
>  	append_ld_queue(chan, desc);
>  
> -	spin_unlock_irqrestore(&chan->desc_lock, flags);
> +	spin_unlock_bh(&chan->desc_lock);
>  
>  	return cookie;
>  }
> @@ -731,15 +730,14 @@ static void fsldma_free_desc_list_reverse(struct fsldma_chan *chan,
>  static void fsl_dma_free_chan_resources(struct dma_chan *dchan)
>  {
>  	struct fsldma_chan *chan = to_fsl_chan(dchan);
> -	unsigned long flags;
>  
>  	chan_dbg(chan, "free all channel resources\n");
> -	spin_lock_irqsave(&chan->desc_lock, flags);
> +	spin_lock_bh(&chan->desc_lock);
>  	fsldma_cleanup_descriptors(chan);
>  	fsldma_free_desc_list(chan, &chan->ld_pending);
>  	fsldma_free_desc_list(chan, &chan->ld_running);
>  	fsldma_free_desc_list(chan, &chan->ld_completed);
> -	spin_unlock_irqrestore(&chan->desc_lock, flags);
> +	spin_unlock_bh(&chan->desc_lock);
>  
>  	dma_pool_destroy(chan->desc_pool);
>  	chan->desc_pool = NULL;
> @@ -958,7 +956,6 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
>  {
>  	struct dma_slave_config *config;
>  	struct fsldma_chan *chan;
> -	unsigned long flags;
>  	int size;
>  
>  	if (!dchan)
> @@ -968,7 +965,7 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
>  
>  	switch (cmd) {
>  	case DMA_TERMINATE_ALL:
> -		spin_lock_irqsave(&chan->desc_lock, flags);
> +		spin_lock_bh(&chan->desc_lock);
>  
>  		/* Halt the DMA engine */
>  		dma_halt(chan);
> @@ -979,7 +976,7 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
>  		fsldma_free_desc_list(chan, &chan->ld_completed);
>  		chan->idle = true;
>  
> -		spin_unlock_irqrestore(&chan->desc_lock, flags);
> +		spin_unlock_bh(&chan->desc_lock);
>  		return 0;
>  
>  	case DMA_SLAVE_CONFIG:
> @@ -1021,11 +1018,10 @@ static int fsl_dma_device_control(struct dma_chan *dchan,
>  static void fsl_dma_memcpy_issue_pending(struct dma_chan *dchan)
>  {
>  	struct fsldma_chan *chan = to_fsl_chan(dchan);
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&chan->desc_lock, flags);
> +	spin_lock_bh(&chan->desc_lock);
>  	fsl_chan_xfer_ld_queue(chan);
> -	spin_unlock_irqrestore(&chan->desc_lock, flags);
> +	spin_unlock_bh(&chan->desc_lock);
>  }
>  
>  /**
> @@ -1124,11 +1120,10 @@ static irqreturn_t fsldma_chan_irq(int irq, void *data)
>  static void dma_do_tasklet(unsigned long data)
>  {
>  	struct fsldma_chan *chan = (struct fsldma_chan *)data;
> -	unsigned long flags;
>  
>  	chan_dbg(chan, "tasklet entry\n");
>  
> -	spin_lock_irqsave(&chan->desc_lock, flags);
> +	spin_lock_bh(&chan->desc_lock);
okay here is the problem :(

You moved to _bh variant. So if you grab the lock in rest of the code
and irq gets triggered then here we will be spinning to grab the lock.
So effectively you made right locking solution into deadlock situation!

>  
>  	/* the hardware is now idle and ready for more */
>  	chan->idle = true;
> @@ -1136,7 +1131,7 @@ static void dma_do_tasklet(unsigned long data)
>  	/* Run all cleanup for descriptors which have been completed */
>  	fsldma_cleanup_descriptors(chan);
>  
> -	spin_unlock_irqrestore(&chan->desc_lock, flags);
> +	spin_unlock_bh(&chan->desc_lock);
>  
>  	chan_dbg(chan, "tasklet exit\n");
>  }


-- 
Vinod Koul
Intel Corp.

^ permalink raw reply

* [PATCH] phy/at8031: enable at8031 to work on interrupt mode
From: Zhao Qiang @ 2014-03-26  6:45 UTC (permalink / raw)
  To: linuxppc-dev, B07421; +Cc: Zhao Qiang, R63061

The at8031 can work on polling mode and interrupt mode.
Add ack_interrupt and config intr funcs to enable
interrupt mode for it.

Signed-off-by: Zhao Qiang <B45475@freescale.com>
---
 drivers/net/phy/at803x.c | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index bc71947..d034ef5 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -27,6 +27,9 @@
 #define AT803X_MMD_ACCESS_CONTROL		0x0D
 #define AT803X_MMD_ACCESS_CONTROL_DATA		0x0E
 #define AT803X_FUNC_DATA			0x4003
+#define AT803X_INER				0x0012
+#define AT803X_INER_INIT			0xec00
+#define AT803X_INSR				0x0013
 #define AT803X_DEBUG_ADDR			0x1D
 #define AT803X_DEBUG_DATA			0x1E
 #define AT803X_DEBUG_SYSTEM_MODE_CTRL		0x05
@@ -191,6 +194,31 @@ static int at803x_config_init(struct phy_device *phydev)
 	return 0;
 }
 
+static int at803x_ack_interrupt(struct phy_device *phydev)
+{
+	int err;
+
+	err = phy_read(phydev, AT803X_INSR);
+
+	return (err < 0) ? err : 0;
+}
+
+static int at803x_config_intr(struct phy_device *phydev)
+{
+	int err;
+	int value;
+
+	value = phy_read(phydev, AT803X_INER);
+
+	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
+		err = phy_write(phydev, AT803X_INER,
+				(value | AT803X_INER_INIT));
+	else
+		err = phy_write(phydev, AT803X_INER, value);
+
+	return err;
+}
+
 static struct phy_driver at803x_driver[] = {
 {
 	/* ATHEROS 8035 */
@@ -240,6 +268,8 @@ static struct phy_driver at803x_driver[] = {
 	.flags		= PHY_HAS_INTERRUPT,
 	.config_aneg	= genphy_config_aneg,
 	.read_status	= genphy_read_status,
+	.ack_interrupt  = &at803x_ack_interrupt,
+	.config_intr    = &at803x_config_intr,
 	.driver		= {
 		.owner = THIS_MODULE,
 	},
-- 
1.8.5

^ permalink raw reply related

* Re: [RFC PATCH] Remove CONFIG_DCACHE_WORD_ACCESS
From: Joe Perches @ 2014-03-26  4:54 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Anton Blanchard
  Cc: linux-arch, Russell King, Catalin Marinas, x86, Will Deacon,
	linux-kernel, Ingo Molnar, Paul Mackerras, Alexander Viro,
	H. Peter Anvin, linux-fsdevel, Thomas Gleixner, linuxppc-dev,
	linux-arm-kernel
In-Reply-To: <1394570240.4840.48.camel@pasglop>

On Wed, 2014-03-12 at 07:37 +1100, Benjamin Herrenschmidt wrote:
> On Tue, 2014-03-04 at 12:23 -0800, Joe Perches wrote:
> > It seems to duplicate CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> > so use that instead.
> > 
> > This changes the !CPU_LITTLE_ENDIAN powerpc arch to use unaligned
> > accesses in fs/dcache.c and fs/namei.c as
> > CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is enabled for that arch.
> > 
> > Remove the now unused DCACHE_WORD_ACCESS defines & uses.
> 
> Interesting.. we have word-at-a-time but we never enabled
> DCACHE_WORD_ACCESS, I wonder why that is. In fact, we should
> probably do it for LE as well for P8 if we can make a P8
> only config option...
> 
> Anton, what do you reckon here ?

Anton, do you have an opinion here?

> Cheers,
> Ben.
> 
> > Signed-off-by: Joe Perches <joe@perches.com>
> > ---
> >  arch/arm/Kconfig                      | 1 -
> >  arch/arm/include/asm/word-at-a-time.h | 4 ++--
> >  arch/arm64/Kconfig                    | 1 -
> >  arch/x86/Kconfig                      | 1 -
> >  fs/Kconfig                            | 4 ----
> >  fs/dcache.c                           | 2 +-
> >  fs/namei.c                            | 2 +-
> >  7 files changed, 4 insertions(+), 11 deletions(-)
> > 
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 623a272..d5a2e60 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -12,7 +12,6 @@ config ARM
> >  	select BUILDTIME_EXTABLE_SORT if MMU
> >  	select CLONE_BACKWARDS
> >  	select CPU_PM if (SUSPEND || CPU_IDLE)
> > -	select DCACHE_WORD_ACCESS if HAVE_EFFICIENT_UNALIGNED_ACCESS
> >  	select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
> >  	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
> >  	select GENERIC_IDLE_POLL_SETUP
> > diff --git a/arch/arm/include/asm/word-at-a-time.h b/arch/arm/include/asm/word-at-a-time.h
> > index a6d0a29..778b2ad 100644
> > --- a/arch/arm/include/asm/word-at-a-time.h
> > +++ b/arch/arm/include/asm/word-at-a-time.h
> > @@ -54,7 +54,7 @@ static inline unsigned long find_zero(unsigned long mask)
> >  #include <asm-generic/word-at-a-time.h>
> >  #endif
> >  
> > -#ifdef CONFIG_DCACHE_WORD_ACCESS
> > +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> >  
> >  /*
> >   * Load an unaligned word from kernel space.
> > @@ -94,5 +94,5 @@ static inline unsigned long load_unaligned_zeropad(const void *addr)
> >  	return ret;
> >  }
> >  
> > -#endif	/* DCACHE_WORD_ACCESS */
> > +#endif	/* HAVE_EFFICIENT_UNALIGNED_ACCESS */
> >  #endif /* __ASM_ARM_WORD_AT_A_TIME_H */
> > diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> > index 764d682..2d6978c 100644
> > --- a/arch/arm64/Kconfig
> > +++ b/arch/arm64/Kconfig
> > @@ -13,7 +13,6 @@ config ARM64
> >  	select CLONE_BACKWARDS
> >  	select COMMON_CLK
> >  	select CPU_PM if (SUSPEND || CPU_IDLE)
> > -	select DCACHE_WORD_ACCESS
> >  	select GENERIC_CLOCKEVENTS
> >  	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
> >  	select GENERIC_IOMAP
> > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> > index abb261e..60cfa073 100644
> > --- a/arch/x86/Kconfig
> > +++ b/arch/x86/Kconfig
> > @@ -98,7 +98,6 @@ config X86
> >  	select CLKEVT_I8253
> >  	select ARCH_HAVE_NMI_SAFE_CMPXCHG
> >  	select GENERIC_IOMAP
> > -	select DCACHE_WORD_ACCESS
> >  	select GENERIC_SMP_IDLE_THREAD
> >  	select ARCH_WANT_IPC_PARSE_VERSION if X86_32
> >  	select HAVE_ARCH_SECCOMP_FILTER
> > diff --git a/fs/Kconfig b/fs/Kconfig
> > index 312393f..7511271 100644
> > --- a/fs/Kconfig
> > +++ b/fs/Kconfig
> > @@ -4,10 +4,6 @@
> >  
> >  menu "File systems"
> >  
> > -# Use unaligned word dcache accesses
> > -config DCACHE_WORD_ACCESS
> > -       bool
> > -
> >  if BLOCK
> >  
> >  source "fs/ext2/Kconfig"
> > diff --git a/fs/dcache.c b/fs/dcache.c
> > index 265e0ce..4e3c195 100644
> > --- a/fs/dcache.c
> > +++ b/fs/dcache.c
> > @@ -163,7 +163,7 @@ int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
> >   * Compare 2 name strings, return 0 if they match, otherwise non-zero.
> >   * The strings are both count bytes long, and count is non-zero.
> >   */
> > -#ifdef CONFIG_DCACHE_WORD_ACCESS
> > +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> >  
> >  #include <asm/word-at-a-time.h>
> >  /*
> > diff --git a/fs/namei.c b/fs/namei.c
> > index 385f781..1ee33ca 100644
> > --- a/fs/namei.c
> > +++ b/fs/namei.c
> > @@ -1618,7 +1618,7 @@ static inline int nested_symlink(struct path *path, struct nameidata *nd)
> >   *   the final mask". Again, that could be replaced with a
> >   *   efficient population count instruction or similar.
> >   */
> > -#ifdef CONFIG_DCACHE_WORD_ACCESS
> > +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
> >  
> >  #include <asm/word-at-a-time.h>

^ permalink raw reply

* Re: Ask for help about fsl ppc toolchian issue "Illegal instruction"
From: Scott Wood @ 2014-03-25 23:05 UTC (permalink / raw)
  To: wyang; +Cc: 许久成, linuxppc-dev@ozlabs.org
In-Reply-To: <533114A4.4080608@gmail.com>

On Tue, 2014-03-25 at 13:31 +0800, wyang wrote:
> 
> On 03/25/2014 10:17 AM, 许久成 wrote:
> 
> > Hi All, 
> > 
> > 
> > We run into an issue when use e500mc toolchain  g++ to compile c++
> > code for p2020 platform,  the code as below:
> 
> Hmm, p2020 should be e500 core rather than e500mc. Additionally, you
> should use gdb to debug it, and check which instruction is illegal.

It's probably a floating point instruction.  e500v2 (and thus p2020)
does not support normal PPC floating point.  You need to use the right
toolchain.

-Scott

^ 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