LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH -V7 06/10] powerpc: Update gup_pmd_range to handle transparent hugepages
From: David Gibson @ 2013-05-03  4:57 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1367178711-8232-7-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

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

On Mon, Apr 29, 2013 at 01:21:47AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH -V7 07/10] powerpc/THP: Add code to handle HPTE faults for large pages
From: David Gibson @ 2013-05-03  5:13 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1367178711-8232-8-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

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

On Mon, Apr 29, 2013 at 01:21:48AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> 
> The deposted PTE page in the second half of the PMD table is used to
> track the state on hash PTEs. After updating the HPTE, we mark the
> coresponding slot in the deposted PTE page valid.
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH -V7 04/10] powerpc: Update find_linux_pte_or_hugepte to handle transparent hugepages
From: David Gibson @ 2013-05-03  4:53 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1367178711-8232-5-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

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

On Mon, Apr 29, 2013 at 01:21:45AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>

What's the difference in meaning between pmd_huge() and pmd_large()?


> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
>  arch/powerpc/mm/hugetlbpage.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
> index 8601f2d..081c001 100644
> --- a/arch/powerpc/mm/hugetlbpage.c
> +++ b/arch/powerpc/mm/hugetlbpage.c
> @@ -954,7 +954,7 @@ pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift
>  			pdshift = PMD_SHIFT;
>  			pm = pmd_offset(pu, ea);
>  
> -			if (pmd_huge(*pm)) {
> +			if (pmd_huge(*pm) || pmd_large(*pm)) {
>  				ret_pte = (pte_t *) pm;
>  				goto out;
>  			} else if (is_hugepd(pm))

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH -V7 08/10] powerpc/THP: Enable THP on PPC64
From: David Gibson @ 2013-05-03  5:15 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1367178711-8232-9-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

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

On Mon, Apr 29, 2013 at 01:21:49AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> 
> We enable only if the we support 16MB page size.
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
>  arch/powerpc/include/asm/pgtable-ppc64.h |  3 +--
>  arch/powerpc/mm/pgtable_64.c             | 28 ++++++++++++++++++++++++++++
>  2 files changed, 29 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
> index 97fc839..d65534b 100644
> --- a/arch/powerpc/include/asm/pgtable-ppc64.h
> +++ b/arch/powerpc/include/asm/pgtable-ppc64.h
> @@ -426,8 +426,7 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
>  	return pmd_val(pmd) >> PTE_RPN_SHIFT;
>  }
>  
> -/* We will enable it in the last patch */
> -#define has_transparent_hugepage() 0
> +extern int has_transparent_hugepage(void);
>  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>  
>  static inline int pmd_young(pmd_t pmd)
> diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
> index 54216c1..b742d6f 100644
> --- a/arch/powerpc/mm/pgtable_64.c
> +++ b/arch/powerpc/mm/pgtable_64.c
> @@ -754,6 +754,34 @@ void update_mmu_cache_pmd(struct vm_area_struct *vma, unsigned long addr,
>  	return;
>  }
>  
> +int has_transparent_hugepage(void)
> +{
> +	if (!mmu_has_feature(MMU_FTR_16M_PAGE))
> +		return 0;
> +	/*
> +	 * We support THP only if HPAGE_SHIFT is 16MB.
> +	 */
> +	if (!HPAGE_SHIFT || (HPAGE_SHIFT != mmu_psize_defs[MMU_PAGE_16M].shift))
> +		return 0;

Again, THP should not be dependent on the value of HPAGE_SHIFT.  Just
checking that mmu_psize_defsz[MMU_PAGE_16M].shift == 24 should be
sufficient (i.e. that 16M hugepages are supported).

> +	/*
> +	 * We need to make sure that we support 16MB hugepage in a segement
> +	 * with base page size 64K or 4K. We only enable THP with a PAGE_SIZE
> +	 * of 64K.
> +	 */
> +	/*
> +	 * If we have 64K HPTE, we will be using that by default
> +	 */
> +	if (mmu_psize_defs[MMU_PAGE_64K].shift &&
> +	    (mmu_psize_defs[MMU_PAGE_64K].penc[MMU_PAGE_16M] == -1))
> +		return 0;
> +	/*
> +	 * Ok we only have 4K HPTE
> +	 */
> +	if (mmu_psize_defs[MMU_PAGE_4K].penc[MMU_PAGE_16M] == -1)
> +		return 0;

Except you don't actually support THP on 4K base page size yet.

> +
> +	return 1;
> +}
>  #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
>  
>  pmd_t pmdp_get_and_clear(struct mm_struct *mm,

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* Re: [PATCH -V7 05/10] powerpc: Replace find_linux_pte with find_linux_pte_or_hugepte
From: David Gibson @ 2013-05-03  4:56 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1367178711-8232-6-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

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

On Mon, Apr 29, 2013 at 01:21:46AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> 
> Replace find_linux_pte with find_linux_pte_or_hugepte and explicitly
> document why we don't need to handle transparent hugepages at callsites.
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
> ---
>  arch/powerpc/include/asm/pgtable-ppc64.h | 24 ------------------------
>  arch/powerpc/kernel/io-workarounds.c     | 10 ++++++++--
>  arch/powerpc/kvm/book3s_hv_rm_mmu.c      |  2 +-
>  arch/powerpc/mm/hash_utils_64.c          |  8 +++++++-
>  arch/powerpc/mm/hugetlbpage.c            |  8 ++++++--
>  arch/powerpc/mm/tlb_hash64.c             |  7 ++++++-
>  arch/powerpc/platforms/pseries/eeh.c     |  7 ++++++-
>  7 files changed, 34 insertions(+), 32 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
> index f0effab..97fc839 100644
> --- a/arch/powerpc/include/asm/pgtable-ppc64.h
> +++ b/arch/powerpc/include/asm/pgtable-ppc64.h
> @@ -343,30 +343,6 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry)
>  
>  void pgtable_cache_add(unsigned shift, void (*ctor)(void *));
>  void pgtable_cache_init(void);
> -
> -/*
> - * find_linux_pte returns the address of a linux pte for a given
> - * effective address and directory.  If not found, it returns zero.
> - */
> -static inline pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea)
> -{
> -	pgd_t *pg;
> -	pud_t *pu;
> -	pmd_t *pm;
> -	pte_t *pt = NULL;
> -
> -	pg = pgdir + pgd_index(ea);
> -	if (!pgd_none(*pg)) {
> -		pu = pud_offset(pg, ea);
> -		if (!pud_none(*pu)) {
> -			pm = pmd_offset(pu, ea);
> -			if (pmd_present(*pm))
> -				pt = pte_offset_kernel(pm, ea);
> -		}
> -	}
> -	return pt;
> -}
> -
>  pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
>  				 unsigned *shift);
>  #endif /* __ASSEMBLY__ */
> diff --git a/arch/powerpc/kernel/io-workarounds.c b/arch/powerpc/kernel/io-workarounds.c
> index 50e90b7..e5263ab 100644
> --- a/arch/powerpc/kernel/io-workarounds.c
> +++ b/arch/powerpc/kernel/io-workarounds.c
> @@ -55,6 +55,7 @@ static struct iowa_bus *iowa_pci_find(unsigned long vaddr, unsigned long paddr)
>  
>  struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
>  {
> +	unsigned shift;
>  	struct iowa_bus *bus;
>  	int token;
>  
> @@ -70,11 +71,16 @@ struct iowa_bus *iowa_mem_find_bus(const PCI_IO_ADDR addr)
>  		if (vaddr < PHB_IO_BASE || vaddr >= PHB_IO_END)
>  			return NULL;
>  
> -		ptep = find_linux_pte(init_mm.pgd, vaddr);
> +		ptep = find_linux_pte_or_hugepte(init_mm.pgd, vaddr, &shift);
>  		if (ptep == NULL)
>  			paddr = 0;
> -		else
> +		else {
> +			/*
> +			 * we don't have hugepages backing iomem
> +			 */
> +			BUG_ON(shift);
>  			paddr = pte_pfn(*ptep) << PAGE_SHIFT;
> +		}
>  		bus = iowa_pci_find(vaddr, paddr);
>  
>  		if (bus == NULL)
> diff --git a/arch/powerpc/kvm/book3s_hv_rm_mmu.c b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
> index 19c93ba..8c345df 100644
> --- a/arch/powerpc/kvm/book3s_hv_rm_mmu.c
> +++ b/arch/powerpc/kvm/book3s_hv_rm_mmu.c
> @@ -27,7 +27,7 @@ static void *real_vmalloc_addr(void *x)
>  	unsigned long addr = (unsigned long) x;
>  	pte_t *p;
>  
> -	p = find_linux_pte(swapper_pg_dir, addr);
> +	p = find_linux_pte_or_hugepte(swapper_pg_dir, addr, NULL);
>  	if (!p || !pte_present(*p))
>  		return NULL;
>  	/* assume we don't have huge pages in vmalloc space... */
> diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> index d0eb6d4..e942ae9 100644
> --- a/arch/powerpc/mm/hash_utils_64.c
> +++ b/arch/powerpc/mm/hash_utils_64.c
> @@ -1131,6 +1131,7 @@ EXPORT_SYMBOL_GPL(hash_page);
>  void hash_preload(struct mm_struct *mm, unsigned long ea,
>  		  unsigned long access, unsigned long trap)
>  {
> +	int shift;
>  	unsigned long vsid;
>  	pgd_t *pgdir;
>  	pte_t *ptep;
> @@ -1152,10 +1153,15 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
>  	pgdir = mm->pgd;
>  	if (pgdir == NULL)
>  		return;
> -	ptep = find_linux_pte(pgdir, ea);
> +	/*
> +	 * THP pages use update_mmu_cache_pmd. We don't do
> +	 * hash preload there. Hence can ignore THP here
> +	 */
> +	ptep = find_linux_pte_or_hugepte(pgdir, ea, &shift);
>  	if (!ptep)
>  		return;
>  
> +	BUG_ON(shift);
>  #ifdef CONFIG_PPC_64K_PAGES
>  	/* If either _PAGE_4K_PFN or _PAGE_NO_CACHE is set (and we are on
>  	 * a 64K kernel), then we don't preload, hash_page() will take
> diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
> index 081c001..1154714 100644
> --- a/arch/powerpc/mm/hugetlbpage.c
> +++ b/arch/powerpc/mm/hugetlbpage.c
> @@ -105,6 +105,7 @@ int pgd_huge(pgd_t pgd)
>  
>  pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
>  {
> +	/* Only called for HugeTLB pages, hence can ignore THP */
>  	return find_linux_pte_or_hugepte(mm->pgd, addr, NULL);
>  }
>  
> @@ -673,11 +674,14 @@ follow_huge_addr(struct mm_struct *mm, unsigned long address, int write)
>  	struct page *page;
>  	unsigned shift;
>  	unsigned long mask;
> -
> +	/*
> +	 * Transparent hugepages are handled by generic code. We can skip them
> +	 * here.
> +	 */
>  	ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift);
>  
>  	/* Verify it is a huge page else bail. */
> -	if (!ptep || !shift)
> +	if (!ptep || !shift || pmd_trans_huge((pmd_t)*ptep))
>  		return ERR_PTR(-EINVAL);
>  
>  	mask = (1UL << shift) - 1;
> diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c
> index 023ec8a..56d9b85 100644
> --- a/arch/powerpc/mm/tlb_hash64.c
> +++ b/arch/powerpc/mm/tlb_hash64.c
> @@ -189,6 +189,7 @@ void tlb_flush(struct mmu_gather *tlb)
>  void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
>  			      unsigned long end)
>  {
> +	int shift;
>  	unsigned long flags;
>  
>  	start = _ALIGN_DOWN(start, PAGE_SIZE);
> @@ -206,11 +207,15 @@ void __flush_hash_table_range(struct mm_struct *mm, unsigned long start,
>  	local_irq_save(flags);
>  	arch_enter_lazy_mmu_mode();
>  	for (; start < end; start += PAGE_SIZE) {
> -		pte_t *ptep = find_linux_pte(mm->pgd, start);
> +		pte_t *ptep = find_linux_pte_or_hugepte(mm->pgd, start, &shift);
>  		unsigned long pte;
>  
>  		if (ptep == NULL)
>  			continue;
> +		/*
> +		 * We won't find hugepages here, this is iomem.
> +		 */

Really?  Why?

> +		BUG_ON(shift);
>  		pte = pte_val(*ptep);
>  		if (!(pte & _PAGE_HASHPTE))
>  			continue;
> diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
> index 6b73d6c..d2e76d2 100644
> --- a/arch/powerpc/platforms/pseries/eeh.c
> +++ b/arch/powerpc/platforms/pseries/eeh.c
> @@ -258,12 +258,17 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity)
>   */
>  static inline unsigned long eeh_token_to_phys(unsigned long token)
>  {
> +	int shift;
>  	pte_t *ptep;
>  	unsigned long pa;
>  
> -	ptep = find_linux_pte(init_mm.pgd, token);
> +	/*
> +	 * We won't find hugepages here, iomem
> +	 */
> +	ptep = find_linux_pte_or_hugepte(init_mm.pgd, token, &shift);
>  	if (!ptep)
>  		return token;
> +	BUG_ON(shift);
>  	pa = pte_pfn(*ptep) << PAGE_SHIFT;
>  
>  	return pa | (token & (PAGE_SIZE-1));

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* RE: pci overmapping
From: Sethi Varun-B16395 @ 2013-05-03  5:29 UTC (permalink / raw)
  To: Wood Scott-B07421; +Cc: Yoder Stuart-B08248, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1367518770.24411.13@snotra>



> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Thursday, May 02, 2013 11:50 PM
> To: Sethi Varun-B16395
> Cc: Wood Scott-B07421; Yoder Stuart-B08248; galak@kernel.crashing.org;
> linuxppc-dev@lists.ozlabs.org
> Subject: Re: pci overmapping
>=20
> On 05/02/2013 01:09:53 PM, Sethi Varun-B16395 wrote:
> >
> >
> > > -----Original Message-----
> > > From: Wood Scott-B07421
> > > Sent: Thursday, May 02, 2013 10:44 PM
> > > To: Yoder Stuart-B08248
> > > Cc: galak@kernel.crashing.org; Sethi Varun-B16395; linuxppc-
> > > dev@lists.ozlabs.org
> > > Subject: Re: pci overmapping
> > >
> > > On 05/02/2013 12:05:42 PM, Yoder Stuart-B08248 wrote:
> > > > Kumar,
> > > >
> > > > In fsl_pci.c there is a change you made a while back:
> > > >   "powerpc/fsl: Setup PCI inbound window based on actual amount of
> > > > memory"
> > > >
> > > > ...and there is this comment in the code:
> > > >
> > > >     /* PCIe can overmap inbound & outbound since RX & TX are
> > separated
> > > > */
> > > >     if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
> > > >
> > > > You are implying that PCIe can overmap and PCI can't.  Why is
> > > > that?   (I'm assuming that 'overmap' means that inbound window
> > > > can extend beyond the end of ram.)
> > >
> > > Shouldn't the concern be whether we're overlapping outbound, not
> > merely
> > > whether we go beyond the end of RAM?
> > >
> > > And couldn't inbound/outbound overlap be an issue even on PCIe, if
> > > there's a PCI bridge underneath it?
> > I believe that the overlap problem would be avoided in case of 36 bit
> > physical support (outbound window address would be high order 36 bit
> > value), right?
>=20
> Not necessarily -- it depends on what the bus addresses are, not the host
> addresses.
The fsl_pci code already checks for the overlap condition. The inbound wind=
ow range is set to the minimum of memory end address or the start of pci ou=
tbound address. In our case, the guest memory end address (host physical ad=
dress derived from the huge tlb page) is less than the pci outbound start a=
ddress. But, it could be the other way round as well. In both cases if the =
inbound memory can't map the end of RAM address (for the guest), the fsl_pc=
i driver would enable swiotlb.

For the first case where end of memory is < start of pci outbound address, =
we can avoid enabling swiotlb (when end address is not a power of two) by o=
ver committing the inbound address window.

-Varun

^ permalink raw reply

* Re: [PATCH -V7 01/10] powerpc/THP: Double the PMD table size for THP
From: David Gibson @ 2013-05-03  3:21 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: paulus, linuxppc-dev, linux-mm
In-Reply-To: <1367178711-8232-2-git-send-email-aneesh.kumar@linux.vnet.ibm.com>

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

On Mon, Apr 29, 2013 at 01:21:42AM +0530, Aneesh Kumar K.V wrote:
> From: "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com>
> 
> THP code does PTE page allocation along with large page request and deposit them
> for later use. This is to ensure that we won't have any failures when we split
> hugepages to regular pages.
> 
> On powerpc we want to use the deposited PTE page for storing hash pte slot and
> secondary bit information for the HPTEs. We use the second half
> of the pmd table to save the deposted PTE page.
> 
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>

So far so good.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply

* RE: [PATCH 2/2 V8] powerpc/85xx: Add machine check handler to fix PCIe erratum on mpc85xx
From: Jia Hongtao-B38951 @ 2013-05-03  2:03 UTC (permalink / raw)
  To: Wood Scott-B07421, galak@kernel.crashing.org
  Cc: linuxppc-dev@lists.ozlabs.org, Li Yang-R58472
In-Reply-To: <1367514224.24411.10@snotra>



> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Friday, May 03, 2013 1:04 AM
> To: Jia Hongtao-B38951
> Cc: linuxppc-dev@lists.ozlabs.org; galak@kernel.crashing.org; Wood Scott-
> B07421; segher@kernel.crashing.org; Li Yang-R58472; Jia Hongtao-B38951
> Subject: Re: [PATCH 2/2 V8] powerpc/85xx: Add machine check handler to
> fix PCIe erratum on mpc85xx
>=20
> On 04/28/2013 12:20:08 AM, Jia Hongtao wrote:
> > A PCIe erratum of mpc85xx may causes a core hang when a link of PCIe
> > goes down. when the link goes down, Non-posted transactions issued via
> > the ATMU requiring completion result in an instruction stall.
> > At the same time a machine-check exception is generated to the core to
> > allow further processing by the handler. We implements the handler
> > which skips the instruction caused the stall.
> >
> > This patch depends on patch:
> > powerpc/85xx: Add platform_device declaration to fsl_pci.h
> >
> > Signed-off-by: Zhao Chenhui <b35336@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > Signed-off-by: Liu Shuo <soniccat.liu@gmail.com>
> > Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
> > ---
> > V8:
> > * Add A variant load instruction emulation.
>=20
> ACK
>=20
> -Scott

Thanks for the review.

Hi Kumar,

Could you please review these MSI and PCI hang errata patches?
http://patchwork.ozlabs.org/patch/233211/
http://patchwork.ozlabs.org/patch/235276/
http://patchwork.ozlabs.org/patch/240238/
http://patchwork.ozlabs.org/patch/240239/ (This patch)

Thanks.
-Hongtao

^ permalink raw reply

* RE: [PATCH v3 1/4] powerpc/mpic: add irq_set_wake support
From: Wang Dongsheng-B40534 @ 2013-05-03  1:54 UTC (permalink / raw)
  To: galak@kernel.crashing.org
  Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1366155021.23030.24@snotra>

Hi Kumar,

Could you apply these patches?

Thanks.

> -----Original Message-----
> From: Wang Dongsheng-B40534
> Sent: Tuesday, April 23, 2013 6:10 PM
> To: galak@kernel.crashing.org
> Cc: linuxppc-dev@lists.ozlabs.org; Wood Scott-B07421
> Subject: RE: [PATCH v3 1/4] powerpc/mpic: add irq_set_wake support
>=20
> Hi Kumar,
>=20
> Could you apply these patches?
>=20
> Thanks.
>=20
> [v3,1/4] powerpc/mpic: add irq_set_wake support
> http://patchwork.ozlabs.org/patch/234934/
>=20
> [v3,2/4] powerpc/mpic: add global timer support
> http://patchwork.ozlabs.org/patch/234935/
>=20
> [v3,3/4] powerpc/mpic: create mpic subsystem object
> http://patchwork.ozlabs.org/patch/234936/
>=20
> [v3,4/4] powerpc/fsl: add MPIC timer wakeup support
> http://patchwork.ozlabs.org/patch/234937/
>=20
>=20
> > -----Original Message-----
> > From: Wood Scott-B07421
> > Sent: Wednesday, April 17, 2013 7:30 AM
> > To: Wang Dongsheng-B40534
> > Cc: Wood Scott-B07421; linuxppc-dev@lists.ozlabs.org;
> > galak@kernel.crashing.org
> > Subject: Re: [PATCH v3 1/4] powerpc/mpic: add irq_set_wake support
> >
> > ACK
> >
> > -Scott
> >
> > On 04/16/2013 05:58:52 AM, Wang Dongsheng-B40534 wrote:
> > > Hi scott,
> > >
> > > Could you ACK these patches?
> > >
> > > [PATCH v3 2/4] powerpc/mpic: add global timer support [PATCH v3 3/4]
> > > powerpc/mpic: create mpic subsystem object [PATCH v3 4/4]
> > > powerpc/fsl: add MPIC timer wakeup support
> > >
> > > Thanks.
> > >

^ permalink raw reply

* [PATCH] powerpc/tm: Fix null pointer deference in flush_hash_page
From: Michael Neuling @ 2013-05-03  1:36 UTC (permalink / raw)
  To: benh; +Cc: Linux PPC dev, John J Miller

Make sure that current->thread.reg exists before we deference it in
flush_hash_page.

Signed-off-by: Michael Neuling <mikey@neuling.org>
Reported-by: John J Miller <millerjo@us.ibm.com>
Cc: <stable@vger.kernel.org>

diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 3e4c4ed..88ac0ee 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1230,6 +1230,7 @@ void flush_hash_page(unsigned long vpn, real_pte_t pte, int psize, int ssize,
 	 * unmapping it first, it may see the speculated version.
 	 */
 	if (local && cpu_has_feature(CPU_FTR_TM) &&
+	    current->thread.regs &&
 	    MSR_TM_ACTIVE(current->thread.regs->msr)) {
 		tm_enable();
 		tm_abort(TM_CAUSE_TLBI);

^ permalink raw reply related

* Re: [PATCH net-next] af_unix: fix a fatal race with bit fields
From: Alan Modra @ 2013-05-03  1:31 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: netdev, Ambrose Feinstein, Paul Mackerras, Anton Blanchard,
	linuxppc-dev, David Miller
In-Reply-To: <1367384672.11020.34.camel@edumazet-glaptop>

On Tue, Apr 30, 2013 at 10:04:32PM -0700, Eric Dumazet wrote:
> These kind of errors are pretty hard to find, its a pity to spend time
> on them.

Well, yes.  From the first comment in gcc PR52080.  "For the following
testcase we generate a 8 byte RMW cycle on IA64 which causes locking
problems in the linux kernel btrfs filesystem."

Did someone fix btrfs, but not check other kernel locks?  Having now
hit the same problem again, have you checked that other kernel locks
don't have adjacent bit fields in the same 64-bit word?  And comment
the struct to ensure someone doesn't optimize those unsigned chars
back to bit fields.

-- 
Alan Modra
Australia Development Lab, IBM

^ permalink raw reply

* Re: [PATCH net-next] af_unix: fix a fatal race with bit fields
From: Benjamin Herrenschmidt @ 2013-05-02 21:11 UTC (permalink / raw)
  To: Stephen Hemminger
  Cc: Eric Dumazet, Alan Modra, netdev, Ambrose Feinstein,
	Paul Mackerras, Anton Blanchard, linuxppc-dev, David Miller
In-Reply-To: <20130501081054.267a7851@nehalam.linuxnetplumber.net>

On Wed, 2013-05-01 at 08:10 -0700, Stephen Hemminger wrote:
> > These kind of errors are pretty hard to find, its a pity to spend
> time
> > on them.
> 
> There is a checkbin target inside arch/powerpc/Makefile
> Shouldn't a check be added there to block building kernel with known
> bad GCC versions?

In this case that makes it all GCC versions except the *very
latest* .... not practical.

I suppose we should try to make sure that at least the next batch of
enterprise distro get that fix on gcc side.

Ben.

^ permalink raw reply

* Re: pci overmapping
From: Scott Wood @ 2013-05-02 18:19 UTC (permalink / raw)
  To: Sethi Varun-B16395
  Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org,
	Yoder Stuart-B08248
In-Reply-To: <C5ECD7A89D1DC44195F34B25E172658D4D3E5A@039-SN2MPN1-011.039d.mgd.msft.net>

On 05/02/2013 01:09:53 PM, Sethi Varun-B16395 wrote:
>=20
>=20
> > -----Original Message-----
> > From: Wood Scott-B07421
> > Sent: Thursday, May 02, 2013 10:44 PM
> > To: Yoder Stuart-B08248
> > Cc: galak@kernel.crashing.org; Sethi Varun-B16395; linuxppc-
> > dev@lists.ozlabs.org
> > Subject: Re: pci overmapping
> >
> > On 05/02/2013 12:05:42 PM, Yoder Stuart-B08248 wrote:
> > > Kumar,
> > >
> > > In fsl_pci.c there is a change you made a while back:
> > >   "powerpc/fsl: Setup PCI inbound window based on actual amount of
> > > memory"
> > >
> > > ...and there is this comment in the code:
> > >
> > >     /* PCIe can overmap inbound & outbound since RX & TX are =20
> separated
> > > */
> > >     if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
> > >
> > > You are implying that PCIe can overmap and PCI can't.  Why is
> > > that?   (I'm assuming that 'overmap' means that inbound window
> > > can extend beyond the end of ram.)
> >
> > Shouldn't the concern be whether we're overlapping outbound, not =20
> merely
> > whether we go beyond the end of RAM?
> >
> > And couldn't inbound/outbound overlap be an issue even on PCIe, if
> > there's a PCI bridge underneath it?
> I believe that the overlap problem would be avoided in case of 36 bit =20
> physical support (outbound window address would be high order 36 bit =20
> value), right?

Not necessarily -- it depends on what the bus addresses are, not the =20
host addresses.

-Scott=

^ permalink raw reply

* RE: pci overmapping
From: Sethi Varun-B16395 @ 2013-05-02 18:09 UTC (permalink / raw)
  To: Wood Scott-B07421, Yoder Stuart-B08248; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <1367514839.24411.12@snotra>



> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Thursday, May 02, 2013 10:44 PM
> To: Yoder Stuart-B08248
> Cc: galak@kernel.crashing.org; Sethi Varun-B16395; linuxppc-
> dev@lists.ozlabs.org
> Subject: Re: pci overmapping
>=20
> On 05/02/2013 12:05:42 PM, Yoder Stuart-B08248 wrote:
> > Kumar,
> >
> > In fsl_pci.c there is a change you made a while back:
> >   "powerpc/fsl: Setup PCI inbound window based on actual amount of
> > memory"
> >
> > ...and there is this comment in the code:
> >
> >     /* PCIe can overmap inbound & outbound since RX & TX are separated
> > */
> >     if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
> >
> > You are implying that PCIe can overmap and PCI can't.  Why is
> > that?   (I'm assuming that 'overmap' means that inbound window
> > can extend beyond the end of ram.)
>=20
> Shouldn't the concern be whether we're overlapping outbound, not merely
> whether we go beyond the end of RAM?
>=20
> And couldn't inbound/outbound overlap be an issue even on PCIe, if
> there's a PCI bridge underneath it?
I believe that the overlap problem would be avoided in case of 36 bit physi=
cal support (outbound window address would be high order 36 bit value), rig=
ht?

-Varun

^ permalink raw reply

* [PATCH 3/3] powerpc/perf: Add e6500 PMU driver
From: Lijun Pan @ 2013-05-02 18:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Lijun.Pan
In-Reply-To: <1367518118-9721-1-git-send-email-Lijun.Pan@freescale.com>

e6500 core performance monitors has the following features:
- 6 performance monitor counters
- 512 events supported
- no threshold events

e6500 PMU has more specific events (Data L1 cache misses, Instruction L1
cache misses, etc ) than e500 PMU (which only had Data L1 cache reloads,
etc). Where available, the more specific events have been used which will
produce slightly different results than e500 PMU equivalents.

Based on work done by Priyanka Jain

Signed-off-by: Lijun Pan <Lijun.Pan@freescale.com>
---
 arch/powerpc/include/asm/reg_fsl_emb.h |    4 +-
 arch/powerpc/perf/Makefile             |    2 +-
 arch/powerpc/perf/e6500-pmu.c          |  120 ++++++++++++++++++++++++++++++++
 3 files changed, 124 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/perf/e6500-pmu.c

diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h
index c51d52e..0e3ddf5 100644
--- a/arch/powerpc/include/asm/reg_fsl_emb.h
+++ b/arch/powerpc/include/asm/reg_fsl_emb.h
@@ -34,8 +34,10 @@
 #define PMLCA_FCM1	0x10000000	/* Freeze when PMM==1 */
 #define PMLCA_FCM0	0x08000000	/* Freeze when PMM==0 */
 #define PMLCA_CE	0x04000000	/* Condition Enable */
+#define PMLCA_FGCS1	0x00000002	/* Freeze in guest state */
+#define PMLCA_FGCS0	0x00000001	/* Freeze in hypervisor state */
 
-#define PMLCA_EVENT_MASK 0x00ff0000	/* Event field */
+#define PMLCA_EVENT_MASK 0x01ff0000	/* Event field */
 #define PMLCA_EVENT_SHIFT	16
 
 #define PMRN_PMLCB0	0x110	/* PM Local Control B0 */
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile
index af3fac2..06dd8d5 100644
--- a/arch/powerpc/perf/Makefile
+++ b/arch/powerpc/perf/Makefile
@@ -8,7 +8,7 @@ obj64-$(CONFIG_PPC_PERF_CTRS)	+= power4-pmu.o ppc970-pmu.o power5-pmu.o \
 obj32-$(CONFIG_PPC_PERF_CTRS)	+= mpc7450-pmu.o
 
 obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o
-obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o
+obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o e6500-pmu.o
 
 obj-$(CONFIG_PPC64)		+= $(obj64-y)
 obj-$(CONFIG_PPC32)		+= $(obj32-y)
diff --git a/arch/powerpc/perf/e6500-pmu.c b/arch/powerpc/perf/e6500-pmu.c
new file mode 100644
index 0000000..cf6eab7
--- /dev/null
+++ b/arch/powerpc/perf/e6500-pmu.c
@@ -0,0 +1,120 @@
+/*
+ * Performance counter support for e6500 family processors.
+ *
+ * Author: Lijun Pan
+ * Based on Priyanka Jain's code
+ * Based on e500-pmu.c
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/string.h>
+#include <linux/perf_event.h>
+#include <asm/reg.h>
+#include <asm/cputable.h>
+
+/*
+ * Map of generic hardware event types to hardware events
+ * Zero if unsupported
+ */
+static int e6500_generic_events[] = {
+	[PERF_COUNT_HW_CPU_CYCLES] = 1,
+	[PERF_COUNT_HW_INSTRUCTIONS] = 2,
+	[PERF_COUNT_HW_CACHE_MISSES] = 221,
+	[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12,
+	[PERF_COUNT_HW_BRANCH_MISSES] = 15,
+};
+
+#define C(x)	PERF_COUNT_HW_CACHE_##x
+
+/*
+ * Table of generalized cache-related events.
+ * 0 means not supported, -1 means nonsensical, other values
+ * are event codes.
+ */
+static int e6500_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+	[C(L1D)] = {
+				/*RESULT_ACCESS		RESULT_MISS */
+		[C(OP_READ)] = {	27,		222	},
+		[C(OP_WRITE)] = {	28,		223	},
+		[C(OP_PREFETCH)] = {	29,		0	},
+	},
+	[C(L1I)] = {
+				/*RESULT_ACCESS		RESULT_MISS */
+		[C(OP_READ)] = {	2,		254	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	37,		0	},
+	},
+	/*
+	 * Assuming LL means L2, it's not a good match for this model.
+	 * It does not have separate read/write events (but it does have
+	 * separate instruction/data events).
+	 */
+	[C(LL)] = {
+				/*RESULT_ACCESS		RESULT_MISS */
+		[C(OP_READ)] = {	0,		0	},
+		[C(OP_WRITE)] = {	0,		0	},
+		[C(OP_PREFETCH)] = {	0,		0	},
+	},
+	/*
+	 * There are data/instruction MMU misses, but that's a miss on
+	 * the chip's internal level-one TLB which is probably not
+	 * what the user wants.  Instead, unified level-two TLB misses
+	 * are reported here.
+	 */
+	[C(DTLB)] = {
+				/*RESULT_ACCESS		RESULT_MISS */
+		[C(OP_READ)] = {	26,		66	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(BPU)] = {
+				/*RESULT_ACCESS		RESULT_MISS */
+		[C(OP_READ)] = {	12,		15	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+	[C(NODE)] = {		/* 	RESULT_ACCESS	RESULT_MISS */
+		[C(OP_READ)] = {	-1,		-1 	},
+		[C(OP_WRITE)] = {	-1,		-1	},
+		[C(OP_PREFETCH)] = {	-1,		-1	},
+	},
+};
+
+static int num_events = 512;
+
+/* Upper half of event id is PMLCb, for threshold events */
+static u64 e6500_xlate_event(u64 event_id)
+{
+	u32 event_low = (u32)event_id;
+	if (event_low >= num_events ||
+		(event_id & (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH)))
+		return 0;
+
+	return FSL_EMB_EVENT_VALID;
+}
+
+static struct fsl_emb_pmu e6500_pmu = {
+	.name			= "e6500 family",
+	.n_counter		= 6,
+	.n_restricted		= 0,
+	.xlate_event		= e6500_xlate_event,
+	.n_generic		= ARRAY_SIZE(e6500_generic_events),
+	.generic_events		= e6500_generic_events,
+	.cache_events		= &e6500_cache_events,
+};
+
+static int init_e6500_pmu(void)
+{
+	if (!cur_cpu_spec->oprofile_cpu_type ||
+		strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e6500"))
+		return -ENODEV;
+
+	return register_fsl_emb_pmu(&e6500_pmu);
+}
+
+early_initcall(init_e6500_pmu);
-- 
1.7.9.7

^ permalink raw reply related

* [PATCH 2/3] powerpc/perf: add 2 additional performance monitor counters for e6500 core
From: Lijun Pan @ 2013-05-02 18:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Lijun.Pan
In-Reply-To: <1367518118-9721-1-git-send-email-Lijun.Pan@freescale.com>

There are 6 counters in e6500 core instead of 4 in e500 core.

Signed-off-by: Lijun Pan <Lijun.Pan@freescale.com>
---
 arch/powerpc/include/asm/reg_fsl_emb.h   |   12 ++++++++++++
 arch/powerpc/kernel/cputable.c           |    2 +-
 arch/powerpc/oprofile/op_model_fsl_emb.c |   30 ++++++++++++++++++++++++++++++
 arch/powerpc/perf/core-fsl-emb.c         |   24 ++++++++++++++++++++++++
 4 files changed, 67 insertions(+), 1 deletion(-)

diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h
index 1cf8ab0..c51d52e 100644
--- a/arch/powerpc/include/asm/reg_fsl_emb.h
+++ b/arch/powerpc/include/asm/reg_fsl_emb.h
@@ -19,10 +19,14 @@
 #define PMRN_PMC1	0x011	/* Performance Monitor Counter 1 */
 #define PMRN_PMC2	0x012	/* Performance Monitor Counter 2 */
 #define PMRN_PMC3	0x013	/* Performance Monitor Counter 3 */
+#define PMRN_PMC4	0x014	/* Performance Monitor Counter 4 */
+#define PMRN_PMC5	0x015	/* Performance Monitor Counter 5 */
 #define PMRN_PMLCA0	0x090	/* PM Local Control A0 */
 #define PMRN_PMLCA1	0x091	/* PM Local Control A1 */
 #define PMRN_PMLCA2	0x092	/* PM Local Control A2 */
 #define PMRN_PMLCA3	0x093	/* PM Local Control A3 */
+#define PMRN_PMLCA4	0x094	/* PM Local Control A4 */
+#define PMRN_PMLCA5	0x095	/* PM Local Control A5 */
 
 #define PMLCA_FC	0x80000000	/* Freeze Counter */
 #define PMLCA_FCS	0x40000000	/* Freeze in Supervisor */
@@ -38,6 +42,8 @@
 #define PMRN_PMLCB1	0x111	/* PM Local Control B1 */
 #define PMRN_PMLCB2	0x112	/* PM Local Control B2 */
 #define PMRN_PMLCB3	0x113	/* PM Local Control B3 */
+#define PMRN_PMLCB4	0x114	/* PM Local Control B4 */
+#define PMRN_PMLCB5	0x115	/* PM Local Control B5 */
 
 #define PMLCB_THRESHMUL_MASK	0x0700	/* Threshold Multiple Field */
 #define PMLCB_THRESHMUL_SHIFT	8
@@ -57,14 +63,20 @@
 #define PMRN_UPMC1	0x001	/* User Performance Monitor Counter 1 */
 #define PMRN_UPMC2	0x002	/* User Performance Monitor Counter 2 */
 #define PMRN_UPMC3	0x003	/* User Performance Monitor Counter 3 */
+#define PMRN_UPMC4	0x004	/* User Performance Monitor Counter 4 */
+#define PMRN_UPMC5	0x005	/* User Performance Monitor Counter 5 */
 #define PMRN_UPMLCA0	0x080	/* User PM Local Control A0 */
 #define PMRN_UPMLCA1	0x081	/* User PM Local Control A1 */
 #define PMRN_UPMLCA2	0x082	/* User PM Local Control A2 */
 #define PMRN_UPMLCA3	0x083	/* User PM Local Control A3 */
+#define PMRN_UPMLCA4	0x084	/* User PM Local Control A4 */
+#define PMRN_UPMLCA5	0x085	/* User PM Local Control A5 */
 #define PMRN_UPMLCB0	0x100	/* User PM Local Control B0 */
 #define PMRN_UPMLCB1	0x101	/* User PM Local Control B1 */
 #define PMRN_UPMLCB2	0x102	/* User PM Local Control B2 */
 #define PMRN_UPMLCB3	0x103	/* User PM Local Control B3 */
+#define PMRN_UPMLCB4	0x104	/* User PM Local Control B4 */
+#define PMRN_UPMLCB5	0x105	/* User PM Local Control B5 */
 #define PMRN_UPMGC0	0x180	/* User PM Global Control 0 */
 
 
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index cc39139..2d4eee2 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -2073,7 +2073,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
 			MMU_FTR_USE_TLBILX,
 		.icache_bsize		= 64,
 		.dcache_bsize		= 64,
-		.num_pmcs		= 4,
+		.num_pmcs		= 6,
 		.oprofile_cpu_type	= "ppc/e6500",
 		.oprofile_type		= PPC_OPROFILE_FSL_EMB,
 		.cpu_setup		= __setup_cpu_e6500,
diff --git a/arch/powerpc/oprofile/op_model_fsl_emb.c b/arch/powerpc/oprofile/op_model_fsl_emb.c
index ccc1daa..2a82d3e 100644
--- a/arch/powerpc/oprofile/op_model_fsl_emb.c
+++ b/arch/powerpc/oprofile/op_model_fsl_emb.c
@@ -46,6 +46,12 @@ static inline u32 get_pmlca(int ctr)
 		case 3:
 			pmlca = mfpmr(PMRN_PMLCA3);
 			break;
+		case 4:
+			pmlca = mfpmr(PMRN_PMLCA4);
+			break;
+		case 5:
+			pmlca = mfpmr(PMRN_PMLCA5);
+			break;
 		default:
 			panic("Bad ctr number\n");
 	}
@@ -68,6 +74,12 @@ static inline void set_pmlca(int ctr, u32 pmlca)
 		case 3:
 			mtpmr(PMRN_PMLCA3, pmlca);
 			break;
+		case 4:
+			mtpmr(PMRN_PMLCA4, pmlca);
+			break;
+		case 5:
+			mtpmr(PMRN_PMLCA5, pmlca);
+			break;
 		default:
 			panic("Bad ctr number\n");
 	}
@@ -84,6 +96,10 @@ static inline unsigned int ctr_read(unsigned int i)
 			return mfpmr(PMRN_PMC2);
 		case 3:
 			return mfpmr(PMRN_PMC3);
+		case 4:
+			return mfpmr(PMRN_PMC4);
+		case 5:
+			return mfpmr(PMRN_PMC5);
 		default:
 			return 0;
 	}
@@ -104,6 +120,12 @@ static inline void ctr_write(unsigned int i, unsigned int val)
 		case 3:
 			mtpmr(PMRN_PMC3, val);
 			break;
+		case 4:
+			mtpmr(PMRN_PMC4, val);
+			break;
+		case 5:
+			mtpmr(PMRN_PMC5, val);
+			break;
 		default:
 			break;
 	}
@@ -133,6 +155,14 @@ static void init_pmc_stop(int ctr)
 			mtpmr(PMRN_PMLCA3, pmlca);
 			mtpmr(PMRN_PMLCB3, pmlcb);
 			break;
+		case 4:
+			mtpmr(PMRN_PMLCA4, pmlca);
+			mtpmr(PMRN_PMLCB4, pmlcb);
+			break;
+		case 5:
+			mtpmr(PMRN_PMLCA5, pmlca);
+			mtpmr(PMRN_PMLCB5, pmlcb);
+			break;
 		default:
 			panic("Bad ctr number!\n");
 	}
diff --git a/arch/powerpc/perf/core-fsl-emb.c b/arch/powerpc/perf/core-fsl-emb.c
index 106c533..a81e666 100644
--- a/arch/powerpc/perf/core-fsl-emb.c
+++ b/arch/powerpc/perf/core-fsl-emb.c
@@ -70,6 +70,12 @@ static unsigned long read_pmc(int idx)
 	case 3:
 		val = mfpmr(PMRN_PMC3);
 		break;
+	case 4:
+		val = mfpmr(PMRN_PMC4);
+		break;
+	case 5:
+		val = mfpmr(PMRN_PMC5);
+		break;
 	default:
 		printk(KERN_ERR "oops trying to read PMC%d\n", idx);
 		val = 0;
@@ -95,6 +101,12 @@ static void write_pmc(int idx, unsigned long val)
 	case 3:
 		mtpmr(PMRN_PMC3, val);
 		break;
+	case 4:
+		mtpmr(PMRN_PMC4, val);
+		break;
+	case 5:
+		mtpmr(PMRN_PMC5, val);
+		break;
 	default:
 		printk(KERN_ERR "oops trying to write PMC%d\n", idx);
 	}
@@ -120,6 +132,12 @@ static void write_pmlca(int idx, unsigned long val)
 	case 3:
 		mtpmr(PMRN_PMLCA3, val);
 		break;
+	case 4:
+		mtpmr(PMRN_PMLCA4, val);
+		break;
+	case 5:
+		mtpmr(PMRN_PMLCA5, val);
+		break;
 	default:
 		printk(KERN_ERR "oops trying to write PMLCA%d\n", idx);
 	}
@@ -145,6 +163,12 @@ static void write_pmlcb(int idx, unsigned long val)
 	case 3:
 		mtpmr(PMRN_PMLCB3, val);
 		break;
+	case 4:
+		mtpmr(PMRN_PMLCB4, val);
+		break;
+	case 5:
+		mtpmr(PMRN_PMLCB5, val);
+		break;
 	default:
 		printk(KERN_ERR "oops trying to write PMLCB%d\n", idx);
 	}
-- 
1.7.9.7

^ permalink raw reply related

* [PATCH 1/3] powerpc/perf: correct typos in counter enumeration
From: Lijun Pan @ 2013-05-02 18:08 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Lijun.Pan

Signed-off-by: Lijun Pan <Lijun.Pan@freescale.com>
---
 arch/powerpc/include/asm/reg_fsl_emb.h |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/powerpc/include/asm/reg_fsl_emb.h b/arch/powerpc/include/asm/reg_fsl_emb.h
index 77bb71c..1cf8ab0 100644
--- a/arch/powerpc/include/asm/reg_fsl_emb.h
+++ b/arch/powerpc/include/asm/reg_fsl_emb.h
@@ -17,8 +17,8 @@
 /* Freescale Book E Performance Monitor APU Registers */
 #define PMRN_PMC0	0x010	/* Performance Monitor Counter 0 */
 #define PMRN_PMC1	0x011	/* Performance Monitor Counter 1 */
-#define PMRN_PMC2	0x012	/* Performance Monitor Counter 1 */
-#define PMRN_PMC3	0x013	/* Performance Monitor Counter 1 */
+#define PMRN_PMC2	0x012	/* Performance Monitor Counter 2 */
+#define PMRN_PMC3	0x013	/* Performance Monitor Counter 3 */
 #define PMRN_PMLCA0	0x090	/* PM Local Control A0 */
 #define PMRN_PMLCA1	0x091	/* PM Local Control A1 */
 #define PMRN_PMLCA2	0x092	/* PM Local Control A2 */
@@ -55,8 +55,8 @@
 
 #define PMRN_UPMC0	0x000	/* User Performance Monitor Counter 0 */
 #define PMRN_UPMC1	0x001	/* User Performance Monitor Counter 1 */
-#define PMRN_UPMC2	0x002	/* User Performance Monitor Counter 1 */
-#define PMRN_UPMC3	0x003	/* User Performance Monitor Counter 1 */
+#define PMRN_UPMC2	0x002	/* User Performance Monitor Counter 2 */
+#define PMRN_UPMC3	0x003	/* User Performance Monitor Counter 3 */
 #define PMRN_UPMLCA0	0x080	/* User PM Local Control A0 */
 #define PMRN_UPMLCA1	0x081	/* User PM Local Control A1 */
 #define PMRN_UPMLCA2	0x082	/* User PM Local Control A2 */
-- 
1.7.9.7

^ permalink raw reply related

* Re: [PATCH 1/1] powerpc: mpc512x_dma: add support for data transfers between memory and i/o memory
From: Vinod Koul @ 2013-05-02 17:14 UTC (permalink / raw)
  To: Alexander Popov; +Cc: linuxppc-dev, linux-kernel, Dan Williams
In-Reply-To: <1367407689-16252-1-git-send-email-a13xp0p0v88@gmail.com>

On Wed, May 01, 2013 at 03:28:09PM +0400, Alexander Popov wrote:
> The initial version of this driver supports only memory to memory
> data transfers.
> 
> Data transfers between memory and i/o memory require more delicate TCD
> (Transfer Control Descriptor) configuration and DMA channel service requests
> via hardware.
> 
> dma_device.device_control callback function is needed to configure
> DMA channel to work with i/o memory.
> 
> Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
> ---
>  drivers/dma/mpc512x_dma.c | 230 ++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 192 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
> index 2d95673..8aedff1 100644
> --- a/drivers/dma/mpc512x_dma.c
> +++ b/drivers/dma/mpc512x_dma.c
> @@ -2,6 +2,7 @@
>   * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
>   * Copyright (C) Semihalf 2009
>   * Copyright (C) Ilya Yanok, Emcraft Systems 2010
> + * Copyright (C) Alexander Popov, Promcontroller 2013
>   *
>   * Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
>   * (defines, structures and comments) was taken from MPC5121 DMA driver
> @@ -28,11 +29,6 @@
>   * file called COPYING.
>   */
>  
> -/*
> - * This is initial version of MPC5121 DMA driver. Only memory to memory
> - * transfers are supported (tested using dmatest module).
> - */
> -
>  #include <linux/module.h>
>  #include <linux/dmaengine.h>
>  #include <linux/dma-mapping.h>
> @@ -183,6 +179,8 @@ struct mpc_dma_desc {
>  
>  struct mpc_dma_chan {
>  	struct dma_chan			chan;
> +	enum dma_transfer_direction	dir;
> +	enum dma_slave_buswidth		slave_reg_width;
>  	struct list_head		free;
>  	struct list_head		prepared;
>  	struct list_head		queued;
> @@ -190,6 +188,7 @@ struct mpc_dma_chan {
>  	struct list_head		completed;
>  	struct mpc_dma_tcd		*tcd;
>  	dma_addr_t			tcd_paddr;
> +	u32				tcd_nunits;
>  
>  	/* Lock for this structure */
>  	spinlock_t			lock;
> @@ -268,7 +267,11 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan)
>  
>  	if (first != prev)
>  		mdma->tcd[cid].e_sg = 1;
> -	out_8(&mdma->regs->dmassrt, cid);
> +
> +	if (first->tcd->biter != 1) /* Request channel service by... */
> +		out_8(&mdma->regs->dmaserq, cid); /* hardware */
> +	else
> +		out_8(&mdma->regs->dmassrt, cid); /* software */
>  }
>  
>  /* Handle interrupt on one half of DMA controller (32 channels) */
> @@ -567,7 +570,42 @@ mpc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
>  	return ret;
>  }
>  
> -/* Prepare descriptor for memory to memory copy */
> +static int mpc_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
> +						unsigned long arg)
> +{
> +	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
> +	struct dma_slave_config *cfg = (void *)arg;
> +	int ret = 0;
> +
> +	if (!chan)
> +		return -EINVAL;
> +
> +	if (cmd == DMA_SLAVE_CONFIG && cfg) {
> +		if (cfg->direction == DMA_DEV_TO_MEM) {
> +			if (cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
> +				mchan->slave_reg_width = cfg->src_addr_width;
> +			else
> +				return -EINVAL;
> +			mchan->dir = DMA_DEV_TO_MEM;
> +			mchan->tcd_nunits = cfg->src_maxburst;
you need to save the slave addr too.

> +		} else if (cfg->direction == DMA_MEM_TO_DEV) {
> +			if (cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
> +				mchan->slave_reg_width = cfg->dst_addr_width;
> +			else
> +				return -EINVAL;
> +			mchan->dir = DMA_MEM_TO_DEV;
> +			mchan->tcd_nunits = cfg->dst_maxburst;
> +		} else {
> +			mchan->dir = DMA_MEM_TO_MEM;
> +			mchan->slave_reg_width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
> +			mchan->tcd_nunits = 0;
> +		}
> +	} else
> +		return -ENOSYS;
ENXIO?

while at it, consider a different way:

	if (cmd != DMA_SLAVE_CONFIG || !cfg)
		return -ENXIO;

then you can shift the sholw code one indent left, makes it look a little
better.

> +
> +	return ret;
> +}
> +
>  static struct dma_async_tx_descriptor *
>  mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
>  					size_t len, unsigned long flags)
> @@ -577,6 +615,7 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
>  	struct mpc_dma_desc *mdesc = NULL;
>  	struct mpc_dma_tcd *tcd;
>  	unsigned long iflags;
> +	u32 iter = 0;
>  
>  	/* Get free descriptor */
>  	spin_lock_irqsave(&mchan->lock, iflags);
> @@ -599,39 +638,153 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
>  	/* Prepare Transfer Control Descriptor for this transaction */
>  	memset(tcd, 0, sizeof(struct mpc_dma_tcd));
>  
> -	if (IS_ALIGNED(src | dst | len, 32)) {
> -		tcd->ssize = MPC_DMA_TSIZE_32;
> -		tcd->dsize = MPC_DMA_TSIZE_32;
> -		tcd->soff = 32;
> -		tcd->doff = 32;
> -	} else if (!mdma->is_mpc8308 && IS_ALIGNED(src | dst | len, 16)) {
> -		/* MPC8308 doesn't support 16 byte transfers */
> -		tcd->ssize = MPC_DMA_TSIZE_16;
> -		tcd->dsize = MPC_DMA_TSIZE_16;
> -		tcd->soff = 16;
> -		tcd->doff = 16;
> -	} else if (IS_ALIGNED(src | dst | len, 4)) {
> -		tcd->ssize = MPC_DMA_TSIZE_4;
> -		tcd->dsize = MPC_DMA_TSIZE_4;
> -		tcd->soff = 4;
> -		tcd->doff = 4;
> -	} else if (IS_ALIGNED(src | dst | len, 2)) {
> -		tcd->ssize = MPC_DMA_TSIZE_2;
> -		tcd->dsize = MPC_DMA_TSIZE_2;
> -		tcd->soff = 2;
> -		tcd->doff = 2;
> -	} else {
> -		tcd->ssize = MPC_DMA_TSIZE_1;
> -		tcd->dsize = MPC_DMA_TSIZE_1;
> -		tcd->soff = 1;
> -		tcd->doff = 1;
> -	}
> -
>  	tcd->saddr = src;
>  	tcd->daddr = dst;
> -	tcd->nbytes = len;
> -	tcd->biter = 1;
> -	tcd->citer = 1;
> +	if (mchan->dir == DMA_MEM_TO_MEM) {
> +		if (IS_ALIGNED(src | dst | len, 32)) {
> +			tcd->ssize = MPC_DMA_TSIZE_32;
> +			tcd->dsize = MPC_DMA_TSIZE_32;
> +			tcd->soff = 32;
> +			tcd->doff = 32;
> +		} else if (!mdma->is_mpc8308 &&
> +					IS_ALIGNED(src | dst | len, 16)) {
> +			/* MPC8308 doesn't support 16 byte transfers */
> +			tcd->ssize = MPC_DMA_TSIZE_16;
> +			tcd->dsize = MPC_DMA_TSIZE_16;
> +			tcd->soff = 16;
> +			tcd->doff = 16;
> +		} else if (IS_ALIGNED(src | dst | len, 4)) {
> +			tcd->ssize = MPC_DMA_TSIZE_4;
> +			tcd->dsize = MPC_DMA_TSIZE_4;
> +			tcd->soff = 4;
> +			tcd->doff = 4;
> +		} else if (IS_ALIGNED(src | dst | len, 2)) {
> +			tcd->ssize = MPC_DMA_TSIZE_2;
> +			tcd->dsize = MPC_DMA_TSIZE_2;
> +			tcd->soff = 2;
> +			tcd->doff = 2;
> +		} else {
> +			tcd->ssize = MPC_DMA_TSIZE_1;
> +			tcd->dsize = MPC_DMA_TSIZE_1;
> +			tcd->soff = 1;
> +			tcd->doff = 1;
> +		}
> +		tcd->nbytes = len;
> +		tcd->biter = 1;
> +		tcd->citer = 1;
> +	} else {
Nope!

This is mempcy and just does memcy and not io-transfers. You need to use
.device_prep_slave_sg() for below...
> +		/* Memory to io-memory transfer or vice versa.
> +		 * DMA controller is going to access io-memory via
> +		 * some FIFO data register. The width of this register
> +		 * is mchan->slave_reg_width.
> +		 *
> +		 * Since some FIFO registers require full width access,
> +		 * let's firmly set the corresponding transfer size
> +		 * to mchan->slave_reg_width
> +		 * and prohibit transfers of packets with a length
> +		 * which is not aligned on mchan->slave_reg_width boundaries
> +		 * to avoid Transfer Control Descriptor inconsistency.
> +		 * Moreover this will save us from playing with
> +		 * source and destination address modulo.
> +		 */
> +
> +		if (!IS_ALIGNED(len, mchan->slave_reg_width))
> +			return NULL;
> +
> +		if (mchan->dir == DMA_DEV_TO_MEM) {
> +			tcd->soff = 0;
> +			if (mchan->slave_reg_width ==
> +					DMA_SLAVE_BUSWIDTH_4_BYTES) {
> +				tcd->ssize = MPC_DMA_TSIZE_4;
> +				if (IS_ALIGNED(dst, 4)) {
> +					tcd->dsize = MPC_DMA_TSIZE_4;
> +					tcd->doff = 4;
> +				} else if (IS_ALIGNED(dst, 2)) {
> +					tcd->dsize = MPC_DMA_TSIZE_2;
> +					tcd->doff = 2;
> +				} else {
> +					tcd->dsize = MPC_DMA_TSIZE_1;
> +					tcd->doff = 1;
> +				}
1. this could use a handler and thus code can look better
2. consider switch for above logic
3. consider converting to TSIZE programatically

> +			} else if (mchan->slave_reg_width ==
> +					DMA_SLAVE_BUSWIDTH_2_BYTES) {
> +				tcd->ssize = MPC_DMA_TSIZE_2;
> +				if (IS_ALIGNED(dst, 2)) {
> +					tcd->dsize = MPC_DMA_TSIZE_2;
> +					tcd->doff = 2;
> +				} else {
> +					tcd->dsize = MPC_DMA_TSIZE_1;
> +					tcd->doff = 1;
> +				}
> +			} else if (mchan->slave_reg_width ==
> +					DMA_SLAVE_BUSWIDTH_1_BYTE) {
> +				tcd->ssize = MPC_DMA_TSIZE_1;
> +				tcd->dsize = MPC_DMA_TSIZE_1;
> +				tcd->doff = 1;
seems repeat of above and should be handled seprately in single place...

> +			} else
> +				return NULL;
> +		} else {
> +			tcd->doff = 0;
> +			if (mchan->slave_reg_width ==
> +					DMA_SLAVE_BUSWIDTH_4_BYTES) {
> +				tcd->dsize = MPC_DMA_TSIZE_4;
> +				if (IS_ALIGNED(src, 4)) {
> +					tcd->ssize = MPC_DMA_TSIZE_4;
> +					tcd->soff = 4;
> +				} else if (IS_ALIGNED(src, 2)) {
> +					tcd->ssize = MPC_DMA_TSIZE_2;
> +					tcd->soff = 2;
> +				} else {
> +					tcd->ssize = MPC_DMA_TSIZE_1;
> +					tcd->soff = 1;
> +				}
> +			} else if (mchan->slave_reg_width ==
> +					DMA_SLAVE_BUSWIDTH_2_BYTES) {
> +				tcd->dsize = MPC_DMA_TSIZE_2;
> +				if (IS_ALIGNED(src, 2)) {
> +					tcd->ssize = MPC_DMA_TSIZE_2;
> +					tcd->soff = 2;
> +				} else {
> +					tcd->ssize = MPC_DMA_TSIZE_1;
> +					tcd->soff = 1;
> +				}
> +			} else if (mchan->slave_reg_width ==
> +					DMA_SLAVE_BUSWIDTH_1_BYTE) {
> +				tcd->dsize = MPC_DMA_TSIZE_1;
> +				tcd->ssize = MPC_DMA_TSIZE_1;
> +				tcd->soff = 1;
> +			} else
> +				return NULL;
> +		}
> +
> +		if (mchan->tcd_nunits) {
> +			tcd->nbytes = mchan->tcd_nunits *
> +						mchan->slave_reg_width;
> +			if (!IS_ALIGNED(len, tcd->nbytes)) {
> +				/* mchan->tcd_nunits is inconsistent */
> +				return NULL;
> +			}
> +
> +			iter = len / tcd->nbytes;
> +			if (iter > ((1 << 15) - 1)) {	/* maximum biter */
> +				return NULL; /* len is too big */
> +			} else {
> +				tcd->biter = iter;
> +				tcd->biter_linkch = iter >> 9;
> +				tcd->citer = tcd->biter;
> +				tcd->citer_linkch = tcd->biter_linkch;
> +			}
> +
> +			/* DMA hardware should automatically clear
> +			 * the corresponding DMAERQ bit when
> +			 * the current major iteration count reaches zero. */
> +			tcd->d_req = 1;
> +		} else {
> +			tcd->nbytes = len;
> +			tcd->biter = 1;
> +			tcd->citer = 1;
> +		}
> +	}

--
~Vinod

^ permalink raw reply

* Re: pci overmapping
From: Scott Wood @ 2013-05-02 17:13 UTC (permalink / raw)
  To: Yoder Stuart-B08248; +Cc: Sethi Varun-B16395, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <9F6FE96B71CF29479FF1CDC8046E15035C8E18@039-SN1MPN1-002.039d.mgd.msft.net>

On 05/02/2013 12:05:42 PM, Yoder Stuart-B08248 wrote:
> Kumar,
>=20
> In fsl_pci.c there is a change you made a while back:
>   "powerpc/fsl: Setup PCI inbound window based on actual amount of =20
> memory"
>=20
> ...and there is this comment in the code:
>=20
>     /* PCIe can overmap inbound & outbound since RX & TX are =20
> separated */
>     if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
>=20
> You are implying that PCIe can overmap and PCI can't.  Why is
> that?   (I'm assuming that 'overmap' means that inbound window
> can extend beyond the end of ram.)

Shouldn't the concern be whether we're overlapping outbound, not merely =20
whether we go beyond the end of RAM?

And couldn't inbound/outbound overlap be an issue even on PCIe, if =20
there's a PCI bridge underneath it?

-Scott=

^ permalink raw reply

* pci overmapping
From: Yoder Stuart-B08248 @ 2013-05-02 17:05 UTC (permalink / raw)
  To: galak@kernel.crashing.org
  Cc: Sethi Varun-B16395, linuxppc-dev@lists.ozlabs.org

Kumar,

In fsl_pci.c there is a change you made a while back:
  "powerpc/fsl: Setup PCI inbound window based on actual amount of memory"

...and there is this comment in the code:

    /* PCIe can overmap inbound & outbound since RX & TX are separated */
    if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {

You are implying that PCIe can overmap and PCI can't.  Why is
that?   (I'm assuming that 'overmap' means that inbound window
can extend beyond the end of ram.)

We are facing an issue for a non-PCI express controller (i.e. without
PCI_CAP_ID_EXP) emulated by QEMU.  In our case we need the ATMU
window to extend beyond the end of ram, since the window size has
to be a power of 2.

Thanks,
Stuart

^ permalink raw reply

* Re: [PATCH 2/2 V8] powerpc/85xx: Add machine check handler to fix PCIe erratum on mpc85xx
From: Scott Wood @ 2013-05-02 17:03 UTC (permalink / raw)
  To: Jia Hongtao; +Cc: B07421, hongtao.jia, linuxppc-dev
In-Reply-To: <1367126408-12997-2-git-send-email-hongtao.jia@freescale.com>

On 04/28/2013 12:20:08 AM, Jia Hongtao wrote:
> A PCIe erratum of mpc85xx may causes a core hang when a link of PCIe
> goes down. when the link goes down, Non-posted transactions issued
> via the ATMU requiring completion result in an instruction stall.
> At the same time a machine-check exception is generated to the core
> to allow further processing by the handler. We implements the handler
> which skips the instruction caused the stall.
>=20
> This patch depends on patch:
> powerpc/85xx: Add platform_device declaration to fsl_pci.h
>=20
> Signed-off-by: Zhao Chenhui <b35336@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> Signed-off-by: Liu Shuo <soniccat.liu@gmail.com>
> Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
> ---
> V8:
> * Add A variant load instruction emulation.

ACK

-Scott=

^ permalink raw reply

* Re: [PATCH net-next] af_unix: fix a fatal race with bit fields
From: Scott Wood @ 2013-05-02 17:02 UTC (permalink / raw)
  To: Alan Modra
  Cc: Eric Dumazet, netdev, Ambrose Feinstein, Paul Mackerras,
	Anton Blanchard, linuxppc-dev, David Miller
In-Reply-To: <20130501035425.GD5221@bubble.grove.modra.org>

On 04/30/2013 10:54:25 PM, Alan Modra wrote:
> On Tue, Apr 30, 2013 at 07:24:20PM -0700, Eric Dumazet wrote:
> > 	li 11,1
> > 	ld 0,0(9)
> > 	rldimi 0,11,31,32
> > 	std 0,0(9)
> > 	blr
> > 	.ident	"GCC: (GNU) 4.6.3"
> >
> > You can see "ld 0,0(9)" is used : its a 64 bit load.
>=20
> Yup.  This is not a powerpc64 specific problem.  See
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D52080
> Fixed in 4.8.0 and 4.7.3.

FWIW (especially if a GCC version check is added), it seems to have =20
been fixed as far back as 4.7.1, not just 4.7.3.

-Scott=

^ permalink raw reply

* [PATCH 2/2] powerpc/512x: DMA via LocalPlus Bus testing driver
From: Alexander Popov @ 2013-05-02 15:23 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, Anatolij Gustschin,
	Grant Likely, Rob Herring, Timur Tabi, Arnd Bergmann,
	Greg Kroah-Hartman
  Cc: devicetree-discuss, linuxppc-dev, linux-kernel

This module tests Direct Memory Access to some device on LocalPlus Bus
for Freescale MPC512x. In other words it tests the bundle
of mpc512x_lpbfifo and mpc512x_dma drivers.

This testing driver was multiply used with static RAM (CY62167EV30LL-45ZXI)
which lives on LocalPlus Bus on our board. This testing driver was used
instead of the original static RAM driver and it is an abnormal hack.
That is why I just provide the driver code and don't modify any environment.

Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
 drivers/misc/mpc512x_lpbdma_test.c | 310 +++++++++++++++++++++++++++++++++++++
 1 file changed, 310 insertions(+)
 create mode 100644 drivers/misc/mpc512x_lpbdma_test.c

diff --git a/drivers/misc/mpc512x_lpbdma_test.c b/drivers/misc/mpc512x_lpbdma_test.c
new file mode 100644
index 0000000..4fdd052
--- /dev/null
+++ b/drivers/misc/mpc512x_lpbdma_test.c
@@ -0,0 +1,310 @@
+/*
+ * Tests for DMA via LocalPlus Bus for the Freescale MPC512x.
+ *
+ * Copyright (C) Promcontroller, 2013.
+ * Author is Alexander Popov <a13xp0p0v88@gmail.com>.
+ *
+ * This module tests Direct Memory Access to the devices on LocalPlus Bus.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/string.h>
+#include <asm/mpc5121.h>
+
+MODULE_AUTHOR("Alexander Popov <a13xp0p0v88@gmail.com>");
+MODULE_LICENSE("GPL");
+
+#define DRV_NAME "mpc512x_lpbdma_test"
+#define ENOUGH 131072
+
+static int repeat = 1;
+
+enum test_iteration_result {
+	NEXT_TEST_PLEASE,
+	TRANSFER_LAUNCHED,
+	ALL_TESTS_DONE,
+};
+
+static struct lpbdma_test_data {
+	struct device *dev;
+	struct resource r_io;
+	void __iomem *bus_vaddr;
+	void *ram_vaddr;
+
+	/* Current data */
+	int current_repeat;
+	int current_test_case;
+	enum mpc512x_lpbfifo_req_dir current_dir;
+	struct mpc512x_lpbfifo_request current_req;
+} tt;
+
+static void lpbdma_prepare_next_iteration(void);
+static void lpbdma_testing(struct work_struct *w);
+static void lpbdma_test_callback(struct mpc512x_lpbfifo_request *req);
+static enum test_iteration_result lpbdma_test_iteration(unsigned int test_case,
+					enum mpc512x_lpbfifo_req_dir dir);
+
+static DECLARE_WORK(lpbdma_work, lpbdma_testing);
+static struct workqueue_struct *wq;
+
+static void lpbdma_prepare_next_iteration(void)
+{
+	tt.current_repeat++;
+
+	if (tt.current_repeat > repeat) {
+		tt.current_repeat = 1;
+		if (tt.current_dir == MPC512X_LPBFIFO_REQ_DIR_READ)
+			tt.current_dir = MPC512X_LPBFIFO_REQ_DIR_WRITE;
+		else {
+			tt.current_dir = MPC512X_LPBFIFO_REQ_DIR_READ;
+			tt.current_test_case += 1;
+		}
+	}
+}
+
+static void lpbdma_testing(struct work_struct *w)
+{
+	lpbdma_prepare_next_iteration();
+	while (lpbdma_test_iteration(tt.current_test_case,
+				tt.current_dir) == NEXT_TEST_PLEASE) {
+		lpbdma_prepare_next_iteration();
+	}
+}
+
+static enum test_iteration_result lpbdma_test_iteration(unsigned int test_case,
+					enum mpc512x_lpbfifo_req_dir dir)
+{
+	struct mpc512x_lpbfifo_request *req = &(tt.current_req);
+	int will_work;
+	unsigned int i;
+	unsigned int bufn;
+	u16 buf;
+
+	/* Prepare request for data transfer */
+	req->cs = 0;
+	req->bus_phys = tt.r_io.start;
+	req->ram_virt = tt.ram_vaddr;
+	req->dir = dir;
+	req->callback = lpbdma_test_callback;
+
+	switch (test_case) {
+	case 0:
+		/* normal LPB_DEV <-> RAM transfer */
+		will_work = 1;
+		req->size = 32768;	/* 32 kBytes, for example */
+		req->portsize = LPB_DEV_PORTSIZE_UNDEFINED;
+		break;
+	case 1:
+		/* maximum size transfer */
+		will_work = 1;
+		req->size = 131068;	/* 128 kBytes - 4 Bytes */
+		req->portsize = LPB_DEV_PORTSIZE_UNDEFINED;
+		break;
+	case 2:
+		/* maximum transfer size is exceeded */
+		will_work = 0;
+		req->size = 133120;	/* 130 kBytes, for example */
+		req->portsize = LPB_DEV_PORTSIZE_UNDEFINED;
+		break;
+	case 3:
+		/* LPB_DEV has own FIFO register
+		 * It's width is 8 bytes, for example */
+		will_work = 1;
+		req->size = 16384;	/* 16 kBytes, for example */
+		req->portsize = LPB_DEV_PORTSIZE_8_BYTES;
+		break;
+	case 4:
+		/* Ditto. But size is not aligned on portsize */
+		will_work = 0;
+		req->size = 16382;
+		req->portsize = LPB_DEV_PORTSIZE_8_BYTES;
+		break;
+	case 5:
+		/* size is not aligned on 4 */
+		will_work = 0;
+		req->size = 42;		/* eh! */
+		req->portsize = LPB_DEV_PORTSIZE_UNDEFINED;
+		break;
+	case 6:
+		/* ram address is not aligned on 4
+		 * but is aligned on 2 */
+		will_work = 1;
+		req->ram_virt += 2;
+		req->size = 65536;	/* 64 kBytes, for example */
+		req->portsize = LPB_DEV_PORTSIZE_UNDEFINED;
+		break;
+	case 7:
+		/* ram address is not aligned even on 2 */
+		will_work = 1;
+		req->ram_virt += 3;
+		req->size = 8192;	/* 8 kBytes, for example */
+		req->portsize = LPB_DEV_PORTSIZE_UNDEFINED;
+		break;
+	default:
+		dev_info(tt.dev, "All tests are done\n");
+		return ALL_TESTS_DONE;
+	}
+
+	if (will_work) {
+		/* prepare source data */
+		if (dir == MPC512X_LPBFIFO_REQ_DIR_READ) {
+			if (req->portsize == LPB_DEV_PORTSIZE_UNDEFINED)
+				bufn = req->size / sizeof(buf);
+			else
+				bufn = req->portsize / sizeof(buf);
+
+			for (i = 0; i < bufn; i++) {
+				get_random_bytes(&buf, sizeof(buf));
+				out_be16(tt.bus_vaddr + i * sizeof(buf), buf);
+			}
+		} else
+			get_random_bytes(req->ram_virt, req->size);
+	}
+
+	if (mpc512x_lpbfifo_submit(req)) {
+		/* submit failed */
+		if (!will_work)
+			dev_info(tt.dev, "Test %u.%i passed\n", test_case, dir);
+		else
+			dev_err(tt.dev, "TEST %u.%i FAILED\n", test_case, dir);
+		return NEXT_TEST_PLEASE;
+	} else {
+		/* Request is submitted. Let's wait
+		 * for lpbdma_test_callback() to be called */
+		dev_info(tt.dev, "Test %u.%i is launched\n", test_case, dir);
+		return TRANSFER_LAUNCHED;
+	}
+}
+
+static void lpbdma_test_callback(struct mpc512x_lpbfifo_request *req)
+{
+	int test_passed = 1;
+	int i = 0;
+	u16 val1, val2;
+
+	if (req->portsize != LPB_DEV_PORTSIZE_UNDEFINED &&
+		req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE) {
+		/* During that transfer the next portion of data
+		 * overwrites the previous one.
+		 * Let's check the last portion of data */
+
+		for (i = 0; i < req->portsize / sizeof(val1); i++) {
+			val1 = in_be16(tt.bus_vaddr + i * sizeof(val1));
+			/* Since req->ram_virt
+			 * might not be aligned: */
+			memcpy(&val2, req->ram_virt + req->size -
+					req->portsize + i * sizeof(val2),
+								sizeof(val2));
+			if (val1 != val2) {
+				test_passed = 0;
+				dev_err(tt.dev, "ERROR: %i: %x != %x\n",
+							i, val2, val1);
+			}
+		}
+	} else {
+		for (i = 0; i < req->size / sizeof(val1); i++) {
+			if (req->portsize != LPB_DEV_PORTSIZE_UNDEFINED) {
+				val1 = in_be16(tt.bus_vaddr +
+					i * sizeof(val1) % req->portsize);
+			} else
+				val1 = in_be16(tt.bus_vaddr + i * sizeof(val1));
+
+			/* Ditto */
+			memcpy(&val2, req->ram_virt + i * sizeof(val2),
+							sizeof(val2));
+
+			if (val1 != val2) {
+				test_passed = 0;
+				dev_err(tt.dev, "ERROR: %i: %x != %x\n",
+							i, val2, val1);
+			}
+		}
+	}
+
+	if (test_passed)
+		dev_info(tt.dev, "...Passed\n");
+	else
+		dev_err(tt.dev, "...FAILED\n");
+
+	/* Next test please */
+	if (wq)
+		queue_work(wq, &lpbdma_work);
+}
+
+static int mpc512x_lpbdma_test_probe(struct platform_device *pdev)
+{
+	struct resource *rio_ptr = &tt.r_io;
+	tt.dev = &pdev->dev;
+
+	if (of_address_to_resource(pdev->dev.of_node, 0, rio_ptr)) {
+		dev_err(tt.dev, "can't find the resource\n");
+		return 1;
+	}
+	dev_info(tt.dev, "Resource on LPB: 0x%x, size %u bytes\n",
+				rio_ptr->start, resource_size(rio_ptr));
+
+	if (!request_mem_region(rio_ptr->start,
+					resource_size(rio_ptr), DRV_NAME)) {
+		dev_err(tt.dev, "can't request_mem_region\n");
+		return 1;
+	}
+
+	tt.bus_vaddr = ioremap(rio_ptr->start, resource_size(rio_ptr));
+	if (!tt.bus_vaddr) {
+		dev_err(tt.dev, "ioremap failed\n");
+		release_mem_region(rio_ptr->start, resource_size(rio_ptr));
+		return 1;
+	}
+
+	tt.ram_vaddr = kmalloc(ENOUGH, GFP_DMA | GFP_KERNEL);
+
+	dev_info(tt.dev, "Let's go!\n");
+
+	tt.current_repeat = 0;
+	tt.current_test_case = 0;
+	tt.current_dir = MPC512X_LPBFIFO_REQ_DIR_READ;
+
+	wq = create_singlethread_workqueue("mpc512x_lpbdma_test");
+	if (wq)
+		queue_work(wq, &lpbdma_work);
+
+	return 0;
+}
+
+static int mpc512x_lpbdma_test_remove(struct platform_device *pdev)
+{
+	if (wq)
+		destroy_workqueue(wq);
+
+	release_mem_region(tt.r_io.start, resource_size(&tt.r_io));
+	iounmap(tt.bus_vaddr);
+	kfree(tt.ram_vaddr);
+	return 0;
+}
+
+static const struct of_device_id lpbdma_test_match[] = {
+	{ .compatible = "tecon,mpc512x_lpbdma_test", },
+	{},
+};
+
+static struct platform_driver mpc512x_lpbdma_test_driver = {
+	.probe = mpc512x_lpbdma_test_probe,
+	.remove = mpc512x_lpbdma_test_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = lpbdma_test_match,
+	},
+};
+module_platform_driver(mpc512x_lpbdma_test_driver);
+
+module_param(repeat, int, 0);
-- 
1.7.11.3

^ permalink raw reply related

* Re: [PATCHv4 1/2] ppc64: perform proper max_bus_speed detection
From: Kleber Sacilotto de Souza @ 2013-05-02 15:21 UTC (permalink / raw)
  To: tony
  Cc: David Airlie, Brian King, dri-devel, Alex Deucher, Jerome Glisse,
	Thadeu Lima de Souza Cascardo, Bjorn Helgaas, linuxppc-dev
In-Reply-To: <51796928.2050406@linux.vnet.ibm.com>

On 04/25/2013 02:34 PM, Lucas Kannebley Tavares wrote:
> On 04/24/2013 08:48 PM, Tony Breeds wrote:
>>> diff --git a/arch/powerpc/platforms/pseries/pci.c
>>> b/arch/powerpc/platforms/pseries/pci.c
>>> index 0b580f4..7f9c956 100644
>>> --- a/arch/powerpc/platforms/pseries/pci.c
>>> +++ b/arch/powerpc/platforms/pseries/pci.c
>>> @@ -108,3 +108,54 @@ static void fixup_winbond_82c105(struct pci_dev*
>>> dev)
>>>   }
>>>   DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND,
>>> PCI_DEVICE_ID_WINBOND_82C105,
>>>                fixup_winbond_82c105);
>>> +
>>> +int pseries_root_bridge_prepare(struct pci_host_bridge *bridge)
>>> +{
>>> +    struct device_node *dn, *pdn;
>>> +    struct pci_bus *bus;
>>> +    const uint32_t *pcie_link_speed_stats;
>>> +
>>> +    bus = bridge->bus;
>>> +
>>> +    dn = pcibios_get_phb_of_node(bus);
>>> +    if (!dn)
>>> +        return 0;
>>> +
>>> +    for (pdn = dn; pdn != NULL; pdn = pdn->parent) {
>>> +        pcie_link_speed_stats = (const uint32_t *) of_get_property(dn,
>>> +            "ibm,pcie-link-speed-stats", NULL);
>>> +        if (pcie_link_speed_stats)
>>> +            break;
>>> +    }
>>
>> Please use the helpers in include/linux/of.h rather than open coding
>> this.
>>
>> Yours Tony
> 
> 
> Hi Tony,
> 
> 
> This is what I can find as an equivalent code:
> 
>     for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
>         pcie_link_speed_stats = (const uint32_t *)
>             of_get_property(dn,
>                 "ibm,pcie-link-speed-stats", NULL);
>         if (pcie_link_speed_stats)
>             break;
>     }
> 
> is this your suggestion, or was it another approach that will have the
> same result?
> 
> Thanks,
> 

Hi Tony,

It seems Lucas' change is a bit incomplete and is not handling the reference counter to
the device_node correctly. Is the following change what you had in mind?


	dn = pcibios_get_phb_of_node(bus);
	if (!dn)
		return 0;

	for (pdn = dn; pdn != NULL; pdn = of_get_next_parent(pdn)) {
		pcie_link_speed_stats = (const uint32_t *) of_get_property(pdn,
			"ibm,pcie-link-speed-stats", NULL);
		if (pcie_link_speed_stats)
			break;
	}

	of_node_put(pdn);


Thanks,

-- 
Kleber Sacilotto de Souza
IBM Linux Technology Center

^ permalink raw reply

* [PATCH 1/2] powerpc/512x: add LocalPlus Bus FIFO device driver
From: Alexander Popov @ 2013-05-02 15:21 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, Anatolij Gustschin,
	Grant Likely, Rob Herring, Timur Tabi
  Cc: devicetree-discuss, linuxppc-dev, linux-kernel

This is SCLPC device driver for the Freescale MPC512x.
It is needed for Direct Memory Access to the devices on LocalPlus Bus.

Signed-off-by: Alexander Popov <a13xp0p0v88@gmail.com>
---
 arch/powerpc/boot/dts/mpc5121.dtsi            |   8 +-
 arch/powerpc/include/asm/mpc5121.h            |  32 ++
 arch/powerpc/platforms/512x/Kconfig           |   6 +
 arch/powerpc/platforms/512x/Makefile          |   1 +
 arch/powerpc/platforms/512x/mpc512x_lpbfifo.c | 493 ++++++++++++++++++++++++++
 5 files changed, 539 insertions(+), 1 deletion(-)
 create mode 100644 arch/powerpc/platforms/512x/mpc512x_lpbfifo.c

diff --git a/arch/powerpc/boot/dts/mpc5121.dtsi b/arch/powerpc/boot/dts/mpc5121.dtsi
index 723e292..6c4d551 100644
--- a/arch/powerpc/boot/dts/mpc5121.dtsi
+++ b/arch/powerpc/boot/dts/mpc5121.dtsi
@@ -259,7 +259,13 @@
 		/* LocalPlus controller */
 		lpc@10000 {
 			compatible = "fsl,mpc5121-lpc";
-			reg = <0x10000 0x200>;
+			reg = <0x10000 0x100>;
+		};
+
+		sclpc@10100 {
+			compatible = "fsl,mpc512x-lpbfifo";
+			reg = <0x10100 0x50>;
+			interrupts = <7 0x8>;
 		};
 
 		pata@10200 {
diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
index 885c040..5ed6a8e 100644
--- a/arch/powerpc/include/asm/mpc5121.h
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -70,4 +70,36 @@ struct mpc512x_lpc {
 int mpc512x_cs_config(unsigned int cs, u32 val);
 int __init mpc5121_clk_init(void);
 
+/*
+ * SCLPC Module (LPB FIFO)
+ */
+enum lpb_dev_portsize {
+	LPB_DEV_PORTSIZE_UNDEFINED = 0,
+	LPB_DEV_PORTSIZE_1_BYTE = 1,
+	LPB_DEV_PORTSIZE_2_BYTES = 2,
+	LPB_DEV_PORTSIZE_4_BYTES = 4,
+	LPB_DEV_PORTSIZE_8_BYTES = 8,
+};
+
+enum mpc512x_lpbfifo_req_dir {
+	MPC512X_LPBFIFO_REQ_DIR_READ,
+	MPC512X_LPBFIFO_REQ_DIR_WRITE,
+};
+
+struct mpc512x_lpbfifo_request {
+	unsigned int cs;
+	phys_addr_t bus_phys;	/* physical address of some device on lpb */
+	void *ram_virt;		/* virtual address of some region in ram */
+
+	/* Details of transfer */
+	u32 size;
+	enum lpb_dev_portsize portsize;
+	enum mpc512x_lpbfifo_req_dir dir;
+
+	/* Call when the transfer is finished */
+	void (*callback)(struct mpc512x_lpbfifo_request *);
+};
+
+extern int mpc512x_lpbfifo_submit(struct mpc512x_lpbfifo_request *req);
+
 #endif /* __ASM_POWERPC_MPC5121_H__ */
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 381a592..2e75d3c 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -10,6 +10,12 @@ config PPC_MPC512x
 	select USB_EHCI_BIG_ENDIAN_MMIO
 	select USB_EHCI_BIG_ENDIAN_DESC
 
+config PPC_MPC512x_LPBFIFO
+	tristate "MPC512x LocalPlus bus FIFO driver"
+	depends on PPC_MPC512x && MPC512X_DMA
+	help
+	  Enable support for the Freescale MPC512x SCLPC.
+
 config MPC5121_ADS
 	bool "Freescale MPC5121E ADS"
 	depends on PPC_MPC512x
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 4efc1c4..f2dc44e 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -2,6 +2,7 @@
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
 obj-y				+= clock.o mpc512x_shared.o
+obj-$(CONFIG_PPC_MPC512x_LPBFIFO) += mpc512x_lpbfifo.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC5121_GENERIC)	+= mpc5121_generic.o
 obj-$(CONFIG_PDM360NG)		+= pdm360ng.o
diff --git a/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c b/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c
new file mode 100644
index 0000000..7095e70
--- /dev/null
+++ b/arch/powerpc/platforms/512x/mpc512x_lpbfifo.c
@@ -0,0 +1,493 @@
+/*
+ * LocalPlus Bus SCLPC driver for the Freescale MPC512x.
+ *
+ * Copyright (C) Promcontroller, 2013.
+ *
+ * Author is Alexander Popov <a13xp0p0v88@gmail.com>.
+ *
+ * The driver design is based on mpc52xx_lpbfifo driver
+ * written by Grant Likely <grant.likely@secretlab.ca>.
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <asm/io.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <asm/mpc5121.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-direction.h>
+#include <linux/dma-mapping.h>
+
+MODULE_AUTHOR("Alexander Popov <a13xp0p0v88@gmail.com>");
+MODULE_DESCRIPTION("MPC512x LocalPlus FIFO device driver");
+MODULE_LICENSE("GPL");
+
+#define DRV_NAME "mpc512x_lpbfifo"
+
+#define LPBFIFO_REG_PACKET_SIZE		(0x00)
+#define LPBFIFO_REG_START_ADDRESS	(0x04)
+#define LPBFIFO_REG_CONTROL		(0x08)
+#define LPBFIFO_REG_ENABLE		(0x0C)
+#define LPBFIFO_REG_STATUS		(0x14)
+#define LPBFIFO_REG_BYTES_DONE		(0x18)
+#define LPBFIFO_REG_EMB_SHARE_COUNTER	(0x1C)
+#define LPBFIFO_REG_EMB_PAUSE_CONTROL	(0x20)
+#define LPBFIFO_REG_FIFO_DATA		(0x40)
+#define LPBFIFO_REG_FIFO_STATUS		(0x44)
+#define LPBFIFO_REG_FIFO_CONTROL	(0x48)
+#define LPBFIFO_REG_FIFO_ALARM		(0x4C)
+
+#define DMA_LPC_CHANNEL_NUMBER		26
+#define DEFAULT_WORDS_PER_TRANSFER	1
+
+static struct mpc512x_lpbfifo {
+	struct device *dev;
+	struct resource res;
+	void __iomem *regs;
+	int irq;
+	spinlock_t lock;
+
+	/* Current state data */
+	int im_last; /* For "last one out turns off the lights" principle */
+	struct mpc512x_lpbfifo_request *req;
+	dma_addr_t ram_bus_addr;
+	struct dma_chan *chan;
+} lpbfifo;
+
+/*
+ * Before we can wrap up handling current mpc512x_lpbfifo_request
+ * and execute the callback registered in it we should:
+ *  1. recognize that everything is really done,
+ *  2. free memory and dmaengine channel.
+ *
+ * Writing from RAM to registers of some device on LPB (transmit)
+ * is not really done until the LPB FIFO completion irq triggers.
+ *
+ * For being sure that writing from registers of some device on LPB
+ * to RAM (receive) is really done we should wait
+ * for mpc512x_lpbfifo_callback() to be called by DMA driver.
+ * In this case LPB FIFO completion irq will not appear at all.
+ *
+ * Moreover, freeing memory and dmaengine channel is not safe until
+ * mpc512x_lpbfifo_callback() is called.
+ *
+ * So to make it simple:
+ * last one out turns off the lights.
+ */
+
+/*
+ * mpc512x_lpbfifo_irq - IRQ handler for LPB FIFO
+ */
+static irqreturn_t mpc512x_lpbfifo_irq(int irq, void *dev_id)
+{
+	struct mpc512x_lpbfifo_request *req;
+	unsigned long flags;
+	u32 status;
+
+	spin_lock_irqsave(&lpbfifo.lock, flags);
+
+	req = lpbfifo.req;
+	if (!req) {
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+		pr_err("bogus LPBFIFO IRQ\n");
+		return IRQ_HANDLED;
+	}
+
+	if (req->dir == MPC512X_LPBFIFO_REQ_DIR_READ) {
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+		pr_err("bogus LPBFIFO IRQ (we are waiting DMA IRQ)\n");
+		return IRQ_HANDLED;
+	}
+
+	/* Clear the interrupt flag */
+	status = in_8(lpbfifo.regs + LPBFIFO_REG_STATUS);
+	if (status & 0x01)
+		out_8(lpbfifo.regs + LPBFIFO_REG_STATUS, 0x01);
+	else
+		out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
+
+	if (!lpbfifo.im_last) {
+		/*  I'm not the last: DMA is still in progress. */
+		lpbfifo.im_last = 1;
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+	} else {
+		/* I'm last. Let's wrap up. */
+		/* Set the FIFO as idle */
+		req = lpbfifo.req;
+		lpbfifo.req = NULL;
+
+		/* The spinlock must be dropped
+		 * before executing the callback,
+		 * otherwise we could end up with a deadlock
+		 * or nested spinlock condition. */
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+		if (req->callback)
+			req->callback(req);
+	}
+
+	return IRQ_HANDLED;
+}
+
+/*
+ * mpc512x_lpbfifo_callback is called by DMA driver
+ * when DMA transaction is finished.
+ */
+static void mpc512x_lpbfifo_callback(void *param)
+{
+	unsigned long flags;
+	struct mpc512x_lpbfifo_request *req;
+	enum dma_data_direction dir;
+
+	spin_lock_irqsave(&lpbfifo.lock, flags);
+
+	/* Free resources */
+	if (lpbfifo.req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE)
+		dir = DMA_TO_DEVICE;
+	else
+		dir = DMA_FROM_DEVICE;
+	dma_unmap_single(lpbfifo.chan->device->dev,
+			lpbfifo.ram_bus_addr, lpbfifo.req->size, dir);
+	dma_release_channel(lpbfifo.chan);
+
+	if (lpbfifo.req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE &&
+							!lpbfifo.im_last) {
+		/* I'm not the last: LPB FIFO is still writing data. */
+		lpbfifo.im_last = 1;
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+	} else {
+		/* I'm the last or alone here. Let's wrap up. */
+		/* Set the FIFO as idle */
+		req = lpbfifo.req;
+		lpbfifo.req = NULL;
+
+		/* The spinlock must be dropped
+		 * before executing the callback,
+		 * otherwise we could end up with a deadlock
+		 * or nested spinlock condition. */
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+		if (req->callback)
+			req->callback(req);
+	}
+}
+
+static bool channel_filter(struct dma_chan *chan, void *filter_param)
+{
+	if (chan->chan_id == DMA_LPC_CHANNEL_NUMBER)
+		return true;
+	else
+		return false;
+}
+
+static int mpc512x_lpbfifo_kick(struct mpc512x_lpbfifo_request *req)
+{
+	u32 bits;
+	int no_incr = 0;
+	u32 bpt;
+	dma_cap_mask_t cap_mask;
+	dma_filter_fn fn = channel_filter;
+	struct dma_device *dma_dev = NULL;
+	dma_addr_t dma_src_addr;
+	dma_addr_t dma_dst_addr;
+	struct dma_slave_config dma_conf = {};
+	struct dma_async_tx_descriptor *dma_tx = NULL;
+	dma_cookie_t cookie;
+	int e;
+
+	/* 1. Check requirements: */
+	/* Packet size must be a multiple of 4 bytes since
+	 * FIFO Data Word Register (which provides data to DMA controller)
+	 * allows only "full-word" (4 bytes) access
+	 * according Reference Manual */
+	if (!IS_ALIGNED(req->size, 4)) {
+		e = -EINVAL;
+		goto err_align;
+	}
+
+	/* Physical address of the device on LPB and packet size
+	 * must be aligned/multiple of BPT (bytes per transaction)
+	 * according Reference Manual */
+	if (req->portsize != LPB_DEV_PORTSIZE_UNDEFINED) {
+		bpt = req->portsize;
+		no_incr = 1;
+	} else
+		bpt = DEFAULT_WORDS_PER_TRANSFER << 2; /* makes life easier */
+
+	if (!IS_ALIGNED(req->bus_phys | req->size, bpt)) {
+			e = -EFAULT;
+			goto err_align;
+	}
+
+	/* 2. Prepare DMA */
+	dma_cap_zero(cap_mask);
+	dma_cap_set(DMA_MEMCPY, cap_mask);
+	lpbfifo.chan = dma_request_channel(cap_mask, fn, NULL);
+	dma_dev = lpbfifo.chan->device;
+
+	if (req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE) {
+		dma_conf.direction = DMA_MEM_TO_DEV;
+		dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+		/* We should limit the maximum number of words
+		 * (units with FIFO Data Register size)
+		 * that can be read from / written to the FIFO
+		 * in one DMA burst.
+		 * This measure and FIFO watermarks will prevent
+		 * DMA controller from overtaking FIFO
+		 * and causing FIFO underflow / overflow error. */
+		dma_conf.dst_maxburst = DEFAULT_WORDS_PER_TRANSFER;
+
+		dma_src_addr = dma_map_single(dma_dev->dev,
+				req->ram_virt, req->size, DMA_TO_DEVICE);
+		if (dma_mapping_error(dma_dev->dev, dma_src_addr)) {
+			pr_err("dma_mapping_error\n");
+			e = -EFAULT;
+			goto err_dma_map;
+		}
+		lpbfifo.ram_bus_addr = dma_src_addr; /* will free it later */
+
+		dma_dst_addr = lpbfifo.res.start + LPBFIFO_REG_FIFO_DATA;
+	} else {
+		dma_conf.direction = DMA_DEV_TO_MEM;
+		dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+		/* Ditto */
+		dma_conf.src_maxburst = DEFAULT_WORDS_PER_TRANSFER;
+
+		dma_src_addr = lpbfifo.res.start + LPBFIFO_REG_FIFO_DATA;
+
+		dma_dst_addr = dma_map_single(dma_dev->dev,
+				req->ram_virt, req->size, DMA_FROM_DEVICE);
+		if (dma_mapping_error(dma_dev->dev, dma_dst_addr)) {
+			pr_err("dma_mapping_error\n");
+			e = -EFAULT;
+			goto err_dma_map;
+		}
+		lpbfifo.ram_bus_addr = dma_dst_addr; /* Ditto */
+	}
+
+	/* Make DMA channel work with LPB FIFO data register */
+	if (dma_dev->device_control(lpbfifo.chan,
+				DMA_SLAVE_CONFIG, (unsigned long)&dma_conf)) {
+		goto err_dma_prep;
+	}
+
+	dma_tx = dma_dev->device_prep_dma_memcpy(lpbfifo.chan,
+		dma_dst_addr, dma_src_addr, req->size, DMA_PREP_INTERRUPT);
+	if (!dma_tx) {
+		pr_err("device_prep_dma_memcpy failed\n");
+		e = -ENOSPC;
+		goto err_dma_prep;
+	}
+
+	dma_tx->callback = mpc512x_lpbfifo_callback;
+	dma_tx->callback_param = NULL;
+
+	/* 3. Prepare FIFO */
+	/* Set and clear the reset bits;
+	 * is good practice in Reference Manual */
+	out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
+	out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x0);
+
+	/* Configure the watermarks.
+	 *
+	 * RAM->DMA->FIFO->LPB_DEV (write):
+	 *  High watermark (7 * 4) free bytes (according Reference Manual)
+	 *  Low watermark 996 bytes (whole FIFO - 28 bytes)
+	 *
+	 * LPB_DEV->FIFO->DMA->RAM (read):
+	 *  High watermark (1024 - 4) free bytes
+	 *   (whole FIFO - DEFAULT_WORDS_PER_TRANSFER)
+	 *  Low watermark 0 bytes
+	 */
+	if (req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE) {
+		out_be16(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 0x0700);
+		out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x000003e4);
+	} else {
+		out_be16(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 0x0);
+		out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x000003fc);
+	}
+
+	/* Start address is a physical address of the region
+	 * which belongs to the device on localplus bus */
+	out_be32(lpbfifo.regs + LPBFIFO_REG_START_ADDRESS, req->bus_phys);
+
+	/* Configure chip select, transfer direction,
+	 * address increment option and bytes per transfer option */
+	bits = (req->cs & 0x7) << 24;
+	if (req->dir == MPC512X_LPBFIFO_REQ_DIR_READ)
+		bits |= 3 << 16; /* read mode bit and flush bit */
+	if (no_incr)
+		bits |= 1 << 8;
+	bits |= bpt & 0x3f;
+	out_be32(lpbfifo.regs + LPBFIFO_REG_CONTROL, bits);
+
+	/* Unmask irqs */
+	bits = 0x00000201; /* set error irq & master enabled bit */
+	if (req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE)
+		bits |= 0x00000100; /* set completion irq too */
+	out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, bits);
+
+	/* 4. Set packet size and kick FIFO off */
+	bits = req->size;
+	bits |= (1<<31); /* set restart bit */
+	out_be32(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, bits);
+
+
+	/* 5. Then kick DMA off */
+	cookie = dma_tx->tx_submit(dma_tx);
+	if (dma_submit_error(cookie)) {
+		pr_err("DMA tx_submit failed\n");
+		e = -ENOSPC;
+		goto err_dma_submit;
+	}
+
+	return 0;
+
+ err_dma_submit:
+
+ err_dma_prep:
+	if (req->dir == MPC512X_LPBFIFO_REQ_DIR_WRITE) {
+		dma_unmap_single(dma_dev->dev, dma_src_addr,
+						req->size, DMA_TO_DEVICE);
+	} else {
+		dma_unmap_single(dma_dev->dev, dma_dst_addr,
+						req->size, DMA_FROM_DEVICE);
+	}
+
+ err_dma_map:
+	dma_release_channel(lpbfifo.chan);
+
+ err_align:
+	return e;
+}
+
+int mpc512x_lpbfifo_submit(struct mpc512x_lpbfifo_request *req)
+{
+	unsigned long flags;
+	int result = 0;
+
+	if (!lpbfifo.regs)
+		return -ENODEV;
+
+	spin_lock_irqsave(&lpbfifo.lock, flags);
+
+	/* A transfer is in progress
+	 * if the req pointer is already set */
+	if (lpbfifo.req) {
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+		return -EBUSY;
+	}
+
+	/* (128 kBytes - 4 Bytes) is a maximum packet size
+	 * that LPB FIFO and DMA controller can handle together
+	 * while exchanging DEFAULT_WORDS_PER_TRANSFER = 1
+	 * per hardware request */
+	if (req->size > 131068) {
+		spin_unlock_irqrestore(&lpbfifo.lock, flags);
+		return -ENOSPC;
+	}
+
+	/* Setup the transfer */
+	lpbfifo.im_last = 0;
+	lpbfifo.req = req;
+
+	result = mpc512x_lpbfifo_kick(req);
+	if (result != 0)
+		lpbfifo.req = NULL;	/* Set the FIFO as idle */
+
+	spin_unlock_irqrestore(&lpbfifo.lock, flags);
+
+	return result;
+}
+EXPORT_SYMBOL(mpc512x_lpbfifo_submit);
+
+static int mpc512x_lpbfifo_probe(struct platform_device *pdev)
+{
+	struct resource *r = &lpbfifo.res;
+	int e = 0, rc = -ENOMEM;
+
+	if (of_address_to_resource(pdev->dev.of_node, 0, r)) {
+		e = -ENODEV;
+		goto err_res;
+	}
+
+	if (!request_mem_region(r->start, resource_size(r), DRV_NAME)) {
+		e = -EBUSY;
+		goto err_res;
+	}
+
+	lpbfifo.irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+	if (!lpbfifo.irq) {
+		e = -ENODEV;
+		goto err_res;
+	}
+
+	lpbfifo.regs = ioremap(r->start, resource_size(r));
+	if (!lpbfifo.regs) {
+		e = -ENOMEM;
+		goto err_regs;
+	}
+
+	spin_lock_init(&lpbfifo.lock);
+
+	/* Put FIFO into reset state */
+	out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
+
+	lpbfifo.dev = &pdev->dev;
+
+	rc = request_irq(lpbfifo.irq,
+				mpc512x_lpbfifo_irq, 0, DRV_NAME, &lpbfifo);
+	if (rc) {
+		e = -ENODEV;
+		goto err_irq;
+	}
+
+	return 0;
+
+ err_irq:
+	iounmap(lpbfifo.regs);
+	lpbfifo.regs = NULL;
+
+ err_regs:
+	release_mem_region(r->start, resource_size(r));
+
+ err_res:
+	dev_err(&pdev->dev, "mpc512x_lpbfifo_probe() failed\n");
+	return e;
+}
+
+static int mpc512x_lpbfifo_remove(struct platform_device *pdev)
+{
+	/* Put FIFO in reset */
+	out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000);
+
+	free_irq(lpbfifo.irq, &lpbfifo);
+	iounmap(lpbfifo.regs);
+	release_mem_region(lpbfifo.res.start, resource_size(&lpbfifo.res));
+	lpbfifo.regs = NULL;
+	lpbfifo.dev = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id mpc512x_lpbfifo_match[] = {
+	{ .compatible = "fsl,mpc512x-lpbfifo", },
+	{},
+};
+
+static struct platform_driver mpc512x_lpbfifo_driver = {
+	.probe = mpc512x_lpbfifo_probe,
+	.remove = mpc512x_lpbfifo_remove,
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.of_match_table = mpc512x_lpbfifo_match,
+	},
+};
+module_platform_driver(mpc512x_lpbfifo_driver);
-- 
1.7.11.3

^ permalink raw reply related


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