LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2014-07-11  5:44 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linuxppc-dev, Linux Kernel list

Hi Linus !

Here are a few more powerpc fixes for 3.16

There's a small series of 3 patches that fix saving/restoring MMUCR2
when using KVM without which perf goes completely bonkers in the host
system. Another perf fix from Anton that's been rotting away in patchwork
due to my poor eyesight, a couple of compile fixes, a little addition
to the WSP removal by Michael (removing a bit more dead stuff) and
a fix for an embarassing regression with our soft irq masking.

Cheers,
Ben.

The following changes since commit 6663a4fa6711050036562ddfd2086edf735fae21:

  powerpc: Don't skip ePAPR spin-table CPUs (2014-06-25 13:10:49 +1000)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git merge

for you to fetch changes up to f56029410a13cae3652d1f34788045c40a13ffc7:

  powerpc/perf: Never program book3s PMCs with values >= 0x80000000 (2014-07-11 13:50:47 +1000)

----------------------------------------------------------------
Anton Blanchard (1):
      powerpc/perf: Never program book3s PMCs with values >= 0x80000000

Guenter Roeck (1):
      powerpc: Disable RELOCATABLE for COMPILE_TEST with PPC64

Joel Stanley (3):
      powerpc/kvm: Remove redundant save of SIER AND MMCR2
      powerpc/perf: Add PPMU_ARCH_207S define
      powerpc/perf: Clear MMCR2 when enabling PMU

Michael Ellerman (2):
      powerpc/cell: Fix compilation with CONFIG_COREDUMP=n
      powerpc: Clean up MMU_FTRS_A2 and MMU_FTR_TYPE_3E

Preeti U Murthy (1):
      powerpc/powernv: Check for IRQHAPPENED before sleeping

 arch/powerpc/Kconfig                         |  3 ++-
 arch/powerpc/include/asm/mmu.h               | 10 +---------
 arch/powerpc/include/asm/perf_event_server.h |  3 +--
 arch/powerpc/kernel/idle_power7.S            |  2 +-
 arch/powerpc/kvm/book3s_hv_interrupts.S      |  5 -----
 arch/powerpc/mm/mmu_context_nohash.c         | 12 +-----------
 arch/powerpc/perf/core-book3s.c              | 26 ++++++++++++++++++++++----
 arch/powerpc/perf/power8-pmu.c               |  2 +-
 arch/powerpc/platforms/cell/spu_syscalls.c   |  2 ++
 arch/powerpc/platforms/cell/spufs/Makefile   |  3 ++-
 arch/powerpc/platforms/cell/spufs/syscalls.c |  6 ++++--
 11 files changed, 37 insertions(+), 37 deletions(-)

^ permalink raw reply

* Re: [PATCH] powerpc/kvm: Create proper names for the kvm_host_state PMU fields
From: Michael Ellerman @ 2014-07-11  4:46 UTC (permalink / raw)
  To: Alexander Graf; +Cc: linuxppc-dev, Paul Mackerras, kvm
In-Reply-To: <53BE67EA.8000206@suse.de>

On Thu, 2014-07-10 at 12:16 +0200, Alexander Graf wrote:
> On 10.07.14 11:34, Michael Ellerman wrote:
> > We have two arrays in kvm_host_state that contain register values for
> > the PMU. Currently we only create an asm-offsets symbol for the base of
> > the arrays, and do the array offset in the assembly code.
> >
> > Creating an asm-offsets symbol for each field individually makes the
> > code much nicer to read, particularly for the MMCRx/SIxR/SDAR fields, and
> > might have helped us notice the recent double restore bug we had in this
> > code.
> >
> > Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
> 
> Acked-by: Alexander Graf <agraf@suse.de>

Thanks.

> I still think this whole code path should just be C though.

Yeah it probably should.

cheers

^ permalink raw reply

* Re: [PATCH tty-next 14/22] tty: Remove tty_wait_until_sent_from_close()
From: Greg Kroah-Hartman @ 2014-07-10 23:09 UTC (permalink / raw)
  To: Peter Hurley
  Cc: One Thousand Gnomes, Karsten Keil, linuxppc-dev, linux-kernel,
	linux-serial
In-Reply-To: <1402924639-5164-15-git-send-email-peter@hurleysoftware.com>

On Mon, Jun 16, 2014 at 09:17:11AM -0400, Peter Hurley wrote:
> tty_wait_until_sent_from_close() drops the tty lock while waiting
> for the tty driver to finish sending previously accepted data (ie.,
> data remaining in its write buffer and transmit fifo).
> 
> However, dropping the tty lock is a hold-over from when the tty
> lock was system-wide; ie., one lock for all ttys.
> 
> Since commit 89c8d91e31f267703e365593f6bfebb9f6d2ad01,
> 'tty: localise the lock', dropping the tty lock has not been necessary.
> 
> CC: Karsten Keil <isdn@linux-pingi.de>
> CC: linuxppc-dev@lists.ozlabs.org
> Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
> ---
>  drivers/isdn/i4l/isdn_tty.c   |  2 +-
>  drivers/tty/hvc/hvc_console.c |  2 +-
>  drivers/tty/hvc/hvcs.c        |  2 +-
>  drivers/tty/tty_port.c        | 11 ++---------
>  include/linux/tty.h           | 18 ------------------
>  5 files changed, 5 insertions(+), 30 deletions(-)

I've applied the first 13 patches in this series, as it looks like you
were going to split things up from here, right?  Can you refresh these
and resend when you have that done?

thanks,

greg k-h

^ permalink raw reply

* Re: [PATCH v2] powerpc/pseries: dynamically added OF nodes need to call of_node_init
From: Nathan Fontenot @ 2014-07-10 19:59 UTC (permalink / raw)
  To: Tyrel Datwyler, linuxppc-dev; +Cc: grant.likely, mdroth, stable
In-Reply-To: <1405018257-35616-1-git-send-email-tyreld@linux.vnet.ibm.com>

On 07/10/2014 01:50 PM, Tyrel Datwyler wrote:
> Commit 75b57ecf9 refactored device tree nodes to use kobjects such that they
> can be exposed via /sysfs. A secondary commit 0829f6d1f furthered this rework
> by moving the kobect initialization logic out of of_node_add into its own
> of_node_init function. The inital commit removed the existing kref_init calls
> in the pseries dlpar code with the assumption kobject initialization would
> occur in of_node_add. The second commit had the side effect of triggering a
> BUG_ON during DLPAR, migration and suspend/resume operations as a result of
> dynamically added nodes being uninitialized.
> 
> This patch fixes this by adding of_node_init calls in place of the previously
> removed kref_init calls.
> 
> Fixes: 0829f6d1f69e ("of: device_node kobject lifecycle fixes")
> Cc: stable@vger.kernel.org
> Signed-off-by: Tyrel Datwyler <tyreld@linux.vnet.ibm.com>

Acked-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>

> ---
> V2:
>  - included stable kernel list on Cc per comment by mpe
> 
>  arch/powerpc/platforms/pseries/dlpar.c    | 1 +
>  arch/powerpc/platforms/pseries/reconfig.c | 1 +
>  2 files changed, 2 insertions(+)
> 
> diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
> index 022b38e..2d0b4d6 100644
> --- a/arch/powerpc/platforms/pseries/dlpar.c
> +++ b/arch/powerpc/platforms/pseries/dlpar.c
> @@ -86,6 +86,7 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
>  	}
>  
>  	of_node_set_flag(dn, OF_DYNAMIC);
> +	of_node_init(dn);
>  
>  	return dn;
>  }
> diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
> index 0435bb6..1c0a60d 100644
> --- a/arch/powerpc/platforms/pseries/reconfig.c
> +++ b/arch/powerpc/platforms/pseries/reconfig.c
> @@ -69,6 +69,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
>  
>  	np->properties = proplist;
>  	of_node_set_flag(np, OF_DYNAMIC);
> +	of_node_init(np);
>  
>  	np->parent = derive_parent(path);
>  	if (IS_ERR(np->parent)) {
> 

^ permalink raw reply

* [PATCH v2] powerpc/pseries: dynamically added OF nodes need to call of_node_init
From: Tyrel Datwyler @ 2014-07-10 18:50 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: mdroth, stable, Tyrel Datwyler, grant.likely, nfont

Commit 75b57ecf9 refactored device tree nodes to use kobjects such that they
can be exposed via /sysfs. A secondary commit 0829f6d1f furthered this rework
by moving the kobect initialization logic out of of_node_add into its own
of_node_init function. The inital commit removed the existing kref_init calls
in the pseries dlpar code with the assumption kobject initialization would
occur in of_node_add. The second commit had the side effect of triggering a
BUG_ON during DLPAR, migration and suspend/resume operations as a result of
dynamically added nodes being uninitialized.

This patch fixes this by adding of_node_init calls in place of the previously
removed kref_init calls.

Fixes: 0829f6d1f69e ("of: device_node kobject lifecycle fixes")
Cc: stable@vger.kernel.org
Signed-off-by: Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
---
V2:
 - included stable kernel list on Cc per comment by mpe

 arch/powerpc/platforms/pseries/dlpar.c    | 1 +
 arch/powerpc/platforms/pseries/reconfig.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 022b38e..2d0b4d6 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -86,6 +86,7 @@ static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa,
 	}
 
 	of_node_set_flag(dn, OF_DYNAMIC);
+	of_node_init(dn);
 
 	return dn;
 }
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 0435bb6..1c0a60d 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -69,6 +69,7 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist
 
 	np->properties = proplist;
 	of_node_set_flag(np, OF_DYNAMIC);
+	of_node_init(np);
 
 	np->parent = derive_parent(path);
 	if (IS_ERR(np->parent)) {
-- 
1.7.12.4

^ permalink raw reply related

* Re: [PATCH] powerpc/pseries: dynamically added OF nodes need to call of_node_init
From: Tyrel Datwyler @ 2014-07-10 18:36 UTC (permalink / raw)
  To: Michael Ellerman; +Cc: grant.likely, nfont, linuxppc-dev
In-Reply-To: <1404959630.27178.1.camel@concordia>

On 07/09/2014 07:33 PM, Michael Ellerman wrote:
> On Wed, 2014-07-09 at 21:20 -0400, Tyrel Datwyler wrote:
>> Commit 75b57ecf9 refactored device tree nodes to use kobjects such that they
>> can be exposed via /sysfs. A secondary commit 0829f6d1f furthered this rework
>> by moving the kobect initialization logic out of of_node_add into its own
>> of_node_init function. The inital commit removed the existing kref_init calls
>> in the pseries dlpar code with the assumption kobject initialization would
>> occur in of_node_add. The second commit had the side effect of triggering a
>> BUG_ON as a result of dynamically added nodes being uninitialized.
> 
> So does this mean DLPAR is broken since 0829f6d1f (3.15-rc1)?

Yes, as well as suspend and migration.

> 
> If so this should have a Cc: stable@kernel.org shouldn't it?

Doh, right you are.

> 
> And the latest trend is to also add:
> 
> Fixes: 0829f6d1f69e ("of: device_node kobject lifecycle fixes")

Got it. Will resend v2.

-Tyrel

> 
> cheers
> 
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
> 

^ permalink raw reply

* Re: [PATCH 1/3] PCI/MSI: Add pci_enable_msi_partial()
From: Bjorn Helgaas @ 2014-07-10 17:02 UTC (permalink / raw)
  To: Alexander Gordeev
  Cc: linux-mips@linux-mips.org, linux-s390@vger.kernel.org,
	linux-pci@vger.kernel.org, x86@kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-ide@vger.kernel.org, open list:INTEL IOMMU (VT-d),
	xen-devel@lists.xenproject.org, linuxppc-dev
In-Reply-To: <20140710101151.GA21629@dhcp-26-207.brq.redhat.com>

On Thu, Jul 10, 2014 at 4:11 AM, Alexander Gordeev <agordeev@redhat.com> wrote:
> On Wed, Jul 09, 2014 at 10:06:48AM -0600, Bjorn Helgaas wrote:
>> Out of curiosity, do you have a pointer to this?  It looks like it
>
> I.e. ICH8 chapter 12.1.30 or ICH10 chapter 14.1.27
>
>> uses one vector per port, and I'm wondering if the reason it requests
>> 16 is because there's some possibility of a part with more than 8
>> ports.
>
> I doubt that is the reason. The only allowed MME values (powers of two)
> are 0b000, 0b001, 0b010 and 0b100. As you can see, only one bit is used -
> I would speculate it suits nicely to some hardware logic.
>
> BTW, apart from AHCI, it seems the reason MSI is not going to disappear
> (in a decade at least) is it is way cheaper to implement than MSI-X.
>
>> > No, this is not an erratum. The value of 8 vectors is reserved and could
>> > cause undefined results if used.
>>
>> As I read the spec (PCI 3.0, sec 6.8.1.3), if MMC contains 0b100
>> (requesting 16 vectors), the OS is allowed to allocate 1, 2, 4, 8, or
>> 16 vectors.  If allocating 8 vectors and writing 0b011 to MME causes
>> undefined results, I'd say that's a chipset defect.
>
> Well, the PCI spec does not prevent devices to have their own specs on top
> of it. Undefined results are meant on the device side here. On the MSI side
> these results are likely perfectly within the PCI spec. I feel speaking as
> a lawer here ;)

I disagree about this part.  The reason MSI is in the PCI spec is so
the OS can have generic support for it without having to put
device-specific support in every driver.  The PCI spec is clear that
the OS can allocate any number of vectors less than or equal to the
number requested via MMC.  The SATA device requests 16, and it should
be perfectly legal for the OS to give it 8.

It's interesting that the ICH10 spec (sec 14.1.27, thanks for the
reference) says MMC 100b means "8 MSI Capable".  That smells like a
hardware bug.  The PCI spec says:

  000 => 1 vector
  001 => 2 vectors
  010 => 4 vectors
  011 => 8 vectors
  100 => 16 vectors

The ICH10 spec seems to think 100 means 8 vectors (not 16 as the PCI
spec says), and that would fit with the rest of the ICH10 MME info.
If ICH10 was built assuming this table:

  000 => 1 vector
  001 => 2 vectors
  010 => 4 vectors
  100 => 8 vectors

then everything makes sense: the device requests 8 vectors, and the
behavior is defined in all possible MME cases (1, 2, 4, or 8 vectors
assigned).  The "Values '011b' to '111b' are reserved" part is still
slightly wrong, because the 100b value is in that range but is not
reserved, but that's a tangent.

So my guess (speculation, I admit) is that the intent was for ICH SATA
to request only 8 vectors, but because of this error, it requests 16.
Maybe some early MSI proposal used a different encoding for MMC and
MME, and ICH was originally designed using that.

>> Interrupt vector space is the issue I would worry about, but I think
>> I'm going to put this on the back burner until it actually becomes a
>> problem.
>
> I plan to try get rid of arch_msi_check_device() hook. Should I repost
> this series afterwards?

Honestly, I'm still not inclined to pursue this because of the API
complication and lack of concrete benefit.

Bjorn

^ permalink raw reply

* [PATCH V3] powerpc : Fail remap_4k_pfn() if PFN doesn't fit inside PTE
From: Madhusudanan Kandasamy @ 2014-07-10 15:15 UTC (permalink / raw)
  To: Benjamin Herrenschmidt, Paul Mackerras, linux-kernel,
	linuxppc-dev

remap_4k_pfn() silently truncates upper bits of input 4K PFN
if it cannot be contained in PTE. This leads invalid memory mapping and could
result in a system crash when the memory is accessed. This patch fails
remap_4k_pfn() and returns -EINVAL if the input 4K PFN cannot be contained in
PTE.

V3 : Added parentheses to protect 'pfn' and entire macro as suggested by Brian.
V2 : Rewritten to avoid helper function as suggested by Stephen Rothwell.

Signed-off-by: Madhusudanan Kandasamy <kmadhu@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/pte-hash64-64k.h | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/include/asm/pte-hash64-64k.h b/arch/powerpc/include/asm/pte-hash64-64k.h
index d836d94..b6d2d42 100644
--- a/arch/powerpc/include/asm/pte-hash64-64k.h
+++ b/arch/powerpc/include/asm/pte-hash64-64k.h
@@ -75,7 +75,8 @@
 	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)

 #define remap_4k_pfn(vma, addr, pfn, prot)				\
-	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,		\
-			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
+	(WARN_ON(((pfn) >= (1UL << (64 - PTE_RPN_SHIFT)))) ? -EINVAL :	\
+		remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,	\
+			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)))

 #endif	/* __ASSEMBLY__ */
-- 
2.0.1

^ permalink raw reply related

* Re: [PATCH V2] powerpc: Fail remap_4k_pfn() if PFN doesn't fit inside PTE
From: Brian W Hart @ 2014-07-10 13:59 UTC (permalink / raw)
  To: linuxppc-dev, linuxppc-dev
In-Reply-To: <53BE51EB.5090208@linux.vnet.ibm.com>

On Thu, Jul 10, 2014 at 02:12:19PM +0530, Madhusudanan Kandasamy wrote:
> V2 : Rewritten to avoid helper function as suggested by Stephen Rothwell.
> remap_4k_pfn() silently truncates upper bits of input 4K PFN if
> it cannot be contained in PTE. This leads invalid memory mapping
> and could result in a system crash when the memory is accessed.
> This patch fails remap_4k_pfn() and returns -EINVAL if the input
> 4K PFN cannot be contained in PTE.
> 
> Signed-off-by: Madhusudanan Kandasamy <kmadhu@linux.vnet.ibm.com>
> ---
>  arch/powerpc/include/asm/pte-hash64-64k.h | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/powerpc/include/asm/pte-hash64-64k.h b/arch/powerpc/include/asm/pte-hash64-64k.h
> index d836d94..b5178e4 100644
> --- a/arch/powerpc/include/asm/pte-hash64-64k.h
> +++ b/arch/powerpc/include/asm/pte-hash64-64k.h
> @@ -75,7 +75,8 @@
>  	(((pte) & _PAGE_COMBO)? MMU_PAGE_4K: MMU_PAGE_64K)
> 
>  #define remap_4k_pfn(vma, addr, pfn, prot)				\
> -	remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,		\
> +	WARN_ON((pfn >= (1UL << (64 - PTE_RPN_SHIFT)))) ? -EINVAL :	\
> +		remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE,	\
>  			__pgprot(pgprot_val((prot)) | _PAGE_4K_PFN))
> 
>  #endif	/* __ASSEMBLY__ */
> -- 
> 2.0.1

Chatted with Madhu.  He'll send a new version that adds some
parentheses to protect 'pfn' inside the macro and the entire macro
against use cases like:

    !remap_4k_pfn(...)

brian

^ permalink raw reply

* [PATCH 5/6] powerpc/powernv: Handle compound PE for EEH
From: Guo Chao @ 2014-07-10 13:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405000426-1016-1-git-send-email-yan@linux.vnet.ibm.com>

From: Gavin Shan <gwshan@linux.vnet.ibm.com>

The patch handles compound PE for EEH backend. If one specific
PE in compound group has been frozen, we enforces to freeze
all PEs in the group. If we're enable DMA or MMIO for one PE
in compound group, DMA or MMIO of all PEs in the group will be
enabled.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/eeh-ioda.c | 125 +++++++++++++++++++-----------
 1 file changed, 78 insertions(+), 47 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index ac4b517..8c8b99f 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -187,10 +187,10 @@ static int ioda_eeh_post_init(struct pci_controller *hose)
  */
 static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
 {
-	s64 ret;
-	u32 pe_no;
 	struct pci_controller *hose = pe->phb;
 	struct pnv_phb *phb = hose->private_data;
+	int enable, ret = 0;
+	s64 rc;
 
 	/* Check on PE number */
 	if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) {
@@ -201,41 +201,38 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
 		return -EINVAL;
 	}
 
-	pe_no = pe->addr;
 	switch (option) {
 	case EEH_OPT_DISABLE:
-		ret = -EEXIST;
-		break;
+		return -EPERM;
 	case EEH_OPT_ENABLE:
-		ret = 0;
-		break;
+		return 0;
 	case EEH_OPT_THAW_MMIO:
-		ret = opal_pci_eeh_freeze_set(phb->opal_id, pe_no,
-				OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO);
-		if (ret) {
-			pr_warning("%s: Failed to enable MMIO for "
-				   "PHB#%x-PE#%x, err=%lld\n",
-				__func__, hose->global_number, pe_no, ret);
-			return -EIO;
-		}
-
+		enable = OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO;
 		break;
 	case EEH_OPT_THAW_DMA:
-		ret = opal_pci_eeh_freeze_set(phb->opal_id, pe_no,
-				OPAL_EEH_ACTION_CLEAR_FREEZE_DMA);
-		if (ret) {
-			pr_warning("%s: Failed to enable DMA for "
-				   "PHB#%x-PE#%x, err=%lld\n",
-				__func__, hose->global_number, pe_no, ret);
-			return -EIO;
-		}
-
+		enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
 		break;
 	default:
-		pr_warning("%s: Invalid option %d\n", __func__, option);
+		pr_warn("%s: Invalid option %d\n",
+			__func__, option);
 		return -EINVAL;
 	}
 
+	/* If PHB supports compound PE, to handle it */
+	if (phb->unfreeze_pe) {
+		ret = phb->unfreeze_pe(phb, pe->addr, enable);
+	} else {
+		rc = opal_pci_eeh_freeze_set(phb->opal_id,
+					     pe->addr,
+					     enable);
+		if (rc != OPAL_SUCCESS) {
+			pr_warn("%s: Failure %lld enable %d for PHB#%x-PE#%x\n",
+				__func__, rc, option, phb->hose->global_number,
+				pe->addr);
+			ret = -EIO;
+		}
+	}
+
 	return ret;
 }
 
@@ -313,16 +310,23 @@ static int ioda_eeh_get_pe_state(struct eeh_pe *pe)
 		return result;
 	}
 
-	/* Fetch state from hardware */
-	rc = opal_pci_eeh_freeze_status(phb->opal_id,
-					pe->addr,
-					&fstate,
-					&pcierr,
-					NULL);
-	if (rc != OPAL_SUCCESS) {
-		pr_warn("%s: Failure %lld getting PHB#%x-PE%x state\n",
-			__func__, rc, phb->hose->global_number, pe->addr);
-		return EEH_STATE_NOT_SUPPORT;
+	/*
+	 * Fetch PE state from hardware. If the PHB
+	 * supports compound PE, let it handle that.
+	 */
+	if (phb->get_pe_state) {
+		fstate = phb->get_pe_state(phb, pe->addr);
+	} else {
+		rc = opal_pci_eeh_freeze_status(phb->opal_id,
+						pe->addr,
+						&fstate,
+						&pcierr,
+						NULL);
+		if (rc != OPAL_SUCCESS) {
+			pr_warn("%s: Failure %lld getting PHB#%x-PE%x state\n",
+				__func__, rc, phb->hose->global_number, pe->addr);
+			return EEH_STATE_NOT_SUPPORT;
+		}
 	}
 
 	/* Figure out state */
@@ -361,6 +365,9 @@ static int ioda_eeh_get_pe_state(struct eeh_pe *pe)
 	}
 
 	/*
+	 * If PHB supports compound PE, to freeze all
+	 * slave PEs for consistency.
+	 *
 	 * If the PE is switching to frozen state for the
 	 * first time, to dump the PHB diag-data.
 	 */
@@ -369,6 +376,9 @@ static int ioda_eeh_get_pe_state(struct eeh_pe *pe)
 	    !(result & EEH_STATE_MMIO_ACTIVE) &&
 	    !(result & EEH_STATE_DMA_ACTIVE)  &&
 	    !(pe->state & EEH_PE_ISOLATED)) {
+		if (phb->freeze_pe)
+			phb->freeze_pe(phb, pe->addr);
+
 		eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
 		ioda_eeh_phb_diag(phb->hose);
 	}
@@ -696,22 +706,43 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
 static int ioda_eeh_get_pe(struct pci_controller *hose,
 			   u16 pe_no, struct eeh_pe **pe)
 {
-	struct eeh_pe *phb_pe, *dev_pe;
-	struct eeh_dev dev;
+	struct pnv_phb *phb = hose->private_data;
+	struct pnv_ioda_pe *pnv_pe;
+	struct eeh_pe *dev_pe;
+	struct eeh_dev edev;
 
-	/* Find the PHB PE */
-	phb_pe = eeh_phb_pe_get(hose);
-	if (!phb_pe)
-		return -EEXIST;
+	/*
+	 * If PHB supports compound PE, to fetch
+	 * the master PE because slave PE is invisible
+	 * to EEH core.
+	 */
+	if (phb->get_pe_state) {
+		pnv_pe = &phb->ioda.pe_array[pe_no];
+		if (pnv_pe->flags & PNV_IODA_PE_SLAVE) {
+			pnv_pe = pnv_pe->master;
+			WARN_ON(!pnv_pe ||
+				!(pnv_pe->flags & PNV_IODA_PE_MASTER));
+			pe_no = pnv_pe->pe_number;
+		}
+	}
 
 	/* Find the PE according to PE# */
-	memset(&dev, 0, sizeof(struct eeh_dev));
-	dev.phb = hose;
-	dev.pe_config_addr = pe_no;
-	dev_pe = eeh_pe_get(&dev);
-	if (!dev_pe) return -EEXIST;
+	memset(&edev, 0, sizeof(struct eeh_dev));
+	edev.phb = hose;
+	edev.pe_config_addr = pe_no;
+	dev_pe = eeh_pe_get(&edev);
+	if (!dev_pe)
+		return -EEXIST;
 
+	/*
+	 * At this point, we're sure the compound PE should
+	 * be put into frozen state.
+	 */
 	*pe = dev_pe;
+	if (phb->freeze_pe &&
+	    !(dev_pe->state & EEH_PE_ISOLATED))
+		phb->freeze_pe(phb, pe_no);
+
 	return 0;
 }
 
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 4/6] powerpc/powernv: handle compound PE
From: Guo Chao @ 2014-07-10 13:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405000426-1016-1-git-send-email-yan@linux.vnet.ibm.com>

From: Gavin Shan <gwshan@linux.vnet.ibm.com>

The patch introduces 3 PHB callbacks: compound PE retrieval, force
freezing and unfreezing compound PE. The PCI config accessors and
EEH backend can use them in subsequent patches.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/pci-ioda.c | 144 ++++++++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/pci.h      |   3 +
 2 files changed, 147 insertions(+)

diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 31a5460..69f0110 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -350,6 +350,146 @@ static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
 		res->start, res->end, pci_addr);
 }
 
+static void pnv_ioda_freeze_pe(struct pnv_phb *phb, int pe_no)
+{
+	struct pnv_ioda_pe *pe = &phb->ioda.pe_array[pe_no];
+	struct pnv_ioda_pe *slave;
+	s64 rc;
+
+	/* Fetch master PE */
+	if (pe->flags & PNV_IODA_PE_SLAVE) {
+		pe = pe->master;
+		WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
+		pe_no = pe->pe_number;
+	}
+
+	/* Freeze master PE */
+	rc = opal_pci_eeh_freeze_set(phb->opal_id,
+				     pe_no,
+				     OPAL_EEH_ACTION_SET_FREEZE_ALL);
+	if (rc != OPAL_SUCCESS) {
+		pr_warn("%s: Failure %lld freezing PHB#%x-PE#%x\n",
+			__func__, rc, phb->hose->global_number, pe_no);
+		return;
+	}
+
+	/* Freeze slave PEs */
+	if (!(pe->flags & PNV_IODA_PE_MASTER))
+		return;
+
+	list_for_each_entry(slave, &pe->slaves, list) {
+		rc = opal_pci_eeh_freeze_set(phb->opal_id,
+					     slave->pe_number,
+					     OPAL_EEH_ACTION_SET_FREEZE_ALL);
+		if (rc != OPAL_SUCCESS)
+			pr_warn("%s: Failure %lld freezing PHB#%x-PE#%x\n",
+				__func__, rc, phb->hose->global_number,
+				slave->pe_number);
+	}
+}
+
+int pnv_ioda_unfreeze_pe(struct pnv_phb *phb, int pe_no, int opt)
+{
+	struct pnv_ioda_pe *pe, *slave;
+	s64 rc;
+
+	/* Find master PE */
+	pe = &phb->ioda.pe_array[pe_no];
+	if (pe->flags & PNV_IODA_PE_SLAVE) {
+		pe = pe->master;
+		WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
+		pe_no = pe->pe_number;
+	}
+
+	/* Clear frozen state for master PE */
+	rc = opal_pci_eeh_freeze_set(phb->opal_id, pe_no, opt);
+	if (rc != OPAL_SUCCESS) {
+		pr_warn("%s: Failure %lld clear %d on PHB#%x-PE#%x\n",
+			__func__, rc, opt, phb->hose->global_number, pe_no);
+		return -EIO;
+	}
+
+	if (!(pe->flags & PNV_IODA_PE_MASTER))
+		return 0;
+
+	/* Clear frozen state for slave PEs */
+	list_for_each_entry(slave, &pe->slaves, list) {
+		rc = opal_pci_eeh_freeze_set(phb->opal_id,
+					     slave->pe_number,
+					     opt);
+		if (rc != OPAL_SUCCESS) {
+			pr_warn("%s: Failure %lld clear %d on PHB#%x-PE#%x\n",
+				__func__, rc, opt, phb->hose->global_number,
+				slave->pe_number);
+			return -EIO;
+		}
+	}
+
+	return 0;
+}
+
+static int pnv_ioda_get_pe_state(struct pnv_phb *phb, int pe_no)
+{
+	struct pnv_ioda_pe *slave, *pe;
+	u8 fstate, state;
+	__be16 pcierr;
+	s64 rc;
+
+	/* Sanity check on PE number */
+	if (pe_no < 0 || pe_no >= phb->ioda.total_pe)
+		return OPAL_EEH_STOPPED_PERM_UNAVAIL;
+
+	/*
+	 * Fetch the master PE and the PE instance might be
+	 * not initialized yet.
+	 */
+	pe = &phb->ioda.pe_array[pe_no];
+	if (pe->flags & PNV_IODA_PE_SLAVE) {
+		pe = pe->master;
+		WARN_ON(!pe || !(pe->flags & PNV_IODA_PE_MASTER));
+		pe_no = pe->pe_number;
+	}
+
+	/* Check the master PE */
+	rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
+					&state, &pcierr, NULL);
+	if (rc != OPAL_SUCCESS) {
+		pr_warn("%s: Failure %lld getting "
+			"PHB#%x-PE#%x state\n",
+			__func__, rc,
+			phb->hose->global_number, pe_no);
+		return OPAL_EEH_STOPPED_TEMP_UNAVAIL;
+	}
+
+	/* Check the slave PE */
+	if (!(pe->flags & PNV_IODA_PE_MASTER))
+		return state;
+
+	list_for_each_entry(slave, &pe->slaves, list) {
+		rc = opal_pci_eeh_freeze_status(phb->opal_id,
+						slave->pe_number,
+						&fstate,
+						&pcierr,
+						NULL);
+		if (rc != OPAL_SUCCESS) {
+			pr_warn("%s: Failure %lld getting "
+				"PHB#%x-PE#%x state\n",
+				__func__, rc,
+				phb->hose->global_number, slave->pe_number);
+			return OPAL_EEH_STOPPED_TEMP_UNAVAIL;
+		}
+
+		/*
+		 * Override the result based on the ascending
+		 * priority.
+		 */
+		if (fstate > state)
+			state = fstate;
+	}
+
+	return state;
+}
+
 /* Currently those 2 are only used when MSIs are enabled, this will change
  * but in the meantime, we need to protect them to avoid warnings
  */
@@ -1611,6 +1751,10 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 		phb->ioda.io_size, phb->ioda.io_segsize);
 
 	phb->hose->ops = &pnv_pci_ops;
+
+	phb->get_pe_state = pnv_ioda_get_pe_state;
+	phb->freeze_pe = pnv_ioda_freeze_pe;
+	phb->unfreeze_pe = pnv_ioda_unfreeze_pe;
 #ifdef CONFIG_EEH
 	phb->eeh_ops = &ioda_eeh_ops;
 #endif
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index def7171..b160e6b 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -128,6 +128,9 @@ struct pnv_phb {
 	int (*init_m64)(struct pnv_phb *phb);
 	void (*alloc_m64_pe)(struct pnv_phb *phb);
 	int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all);
+	int (*get_pe_state)(struct pnv_phb *phb, int pe_no);
+	void (*freeze_pe)(struct pnv_phb *phb, int pe_no);
+	int (*unfreeze_pe)(struct pnv_phb *phb, int pe_no, int opt);
 
 	union {
 		struct {
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 3/6] powerpc/powernv: Split ioda_eeh_get_state()
From: Guo Chao @ 2014-07-10 13:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405000426-1016-1-git-send-email-yan@linux.vnet.ibm.com>

From: Gavin Shan <gwshan@linux.vnet.ibm.com>

Function ioda_eeh_get_state() is used to fetch EEH state for PHB
or PE. We're going to support compound PE and the function becomes
more complicated with that. The patch splits the function into two
for PHB and PE cases separately. Besides, I also clean the code up
for a bit to improve the readability.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/eeh-ioda.c | 186 +++++++++++++++++-------------
 1 file changed, 105 insertions(+), 81 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 723db8b..ac4b517 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -255,130 +255,154 @@ static void ioda_eeh_phb_diag(struct pci_controller *hose)
 	pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
 }
 
-/**
- * ioda_eeh_get_state - Retrieve the state of PE
- * @pe: EEH PE
- *
- * The PE's state should be retrieved from the PEEV, PEST
- * IODA tables. Since the OPAL has exported the function
- * to do it, it'd better to use that.
- */
-static int ioda_eeh_get_state(struct eeh_pe *pe)
+static int ioda_eeh_get_phb_state(struct eeh_pe *pe)
 {
-	s64 ret = 0;
+	struct pnv_phb *phb = pe->phb->private_data;
 	u8 fstate;
 	__be16 pcierr;
-	u32 pe_no;
-	int result;
-	struct pci_controller *hose = pe->phb;
-	struct pnv_phb *phb = hose->private_data;
+	s64 rc;
+	int result = 0;
+
+	rc = opal_pci_eeh_freeze_status(phb->opal_id,
+					pe->addr,
+					&fstate,
+					&pcierr,
+					NULL);
+	if (rc != OPAL_SUCCESS) {
+		pr_warn("%s: Failure %lld getting PHB#%x state\n",
+			__func__, rc, phb->hose->global_number);
+                return EEH_STATE_NOT_SUPPORT;
+        }
 
 	/*
-	 * Sanity check on PE address. The PHB PE address should
-	 * be zero.
+	 * Check PHB state. If the PHB is frozen for the
+	 * first time, to dump the PHB diag-data.
 	 */
-	if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) {
-		pr_err("%s: PE address %x out of range [0, %x] "
-		       "on PHB#%x\n",
-		       __func__, pe->addr, phb->ioda.total_pe,
-		       hose->global_number);
-		return EEH_STATE_NOT_SUPPORT;
+	if (be16_to_cpu(pcierr) != OPAL_EEH_PHB_ERROR) {
+		result = (EEH_STATE_MMIO_ACTIVE  |
+			  EEH_STATE_DMA_ACTIVE   |
+			  EEH_STATE_MMIO_ENABLED |
+			  EEH_STATE_DMA_ENABLED);
+	} else if (!(pe->state & EEH_PE_ISOLATED)) {
+		eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
+		ioda_eeh_phb_diag(phb->hose);
 	}
 
+	return result;
+}
+
+static int ioda_eeh_get_pe_state(struct eeh_pe *pe)
+{
+	struct pnv_phb *phb = pe->phb->private_data;
+	u8 fstate;
+	__be16 pcierr;
+	s64 rc;
+	int result;
+
 	/*
-	 * If we're in middle of PE reset, return normal
-	 * state to keep EEH core going. For PHB reset, we
-	 * still expect to have fenced PHB cleared with
-	 * PHB reset.
+	 * We don't clobber hardware frozen state until PE
+	 * reset is completed. In order to keep EEH core
+	 * moving forward, we have to return operational
+	 * state during PE reset.
 	 */
-	if (!(pe->type & EEH_PE_PHB) &&
-	    (pe->state & EEH_PE_RESET)) {
-		result = (EEH_STATE_MMIO_ACTIVE |
-			  EEH_STATE_DMA_ACTIVE |
+	if (pe->state & EEH_PE_RESET) {
+		result = (EEH_STATE_MMIO_ACTIVE  |
+			  EEH_STATE_DMA_ACTIVE   |
 			  EEH_STATE_MMIO_ENABLED |
 			  EEH_STATE_DMA_ENABLED);
 		return result;
 	}
 
-	/* Retrieve PE status through OPAL */
-	pe_no = pe->addr;
-	ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
-			&fstate, &pcierr, NULL);
-	if (ret) {
-		pr_err("%s: Failed to get EEH status on "
-		       "PHB#%x-PE#%x\n, err=%lld\n",
-		       __func__, hose->global_number, pe_no, ret);
+	/* Fetch state from hardware */
+	rc = opal_pci_eeh_freeze_status(phb->opal_id,
+					pe->addr,
+					&fstate,
+					&pcierr,
+					NULL);
+	if (rc != OPAL_SUCCESS) {
+		pr_warn("%s: Failure %lld getting PHB#%x-PE%x state\n",
+			__func__, rc, phb->hose->global_number, pe->addr);
 		return EEH_STATE_NOT_SUPPORT;
 	}
 
-	/* Check PHB status */
-	if (pe->type & EEH_PE_PHB) {
-		result = 0;
-		result &= ~EEH_STATE_RESET_ACTIVE;
-
-		if (be16_to_cpu(pcierr) != OPAL_EEH_PHB_ERROR) {
-			result |= EEH_STATE_MMIO_ACTIVE;
-			result |= EEH_STATE_DMA_ACTIVE;
-			result |= EEH_STATE_MMIO_ENABLED;
-			result |= EEH_STATE_DMA_ENABLED;
-		} else if (!(pe->state & EEH_PE_ISOLATED)) {
-			eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
-			ioda_eeh_phb_diag(hose);
-		}
-
-		return result;
-	}
-
-	/* Parse result out */
-	result = 0;
+	/* Figure out state */
 	switch (fstate) {
 	case OPAL_EEH_STOPPED_NOT_FROZEN:
-		result &= ~EEH_STATE_RESET_ACTIVE;
-		result |= EEH_STATE_MMIO_ACTIVE;
-		result |= EEH_STATE_DMA_ACTIVE;
-		result |= EEH_STATE_MMIO_ENABLED;
-		result |= EEH_STATE_DMA_ENABLED;
+		result = (EEH_STATE_MMIO_ACTIVE  |
+			  EEH_STATE_DMA_ACTIVE   |
+			  EEH_STATE_MMIO_ENABLED |
+			  EEH_STATE_DMA_ENABLED);
 		break;
 	case OPAL_EEH_STOPPED_MMIO_FREEZE:
-		result &= ~EEH_STATE_RESET_ACTIVE;
-		result |= EEH_STATE_DMA_ACTIVE;
-		result |= EEH_STATE_DMA_ENABLED;
+		result = (EEH_STATE_DMA_ACTIVE |
+			  EEH_STATE_DMA_ENABLED);
 		break;
 	case OPAL_EEH_STOPPED_DMA_FREEZE:
-		result &= ~EEH_STATE_RESET_ACTIVE;
-		result |= EEH_STATE_MMIO_ACTIVE;
-		result |= EEH_STATE_MMIO_ENABLED;
+		result = (EEH_STATE_MMIO_ACTIVE |
+			  EEH_STATE_MMIO_ENABLED);
 		break;
 	case OPAL_EEH_STOPPED_MMIO_DMA_FREEZE:
-		result &= ~EEH_STATE_RESET_ACTIVE;
+		result = 0;
 		break;
 	case OPAL_EEH_STOPPED_RESET:
-		result |= EEH_STATE_RESET_ACTIVE;
+		result = EEH_STATE_RESET_ACTIVE;
 		break;
 	case OPAL_EEH_STOPPED_TEMP_UNAVAIL:
-		result |= EEH_STATE_UNAVAILABLE;
+		result = EEH_STATE_UNAVAILABLE;
 		break;
 	case OPAL_EEH_STOPPED_PERM_UNAVAIL:
-		result |= EEH_STATE_NOT_SUPPORT;
+		result = EEH_STATE_NOT_SUPPORT;
 		break;
 	default:
-		pr_warning("%s: Unexpected EEH status 0x%x "
-			   "on PHB#%x-PE#%x\n",
-			   __func__, fstate, hose->global_number, pe_no);
+		result = EEH_STATE_NOT_SUPPORT;
+		pr_warn("%s: Invalid PHB#%x-PE#%x state %x\n",
+			__func__, phb->hose->global_number,
+			pe->addr, fstate);
 	}
 
-	/* Dump PHB diag-data for frozen PE */
-	if (result != EEH_STATE_NOT_SUPPORT &&
-	    (result & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) !=
-	    (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE) &&
+	/*
+	 * If the PE is switching to frozen state for the
+	 * first time, to dump the PHB diag-data.
+	 */
+	if (!(result & EEH_STATE_NOT_SUPPORT) &&
+	    !(result & EEH_STATE_UNAVAILABLE) &&
+	    !(result & EEH_STATE_MMIO_ACTIVE) &&
+	    !(result & EEH_STATE_DMA_ACTIVE)  &&
 	    !(pe->state & EEH_PE_ISOLATED)) {
 		eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
-		ioda_eeh_phb_diag(hose);
+		ioda_eeh_phb_diag(phb->hose);
 	}
 
 	return result;
 }
 
+/**
+ * ioda_eeh_get_state - Retrieve the state of PE
+ * @pe: EEH PE
+ *
+ * The PE's state should be retrieved from the PEEV, PEST
+ * IODA tables. Since the OPAL has exported the function
+ * to do it, it'd better to use that.
+ */
+static int ioda_eeh_get_state(struct eeh_pe *pe)
+{
+	struct pnv_phb *phb = pe->phb->private_data;
+
+	/* Sanity check on PE number. PHB PE should have 0 */
+	if (pe->addr < 0 ||
+	    pe->addr >= phb->ioda.total_pe) {
+		pr_warn("%s: PHB#%x-PE#%x out of range [0, %x]\n",
+			__func__, phb->hose->global_number,
+			pe->addr, phb->ioda.total_pe);
+		return EEH_STATE_NOT_SUPPORT;
+	}
+
+	if (pe->type & EEH_PE_PHB)
+		return ioda_eeh_get_phb_state(pe);
+
+	return ioda_eeh_get_pe_state(pe);
+}
+
 static s64 ioda_eeh_phb_poll(struct pnv_phb *phb)
 {
 	s64 rc = OPAL_HARDWARE;
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 6/6] powerpc/powernv: Handle compound PE in config accessors
From: Guo Chao @ 2014-07-10 13:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405000426-1016-1-git-send-email-yan@linux.vnet.ibm.com>

From: Gavin Shan <gwshan@linux.vnet.ibm.com>

The PCI config accessors check for PE frozen state and clear it if
EEH is disabled. The patch handles compound PE in config accessors
if PHB supports it. For consistency, all PEs will be put into frozen
state if any one in compound group gets frozen by hardware.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/pci.c | 89 ++++++++++++++++++++++++------------
 1 file changed, 60 insertions(+), 29 deletions(-)

diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 02f4bd9..353e35b 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -319,43 +319,52 @@ void pnv_pci_dump_phb_diag_data(struct pci_controller *hose,
 static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
 {
 	unsigned long flags, rc;
-	int has_diag;
+	int has_diag, ret = 0;
 
 	spin_lock_irqsave(&phb->lock, flags);
 
+	/* Fetch PHB diag-data */
 	rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
 					 PNV_PCI_DIAG_BUF_SIZE);
 	has_diag = (rc == OPAL_SUCCESS);
 
-	rc = opal_pci_eeh_freeze_set(phb->opal_id, pe_no,
-				     OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
-	if (rc) {
-		pr_warning("PCI %d: Failed to clear EEH freeze state"
-			   " for PE#%d, err %ld\n",
-			   phb->hose->global_number, pe_no, rc);
-
-		/* For now, let's only display the diag buffer when we fail to clear
-		 * the EEH status. We'll do more sensible things later when we have
-		 * proper EEH support. We need to make sure we don't pollute ourselves
-		 * with the normal errors generated when probing empty slots
-		 */
-		if (has_diag)
-			pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob);
-		else
-			pr_warning("PCI %d: No diag data available\n",
-				   phb->hose->global_number);
+	/* If PHB supports compound PE, to handle it */
+	if (phb->unfreeze_pe) {
+		ret = phb->unfreeze_pe(phb,
+				       pe_no,
+				       OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+	} else {
+		rc = opal_pci_eeh_freeze_set(phb->opal_id,
+					     pe_no,
+					     OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+		if (rc) {
+			pr_warn("%s: Failure %ld clearing frozen "
+				"PHB#%x-PE#%x\n",
+				__func__, rc, phb->hose->global_number,
+				pe_no);
+			ret = -EIO;
+		}
 	}
 
+	/*
+	 * For now, let's only display the diag buffer when we fail to clear
+	 * the EEH status. We'll do more sensible things later when we have
+	 * proper EEH support. We need to make sure we don't pollute ourselves
+	 * with the normal errors generated when probing empty slots
+	 */
+	if (has_diag && ret)
+		pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob);
+
 	spin_unlock_irqrestore(&phb->lock, flags);
 }
 
 static void pnv_pci_config_check_eeh(struct pnv_phb *phb,
 				     struct device_node *dn)
 {
-	s64	rc;
 	u8	fstate;
 	__be16	pcierr;
-	u32	pe_no;
+	int	pe_no;
+	s64	rc;
 
 	/*
 	 * Get the PE#. During the PCI probe stage, we might not
@@ -370,20 +379,42 @@ static void pnv_pci_config_check_eeh(struct pnv_phb *phb,
 			pe_no = phb->ioda.reserved_pe;
 	}
 
-	/* Read freeze status */
-	rc = opal_pci_eeh_freeze_status(phb->opal_id, pe_no, &fstate, &pcierr,
-					NULL);
-	if (rc) {
-		pr_warning("%s: Can't read EEH status (PE#%d) for "
-			   "%s, err %lld\n",
-			   __func__, pe_no, dn->full_name, rc);
-		return;
+	/*
+	 * Fetch frozen state. If the PHB support compound PE,
+	 * we need handle that case.
+	 */
+	if (phb->get_pe_state) {
+		fstate = phb->get_pe_state(phb, pe_no);
+	} else {
+		rc = opal_pci_eeh_freeze_status(phb->opal_id,
+						pe_no,
+						&fstate,
+						&pcierr,
+						NULL);
+		if (rc) {
+			pr_warn("%s: Failure %lld getting PHB#%x-PE#%x state\n",
+				__func__, rc, phb->hose->global_number, pe_no);
+			return;
+		}
 	}
+
 	cfg_dbg(" -> EEH check, bdfn=%04x PE#%d fstate=%x\n",
 		(PCI_DN(dn)->busno << 8) | (PCI_DN(dn)->devfn),
 		pe_no, fstate);
-	if (fstate != 0)
+
+	/* Clear the frozen state if applicable */
+	if (fstate == OPAL_EEH_STOPPED_MMIO_FREEZE ||
+	    fstate == OPAL_EEH_STOPPED_DMA_FREEZE  ||
+	    fstate == OPAL_EEH_STOPPED_MMIO_DMA_FREEZE) {
+		/*
+		 * If PHB supports compound PE, freeze it for
+		 * consistency.
+		 */
+		if (phb->freeze_pe)
+			phb->freeze_pe(phb, pe_no);
+
 		pnv_pci_handle_eeh_config(phb, pe_no);
+	}
 }
 
 int pnv_pci_cfg_read(struct device_node *dn,
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 1/6] powerpc/powernv: Enable M64 aperatus for PHB3
From: Guo Chao @ 2014-07-10 13:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Guo Chao
In-Reply-To: <1405000426-1016-1-git-send-email-yan@linux.vnet.ibm.com>

This patch enable M64 aperatus for PHB3.

We already had platform hook (ppc_md.pcibios_window_alignment) to affect
the PCI resource assignment done in PCI core so that each PE's M32 resource
was built on basis of M32 segment size. Similarly, we're using that for
M64 assignment on basis of M64 segment size.

   * We're using last M64 BAR to cover M64 aperatus, and it's shared by all
     256 PEs.
   * We don't support P7IOC yet. However, some function callbacks are added
     to (struct pnv_phb) so that we can reuse them on P7IOC in future.
   * PE, corresponding to PCI bus with large M64 BAR device attached, might
     span multiple M64 segments. We introduce "compound" PE to cover the case.
     The compound PE is a list of PEs and the master PE is used as before.
     The slave PEs are just for MMIO isolation.

Signed-off-by: Guo Chao <yan@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/opal.h           |   8 +-
 arch/powerpc/platforms/powernv/pci-ioda.c | 284 ++++++++++++++++++++++++++++--
 arch/powerpc/platforms/powernv/pci.h      |  20 +++
 3 files changed, 297 insertions(+), 15 deletions(-)

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 0da1dbd..ae885cc 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -340,6 +340,12 @@ enum OpalMveEnableAction {
 	OPAL_ENABLE_MVE = 1
 };
 
+enum OpalM64EnableAction {
+	OPAL_DISABLE_M64 = 0,
+	OPAL_ENABLE_M64_SPLIT = 1,
+	OPAL_ENABLE_M64_NON_SPLIT = 2
+};
+
 enum OpalPciResetScope {
 	OPAL_PHB_COMPLETE = 1, OPAL_PCI_LINK = 2, OPAL_PHB_ERROR = 3,
 	OPAL_PCI_HOT_RESET = 4, OPAL_PCI_FUNDAMENTAL_RESET = 5,
@@ -768,7 +774,7 @@ int64_t opal_pci_set_phb_mem_window(uint64_t phb_id, uint16_t window_type,
 				    uint16_t window_num,
 				    uint64_t starting_real_address,
 				    uint64_t starting_pci_address,
-				    uint16_t segment_size);
+				    uint64_t size);
 int64_t opal_pci_map_pe_mmio_window(uint64_t phb_id, uint16_t pe_number,
 				    uint16_t window_type, uint16_t window_num,
 				    uint16_t segment_num);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index de19ede..851e615 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -36,6 +36,7 @@
 #include <asm/tce.h>
 #include <asm/xics.h>
 #include <asm/debug.h>
+#include <asm/firmware.h>
 
 #include "powernv.h"
 #include "pci.h"
@@ -82,6 +83,12 @@ static inline void __raw_rm_writeq(u64 val, volatile void __iomem *paddr)
 		: : "r" (val), "r" (paddr) : "memory");
 }
 
+static inline bool pnv_pci_is_mem_pref_64(unsigned long flags)
+{
+	return ((flags & (IORESOURCE_MEM_64 | IORESOURCE_PREFETCH)) ==
+		(IORESOURCE_MEM_64 | IORESOURCE_PREFETCH));
+}
+
 static int pnv_ioda_alloc_pe(struct pnv_phb *phb)
 {
 	unsigned long pe;
@@ -106,6 +113,243 @@ static void pnv_ioda_free_pe(struct pnv_phb *phb, int pe)
 	clear_bit(pe, phb->ioda.pe_alloc);
 }
 
+/* The default M64 BAR is shared by all PEs */
+static int pnv_ioda2_init_m64(struct pnv_phb *phb)
+{
+	const char *desc;
+	struct resource *r;
+	s64 rc;
+
+	/* Configure the default M64 BAR */
+	rc = opal_pci_set_phb_mem_window(phb->opal_id,
+					 OPAL_M64_WINDOW_TYPE,
+					 phb->ioda.m64_bar_idx,
+					 phb->ioda.m64_base,
+					 0, /* unused */
+					 phb->ioda.m64_size);
+	if (rc != OPAL_SUCCESS) {
+		desc = "configuring";
+		goto fail;
+	}
+
+	/* Enable the default M64 BAR */
+	rc = opal_pci_phb_mmio_enable(phb->opal_id,
+				      OPAL_M64_WINDOW_TYPE,
+				      phb->ioda.m64_bar_idx,
+				      OPAL_ENABLE_M64_SPLIT);
+	if (rc != OPAL_SUCCESS) {
+		desc = "enabling";
+		goto fail;
+	}
+
+	/* Mark the M64 BAR assigned */
+	set_bit(phb->ioda.m64_bar_idx, &phb->ioda.m64_bar_alloc);
+
+	/*
+	 * Strip off the segment used by the reserved PE, which is
+	 * expected to be 0 or last one of PE capabicity.
+	 */
+	r = &phb->hose->mem_resources[1];
+	if (phb->ioda.reserved_pe == 0)
+		r->start += phb->ioda.m64_segsize;
+	else if (phb->ioda.reserved_pe == (phb->ioda.total_pe - 1))
+		r->end -= phb->ioda.m64_segsize;
+	else
+		pr_warn("  Cannot strip M64 segment for reserved PE#%d\n",
+			phb->ioda.reserved_pe);
+
+	return 0;
+
+fail:
+	pr_warn("  Failure %lld %s M64 BAR#%d\n",
+		rc, desc, phb->ioda.m64_bar_idx);
+	opal_pci_phb_mmio_enable(phb->opal_id,
+				 OPAL_M64_WINDOW_TYPE,
+				 phb->ioda.m64_bar_idx,
+				 OPAL_DISABLE_M64);
+	return -EIO;
+}
+
+static void pnv_ioda2_alloc_m64_pe(struct pnv_phb *phb)
+{
+	resource_size_t sgsz = phb->ioda.m64_segsize;
+	struct pci_dev *pdev;
+	struct resource *r;
+	int base, step, i;
+
+	/*
+	 * Root bus always has full M64 range and root port has
+	 * M64 range used in reality. So we're checking root port
+	 * instead of root bus.
+	 */
+	list_for_each_entry(pdev, &phb->hose->bus->devices, bus_list) {
+		for (i = PCI_BRIDGE_RESOURCES;
+		     i <= PCI_BRIDGE_RESOURCE_END; i++) {
+			r = &pdev->resource[i];
+			if (!r->parent ||
+			    !pnv_pci_is_mem_pref_64(r->flags))
+				continue;
+
+			base = (r->start - phb->ioda.m64_base) / sgsz;
+			for (step = 0; step < resource_size(r) / sgsz; step++)
+				set_bit(base + step, phb->ioda.pe_alloc);
+		}
+	}
+}
+
+static int pnv_ioda2_pick_m64_pe(struct pnv_phb *phb,
+				 struct pci_bus *bus, int all)
+{
+	resource_size_t segsz = phb->ioda.m64_segsize;
+	struct pci_dev *pdev;
+	struct resource *r;
+	struct pnv_ioda_pe *master_pe, *pe;
+	unsigned long size, *pe_alloc;
+	bool found;
+	int start, i, j;
+
+	/* Root bus shouldn't use M64 */
+	if (pci_is_root_bus(bus))
+		return IODA_INVALID_PE;
+
+	/* We support only one M64 window on each bus */
+	found = false;
+	pci_bus_for_each_resource(bus, r, i) {
+		if (r && r->parent &&
+		    pnv_pci_is_mem_pref_64(r->flags)) {
+			found = true;
+			break;
+		}
+	}
+
+	/* No M64 window found ? */
+	if (!found)
+		return IODA_INVALID_PE;
+
+	/* Allocate bitmap */
+	size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long));
+	pe_alloc = kzalloc(size, GFP_KERNEL);
+	if (!pe_alloc) {
+		pr_warn("%s: Out of memory !\n",
+			__func__);
+		return IODA_INVALID_PE;
+	}
+
+	/*
+	 * Figure out reserved PE numbers by the PE
+	 * the its child PEs.
+	 */
+	start = (r->start - phb->ioda.m64_base) / segsz;
+	for (i = 0; i < resource_size(r) / segsz; i++)
+		set_bit(start + i, pe_alloc);
+
+	if (all)
+		goto done;
+
+	/*
+	 * If the PE doesn't cover all subordinate buses,
+	 * we need subtract from reserved PEs for children.
+	 */
+	list_for_each_entry(pdev, &bus->devices, bus_list) {
+		if (!pdev->subordinate)
+			continue;
+
+		pci_bus_for_each_resource(pdev->subordinate, r, i) {
+			if (!r || !r->parent ||
+			    !pnv_pci_is_mem_pref_64(r->flags))
+				continue;
+
+			start = (r->start - phb->ioda.m64_base) / segsz;
+			for (j = 0; j < resource_size(r) / segsz ; j++)
+				clear_bit(start + j, pe_alloc);
+                }
+        }
+
+	/*
+	 * the current bus might not own M64 window and that's all
+	 * contributed by its child buses. For the case, we needn't
+	 * pick M64 dependent PE#.
+	 */
+	if (bitmap_empty(pe_alloc, phb->ioda.total_pe)) {
+		kfree(pe_alloc);
+		return IODA_INVALID_PE;
+	}
+
+	/*
+	 * Figure out the master PE and put all slave PEs to master
+	 * PE's list to form compound PE.
+	 */
+done:
+	master_pe = NULL;
+	i = -1;
+	while ((i = find_next_bit(pe_alloc, phb->ioda.total_pe, i + 1)) <
+		phb->ioda.total_pe) {
+		pe = &phb->ioda.pe_array[i];
+		pe->phb = phb;
+		pe->pe_number = i;
+
+		if (!master_pe) {
+			pe->flags |= PNV_IODA_PE_MASTER;
+			INIT_LIST_HEAD(&pe->slaves);
+			master_pe = pe;
+		} else {
+			pe->flags |= PNV_IODA_PE_SLAVE;
+			pe->master = master_pe;
+			list_add_tail(&pe->list, &master_pe->slaves);
+		}
+	}
+
+	kfree(pe_alloc);
+	return master_pe->pe_number;
+}
+
+static void __init pnv_ioda_parse_m64_window(struct pnv_phb *phb)
+{
+	struct pci_controller *hose = phb->hose;
+	struct device_node *dn = hose->dn;
+	struct resource *res;
+	const u32 *r;
+	u64 pci_addr;
+
+	if (!firmware_has_feature(FW_FEATURE_OPALv3)) {
+		pr_info("  Firmware too old to support M64 window\n");
+		return;
+	}
+
+	r = of_get_property(dn, "ibm,opal-m64-window", NULL);
+	if (!r) {
+		pr_info("  No <ibm,opal-m64-window> on %s\n",
+			dn->full_name);
+		return;
+	}
+
+	/* FIXME: Support M64 for P7IOC */
+	if (phb->type != PNV_PHB_IODA2) {
+		pr_info("  Not support M64 window\n");
+		return;
+	}
+
+	res = &hose->mem_resources[1];
+	res->start = of_translate_address(dn, r + 2);
+	res->end = res->start + of_read_number(r + 4, 2) - 1;
+	res->flags = (IORESOURCE_MEM | IORESOURCE_MEM_64 | IORESOURCE_PREFETCH);
+	pci_addr = of_read_number(r, 2);
+	hose->mem_offset[1] = res->start - pci_addr;
+
+	phb->ioda.m64_size = resource_size(res);
+	phb->ioda.m64_segsize = phb->ioda.m64_size / phb->ioda.total_pe;
+	phb->ioda.m64_base = pci_addr;
+
+	/* Use last M64 BAR to cover M64 window */
+	phb->ioda.m64_bar_idx = 15;
+	phb->init_m64 = pnv_ioda2_init_m64;
+	phb->alloc_m64_pe = pnv_ioda2_alloc_m64_pe;
+	phb->pick_m64_pe = pnv_ioda2_pick_m64_pe;
+
+	pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx Prefetchable\n",
+		res->start, res->end, pci_addr);
+}
+
 /* Currently those 2 are only used when MSIs are enabled, this will change
  * but in the meantime, we need to protect them to avoid warnings
  */
@@ -363,9 +607,16 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all)
 	struct pci_controller *hose = pci_bus_to_host(bus);
 	struct pnv_phb *phb = hose->private_data;
 	struct pnv_ioda_pe *pe;
-	int pe_num;
+	int pe_num = IODA_INVALID_PE;
+
+	/* Check if PE is determined by M64 */
+	if (phb->pick_m64_pe)
+		pe_num = phb->pick_m64_pe(phb, bus, all);
+
+	/* The PE number isn't pinned by M64 */
+	if (pe_num == IODA_INVALID_PE)
+		pe_num = pnv_ioda_alloc_pe(phb);
 
-	pe_num = pnv_ioda_alloc_pe(phb);
 	if (pe_num == IODA_INVALID_PE) {
 		pr_warning("%s: Not enough PE# available for PCI bus %04x:%02x\n",
 			__func__, pci_domain_nr(bus), bus->number);
@@ -441,8 +692,15 @@ static void pnv_ioda_setup_PEs(struct pci_bus *bus)
 static void pnv_pci_ioda_setup_PEs(void)
 {
 	struct pci_controller *hose, *tmp;
+	struct pnv_phb *phb;
 
 	list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+		phb = hose->private_data;
+
+		/* M64 layout might affect PE allocation */
+		if (phb->alloc_m64_pe)
+			phb->alloc_m64_pe(phb);
+
 		pnv_ioda_setup_PEs(hose->bus);
 	}
 }
@@ -1055,9 +1313,6 @@ static void pnv_ioda_setup_pe_seg(struct pci_controller *hose,
 				index++;
 			}
 		} else if (res->flags & IORESOURCE_MEM) {
-			/* WARNING: Assumes M32 is mem region 0 in PHB. We need to
-			 * harden that algorithm when we start supporting M64
-			 */
 			region.start = res->start -
 				       hose->mem_offset[0] -
 				       phb->ioda.m32_pci_base;
@@ -1178,7 +1433,8 @@ static resource_size_t pnv_pci_window_alignment(struct pci_bus *bus,
 		bridge = bridge->bus->self;
 	}
 
-	/* We need support prefetchable memory window later */
+	if (pnv_pci_is_mem_pref_64(type))
+		return phb->ioda.m64_segsize;
 	if (type & IORESOURCE_MEM)
 		return phb->ioda.m32_segsize;
 
@@ -1299,6 +1555,10 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 	prop32 = of_get_property(np, "ibm,opal-reserved-pe", NULL);
 	if (prop32)
 		phb->ioda.reserved_pe = be32_to_cpup(prop32);
+
+	/* Parse 64-bit MMIO range */
+	pnv_ioda_parse_m64_window(phb);
+
 	phb->ioda.m32_size = resource_size(&hose->mem_resources[0]);
 	/* FW Has already off top 64k of M32 space (MSI space) */
 	phb->ioda.m32_size += 0x10000;
@@ -1334,14 +1594,6 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 	/* Calculate how many 32-bit TCE segments we have */
 	phb->ioda.tce32_count = phb->ioda.m32_pci_base >> 28;
 
-	/* Clear unusable m64 */
-	hose->mem_resources[1].flags = 0;
-	hose->mem_resources[1].start = 0;
-	hose->mem_resources[1].end = 0;
-	hose->mem_resources[2].flags = 0;
-	hose->mem_resources[2].start = 0;
-	hose->mem_resources[2].end = 0;
-
 #if 0 /* We should really do that ... */
 	rc = opal_pci_set_phb_mem_window(opal->phb_id,
 					 window_type,
@@ -1404,6 +1656,10 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 		ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL);
 		ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET);
 	}
+
+	/* Configure M64 window */
+	if (phb->init_m64 && phb->init_m64(phb))
+		hose->mem_resources[1].flags = 0;
 }
 
 void __init pnv_pci_init_ioda2_phb(struct device_node *np)
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 676232c..def7171 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -21,6 +21,8 @@ enum pnv_phb_model {
 #define PNV_IODA_PE_DEV		(1 << 0)	/* PE has single PCI device	*/
 #define PNV_IODA_PE_BUS		(1 << 1)	/* PE has primary PCI bus	*/
 #define PNV_IODA_PE_BUS_ALL	(1 << 2)	/* PE has subordinate buses	*/
+#define PNV_IODA_PE_MASTER	(1 << 3)	/* Master PE in compound case	*/
+#define PNV_IODA_PE_SLAVE	(1 << 4)	/* Slave PE in compound case	*/
 
 /* Data associated with a PE, including IOMMU tracking etc.. */
 struct pnv_phb;
@@ -64,6 +66,10 @@ struct pnv_ioda_pe {
 	 */
 	int			mve_number;
 
+	/* PEs in compound case */
+	struct pnv_ioda_pe	*master;
+	struct list_head	slaves;
+
 	/* Link in list of PE#s */
 	struct list_head	dma_link;
 	struct list_head	list;
@@ -119,6 +125,9 @@ struct pnv_phb {
 	void (*fixup_phb)(struct pci_controller *hose);
 	u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn);
 	void (*shutdown)(struct pnv_phb *phb);
+	int (*init_m64)(struct pnv_phb *phb);
+	void (*alloc_m64_pe)(struct pnv_phb *phb);
+	int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all);
 
 	union {
 		struct {
@@ -129,9 +138,20 @@ struct pnv_phb {
 			/* Global bridge info */
 			unsigned int		total_pe;
 			unsigned int		reserved_pe;
+
+			/* 32-bit MMIO window */
 			unsigned int		m32_size;
 			unsigned int		m32_segsize;
 			unsigned int		m32_pci_base;
+
+			/* 64-bit MMIO window */
+			unsigned int		m64_bar_idx;
+			unsigned long		m64_size;
+			unsigned long		m64_segsize;
+			unsigned long		m64_base;
+			unsigned long		m64_bar_alloc;
+
+			/* IO ports */
 			unsigned int		io_size;
 			unsigned int		io_segsize;
 			unsigned int		io_pci_base;
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 2/6] powerpc/powernv: Allows to freeze PE
From: Guo Chao @ 2014-07-10 13:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Gavin Shan
In-Reply-To: <1405000426-1016-1-git-send-email-yan@linux.vnet.ibm.com>

From: Gavin Shan <gwshan@linux.vnet.ibm.com>

For compound PE, all PEs should be frozen if any one in the group
becomes frozen. Unfortunately, hardware doesn't always do that
automatically with help of PELTV. So we have to flirt with
PESTA/B a bit to freeze all PEs for the case.

The patch sychronizes with firmware hearder and change the name
of opal_pci_eeh_freeze_clear() to opal_pci_eeh_freeze_set() to
reflect its usage: the API can be used to clear or set frozen
state for the specified PE.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/include/asm/opal.h                | 9 +++++----
 arch/powerpc/platforms/powernv/eeh-ioda.c      | 6 +++---
 arch/powerpc/platforms/powernv/opal-wrappers.S | 2 +-
 arch/powerpc/platforms/powernv/pci-ioda.c      | 4 ++--
 arch/powerpc/platforms/powernv/pci.c           | 4 ++--
 5 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ae885cc..edbfe1c 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -84,7 +84,7 @@ struct opal_sg_list {
 #define OPAL_PCI_EEH_FREEZE_STATUS		23
 #define OPAL_PCI_SHPC				24
 #define OPAL_CONSOLE_WRITE_BUFFER_SPACE		25
-#define OPAL_PCI_EEH_FREEZE_CLEAR		26
+#define OPAL_PCI_EEH_FREEZE_SET			26
 #define OPAL_PCI_PHB_MMIO_ENABLE		27
 #define OPAL_PCI_SET_PHB_MEM_WINDOW		28
 #define OPAL_PCI_MAP_PE_MMIO_WINDOW		29
@@ -167,7 +167,8 @@ enum OpalFreezeState {
 	OPAL_EEH_STOPPED_PERM_UNAVAIL = 6
 };
 
-enum OpalEehFreezeActionToken {
+enum OpalPciFreezeActionToken {
+	OPAL_EEH_ACTION_SET_FREEZE_ALL = 0,
 	OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO = 1,
 	OPAL_EEH_ACTION_CLEAR_FREEZE_DMA = 2,
 	OPAL_EEH_ACTION_CLEAR_FREEZE_ALL = 3
@@ -762,8 +763,8 @@ int64_t opal_pci_eeh_freeze_status(uint64_t phb_id, uint64_t pe_number,
 				   uint8_t *freeze_state,
 				   __be16 *pci_error_type,
 				   __be64 *phb_status);
-int64_t opal_pci_eeh_freeze_clear(uint64_t phb_id, uint64_t pe_number,
-				  uint64_t eeh_action_token);
+int64_t opal_pci_eeh_freeze_set(uint64_t phb_id, uint64_t pe_number,
+				uint64_t eeh_action_token);
 int64_t opal_pci_shpc(uint64_t phb_id, uint64_t shpc_action, uint8_t *state);
 
 
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 8ad0c5b..723db8b 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -210,7 +210,7 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
 		ret = 0;
 		break;
 	case EEH_OPT_THAW_MMIO:
-		ret = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
+		ret = opal_pci_eeh_freeze_set(phb->opal_id, pe_no,
 				OPAL_EEH_ACTION_CLEAR_FREEZE_MMIO);
 		if (ret) {
 			pr_warning("%s: Failed to enable MMIO for "
@@ -221,7 +221,7 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
 
 		break;
 	case EEH_OPT_THAW_DMA:
-		ret = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
+		ret = opal_pci_eeh_freeze_set(phb->opal_id, pe_no,
 				OPAL_EEH_ACTION_CLEAR_FREEZE_DMA);
 		if (ret) {
 			pr_warning("%s: Failed to enable DMA for "
@@ -809,7 +809,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
 					hose->global_number, frozen_pe_no);
 				pr_info("EEH: PHB location: %s\n",
 					eeh_pe_loc_get(phb_pe));
-				opal_pci_eeh_freeze_clear(phb->opal_id, frozen_pe_no,
+				opal_pci_eeh_freeze_set(phb->opal_id, frozen_pe_no,
 					OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
 				ret = EEH_NEXT_ERR_NONE;
 			} else if ((*pe)->state & EEH_PE_ISOLATED) {
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 4abbff2..abf5ffa 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -85,7 +85,7 @@ OPAL_CALL(opal_set_xive,			OPAL_SET_XIVE);
 OPAL_CALL(opal_get_xive,			OPAL_GET_XIVE);
 OPAL_CALL(opal_register_exception_handler,	OPAL_REGISTER_OPAL_EXCEPTION_HANDLER);
 OPAL_CALL(opal_pci_eeh_freeze_status,		OPAL_PCI_EEH_FREEZE_STATUS);
-OPAL_CALL(opal_pci_eeh_freeze_clear,		OPAL_PCI_EEH_FREEZE_CLEAR);
+OPAL_CALL(opal_pci_eeh_freeze_set,		OPAL_PCI_EEH_FREEZE_SET);
 OPAL_CALL(opal_pci_shpc,			OPAL_PCI_SHPC);
 OPAL_CALL(opal_pci_phb_mmio_enable,		OPAL_PCI_PHB_MMIO_ENABLE);
 OPAL_CALL(opal_pci_set_phb_mem_window,		OPAL_PCI_SET_PHB_MEM_WINDOW);
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 851e615..31a5460 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -426,8 +426,8 @@ static int pnv_ioda_configure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe)
 				pe->pe_number, OPAL_ADD_PE_TO_DOMAIN);
 	if (rc)
 		pe_warn(pe, "OPAL error %d adding self to PELTV\n", rc);
-	opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number,
-				  OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+	opal_pci_eeh_freeze_set(phb->opal_id, pe->pe_number,
+				OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
 
 	/* Add to all parents PELT-V */
 	while (parent) {
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index f91a4e5..02f4bd9 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -327,8 +327,8 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
 					 PNV_PCI_DIAG_BUF_SIZE);
 	has_diag = (rc == OPAL_SUCCESS);
 
-	rc = opal_pci_eeh_freeze_clear(phb->opal_id, pe_no,
-				       OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
+	rc = opal_pci_eeh_freeze_set(phb->opal_id, pe_no,
+				     OPAL_EEH_ACTION_CLEAR_FREEZE_ALL);
 	if (rc) {
 		pr_warning("PCI %d: Failed to clear EEH freeze state"
 			   " for PE#%d, err %ld\n",
-- 
1.8.3.1

^ permalink raw reply related

* [PATCH 0/6] powerpc/powernv: Support M64 window
From: Guo Chao @ 2014-07-10 13:53 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Guo Chao

Currently, all MMIO resources, including 64-bits MMIO resources are hooked
to PHB 32-bits MMIO BAR, which has limited space. If there're PCI devices
with large 64-bits MMIO BAR (could reach 1GB), we're running out of MMIO
resources (as well as PE numbers) quickly. The patchset reuses the M32
infrastructure to support M64:

   * The last M64 BAR covers all M64 aperatus and that's shared by all PEs.
   * Reuse ppc_md.pcibios_window_alignment() to affect resource assignment
     in PCI core so that we can get well segmented 64-bits window of PCI
     bridges.
   * One PCI bus might require multiple discrete M64 segment. We invent
     if we're going to unfreeze any one in the group.

The patchset requires corresponding changes from firmware. And we don't
support M64 for P7 yet. That's something to do in future.

Gavin Shan (5):
  powerpc/powernv: Allows to freeze PE
  powerpc/powernv: Split ioda_eeh_get_state()
  powerpc/powernv: handle compound PE
  powerpc/powernv: Handle compound PE for EEH
  powerpc/powernv: Handle compound PE in config accessors

Guo Chao (1):
  powerpc/powernv: Enable M64 aperatus for PHB3

 arch/powerpc/include/asm/opal.h                |  17 +-
 arch/powerpc/platforms/powernv/eeh-ioda.c      | 293 ++++++++++-------
 arch/powerpc/platforms/powernv/opal-wrappers.S |   2 +-
 arch/powerpc/platforms/powernv/pci-ioda.c      | 432 ++++++++++++++++++++++++-
 arch/powerpc/platforms/powernv/pci.c           |  87 +++--
 arch/powerpc/platforms/powernv/pci.h           |  23 ++
 6 files changed, 685 insertions(+), 169 deletions(-)

-- 
1.8.3.1

^ permalink raw reply

* Re: [PATCH] powerpc/pseries: dynamically added OF nodes need to call of_node_init
From: Nathan Fontenot @ 2014-07-10 13:40 UTC (permalink / raw)
  To: Michael Ellerman, Tyrel Datwyler; +Cc: grant.likely, linuxppc-dev
In-Reply-To: <1404959630.27178.1.camel@concordia>

On 07/09/2014 09:33 PM, Michael Ellerman wrote:
> On Wed, 2014-07-09 at 21:20 -0400, Tyrel Datwyler wrote:
>> Commit 75b57ecf9 refactored device tree nodes to use kobjects such that they
>> can be exposed via /sysfs. A secondary commit 0829f6d1f furthered this rework
>> by moving the kobect initialization logic out of of_node_add into its own
>> of_node_init function. The inital commit removed the existing kref_init calls
>> in the pseries dlpar code with the assumption kobject initialization would
>> occur in of_node_add. The second commit had the side effect of triggering a
>> BUG_ON as a result of dynamically added nodes being uninitialized.
> 
> So does this mean DLPAR is broken since 0829f6d1f (3.15-rc1)?

Yes. Partition migration would also be affected by this.

-Nathan

> 
> If so this should have a Cc: stable@kernel.org shouldn't it?
> 
> And the latest trend is to also add:
> 
> Fixes: 0829f6d1f69e ("of: device_node kobject lifecycle fixes")
> 
> cheers
> 
> 

^ permalink raw reply

* Re: [PATCH 2/9] drivers: base: support cpu cache information interface to userspace via sysfs
From: Sudeep Holla @ 2014-07-10 13:37 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Rob Herring, Lorenzo Pieralisi, linux-ia64@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-s390@vger.kernel.org,
	x86@kernel.org, Heiko Carstens, linux-kernel@vger.kernel.org,
	Sudeep Holla, linux390@de.ibm.com, linuxppc-dev@lists.ozlabs.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <20140710000905.GA18025@kroah.com>

Hi Greg,

Thanks for reviewing this.

On 10/07/14 01:09, Greg Kroah-Hartman wrote:
> On Wed, Jun 25, 2014 at 06:30:37PM +0100, Sudeep Holla wrote:
>> +static const struct device_attribute *cache_optional_attrs[] =3D {
>> +=09&dev_attr_coherency_line_size,
>> +=09&dev_attr_ways_of_associativity,
>> +=09&dev_attr_number_of_sets,
>> +=09&dev_attr_size,
>> +=09&dev_attr_attributes,
>> +=09&dev_attr_physical_line_partition,
>> +=09NULL
>> +};
>> +
>> +static int device_add_attrs(struct device *dev,
>> +=09=09=09    const struct device_attribute **dev_attrs)
>> +{
>> +=09int i, error =3D 0;
>> +=09struct device_attribute *dev_attr;
>> +=09char *buf;
>> +
>> +=09if (!dev_attrs)
>> +=09=09return 0;
>> +
>> +=09buf =3D kmalloc(PAGE_SIZE, GFP_KERNEL);
>> +=09if (!buf)
>> +=09=09return -ENOMEM;
>> +
>> +=09for (i =3D 0; dev_attrs[i]; i++) {
>> +=09=09dev_attr =3D (struct device_attribute *)dev_attrs[i];
>> +
>> +=09=09/* create attributes that provides meaningful value */
>> +=09=09if (dev_attr->show(dev, dev_attr, buf) < 0)
>> +=09=09=09continue;
>> +
>> +=09=09error =3D device_create_file(dev, dev_attrs[i]);
>> +=09=09if (error) {
>> +=09=09=09while (--i >=3D 0)
>> +=09=09=09=09device_remove_file(dev, dev_attrs[i]);
>> +=09=09=09break;
>> +=09=09}
>> +=09}
>> +
>> +=09kfree(buf);
>> +=09return error;
>> +}
>
> Ick, why create your own function for this when the driver core has this
> functionality built into it?  Look at the is_visible() callback, and how
> it is use for an attribute group please.
>

I agree even I added this function hesitantly as didn't realize that I can =
use
is_visible for this purpose. Thanks for pointing that out I will have a loo=
k
at it.

>> +static void device_remove_attrs(struct device *dev,
>> +=09=09=09=09const struct device_attribute **dev_attrs)
>> +{
>> +=09int i;
>> +
>> +=09if (!dev_attrs)
>> +=09=09return;
>> +
>> +=09for (i =3D 0; dev_attrs[i]; dev_attrs++, i++)
>> +=09=09device_remove_file(dev, dev_attrs[i]);
>> +}
>
> You should just remove a whole group at once, not individually.
>

Right, I must be able to get rid of these 2 functions once I use
is_visible callback.

>> +
>> +const struct device_attribute **
>> +__weak cache_get_priv_attr(struct device *cache_idx_dev)
>> +{
>> +=09return NULL;
>> +}
>> +
>> +/* Add/Remove cache interface for CPU device */
>> +static void cpu_cache_sysfs_exit(unsigned int cpu)
>> +{
>> +=09int i;
>> +=09struct device *tmp_dev;
>> +=09const struct device_attribute **ci_priv_attr;
>> +
>> +=09if (per_cpu_index_dev(cpu)) {
>> +=09=09for (i =3D 0; i < cache_leaves(cpu); i++) {
>> +=09=09=09tmp_dev =3D per_cache_index_dev(cpu, i);
>> +=09=09=09if (!tmp_dev)
>> +=09=09=09=09continue;
>> +=09=09=09ci_priv_attr =3D cache_get_priv_attr(tmp_dev);
>> +=09=09=09device_remove_attrs(tmp_dev, ci_priv_attr);
>> +=09=09=09device_remove_attrs(tmp_dev, cache_optional_attrs);
>> +=09=09=09device_unregister(tmp_dev);
>> +=09=09}
>> +=09=09kfree(per_cpu_index_dev(cpu));
>> +=09=09per_cpu_index_dev(cpu) =3D NULL;
>> +=09}
>> +=09device_unregister(per_cpu_cache_dev(cpu));
>> +=09per_cpu_cache_dev(cpu) =3D NULL;
>> +}
>> +
>> +static int cpu_cache_sysfs_init(unsigned int cpu)
>> +{
>> +=09struct device *dev =3D get_cpu_device(cpu);
>> +
>> +=09if (per_cpu_cacheinfo(cpu) =3D=3D NULL)
>> +=09=09return -ENOENT;
>> +
>> +=09per_cpu_cache_dev(cpu) =3D device_create(dev->class, dev, cpu,
>> +=09=09=09=09=09       NULL, "cache");
>> +=09if (IS_ERR_OR_NULL(per_cpu_cache_dev(cpu)))
>> +=09=09return PTR_ERR(per_cpu_cache_dev(cpu));
>> +
>> +=09/* Allocate all required memory */
>> +=09per_cpu_index_dev(cpu) =3D kzalloc(sizeof(struct device *) *
>> +=09=09=09=09=09 cache_leaves(cpu), GFP_KERNEL);
>> +=09if (unlikely(per_cpu_index_dev(cpu) =3D=3D NULL))
>> +=09=09goto err_out;
>> +
>> +=09return 0;
>> +
>> +err_out:
>> +=09cpu_cache_sysfs_exit(cpu);
>> +=09return -ENOMEM;
>> +}
>> +
>> +static int cache_add_dev(unsigned int cpu)
>> +{
>> +=09unsigned short i;
>> +=09int rc;
>> +=09struct device *tmp_dev, *parent;
>> +=09struct cacheinfo *this_leaf;
>> +=09const struct device_attribute **ci_priv_attr;
>> +=09struct cpu_cacheinfo *this_cpu_ci =3D get_cpu_cacheinfo(cpu);
>> +
>> +=09rc =3D cpu_cache_sysfs_init(cpu);
>> +=09if (unlikely(rc < 0))
>> +=09=09return rc;
>> +
>> +=09parent =3D per_cpu_cache_dev(cpu);
>> +=09for (i =3D 0; i < cache_leaves(cpu); i++) {
>> +=09=09this_leaf =3D this_cpu_ci->info_list + i;
>> +=09=09if (this_leaf->disable_sysfs)
>> +=09=09=09continue;
>> +=09=09tmp_dev =3D device_create_with_groups(parent->class, parent, i,
>> +=09=09=09=09=09=09    this_leaf,
>> +=09=09=09=09=09=09    cache_default_groups,
>> +=09=09=09=09=09=09    "index%1u", i);
>> +=09=09if (IS_ERR_OR_NULL(tmp_dev)) {
>> +=09=09=09rc =3D PTR_ERR(tmp_dev);
>> +=09=09=09goto err;
>> +=09=09}
>> +
>> +=09=09rc =3D device_add_attrs(tmp_dev, cache_optional_attrs);
>> +=09=09if (unlikely(rc))
>> +=09=09=09goto err;
>> +
>> +=09=09ci_priv_attr =3D cache_get_priv_attr(tmp_dev);
>> +=09=09rc =3D device_add_attrs(tmp_dev, ci_priv_attr);
>> +=09=09if (unlikely(rc))
>> +=09=09=09goto err;
>
> You just raced with userspace here, creating these files _after_ the
> device was announced to userspace, causing problems with anyone wanting
> to read these attributes :(
>
> I think if you fix up the is_visible() thing above, these calls will go
> away, right?
>

Yes I agree.

Regards,
Sudeep

^ permalink raw reply

* Re: [PATCH v2] Use the POWER8 Micro Partition Prefetch Engine in KVM HV on POWER8
From: Alexander Graf @ 2014-07-10 13:30 UTC (permalink / raw)
  To: Mel Gorman; +Cc: Stewart Smith, paulus, linuxppc-dev, kvm-ppc
In-Reply-To: <20140710133012.GR25275@novell.com>


On 10.07.14 15:30, Mel Gorman wrote:
> On Thu, Jul 10, 2014 at 03:17:16PM +0200, Alexander Graf wrote:
>> On 10.07.14 15:07, Mel Gorman wrote:
>>> On Thu, Jul 10, 2014 at 01:05:47PM +0200, Alexander Graf wrote:
>>>> On 09.07.14 00:59, Stewart Smith wrote:
>>>>> Hi!
>>>>>
>>>>> Thanks for review, much appreciated!
>>>>>
>>>>> Alexander Graf <agraf@suse.de> writes:
>>>>>> On 08.07.14 07:06, Stewart Smith wrote:
>>>>>>> @@ -1528,6 +1535,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
>>>>>>>    	int i, need_vpa_update;
>>>>>>>    	int srcu_idx;
>>>>>>>    	struct kvm_vcpu *vcpus_to_update[threads_per_core];
>>>>>>> +	phys_addr_t phy_addr, tmp;
>>>>>> Please put the variable declarations into the if () branch so that the
>>>>>> compiler can catch potential leaks :)
>>>>> ack. will fix.
>>>>>
>>>>>>> @@ -1590,9 +1598,48 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
>>>>>>>    	srcu_idx = srcu_read_lock(&vc->kvm->srcu);
>>>>>>> +	/* If we have a saved list of L2/L3, restore it */
>>>>>>> +	if (cpu_has_feature(CPU_FTR_ARCH_207S) && vc->mpp_buffer) {
>>>>>>> +		phy_addr = virt_to_phys((void *)vc->mpp_buffer);
>>>>>>> +#if defined(CONFIG_PPC_4K_PAGES)
>>>>>>> +		phy_addr = (phy_addr + 8*4096) & ~(8*4096);
>>>>>> get_free_pages() is automatically aligned to the order, no?
>>>>> That's what Paul reckoned too, and then we've attempted to find anywhere
>>>>> that documents that behaviour. Happen to be able to point to docs/source
>>>>> that say this is part of API?
>>>> Phew - it's probably buried somewhere. I could only find this
>>>> document saying that we always get order-aligned allocations:
>>>>
>>>> http://www.thehackademy.net/madchat/ebooks/Mem_virtuelle/linux-mm/zonealloc.html
>>>>
>>>> Mel, do you happen to have any pointer to something that explicitly
>>>> (or even properly implicitly) says that get_free_pages() returns
>>>> order-aligned memory?
>>>>
>>> I did not read the whole thread so I lack context and will just answer
>>> this part.
>>>
>>> There is no guarantee that pages are returned in PFN order for multiple
>>> requests to the page allocator. This is the relevant comment in
>>> rmqueue_bulk
>>>
>>>                  /*
>>>                   * Split buddy pages returned by expand() are received here
>>>                   * in physical page order. The page is added to the callers and
>>>                   * list and the list head then moves forward. From the callers
>>>                   * perspective, the linked list is ordered by page number in
>>>                   * some conditions. This is useful for IO devices that can
>>>                   * merge IO requests if the physical pages are ordered
>>>                   * properly.
>>>                   */
>>>
>>> It will probably be true early in the lifetime of the system but the milage
>>> will vary on systems with a lot of uptime. If you depend on this behaviour
>>> for correctness then you will have a bad day.
>>>
>>> High-order page requests to the page allocator are guaranteed to be in physical
>>> order. However, this does not apply to vmalloc() where allocations are
>>> only guaranteed to be virtually contiguous.
>> Hrm, ok to be very concrete:
>>
>>    Does __get_free_pages(..., 4); on a 4k page size system give me a
>> 64k aligned pointer? :)
>>
> Yes.

Awesome - thanks a lot! :)


Alex

^ permalink raw reply

* Re: [PATCH v2] Use the POWER8 Micro Partition Prefetch Engine in KVM HV on POWER8
From: Mel Gorman @ 2014-07-10 13:30 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Stewart Smith, paulus, linuxppc-dev, kvm-ppc
In-Reply-To: <53BE925C.2030401@suse.de>

On Thu, Jul 10, 2014 at 03:17:16PM +0200, Alexander Graf wrote:
> 
> On 10.07.14 15:07, Mel Gorman wrote:
> >On Thu, Jul 10, 2014 at 01:05:47PM +0200, Alexander Graf wrote:
> >>On 09.07.14 00:59, Stewart Smith wrote:
> >>>Hi!
> >>>
> >>>Thanks for review, much appreciated!
> >>>
> >>>Alexander Graf <agraf@suse.de> writes:
> >>>>On 08.07.14 07:06, Stewart Smith wrote:
> >>>>>@@ -1528,6 +1535,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
> >>>>>   	int i, need_vpa_update;
> >>>>>   	int srcu_idx;
> >>>>>   	struct kvm_vcpu *vcpus_to_update[threads_per_core];
> >>>>>+	phys_addr_t phy_addr, tmp;
> >>>>Please put the variable declarations into the if () branch so that the
> >>>>compiler can catch potential leaks :)
> >>>ack. will fix.
> >>>
> >>>>>@@ -1590,9 +1598,48 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
> >>>>>   	srcu_idx = srcu_read_lock(&vc->kvm->srcu);
> >>>>>+	/* If we have a saved list of L2/L3, restore it */
> >>>>>+	if (cpu_has_feature(CPU_FTR_ARCH_207S) && vc->mpp_buffer) {
> >>>>>+		phy_addr = virt_to_phys((void *)vc->mpp_buffer);
> >>>>>+#if defined(CONFIG_PPC_4K_PAGES)
> >>>>>+		phy_addr = (phy_addr + 8*4096) & ~(8*4096);
> >>>>get_free_pages() is automatically aligned to the order, no?
> >>>That's what Paul reckoned too, and then we've attempted to find anywhere
> >>>that documents that behaviour. Happen to be able to point to docs/source
> >>>that say this is part of API?
> >>Phew - it's probably buried somewhere. I could only find this
> >>document saying that we always get order-aligned allocations:
> >>
> >>http://www.thehackademy.net/madchat/ebooks/Mem_virtuelle/linux-mm/zonealloc.html
> >>
> >>Mel, do you happen to have any pointer to something that explicitly
> >>(or even properly implicitly) says that get_free_pages() returns
> >>order-aligned memory?
> >>
> >I did not read the whole thread so I lack context and will just answer
> >this part.
> >
> >There is no guarantee that pages are returned in PFN order for multiple
> >requests to the page allocator. This is the relevant comment in
> >rmqueue_bulk
> >
> >                 /*
> >                  * Split buddy pages returned by expand() are received here
> >                  * in physical page order. The page is added to the callers and
> >                  * list and the list head then moves forward. From the callers
> >                  * perspective, the linked list is ordered by page number in
> >                  * some conditions. This is useful for IO devices that can
> >                  * merge IO requests if the physical pages are ordered
> >                  * properly.
> >                  */
> >
> >It will probably be true early in the lifetime of the system but the milage
> >will vary on systems with a lot of uptime. If you depend on this behaviour
> >for correctness then you will have a bad day.
> >
> >High-order page requests to the page allocator are guaranteed to be in physical
> >order. However, this does not apply to vmalloc() where allocations are
> >only guaranteed to be virtually contiguous.
> 
> Hrm, ok to be very concrete:
> 
>   Does __get_free_pages(..., 4); on a 4k page size system give me a
> 64k aligned pointer? :)
> 

Yes.

-- 
Mel Gorman
SUSE Labs

^ permalink raw reply

* Re: [PATCH v2] Use the POWER8 Micro Partition Prefetch Engine in KVM HV on POWER8
From: Alexander Graf @ 2014-07-10 13:17 UTC (permalink / raw)
  To: Mel Gorman; +Cc: Stewart Smith, paulus, linuxppc-dev, kvm-ppc
In-Reply-To: <20140710130716.GQ25275@novell.com>


On 10.07.14 15:07, Mel Gorman wrote:
> On Thu, Jul 10, 2014 at 01:05:47PM +0200, Alexander Graf wrote:
>> On 09.07.14 00:59, Stewart Smith wrote:
>>> Hi!
>>>
>>> Thanks for review, much appreciated!
>>>
>>> Alexander Graf <agraf@suse.de> writes:
>>>> On 08.07.14 07:06, Stewart Smith wrote:
>>>>> @@ -1528,6 +1535,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
>>>>>    	int i, need_vpa_update;
>>>>>    	int srcu_idx;
>>>>>    	struct kvm_vcpu *vcpus_to_update[threads_per_core];
>>>>> +	phys_addr_t phy_addr, tmp;
>>>> Please put the variable declarations into the if () branch so that the
>>>> compiler can catch potential leaks :)
>>> ack. will fix.
>>>
>>>>> @@ -1590,9 +1598,48 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
>>>>>    	srcu_idx = srcu_read_lock(&vc->kvm->srcu);
>>>>> +	/* If we have a saved list of L2/L3, restore it */
>>>>> +	if (cpu_has_feature(CPU_FTR_ARCH_207S) && vc->mpp_buffer) {
>>>>> +		phy_addr = virt_to_phys((void *)vc->mpp_buffer);
>>>>> +#if defined(CONFIG_PPC_4K_PAGES)
>>>>> +		phy_addr = (phy_addr + 8*4096) & ~(8*4096);
>>>> get_free_pages() is automatically aligned to the order, no?
>>> That's what Paul reckoned too, and then we've attempted to find anywhere
>>> that documents that behaviour. Happen to be able to point to docs/source
>>> that say this is part of API?
>> Phew - it's probably buried somewhere. I could only find this
>> document saying that we always get order-aligned allocations:
>>
>> http://www.thehackademy.net/madchat/ebooks/Mem_virtuelle/linux-mm/zonealloc.html
>>
>> Mel, do you happen to have any pointer to something that explicitly
>> (or even properly implicitly) says that get_free_pages() returns
>> order-aligned memory?
>>
> I did not read the whole thread so I lack context and will just answer
> this part.
>
> There is no guarantee that pages are returned in PFN order for multiple
> requests to the page allocator. This is the relevant comment in
> rmqueue_bulk
>
>                  /*
>                   * Split buddy pages returned by expand() are received here
>                   * in physical page order. The page is added to the callers and
>                   * list and the list head then moves forward. From the callers
>                   * perspective, the linked list is ordered by page number in
>                   * some conditions. This is useful for IO devices that can
>                   * merge IO requests if the physical pages are ordered
>                   * properly.
>                   */
>
> It will probably be true early in the lifetime of the system but the milage
> will vary on systems with a lot of uptime. If you depend on this behaviour
> for correctness then you will have a bad day.
>
> High-order page requests to the page allocator are guaranteed to be in physical
> order. However, this does not apply to vmalloc() where allocations are
> only guaranteed to be virtually contiguous.

Hrm, ok to be very concrete:

   Does __get_free_pages(..., 4); on a 4k page size system give me a 64k 
aligned pointer? :)


Alex

^ permalink raw reply

* Re: [PATCH v2] Use the POWER8 Micro Partition Prefetch Engine in KVM HV on POWER8
From: Mel Gorman @ 2014-07-10 13:07 UTC (permalink / raw)
  To: Alexander Graf; +Cc: Stewart Smith, paulus, linuxppc-dev, kvm-ppc
In-Reply-To: <53BE738B.1010100@suse.de>

On Thu, Jul 10, 2014 at 01:05:47PM +0200, Alexander Graf wrote:
> 
> On 09.07.14 00:59, Stewart Smith wrote:
> >Hi!
> >
> >Thanks for review, much appreciated!
> >
> >Alexander Graf <agraf@suse.de> writes:
> >>On 08.07.14 07:06, Stewart Smith wrote:
> >>>@@ -1528,6 +1535,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
> >>>   	int i, need_vpa_update;
> >>>   	int srcu_idx;
> >>>   	struct kvm_vcpu *vcpus_to_update[threads_per_core];
> >>>+	phys_addr_t phy_addr, tmp;
> >>Please put the variable declarations into the if () branch so that the
> >>compiler can catch potential leaks :)
> >ack. will fix.
> >
> >>>@@ -1590,9 +1598,48 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
> >>>   	srcu_idx = srcu_read_lock(&vc->kvm->srcu);
> >>>+	/* If we have a saved list of L2/L3, restore it */
> >>>+	if (cpu_has_feature(CPU_FTR_ARCH_207S) && vc->mpp_buffer) {
> >>>+		phy_addr = virt_to_phys((void *)vc->mpp_buffer);
> >>>+#if defined(CONFIG_PPC_4K_PAGES)
> >>>+		phy_addr = (phy_addr + 8*4096) & ~(8*4096);
> >>get_free_pages() is automatically aligned to the order, no?
> >That's what Paul reckoned too, and then we've attempted to find anywhere
> >that documents that behaviour. Happen to be able to point to docs/source
> >that say this is part of API?
> 
> Phew - it's probably buried somewhere. I could only find this
> document saying that we always get order-aligned allocations:
> 
> http://www.thehackademy.net/madchat/ebooks/Mem_virtuelle/linux-mm/zonealloc.html
> 
> Mel, do you happen to have any pointer to something that explicitly
> (or even properly implicitly) says that get_free_pages() returns
> order-aligned memory?
> 

I did not read the whole thread so I lack context and will just answer
this part.

There is no guarantee that pages are returned in PFN order for multiple
requests to the page allocator. This is the relevant comment in
rmqueue_bulk

                /*
                 * Split buddy pages returned by expand() are received here
                 * in physical page order. The page is added to the callers and
                 * list and the list head then moves forward. From the callers
                 * perspective, the linked list is ordered by page number in
                 * some conditions. This is useful for IO devices that can
                 * merge IO requests if the physical pages are ordered
                 * properly.
                 */

It will probably be true early in the lifetime of the system but the milage
will vary on systems with a lot of uptime. If you depend on this behaviour
for correctness then you will have a bad day.

High-order page requests to the page allocator are guaranteed to be in physical
order. However, this does not apply to vmalloc() where allocations are
only guaranteed to be virtually contiguous.

-- 
Mel Gorman
SUSE Labs

^ permalink raw reply

* Re: [PATCH v2] Use the POWER8 Micro Partition Prefetch Engine in KVM HV on POWER8
From: Alexander Graf @ 2014-07-10 11:05 UTC (permalink / raw)
  To: Stewart Smith, linuxppc-dev, paulus, kvm-ppc, Mel Gorman
In-Reply-To: <m3bnszqwx1.fsf@oc8180480414.ibm.com>


On 09.07.14 00:59, Stewart Smith wrote:
> Hi!
>
> Thanks for review, much appreciated!
>
> Alexander Graf <agraf@suse.de> writes:
>> On 08.07.14 07:06, Stewart Smith wrote:
>>> @@ -1528,6 +1535,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
>>>    	int i, need_vpa_update;
>>>    	int srcu_idx;
>>>    	struct kvm_vcpu *vcpus_to_update[threads_per_core];
>>> +	phys_addr_t phy_addr, tmp;
>> Please put the variable declarations into the if () branch so that the
>> compiler can catch potential leaks :)
> ack. will fix.
>
>>> @@ -1590,9 +1598,48 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
>>>    
>>>    	srcu_idx = srcu_read_lock(&vc->kvm->srcu);
>>>    
>>> +	/* If we have a saved list of L2/L3, restore it */
>>> +	if (cpu_has_feature(CPU_FTR_ARCH_207S) && vc->mpp_buffer) {
>>> +		phy_addr = virt_to_phys((void *)vc->mpp_buffer);
>>> +#if defined(CONFIG_PPC_4K_PAGES)
>>> +		phy_addr = (phy_addr + 8*4096) & ~(8*4096);
>> get_free_pages() is automatically aligned to the order, no?
> That's what Paul reckoned too, and then we've attempted to find anywhere
> that documents that behaviour. Happen to be able to point to docs/source
> that say this is part of API?

Phew - it's probably buried somewhere. I could only find this document 
saying that we always get order-aligned allocations:

http://www.thehackademy.net/madchat/ebooks/Mem_virtuelle/linux-mm/zonealloc.html

Mel, do you happen to have any pointer to something that explicitly (or 
even properly implicitly) says that get_free_pages() returns 
order-aligned memory?

>
>>> +#endif
>>> +		tmp = phy_addr & PPC_MPPE_ADDRESS_MASK;
>>> +		tmp = tmp | PPC_MPPE_WHOLE_TABLE;
>>> +
>>> +		/* For sanity, abort any 'save' requests in progress */
>>> +		asm volatile(PPC_LOGMPP(R1) : : "r" (tmp));
>>> +
>>> +		/* Inititate a cache-load request */
>>> +		mtspr(SPRN_MPPR, tmp);
>>> +	}
>> In fact, this whole block up here could be a function, no?
> It could, perfectly happy for it to be one. Will fix.
>
>>> +
>>> +	/* Allocate memory before switching out of guest so we don't
>>> +	   trash L2/L3 with memory allocation stuff */
>>> +	if (cpu_has_feature(CPU_FTR_ARCH_207S) && !vc->mpp_buffer) {
>>> +		vc->mpp_buffer = __get_free_pages(GFP_KERNEL|__GFP_ZERO,
>>> +						  MPP_BUFFER_ORDER);
>> get_order(64 * 1024)?
>>
>> Also, why allocate it here and not on vcore creation?
> There's also the possibility of saving/restorting part of the L3 cache
> as well, and I was envisioning a future patch to this which checks a
> flag in vcore (maybe exposed via sysfs or whatever mechanism is
> applicable) if it should save/restore L2 or L2/L3, so thus it makes a
> bit more sense allocating it there rather than elsewhere.
>
> There's also no real reason to fail to create a vcore if we can't
> allocate a buffer for L2/L3 cache contents - retrying later is perfectly
> harmless.

If we failed during core creation just don't save/restore L2 cache 
contents at all. I really prefer to have allocation and dealloction all 
at init time - and such low order allocations will most likely succeed.

Let's leave the L3 cache bits for later when we know whether it actually 
has an impact. I personally doubt it :).


Alex

^ permalink raw reply

* Re: [PATCH] powerpc/kvm: Create proper names for the kvm_host_state PMU fields
From: Alexander Graf @ 2014-07-10 10:16 UTC (permalink / raw)
  To: Michael Ellerman, linuxppc-dev; +Cc: Paul Mackerras, kvm
In-Reply-To: <1404984871-15145-1-git-send-email-mpe@ellerman.id.au>


On 10.07.14 11:34, Michael Ellerman wrote:
> We have two arrays in kvm_host_state that contain register values for
> the PMU. Currently we only create an asm-offsets symbol for the base of
> the arrays, and do the array offset in the assembly code.
>
> Creating an asm-offsets symbol for each field individually makes the
> code much nicer to read, particularly for the MMCRx/SIxR/SDAR fields, and
> might have helped us notice the recent double restore bug we had in this
> code.
>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

Acked-by: Alexander Graf <agraf@suse.de>

I still think this whole code path should just be C though.


Alex

^ permalink raw reply

* Re: [PATCH 1/3] PCI/MSI: Add pci_enable_msi_partial()
From: Alexander Gordeev @ 2014-07-10 10:11 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-mips@linux-mips.org, linux-s390@vger.kernel.org,
	linux-pci@vger.kernel.org, x86@kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-ide@vger.kernel.org, open list:INTEL IOMMU (VT-d),
	xen-devel@lists.xenproject.org, linuxppc-dev
In-Reply-To: <CAErSpo4oiabgoOjsGdWZpCMPnmopK4xRzB2f3tM0AiUFrdhFww@mail.gmail.com>

On Wed, Jul 09, 2014 at 10:06:48AM -0600, Bjorn Helgaas wrote:
> Out of curiosity, do you have a pointer to this?  It looks like it

I.e. ICH8 chapter 12.1.30 or ICH10 chapter 14.1.27

> uses one vector per port, and I'm wondering if the reason it requests
> 16 is because there's some possibility of a part with more than 8
> ports.

I doubt that is the reason. The only allowed MME values (powers of two)
are 0b000, 0b001, 0b010 and 0b100. As you can see, only one bit is used -
I would speculate it suits nicely to some hardware logic.

BTW, apart from AHCI, it seems the reason MSI is not going to disappear
(in a decade at least) is it is way cheaper to implement than MSI-X.

> > No, this is not an erratum. The value of 8 vectors is reserved and could
> > cause undefined results if used.
> 
> As I read the spec (PCI 3.0, sec 6.8.1.3), if MMC contains 0b100
> (requesting 16 vectors), the OS is allowed to allocate 1, 2, 4, 8, or
> 16 vectors.  If allocating 8 vectors and writing 0b011 to MME causes
> undefined results, I'd say that's a chipset defect.

Well, the PCI spec does not prevent devices to have their own specs on top
of it. Undefined results are meant on the device side here. On the MSI side
these results are likely perfectly within the PCI spec. I feel speaking as
a lawer here ;)

> Interrupt vector space is the issue I would worry about, but I think
> I'm going to put this on the back burner until it actually becomes a
> problem.

I plan to try get rid of arch_msi_check_device() hook. Should I repost
this series afterwards?

Thanks!

-- 
Regards,
Alexander Gordeev
agordeev@redhat.com

^ 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