LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] powerpc: Remove platforms/wsp and associated pieces
From: Paul Bolle @ 2014-06-02  8:04 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: linuxppc-dev, Jimi Xenidis, Stephen Rothwell
In-Reply-To: <1401672046-17607-1-git-send-email-mpe@ellerman.id.au>

On Mon, 2014-06-02 at 11:20 +1000, Michael Ellerman wrote:
> __attribute__ ((unused))
> 
> WSP is the last user of CONFIG_PPC_A2, so we remove that as well.
> 
> Although CONFIG_PPC_ICSWX still exists, it's no longer selectable for
> any Book3E platform, so we can remove the code in mmu-book3e.h that
> depended on it.
> 
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> ---
>  arch/powerpc/Kconfig.debug             |    5 -
>  arch/powerpc/configs/chroma_defconfig  |  307 ---------
>  arch/powerpc/include/asm/mmu-book3e.h  |    4 -
>  arch/powerpc/include/asm/reg_a2.h      |    9 -
>  arch/powerpc/include/asm/wsp.h         |   14 -
>  arch/powerpc/kernel/Makefile           |    1 -
>  arch/powerpc/kernel/cpu_setup_a2.S     |  120 ----
>  arch/powerpc/kernel/cputable.c         |   38 --
>  arch/powerpc/kernel/exceptions-64e.S   |   16 -
>  arch/powerpc/kernel/udbg.c             |    2 -
>  arch/powerpc/kernel/udbg_16550.c       |   11 -
>  arch/powerpc/platforms/Kconfig         |    1 -
>  arch/powerpc/platforms/Kconfig.cputype |    6 +-
>  arch/powerpc/platforms/Makefile        |    1 -
>  arch/powerpc/platforms/wsp/Kconfig     |   30 -
>  arch/powerpc/platforms/wsp/Makefile    |   10 -
>  arch/powerpc/platforms/wsp/chroma.c    |   56 --
>  arch/powerpc/platforms/wsp/h8.c        |  135 ----
>  arch/powerpc/platforms/wsp/ics.c       |  762 ---------------------
>  arch/powerpc/platforms/wsp/ics.h       |   25 -
>  arch/powerpc/platforms/wsp/msi.c       |  102 ---
>  arch/powerpc/platforms/wsp/msi.h       |   19 -
>  arch/powerpc/platforms/wsp/opb_pic.c   |  321 ---------
>  arch/powerpc/platforms/wsp/psr2.c      |   67 --
>  arch/powerpc/platforms/wsp/scom_smp.c  |  434 ------------

This (trivially) conflicts with commit 2751b628c97e ("powerpc: Fix SMP
issues with ppc64le ABIv2") in next-20140530.

>  arch/powerpc/platforms/wsp/scom_wsp.c  |   82 ---
>  arch/powerpc/platforms/wsp/setup.c     |   36 -
>  arch/powerpc/platforms/wsp/smp.c       |   88 ---
>  arch/powerpc/platforms/wsp/wsp.c       |  117 ----
>  arch/powerpc/platforms/wsp/wsp.h       |   29 -
>  arch/powerpc/platforms/wsp/wsp_pci.c   | 1134 --------------------------------
>  arch/powerpc/platforms/wsp/wsp_pci.h   |  268 --------
>  32 files changed, 1 insertion(+), 4249 deletions(-)
>  delete mode 100644 arch/powerpc/configs/chroma_defconfig
>  delete mode 100644 arch/powerpc/include/asm/wsp.h
>  delete mode 100644 arch/powerpc/kernel/cpu_setup_a2.S
>  delete mode 100644 arch/powerpc/platforms/wsp/Kconfig
>  delete mode 100644 arch/powerpc/platforms/wsp/Makefile
>  delete mode 100644 arch/powerpc/platforms/wsp/chroma.c
>  delete mode 100644 arch/powerpc/platforms/wsp/h8.c
>  delete mode 100644 arch/powerpc/platforms/wsp/ics.c
>  delete mode 100644 arch/powerpc/platforms/wsp/ics.h
>  delete mode 100644 arch/powerpc/platforms/wsp/msi.c
>  delete mode 100644 arch/powerpc/platforms/wsp/msi.h
>  delete mode 100644 arch/powerpc/platforms/wsp/opb_pic.c
>  delete mode 100644 arch/powerpc/platforms/wsp/psr2.c
>  delete mode 100644 arch/powerpc/platforms/wsp/scom_smp.c
>  delete mode 100644 arch/powerpc/platforms/wsp/scom_wsp.c
>  delete mode 100644 arch/powerpc/platforms/wsp/setup.c
>  delete mode 100644 arch/powerpc/platforms/wsp/smp.c
>  delete mode 100644 arch/powerpc/platforms/wsp/wsp.c
>  delete mode 100644 arch/powerpc/platforms/wsp/wsp.h
>  delete mode 100644 arch/powerpc/platforms/wsp/wsp_pci.c
>  delete mode 100644 arch/powerpc/platforms/wsp/wsp_pci.h

For what it's worth, according to my scripts this doesn't introduce
Kconfig related regressions (eg, you've removed all references to the
Kconfig symbols that were removed). And, of course, that puzzling check
for CONFIG_WSP_DD1_WORKAROUND_DD1_TCE_BUGS is now gone.

Thanks,


Paul Bolle

^ permalink raw reply

* Re: [PATCH] powerpc, xmon: Enable hardware instruction breakpoint support on POWER8
From: Anshuman Khandual @ 2014-06-02  8:48 UTC (permalink / raw)
  To: Michael Neuling; +Cc: linuxppc-dev
In-Reply-To: <1401603491.13479.11.camel@ale.ozlabs.ibm.com>

On 06/01/2014 11:48 AM, Michael Neuling wrote:
> On Fri, 2014-05-30 at 17:40 +0530, Anshuman Khandual wrote:
>> This patch enables support for hardware instruction breakpoints on POWER8 with
>> the help of a new register called CIABR (Completed Instruction Address Breakpoint
>> Register). With this patch, single hardware instruction breakpoint can be added
>> and cleared during any active xmon debug session. This hardware based instruction
>> breakpoint mechanism works correctly along with the existing TRAP based instruction
>> breakpoints available on xmon. Example usage as follows.
> 
> Have you actually tried this on a guest?
> 

Yeah on a guest which runs on PVM.

> Please also compile with a range of configs.  It doesn't compile with
> ppc64e_defconfig.

Yeah. Need to change the way we get the "plapr_set_ciabr" function from plpar_wrappers.h
header file. Will add this hunk of code in "xmon.h" header and remove the CONFIG_PPC64 ifdef
code from the function write_ciabr.

+#ifdef CONFIG_PPC_BOOK3S_64
+#include <asm/plpar_wrappers.h>
+#else
+static inline long plapr_set_ciabr(unsigned long ciabr) {return 0;};
+#endif

> 
> In file included from /scratch/mikey/src/linux-ozlabs/arch/powerpc/xmon/xmon.c:51:0:
> /scratch/mikey/src/linux-ozlabs/arch/powerpc/include/asm/plpar_wrappers.h: In function 'get_cede_latency_hint':
> /scratch/mikey/src/linux-ozlabs/arch/powerpc/include/asm/plpar_wrappers.h:26:9: error: 'struct paca_struct' has no member named 'lppaca_ptr'
> /scratch/mikey/src/linux-ozlabs/arch/powerpc/include/asm/plpar_wrappers.h: In function 'set_cede_latency_hint':
> /scratch/mikey/src/linux-ozlabs/arch/powerpc/include/asm/plpar_wrappers.h:31:2: error: 'struct paca_struct' has no member named 'lppaca_ptr'
> /scratch/mikey/src/linux-ozlabs/arch/powerpc/include/asm/plpar_wrappers.h: In function 'plpar_page_set_loaned':
> /scratch/mikey/src/linux-ozlabs/arch/powerpc/include/asm/plpar_wrappers.h:98:2: error: implicit declaration of function 'cmo_get_page_size' [-Werror=implicit-function-declaration]
> cc1: all warnings being treated as errors
> 
>> -				    (bp->enabled & BP_IABR)? "inst": "trap");
>> +					(bp->enabled & (BP_IABR | BP_CIABR))?
>> +				       				"inst": "trap");
> 
> Git complains about whitespace issues here.  Spaces before tabs.

Will take care of this next version.

^ permalink raw reply

* Re: [PATCH 1/3] powerpc: Split __SYSFS_SPRSETUP macro
From: Madhavan Srinivasan @ 2014-06-02  9:09 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <c0db1b210405db5ff579a2d7432dde2c73bd47bb.1400652868.git.sam.bobroff@au1.ibm.com>

On Wednesday 21 May 2014 12:02 PM, Sam Bobroff wrote:
> Split the __SYSFS_SPRSETUP macro into two parts so that registers requiring
> custom read and write functions can use common code for their show and store
> functions.
> 
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
> ---
>  arch/powerpc/kernel/sysfs.c |   19 +++++++++++++------
>  1 file changed, 13 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
> index d90d4b7..e2a1d6f 100644
> --- a/arch/powerpc/kernel/sysfs.c
> +++ b/arch/powerpc/kernel/sysfs.c
> @@ -404,7 +404,7 @@ void ppc_enable_pmcs(void)
>  }
>  EXPORT_SYMBOL(ppc_enable_pmcs);
>  
> -#define __SYSFS_SPRSETUP(NAME, ADDRESS, EXTRA) \
> +#define __SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, EXTRA) \
>  static void read_##NAME(void *val) \
>  { \
>  	*(unsigned long *)val = mfspr(ADDRESS);	\
> @@ -413,7 +413,9 @@ static void write_##NAME(void *val) \
>  { \
>  	EXTRA; \
>  	mtspr(ADDRESS, *(unsigned long *)val);	\
> -} \
> +}
> +
> +#define __SYSFS_SPRSETUP_SHOW_STORE(NAME) \
>  static ssize_t show_##NAME(struct device *dev, \
>  			struct device_attribute *attr, \
>  			char *buf) \
> @@ -436,10 +438,15 @@ static ssize_t __used \
>  	return count; \
>  }
>  
> -#define SYSFS_PMCSETUP(NAME, ADDRESS)	\
> -	__SYSFS_SPRSETUP(NAME, ADDRESS, ppc_enable_pmcs())
> -#define SYSFS_SPRSETUP(NAME, ADDRESS)	\
> -	__SYSFS_SPRSETUP(NAME, ADDRESS, )
> +#define SYSFS_PMCSETUP(NAME, ADDRESS) \
> +	__SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ppc_enable_pmcs()) \
> +	__SYSFS_SPRSETUP_SHOW_STORE(NAME)
> +#define SYSFS_SPRSETUP(NAME, ADDRESS) \
> +	__SYSFS_SPRSETUP_READ_WRITE(NAME, ADDRESS, ) \
> +	__SYSFS_SPRSETUP_SHOW_STORE(NAME)
> +
> +#define SYSFS_SPRSETUP_SHOW_STORE(NAME) \
> +	__SYSFS_SPRSETUP_SHOW_STORE(NAME)
>  
>  /* Let's define all possible registers, we'll only hook up the ones
>   * that are implemented on the current processor
> 

Acked-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>

^ permalink raw reply

* Re: [PATCH 2/3] powerpc: fix regression of per-CPU DSCR setting
From: Madhavan Srinivasan @ 2014-06-02  9:27 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <ebb9e3af49b234c98cbfa6b34ba04dfa70c7d7f3.1400652868.git.sam.bobroff@au1.ibm.com>

On Wednesday 21 May 2014 12:02 PM, Sam Bobroff wrote:
> Since commit "efcac65 powerpc: Per process DSCR + some fixes (try#4)"
> it is no longer possible to set the DSCR on a per-CPU basis.
> 
> The old behaviour was to minipulate the DSCR SPR directly but this is no
> longer sufficient: the value is quickly overwritten by context switching.
> 
> This patch stores the per-CPU DSCR value in a kernel variable rather than
> directly in the SPR and it is used whenever a process has not set the DSCR
> itself. The sysfs interface (/sys/devices/system/cpu/cpuN/dscr) is unchanged.
> 
> Writes to the old global default (/sys/devices/system/cpu/dscr_default)
> now set all of the per-CPU values and reads return the last written value.
> 
> The new per-CPU default is added to the paca_struct and is used everywhere
> outside of sysfs.c instead of the old global default.
> 
> Signed-off-by: Sam Bobroff <sam.bobroff@au1.ibm.com>
> ---
>  arch/powerpc/include/asm/paca.h         |    3 +++
>  arch/powerpc/kernel/asm-offsets.c       |    1 +
>  arch/powerpc/kernel/entry_64.S          |    9 +--------
>  arch/powerpc/kernel/sysfs.c             |   32 ++++++++++++++++++-------------
>  arch/powerpc/kernel/tm.S                |   16 ++++------------
>  arch/powerpc/kvm/book3s_hv_rmhandlers.S |    3 +--
>  6 files changed, 29 insertions(+), 35 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
> index 8e956a0..bb0bd25 100644
> --- a/arch/powerpc/include/asm/paca.h
> +++ b/arch/powerpc/include/asm/paca.h
> @@ -92,7 +92,10 @@ struct paca_struct {
>  	struct slb_shadow *slb_shadow_ptr;
>  	struct dtl_entry *dispatch_log;
>  	struct dtl_entry *dispatch_log_end;
> +#endif /* CONFIG_PPC_STD_MMU_64 */
> +	u64 dscr_default;		/* per-CPU default DSCR */
>  
> +#ifdef CONFIG_PPC_STD_MMU_64
>  	/*
>  	 * Now, starting in cacheline 2, the exception save areas
>  	 */
> diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
> index dba8140..cba2697 100644
> --- a/arch/powerpc/kernel/asm-offsets.c
> +++ b/arch/powerpc/kernel/asm-offsets.c
> @@ -247,6 +247,7 @@ int main(void)
>  #endif
>  	DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
>  	DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
> +	DEFINE(PACA_DSCR, offsetof(struct paca_struct, dscr_default));
>  	DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime));
>  	DEFINE(PACA_STARTTIME_USER, offsetof(struct paca_struct, starttime_user));
>  	DEFINE(PACA_USER_TIME, offsetof(struct paca_struct, user_time));
> diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
> index 9fde8a1..911d453 100644
> --- a/arch/powerpc/kernel/entry_64.S
> +++ b/arch/powerpc/kernel/entry_64.S
> @@ -387,12 +387,6 @@ _GLOBAL(ret_from_kernel_thread)
>  	li	r3,0
>  	b	syscall_exit
>  
> -	.section	".toc","aw"
> -DSCR_DEFAULT:
> -	.tc dscr_default[TC],dscr_default
> -
> -	.section	".text"
> -
>  /*
>   * This routine switches between two different tasks.  The process
>   * state of one is saved on its kernel stack.  Then the state
> @@ -577,11 +571,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
>  #ifdef CONFIG_PPC64
>  BEGIN_FTR_SECTION
>  	lwz	r6,THREAD_DSCR_INHERIT(r4)
> -	ld	r7,DSCR_DEFAULT@toc(2)
>  	ld	r0,THREAD_DSCR(r4)
>  	cmpwi	r6,0
>  	bne	1f
> -	ld	r0,0(r7)
> +	ld	r0,PACA_DSCR(r13)
>  1:
>  BEGIN_FTR_SECTION_NESTED(70)
>  	mfspr	r8, SPRN_FSCR
> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
> index e2a1d6f..67fd2fd 100644
> --- a/arch/powerpc/kernel/sysfs.c
> +++ b/arch/powerpc/kernel/sysfs.c
> @@ -484,7 +484,6 @@ SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
>  SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
>  SYSFS_SPRSETUP(purr, SPRN_PURR);
>  SYSFS_SPRSETUP(spurr, SPRN_SPURR);
> -SYSFS_SPRSETUP(dscr, SPRN_DSCR);
>  SYSFS_SPRSETUP(pir, SPRN_PIR);
>  
>  /*
> @@ -494,12 +493,27 @@ SYSFS_SPRSETUP(pir, SPRN_PIR);
>  */
>  static DEVICE_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
>  static DEVICE_ATTR(spurr, 0400, show_spurr, NULL);
> -static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
>  static DEVICE_ATTR(purr, 0400, show_purr, store_purr);
>  static DEVICE_ATTR(pir, 0400, show_pir, NULL);
>  
> -unsigned long dscr_default = 0;
> -EXPORT_SYMBOL(dscr_default);
> +static unsigned long dscr_default;
> +
> +static void read_dscr(void *val)
> +{
> +	*(unsigned long *)val = get_paca()->dscr_default;
> +}
> +
> +static void write_dscr(void *val)
> +{
> +	get_paca()->dscr_default = *(unsigned long *)val;
> +	if (!current->thread.dscr_inherit) {
> +		current->thread.dscr = *(unsigned long *)val;
> +		mtspr(SPRN_DSCR, *(unsigned long *)val);
> +	}
> +}
> +
> +SYSFS_SPRSETUP_SHOW_STORE(dscr);
> +static DEVICE_ATTR(dscr, 0600, show_dscr, store_dscr);
>  
>  static void add_write_permission_dev_attr(struct device_attribute *attr)
>  {
> @@ -512,14 +526,6 @@ static ssize_t show_dscr_default(struct device *dev,
>  	return sprintf(buf, "%lx\n", dscr_default);
>  }
>  
> -static void update_dscr(void *dummy)
> -{
> -	if (!current->thread.dscr_inherit) {
> -		current->thread.dscr = dscr_default;
> -		mtspr(SPRN_DSCR, dscr_default);
> -	}
> -}
> -
>  static ssize_t __used store_dscr_default(struct device *dev,
>  		struct device_attribute *attr, const char *buf,
>  		size_t count)
> @@ -532,7 +538,7 @@ static ssize_t __used store_dscr_default(struct device *dev,
>  		return -EINVAL;
>  	dscr_default = val;
>  
> -	on_each_cpu(update_dscr, NULL, 1);
> +	on_each_cpu(write_dscr, &val, 1);
>  
>  	return count;
>  }

Acked-by: Madhavan Srinivasan <maddy@linux.vnet.ibm.com>

> diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
> index ee061c3..2a324f4 100644
> --- a/arch/powerpc/kernel/tm.S
> +++ b/arch/powerpc/kernel/tm.S
> @@ -78,12 +78,6 @@ _GLOBAL(tm_abort)
>  	TABORT(R3)
>  	blr
>  
> -	.section	".toc","aw"
> -DSCR_DEFAULT:
> -	.tc dscr_default[TC],dscr_default
> -
> -	.section	".text"
> -
>  /* void tm_reclaim(struct thread_struct *thread,
>   *                 unsigned long orig_msr,
>   *		   uint8_t cause)
> @@ -298,9 +292,8 @@ dont_backup_fp:
>  	mtlr	r0
>  	ld	r2, STK_GOT(r1)
>  
> -	/* Load system default DSCR */
> -	ld	r4, DSCR_DEFAULT@toc(r2)
> -	ld	r0, 0(r4)
> +	/* Load CPU's default DSCR */
> +	ld	r0, PACA_DSCR(r13)
>  	mtspr	SPRN_DSCR, r0
>  
>  	blr
> @@ -479,9 +472,8 @@ restore_gprs:
>  	mtlr	r0
>  	ld	r2, STK_GOT(r1)
>  
> -	/* Load system default DSCR */
> -	ld	r4, DSCR_DEFAULT@toc(r2)
> -	ld	r0, 0(r4)
> +	/* Load CPU's default DSCR */
> +	ld	r0, PACA_DSCR(r13)
>  	mtspr	SPRN_DSCR, r0
>  
>  	blr
> diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> index 9f0ad71..12f4ce5 100644
> --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
> @@ -286,8 +286,7 @@ kvm_start_guest:
>  	beq	kvm_no_guest
>  
>  	/* Set HSTATE_DSCR(r13) to something sensible */
> -	LOAD_REG_ADDR(r6, dscr_default)
> -	ld	r6, 0(r6)
> +	ld	r6, PACA_DSCR(r13)
>  	std	r6, HSTATE_DSCR(r13)
>  
>  	bl	kvmppc_hv_entry
> 

^ permalink raw reply

* Re: [PATCH v2] powerpc/booke64: wrap tlb lock and search in htw miss with FTR_SMT
From: Tudor Laurentiu @ 2014-06-02 12:48 UTC (permalink / raw)
  To: Scott Wood; +Cc: Laurentiu Tudor, linuxppc-dev
In-Reply-To: <1401489946-12935-1-git-send-email-scottwood@freescale.com>

On 05/31/2014 01:45 AM, Scott Wood wrote:
> From: Laurentiu Tudor <Laurentiu.Tudor@freescale.com>
>
> Virtualized environments may expose a e6500 dual-threaded core
> as two single-threaded e6500 cores. Take advantage of this
> and get rid of the tlb lock and the trap-causing tlbsx in
> the htw miss handler by guarding with CPU_FTR_SMT, as it's
> already being done in the bolted tlb1 miss handler.
>
> As seen in the results below, measurements done with lmbench
> random memory access latency test running under Freescale's
> Embedded Hypervisor, there is a ~34% improvement.
>
> Memory latencies in nanoseconds - smaller is better
>      (WARNING - may not be correct, check graphs)
> ----------------------------------------------------
> Host       Mhz   L1 $   L2 $    Main mem    Rand mem
> ---------  ---   ----   ----    --------    --------
> smt       1665 1.8020   13.2    83.0         1149.7
> nosmt     1665 1.8020   13.2    83.0          758.1
>
> Signed-off-by: Laurentiu Tudor <Laurentiu.Tudor@freescale.com>
> Cc: Scott Wood <scottwood@freescale.com>
> [scottwood@freescale.com: commit message tweak]
> Signed-off-by: Scott Wood <scottwood@freescale.com>
> ---
> v2:
>   - s/expose/may expose/ in commit message
>   - rebased onto my patch queue to resolve conflict

Thanks!

>   - resent since the original didn't make it to the list archives
>     or patchwork.

The only thing i can think of is that maybe i've misspelled the mailing 
list address ...

---
Best Regards, Laurentiu

^ permalink raw reply

* Re: [V6 00/11] perf: New conditional branch filter
From: Stephane Eranian @ 2014-06-02 12:59 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Michael Neuling, ak@linux.intel.com, Peter Zijlstra, LKML,
	Michael Ellerman, Linux PPC dev, Arnaldo Carvalho de Melo,
	Sukadev Bhattiprolu, Ingo Molnar
In-Reply-To: <53859873.9070603@linux.vnet.ibm.com>

On Wed, May 28, 2014 at 10:04 AM, Anshuman Khandual
<khandual@linux.vnet.ibm.com> wrote:
> On 05/27/2014 05:39 PM, Stephane Eranian wrote:
>> I have been looking at those patches and ran some tests.
>> And I found a few issues so far.
>>
>> I am running:
>> $ perf record -j any_ret -e cycles:u test_program
>> $ perf report -D
>>
>> Most entries are okay and match the filter, however some do not make sense:
>>
>> 3642586996762 0x15d0 [0x108]: PERF_RECORD_SAMPLE(IP, 2): 17921/17921:
>> 0x10001170 period: 613678 addr: 0
>> .... branch stack: nr:9
>> .....  0: 00000000100011cc -> 0000000010000e38
>> .....  1: 0000000010001150 -> 00000000100011bc
>> .....  2: 0000000010001208 -> 0000000010000e38
>> .....  3: 0000000010001160 -> 00000000100011f8
>> .....  4: 00000000100011cc -> 0000000010000e38
>> .....  5: 0000000010001150 -> 00000000100011bc
>> .....  6: 0000000010001208 -> 0000000010000e38
>> .....  7: 0000000010001160 -> 00000000100011f8
>> .....  8: 0000000000000000 -> 0000000010001160
>> ^^^^^^
>> Entry 8 does not make sense, unless 0x0 is a valid return branch
>> instruction address.
>> If an address is invalid, the whole entry needs to be eliminated. It
>> is okay to have
>> less than the max number of entries supported by HW.
>
> Hey Stephane,
>
> Okay. The same behaviour is also reflected in the test results what I have
> shared in the patchset. Here is that section.
>
> (3) perf record -j any_ret -e branch-misses:u ./cprog
>
> # Overhead  Command  Source Shared Object          Source Symbol  Target Shared Object          Target Symbol
> # ........  .......  ....................  .....................  ....................  .....................
> #
>     15.61%    cprog  [unknown]             [.] 00000000           cprog                 [.] sw_3_1
>      6.28%    cprog  cprog                 [.] symbol2            cprog                 [.] hw_1_2
>      6.28%    cprog  cprog                 [.] ctr_addr           cprog                 [.] sw_4_1
>      6.26%    cprog  cprog                 [.] success_3_1_3      cprog                 [.] sw_3_1
>      6.24%    cprog  cprog                 [.] symbol1            cprog                 [.] hw_1_1
>      6.24%    cprog  cprog                 [.] sw_4_2             cprog                 [.] callme
>      6.21%    cprog  [unknown]             [.] 00000000           cprog                 [.] callme
>      6.19%    cprog  cprog                 [.] lr_addr            cprog                 [.] sw_4_2
>      3.16%    cprog  cprog                 [.] hw_1_2             cprog                 [.] callme
>      3.15%    cprog  cprog                 [.] success_3_1_1      cprog                 [.] sw_3_1
>      3.15%    cprog  cprog                 [.] sw_4_1             cprog                 [.] callme
>      3.14%    cprog  cprog                 [.] callme             cprog                 [.] main
>      3.13%    cprog  cprog                 [.] hw_1_1             cprog                 [.] callme
>
> So a lot of samples above have 0x0 as the "from" address. This originates from the code
> section here inside the function "power_pmu_bhrb_read", where we hit two back to back

Could you explain the back-to-back case a bit more here?
Back-to-back returns to me means something like:

int foo()
{
  ...
   return bar();
}

int bar()
{
  return 0;
}

Not counting the leaf optimization here, bar return to foo which
immediately returns: 2 back-2-back returns.
Is that the case you're talking about here?

> target addresses. So we zero out the from address for the first target address and re-read
> the second address over again. So thats how we get zero as the from address. This is how the
> HW capture the samples. I was reluctant to drop these samples but I agree that these kind of
> samples can be dropped if we need to.
>
I think we need to make it as simple as possible for tools, i.e.,
avoid having to decode the
disassembly to figure out what happened. Here address 0 is not exploitable.

> if (val & BHRB_TARGET) {
>         /* Shouldn't have two targets in a
>            row.. Reset index and try again */
>         r_index--;
>         addr = 0;
> }

^ permalink raw reply

* Re: Re: P1022 audio driver help!
From: eshe168 @ 2014-06-02 14:05 UTC (permalink / raw)
  To: timur; +Cc: linuxppc-dev, zhphsearch
In-Reply-To: <5388A851.2010508@tabi.org>

[-- Attachment #1: Type: text/plain, Size: 1650 bytes --]







Hi Timur
thanks for your repons.
I have another question. Did you test full duplex in P1022 RDK board?Our design is same with P1022 RDK.
B.R.杨小帅
 From: Timur TabiDate: 2014-05-30 23:48To: eshe168CC: linuxppc-dev; zhphsearchSubject: Re: P1022 audio driver help!On 05/30/2014 01:03 AM, eshe168 wrote:
> @timur
> hi,
> Audio card (wm8776) cannot work in full duplex, CPU is FSL P1022.
> The PCB design about audio card reference FSL P1022 development board,
> and palying or recording is OK separately.
> My question is whether P1022 audio driver cannot support full duplex?
 
I was never able to get the P1022ds audio to work in full duplex.  After 
trying for a few weeks, I just gave up.
 
If you look inside fsl_ssi.c (the main driver) you'll see this comment I 
wrote:
 
/*
  * FIXME: The documentation says that SxCCR[WL] should not be
  * modified while the SSI is enabled.  The only time this can
  * happen is if we're trying to do simultaneous playback and
  * capture in asynchronous mode.  Unfortunately, I have been enable
  * to get that to work at all on the P1022DS.  Therefore, we don't
  * bother to disable/enable the SSI when setting SxCCR[WL], because
  * the SSI will stop anyway.  Maybe one day, this will get fixed.
  */
 
(it should say "I have been unable" instead of "I have been enable")
 
Full duplex works fine on the MPC8610, which has the same audio 
controller as the P1022, so I know the controller is physically capable 
of it.  I just don't know why it doesn't work on the P1022DS.  I also 
don't know if it's a problem with the P1022DS board or with the P1022 
SOC itself.
 


[-- Attachment #2: Type: text/html, Size: 3276 bytes --]

^ permalink raw reply

* [PATCH 1/4 v3] KVM: PPC: e500mc: Revert "add load inst fixup"
From: Mihai Caraman @ 2014-06-02 15:50 UTC (permalink / raw)
  To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1401724216-26486-1-git-send-email-mihai.caraman@freescale.com>

The commit 1d628af7 "add load inst fixup" made an attempt to handle
failures generated by reading the guest current instruction. The fixup
code that was added works by chance hiding the real issue.

Load external pid (lwepx) instruction, used by KVM to read guest
instructions, is executed in a substituted guest translation context
(EPLC[EGS] = 1). In consequence lwepx's TLB error and data storage
interrupts need to be handled by KVM, even though these interrupts
are generated from host context (MSR[GS] = 0) where lwepx is executed.

Currently, KVM hooks only interrupts generated from guest context
(MSR[GS] = 1), doing minimal checks on the fast path to avoid host
performance degradation. As a result, the host kernel handles lwepx
faults searching the faulting guest data address (loaded in DEAR) in
its own Logical Partition ID (LPID) 0 context. In case a host translation
is found the execution returns to the lwepx instruction instead of the
fixup, the host ending up in an infinite loop.

Revert the commit "add load inst fixup". lwepx issue will be addressed
in a subsequent patch without needing fixup code.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v3:
 - no change

v2:
 - reworked patch description


 arch/powerpc/kvm/bookehv_interrupts.S | 26 +-------------------------
 1 file changed, 1 insertion(+), 25 deletions(-)

diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index a1712b8..6ff4480 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -29,7 +29,6 @@
 #include <asm/asm-compat.h>
 #include <asm/asm-offsets.h>
 #include <asm/bitsperlong.h>
-#include <asm/thread_info.h>
 
 #ifdef CONFIG_64BIT
 #include <asm/exception-64e.h>
@@ -164,32 +163,9 @@
 	PPC_STL	r30, VCPU_GPR(R30)(r4)
 	PPC_STL	r31, VCPU_GPR(R31)(r4)
 	mtspr	SPRN_EPLC, r8
-
-	/* disable preemption, so we are sure we hit the fixup handler */
-	CURRENT_THREAD_INFO(r8, r1)
-	li	r7, 1
-	stw	r7, TI_PREEMPT(r8)
-
 	isync
-
-	/*
-	 * In case the read goes wrong, we catch it and write an invalid value
-	 * in LAST_INST instead.
-	 */
-1:	lwepx	r9, 0, r5
-2:
-.section .fixup, "ax"
-3:	li	r9, KVM_INST_FETCH_FAILED
-	b	2b
-.previous
-.section __ex_table,"a"
-	PPC_LONG_ALIGN
-	PPC_LONG 1b,3b
-.previous
-
+	lwepx   r9, 0, r5
 	mtspr	SPRN_EPLC, r3
-	li	r7, 0
-	stw	r7, TI_PREEMPT(r8)
 	stw	r9, VCPU_LAST_INST(r4)
 	.endif
 
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH 0/4 v3] KVM: PPC: Read guest instruction from kvmppc_get_last_inst()
From: Mihai Caraman @ 2014-06-02 15:50 UTC (permalink / raw)
  To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm

Read guest last instruction from kvmppc_get_last_inst() allowing the function
to fail in order to emulate again. On bookehv architecture search for
the physical address and kmap it, instead of using Load External PID (lwepx)
instruction. This fixes an infinite loop caused by lwepx's data TLB miss
exception handled in the host and the TODO for execute-but-not-read entries
and TLB eviction.

Mihai Caraman (4):
  KVM: PPC: e500mc: Revert "add load inst fixup"
  KVM: PPC: Book3e: Add TLBSEL/TSIZE defines for MAS0/1
  KVM: PPC: Alow kvmppc_get_last_inst() to fail
  KVM: PPC: Bookehv: Get vcpu's last instruction for emulation

 arch/powerpc/include/asm/kvm_book3s.h    |  28 ++------
 arch/powerpc/include/asm/kvm_booke.h     |   7 +-
 arch/powerpc/include/asm/kvm_ppc.h       |  16 +++++
 arch/powerpc/include/asm/mmu-book3e.h    |   7 +-
 arch/powerpc/kvm/book3s_64_mmu_hv.c      |  16 ++---
 arch/powerpc/kvm/book3s_paired_singles.c |  38 ++++++----
 arch/powerpc/kvm/book3s_pr.c             | 116 +++++++++++++++++--------------
 arch/powerpc/kvm/booke.c                 |  35 ++++++++++
 arch/powerpc/kvm/bookehv_interrupts.S    |  55 ++-------------
 arch/powerpc/kvm/e500_mmu_host.c         |  98 ++++++++++++++++++++++++++
 arch/powerpc/kvm/emulate.c               |  18 +++--
 arch/powerpc/kvm/powerpc.c               |  10 ++-
 12 files changed, 279 insertions(+), 165 deletions(-)

-- 
1.7.11.7

^ permalink raw reply

* [PATCH 2/4] KVM: PPC: Book3e: Add TLBSEL/TSIZE defines for MAS0/1
From: Mihai Caraman @ 2014-06-02 15:50 UTC (permalink / raw)
  To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1401724216-26486-1-git-send-email-mihai.caraman@freescale.com>

Add mising defines MAS0_GET_TLBSEL() and MAS1_GET_TSIZE() for Book3E.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v3:
 - no change

v2:
 - no change

 arch/powerpc/include/asm/mmu-book3e.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/mmu-book3e.h b/arch/powerpc/include/asm/mmu-book3e.h
index 901dac6..60a949a 100644
--- a/arch/powerpc/include/asm/mmu-book3e.h
+++ b/arch/powerpc/include/asm/mmu-book3e.h
@@ -40,7 +40,11 @@
 
 /* MAS registers bit definitions */
 
-#define MAS0_TLBSEL(x)		(((x) << 28) & 0x30000000)
+#define MAS0_TLBSEL_MASK	0x30000000
+#define MAS0_TLBSEL_SHIFT	28
+#define MAS0_TLBSEL(x)		(((x) << MAS0_TLBSEL_SHIFT) & MAS0_TLBSEL_MASK)
+#define MAS0_GET_TLBSEL(mas0)	(((mas0) & MAS0_TLBSEL_MASK) >> \
+			MAS0_TLBSEL_SHIFT)
 #define MAS0_ESEL_MASK		0x0FFF0000
 #define MAS0_ESEL_SHIFT		16
 #define MAS0_ESEL(x)		(((x) << MAS0_ESEL_SHIFT) & MAS0_ESEL_MASK)
@@ -58,6 +62,7 @@
 #define MAS1_TSIZE_MASK		0x00000f80
 #define MAS1_TSIZE_SHIFT	7
 #define MAS1_TSIZE(x)		(((x) << MAS1_TSIZE_SHIFT) & MAS1_TSIZE_MASK)
+#define MAS1_GET_TSIZE(mas1)	(((mas1) & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT)
 
 #define MAS2_EPN		(~0xFFFUL)
 #define MAS2_X0			0x00000040
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH 4/4 v3] KVM: PPC: Bookehv: Get vcpu's last instruction for emulation
From: Mihai Caraman @ 2014-06-02 15:50 UTC (permalink / raw)
  To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1401724216-26486-1-git-send-email-mihai.caraman@freescale.com>

On book3e, KVM uses load external pid (lwepx) dedicated instruction to read
guest last instruction on the exit path. lwepx exceptions (DTLB_MISS, DSI
and LRAT), generated by loading a guest address, needs to be handled by KVM.
These exceptions are generated in a substituted guest translation context
(EPLC[EGS] = 1) from host context (MSR[GS] = 0).

Currently, KVM hooks only interrupts generated from guest context (MSR[GS] = 1),
doing minimal checks on the fast path to avoid host performance degradation.
lwepx exceptions originate from host state (MSR[GS] = 0) which implies
additional checks in DO_KVM macro (beside the current MSR[GS] = 1) by looking
at the Exception Syndrome Register (ESR[EPID]) and the External PID Load Context
Register (EPLC[EGS]). Doing this on each Data TLB miss exception is obvious
too intrusive for the host.

Read guest last instruction from kvmppc_load_last_inst() by searching for the
physical address and kmap it. This address the TODO for TLB eviction and
execute-but-not-read entries, and allow us to get rid of lwepx until we are
able to handle failures.

A simple stress benchmark shows a 1% sys performance degradation compared with
previous approach (lwepx without failure handling):

time for i in `seq 1 10000`; do /bin/echo > /dev/null; done

real	0m 8.85s
user	0m 4.34s
sys	0m 4.48s

vs

real	0m 8.84s
user	0m 4.36s
sys	0m 4.44s

An alternative solution, to handle lwepx exceptions in KVM, is to temporary
highjack the interrupt vector from host. Some cores share host IVOR registers
between hardware threads, which is the case of FSL e6500, which impose additional
synchronization logic for this solution to work. This optimized solution can
be developed later on top of this patch.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v3:
 - reworked patch description
 - use unaltered kmap addr for kunmap
 - get last instruction before beeing preempted

v2:
 - reworked patch description
 - used pr_* functions
 - addressed cosmetic feedback

 arch/powerpc/kvm/booke.c              | 32 ++++++++++++
 arch/powerpc/kvm/bookehv_interrupts.S | 37 ++++----------
 arch/powerpc/kvm/e500_mmu_host.c      | 93 +++++++++++++++++++++++++++++++++++
 3 files changed, 134 insertions(+), 28 deletions(-)

diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 34a42b9..4ef52a8 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -880,6 +880,8 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	int r = RESUME_HOST;
 	int s;
 	int idx;
+	u32 last_inst = KVM_INST_FETCH_FAILED;
+	enum emulation_result emulated = EMULATE_DONE;
 
 	/* update before a new last_exit_type is rewritten */
 	kvmppc_update_timing_stats(vcpu);
@@ -887,6 +889,15 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	/* restart interrupts if they were meant for the host */
 	kvmppc_restart_interrupt(vcpu, exit_nr);
 
+	/*
+	 * get last instruction before beeing preempted
+	 * TODO: for e6500 check also BOOKE_INTERRUPT_LRAT_ERROR & ESR_DATA
+	 */
+	if (exit_nr == BOOKE_INTERRUPT_DATA_STORAGE ||
+	    exit_nr == BOOKE_INTERRUPT_DTLB_MISS ||
+	    exit_nr == BOOKE_INTERRUPT_HV_PRIV)
+		emulated = kvmppc_get_last_inst(vcpu, false, &last_inst);
+
 	local_irq_enable();
 
 	trace_kvm_exit(exit_nr, vcpu);
@@ -895,6 +906,26 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	run->exit_reason = KVM_EXIT_UNKNOWN;
 	run->ready_for_interrupt_injection = 1;
 
+	switch (emulated) {
+	case EMULATE_AGAIN:
+		r = RESUME_GUEST;
+		goto out;
+
+	case EMULATE_FAIL:
+		pr_debug("%s: emulation at %lx failed (%08x)\n",
+		       __func__, vcpu->arch.pc, last_inst);
+		/* For debugging, encode the failing instruction and
+		 * report it to userspace. */
+		run->hw.hardware_exit_reason = ~0ULL << 32;
+		run->hw.hardware_exit_reason |= last_inst;
+		kvmppc_core_queue_program(vcpu, ESR_PIL);
+		r = RESUME_HOST;
+		goto out;
+
+	default:
+		break;
+	}
+
 	switch (exit_nr) {
 	case BOOKE_INTERRUPT_MACHINE_CHECK:
 		printk("MACHINE CHECK: %lx\n", mfspr(SPRN_MCSR));
@@ -1184,6 +1215,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 		BUG();
 	}
 
+out:
 	/*
 	 * To avoid clobbering exit_reason, only check for signals if we
 	 * aren't already exiting to userspace for some other reason.
diff --git a/arch/powerpc/kvm/bookehv_interrupts.S b/arch/powerpc/kvm/bookehv_interrupts.S
index 6ff4480..e000b39 100644
--- a/arch/powerpc/kvm/bookehv_interrupts.S
+++ b/arch/powerpc/kvm/bookehv_interrupts.S
@@ -121,38 +121,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)
@@ -162,10 +138,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 f692c12..0528fe5 100644
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -606,10 +606,103 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
 	}
 }
 
+#ifdef CONFIG_KVM_BOOKE_HV
 int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, bool prev, u32 *instr)
 {
+	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;
+
+	WARN_ON_ONCE(prev);
+
+	/* 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);
+	asm volatile("tlbsx 0, %[geaddr]\n" : :
+		     [geaddr] "r" (geaddr));
+	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) | mas3;
+	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))) {
+		pr_debug("Instuction emulation from a guest page\n"
+				"withot execute permission\n");
+		return EMULATE_FAIL;
+	}
+
+	/*
+	 * 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) {
+		pr_debug("Instuction emulation from cache-inhibited\n"
+				"guest pages is not supported\n");
+		return EMULATE_FAIL;
+	}
+
+	/* Get page size */
+	psize_shift = MAS1_GET_TSIZE(mas1) + 10;
+
+	/* Map a page and get guest's instruction */
+	addr = (mas7_mas3 & (~0ULL << psize_shift)) |
+	       (geaddr & ((1ULL << psize_shift) - 1ULL));
+	pfn = addr >> PAGE_SHIFT;
+
+	/* Guard us against emulation from devices area */
+	if (unlikely(!page_is_ram(pfn))) {
+		pr_debug("Instruction emulation from non-RAM host\n"
+				"pages is not supported\n");
+		return EMULATE_FAIL;
+	}
+
+	if (unlikely(!pfn_valid(pfn))) {
+		pr_debug("Invalid frame number\n");
+		return EMULATE_FAIL;
+	}
+
+	page = pfn_to_page(pfn);
+	eaddr = (unsigned long)kmap_atomic(page);
+	*instr = *(u32 *)(eaddr | (addr & ~PAGE_MASK));
+	kunmap_atomic((u32 *)eaddr);
+
+	return EMULATE_DONE;
+}
+#else
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, u32 *instr)
+{
 	return EMULATE_FAIL;
 }
+#endif
 
 /************* MMU Notifiers *************/
 
-- 
1.7.11.7

^ permalink raw reply related

* [PATCH 3/4 v3] KVM: PPC: Alow kvmppc_get_last_inst() to fail
From: Mihai Caraman @ 2014-06-02 15:50 UTC (permalink / raw)
  To: kvm-ppc; +Cc: Mihai Caraman, linuxppc-dev, kvm
In-Reply-To: <1401724216-26486-1-git-send-email-mihai.caraman@freescale.com>

On book3e, guest last instruction is read on the exit path using load
external pid (lwepx) dedicated instruction. This load operation may fail
due to TLB eviction and execute-but-not-read entries.

This patch lay down the path for an alternative solution to read the guest
last instruction, by allowing kvmppc_get_lat_inst() function to fail.
Architecture specific implmentations of kvmppc_load_last_inst() may read
last guest instruction and instruct the emulation layer to re-execute the
guest in case of failure.

Make kvmppc_get_last_inst() definition common between architectures.

Signed-off-by: Mihai Caraman <mihai.caraman@freescale.com>
---
v3:
 - these changes compile on book3s, please validate the functionality and
   do the necessary adaptations!
 - rework patch description
 - add common definition for kvmppc_get_last_inst()
 - check return values in book3s code

v2:
 - integrated kvmppc_get_last_inst() in book3s code and checked build
 - addressed cosmetic feedback

 arch/powerpc/include/asm/kvm_book3s.h    |  28 ++------
 arch/powerpc/include/asm/kvm_booke.h     |   7 +-
 arch/powerpc/include/asm/kvm_ppc.h       |  16 +++++
 arch/powerpc/kvm/book3s_64_mmu_hv.c      |  16 ++---
 arch/powerpc/kvm/book3s_paired_singles.c |  38 ++++++----
 arch/powerpc/kvm/book3s_pr.c             | 116 +++++++++++++++++--------------
 arch/powerpc/kvm/booke.c                 |   3 +
 arch/powerpc/kvm/e500_mmu_host.c         |   5 ++
 arch/powerpc/kvm/emulate.c               |  18 +++--
 arch/powerpc/kvm/powerpc.c               |  10 ++-
 10 files changed, 142 insertions(+), 115 deletions(-)

diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h
index f52f656..3409572 100644
--- a/arch/powerpc/include/asm/kvm_book3s.h
+++ b/arch/powerpc/include/asm/kvm_book3s.h
@@ -274,30 +274,14 @@ static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
 	return (kvmppc_get_msr(vcpu) & MSR_LE) != (MSR_KERNEL & MSR_LE);
 }
 
-static inline u32 kvmppc_get_last_inst_internal(struct kvm_vcpu *vcpu, ulong pc)
+static inline int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, bool prev,
+					 u32 *inst)
 {
-	/* Load the instruction manually if it failed to do so in the
-	 * exit path */
-	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
-		kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);
+	ulong pc = kvmppc_get_pc(vcpu);
 
-	return kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) :
-		vcpu->arch.last_inst;
-}
-
-static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
-{
-	return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu));
-}
-
-/*
- * Like kvmppc_get_last_inst(), but for fetching a sc instruction.
- * Because the sc instruction sets SRR0 to point to the following
- * instruction, we have to fetch from pc - 4.
- */
-static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu)
-{
-	return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu) - 4);
+	if (prev)
+		pc -= 4;
+	return kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);
 }
 
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
diff --git a/arch/powerpc/include/asm/kvm_booke.h b/arch/powerpc/include/asm/kvm_booke.h
index c7aed61..1e28371 100644
--- a/arch/powerpc/include/asm/kvm_booke.h
+++ b/arch/powerpc/include/asm/kvm_booke.h
@@ -33,6 +33,8 @@
 #define KVMPPC_INST_EHPRIV_DEBUG	(KVMPPC_INST_EHPRIV | \
 					 (EHPRIV_OC_DEBUG << EHPRIV_OC_SHIFT))
 
+extern int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, bool prev, u32 *inst);
+
 static inline void kvmppc_set_gpr(struct kvm_vcpu *vcpu, int num, ulong val)
 {
 	vcpu->arch.gpr[num] = val;
@@ -69,11 +71,6 @@ static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
 	return false;
 }
 
-static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
-{
-	return vcpu->arch.last_inst;
-}
-
 static inline void kvmppc_set_ctr(struct kvm_vcpu *vcpu, ulong val)
 {
 	vcpu->arch.ctr = val;
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 4a7cc45..619be2f 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -234,6 +234,22 @@ struct kvmppc_ops {
 extern struct kvmppc_ops *kvmppc_hv_ops;
 extern struct kvmppc_ops *kvmppc_pr_ops;
 
+static inline int kvmppc_get_last_inst(struct kvm_vcpu *vcpu, bool prev,
+					u32 *inst)
+{
+	int ret = EMULATE_DONE;
+
+	/* Load the instruction manually if it failed to do so in the
+	 * exit path */
+	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
+		ret = kvmppc_load_last_inst(vcpu, prev, &vcpu->arch.last_inst);
+
+	*inst = kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) :
+		vcpu->arch.last_inst;
+
+	return ret;
+}
+
 static inline bool is_kvmppc_hv_enabled(struct kvm *kvm)
 {
 	return kvm->arch.kvm_ops == kvmppc_hv_ops;
diff --git a/arch/powerpc/kvm/book3s_64_mmu_hv.c b/arch/powerpc/kvm/book3s_64_mmu_hv.c
index 8056107..2ffb3dd 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_hv.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_hv.c
@@ -530,21 +530,13 @@ static int instruction_is_store(unsigned int instr)
 static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
 				  unsigned long gpa, gva_t ea, int is_store)
 {
-	int ret;
 	u32 last_inst;
-	unsigned long srr0 = kvmppc_get_pc(vcpu);
 
-	/* We try to load the last instruction.  We don't let
-	 * emulate_instruction do it as it doesn't check what
-	 * kvmppc_ld returns.
+	/*
 	 * If we fail, we just return to the guest and try executing it again.
 	 */
-	if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED) {
-		ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
-		if (ret != EMULATE_DONE || last_inst == KVM_INST_FETCH_FAILED)
-			return RESUME_GUEST;
-		vcpu->arch.last_inst = last_inst;
-	}
+	if (kvmppc_get_last_inst(vcpu, false, &last_inst) != EMULATE_DONE)
+		return RESUME_GUEST;
 
 	/*
 	 * WARNING: We do not know for sure whether the instruction we just
@@ -558,7 +550,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	 * we just return and retry the instruction.
 	 */
 
-	if (instruction_is_store(kvmppc_get_last_inst(vcpu)) != !!is_store)
+	if (instruction_is_store(last_inst) != !!is_store)
 		return RESUME_GUEST;
 
 	/*
diff --git a/arch/powerpc/kvm/book3s_paired_singles.c b/arch/powerpc/kvm/book3s_paired_singles.c
index 6c8011f..6362ad4 100644
--- a/arch/powerpc/kvm/book3s_paired_singles.c
+++ b/arch/powerpc/kvm/book3s_paired_singles.c
@@ -639,26 +639,36 @@ 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, ax_ra, ax_rb, ax_rc;
+	short full_d;
+	u64 *fpr_d, *fpr_a, *fpr_b, *fpr_c;
 
-	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_FPR(vcpu, ax_rd);
-	u64 *fpr_a = &VCPU_FPR(vcpu, ax_ra);
-	u64 *fpr_b = &VCPU_FPR(vcpu, ax_rb);
-	u64 *fpr_c = &VCPU_FPR(vcpu, ax_rc);
-
-	bool rcomp = (inst & 1) ? true : false;
-	u32 cr = kvmppc_get_cr(vcpu);
+	bool rcomp;
+	u32 cr;
 #ifdef DEBUG
 	int i;
 #endif
 
+	emulated = kvmppc_get_last_inst(vcpu, false, &inst);
+	if (emulated != EMULATE_DONE)
+		return emulated;
+
+	ax_rd = inst_get_field(inst, 6, 10);
+	ax_ra = inst_get_field(inst, 11, 15);
+	ax_rb = inst_get_field(inst, 16, 20);
+	ax_rc = inst_get_field(inst, 21, 25);
+	full_d = inst_get_field(inst, 16, 31);
+
+	fpr_d = &VCPU_FPR(vcpu, ax_rd);
+	fpr_a = &VCPU_FPR(vcpu, ax_ra);
+	fpr_b = &VCPU_FPR(vcpu, ax_rb);
+	fpr_c = &VCPU_FPR(vcpu, ax_rc);
+
+	rcomp = (inst & 1) ? true : false;
+	cr = kvmppc_get_cr(vcpu);
+
 	if (!kvmppc_inst_is_paired_single(vcpu, inst))
 		return EMULATE_FAIL;
 
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 23367a7..48b633c 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -637,42 +637,6 @@ static void kvmppc_giveup_fac(struct kvm_vcpu *vcpu, ulong fac)
 #endif
 }
 
-static int kvmppc_read_inst(struct kvm_vcpu *vcpu)
-{
-	ulong srr0 = kvmppc_get_pc(vcpu);
-	u32 last_inst = kvmppc_get_last_inst(vcpu);
-	int ret;
-
-	ret = kvmppc_ld(vcpu, &srr0, sizeof(u32), &last_inst, false);
-	if (ret == -ENOENT) {
-		ulong msr = kvmppc_get_msr(vcpu);
-
-		msr = kvmppc_set_field(msr, 33, 33, 1);
-		msr = kvmppc_set_field(msr, 34, 36, 0);
-		msr = kvmppc_set_field(msr, 42, 47, 0);
-		kvmppc_set_msr_fast(vcpu, msr);
-		kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_INST_STORAGE);
-		return EMULATE_AGAIN;
-	}
-
-	return EMULATE_DONE;
-}
-
-static int kvmppc_check_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr)
-{
-
-	/* Need to do paired single emulation? */
-	if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE))
-		return EMULATE_DONE;
-
-	/* Read out the instruction */
-	if (kvmppc_read_inst(vcpu) == EMULATE_DONE)
-		/* Need to emulate */
-		return EMULATE_FAIL;
-
-	return EMULATE_AGAIN;
-}
-
 /* Handle external providers (FPU, Altivec, VSX) */
 static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
 			     ulong msr)
@@ -977,15 +941,24 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
 	{
 		enum emulation_result er;
 		ulong flags;
+		u32 last_inst;
+		int emul;
 
 program_interrupt:
 		flags = vcpu->arch.shadow_srr1 & 0x1f0000ull;
 
+		emul = kvmppc_get_last_inst(vcpu, false, &last_inst);
+		if (emul != EMULATE_DONE) {
+			r = RESUME_GUEST;
+			break;
+		}
+
 		if (kvmppc_get_msr(vcpu) & MSR_PR) {
 #ifdef EXIT_DEBUG
-			printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
+			pr_info("Userspace triggered 0x700 exception at\n"
+			    "0x%lx (0x%x)\n", kvmppc_get_pc(vcpu), last_inst);
 #endif
-			if ((kvmppc_get_last_inst(vcpu) & 0xff0007ff) !=
+			if ((last_inst & 0xff0007ff) !=
 			    (INS_DCBZ & 0xfffffff7)) {
 				kvmppc_core_queue_program(vcpu, flags);
 				r = RESUME_GUEST;
@@ -1004,7 +977,7 @@ program_interrupt:
 			break;
 		case EMULATE_FAIL:
 			printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n",
-			       __func__, kvmppc_get_pc(vcpu), kvmppc_get_last_inst(vcpu));
+			       __func__, kvmppc_get_pc(vcpu), last_inst);
 			kvmppc_core_queue_program(vcpu, flags);
 			r = RESUME_GUEST;
 			break;
@@ -1021,8 +994,25 @@ program_interrupt:
 		break;
 	}
 	case BOOK3S_INTERRUPT_SYSCALL:
+	{
+		u32 last_sc;
+		int emul;
+
+		/* Get last sc for papr */
+		if (vcpu->arch.papr_enabled) {
+			/*
+			 * The sc instuction sets SRR0 to point to the next inst
+			 */
+			emul = kvmppc_get_last_inst(vcpu, true, &last_sc);
+			if (emul != EMULATE_DONE) {
+				kvmppc_set_pc(vcpu, kvmppc_get_pc(vcpu) - 4);
+				r = RESUME_GUEST;
+				break;
+			}
+		}
+
 		if (vcpu->arch.papr_enabled &&
-		    (kvmppc_get_last_sc(vcpu) == 0x44000022) &&
+		    (last_sc == 0x44000022) &&
 		    !(kvmppc_get_msr(vcpu) & MSR_PR)) {
 			/* SC 1 papr hypercalls */
 			ulong cmd = kvmppc_get_gpr(vcpu, 3);
@@ -1067,36 +1057,53 @@ program_interrupt:
 			r = RESUME_GUEST;
 		}
 		break;
+	}
 	case BOOK3S_INTERRUPT_FP_UNAVAIL:
 	case BOOK3S_INTERRUPT_ALTIVEC:
 	case BOOK3S_INTERRUPT_VSX:
 	{
 		int ext_msr = 0;
+		int emul;
+		u32 last_inst;
 
-		switch (exit_nr) {
-		case BOOK3S_INTERRUPT_FP_UNAVAIL: ext_msr = MSR_FP;  break;
-		case BOOK3S_INTERRUPT_ALTIVEC:    ext_msr = MSR_VEC; break;
-		case BOOK3S_INTERRUPT_VSX:        ext_msr = MSR_VSX; break;
-		}
+		if (!(vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)) {
+			/* Do paired single emulation */
+
+			switch (exit_nr) {
+			case BOOK3S_INTERRUPT_FP_UNAVAIL:
+				ext_msr = MSR_FP;
+				break;
+
+			case BOOK3S_INTERRUPT_ALTIVEC:
+				ext_msr = MSR_VEC;
+				break;
+
+			case BOOK3S_INTERRUPT_VSX:
+				ext_msr = MSR_VSX;
+				break;
+			}
 
-		switch (kvmppc_check_ext(vcpu, exit_nr)) {
-		case EMULATE_DONE:
-			/* everything ok - let's enable the ext */
 			r = kvmppc_handle_ext(vcpu, exit_nr, ext_msr);
 			break;
-		case EMULATE_FAIL:
+		}
+
+		emul = kvmppc_get_last_inst(vcpu, false, &last_inst);
+		if (emul == EMULATE_DONE) {
 			/* we need to emulate this instruction */
 			goto program_interrupt;
 			break;
-		default:
-			/* nothing to worry about - go again */
-			break;
+		} else {
+			r = RESUME_GUEST;
 		}
+
 		break;
 	}
 	case BOOK3S_INTERRUPT_ALIGNMENT:
-		if (kvmppc_read_inst(vcpu) == EMULATE_DONE) {
-			u32 last_inst = kvmppc_get_last_inst(vcpu);
+	{
+		u32 last_inst;
+		int emul = kvmppc_get_last_inst(vcpu, false, &last_inst);
+
+		if (emul == EMULATE_DONE) {
 			u32 dsisr;
 			u64 dar;
 
@@ -1110,6 +1117,7 @@ program_interrupt:
 		}
 		r = RESUME_GUEST;
 		break;
+	}
 #ifdef CONFIG_PPC_BOOK3S_64
 	case BOOK3S_INTERRUPT_FAC_UNAVAIL:
 		kvmppc_handle_fac(vcpu, vcpu->arch.shadow_fscr >> 56);
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index ab62109..34a42b9 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -752,6 +752,9 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		 * they were actually modified by emulation. */
 		return RESUME_GUEST_NV;
 
+	case EMULATE_AGAIN:
+		return RESUME_GUEST;
+
 	case EMULATE_DO_DCR:
 		run->exit_reason = KVM_EXIT_DCR;
 		return RESUME_HOST;
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c
index dd2cc03..f692c12 100644
--- a/arch/powerpc/kvm/e500_mmu_host.c
+++ b/arch/powerpc/kvm/e500_mmu_host.c
@@ -606,6 +606,11 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
 	}
 }
 
+int kvmppc_load_last_inst(struct kvm_vcpu *vcpu, bool prev, u32 *instr)
+{
+	return EMULATE_FAIL;
+}
+
 /************* 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 da86d9b..c5c64b6 100644
--- a/arch/powerpc/kvm/emulate.c
+++ b/arch/powerpc/kvm/emulate.c
@@ -224,19 +224,25 @@ 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, false, &inst);
+	if (emulated != EMULATE_DONE)
+		return emulated;
+
 	pr_debug("Emulating opcode %d / %d\n", get_op(inst), get_xop(inst));
 
+	ra = get_ra(inst);
+	rs = get_rs(inst);
+	rt = get_rt(inst);
+	sprn = get_sprn(inst);
+
 	switch (get_op(inst)) {
 	case OP_TRAP:
 #ifdef CONFIG_PPC_BOOK3S
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index bab20f4..1dba84b 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -261,6 +261,9 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		 * actually modified. */
 		r = RESUME_GUEST_NV;
 		break;
+	case EMULATE_AGAIN:
+		r = RESUME_GUEST;
+		break;
 	case EMULATE_DO_MMIO:
 		run->exit_reason = KVM_EXIT_MMIO;
 		/* We must reload nonvolatiles because "update" load/store
@@ -270,11 +273,14 @@ int kvmppc_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu)
 		r = RESUME_HOST_NV;
 		break;
 	case EMULATE_FAIL:
+	{
+		u32 last_inst;
+		kvmppc_get_last_inst(vcpu, false, &last_inst);
 		/* XXX Deliver Program interrupt to guest. */
-		printk(KERN_EMERG "%s: emulation failed (%08x)\n", __func__,
-		       kvmppc_get_last_inst(vcpu));
+		pr_emerg("%s: emulation failed (%08x)\n", __func__, last_inst);
 		r = RESUME_HOST;
 		break;
+	}
 	default:
 		WARN_ON(1);
 		r = RESUME_GUEST;
-- 
1.7.11.7

^ permalink raw reply related

* Re: P1022 audio driver help!
From: Timur Tabi @ 2014-06-02 15:52 UTC (permalink / raw)
  To: eshe168@gmail.com; +Cc: linuxppc-dev, zhphsearch
In-Reply-To: <201406022205351271662@gmail.com>

eshe168@gmail.com wrote:
>
> I have another question. Did you test full duplex in P1022 RDK board?
> Our design is same with P1022 RDK.

No, I don't think I did.  The P1022RDK was not a board that my team was 
responsible for, so I only did minimal work on it.  I added support for 
it in the upstream kernel.  It was so long ago that I don't really 
remember much about it.  I still have the board, though.

^ permalink raw reply

* Re: [V6 00/11] perf: New conditional branch filter
From: Anshuman Khandual @ 2014-06-02 16:04 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: Michael Neuling, ak@linux.intel.com, Peter Zijlstra, LKML,
	Michael Ellerman, Linux PPC dev, Arnaldo Carvalho de Melo,
	Sukadev Bhattiprolu, Ingo Molnar
In-Reply-To: <CABPqkBSmuMth4KmdLw7Nigf5uQREQJ+xL=42xV9c8FjR2VPO5g@mail.gmail.com>

On 06/02/2014 06:29 PM, Stephane Eranian wrote:
> On Wed, May 28, 2014 at 10:04 AM, Anshuman Khandual
> <khandual@linux.vnet.ibm.com> wrote:
>> On 05/27/2014 05:39 PM, Stephane Eranian wrote:
>>> I have been looking at those patches and ran some tests.
>>> And I found a few issues so far.
>>>
>>> I am running:
>>> $ perf record -j any_ret -e cycles:u test_program
>>> $ perf report -D
>>>
>>> Most entries are okay and match the filter, however some do not make sense:
>>>
>>> 3642586996762 0x15d0 [0x108]: PERF_RECORD_SAMPLE(IP, 2): 17921/17921:
>>> 0x10001170 period: 613678 addr: 0
>>> .... branch stack: nr:9
>>> .....  0: 00000000100011cc -> 0000000010000e38
>>> .....  1: 0000000010001150 -> 00000000100011bc
>>> .....  2: 0000000010001208 -> 0000000010000e38
>>> .....  3: 0000000010001160 -> 00000000100011f8
>>> .....  4: 00000000100011cc -> 0000000010000e38
>>> .....  5: 0000000010001150 -> 00000000100011bc
>>> .....  6: 0000000010001208 -> 0000000010000e38
>>> .....  7: 0000000010001160 -> 00000000100011f8
>>> .....  8: 0000000000000000 -> 0000000010001160
>>> ^^^^^^
>>> Entry 8 does not make sense, unless 0x0 is a valid return branch
>>> instruction address.
>>> If an address is invalid, the whole entry needs to be eliminated. It
>>> is okay to have
>>> less than the max number of entries supported by HW.
>>
>> Hey Stephane,
>>
>> Okay. The same behaviour is also reflected in the test results what I have
>> shared in the patchset. Here is that section.
>>
>> (3) perf record -j any_ret -e branch-misses:u ./cprog
>>
>> # Overhead  Command  Source Shared Object          Source Symbol  Target Shared Object          Target Symbol
>> # ........  .......  ....................  .....................  ....................  .....................
>> #
>>     15.61%    cprog  [unknown]             [.] 00000000           cprog                 [.] sw_3_1
>>      6.28%    cprog  cprog                 [.] symbol2            cprog                 [.] hw_1_2
>>      6.28%    cprog  cprog                 [.] ctr_addr           cprog                 [.] sw_4_1
>>      6.26%    cprog  cprog                 [.] success_3_1_3      cprog                 [.] sw_3_1
>>      6.24%    cprog  cprog                 [.] symbol1            cprog                 [.] hw_1_1
>>      6.24%    cprog  cprog                 [.] sw_4_2             cprog                 [.] callme
>>      6.21%    cprog  [unknown]             [.] 00000000           cprog                 [.] callme
>>      6.19%    cprog  cprog                 [.] lr_addr            cprog                 [.] sw_4_2
>>      3.16%    cprog  cprog                 [.] hw_1_2             cprog                 [.] callme
>>      3.15%    cprog  cprog                 [.] success_3_1_1      cprog                 [.] sw_3_1
>>      3.15%    cprog  cprog                 [.] sw_4_1             cprog                 [.] callme
>>      3.14%    cprog  cprog                 [.] callme             cprog                 [.] main
>>      3.13%    cprog  cprog                 [.] hw_1_1             cprog                 [.] callme
>>
>> So a lot of samples above have 0x0 as the "from" address. This originates from the code
>> section here inside the function "power_pmu_bhrb_read", where we hit two back to back
> 
> Could you explain the back-to-back case a bit more here?
> Back-to-back returns to me means something like:
> 
> int foo()
> {
>   ...
>    return bar();
> }
> 
> int bar()
> {
>   return 0;
> }
> 
> Not counting the leaf optimization here, bar return to foo which
> immediately returns: 2 back-2-back returns.
> Is that the case you're talking about here?
> 

No. Filtering of return branches has been implemented in SW only. So PMU as such does not capture
return only branches. It captures all the branches what it encounters. During the capture process
PMU might *record* two back to back "target addresses" (without capturing the from address for the
first one) for which we are unable to figure out the "from address". This leaves us with one branch
record where we have the target address not from address and so we make it zero. With the current
logic all branch records with "from address" as zero get filtered through and become the part of the
final set. I was not too sure how to deal with these cases.

>> target addresses. So we zero out the from address for the first target address and re-read
>> the second address over again. So thats how we get zero as the from address. This is how the
>> HW capture the samples. I was reluctant to drop these samples but I agree that these kind of
>> samples can be dropped if we need to.
>>
> I think we need to make it as simple as possible for tools, i.e.,
> avoid having to decode the
> disassembly to figure out what happened. Here address 0 is not exploitable.

Thats right. Dropping the branch record where we have only the target address not the from address
might just solve this problem.

^ permalink raw reply

* Re: [V6 00/11] perf: New conditional branch filter
From: Stephane Eranian @ 2014-06-02 16:25 UTC (permalink / raw)
  To: Anshuman Khandual
  Cc: Michael Neuling, ak@linux.intel.com, Peter Zijlstra, LKML,
	Michael Ellerman, Linux PPC dev, Arnaldo Carvalho de Melo,
	Sukadev Bhattiprolu, Ingo Molnar
In-Reply-To: <538CA096.20709@linux.vnet.ibm.com>

On Mon, Jun 2, 2014 at 6:04 PM, Anshuman Khandual
<khandual@linux.vnet.ibm.com> wrote:
> On 06/02/2014 06:29 PM, Stephane Eranian wrote:
>> On Wed, May 28, 2014 at 10:04 AM, Anshuman Khandual
>> <khandual@linux.vnet.ibm.com> wrote:
>>> On 05/27/2014 05:39 PM, Stephane Eranian wrote:
>>>> I have been looking at those patches and ran some tests.
>>>> And I found a few issues so far.
>>>>
>>>> I am running:
>>>> $ perf record -j any_ret -e cycles:u test_program
>>>> $ perf report -D
>>>>
>>>> Most entries are okay and match the filter, however some do not make sense:
>>>>
>>>> 3642586996762 0x15d0 [0x108]: PERF_RECORD_SAMPLE(IP, 2): 17921/17921:
>>>> 0x10001170 period: 613678 addr: 0
>>>> .... branch stack: nr:9
>>>> .....  0: 00000000100011cc -> 0000000010000e38
>>>> .....  1: 0000000010001150 -> 00000000100011bc
>>>> .....  2: 0000000010001208 -> 0000000010000e38
>>>> .....  3: 0000000010001160 -> 00000000100011f8
>>>> .....  4: 00000000100011cc -> 0000000010000e38
>>>> .....  5: 0000000010001150 -> 00000000100011bc
>>>> .....  6: 0000000010001208 -> 0000000010000e38
>>>> .....  7: 0000000010001160 -> 00000000100011f8
>>>> .....  8: 0000000000000000 -> 0000000010001160
>>>> ^^^^^^
>>>> Entry 8 does not make sense, unless 0x0 is a valid return branch
>>>> instruction address.
>>>> If an address is invalid, the whole entry needs to be eliminated. It
>>>> is okay to have
>>>> less than the max number of entries supported by HW.
>>>
>>> Hey Stephane,
>>>
>>> Okay. The same behaviour is also reflected in the test results what I have
>>> shared in the patchset. Here is that section.
>>>
>>> (3) perf record -j any_ret -e branch-misses:u ./cprog
>>>
>>> # Overhead  Command  Source Shared Object          Source Symbol  Target Shared Object          Target Symbol
>>> # ........  .......  ....................  .....................  ....................  .....................
>>> #
>>>     15.61%    cprog  [unknown]             [.] 00000000           cprog                 [.] sw_3_1
>>>      6.28%    cprog  cprog                 [.] symbol2            cprog                 [.] hw_1_2
>>>      6.28%    cprog  cprog                 [.] ctr_addr           cprog                 [.] sw_4_1
>>>      6.26%    cprog  cprog                 [.] success_3_1_3      cprog                 [.] sw_3_1
>>>      6.24%    cprog  cprog                 [.] symbol1            cprog                 [.] hw_1_1
>>>      6.24%    cprog  cprog                 [.] sw_4_2             cprog                 [.] callme
>>>      6.21%    cprog  [unknown]             [.] 00000000           cprog                 [.] callme
>>>      6.19%    cprog  cprog                 [.] lr_addr            cprog                 [.] sw_4_2
>>>      3.16%    cprog  cprog                 [.] hw_1_2             cprog                 [.] callme
>>>      3.15%    cprog  cprog                 [.] success_3_1_1      cprog                 [.] sw_3_1
>>>      3.15%    cprog  cprog                 [.] sw_4_1             cprog                 [.] callme
>>>      3.14%    cprog  cprog                 [.] callme             cprog                 [.] main
>>>      3.13%    cprog  cprog                 [.] hw_1_1             cprog                 [.] callme
>>>
>>> So a lot of samples above have 0x0 as the "from" address. This originates from the code
>>> section here inside the function "power_pmu_bhrb_read", where we hit two back to back
>>
>> Could you explain the back-to-back case a bit more here?
>> Back-to-back returns to me means something like:
>>
>> int foo()
>> {
>>   ...
>>    return bar();
>> }
>>
>> int bar()
>> {
>>   return 0;
>> }
>>
>> Not counting the leaf optimization here, bar return to foo which
>> immediately returns: 2 back-2-back returns.
>> Is that the case you're talking about here?
>>
>
> No. Filtering of return branches has been implemented in SW only. So PMU as such does not capture
> return only branches. It captures all the branches what it encounters. During the capture process
> PMU might *record* two back to back "target addresses" (without capturing the from address for the
> first one) for which we are unable to figure out the "from address". This leaves us with one branch
> record where we have the target address not from address and so we make it zero. With the current
> logic all branch records with "from address" as zero get filtered through and become the part of the
> final set. I was not too sure how to deal with these cases.
>
So PPC8 captures all branches, no HW filter. But then in SW you filter
out non return branches.
Given you're description, I have to believe that sometimes the HW does
not even capture the
from address. If so, then in that case, I think it is best to drop the
sample. Because the target
address may be the target of an indirect branch for which there is no
way to find the source.
In other words, the record cannot be exploited.

But why does the HW not capture some from addresses?
I am worried this might create some bias in the samples.

>>> target addresses. So we zero out the from address for the first target address and re-read
>>> the second address over again. So thats how we get zero as the from address. This is how the
>>> HW capture the samples. I was reluctant to drop these samples but I agree that these kind of
>>> samples can be dropped if we need to.
>>>
>> I think we need to make it as simple as possible for tools, i.e.,
>> avoid having to decode the
>> disassembly to figure out what happened. Here address 0 is not exploitable.
>
> Thats right. Dropping the branch record where we have only the target address not the from address
> might just solve this problem.
>

^ permalink raw reply

* Re: [PATCH v2] powerpc/booke64: wrap tlb lock and search in htw miss with FTR_SMT
From: Scott Wood @ 2014-06-02 16:45 UTC (permalink / raw)
  To: Tudor Laurentiu; +Cc: Laurentiu Tudor, linuxppc-dev
In-Reply-To: <538C7297.4040307@freescale.com>

On Mon, 2014-06-02 at 15:48 +0300, Tudor Laurentiu wrote:
> On 05/31/2014 01:45 AM, Scott Wood wrote:
> > From: Laurentiu Tudor <Laurentiu.Tudor@freescale.com>
> >   - resent since the original didn't make it to the list archives
> >     or patchwork.
> 
> The only thing i can think of is that maybe i've misspelled the mailing 
> list address ...

It looks right to me.  Did you get a bounce?

-Scott

^ permalink raw reply

* Re: [PATCH 2/2] powerpc/powernv: Enable POWER8 doorbell IPIs
From: Anton Blanchard @ 2014-06-02 22:06 UTC (permalink / raw)
  To: Michael Neuling; +Cc: Preeti U Murthy, Paul Mackerras, linuxppc-dev
In-Reply-To: <1401692223-28337-2-git-send-email-mikey@neuling.org>

Hi,

> This patch enables POWER8 doorbell IPIs on powernv.
> 
> Since doorbells can only IPI within a core, we test to see when we
> can use doorbells and if not we fall back to XICS.  This also enables
> hypervisor doorbells to wakeup us up from nap/sleep via the LPCR
> PECEDH bit.
> 
> Based on tests by Anton, the best case IPI latency between two
> threads dropped from 894ns to 512ns.
> 
> Signed-off-by: Michael Neuling <mikey@neuling.org>

Thanks Mikey!

Tested-by: Anton Blanchard <anton@samba.org>

Anton

^ permalink raw reply

* Re: [V6 00/11] perf: New conditional branch filter
From: Michael Neuling @ 2014-06-02 22:52 UTC (permalink / raw)
  To: Stephane Eranian
  Cc: ak@linux.intel.com, Peter Zijlstra, LKML, Michael Ellerman,
	Linux PPC dev, Arnaldo Carvalho de Melo, Sukadev Bhattiprolu,
	Ingo Molnar, Anshuman Khandual
In-Reply-To: <CABPqkBSmuMth4KmdLw7Nigf5uQREQJ+xL=42xV9c8FjR2VPO5g@mail.gmail.com>

On Mon, 2014-06-02 at 14:59 +0200, Stephane Eranian wrote:
> On Wed, May 28, 2014 at 10:04 AM, Anshuman Khandual
> <khandual@linux.vnet.ibm.com> wrote:
> > On 05/27/2014 05:39 PM, Stephane Eranian wrote:
> >> I have been looking at those patches and ran some tests.
> >> And I found a few issues so far.
> >>
> >> I am running:
> >> $ perf record -j any_ret -e cycles:u test_program
> >> $ perf report -D
> >>
> >> Most entries are okay and match the filter, however some do not make s=
ense:
> >>
> >> 3642586996762 0x15d0 [0x108]: PERF_RECORD_SAMPLE(IP, 2): 17921/17921:
> >> 0x10001170 period: 613678 addr: 0
> >> .... branch stack: nr:9
> >> .....  0: 00000000100011cc -> 0000000010000e38
> >> .....  1: 0000000010001150 -> 00000000100011bc
> >> .....  2: 0000000010001208 -> 0000000010000e38
> >> .....  3: 0000000010001160 -> 00000000100011f8
> >> .....  4: 00000000100011cc -> 0000000010000e38
> >> .....  5: 0000000010001150 -> 00000000100011bc
> >> .....  6: 0000000010001208 -> 0000000010000e38
> >> .....  7: 0000000010001160 -> 00000000100011f8
> >> .....  8: 0000000000000000 -> 0000000010001160
> >> ^^^^^^
> >> Entry 8 does not make sense, unless 0x0 is a valid return branch
> >> instruction address.
> >> If an address is invalid, the whole entry needs to be eliminated. It
> >> is okay to have
> >> less than the max number of entries supported by HW.
> >
> > Hey Stephane,
> >
> > Okay. The same behaviour is also reflected in the test results what I h=
ave
> > shared in the patchset. Here is that section.
> >
> > (3) perf record -j any_ret -e branch-misses:u ./cprog
> >
> > # Overhead  Command  Source Shared Object          Source Symbol  Targe=
t Shared Object          Target Symbol
> > # ........  .......  ....................  .....................  .....=
...............  .....................
> > #
> >     15.61%    cprog  [unknown]             [.] 00000000           cprog=
                 [.] sw_3_1
> >      6.28%    cprog  cprog                 [.] symbol2            cprog=
                 [.] hw_1_2
> >      6.28%    cprog  cprog                 [.] ctr_addr           cprog=
                 [.] sw_4_1
> >      6.26%    cprog  cprog                 [.] success_3_1_3      cprog=
                 [.] sw_3_1
> >      6.24%    cprog  cprog                 [.] symbol1            cprog=
                 [.] hw_1_1
> >      6.24%    cprog  cprog                 [.] sw_4_2             cprog=
                 [.] callme
> >      6.21%    cprog  [unknown]             [.] 00000000           cprog=
                 [.] callme
> >      6.19%    cprog  cprog                 [.] lr_addr            cprog=
                 [.] sw_4_2
> >      3.16%    cprog  cprog                 [.] hw_1_2             cprog=
                 [.] callme
> >      3.15%    cprog  cprog                 [.] success_3_1_1      cprog=
                 [.] sw_3_1
> >      3.15%    cprog  cprog                 [.] sw_4_1             cprog=
                 [.] callme
> >      3.14%    cprog  cprog                 [.] callme             cprog=
                 [.] main
> >      3.13%    cprog  cprog                 [.] hw_1_1             cprog=
                 [.] callme
> >
> > So a lot of samples above have 0x0 as the "from" address. This originat=
es from the code
> > section here inside the function "power_pmu_bhrb_read", where we hit tw=
o back to back
>=20
> Could you explain the back-to-back case a bit more here?
> Back-to-back returns to me means something like:
>=20
> int foo()
> {
>   ...
>    return bar();
> }
>=20
> int bar()
> {
>   return 0;
> }
>=20
> Not counting the leaf optimization here, bar return to foo which
> immediately returns: 2 back-2-back returns.
> Is that the case you're talking about here?
>=20
> > target addresses. So we zero out the from address for the first target =
address and re-read
> > the second address over again. So thats how we get zero as the from add=
ress. This is how the
> > HW capture the samples. I was reluctant to drop these samples but I agr=
ee that these kind of
> > samples can be dropped if we need to.
> >
> I think we need to make it as simple as possible for tools, i.e.,
> avoid having to decode the
> disassembly to figure out what happened. Here address 0 is not exploitabl=
e.

This was my fault.  I figured if we only had partial information from
the hardware, it was best to at least export that to the tools.  If you
disagree then we can we remove them.  There was a discussion a while
back on this here:
  https://lkml.org/lkml/2013/5/8/543

Because of the way the branch buffer is structured, we can certainly
lose the from address of the oldest branch in the buffer.  I've not seen
the hardware lose the from branches in the middle of the buffer but I
guess it's possible.  We'll have to get back to you on how or why this
would occur (and associated bias) after talking to some hardware folk.

FWIW, there was some discussion on how the POWER8 branch buffer works a
while back here (same thread as before):
  https://lkml.org/lkml/2013/5/8/541

Mikey

^ permalink raw reply

* [RFC PATCH 0/3] CMA: generalize CMA reserved area management code
From: Joonsoo Kim @ 2014-06-03  1:11 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel

Currently, there are two users on CMA functionality, one is the DMA
subsystem and the other is the kvm on powerpc. They have their own code
to manage CMA reserved area even if they looks really similar.
>From my guess, it is caused by some needs on bitmap management. Kvm side
wants to maintain bitmap not for 1 page, but for more size. Eventually it
use bitmap where one bit represents 64 pages.

When I implement CMA related patches, I should change those two places
to apply my change and it seem to be painful to me. I want to change
this situation and reduce future code management overhead through
this patch.

This change could also help developer who want to use CMA in their
new feature development, since they can use CMA easily without
copying & pasting this reserved area management code.

Now, we are in merge window, so this is not for merging. I'd like to
listen opinion from people who related to this stuff before actually
trying to merge this patchset. If all agree with this change, I will
resend it after rc1.

Thanks.

Joonsoo Kim (3):
  CMA: generalize CMA reserved area management functionality
  DMA, CMA: use general CMA reserved area management framework
  PPC, KVM, CMA: use general CMA reserved area management framework

 arch/powerpc/kvm/book3s_hv_builtin.c |   17 +-
 arch/powerpc/kvm/book3s_hv_cma.c     |  240 -------------------------
 arch/powerpc/kvm/book3s_hv_cma.h     |   27 ---
 drivers/base/Kconfig                 |   10 --
 drivers/base/dma-contiguous.c        |  230 ++----------------------
 include/linux/cma.h                  |   28 +++
 include/linux/dma-contiguous.h       |    7 +-
 mm/Kconfig                           |   11 ++
 mm/Makefile                          |    1 +
 mm/cma.c                             |  329 ++++++++++++++++++++++++++++++++++
 10 files changed, 396 insertions(+), 504 deletions(-)
 delete mode 100644 arch/powerpc/kvm/book3s_hv_cma.c
 delete mode 100644 arch/powerpc/kvm/book3s_hv_cma.h
 create mode 100644 include/linux/cma.h
 create mode 100644 mm/cma.c

-- 
1.7.9.5

^ permalink raw reply

* [RFC PATCH 1/3] CMA: generalize CMA reserved area management functionality
From: Joonsoo Kim @ 2014-06-03  1:11 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1401757919-30018-1-git-send-email-iamjoonsoo.kim@lge.com>

Currently, there are two users on CMA functionality, one is the DMA
subsystem and the other is the kvm on powerpc. They have their own code
to manage CMA reserved area even if they looks really similar.
>From my guess, it is caused by some needs on bitmap management. Kvm side
wants to maintain bitmap not for 1 page, but for more size. Eventually it
use bitmap where one bit represents 64 pages.

When I implement CMA related patches, I should change those two places
to apply my change and it seem to be painful to me. I want to change
this situation and reduce future code management overhead through
this patch.

This change could also help developer who want to use CMA in their
new feature development, since they can use CMA easily without
copying & pasting this reserved area management code.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 00e13ce..b3fe1cc 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -283,7 +283,7 @@ config CMA_ALIGNMENT
 
 	  If unsure, leave the default value "8".
 
-config CMA_AREAS
+config DMA_CMA_AREAS
 	int "Maximum count of the CMA device-private areas"
 	default 7
 	help
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 83969f8..48cdac8 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -186,7 +186,7 @@ static int __init cma_activate_area(struct cma *cma)
 	return 0;
 }
 
-static struct cma cma_areas[MAX_CMA_AREAS];
+static struct cma cma_areas[MAX_DMA_CMA_AREAS];
 static unsigned cma_area_count;
 
 static int __init cma_init_reserved_areas(void)
diff --git a/include/linux/cma.h b/include/linux/cma.h
new file mode 100644
index 0000000..60ba06f
--- /dev/null
+++ b/include/linux/cma.h
@@ -0,0 +1,28 @@
+/*
+ * Contiguous Memory Allocator
+ *
+ * Copyright LG Electronics Inc., 2014
+ * Written by:
+ *	Joonsoo Kim <iamjoonsoo.kim@lge.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 of the
+ * License or (at your optional) any later version of the license.
+ *
+ */
+
+#ifndef __CMA_H__
+#define __CMA_H__
+
+struct cma;
+
+extern struct page *cma_alloc(struct cma *cma, unsigned long count,
+				unsigned long align);
+extern bool cma_release(struct cma *cma, struct page *pages,
+				unsigned long count);
+extern int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base,
+				phys_addr_t limit, phys_addr_t alignment,
+				unsigned long bitmap_shift, bool fixed,
+				struct cma **res_cma);
+#endif
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index 772eab5..dfb1dc9 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -63,7 +63,7 @@ struct device;
  * There is always at least global CMA area and a few optional device
  * private areas configured in kernel .config.
  */
-#define MAX_CMA_AREAS	(1 + CONFIG_CMA_AREAS)
+#define MAX_DMA_CMA_AREAS  (1 + CONFIG_DMA_CMA_AREAS)
 
 extern struct cma *dma_contiguous_default_area;
 
@@ -123,7 +123,7 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 
 #else
 
-#define MAX_CMA_AREAS	(0)
+#define MAX_DMA_CMA_AREAS	(0)
 
 static inline struct cma *dev_get_cma_area(struct device *dev)
 {
diff --git a/mm/Kconfig b/mm/Kconfig
index 7511b4a..0877ddc 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -515,6 +515,17 @@ config CMA_DEBUG
 	  processing calls such as dma_alloc_from_contiguous().
 	  This option does not affect warning and error messages.
 
+config CMA_AREAS
+	int "Maximum count of the CMA areas"
+	depends on CMA
+	default 7
+	help
+	  CMA allows to create CMA areas for particular purpose, mainly,
+	  used as device private area. This parameter sets the maximum
+	  number of CMA area in the system.
+
+	  If unsure, leave the default value "7".
+
 config ZBUD
 	tristate
 	default n
diff --git a/mm/Makefile b/mm/Makefile
index 1eaa70b..bc0422b 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -62,3 +62,4 @@ obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
 obj-$(CONFIG_ZBUD)	+= zbud.o
 obj-$(CONFIG_ZSMALLOC)	+= zsmalloc.o
 obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o
+obj-$(CONFIG_CMA)	+= cma.o
diff --git a/mm/cma.c b/mm/cma.c
new file mode 100644
index 0000000..0dae88d
--- /dev/null
+++ b/mm/cma.c
@@ -0,0 +1,329 @@
+/*
+ * Contiguous Memory Allocator
+ *
+ * Copyright (c) 2010-2011 by Samsung Electronics.
+ * Copyright IBM Corporation, 2013
+ * Copyright LG Electronics Inc., 2014
+ * Written by:
+ *	Marek Szyprowski <m.szyprowski@samsung.com>
+ *	Michal Nazarewicz <mina86@mina86.com>
+ *	Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+ *	Joonsoo Kim <iamjoonsoo.kim@lge.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 of the
+ * License or (at your optional) any later version of the license.
+ */
+
+#define pr_fmt(fmt) "cma: " fmt
+
+#ifdef CONFIG_CMA_DEBUG
+#ifndef DEBUG
+#  define DEBUG
+#endif
+#endif
+
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/mutex.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+
+struct cma {
+	unsigned long	base_pfn;
+	unsigned long	count;
+	unsigned long	*bitmap;
+	unsigned long	bitmap_shift;
+	struct mutex	lock;
+};
+
+/*
+ * There is always at least global CMA area and a few optional
+ * areas configured in kernel .config.
+ */
+#define MAX_CMA_AREAS	(1 + CONFIG_CMA_AREAS)
+
+static struct cma cma_areas[MAX_CMA_AREAS];
+static unsigned cma_area_count;
+static DEFINE_MUTEX(cma_mutex);
+
+static unsigned long cma_bitmap_mask(struct cma *cma,
+				unsigned long align_order)
+{
+	return (1 << (align_order >> cma->bitmap_shift)) - 1;
+}
+
+static unsigned long cma_bitmap_max_no(struct cma *cma)
+{
+	return cma->count >> cma->bitmap_shift;
+}
+
+static unsigned long cma_bitmap_pages_to_bits(struct cma *cma,
+						unsigned long pages)
+{
+	return ALIGN(pages, 1 << cma->bitmap_shift) >> cma->bitmap_shift;
+}
+
+static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
+{
+	unsigned long bitmapno, nr_bits;
+
+	bitmapno = (pfn - cma->base_pfn) >> cma->bitmap_shift;
+	nr_bits = cma_bitmap_pages_to_bits(cma, count);
+
+	mutex_lock(&cma->lock);
+	bitmap_clear(cma->bitmap, bitmapno, nr_bits);
+	mutex_unlock(&cma->lock);
+}
+
+static int __init cma_activate_area(struct cma *cma)
+{
+	int max_bitmapno = cma_bitmap_max_no(cma);
+	int bitmap_size = BITS_TO_LONGS(max_bitmapno) * sizeof(long);
+	unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
+	unsigned i = cma->count >> pageblock_order;
+	struct zone *zone;
+
+	pr_debug("%s()\n", __func__);
+	if (!cma->count)
+		return 0;
+
+	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+	if (!cma->bitmap)
+		return -ENOMEM;
+
+	WARN_ON_ONCE(!pfn_valid(pfn));
+	zone = page_zone(pfn_to_page(pfn));
+
+	do {
+		unsigned j;
+
+		base_pfn = pfn;
+		for (j = pageblock_nr_pages; j; --j, pfn++) {
+			WARN_ON_ONCE(!pfn_valid(pfn));
+			/*
+			 * alloc_contig_range requires the pfn range
+			 * specified to be in the same zone. Make this
+			 * simple by forcing the entire CMA resv range
+			 * to be in the same zone.
+			 */
+			if (page_zone(pfn_to_page(pfn)) != zone)
+				goto err;
+		}
+		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
+	} while (--i);
+
+	mutex_init(&cma->lock);
+	return 0;
+
+err:
+	kfree(cma->bitmap);
+	return -EINVAL;
+}
+
+static int __init cma_init_reserved_areas(void)
+{
+	int i;
+
+	for (i = 0; i < cma_area_count; i++) {
+		int ret = cma_activate_area(&cma_areas[i]);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+core_initcall(cma_init_reserved_areas);
+
+/**
+ * cma_declare_contiguous() - reserve custom contiguous area
+ * @size: Size of the reserved area (in bytes),
+ * @base: Base address of the reserved area optional, use 0 for any
+ * @limit: End address of the reserved memory (optional, 0 for any).
+ * @bitmap_shift: Order of pages represented by one bit on bitmap.
+ * @fixed: hint about where to place the reserved area
+ * @res_cma: Pointer to store the created cma region.
+ *
+ * This function reserves memory from early allocator. It should be
+ * called by arch specific code once the early allocator (memblock or bootmem)
+ * has been activated and all other subsystems have already allocated/reserved
+ * memory. This function allows to create custom reserved areas.
+ *
+ * If @fixed is true, reserve contiguous area at exactly @base.  If false,
+ * reserve in range from @base to @limit.
+ */
+int __init cma_declare_contiguous(phys_addr_t size, phys_addr_t base,
+				phys_addr_t limit, phys_addr_t alignment,
+				unsigned long bitmap_shift, bool fixed,
+				struct cma **res_cma)
+{
+	struct cma *cma = &cma_areas[cma_area_count];
+	int ret = 0;
+
+	pr_debug("%s(size %lx, base %08lx, limit %08lx, alignment %08lx)\n",
+			__func__, (unsigned long)size, (unsigned long)base,
+			(unsigned long)limit, (unsigned long)alignment);
+
+	/* Sanity checks */
+	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
+		pr_err("Not enough slots for CMA reserved regions!\n");
+		return -ENOSPC;
+	}
+
+	if (!size)
+		return -EINVAL;
+
+	/*
+	 * Sanitise input arguments.
+	 * CMA area should be at least MAX_ORDER - 1 aligned. Otherwise,
+	 * CMA area could be merged into other MIGRATE_TYPE by buddy mechanism
+	 * and CMA property will be broken.
+	 */
+	alignment >>= PAGE_SHIFT;
+	alignment = PAGE_SIZE << max3(MAX_ORDER - 1, pageblock_order,
+						(int)alignment);
+	base = ALIGN(base, alignment);
+	size = ALIGN(size, alignment);
+	limit &= ~(alignment - 1);
+	/* size should be aligned with bitmap_shift */
+	BUG_ON(!IS_ALIGNED(size >> PAGE_SHIFT, 1 << cma->bitmap_shift));
+
+	/* Reserve memory */
+	if (base && fixed) {
+		if (memblock_is_region_reserved(base, size) ||
+		    memblock_reserve(base, size) < 0) {
+			ret = -EBUSY;
+			goto err;
+		}
+	} else {
+		phys_addr_t addr = memblock_alloc_range(size, alignment, base,
+							limit);
+		if (!addr) {
+			ret = -ENOMEM;
+			goto err;
+		} else {
+			base = addr;
+		}
+	}
+
+	/*
+	 * Each reserved area must be initialised later, when more kernel
+	 * subsystems (like slab allocator) are available.
+	 */
+	cma->base_pfn = PFN_DOWN(base);
+	cma->count = size >> PAGE_SHIFT;
+	cma->bitmap_shift = bitmap_shift;
+	*res_cma = cma;
+	cma_area_count++;
+
+	pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
+		(unsigned long)base);
+
+	return 0;
+
+err:
+	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
+	return ret;
+}
+
+/**
+ * cma_alloc() - allocate pages from contiguous area
+ * @cma:   Contiguous memory region for which the allocation is performed.
+ * @count: Requested number of pages.
+ * @align: Requested alignment of pages (in PAGE_SIZE order).
+ *
+ * This function allocates part of contiguous memory on specific
+ * contiguous memory area.
+ */
+struct page *cma_alloc(struct cma *cma, unsigned long count,
+				       unsigned long align)
+{
+	unsigned long mask, pfn, start = 0;
+	unsigned long max_bitmapno, bitmapno, nr_bits;
+	struct page *page = NULL;
+	int ret;
+
+	if (!cma || !cma->count)
+		return NULL;
+
+	pr_debug("%s(cma %p, count %ld, align %ld)\n", __func__, (void *)cma,
+		 count, align);
+
+	if (!count)
+		return NULL;
+
+	mask = cma_bitmap_mask(cma, align);
+	max_bitmapno = cma_bitmap_max_no(cma);
+	nr_bits = cma_bitmap_pages_to_bits(cma, count);
+
+	for (;;) {
+		mutex_lock(&cma->lock);
+		bitmapno = bitmap_find_next_zero_area(cma->bitmap,
+					max_bitmapno, start, nr_bits, mask);
+		if (bitmapno >= max_bitmapno) {
+			mutex_unlock(&cma->lock);
+			break;
+		}
+		bitmap_set(cma->bitmap, bitmapno, nr_bits);
+		/*
+		 * It's safe to drop the lock here. We've marked this region for
+		 * our exclusive use. If the migration fails we will take the
+		 * lock again and unmark it.
+		 */
+		mutex_unlock(&cma->lock);
+
+		pfn = cma->base_pfn + (bitmapno << cma->bitmap_shift);
+		mutex_lock(&cma_mutex);
+		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
+		mutex_unlock(&cma_mutex);
+		if (ret == 0) {
+			page = pfn_to_page(pfn);
+			break;
+		}
+		clear_cma_bitmap(cma, pfn, count);
+		if (ret != -EBUSY)
+			break;
+
+		pr_debug("%s(): memory range at %p is busy, retrying\n",
+			 __func__, pfn_to_page(pfn));
+		/* try again with a bit different memory target */
+		start = bitmapno + mask + 1;
+	}
+
+	pr_debug("%s(): returned %p\n", __func__, page);
+	return page;
+}
+
+/**
+ * cma_release() - release allocated pages
+ * @cma:   Contiguous memory region for which the allocation is performed.
+ * @pages: Allocated pages.
+ * @count: Number of allocated pages.
+ *
+ * This function releases memory allocated by alloc_cma().
+ * It returns false when provided pages do not belong to contiguous area and
+ * true otherwise.
+ */
+bool cma_release(struct cma *cma, struct page *pages, unsigned long count)
+{
+	unsigned long pfn;
+
+	if (!cma || !pages)
+		return false;
+
+	pr_debug("%s(page %p)\n", __func__, (void *)pages);
+
+	pfn = page_to_pfn(pages);
+	if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
+		return false;
+
+	VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
+
+	free_contig_range(pfn, count);
+	clear_cma_bitmap(cma, pfn, count);
+
+	return true;
+}
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 2/3] DMA, CMA: use general CMA reserved area management framework
From: Joonsoo Kim @ 2014-06-03  1:11 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1401757919-30018-1-git-send-email-iamjoonsoo.kim@lge.com>

Now, we have general CMA reserved area management framework,
so use it for future maintainabilty. There is no functional change.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index b3fe1cc..4eac559 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -283,16 +283,6 @@ config CMA_ALIGNMENT
 
 	  If unsure, leave the default value "8".
 
-config DMA_CMA_AREAS
-	int "Maximum count of the CMA device-private areas"
-	default 7
-	help
-	  CMA allows to create CMA areas for particular devices. This parameter
-	  sets the maximum number of such device private CMA areas in the
-	  system.
-
-	  If unsure, leave the default value "7".
-
 endif
 
 endmenu
diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index 48cdac8..4bce4e1 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -24,23 +24,9 @@
 
 #include <linux/memblock.h>
 #include <linux/err.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <linux/page-isolation.h>
 #include <linux/sizes.h>
-#include <linux/slab.h>
-#include <linux/swap.h>
-#include <linux/mm_types.h>
 #include <linux/dma-contiguous.h>
-
-struct cma {
-	unsigned long	base_pfn;
-	unsigned long	count;
-	unsigned long	*bitmap;
-	struct mutex	lock;
-};
-
-struct cma *dma_contiguous_default_area;
+#include <linux/cma.h>
 
 #ifdef CONFIG_CMA_SIZE_MBYTES
 #define CMA_SIZE_MBYTES CONFIG_CMA_SIZE_MBYTES
@@ -48,6 +34,8 @@ struct cma *dma_contiguous_default_area;
 #define CMA_SIZE_MBYTES 0
 #endif
 
+struct cma *dma_contiguous_default_area;
+
 /*
  * Default global CMA area size can be defined in kernel's .config.
  * This is useful mainly for distro maintainers to create a kernel
@@ -154,55 +142,6 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
 	}
 }
 
-static DEFINE_MUTEX(cma_mutex);
-
-static int __init cma_activate_area(struct cma *cma)
-{
-	int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long);
-	unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
-	unsigned i = cma->count >> pageblock_order;
-	struct zone *zone;
-
-	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-
-	if (!cma->bitmap)
-		return -ENOMEM;
-
-	WARN_ON_ONCE(!pfn_valid(pfn));
-	zone = page_zone(pfn_to_page(pfn));
-
-	do {
-		unsigned j;
-		base_pfn = pfn;
-		for (j = pageblock_nr_pages; j; --j, pfn++) {
-			WARN_ON_ONCE(!pfn_valid(pfn));
-			if (page_zone(pfn_to_page(pfn)) != zone)
-				return -EINVAL;
-		}
-		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
-	} while (--i);
-
-	mutex_init(&cma->lock);
-	return 0;
-}
-
-static struct cma cma_areas[MAX_DMA_CMA_AREAS];
-static unsigned cma_area_count;
-
-static int __init cma_init_reserved_areas(void)
-{
-	int i;
-
-	for (i = 0; i < cma_area_count; i++) {
-		int ret = cma_activate_area(&cma_areas[i]);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-core_initcall(cma_init_reserved_areas);
-
 /**
  * dma_contiguous_reserve_area() - reserve custom contiguous area
  * @size: Size of the reserved area (in bytes),
@@ -224,176 +163,31 @@ int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
 				       phys_addr_t limit, struct cma **res_cma,
 				       bool fixed)
 {
-	struct cma *cma = &cma_areas[cma_area_count];
-	phys_addr_t alignment;
-	int ret = 0;
-
-	pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
-		 (unsigned long)size, (unsigned long)base,
-		 (unsigned long)limit);
-
-	/* Sanity checks */
-	if (cma_area_count == ARRAY_SIZE(cma_areas)) {
-		pr_err("Not enough slots for CMA reserved regions!\n");
-		return -ENOSPC;
-	}
-
-	if (!size)
-		return -EINVAL;
-
-	/* Sanitise input arguments */
-	alignment = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
-	base = ALIGN(base, alignment);
-	size = ALIGN(size, alignment);
-	limit &= ~(alignment - 1);
-
-	/* Reserve memory */
-	if (base && fixed) {
-		if (memblock_is_region_reserved(base, size) ||
-		    memblock_reserve(base, size) < 0) {
-			ret = -EBUSY;
-			goto err;
-		}
-	} else {
-		phys_addr_t addr = memblock_alloc_range(size, alignment, base,
-							limit);
-		if (!addr) {
-			ret = -ENOMEM;
-			goto err;
-		} else {
-			base = addr;
-		}
-	}
-
-	/*
-	 * Each reserved area must be initialised later, when more kernel
-	 * subsystems (like slab allocator) are available.
-	 */
-	cma->base_pfn = PFN_DOWN(base);
-	cma->count = size >> PAGE_SHIFT;
-	*res_cma = cma;
-	cma_area_count++;
+	int ret;
+	struct cma *cma;
 
-	pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
-		(unsigned long)base);
+	ret = cma_declare_contiguous(size, base, limit, 0, 0, fixed, &cma);
+	if (ret)
+		return ret;
 
 	/* Architecture specific contiguous memory fixup. */
 	dma_contiguous_early_fixup(base, size);
-	return 0;
-err:
-	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
-	return ret;
-}
+	*res_cma = cma;
 
-static void clear_cma_bitmap(struct cma *cma, unsigned long pfn, int count)
-{
-	mutex_lock(&cma->lock);
-	bitmap_clear(cma->bitmap, pfn - cma->base_pfn, count);
-	mutex_unlock(&cma->lock);
+	return 0;
 }
 
-/**
- * dma_alloc_from_contiguous() - allocate pages from contiguous area
- * @dev:   Pointer to device for which the allocation is performed.
- * @count: Requested number of pages.
- * @align: Requested alignment of pages (in PAGE_SIZE order).
- *
- * This function allocates memory buffer for specified device. It uses
- * device specific contiguous memory area if available or the default
- * global one. Requires architecture specific dev_get_cma_area() helper
- * function.
- */
 struct page *dma_alloc_from_contiguous(struct device *dev, int count,
 				       unsigned int align)
 {
-	unsigned long mask, pfn, pageno, start = 0;
-	struct cma *cma = dev_get_cma_area(dev);
-	struct page *page = NULL;
-	int ret;
-
-	if (!cma || !cma->count)
-		return NULL;
-
 	if (align > CONFIG_CMA_ALIGNMENT)
 		align = CONFIG_CMA_ALIGNMENT;
 
-	pr_debug("%s(cma %p, count %d, align %d)\n", __func__, (void *)cma,
-		 count, align);
-
-	if (!count)
-		return NULL;
-
-	mask = (1 << align) - 1;
-
-
-	for (;;) {
-		mutex_lock(&cma->lock);
-		pageno = bitmap_find_next_zero_area(cma->bitmap, cma->count,
-						    start, count, mask);
-		if (pageno >= cma->count) {
-			mutex_unlock(&cma->lock);
-			break;
-		}
-		bitmap_set(cma->bitmap, pageno, count);
-		/*
-		 * It's safe to drop the lock here. We've marked this region for
-		 * our exclusive use. If the migration fails we will take the
-		 * lock again and unmark it.
-		 */
-		mutex_unlock(&cma->lock);
-
-		pfn = cma->base_pfn + pageno;
-		mutex_lock(&cma_mutex);
-		ret = alloc_contig_range(pfn, pfn + count, MIGRATE_CMA);
-		mutex_unlock(&cma_mutex);
-		if (ret == 0) {
-			page = pfn_to_page(pfn);
-			break;
-		} else if (ret != -EBUSY) {
-			clear_cma_bitmap(cma, pfn, count);
-			break;
-		}
-		clear_cma_bitmap(cma, pfn, count);
-		pr_debug("%s(): memory range at %p is busy, retrying\n",
-			 __func__, pfn_to_page(pfn));
-		/* try again with a bit different memory target */
-		start = pageno + mask + 1;
-	}
-
-	pr_debug("%s(): returned %p\n", __func__, page);
-	return page;
+	return cma_alloc(dev_get_cma_area(dev), count, align);
 }
 
-/**
- * dma_release_from_contiguous() - release allocated pages
- * @dev:   Pointer to device for which the pages were allocated.
- * @pages: Allocated pages.
- * @count: Number of allocated pages.
- *
- * This function releases memory allocated by dma_alloc_from_contiguous().
- * It returns false when provided pages do not belong to contiguous area and
- * true otherwise.
- */
 bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 				 int count)
 {
-	struct cma *cma = dev_get_cma_area(dev);
-	unsigned long pfn;
-
-	if (!cma || !pages)
-		return false;
-
-	pr_debug("%s(page %p)\n", __func__, (void *)pages);
-
-	pfn = page_to_pfn(pages);
-
-	if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
-		return false;
-
-	VM_BUG_ON(pfn + count > cma->base_pfn + cma->count);
-
-	free_contig_range(pfn, count);
-	clear_cma_bitmap(cma, pfn, count);
-
-	return true;
+	return cma_release(dev_get_cma_area(dev), pages, count);
 }
diff --git a/include/linux/dma-contiguous.h b/include/linux/dma-contiguous.h
index dfb1dc9..ecb85ac 100644
--- a/include/linux/dma-contiguous.h
+++ b/include/linux/dma-contiguous.h
@@ -53,9 +53,10 @@
 
 #ifdef __KERNEL__
 
+#include <linux/device.h>
+
 struct cma;
 struct page;
-struct device;
 
 #ifdef CONFIG_DMA_CMA
 
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 3/3] PPC, KVM, CMA: use general CMA reserved area management framework
From: Joonsoo Kim @ 2014-06-03  1:11 UTC (permalink / raw)
  To: Andrew Morton, Aneesh Kumar K.V, Marek Szyprowski,
	Michal Nazarewicz
  Cc: Russell King - ARM Linux, kvm, linux-mm, Gleb Natapov,
	Greg Kroah-Hartman, Alexander Graf, kvm-ppc, linux-kernel,
	Minchan Kim, Paul Mackerras, Paolo Bonzini, Joonsoo Kim,
	linuxppc-dev, linux-arm-kernel
In-Reply-To: <1401757919-30018-1-git-send-email-iamjoonsoo.kim@lge.com>

Now, we have general CMA reserved area management framework,
so use it for future maintainabilty. There is no functional change.

Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>

diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c
index 8cd0dae..43c3f81 100644
--- a/arch/powerpc/kvm/book3s_hv_builtin.c
+++ b/arch/powerpc/kvm/book3s_hv_builtin.c
@@ -15,12 +15,14 @@
 #include <linux/init.h>
 #include <linux/memblock.h>
 #include <linux/sizes.h>
+#include <linux/cma.h>
 
 #include <asm/cputable.h>
 #include <asm/kvm_ppc.h>
 #include <asm/kvm_book3s.h>
 
-#include "book3s_hv_cma.h"
+#define KVM_CMA_CHUNK_ORDER	18
+
 /*
  * Hash page table alignment on newer cpus(CPU_FTR_ARCH_206)
  * should be power of 2.
@@ -42,6 +44,8 @@ static unsigned long kvm_cma_resv_ratio = 5;
 unsigned long kvm_rma_pages = (1 << 27) >> PAGE_SHIFT;	/* 128MB */
 EXPORT_SYMBOL_GPL(kvm_rma_pages);
 
+static struct cma *kvm_cma;
+
 /* Work out RMLS (real mode limit selector) field value for a given RMA size.
    Assumes POWER7 or PPC970. */
 static inline int lpcr_rmls(unsigned long rma_size)
@@ -96,7 +100,7 @@ struct kvm_rma_info *kvm_alloc_rma()
 	ri = kmalloc(sizeof(struct kvm_rma_info), GFP_KERNEL);
 	if (!ri)
 		return NULL;
-	page = kvm_alloc_cma(kvm_rma_pages, kvm_rma_pages);
+	page = cma_alloc(kvm_cma, kvm_rma_pages, get_order(kvm_rma_pages));
 	if (!page)
 		goto err_out;
 	atomic_set(&ri->use_count, 1);
@@ -111,7 +115,7 @@ EXPORT_SYMBOL_GPL(kvm_alloc_rma);
 void kvm_release_rma(struct kvm_rma_info *ri)
 {
 	if (atomic_dec_and_test(&ri->use_count)) {
-		kvm_release_cma(pfn_to_page(ri->base_pfn), kvm_rma_pages);
+		cma_release(kvm_cma, pfn_to_page(ri->base_pfn), kvm_rma_pages);
 		kfree(ri);
 	}
 }
@@ -133,13 +137,13 @@ struct page *kvm_alloc_hpt(unsigned long nr_pages)
 	/* Old CPUs require HPT aligned on a multiple of its size */
 	if (!cpu_has_feature(CPU_FTR_ARCH_206))
 		align_pages = nr_pages;
-	return kvm_alloc_cma(nr_pages, align_pages);
+	return cma_alloc(kvm_cma, nr_pages, get_order(align_pages));
 }
 EXPORT_SYMBOL_GPL(kvm_alloc_hpt);
 
 void kvm_release_hpt(struct page *page, unsigned long nr_pages)
 {
-	kvm_release_cma(page, nr_pages);
+	cma_release(kvm_cma, page, nr_pages);
 }
 EXPORT_SYMBOL_GPL(kvm_release_hpt);
 
@@ -178,6 +182,7 @@ void __init kvm_cma_reserve(void)
 			align_size = HPT_ALIGN_PAGES << PAGE_SHIFT;
 
 		align_size = max(kvm_rma_pages << PAGE_SHIFT, align_size);
-		kvm_cma_declare_contiguous(selected_size, align_size);
+		cma_declare_contiguous(selected_size, 0, 0, align_size,
+			KVM_CMA_CHUNK_ORDER - PAGE_SHIFT, false, &kvm_cma);
 	}
 }
diff --git a/arch/powerpc/kvm/book3s_hv_cma.c b/arch/powerpc/kvm/book3s_hv_cma.c
deleted file mode 100644
index d9d3d85..0000000
--- a/arch/powerpc/kvm/book3s_hv_cma.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Contiguous Memory Allocator for ppc KVM hash pagetable  based on CMA
- * for DMA mapping framework
- *
- * Copyright IBM Corporation, 2013
- * Author Aneesh Kumar K.V <aneesh.kumar@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 of the
- * License or (at your optional) any later version of the license.
- *
- */
-#define pr_fmt(fmt) "kvm_cma: " fmt
-
-#ifdef CONFIG_CMA_DEBUG
-#ifndef DEBUG
-#  define DEBUG
-#endif
-#endif
-
-#include <linux/memblock.h>
-#include <linux/mutex.h>
-#include <linux/sizes.h>
-#include <linux/slab.h>
-
-#include "book3s_hv_cma.h"
-
-struct kvm_cma {
-	unsigned long	base_pfn;
-	unsigned long	count;
-	unsigned long	*bitmap;
-};
-
-static DEFINE_MUTEX(kvm_cma_mutex);
-static struct kvm_cma kvm_cma_area;
-
-/**
- * kvm_cma_declare_contiguous() - reserve area for contiguous memory handling
- *			          for kvm hash pagetable
- * @size:  Size of the reserved memory.
- * @alignment:  Alignment for the contiguous memory area
- *
- * This function reserves memory for kvm cma area. It should be
- * called by arch code when early allocator (memblock or bootmem)
- * is still activate.
- */
-long __init kvm_cma_declare_contiguous(phys_addr_t size, phys_addr_t alignment)
-{
-	long base_pfn;
-	phys_addr_t addr;
-	struct kvm_cma *cma = &kvm_cma_area;
-
-	pr_debug("%s(size %lx)\n", __func__, (unsigned long)size);
-
-	if (!size)
-		return -EINVAL;
-	/*
-	 * Sanitise input arguments.
-	 * We should be pageblock aligned for CMA.
-	 */
-	alignment = max(alignment, (phys_addr_t)(PAGE_SIZE << pageblock_order));
-	size = ALIGN(size, alignment);
-	/*
-	 * Reserve memory
-	 * Use __memblock_alloc_base() since
-	 * memblock_alloc_base() panic()s.
-	 */
-	addr = __memblock_alloc_base(size, alignment, 0);
-	if (!addr) {
-		base_pfn = -ENOMEM;
-		goto err;
-	} else
-		base_pfn = PFN_DOWN(addr);
-
-	/*
-	 * Each reserved area must be initialised later, when more kernel
-	 * subsystems (like slab allocator) are available.
-	 */
-	cma->base_pfn = base_pfn;
-	cma->count    = size >> PAGE_SHIFT;
-	pr_info("CMA: reserved %ld MiB\n", (unsigned long)size / SZ_1M);
-	return 0;
-err:
-	pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
-	return base_pfn;
-}
-
-/**
- * kvm_alloc_cma() - allocate pages from contiguous area
- * @nr_pages: Requested number of pages.
- * @align_pages: Requested alignment in number of pages
- *
- * This function allocates memory buffer for hash pagetable.
- */
-struct page *kvm_alloc_cma(unsigned long nr_pages, unsigned long align_pages)
-{
-	int ret;
-	struct page *page = NULL;
-	struct kvm_cma *cma = &kvm_cma_area;
-	unsigned long chunk_count, nr_chunk;
-	unsigned long mask, pfn, pageno, start = 0;
-
-
-	if (!cma || !cma->count)
-		return NULL;
-
-	pr_debug("%s(cma %p, count %lu, align pages %lu)\n", __func__,
-		 (void *)cma, nr_pages, align_pages);
-
-	if (!nr_pages)
-		return NULL;
-	/*
-	 * align mask with chunk size. The bit tracks pages in chunk size
-	 */
-	VM_BUG_ON(!is_power_of_2(align_pages));
-	mask = (align_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT)) - 1;
-	BUILD_BUG_ON(PAGE_SHIFT > KVM_CMA_CHUNK_ORDER);
-
-	chunk_count = cma->count >>  (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-	nr_chunk = nr_pages >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-
-	mutex_lock(&kvm_cma_mutex);
-	for (;;) {
-		pageno = bitmap_find_next_zero_area(cma->bitmap, chunk_count,
-						    start, nr_chunk, mask);
-		if (pageno >= chunk_count)
-			break;
-
-		pfn = cma->base_pfn + (pageno << (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT));
-		ret = alloc_contig_range(pfn, pfn + nr_pages, MIGRATE_CMA);
-		if (ret == 0) {
-			bitmap_set(cma->bitmap, pageno, nr_chunk);
-			page = pfn_to_page(pfn);
-			memset(pfn_to_kaddr(pfn), 0, nr_pages << PAGE_SHIFT);
-			break;
-		} else if (ret != -EBUSY) {
-			break;
-		}
-		pr_debug("%s(): memory range at %p is busy, retrying\n",
-			 __func__, pfn_to_page(pfn));
-		/* try again with a bit different memory target */
-		start = pageno + mask + 1;
-	}
-	mutex_unlock(&kvm_cma_mutex);
-	pr_debug("%s(): returned %p\n", __func__, page);
-	return page;
-}
-
-/**
- * kvm_release_cma() - release allocated pages for hash pagetable
- * @pages: Allocated pages.
- * @nr_pages: Number of allocated pages.
- *
- * This function releases memory allocated by kvm_alloc_cma().
- * It returns false when provided pages do not belong to contiguous area and
- * true otherwise.
- */
-bool kvm_release_cma(struct page *pages, unsigned long nr_pages)
-{
-	unsigned long pfn;
-	unsigned long nr_chunk;
-	struct kvm_cma *cma = &kvm_cma_area;
-
-	if (!cma || !pages)
-		return false;
-
-	pr_debug("%s(page %p count %lu)\n", __func__, (void *)pages, nr_pages);
-
-	pfn = page_to_pfn(pages);
-
-	if (pfn < cma->base_pfn || pfn >= cma->base_pfn + cma->count)
-		return false;
-
-	VM_BUG_ON(pfn + nr_pages > cma->base_pfn + cma->count);
-	nr_chunk = nr_pages >>  (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-
-	mutex_lock(&kvm_cma_mutex);
-	bitmap_clear(cma->bitmap,
-		     (pfn - cma->base_pfn) >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT),
-		     nr_chunk);
-	free_contig_range(pfn, nr_pages);
-	mutex_unlock(&kvm_cma_mutex);
-
-	return true;
-}
-
-static int __init kvm_cma_activate_area(unsigned long base_pfn,
-					unsigned long count)
-{
-	unsigned long pfn = base_pfn;
-	unsigned i = count >> pageblock_order;
-	struct zone *zone;
-
-	WARN_ON_ONCE(!pfn_valid(pfn));
-	zone = page_zone(pfn_to_page(pfn));
-	do {
-		unsigned j;
-		base_pfn = pfn;
-		for (j = pageblock_nr_pages; j; --j, pfn++) {
-			WARN_ON_ONCE(!pfn_valid(pfn));
-			/*
-			 * alloc_contig_range requires the pfn range
-			 * specified to be in the same zone. Make this
-			 * simple by forcing the entire CMA resv range
-			 * to be in the same zone.
-			 */
-			if (page_zone(pfn_to_page(pfn)) != zone)
-				return -EINVAL;
-		}
-		init_cma_reserved_pageblock(pfn_to_page(base_pfn));
-	} while (--i);
-	return 0;
-}
-
-static int __init kvm_cma_init_reserved_areas(void)
-{
-	int bitmap_size, ret;
-	unsigned long chunk_count;
-	struct kvm_cma *cma = &kvm_cma_area;
-
-	pr_debug("%s()\n", __func__);
-	if (!cma->count)
-		return 0;
-	chunk_count = cma->count >> (KVM_CMA_CHUNK_ORDER - PAGE_SHIFT);
-	bitmap_size = BITS_TO_LONGS(chunk_count) * sizeof(long);
-	cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
-	if (!cma->bitmap)
-		return -ENOMEM;
-
-	ret = kvm_cma_activate_area(cma->base_pfn, cma->count);
-	if (ret)
-		goto error;
-	return 0;
-
-error:
-	kfree(cma->bitmap);
-	return ret;
-}
-core_initcall(kvm_cma_init_reserved_areas);
diff --git a/arch/powerpc/kvm/book3s_hv_cma.h b/arch/powerpc/kvm/book3s_hv_cma.h
deleted file mode 100644
index 655144f..0000000
--- a/arch/powerpc/kvm/book3s_hv_cma.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Contiguous Memory Allocator for ppc KVM hash pagetable  based on CMA
- * for DMA mapping framework
- *
- * Copyright IBM Corporation, 2013
- * Author Aneesh Kumar K.V <aneesh.kumar@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 of the
- * License or (at your optional) any later version of the license.
- *
- */
-
-#ifndef __POWERPC_KVM_CMA_ALLOC_H__
-#define __POWERPC_KVM_CMA_ALLOC_H__
-/*
- * Both RMA and Hash page allocation will be multiple of 256K.
- */
-#define KVM_CMA_CHUNK_ORDER	18
-
-extern struct page *kvm_alloc_cma(unsigned long nr_pages,
-				  unsigned long align_pages);
-extern bool kvm_release_cma(struct page *pages, unsigned long nr_pages);
-extern long kvm_cma_declare_contiguous(phys_addr_t size,
-				       phys_addr_t alignment) __init;
-#endif
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH 4/4] powerpc/eeh: Avoid event on passed PE
From: Paul Mackerras @ 2014-06-03  5:54 UTC (permalink / raw)
  To: Alexander Graf
  Cc: aik, Gavin Shan, kvm-ppc, alex.williamson, qiudayu, linuxppc-dev
In-Reply-To: <537B3B97.3020100@suse.de>

On Tue, May 20, 2014 at 01:25:11PM +0200, Alexander Graf wrote:
> 
> On 20.05.14 10:30, Gavin Shan wrote:
> >If we detects frozen state on PE that has been passed to guest, we
> >needn't handle it. Instead, we rely on the guest to detect and recover
> >it. The patch avoid EEH event on the frozen passed PE so that the guest
> >can have chance to handle that.
> >
> >Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
> 
> How does the guest learn about this failure? We'd need to inject an error
> into it, no?
> 
> I think what you want is an irqfd that the in-kernel eeh code notifies when
> it sees a failure. When such an fd exists, the kernel skips its own error
> handling.

Well... we don't have irqfd support for book3s HV upstream yet.  The
way the current code is, we have to turn on GSI routing, which puts a
hard and relatively small limit on the hardware IRQ numbers we can use
as it uses a flat array indexed by hardware IRQ number.  Which is a
problem that I need to solve somehow, but it makes using an irqfd
unattractive in the short term.

Paul.

^ permalink raw reply

* Re: [PATCH] powerpc, xmon: Enable hardware instruction breakpoint support on POWER8
From: Anshuman Khandual @ 2014-06-03  6:03 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: linuxppc-dev, mikey
In-Reply-To: <8761knl6x5.fsf@linux.vnet.ibm.com>

On 05/30/2014 07:12 PM, Aneesh Kumar K.V wrote:
> Anshuman Khandual <khandual@linux.vnet.ibm.com> writes:
> 
>> This patch enables support for hardware instruction breakpoints on POWER8 with
>> the help of a new register called CIABR (Completed Instruction Address Breakpoint
>> Register). With this patch, single hardware instruction breakpoint can be added
>> and cleared during any active xmon debug session. This hardware based instruction
>> breakpoint mechanism works correctly along with the existing TRAP based instruction
>> breakpoints available on xmon. Example usage as follows.
>>
>> (A) Start xmon:
>> $echo x > /proc/sysrq-trigger
>> SysRq : Entering xmon
>> cpu 0x0: Vector: 0  at [c000001f6c67f960]
>>     pc: c000000000072078: .sysrq_handle_xmon+0x58/0x60
>>     lr: c000000000072078: .sysrq_handle_xmon+0x58/0x60
>>     sp: c000001f6c67fac0
>>    msr: 9000000000009032
>>   current = 0xc000001f6e709ac0
>>   paca    = 0xc00000000fffa000   softe: 0        irq_happened: 0x00
>>     pid   = 3250, comm = bash
>> enter ? for help
>> 0:mon> b
>>    type            address
>>
>> (B) Set the breakpoint:
>> 0:mon> ls .power_pmu_add
>> .power_pmu_add: c000000000078f50
>> 0:mon> bi c000000000078f50
>> 0:mon> b
>>    type            address
>>  1 inst   c000000000078f50  .power_pmu_add+0x0/0x2e0
>> 0:mon> ls .perf_event_interrupt
>> .perf_event_interrupt: c00000000007aee0
>> 0:mon> bi c00000000007aee0
>> One instruction breakpoint possible with CIABR
>> 0:mon> x
>>
>> (C) Run the workload (with the breakpoint):
>> $./perf record ls
>> cpu 0x2: Vector: d00 (Single Step) at [c000001f718133a0]
>>     pc: c000000000078f54: .power_pmu_add+0x4/0x2e0
>>     lr: c000000000155be0: .event_sched_in+0x90/0x1d0
>>     sp: c000001f71813620
>>    msr: 9000000040109032
>>   current = 0xc000001f6ce30000
>>   paca    = 0xc00000000fffa600   softe: 0        irq_happened: 0x01
>>     pid   = 3270, comm = ls
>>         std     r22,-80(r1)
>> enter ? for help
>>
>> (D) Clear the breakpoint:
>> 2:mon> bc
>> All breakpoints cleared
>> 2:mon> x
>> [ perf record: Woken up 1 times to write data ]
>> [ perf record: Captured and wrote 0.002 MB perf.data (~66 samples) ]
>>
>> (E) Run the workload again (without any breakpoints):
>> $./perf record ls
>> [ perf record: Woken up 1 times to write data ]
>> [ perf record: Captured and wrote 0.001 MB perf.data (~61 samples) ]
>>
>> Signed-off-by: Anshuman Khandual <khandual@linux.vnet.ibm.com>
>> ---
>>  arch/powerpc/xmon/xmon.c | 62 ++++++++++++++++++++++++++++++++++++++++++++----
>>  1 file changed, 58 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
>> index 3fd1d9a..f74ec83 100644
>> --- a/arch/powerpc/xmon/xmon.c
>> +++ b/arch/powerpc/xmon/xmon.c
>> @@ -48,6 +48,7 @@
>>  #ifdef CONFIG_PPC64
>>  #include <asm/hvcall.h>
>>  #include <asm/paca.h>
>> +#include <asm/plpar_wrappers.h>
>>  #endif
>>  
>>  #include "nonstdio.h"
>> @@ -89,6 +90,7 @@ struct bpt {
>>  /* Bits in bpt.enabled */
>>  #define BP_IABR_TE	1		/* IABR translation enabled */
>>  #define BP_IABR		2
>> +#define BP_CIABR	4
>>  #define BP_TRAP		8
>>  #define BP_DABR		0x10
>>  
>> @@ -97,6 +99,7 @@ static struct bpt bpts[NBPTS];
>>  static struct bpt dabr;
>>  static struct bpt *iabr;
>>  static unsigned bpinstr = 0x7fe00008;	/* trap */
>> +static bool ciabr_used = false;		/* CIABR instruction breakpoint */
>>  
>>  #define BP_NUM(bp)	((bp) - bpts + 1)
>>  
>> @@ -269,6 +272,34 @@ static inline void cinval(void *p)
>>  	asm volatile ("dcbi 0,%0; icbi 0,%0" : : "r" (p));
>>  }
>>  
>> +static void write_ciabr(unsigned long ciabr)
>> +{
>> +	if (cpu_has_feature(CPU_FTR_HVMODE)) {
>> +		mtspr(SPRN_CIABR, ciabr);
>> +		return;
>> +	}
>> +
>> +#ifdef CONFIG_PPC64
>> +	plapr_set_ciabr(ciabr);
>> +#endif
>> +}
>> +
>> +static void set_ciabr(unsigned long addr)
>> +{
>> +	addr &= ~CIABR_PRIV;
>> +	if (cpu_has_feature(CPU_FTR_HVMODE))
>> +		addr |= CIABR_PRIV_HYPER;
>> +	else
>> +		addr |= CIABR_PRIV_SUPER;
>> +	write_ciabr(addr);
>> +}
>> +
>> +static void clear_ciabr(void)
>> +{
>> +	if (cpu_has_feature(CPU_FTR_ARCH_207S))
>> +		write_ciabr(0);
>> +}
>> +
>>  /*
>>   * Disable surveillance (the service processor watchdog function)
>>   * while we are in xmon.
>> @@ -764,6 +795,9 @@ static void insert_cpu_bpts(void)
>>  	if (iabr && cpu_has_feature(CPU_FTR_IABR))
>>  		mtspr(SPRN_IABR, iabr->address
>>  			 | (iabr->enabled & (BP_IABR|BP_IABR_TE)));
>> +
>> +	if (iabr && cpu_has_feature(CPU_FTR_ARCH_207S))
>> +		set_ciabr(iabr->address);
>>  }
>>  
>>  static void remove_bpts(void)
>> @@ -791,6 +825,7 @@ static void remove_cpu_bpts(void)
>>  	hw_breakpoint_disable();
>>  	if (cpu_has_feature(CPU_FTR_IABR))
>>  		mtspr(SPRN_IABR, 0);
>> +	clear_ciabr();
>>  }
>>  
>>  /* Command interpreting routine */
>> @@ -1124,7 +1159,7 @@ static char *breakpoint_help_string =
>>      "b <addr> [cnt]   set breakpoint at given instr addr\n"
>>      "bc               clear all breakpoints\n"
>>      "bc <n/addr>      clear breakpoint number n or at addr\n"
>> -    "bi <addr> [cnt]  set hardware instr breakpoint (POWER3/RS64 only)\n"
>> +    "bi <addr> [cnt]  set hardware instr breakpoint (POWER3/RS64/POWER8 only)\n"
>>      "bd <addr> [cnt]  set hardware data breakpoint\n"
>>      "";
>>  
>> @@ -1163,11 +1198,20 @@ bpt_cmds(void)
>>  		break;
>>  
>>  	case 'i':	/* bi - hardware instr breakpoint */
>> -		if (!cpu_has_feature(CPU_FTR_IABR)) {
>> +		if (!cpu_has_feature(CPU_FTR_IABR) && !cpu_has_feature(CPU_FTR_ARCH_207S)) {
>>  			printf("Hardware instruction breakpoint "
>>  			       "not supported on this cpu\n");
>>  			break;
>>  		}
>> +
>> +		if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
>> +			if (ciabr_used) {
>> +				printf("One instruction breakpoint "
>> +					"possible with CIABR\n");
>> +				break;
>> +			}
> 
> We don't seem to do that with iabr ? Why keep ciabr different 

Right now with the IABR implementation if we try to set hardware instruction
breakpoint while one is already there, it just get overridden with the new
address without complaining. I thought with this at least for CIABR cases,
it will complain about it and require the user to clear the breakpoint
explicitly before allowing a new breakpoint. Okay will remove this.
 
> 
>> +		}
> 
> 
> Why is this implemented different than existing iabr, You could do this
> with iabr and iabr->enabled = BP_CIABR right ?

Did not get it, yeah its implemented in that way only. 

^ permalink raw reply

* FMD15 and t104x
From: Tony @ 2014-06-03  6:43 UTC (permalink / raw)
  To: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 219 bytes --]

Hi,

I am working with 3.0.x kernel with fmd15. I could bringup the t1040qsd but
the ethernet is not getting detected. Is t104x devices required backporting
of FMD19 ? OR modifying the dts file is enough ?

Thanks
Alan

[-- Attachment #2: Type: text/html, Size: 282 bytes --]

^ 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