* [PATCH V2] cxl: Fix timebase synchronization status on P9
From: Christophe Lombard @ 2018-02-15 16:52 UTC (permalink / raw)
To: linuxppc-dev, fbarrat, vaibhav, andrew.donnellan
The PSL Timebase register is updated by the PSL to maintain the
timebase.
On P9, the Timebase value is only provided by the CAPP as received
the last time a timebase request was performed.
The timebase requests are initiated through the adapter configuration or
application registers.
The specific sysfs entry "/sys/class/cxl/cardxx/psl_timebase_synced" is
now dynamically updated according the content of the PSL Timebase
register.
Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com>
---
Changelog[v2]
- Missing Signed-off-by
- Spaces required around the ':'
---
drivers/misc/cxl/pci.c | 35 +++++++++++++++++++----------------
drivers/misc/cxl/sysfs.c | 14 ++++++++++++++
2 files changed, 33 insertions(+), 16 deletions(-)
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 758842f..270afb5 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -612,8 +612,6 @@ static u64 timebase_read_xsl(struct cxl *adapter)
static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
{
- u64 psl_tb;
- int delta;
unsigned int retry = 0;
struct device_node *np;
@@ -641,20 +639,25 @@ static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
cxl_p1_write(adapter, CXL_PSL_Control, 0x0000000000000000);
cxl_p1_write(adapter, CXL_PSL_Control, CXL_PSL_Control_tb);
- /* Wait until CORE TB and PSL TB difference <= 16usecs */
- do {
- msleep(1);
- if (retry++ > 5) {
- dev_info(&dev->dev, "PSL timebase can't synchronize\n");
- return;
- }
- psl_tb = adapter->native->sl_ops->timebase_read(adapter);
- delta = mftb() - psl_tb;
- if (delta < 0)
- delta = -delta;
- } while (tb_to_ns(delta) > 16000);
-
- adapter->psl_timebase_synced = true;
+ if (cxl_is_power8()) {
+ u64 psl_tb;
+ int delta;
+
+ /* Wait until CORE TB and PSL TB difference <= 16usecs */
+ do {
+ msleep(1);
+ if (retry++ > 5) {
+ dev_info(&dev->dev, "PSL timebase can't synchronize\n");
+ return;
+ }
+ psl_tb = adapter->native->sl_ops->timebase_read(adapter);
+ delta = mftb() - psl_tb;
+ if (delta < 0)
+ delta = -delta;
+ } while (tb_to_ns(delta) > 16000);
+
+ adapter->psl_timebase_synced = true;
+ }
return;
}
diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c
index a8b6d6a..5384c59 100644
--- a/drivers/misc/cxl/sysfs.c
+++ b/drivers/misc/cxl/sysfs.c
@@ -63,6 +63,20 @@ static ssize_t psl_timebase_synced_show(struct device *device,
{
struct cxl *adapter = to_cxl_adapter(device);
+ /*
+ * On P9, the Timebase value is only updated as a result of
+ * PSL TimeBase command sent to CAPP.
+ */
+ if (cxl_is_power9()) {
+ u64 psl_tb;
+ int delta;
+
+ psl_tb = cxl_p1_read(adapter, CXL_PSL9_Timebase);
+ delta = mftb() - psl_tb;
+ if (delta < 0)
+ delta = -delta;
+ adapter->psl_timebase_synced = true ? tb_to_ns(delta) < 16000 : false;
+ }
return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced);
}
--
2.7.4
^ permalink raw reply related
* Re: [RFC][PATCH bpf v2 1/2] bpf: allow 64-bit offsets for bpf function calls
From: Daniel Borkmann @ 2018-02-15 16:25 UTC (permalink / raw)
To: Sandipan Das, ast; +Cc: netdev, linuxppc-dev, mpe, naveen.n.rao
In-Reply-To: <20180213040600.5821-1-sandipan@linux.vnet.ibm.com>
On 02/13/2018 05:05 AM, Sandipan Das wrote:
> The imm field of a bpf_insn is a signed 32-bit integer. For
> JIT-ed bpf-to-bpf function calls, it stores the offset from
> __bpf_call_base to the start of the callee function.
>
> For some architectures, such as powerpc64, it was found that
> this offset may be as large as 64 bits because of which this
> cannot be accomodated in the imm field without truncation.
>
> To resolve this, we additionally make aux->func within each
> bpf_prog associated with the functions to point to the list
> of all function addresses determined by the verifier.
>
> We keep the value assigned to the off field of the bpf_insn
> as a way to index into aux->func and also set aux->func_cnt
> so that this can be used for performing basic upper bound
> checks for the off field.
>
> Signed-off-by: Sandipan Das <sandipan@linux.vnet.ibm.com>
> ---
> v2: Make aux->func point to the list of functions determined
> by the verifier rather than allocating a separate callee
> list for each function.
Approach looks good to me; do you know whether s390x JIT would
have similar requirement? I think one limitation that would still
need to be addressed later with such approach would be regarding the
xlated prog dump in bpftool, see 'BPF calls via JIT' in 7105e828c087
("bpf: allow for correlation of maps and helpers in dump"). Any
ideas for this (potentially if we could use off + imm for calls,
we'd get to 48 bits, but that seems still not be enough as you say)?
Thanks,
Daniel
^ permalink raw reply
* Re: [PATCH 0/3] perf trace powerpc: Remove libaudit dependency for syscalls
From: Arnaldo Carvalho de Melo @ 2018-02-15 13:56 UTC (permalink / raw)
To: Ravi Bangoria
Cc: alexander.shishkin, jolsa, namhyung, linux-kernel, brueckner,
tmricht, linuxppc-dev, mpe
In-Reply-To: <20180215134336.GD22818@kernel.org>
Em Thu, Feb 15, 2018 at 10:43:36AM -0300, Arnaldo Carvalho de Melo escreveu:
> Em Mon, Jan 29, 2018 at 02:04:14PM +0530, Ravi Bangoria escreveu:
> > This is almost identical set of patches recently done for s390.
> >
> > With this, user can run perf trace without libaudit on powerpc
> > as well. Ex,
> >
> > $ make
> > ... libaudit: [ OFF ]
> >
> > $ ./perf trace ls
>
> Thanks, applied.
Ah, I already had to update the unistd.h copy to catch some new syscalls
for s/390 :-)
https://git.kernel.org/acme/c/b4ec64dc68da
- Arnaldo
^ permalink raw reply
* Re: [PATCH 0/3] perf trace powerpc: Remove libaudit dependency for syscalls
From: Arnaldo Carvalho de Melo @ 2018-02-15 13:43 UTC (permalink / raw)
To: Ravi Bangoria
Cc: alexander.shishkin, jolsa, namhyung, linux-kernel, brueckner,
tmricht, linuxppc-dev, mpe
In-Reply-To: <20180129083417.31240-1-ravi.bangoria@linux.vnet.ibm.com>
Em Mon, Jan 29, 2018 at 02:04:14PM +0530, Ravi Bangoria escreveu:
> This is almost identical set of patches recently done for s390.
>
> With this, user can run perf trace without libaudit on powerpc
> as well. Ex,
>
> $ make
> ... libaudit: [ OFF ]
>
> $ ./perf trace ls
Thanks, applied.
- Arnaldo
^ permalink raw reply
* [PATCH] powerpc/eeh: Add conditional check on notify_resume
From: Bryant G. Ly @ 2018-02-15 18:49 UTC (permalink / raw)
To: benh, paulus, mpe; +Cc: seroyer, jjalvare, aik, ruscur, linuxppc-dev
From: "Juan J. Alvarez" <jjalvare@linux.vnet.ibm.com>
EEH structure is not populated with function
notify resume when running on systems that do not support
it, i.e: BMC. Hence adding a conditional check for NULL for
systems that don't add function notify_resume.
Signed-off-by: Juan J. Alvarez <jjalvare@linux.vnet.ibm.com>
Reviewed-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
Tested-by: Carol L. Soto <clsoto@us.ibm.com>
---
arch/powerpc/kernel/eeh_driver.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index beea218..0c0b66f 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -384,7 +384,8 @@ static void *eeh_report_resume(void *data, void *userdata)
eeh_pcid_put(dev);
pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
#ifdef CONFIG_PCI_IOV
- eeh_ops->notify_resume(eeh_dev_to_pdn(edev));
+ if (eeh_ops->notify_resume && eeh_dev_to_pdn(edev))
+ eeh_ops->notify_resume(eeh_dev_to_pdn(edev));
#endif
return NULL;
}
--
2.7.2
^ permalink raw reply related
* Re: [RFC][PATCH bpf v2 1/2] bpf: allow 64-bit offsets for bpf function calls
From: Daniel Borkmann @ 2018-02-15 20:18 UTC (permalink / raw)
To: Sandipan Das, ast; +Cc: netdev, linuxppc-dev, mpe, naveen.n.rao
In-Reply-To: <d39a3902-39bc-df56-71bf-0e6f9869ce14@iogearbox.net>
On 02/15/2018 05:25 PM, Daniel Borkmann wrote:
> On 02/13/2018 05:05 AM, Sandipan Das wrote:
>> The imm field of a bpf_insn is a signed 32-bit integer. For
>> JIT-ed bpf-to-bpf function calls, it stores the offset from
>> __bpf_call_base to the start of the callee function.
>>
>> For some architectures, such as powerpc64, it was found that
>> this offset may be as large as 64 bits because of which this
>> cannot be accomodated in the imm field without truncation.
>>
>> To resolve this, we additionally make aux->func within each
>> bpf_prog associated with the functions to point to the list
>> of all function addresses determined by the verifier.
>>
>> We keep the value assigned to the off field of the bpf_insn
>> as a way to index into aux->func and also set aux->func_cnt
>> so that this can be used for performing basic upper bound
>> checks for the off field.
>>
>> Signed-off-by: Sandipan Das <sandipan@linux.vnet.ibm.com>
>> ---
>> v2: Make aux->func point to the list of functions determined
>> by the verifier rather than allocating a separate callee
>> list for each function.
>
> Approach looks good to me; do you know whether s390x JIT would
> have similar requirement? I think one limitation that would still
> need to be addressed later with such approach would be regarding the
> xlated prog dump in bpftool, see 'BPF calls via JIT' in 7105e828c087
> ("bpf: allow for correlation of maps and helpers in dump"). Any
> ideas for this (potentially if we could use off + imm for calls,
> we'd get to 48 bits, but that seems still not be enough as you say)?
One other random thought, although I'm not sure how feasible this
is for ppc64 JIT to realize ... but idea would be to have something
like the below:
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 29ca920..daa7258 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -512,6 +512,11 @@ int bpf_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
return ret;
}
+void * __weak bpf_jit_image_alloc(unsigned long size)
+{
+ return module_alloc(size);
+}
+
struct bpf_binary_header *
bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
unsigned int alignment,
@@ -525,7 +530,7 @@ bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr,
* random section of illegal instructions.
*/
size = round_up(proglen + sizeof(*hdr) + 128, PAGE_SIZE);
- hdr = module_alloc(size);
+ hdr = bpf_jit_image_alloc(size);
if (hdr == NULL)
return NULL;
And ppc64 JIT could override bpf_jit_image_alloc() in a similar way
like some archs would override the module_alloc() helper through a
custom implementation, usually via __vmalloc_node_range(), so we
could perhaps fit the range for BPF JITed images in a way that they
could use the 32bit imm in the end? There are not that many progs
loaded typically, so the range could be a bit narrower in such case
anyway. (Not sure if this would work out though, but I thought to
bring it up.)
Thanks,
Daniel
^ permalink raw reply related
* [RFC 0/4] powerpc/drcinfo: Fix bugs 'ibm,drc-info' property
From: Michael Bringmann @ 2018-02-15 21:53 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
This patch set corrects some errors and omissions in the previous
set of patches adding support for the "ibm,drc-info" property to
powerpc systems.
Unfortunately, some errors in the previous patch set break things
in some of the DLPAR operations. In particular when attempting to
hot-add a new CPU or set of CPUs, the original patch failed to
properly calculate the available resources, and aborted the operation.
In addition, the original set missed several opportunities to compress
and reuse common code, especially, in the area of device processing.
Signed-off-by: Michael W. Bringmann <mwb@linux.vnet.ibm.com>
^ permalink raw reply
* [RFC 1/4] powerpc/hotplug/drcinfo: Fix bugs parsing ibm,drc-info structs
From: Michael Bringmann @ 2018-02-15 21:54 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, Michael Ellerman, John Allen,
Tyrel Datwyler, Thomas Falcon
In-Reply-To: <531f98fb-a29b-53e2-e7d5-870a531b76fd@linux.vnet.ibm.com>
This patch fixes a memory parsing bug when using of_prop_next_u32
calls at the start of a structure. Depending upon the value of
"cur" memory pointer argument to of_prop_next_u32, it will or it
won't advance the value of the returned memory pointer by the
size of one u32. This patch corrects the code to deal with that
indexing feature when parsing the ibm,drc-info structs for CPUs.
Also, need to advance the pointer at the end of_read_drc_info_cell
for same reason.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmware feature" -- end of patch series applied to powerpc next)
---
arch/powerpc/platforms/pseries/of_helpers.c | 4 +---
arch/powerpc/platforms/pseries/pseries_energy.c | 2 ++
drivers/pci/hotplug/rpaphp_core.c | 1 +
3 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/of_helpers.c b/arch/powerpc/platforms/pseries/of_helpers.c
index 7eea891..20598b2 100644
--- a/arch/powerpc/platforms/pseries/of_helpers.c
+++ b/arch/powerpc/platforms/pseries/of_helpers.c
@@ -65,9 +65,7 @@ int of_read_drc_info_cell(struct property **prop, const __be32 **curval,
/* Get drc-index-start:encode-int */
p2 = (const __be32 *)p;
- p2 = of_prop_next_u32(*prop, p2, &data->drc_index_start);
- if (!p2)
- return -EINVAL;
+ data->drc_index_start = of_read_number(p2, 1);
/* Get drc-name-suffix-start:encode-int */
p2 = of_prop_next_u32(*prop, p2, &data->drc_name_suffix_start);
diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c
index 6ed2212..c7d84aa 100644
--- a/arch/powerpc/platforms/pseries/pseries_energy.c
+++ b/arch/powerpc/platforms/pseries/pseries_energy.c
@@ -64,6 +64,7 @@ static u32 cpu_to_drc_index(int cpu)
value = of_prop_next_u32(info, NULL, &num_set_entries);
if (!value)
goto err_of_node_put;
+ value++;
for (j = 0; j < num_set_entries; j++) {
@@ -126,6 +127,7 @@ static int drc_index_to_cpu(u32 drc_index)
value = of_prop_next_u32(info, NULL, &num_set_entries);
if (!value)
goto err_of_node_put;
+ value++;
for (j = 0; j < num_set_entries; j++) {
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 53902c7..477a21c 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -253,6 +253,7 @@ static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
value = of_prop_next_u32(info, NULL, &entries);
if (!value)
return -EINVAL;
+ value++;
for (j = 0; j < entries; j++) {
of_read_drc_info_cell(&info, &value, &drc);
^ permalink raw reply related
* [RFC 2/4] powerpc/hotplug/drcinfo: Provide common parser for ibm,drc-info
From: Michael Bringmann @ 2018-02-15 21:55 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
In-Reply-To: <531f98fb-a29b-53e2-e7d5-870a531b76fd@linux.vnet.ibm.com>
This patch provides a common parse function for the ibm,drc-info
property that can be modified by a callback function. The caller
provides a pointer to the function and a pointer to their unique
data, and the parser provides the current lmb set from the struct.
The callback function may return codes indicating that the parsing
is complete, or should continue, along with an error code that may
be returned to the caller.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmwar
e feature" -- end of patch series applied to powerpc next)
---
arch/powerpc/include/asm/prom.h | 7 +++
arch/powerpc/platforms/pseries/Makefile | 2 -
arch/powerpc/platforms/pseries/drchelpers.c | 66 +++++++++++++++++++++++++++
3 files changed, 74 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/platforms/pseries/drchelpers.c
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index 7db7958..e75963e 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -94,6 +94,13 @@ struct of_drc_info {
extern int of_read_drc_info_cell(struct property **prop,
const __be32 **curval, struct of_drc_info *data);
+extern int drc_info_parser(struct device_node *dn,
+ int (*usercb)(struct of_drc_info *drc,
+ void *data,
+ void *optional_data,
+ int *ret_code),
+ char *opt_drc_type,
+ void *data);
/*
* There are two methods for telling firmware what our capabilities are.
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile
index 13eede6..38c8547 100644
--- a/arch/powerpc/platforms/pseries/Makefile
+++ b/arch/powerpc/platforms/pseries/Makefile
@@ -3,7 +3,7 @@ ccflags-$(CONFIG_PPC64) := $(NO_MINIMAL_TOC)
ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG
obj-y := lpar.o hvCall.o nvram.o reconfig.o \
- of_helpers.o \
+ of_helpers.o drchelpers.o \
setup.o iommu.o event_sources.o ras.o \
firmware.o power.o dlpar.o mobility.o rng.o \
pci.o pci_dlpar.o eeh_pseries.o msi.o
diff --git a/arch/powerpc/platforms/pseries/drchelpers.c b/arch/powerpc/platforms/pseries/drchelpers.c
new file mode 100644
index 0000000..556e05d
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/drchelpers.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 Michael Bringmann <mbringm@us.ibm.com>, IBM
+ *
+ * pSeries specific routines for device-tree properties.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+
+#include <asm/prom.h>
+#include "pseries.h"
+
+#define MAX_DRC_NAME_LEN 64
+
+int drc_info_parser(struct device_node *dn,
+ int (*usercb)(struct of_drc_info *drc,
+ void *data,
+ void *optional_data,
+ int *ret_code),
+ char *opt_drc_type,
+ void *data)
+{
+ struct property *info;
+ unsigned int entries;
+ struct of_drc_info drc;
+ const __be32 *value;
+ int j, done = 0, ret_code = -EINVAL;
+
+ info = of_find_property(dn, "ibm,drc-info", NULL);
+ if (info == NULL)
+ return -EINVAL;
+
+ value = of_prop_next_u32(info, NULL, &entries);
+ if (!value)
+ return -EINVAL;
+ value++;
+
+ for (j = 0, done = 0; (j < entries) && (!done); j++) {
+ of_read_drc_info_cell(&info, &value, &drc);
+
+ if (opt_drc_type && strcmp(opt_drc_type, drc.drc_type))
+ continue;
+
+ done = usercb(&drc, data, NULL, &ret_code);
+ }
+
+ return ret_code;
+}
+EXPORT_SYMBOL(drc_info_parser);
^ permalink raw reply related
* [RFC 4/4] powerpc/hotplug/drcinfo: Improve code for ibm,drc-info device processing
From: Michael Bringmann @ 2018-02-15 21:56 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
In-Reply-To: <531f98fb-a29b-53e2-e7d5-870a531b76fd@linux.vnet.ibm.com>
This patch extends the use of a common parse function for the
ibm,drc-info property that can be modified by a callback function
to the hotplug device processing. Candidate code is replaced by
a call to the parser including a pointer to a local context-specific
functions, and local data.
In addition, the original set missed several opportunities to compress
and reuse common code which this patch attempts to provide.
Finally, a bug with the registration of slots was observed on some
systems, and the code was rewritten to prevent its reoccurrence.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmwar
e feature" -- end of patch series applied to powerpc next)
---
drivers/pci/hotplug/rpaphp_core.c | 188 ++++++++++++++++++++++++++-----------
1 file changed, 130 insertions(+), 58 deletions(-)
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 477a21c..2c3992d 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -236,49 +236,52 @@ static int rpaphp_check_drc_props_v1(struct device_node *dn, char *drc_name,
return -EINVAL;
}
-static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
- char *drc_type, unsigned int my_index)
+struct check_drc_props_v2_struct {
+ char *drc_name;
+ char *drc_type;
+ unsigned int my_index;
+};
+
+static int check_drc_props_v2_checkRun(struct of_drc_info *drc,
+ void *idata, void *not_used,
+ int *ret_code)
{
- struct property *info;
- unsigned int entries;
- struct of_drc_info drc;
- const __be32 *value;
+ struct check_drc_props_v2_struct *cdata = idata;
char cell_drc_name[MAX_DRC_NAME_LEN];
- int j, fndit;
-
- info = of_find_property(dn->parent, "ibm,drc-info", NULL);
- if (info == NULL)
- return -EINVAL;
-
- value = of_prop_next_u32(info, NULL, &entries);
- if (!value)
- return -EINVAL;
- value++;
-
- for (j = 0; j < entries; j++) {
- of_read_drc_info_cell(&info, &value, &drc);
- /* Should now know end of current entry */
+ (*ret_code) = -EINVAL;
- if (my_index > drc.last_drc_index)
- continue;
+ if (cdata->my_index > drc->last_drc_index)
+ return 0;
- fndit = 1;
- break;
+ /* Found drc_index. Now match the rest. */
+ sprintf(cell_drc_name, "%s%d", drc->drc_name_prefix,
+ cdata->my_index - drc->drc_index_start +
+ drc->drc_name_suffix_start);
+
+ if (((cdata->drc_name == NULL) ||
+ (cdata->drc_name && !strcmp(cdata->drc_name, cell_drc_name))) &&
+ ((cdata->drc_type == NULL) ||
+ (cdata->drc_type && !strcmp(cdata->drc_type, drc->drc_type)))) {
+ (*ret_code) = 0;
+ return 1;
}
- /* Found it */
- if (fndit)
- sprintf(cell_drc_name, "%s%d", drc.drc_name_prefix,
- my_index);
+ return 0;
+}
- if (((drc_name == NULL) ||
- (drc_name && !strcmp(drc_name, cell_drc_name))) &&
- ((drc_type == NULL) ||
- (drc_type && !strcmp(drc_type, drc.drc_type))))
- return 0;
+static int rpaphp_check_drc_props_v2(struct device_node *dn, char *drc_name,
+ char *drc_type, unsigned int my_index)
+{
+ struct device_node *root = dn;
+ struct check_drc_props_v2_struct cdata = {
+ drc_name, drc_type, be32_to_cpu(my_index) };
- return -EINVAL;
+ if (drc_type && strcmp(drc_type, "SLOT"))
+ root = dn->parent;
+
+ return drc_info_parser(root, check_drc_props_v2_checkRun,
+ drc_type, &cdata);
}
int rpaphp_check_drc_props(struct device_node *dn, char *drc_name,
@@ -301,7 +304,6 @@ int rpaphp_check_drc_props(struct device_node *dn, char *drc_name,
}
EXPORT_SYMBOL_GPL(rpaphp_check_drc_props);
-
static int is_php_type(char *drc_type)
{
unsigned long value;
@@ -361,17 +363,40 @@ static int is_php_dn(struct device_node *dn, const int **indexes,
*
* To remove a slot, it suffices to call rpaphp_deregister_slot().
*/
-int rpaphp_add_slot(struct device_node *dn)
+
+static int rpaphp_add_slot_common(struct device_node *dn,
+ u32 drc_index, char *drc_name, char *drc_type,
+ u32 drc_power_domain)
{
struct slot *slot;
int retval = 0;
- int i;
+
+ slot = alloc_slot_struct(dn, drc_index, drc_name,
+ drc_power_domain);
+ if (!slot)
+ return -ENOMEM;
+
+ slot->type = simple_strtoul(drc_type, NULL, 10);
+
+ dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
+ drc_index, drc_name, drc_type);
+
+ retval = rpaphp_enable_slot(slot);
+ if (!retval)
+ retval = rpaphp_register_slot(slot);
+
+ if (retval)
+ dealloc_slot_struct(slot);
+
+ return retval;
+}
+
+static int rpaphp_add_slot_v1(struct device_node *dn)
+{
+ int i, retval = 0;
const int *indexes, *names, *types, *power_domains;
char *name, *type;
- if (!dn->name || strcmp(dn->name, "pci"))
- return 0;
-
/* If this is not a hotplug slot, return without doing anything. */
if (!is_php_dn(dn, &indexes, &names, &types, &power_domains))
return 0;
@@ -382,25 +407,13 @@ int rpaphp_add_slot(struct device_node *dn)
name = (char *) &names[1];
type = (char *) &types[1];
for (i = 0; i < be32_to_cpu(indexes[0]); i++) {
- int index;
-
- index = be32_to_cpu(indexes[i + 1]);
- slot = alloc_slot_struct(dn, index, name,
- be32_to_cpu(power_domains[i + 1]));
- if (!slot)
- return -ENOMEM;
-
- slot->type = simple_strtoul(type, NULL, 10);
-
- dbg("Found drc-index:0x%x drc-name:%s drc-type:%s\n",
- index, name, type);
-
- retval = rpaphp_enable_slot(slot);
+
+ retval = rpaphp_add_slot_common(dn,
+ be32_to_cpu(indexes[i + 1]),
+ name, type,
+ be32_to_cpu(power_domains[i + 1]));
if (!retval)
- retval = rpaphp_register_slot(slot);
-
- if (retval)
- dealloc_slot_struct(slot);
+ return retval;
name += strlen(name) + 1;
type += strlen(type) + 1;
@@ -410,6 +423,65 @@ int rpaphp_add_slot(struct device_node *dn)
/* XXX FIXME: reports a failure only if last entry in loop failed */
return retval;
}
+
+struct rpaphp_add_slot_v2_struct {
+ struct device_node *dn;
+};
+
+static int rpaphp_add_slot_v2_checkRun(struct of_drc_info *drc,
+ void *idata, void *not_used,
+ int *ret_code)
+{
+ struct rpaphp_add_slot_v2_struct *cdata = idata;
+ u32 drc_index;
+ char drc_name[MAX_DRC_NAME_LEN];
+ int i, retval;
+
+ (*ret_code) = -EINVAL;
+
+ if (!is_php_type((char *) drc->drc_type)) {
+ (*ret_code) = 0;
+ return 1;
+ }
+
+ for (i = 0, drc_index = drc->drc_index_start;
+ i < drc->num_sequential_elems; i++, drc_index++) {
+
+ sprintf(drc_name, "%s%d", drc->drc_name_prefix,
+ drc_index - drc->drc_index_start +
+ drc->drc_name_suffix_start);
+
+ retval = rpaphp_add_slot_common(cdata->dn,
+ drc_index, drc_name, drc->drc_type,
+ drc->drc_power_domain);
+ if (!retval) {
+ (*ret_code) = retval;
+ return 1;
+ }
+ }
+
+ (*ret_code) = retval;
+ return 0;
+}
+
+static int rpaphp_add_slot_v2(struct device_node *dn)
+{
+ struct rpaphp_add_slot_v2_struct cdata = { dn };
+
+ return drc_info_parser(dn, rpaphp_add_slot_v2_checkRun,
+ NULL, &cdata);
+}
+
+int rpaphp_add_slot(struct device_node *dn)
+{
+ if (!dn->name || strcmp(dn->name, "pci"))
+ return 0;
+
+ if (firmware_has_feature(FW_FEATURE_DRC_INFO))
+ return rpaphp_add_slot_v2(dn);
+ else
+ return rpaphp_add_slot_v1(dn);
+}
EXPORT_SYMBOL_GPL(rpaphp_add_slot);
static void __exit cleanup_slots(void)
^ permalink raw reply related
* Re: [PATCH] powerpc/eeh: Add conditional check on notify_resume
From: Andrew Donnellan @ 2018-02-15 23:21 UTC (permalink / raw)
To: Bryant G. Ly, benh, paulus, mpe; +Cc: aik, linuxppc-dev, jjalvare, seroyer
In-Reply-To: <1518720591-84657-1-git-send-email-bryantly@linux.vnet.ibm.com>
On 16/02/18 05:49, Bryant G. Ly wrote:
> From: "Juan J. Alvarez" <jjalvare@linux.vnet.ibm.com>
>
> EEH structure is not populated with function
> notify resume when running on systems that do not support
> it, i.e: BMC. Hence adding a conditional check for NULL for
Seems to me that by "BMC" you really mean "powernv platform"?
> systems that don't add function notify_resume.
>
> Signed-off-by: Juan J. Alvarez <jjalvare@linux.vnet.ibm.com>
> Reviewed-by: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
> Tested-by: Carol L. Soto <clsoto@us.ibm.com>
Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
> ---
> arch/powerpc/kernel/eeh_driver.c | 3 ++-
> 1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
> index beea218..0c0b66f 100644
> --- a/arch/powerpc/kernel/eeh_driver.c
> +++ b/arch/powerpc/kernel/eeh_driver.c
> @@ -384,7 +384,8 @@ static void *eeh_report_resume(void *data, void *userdata)
> eeh_pcid_put(dev);
> pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED);
> #ifdef CONFIG_PCI_IOV
> - eeh_ops->notify_resume(eeh_dev_to_pdn(edev));
> + if (eeh_ops->notify_resume && eeh_dev_to_pdn(edev))
> + eeh_ops->notify_resume(eeh_dev_to_pdn(edev));
> #endif
> return NULL;
> }
>
--
Andrew Donnellan OzLabs, ADL Canberra
andrew.donnellan@au1.ibm.com IBM Australia Limited
^ permalink raw reply
* [RFC 0/3] powerpc/hotplug: Fix affinity assoc for LPAR migration
From: Michael Bringmann @ 2018-02-15 23:40 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
The migration of LPARs across Power systems affects many attributes
including that of the associativity of memory blocks and CPUs. The
patches in this set execute when a system is coming up fresh upon a
migration target. They are intended to,
* Recognize changes to the associativity of memory and CPUs recorded
in internal data structures when compared to the latest copies in
the device tree (e.g. ibm,dynamic-memory, ibm,dynamic-memory-v2,
cpus),
* Recognize changes to the associativity mapping (e.g. ibm,
associativity-lookup-arrays), locate all assigned memory blocks
corresponding to each changed row, and readd all such blocks.
* Generate calls to other code layers to reset the data structures
related to associativity of the CPUs and memory.
* Re-register the 'changed' entities into the target system.
Re-registration of CPUs and memory blocks mostly entails acting as
if they have been newly hot-added into the target system.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
Michael Bringmann (3):
hotplug/mobility: Apply assoc lookup updates for Post Migration Topo
postmigration/memory: Review assoc lookup array changes
postmigration/memory: Associativity & 'ibm,dynamic-memory-v2'
---
Changes in RFC:
-- Rename pseries_update_drconf_cpu to pseries_update_cpu
-- Simplify code to update CPU nodes during mobility checks.
Remove functions to generate extra HP_ELOG messages in favor
of direct function calls to dlpar_cpu_readd_by_index, or
dlpar_memory_readd_by_index.
-- Move check for "cpu" node type from pseries_update_cpu to
pseries_smp_notifier in 'hotplug-cpu.c'
-- Remove functions 'pseries_memory_readd_by_index' and
'pseries_cpu_readd_by_index' as no longer needed outside of
'mobility.c'.
-- Update patch for recent checkin compatibility
-- Resubmit as RFC pending further integration with LMB changes
by Nathan Fontenot
^ permalink raw reply
* [RFC 1/3] hotplug/mobility: Apply assoc updates for Post Migration Topo
From: Michael Bringmann @ 2018-02-15 23:41 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
In-Reply-To: <80574cd2-9cef-9724-d6ce-9ff38a7e0677@linux.vnet.ibm.com>
hotplug/mobility: Recognize more changes to the associativity of
memory blocks described by the 'ibm,dynamic-memory' and 'cpu'
properties when processing the topology of LPARS in Post Migration
events. Previous efforts only recognized whether a memory block's
assignment had changed in the property. Changes here include:
* Checking the aa_index values of the old/new properties and 'readd'
any block for which the setting has changed.
* Checking for changes in cpu associativity and making 'readd' calls
when differences are observed.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---
Changes in RFC:
-- Simplify code to update CPU nodes during mobility checks.
Remove functions to generate extra HP_ELOG messages in favor
of direct function calls to dlpar_cpu_readd_by_index.
-- Move check for "cpu" node type from pseries_update_cpu to
pseries_smp_notifier in 'hotplug-cpu.c'
-- Remove functions 'pseries_memory_readd_by_index' and
'pseries_cpu_readd_by_index' as no longer needed outside of
'mobility.c'.
-- Update patch for recent checking compatibility
-- Resubmit as RFC pending further integration with LMB changes
by Nathan Fontenot
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 69 +++++++++++++++++++++++
arch/powerpc/platforms/pseries/hotplug-memory.c | 7 ++
2 files changed, 76 insertions(+)
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index a7d14aa7..91ef22a 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -636,6 +636,27 @@ static int dlpar_cpu_remove_by_index(u32 drc_index)
return rc;
}
+static int dlpar_cpu_readd_by_index(u32 drc_index)
+{
+ int rc = 0;
+
+ pr_info("Attempting to update CPU, drc index %x\n", drc_index);
+
+ if (dlpar_cpu_remove_by_index(drc_index))
+ rc = -EINVAL;
+ else if (dlpar_cpu_add(drc_index))
+ rc = -EINVAL;
+
+ if (rc)
+ pr_info("Failed to update cpu at drc_index %lx\n",
+ (unsigned long int)drc_index);
+ else
+ pr_info("CPU at drc_index %lx was updated\n",
+ (unsigned long int)drc_index);
+
+ return rc;
+}
+
static int find_dlpar_cpus_to_remove(u32 *cpu_drcs, int cpus_to_remove)
{
struct device_node *dn;
@@ -826,6 +847,9 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
else
rc = -EINVAL;
break;
+ case PSERIES_HP_ELOG_ACTION_READD:
+ rc = dlpar_cpu_readd_by_index(drc_index);
+ break;
default:
pr_err("Invalid action (%d) specified\n", hp_elog->action);
rc = -EINVAL;
@@ -876,12 +900,53 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+static int pseries_update_cpu(struct of_reconfig_data *pr)
+{
+ u32 old_entries, new_entries;
+ __be32 *p, *old_assoc, *new_assoc;
+ int rc = 0;
+
+ /* So far, we only handle the 'ibm,associativity' property,
+ * here.
+ * The first int of the property is the number of domains
+ * described. This is followed by an array of level values.
+ */
+ p = (__be32 *) pr->old_prop->value;
+ if (!p)
+ return -EINVAL;
+ old_entries = be32_to_cpu(*p++);
+ old_assoc = p;
+
+ p = (__be32 *)pr->prop->value;
+ if (!p)
+ return -EINVAL;
+ new_entries = be32_to_cpu(*p++);
+ new_assoc = p;
+
+ if (old_entries == new_entries) {
+ int sz = old_entries * sizeof(int);
+
+ if (!memcmp(old_assoc, new_assoc, sz))
+ rc = dlpar_cpu_readd_by_index(
+ be32_to_cpu(pr->dn->phandle));
+
+ } else {
+ rc = dlpar_cpu_readd_by_index(
+ be32_to_cpu(pr->dn->phandle));
+ }
+
+ return rc;
+}
+
static int pseries_smp_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
struct of_reconfig_data *rd = data;
int err = 0;
+ if (strcmp(rd->dn->type, "cpu"))
+ return notifier_from_errno(err);
+
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
err = pseries_add_processor(rd->dn);
@@ -889,6 +954,10 @@ static int pseries_smp_notifier(struct notifier_block *nb,
case OF_RECONFIG_DETACH_NODE:
pseries_remove_processor(rd->dn);
break;
+ case OF_RECONFIG_UPDATE_PROPERTY:
+ if (!strcmp(rd->prop->name, "ibm,associativity"))
+ err = pseries_update_cpu(rd);
+ break;
}
return notifier_from_errno(err);
}
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 1d48ab4..0e2ae20 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -1160,6 +1160,13 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
memblock_size);
rc = (rc < 0) ? -EINVAL : 0;
break;
+ } else if ((be32_to_cpu(old_drmem[i].aa_index) !=
+ be32_to_cpu(new_drmem[i].aa_index)) &&
+ (be32_to_cpu(new_drmem[i].flags) &
+ DRCONF_MEM_ASSIGNED)) {
+ rc = dlpar_memory_readd_by_index(
+ be32_to_cpu(new_drmem[i].drc_index),
+ pr->prop);
}
}
return rc;
^ permalink raw reply related
* [RFC 2/3] postmigration/memory: Review assoc lookup array changes
From: Michael Bringmann @ 2018-02-15 23:42 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
In-Reply-To: <80574cd2-9cef-9724-d6ce-9ff38a7e0677@linux.vnet.ibm.com>
postmigration/memory: In an LPAR migration scenario, the property
"ibm,associativity-lookup-arrays" may change. In the event that a
row of the array differs, locate all assigned memory blocks with that
'aa_index' and 're-add' them to the system memory block data structures.
In the process of the 're-add', the appropriate entry of the property
'ibm,dynamic-memory' would be updated as well as any other applicable
system data structures.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---
Changes in RFC:
-- Simplify code to update memory nodes during mobility checks.
Remove functions to generate extra HP_ELOG messages in favor
of direct function calls to dlpar_memory_readd_by_index.
-- Resubmit as RFC pending further integration with LMB changes
by Nathan Fontenot
---
arch/powerpc/platforms/pseries/hotplug-memory.c | 121 +++++++++++++++++++++++
1 file changed, 121 insertions(+)
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 0e2ae20..04208b0 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -1172,6 +1172,124 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
return rc;
}
+struct assoc_arrays {
+ u32 n_arrays;
+ u32 array_sz;
+ const __be32 *arrays;
+};
+
+static int pseries_update_ala_memory_aai(int aa_index,
+ struct property *dmprop)
+{
+ struct of_drconf_cell *drmem;
+ u32 entries;
+ __be32 *p;
+ int i;
+ int rc = 0;
+
+ p = (__be32 *) dmprop->value;
+ if (!p)
+ return -EINVAL;
+
+ /* The first int of the property is the number of lmb's
+ * described by the property. This is followed by an array
+ * of of_drconf_cell entries. Get the number of entries
+ * and skip to the array of of_drconf_cell's.
+ */
+ entries = be32_to_cpu(*p++);
+ drmem = (struct of_drconf_cell *)p;
+
+ for (i = 0; i < entries; i++) {
+ if ((be32_to_cpu(drmem[i].aa_index) != aa_index) &&
+ (be32_to_cpu(drmem[i].flags) & DRCONF_MEM_ASSIGNED)) {
+ rc = dlpar_memory_readd_by_index(
+ be32_to_cpu(drmem[i].drc_index),
+ dmprop);
+ }
+ }
+
+ return rc;
+}
+
+static int pseries_update_ala_memory(struct of_reconfig_data *pr)
+{
+ struct assoc_arrays new_ala, old_ala;
+ struct device_node *dn;
+ struct property *dmprop;
+ __be32 *p;
+ int i, lim;
+
+ if (rtas_hp_event)
+ return 0;
+
+ dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (!dn)
+ return -ENODEV;
+
+ dmprop = of_find_property(dn, "ibm,dynamic-memory", NULL);
+ if (!dmprop) {
+ of_node_put(dn);
+ return -ENODEV;
+ }
+
+ /*
+ * The layout of the ibm,associativity-lookup-arrays
+ * property is a number N indicating the number of
+ * associativity arrays, followed by a number M
+ * indicating the size of each associativity array,
+ * followed by a list of N associativity arrays.
+ */
+
+ p = (__be32 *) pr->old_prop->value;
+ if (!p) {
+ of_node_put(dn);
+ return -EINVAL;
+ }
+ old_ala.n_arrays = of_read_number(p++, 1);
+ old_ala.array_sz = of_read_number(p++, 1);
+ old_ala.arrays = p;
+
+ p = (__be32 *) pr->prop->value;
+ if (!p) {
+ of_node_put(dn);
+ return -EINVAL;
+ }
+ new_ala.n_arrays = of_read_number(p++, 1);
+ new_ala.array_sz = of_read_number(p++, 1);
+ new_ala.arrays = p;
+
+ lim = (new_ala.n_arrays > old_ala.n_arrays) ? old_ala.n_arrays :
+ new_ala.n_arrays;
+
+ if (old_ala.array_sz == new_ala.array_sz) {
+
+ for (i = 0; i < lim; i++) {
+ int index = (i * new_ala.array_sz);
+
+ if (!memcmp(&old_ala.arrays[index],
+ &new_ala.arrays[index],
+ new_ala.array_sz))
+ continue;
+
+ pseries_update_ala_memory_aai(i, dmprop);
+ }
+
+ for (i = lim; i < new_ala.n_arrays; i++)
+ pseries_update_ala_memory_aai(i, dmprop);
+
+ } else {
+ /* Update all entries representing these rows;
+ * as all rows have different sizes, none can
+ * have equivalent values.
+ */
+ for (i = 0; i < lim; i++)
+ pseries_update_ala_memory_aai(i, dmprop);
+ }
+
+ of_node_put(dn);
+ return 0;
+}
+
static int pseries_memory_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -1188,6 +1306,9 @@ static int pseries_memory_notifier(struct notifier_block *nb,
case OF_RECONFIG_UPDATE_PROPERTY:
if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
err = pseries_update_drconf_memory(rd);
+ if (!strcmp(rd->prop->name,
+ "ibm,associativity-lookup-arrays"))
+ err = pseries_update_ala_memory(rd);
break;
}
return notifier_from_errno(err);
^ permalink raw reply related
* [RFC 3/3] postmigration/memory: Associativity & ibm, dynamic-memory-v2
From: Michael Bringmann @ 2018-02-15 23:42 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
In-Reply-To: <80574cd2-9cef-9724-d6ce-9ff38a7e0677@linux.vnet.ibm.com>
postmigration/memory: Now apply changes to the associativity of memory
blocks described by the 'ibm,dynamic-memory-v2' property regarding
the topology of LPARS in Post Migration events.
* Extend the previous work done for the 'ibm,associativity-lookup-array'
to apply to either property 'ibm,dynamic-memory' or
'ibm,dynamic-memory-v2', whichever is present.
* Add new code to parse the 'ibm,dynamic-memory-v2' property looking
for differences in block 'assignment', associativity indexes per
block, and any other difference currently known.
When block differences are recognized, the memory block may be removed,
added, or updated depending upon the state of the new device tree
property and differences from the migrated value of the property.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/prom.h | 12 ++
arch/powerpc/platforms/pseries/hotplug-memory.c | 171 ++++++++++++++++++++++-
2 files changed, 174 insertions(+), 9 deletions(-)
diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
index 825bd59..e16ef0f 100644
--- a/arch/powerpc/include/asm/prom.h
+++ b/arch/powerpc/include/asm/prom.h
@@ -92,6 +92,18 @@ struct of_drconf_cell {
u32 flags;
};
+/* The of_drconf_cell_v2 struct defines the layout of the LMB array
+ * specified in the device tree property
+ * ibm,dynamic-reconfiguration-memory/ibm,dynamic-memory-v2
+ */
+struct of_drconf_cell_v2 {
+ u32 num_seq_lmbs;
+ u64 base_address;
+ u32 drc_index;
+ u32 aa_index;
+ u32 flags;
+} __attribute__((packed));
+
#define DRCONF_MEM_ASSIGNED 0x00000008
#define DRCONF_MEM_AI_INVALID 0x00000040
#define DRCONF_MEM_RESERVED 0x00000080
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 04208b0..96eaa9a 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -1172,14 +1172,112 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
return rc;
}
+static inline int pseries_memory_v2_find_drc(u32 drc_index,
+ u64 *base_addr, unsigned long memblock_size,
+ struct of_drconf_cell_v2 **drmem,
+ struct of_drconf_cell_v2 *last_drmem)
+{
+ struct of_drconf_cell_v2 *dm = (*drmem);
+
+ while (dm < last_drmem) {
+ if ((be32_to_cpu(dm->drc_index) <= drc_index) &&
+ (drc_index <= (be32_to_cpu(dm->drc_index)+
+ be32_to_cpu(dm->num_seq_lmbs)-1))) {
+ int offset = drc_index - be32_to_cpu(dm->drc_index);
+ (*base_addr) = be64_to_cpu(dm->base_address) +
+ (offset * memblock_size);
+ break;
+ } else if (drc_index > (be32_to_cpu(dm->drc_index)+
+ be32_to_cpu(dm->num_seq_lmbs)-1)) {
+ dm++;
+ (*drmem) = dm;
+ } else if (be32_to_cpu(dm->drc_index) > drc_index) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int pseries_update_drconf_memory_v2(struct of_reconfig_data *pr)
+{
+ struct of_drconf_cell_v2 *new_drmem, *old_drmem, *last_old_drmem;
+ unsigned long memblock_size;
+ u32 new_entries, old_entries;
+ u64 old_base_addr;
+ __be32 *p;
+ int i, rc = 0;
+
+ if (rtas_hp_event)
+ return 0;
+
+ memblock_size = pseries_memory_block_size();
+ if (!memblock_size)
+ return -EINVAL;
+
+ /* The first int of the property is the number of lmb's
+ * described by the property. This is followed by an array
+ * of of_drconf_cell_v2 entries. Get the number of entries
+ * and skip to the array of of_drconf_cell_v2's.
+ */
+ p = (__be32 *) pr->old_prop->value;
+ if (!p)
+ return -EINVAL;
+ old_entries = be32_to_cpu(*p++);
+ old_drmem = (struct of_drconf_cell_v2 *)p;
+ last_old_drmem = old_drmem +
+ (sizeof(struct of_drconf_cell_v2) * old_entries);
+
+ p = (__be32 *)pr->prop->value;
+ new_entries = be32_to_cpu(*p++);
+ new_drmem = (struct of_drconf_cell_v2 *)p;
+
+ for (i = 0; i < new_entries; i++) {
+ int j;
+ u32 new_drc_index = be32_to_cpu(new_drmem->drc_index);
+
+ for (j = 0; j < new_drmem->num_seq_lmbs; j++) {
+ if (!pseries_memory_v2_find_drc(new_drc_index+j,
+ &old_base_addr,
+ memblock_size,
+ &old_drmem,
+ last_old_drmem)) {
+ if ((be32_to_cpu(old_drmem->flags) &
+ DRCONF_MEM_ASSIGNED) &&
+ (!(be32_to_cpu(new_drmem->flags) &
+ DRCONF_MEM_ASSIGNED))) {
+ rc = pseries_remove_memblock(
+ old_base_addr,
+ memblock_size);
+ } else if ((!(be32_to_cpu(old_drmem->flags) &
+ DRCONF_MEM_ASSIGNED)) &&
+ (be32_to_cpu(new_drmem->flags) &
+ DRCONF_MEM_ASSIGNED)) {
+ rc = memblock_add(
+ old_base_addr, memblock_size);
+ } else if ((be32_to_cpu(old_drmem->aa_index) !=
+ be32_to_cpu(new_drmem->aa_index)) &&
+ (be32_to_cpu(new_drmem->flags) &
+ DRCONF_MEM_ASSIGNED)) {
+ dlpar_memory_readd_by_index(
+ new_drc_index+j,
+ pr->prop);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
struct assoc_arrays {
u32 n_arrays;
u32 array_sz;
const __be32 *arrays;
};
-static int pseries_update_ala_memory_aai(int aa_index,
- struct property *dmprop)
+static int pseries_update_ala_memory_aai_v1(int aa_index,
+ struct property *dmprop)
{
struct of_drconf_cell *drmem;
u32 entries;
@@ -1211,11 +1309,48 @@ static int pseries_update_ala_memory_aai(int aa_index,
return rc;
}
+static int pseries_update_ala_memory_aai_v2(int aa_index,
+ struct property *dmprop)
+{
+ struct of_drconf_cell_v2 *drmem;
+ u32 entries;
+ __be32 *p;
+ int i;
+
+ p = (__be32 *) dmprop->value;
+ if (!p)
+ return -EINVAL;
+
+ /* The first int of the property is the number of lmb's
+ * described by the property. This is followed by an array
+ * of of_drconf_cell_v2 entries. Get the number of entries
+ * and skip to the array of of_drconf_cell_v2's.
+ */
+ entries = be32_to_cpu(*p++);
+ drmem = (struct of_drconf_cell_v2 *)p;
+
+ for (i = 0; i < entries; i++) {
+ if ((be32_to_cpu(drmem[i].aa_index) != aa_index) &&
+ (be32_to_cpu(drmem[i].flags) & DRCONF_MEM_ASSIGNED)) {
+ int j;
+ int lim = be32_to_cpu(drmem->num_seq_lmbs);
+ u32 drc_index = be32_to_cpu(drmem->drc_index);
+
+ for (j = 0; j < lim; j++)
+ dlpar_memory_readd_by_index(drc_index+j,
+ dmprop);
+ }
+ }
+
+ return 0;
+}
+
static int pseries_update_ala_memory(struct of_reconfig_data *pr)
{
struct assoc_arrays new_ala, old_ala;
struct device_node *dn;
struct property *dmprop;
+ bool v1 = true;
__be32 *p;
int i, lim;
@@ -1228,8 +1363,13 @@ static int pseries_update_ala_memory(struct of_reconfig_data *pr)
dmprop = of_find_property(dn, "ibm,dynamic-memory", NULL);
if (!dmprop) {
- of_node_put(dn);
- return -ENODEV;
+ v1 = false;
+ dmprop = of_find_property(dn, "ibm,dynamic-memory-v2",
+ NULL);
+ if (!dmprop) {
+ of_node_put(dn);
+ return -ENODEV;
+ }
}
/*
@@ -1271,19 +1411,30 @@ static int pseries_update_ala_memory(struct of_reconfig_data *pr)
new_ala.array_sz))
continue;
- pseries_update_ala_memory_aai(i, dmprop);
+ if (v1)
+ pseries_update_ala_memory_aai_v1(i, dmprop);
+ else
+ pseries_update_ala_memory_aai_v2(i, dmprop);
}
- for (i = lim; i < new_ala.n_arrays; i++)
- pseries_update_ala_memory_aai(i, dmprop);
+ for (i = lim; i < new_ala.n_arrays; i++) {
+ if (v1)
+ pseries_update_ala_memory_aai_v1(i, dmprop);
+ else
+ pseries_update_ala_memory_aai_v2(i, dmprop);
+ }
} else {
/* Update all entries representing these rows;
* as all rows have different sizes, none can
* have equivalent values.
*/
- for (i = 0; i < lim; i++)
- pseries_update_ala_memory_aai(i, dmprop);
+ for (i = 0; i < lim; i++) {
+ if (v1)
+ pseries_update_ala_memory_aai_v1(i, dmprop);
+ else
+ pseries_update_ala_memory_aai_v2(i, dmprop);
+ }
}
of_node_put(dn);
@@ -1306,6 +1457,8 @@ static int pseries_memory_notifier(struct notifier_block *nb,
case OF_RECONFIG_UPDATE_PROPERTY:
if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
err = pseries_update_drconf_memory(rd);
+ if (!strcmp(rd->prop->name, "ibm,dynamic-memory-v2"))
+ err = pseries_update_drconf_memory_v2(rd);
if (!strcmp(rd->prop->name,
"ibm,associativity-lookup-arrays"))
err = pseries_update_ala_memory(rd);
To: linuxppc-dev@lists.ozlabs.org
^ permalink raw reply related
* [RFC] powerpc/kernel: Add 'ibm,thread-groups' property for CPU allocation
From: Michael Bringmann @ 2018-02-15 23:48 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
Add code to parse the new property 'ibm,thread-groups" when it is
present. The content of this property explicitly defines the number
of threads per core as well as the PowerPC 'threads_core_mask'.
The design provides a common device-tree for both P9 normal core and
P9 fused core systems. The new property has been observed to be
available on P9 pHyp systems, but it may not be present on OpenPower
BMC systems.
The property updates the kernel to know which CPUs/threads of each
core are actually present, and then use the map when adding cores
to the system at boot, or during hotplug operations.
* Previously, the information about the number of threads per core
was inferred solely from the "ibm,ppc-interrupt-server#s" property
in the system device tree.
* Also previous to this property, The mask of threads per CPU was
inferred to be a strict linear series from 0..(nthreads-1).
* There may be a different thread group mask for each core in the
system.
* Also after reading the property, we can determine which of the
possible threads we are allowed to online for each CPU. It is no
longer a simple linear sequence, but may be discontinuous e.g.
activate threads 1,2,3,5,6,7 on a core instead of 0-5 sequentially.
In the event of LPAR migration, we also provide a hook to re-process
the property in the event that it is changed. Rules about fused-core
and split-core migration are outside the scope of this change, however.
We update the 'ppc_thread_group_mask' for subsequent use by DLPAR
operations. It is the responsibility of the user to put the source
system into SMT4 mode when moving from a fused-core to split-core
target.
Implementation of the "ibm,thread-groups" property is spread across
a few files in the powerpc specific code:
* prom.c: Parse the property and create 'ppc_thread_group_mask'.
Use the mask in operation of early_init_dt_scan_cpus().
* setup-common.c: Parse the property, create 'ppc_thread_group_mask',
and use the value in cpu_init_thread_core_maps(), and
smp_setup_cpu_maps.
* hotplug-cpu.c: Use 'ppc_thread_group_mask' in several locations
where the code previously expected to iterate over a
linear series of active threads (0..nthreads-1).
* mobility.c: Look for and process changes to the thread group mask
in the context of post migration topology changes
Note that the "ibm,thread-groups" property also includes semantics
of 'thread-group' i.e. define one or more subgroups of the available
threads, each group of threads to be used for a specific class of
task. Translating thread group semantics into Linux kernel features
is TBD.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/cputhreads.h | 6 +
arch/powerpc/kernel/setup-common.c | 136 ++++++++++++++++++++++++--
arch/powerpc/platforms/pseries/hotplug-cpu.c | 14 ++-
arch/powerpc/platforms/pseries/mobility.c | 6 +
4 files changed, 150 insertions(+), 12 deletions(-)
diff --git a/arch/powerpc/include/asm/cputhreads.h b/arch/powerpc/include/asm/cputhreads.h
index d71a909..df6ade9 100644
--- a/arch/powerpc/include/asm/cputhreads.h
+++ b/arch/powerpc/include/asm/cputhreads.h
@@ -31,6 +31,12 @@
#define threads_core_mask (*get_cpu_mask(0))
#endif
+extern cpumask_t ppc_thread_group_mask;
+
+extern int process_thread_group_mask(struct device_node *dn,
+ const __be32 *prop, int prop_len);
+
+
/* cpu_thread_mask_to_cores - Return a cpumask of one per cores
* hit by the argument
*
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 8fd3a70..1102d12 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -416,13 +416,18 @@ void __init check_for_initrd(void)
EXPORT_SYMBOL_GPL(threads_shift);
EXPORT_SYMBOL_GPL(threads_core_mask);
-static void __init cpu_init_thread_core_maps(int tpc)
+cpumask_t ppc_thread_group_mask;
+EXPORT_SYMBOL_GPL(ppc_thread_group_mask);
+
+static void __init cpu_init_thread_core_maps(int tpc,
+ cpumask_t *thread_group_mask)
{
int i;
threads_per_core = tpc;
threads_per_subcore = tpc;
cpumask_clear(&threads_core_mask);
+ DBG("INFO: Entry %s (%d)\n", __FUNCTION__, tpc);
/* This implementation only supports power of 2 number of threads
* for simplicity and performance
@@ -432,12 +437,112 @@ static void __init cpu_init_thread_core_maps(int tpc)
for (i = 0; i < tpc; i++)
cpumask_set_cpu(i, &threads_core_mask);
+ cpumask_and(&threads_core_mask, &threads_core_mask, thread_group_mask);
printk(KERN_INFO "CPU maps initialized for %d thread%s per core\n",
tpc, tpc > 1 ? "s" : "");
printk(KERN_DEBUG " (thread shift is %d)\n", threads_shift);
}
+int process_thread_group_mask(struct device_node *dn,
+ const __be32 *prop, int prop_len)
+{
+ const __be32 *thrgrp;
+ const __be32 *intserv;
+ int lentg, len, cpu, nthreads = 1;
+ int j, k, rc = 0;
+ u32 cc_type = 0, no_split = 0, thr_per_split = 0;
+ DBG("INFO: Entry %s\n", __FUNCTION__);
+
+ /* First CPU/thread */
+ intserv = of_get_property(dn, "reg", &len);
+ if (intserv)
+ cpu = of_read_number(intserv, 1);
+ else
+ cpu = 0;
+
+ /* Num of threads in core */
+ intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s",
+ &len);
+ if (intserv) {
+ DBG(" ibm,ppc-interrupt-server#s -> %d threads\n",
+ nthreads);
+ } else {
+ DBG(" no ibm,ppc-interrupt-server#s -> 1 thread\n");
+ len = 4;
+ }
+
+ nthreads = len / sizeof(int);
+ DBG(" cpu %d nthreads %d\n", cpu, nthreads);
+
+ if (prop) {
+ thrgrp = prop;
+ } else {
+ thrgrp = of_get_property(dn, "ibm,thread-groups",
+ &lentg);
+ if (!thrgrp) {
+ rc = -ENOENT;
+ DBG(" error, %d\n", __LINE__);
+ goto endit;
+ }
+ }
+
+ /* Process the thread groups for the Core thread mask */
+ /* Characteristic type per table */
+ cc_type = of_read_number(thrgrp++, 1);
+
+ /*
+ * 1 : Group shares common L1, translation cache, and
+ * instruction data flow
+ * >1 : Reserved
+ */
+ if (cc_type != 1) {
+ rc = -EINVAL;
+ DBG(" error, %d\n", __LINE__);
+ goto endit;
+ }
+
+ /* No. splits */
+ no_split = of_read_number(thrgrp++, 1);
+ if (no_split == 0) {
+ rc = -EINVAL;
+ DBG(" error, %d\n", __LINE__);
+ goto endit;
+ }
+
+ /* Threads per split */
+ thr_per_split = of_read_number(thrgrp++, 1);
+ if (thr_per_split == 0) {
+ rc = -EINVAL;
+ DBG(" error, %d\n", __LINE__);
+ goto endit;
+ }
+
+ DBG(" Property ibm,thread-group "
+ "(cc_t=%d, no_spl=%d, thr_p_spl=%d)\n",
+ (int)cc_type, (int)no_split, (int)thr_per_split);
+
+ for (j = 0; j < no_split; j++) {
+ for (k = 0; k < thr_per_split; k++) {
+ u32 t = of_read_number(thrgrp++, 1);
+
+ cpumask_set_cpu(t, &ppc_thread_group_mask);
+ DBG(" !!enable thread %d\n", (int)t);
+ }
+ }
+
+endit:
+ if (rc) {
+ DBG(" WARNING: error processing (%d)"
+ "ibm,thread-group property\n", rc);
+ for (j = 0; j < nthreads; j++)
+ cpumask_set_cpu(cpu+j,
+ &ppc_thread_group_mask);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL(process_thread_group_mask);
/**
* setup_cpu_maps - initialize the following cpu maps:
@@ -489,20 +594,35 @@ void __init smp_setup_cpu_maps(void)
nthreads = len / sizeof(int);
+ process_thread_group_mask(dn, NULL, 0);
+
for (j = 0; j < nthreads && cpu < nr_cpu_ids; j++) {
bool avail;
- DBG(" thread %d -> cpu %d (hard id %d)\n",
- j, cpu, be32_to_cpu(intserv[j]));
-
avail = of_device_is_available(dn);
if (!avail)
avail = !of_property_match_string(dn,
"enable-method", "spin-table");
- set_cpu_present(cpu, avail);
- set_hard_smp_processor_id(cpu, be32_to_cpu(intserv[j]));
- set_cpu_possible(cpu, true);
+ DBG(" thread %d -> cpu %d (hard id %d) %d\n",
+ j, cpu, be32_to_cpu(intserv[j]),
+ cpumask_test_cpu(cpu, &ppc_thread_group_mask));
+
+ if (cpumask_test_cpu(cpu,
+ &ppc_thread_group_mask)) {
+ DBG(" !!thread %d present"
+ "/possible\n", (int)cpu);
+ set_cpu_present(cpu, avail);
+ set_hard_smp_processor_id(cpu,
+ be32_to_cpu(intserv[j]));
+ set_cpu_possible(cpu, true);
+ } else {
+ DBG(" !!NOT thread %d "
+ "present/possible\n", (int)cpu);
+ set_cpu_present(cpu, false);
+ set_cpu_possible(cpu, false);
+ }
+
cpu++;
}
}
@@ -561,7 +681,7 @@ void __init smp_setup_cpu_maps(void)
* every CPU in the system. If that is not the case, then some code
* here will have to be reworked
*/
- cpu_init_thread_core_maps(nthreads);
+ cpu_init_thread_core_maps(nthreads, &ppc_thread_group_mask);
/* Now that possible cpus are set, set nr_cpu_ids for later use */
setup_nr_cpu_ids();
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index a7d14aa7..106d0fe 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -36,6 +36,7 @@
#include <asm/xics.h>
#include <asm/xive.h>
#include <asm/plpar_wrappers.h>
+#include <asm/cputhreads.h>
#include "pseries.h"
#include "offline_states.h"
@@ -254,6 +255,8 @@ static int pseries_add_processor(struct device_node *np)
if (!intserv)
return 0;
+ process_thread_group_mask(np, NULL, 0);
+
zalloc_cpumask_var(&candidate_mask, GFP_KERNEL);
zalloc_cpumask_var(&tmp, GFP_KERNEL);
@@ -325,6 +328,7 @@ static void pseries_remove_processor(struct device_node *np)
cpu_maps_update_begin();
for (i = 0; i < nthreads; i++) {
thread = be32_to_cpu(intserv[i]);
+ cpumask_clear_cpu(thread, &ppc_thread_group_mask);
for_each_present_cpu(cpu) {
if (get_hard_smp_processor_id(cpu) != thread)
continue;
@@ -363,10 +367,12 @@ static int dlpar_online_cpu(struct device_node *dn)
BUG_ON(get_cpu_current_state(cpu)
!= CPU_STATE_OFFLINE);
cpu_maps_update_done();
- timed_topology_update(1);
- rc = device_online(get_cpu_device(cpu));
- if (rc)
- goto out;
+ if (cpumask_test_cpu(thread, &ppc_thread_group_mask)) {
+ timed_topology_update(1);
+ rc = device_online(get_cpu_device(cpu));
+ if (rc)
+ goto out;
+ }
cpu_maps_update_begin();
break;
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c
index f7042ad..0816ccf 100644
--- a/arch/powerpc/platforms/pseries/mobility.c
+++ b/arch/powerpc/platforms/pseries/mobility.c
@@ -20,6 +20,7 @@
#include <asm/machdep.h>
#include <asm/rtas.h>
+#include <asm/cputhreads.h>
#include "pseries.h"
static struct kobject *mobility_kobj;
@@ -121,6 +122,11 @@ static int update_dt_property(struct device_node *dn, struct property **prop,
}
if (!more) {
+ printk(KERN_INFO "INFO: Processing %s %s\n", __FUNCTION__, name);
+ if (strcmp(name, "ibm,thread-groups") == 0)
+ process_thread_group_mask(dn,
+ new_prop->value, new_prop->length);
+
of_update_property(dn, new_prop);
*prop = NULL;
}
^ permalink raw reply related
* [RFC 3/4] powerpc/hotplug/drcinfo: Fix hot-add CPU issues
From: Michael Bringmann @ 2018-02-15 23:52 UTC (permalink / raw)
To: linuxppc-dev
Cc: Michael Bringmann, Nathan Fontenot, John Allen, Tyrel Datwyler,
Thomas Falcon
In-Reply-To: <531f98fb-a29b-53e2-e7d5-870a531b76fd@linux.vnet.ibm.com>
This patch applies a common parse function for the ibm,drc-info
property that can be modified by a callback function to the
hot-add CPU code. Candidate code is replaced by a call to the
parser including a pointer to a local context-specific functions,
and local data.
In addition, a bug in the release of the previous patch set may
break things in some of the CPU DLPAR operations. For instance,
when attempting to hot-add a new CPU or set of CPUs, the original
patch failed to always properly calculate the available resources,
and aborted the operation.
Signed-off-by: Michael Bringmann <mwb@linux.vnet.ibm.com>
Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmwar
e feature" -- end of patch series applied to powerpc next)
---
arch/powerpc/platforms/pseries/hotplug-cpu.c | 129 +++++++++++++++++------
arch/powerpc/platforms/pseries/pseries_energy.c | 112 ++++++++++----------
2 files changed, 154 insertions(+), 87 deletions(-)
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index a7d14aa7..9346b04 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -408,25 +408,67 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
return found;
}
-static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
+static bool check_cpu_drc_index(struct device_node *parent,
+ int (*checkRun)(struct of_drc_info *drc,
+ void *data,
+ void *not_used,
+ int *ret_code),
+ void *cdata)
{
- bool found = false;
- int rc, index;
+ int found = 0;
+
+ if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
+ found = drc_info_parser(parent, checkRun, "CPU", cdata);
+ } else {
+ int rc, index = 0;
- index = 0;
- while (!found) {
- u32 drc;
+ while (!found) {
+ u32 drc;
- rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
+ rc = of_property_read_u32_index(parent,
+ "ibm,drc-indexes",
index++, &drc);
- if (rc)
- break;
+ if (rc)
+ break;
+ found = checkRun(NULL, cdata, &drc, NULL);
+ }
+ }
- if (drc == drc_index)
- found = true;
+ return (bool)found;
+}
+
+struct valid_cpu_drc_index_struct {
+ u32 targ_drc_index;
+};
+
+static int valid_cpu_drc_index_checkRun(struct of_drc_info *drc,
+ void *idata,
+ void *drc_index,
+ int *ret_code)
+{
+ struct valid_cpu_drc_index_struct *cdata = idata;
+
+ if (drc) {
+ if ((drc->drc_index_start <= cdata->targ_drc_index) &&
+ (cdata->targ_drc_index <= drc->last_drc_index)) {
+ (*ret_code) = 1;
+ return 1;
+ }
+ } else {
+ if (*((u32*)drc_index) == cdata->targ_drc_index) {
+ (*ret_code) = 1;
+ return 1;
+ }
}
+ return 0;
+}
- return found;
+static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
+{
+ struct valid_cpu_drc_index_struct cdata = { drc_index };
+
+ return check_cpu_drc_index(parent, valid_cpu_drc_index_checkRun,
+ &cdata);
}
static ssize_t dlpar_cpu_add(u32 drc_index)
@@ -718,11 +760,45 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
return rc;
}
+struct find_dlpar_cpus_to_add_struct {
+ struct device_node *parent;
+ u32 *cpu_drcs;
+ u32 cpus_to_add;
+ u32 cpus_found;
+};
+
+static int find_dlpar_cpus_to_add_checkRun(struct of_drc_info *drc,
+ void *idata,
+ void *drc_index,
+ int *ret_code)
+{
+ struct find_dlpar_cpus_to_add_struct *cdata = idata;
+
+ if (drc) {
+ int k;
+
+ for (k = 0; (k < drc->num_sequential_elems) &&
+ (cdata->cpus_found < cdata->cpus_to_add); k++) {
+ u32 idrc = drc->drc_index_start +
+ (k * drc->sequential_inc);
+
+ if (dlpar_cpu_exists(cdata->parent, idrc))
+ continue;
+ cdata->cpu_drcs[cdata->cpus_found++] = idrc;
+ }
+ } else {
+ if (!dlpar_cpu_exists(cdata->parent, *((u32*)drc_index)))
+ cdata->cpu_drcs[cdata->cpus_found++] =
+ *((u32*)drc_index);
+ }
+ return 0;
+}
+
static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
{
struct device_node *parent;
- int cpus_found = 0;
- int index, rc;
+ struct find_dlpar_cpus_to_add_struct cdata = {
+ NULL, cpu_drcs, cpus_to_add, 0 };
parent = of_find_node_by_path("/cpus");
if (!parent) {
@@ -731,28 +807,15 @@ static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
return -1;
}
- /* Search the ibm,drc-indexes array for possible CPU drcs to
- * add. Note that the format of the ibm,drc-indexes array is
- * the number of entries in the array followed by the array
- * of drc values so we start looking at index = 1.
+ /* Search the appropriate property for possible CPU drcs to
+ * add.
*/
- index = 1;
- while (cpus_found < cpus_to_add) {
- u32 drc;
-
- rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
- index++, &drc);
- if (rc)
- break;
-
- if (dlpar_cpu_exists(parent, drc))
- continue;
-
- cpu_drcs[cpus_found++] = drc;
- }
+ cdata.parent = parent;
+ check_cpu_drc_index(parent, find_dlpar_cpus_to_add_checkRun,
+ &cdata);
of_node_put(parent);
- return cpus_found;
+ return cdata.cpus_found;
}
static int dlpar_cpu_add_by_count(u32 cpus_to_add)
diff --git a/arch/powerpc/platforms/pseries/pseries_energy.c b/arch/powerpc/platforms/pseries/pseries_energy.c
index c7d84aa..332f3ce 100644
--- a/arch/powerpc/platforms/pseries/pseries_energy.c
+++ b/arch/powerpc/platforms/pseries/pseries_energy.c
@@ -36,6 +36,26 @@
/* Helper Routines to convert between drc_index to cpu numbers */
+struct cpu_to_drc_index_struct {
+ u32 thread_index;
+ u32 ret;
+};
+
+static int cpu_to_drc_index_checkRun(struct of_drc_info *drc,
+ void *idata, void *not_used, int *ret_code)
+{
+ struct cpu_to_drc_index_struct *cdata = idata;
+
+ if (cdata->thread_index < drc->last_drc_index) {
+ cdata->ret = drc->drc_index_start +
+ (cdata->thread_index * drc->sequential_inc);
+ (*ret_code) = 1;
+ return 1;
+ }
+ (*ret_code) = 0;
+ return 0;
+}
+
static u32 cpu_to_drc_index(int cpu)
{
struct device_node *dn = NULL;
@@ -51,32 +71,16 @@ static u32 cpu_to_drc_index(int cpu)
thread_index = cpu_core_index_of_thread(cpu);
if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
- struct property *info = NULL;
- struct of_drc_info drc;
- int j;
- u32 num_set_entries;
- const __be32 *value;
-
- info = of_find_property(dn, "ibm,drc-info", NULL);
- if (info == NULL)
- goto err_of_node_put;
+ struct cpu_to_drc_index_struct cdata = {
+ thread_index, 0 };
- value = of_prop_next_u32(info, NULL, &num_set_entries);
- if (!value)
- goto err_of_node_put;
- value++;
-
- for (j = 0; j < num_set_entries; j++) {
+ rc = drc_info_parser(dn, &cpu_to_drc_index_checkRun,
+ "CPU", &cdata);
- of_read_drc_info_cell(&info, &value, &drc);
- if (strncmp(drc.drc_type, "CPU", 3))
- goto err;
-
- if (thread_index < drc.last_drc_index)
- break;
- }
+ if (rc < 0)
+ goto err_of_node_put;
- ret = drc.drc_index_start + (thread_index * drc.sequential_inc);
+ ret = cdata.ret;
} else {
const __be32 *indexes;
@@ -102,11 +106,36 @@ static u32 cpu_to_drc_index(int cpu)
return ret;
}
+struct drc_index_to_cpu_struct {
+ u32 drc_index;
+ u32 thread_index;
+ u32 cpu;
+};
+
+static int drc_index_to_cpu_checkRun(struct of_drc_info *drc,
+ void *idata, void *not_used, int *ret_code)
+{
+ struct drc_index_to_cpu_struct *cdata = idata;
+
+ if (cdata->drc_index > drc->last_drc_index) {
+ cdata->cpu += drc->num_sequential_elems;
+ (*ret_code) = 0;
+ return 0;
+ } else {
+ cdata->cpu += ((cdata->drc_index - drc->drc_index_start) /
+ drc->sequential_inc);
+
+ cdata->thread_index = cpu_first_thread_of_core(cdata->cpu);
+ (*ret_code) = 0;
+ return 0;
+ }
+}
+
static int drc_index_to_cpu(u32 drc_index)
{
struct device_node *dn = NULL;
const int *indexes;
- int thread_index = 0, cpu = 0;
+ int thread_index = 0;
int rc = 1;
dn = of_find_node_by_path("/cpus");
@@ -114,38 +143,13 @@ static int drc_index_to_cpu(u32 drc_index)
goto err;
if (firmware_has_feature(FW_FEATURE_DRC_INFO)) {
- struct property *info = NULL;
- struct of_drc_info drc;
- int j;
- u32 num_set_entries;
- const __be32 *value;
-
- info = of_find_property(dn, "ibm,drc-info", NULL);
- if (info == NULL)
- goto err_of_node_put;
-
- value = of_prop_next_u32(info, NULL, &num_set_entries);
- if (!value)
- goto err_of_node_put;
- value++;
-
- for (j = 0; j < num_set_entries; j++) {
+ struct drc_index_to_cpu_struct cdata = {
+ drc_index, 0, 0 };
- of_read_drc_info_cell(&info, &value, &drc);
- if (strncmp(drc.drc_type, "CPU", 3))
- goto err;
+ rc = drc_info_parser(dn, &drc_index_to_cpu_checkRun,
+ "CPU", &cdata);
+ thread_index = cdata.thread_index;
- if (drc_index > drc.last_drc_index) {
- cpu += drc.num_sequential_elems;
- continue;
- }
- cpu += ((drc_index - drc.drc_index_start) /
- drc.sequential_inc);
-
- thread_index = cpu_first_thread_of_core(cpu);
- rc = 0;
- break;
- }
} else {
unsigned long int i;
^ permalink raw reply related
* Re: [PATCH v2] cxl: Check if PSL data-cache is available before issue flush request
From: Andrew Donnellan @ 2018-02-16 2:08 UTC (permalink / raw)
To: Vaibhav Jain, linuxppc-dev, Frederic Barrat
Cc: Christophe Lombard, Philippe Bergheaud, Alastair D'Silva
In-Reply-To: <20180215154924.22005-1-vaibhav@linux.vnet.ibm.com>
On 16/02/18 02:49, Vaibhav Jain wrote:
> PSL9D doesn't have a data-cache that needs to be flushed before
> resetting the card. However when cxl tries to flush data-cache on such
> a card, it times-out as PSL_Control register never indicates flush
> operation complete due to missing data-cache. This is usually
> indicated in the kernel logs with this message:
>
> "WARNING: cache flush timed out"
>
> To fix this the patch checks PSL_Debug register CDC-Field(BIT:27)
> which indicates the absence of a data-cache and sets a flag
> 'no_data_cache' in 'struct cxl_native' to indicate this. When
> cxl_data_cache_flush() is called it checks the flag and if set bails
> out early without requesting a data-cache flush operation to the PSL.
>
> Signed-off-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com>
LGTM
Acked-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
--
Andrew Donnellan OzLabs, ADL Canberra
andrew.donnellan@au1.ibm.com IBM Australia Limited
^ permalink raw reply
* Re: [PATCH] powerpc/npu-dma.c: Fix deadlock in mmio_invalidate
From: Mark Hairgrove @ 2018-02-16 3:11 UTC (permalink / raw)
To: Alistair Popple; +Cc: Balbir Singh, mpe, linuxppc-dev, Javier Cabezas
In-Reply-To: <3544963.SI8Y64vzmd@new-mexico>
On Wed, 14 Feb 2018, Alistair Popple wrote:
> > > +struct mmio_atsd_reg {
> > > + struct npu *npu;
> > > + int reg;
> > > +};
> > > +
> >
> > Is it just easier to move reg to inside of struct npu?
>
> I don't think so, struct npu is global to all npu contexts where as this is
> specific to the given invalidation. We don't have enough registers to assign
> each NPU context it's own dedicated register so I'm not sure it makes sense to
> put it there either.
>
> > > +static void acquire_atsd_reg(struct npu_context *npu_context,
> > > + struct mmio_atsd_reg mmio_atsd_reg[NV_MAX_NPUS])
> > > +{
> > > + int i, j;
> > > + struct npu *npu;
> > > + struct pci_dev *npdev;
> > > + struct pnv_phb *nphb;
> > >
> > > - /*
> > > - * The GPU requires two flush ATSDs to ensure all entries have
> > > - * been flushed. We use PID 0 as it will never be used for a
> > > - * process on the GPU.
> > > - */
> > > - if (flush)
> > > - mmio_invalidate_pid(npu, 0, true);
> > > + for (i = 0; i <= max_npu2_index; i++) {
> > > + mmio_atsd_reg[i].reg = -1;
> > > + for (j = 0; j < NV_MAX_LINKS; j++) {
> >
> > Is it safe to assume that npu_context->npdev will not change in this
> > loop? I guess it would need to be stronger than just this loop.
>
> It is not safe to assume that npu_context->npdev won't change during this loop,
> however I don't think it is a problem if it does as we only read each element
> once during the invalidation.
Shouldn't that be enforced with READ_ONCE() then?
I assume that npdev->bus can't change until after the last
pnv_npu2_destroy_context() is called for an npu. In that case, the
mmu_notifier_unregister() in pnv_npu2_release_context() will block until
mmio_invalidate() is done using npdev. That seems safe enough, but a
comment somewhere about that would be useful.
>
> There are two possibilities for how this could change. pnv_npu2_init_context()
> will add a nvlink to the npdev which will result in the TLB invalidation being
> sent to that GPU as well which should not be a problem.
>
> pnv_npu2_destroy_context() will remove the the nvlink from npdev. If it happens
> prior to this loop it should not be a problem (as the destruction will have
> already invalidated the GPU TLB). If it happens after this loop it shouldn't be
> a problem either (it will just result in an extra TLB invalidate being sent to
> this GPU).
>
> > > + npdev = npu_context->npdev[i][j];
> > > + if (!npdev)
> > > + continue;
> > > +
> > > + nphb = pci_bus_to_host(npdev->bus)->private_data;
> > > + npu = &nphb->npu;
> > > + mmio_atsd_reg[i].npu = npu;
> > > + mmio_atsd_reg[i].reg = get_mmio_atsd_reg(npu);
> > > + while (mmio_atsd_reg[i].reg < 0) {
> > > + mmio_atsd_reg[i].reg = get_mmio_atsd_reg(npu);
> > > + cpu_relax();
> >
> > A cond_resched() as well if we have too many tries?
>
> I don't think we can as the invalidate_range() function is called under the ptl
> spin-lock and is not allowed to sleep (at least according to
> include/linux/mmu_notifier.h).
>
> - Alistair
>
> > Balbir
> >
>
>
>
^ permalink raw reply
* [PATCH v2 (skiboot)] dt: add /cpus/ibm, powerpc-cpu-features device tree bindings
From: Nicholas Piggin @ 2018-02-16 3:40 UTC (permalink / raw)
To: skiboot; +Cc: Nicholas Piggin, linuxppc-dev, Segher Boessenkool
This is a new CPU feature advertising interface that is fine-grained,
extensible, aware of privilege levels, and gives control of features
to all levels of the stack (firmware, hypervisor, and OS).
The design and binding specification is described in detail in doc/.
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
---
Since v1:
- Fold branch-v3 into fixed-point-v3, as pointed out by Segher they
are all fixed point facilities.
- Fixed typo (Segher)
core/Makefile.inc | 2 +-
core/cpufeatures.c | 921 +++++++++++++++++++++
core/device.c | 7 +
core/init.c | 1 +
.../ibm,powerpc-cpu-features/binding.txt | 245 ++++++
.../ibm,powerpc-cpu-features/design.txt | 157 ++++
include/device.h | 1 +
include/skiboot.h | 5 +
8 files changed, 1338 insertions(+), 1 deletion(-)
create mode 100644 core/cpufeatures.c
create mode 100644 doc/device-tree/ibm,powerpc-cpu-features/binding.txt
create mode 100644 doc/device-tree/ibm,powerpc-cpu-features/design.txt
diff --git a/core/Makefile.inc b/core/Makefile.inc
index d6a7269f..5c120564 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -9,7 +9,7 @@ CORE_OBJS += vpd.o hostservices.o platform.o nvram.o nvram-format.o hmi.o
CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o
CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o
CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o powercap.o psr.o
-CORE_OBJS += pci-dt-slot.o direct-controls.o
+CORE_OBJS += pci-dt-slot.o direct-controls.o cpufeatures.o
ifeq ($(SKIBOOT_GCOV),1)
CORE_OBJS += gcov-profiling.o
diff --git a/core/cpufeatures.c b/core/cpufeatures.c
new file mode 100644
index 00000000..fa5c4ce5
--- /dev/null
+++ b/core/cpufeatures.c
@@ -0,0 +1,921 @@
+/* Copyright 2017-2018 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This file deals with setup of /cpus/ibm,powerpc-cpu-features dt
+ */
+
+#include <skiboot.h>
+#include <cpu.h>
+#include <processor.h>
+#include <ccan/str/str.h>
+#include <device.h>
+
+#ifdef DEBUG
+#define DBG(fmt, a...) prlog(PR_DEBUG, "CPUFT: " fmt, ##a)
+#else
+#define DBG(fmt, a...)
+#endif
+
+/* Device-tree visible constants follow */
+#define ISA_V2_07B 2070
+#define ISA_V3_0B 3000
+
+#define USABLE_PR (1U << 0)
+#define USABLE_OS (1U << 1)
+#define USABLE_HV (1U << 2)
+
+#define HV_SUPPORT_HFSCR (1U << 0)
+#define OS_SUPPORT_FSCR (1U << 0)
+
+/* Following are definitions for the match tables, not the DT binding itself */
+#define ISA_BASE 0
+
+#define HV_NONE 0
+#define HV_CUSTOM 1
+#define HV_HFSCR 2
+
+#define OS_NONE 0
+#define OS_CUSTOM 1
+#define OS_FSCR 2
+
+/* CPU bitmasks for match table */
+#define CPU_P8_DD1 (1U << 0)
+#define CPU_P8_DD2 (1U << 1)
+#define CPU_P9_DD1 (1U << 2)
+#define CPU_P9_DD2 (1U << 3)
+
+#define CPU_P8 (CPU_P8_DD1|CPU_P8_DD2)
+#define CPU_P9 (CPU_P9_DD1|CPU_P9_DD2)
+#define CPU_ALL (CPU_P8|CPU_P9)
+
+struct cpu_feature {
+ const char *name;
+ uint32_t cpus_supported;
+ uint32_t isa;
+ uint32_t usable_privilege;
+ uint32_t hv_support;
+ uint32_t os_support;
+ uint32_t hfscr_bit_nr;
+ uint32_t fscr_bit_nr;
+ uint32_t hwcap_bit_nr;
+ const char *dependencies_names; /* space-delimited names */
+};
+
+/*
+ * The base (or NULL) cpu feature set is the CPU features available
+ * when no child nodes of the /cpus/ibm,powerpc-cpu-features node exist. The
+ * base feature set is POWER8 (ISAv2.07B), less features that are listed
+ * explicitly.
+ *
+ * XXX: currently, the feature dependencies are not necessarily captured
+ * exactly or completely. This is somewhat acceptable because all
+ * implementations must be aware of all these features.
+ */
+static const struct cpu_feature cpu_features_table[] = {
+ /*
+ * Big endian as in ISAv2.07B, MSR_LE=0
+ */
+ { "big-endian",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * Little endian as in ISAv2.07B, MSR_LE=1.
+ *
+ * When both big and little endian are defined, there is an LPCR ILE
+ * bit and implementation specific way to switch HILE mode, MSR_SLE,
+ * etc.
+ */
+ { "little-endian",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * MSR_HV=1 mode as in ISAv2.07B (i.e., hypervisor privileged
+ * instructions and registers).
+ */
+ { "hypervisor",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV,
+ HV_CUSTOM, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B interrupt vectors, registers, and control registers
+ * (e.g., AIL, ILE, HV, etc LPCR bits).
+ *
+ * This does not necessarily specify all possible interrupt types.
+ * floating-point, for example requires some ways to handle floating
+ * point exceptions, but the low level details of interrupt handler
+ * is not a dependency there. There will always be *some* interrupt
+ * handler, (and some way to provide memory magagement, etc.).
+ */
+ { "interrupt-facilities",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ { "smt",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, 14,
+ NULL, },
+
+ /*
+ * ISAv2.07B Program Priority Registers (PPR)
+ * PPR and associated control registers (e.g. RPR, PSPB),
+ * priority "or" instructions, etc.
+ */
+ { "program-priority-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 5.7.9.1. Virtual Page Class Key Protecion
+ * AMR, IAMR, AMOR, UAMOR, etc registers and MMU key bits.
+ */
+ { "virtual-page-class-key-protection",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B SAO storage control attribute
+ */
+ { "strong-access-ordering",
+ CPU_ALL & ~CPU_P9_DD1,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B no-execute storage control attribute
+ */
+ { "no-execute",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * Cache inhibited attribute supported on large pages.
+ */
+ { "cache-inhibited-large-page",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 8. Debug Facilities
+ * CIEA, CIABR, DEAW, MEte, trace interrupt, etc.
+ * Except CFAR, branch tracing.
+ */
+ { "debug-facilities",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B CFAR
+ */
+ { "come-from-address-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ "debug-facilities", },
+
+ /*
+ * ISAv2.07B Branch tracing (optional in ISA)
+ */
+ { "branch-tracing",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ "debug-facilities", },
+
+ /*
+ * ISAv2.07B Floating-point Facility
+ */
+ { "floating-point",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(63), -1, 27,
+ NULL, },
+
+ /*
+ * ISAv2.07B Vector Facility (VMX)
+ */
+ { "vector",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(62), -1, 28,
+ "floating-point", },
+
+ /*
+ * ISAv2.07B Vector-scalar Facility (VSX)
+ */
+ { "vector-scalar",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, 7,
+ "vector", },
+
+ { "vector-crypto",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, 57,
+ "vector", },
+
+ /*
+ * ISAv2.07B Quadword Load and Store instructions
+ * including lqarx/stdqcx. instructions.
+ */
+ { "quadword-load-store",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Binary Coded Decimal (BCD)
+ * BCD fixed point instructions
+ */
+ { "decimal-integer",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Decimal floating-point Facility (DFP)
+ */
+ { "decimal-floating-point",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, 10,
+ "floating-point", },
+
+ /*
+ * ISAv2.07B
+ * DSCR, default data prefetch LPCR, etc
+ */
+ { "data-stream-control-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(61), PPC_BITLSHIFT(61), 61,
+ NULL, },
+
+ /*
+ * ISAv2.07B Branch History Rolling Buffer (BHRB)
+ */
+ { "branch-history-rolling-buffer",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(59), -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Transactional Memory Facility (TM or HTM)
+ */
+ { "transactional-memory",
+ CPU_P8, /* P9 support is not enabled yet */
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(58), -1, 62,
+ NULL, },
+
+ /*
+ * ISAv3.0B TM additions
+ * TEXASR bit 17, self-induced vs external footprint overflow
+ */
+ { "transactional-memory-v3",
+ 0,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "transactional-memory", },
+
+ /*
+ * ISAv2.07B Event-Based Branch Facility (EBB)
+ */
+ { "event-based-branch",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(56), PPC_BITLSHIFT(56), 60,
+ NULL, },
+
+ /*
+ * ISAv2.07B Target Address Register (TAR)
+ */
+ { "target-address-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_CUSTOM, OS_CUSTOM,
+ PPC_BITLSHIFT(55), PPC_BITLSHIFT(55), 58,
+ NULL, },
+
+ /*
+ * ISAv2.07B Control Register (CTRL)
+ */
+ { "control-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 11. Processor Control.
+ * msgsnd, msgsndp, doorbell, etc.
+ *
+ * ISAv3.0B is not compatible (different addressing, HFSCR required
+ * for msgsndp).
+ */
+ { "processor-control-facility",
+ CPU_P8_DD2, /* P8 DD1 has no dbell */
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B PURR, SPURR registers
+ */
+ { "processor-utilization-of-resources-register",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER8 initiate coprocessor store word indexed (icswx) instruction
+ */
+ { "coprocessor-icswx",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B hash based MMU and all instructions, registers,
+ * data structures, exceptions, etc.
+ */
+ { "mmu-hash",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER8 MCE / machine check exception.
+ */
+ { "machine-check-power8",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER8 PMU / performance monitor unit.
+ */
+ { "performance-monitor-power8",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B alignment interrupts set DSISR register
+ *
+ * POWER CPUs do not used this, and it's removed from ISAv3.0B.
+ */
+ { "alignment-interrupt-dsisr",
+ 0,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B / POWER8 doze, nap, sleep, winkle instructions
+ * XXX: is Linux we using some BookIV specific implementation details
+ * in nap handling? We have no POWER8 specific key here.
+ */
+ { "idle-nap",
+ CPU_P8,
+ ISA_BASE, USABLE_HV,
+ HV_CUSTOM, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B wait instruction
+ */
+ { "wait",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ { "subcore",
+ CPU_P8,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ "smt", },
+
+ /*
+ * ISAv3.0B radix based MMU
+ */
+ { "mmu-radix",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B hash based MMU, new hash pte format, PCTR, etc
+ */
+ { "mmu-hash-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B wait instruction
+ */
+ { "wait-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B stop idle instructions and registers
+ * XXX: Same question as for idle-nap
+ */
+ { "idle-stop",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Hypervisor Virtualization Interrupt
+ * Also associated system registers, LPCR EE, HEIC, HVICE,
+ * system reset SRR1 reason, etc.
+ */
+ { "hypervisor-virtualization-interrupt",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV,
+ HV_CUSTOM, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER9 MCE / machine check exception.
+ */
+ { "machine-check-power9",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * POWER9 PMU / performance monitor unit.
+ */
+ { "performance-monitor-power9",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_CUSTOM,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B scv/rfscv system call instructions and exceptions, fscr bit
+ * etc.
+ */
+ { "system-call-vectored",
+ CPU_P9,
+ ISA_V3_0B, USABLE_OS|USABLE_PR,
+ HV_NONE, OS_CUSTOM,
+ -1, PPC_BITLSHIFT(51), -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Book3S Chapter 10. Processor Control.
+ * global msgsnd, msgsndp, msgsync, doorbell, etc.
+ */
+ { "processor-control-facility-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_CUSTOM, OS_NONE,
+ PPC_BITLSHIFT(53), -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B addpcis instruction
+ */
+ { "pc-relative-addressing",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv2.07B Book3S Chapter 7. Timer Facilities
+ * TB, VTB, DEC, HDEC, IC, etc registers and exceptions.
+ * Not including PURR or SPURR registers.
+ */
+ { "timer-facilities",
+ CPU_ALL,
+ ISA_BASE, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Book3S Chapter 7. Timer Facilities
+ * Large decrementer and hypervisor decrementer
+ */
+ { "timer-facilities-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "timer-facilities", },
+
+ /*
+ * ISAv3.0B deliver a random number instruction (darn)
+ */
+ { "random-number-generator",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B fixed point instructions and registers
+ * multiply-add, modulo, count trailing zeroes, cmprb, cmpeqb,
+ * extswsli, mfvsrld, mtvsrdd, mtvsrws, addex, CA32, OV32,
+ * mcrxrx, setb
+ */
+ { "fixed-point-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ { "decimal-integer-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "fixed-point-v3 decimal-integer", },
+
+ /*
+ * ISAv3.0B lightweight mffs
+ */
+ { "floating-point-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "floating-point", },
+
+ { "decimal-floating-point-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "floating-point-v3 decimal-floating-point", },
+
+ { "vector-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "vector", },
+
+ { "vector-scalar-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "vector-v3 vector-scalar" },
+
+ { "vector-binary128",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, 54,
+ "vector-scalar-v3", },
+
+ { "vector-binary16",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "vector-v3", },
+
+ /*
+ * ISAv3.0B external exception for EBB
+ */
+ { "event-based-branch-v3",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ "event-based-branch", },
+
+ /*
+ * ISAv3.0B Atomic Memory Operations (AMO)
+ */
+ { "atomic-memory-operations",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B Copy-Paste Facility
+ */
+ { "copy-paste",
+ CPU_P9,
+ ISA_V3_0B, USABLE_HV|USABLE_OS|USABLE_PR,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+
+ /*
+ * ISAv3.0B GSR SPR register
+ * POWER9 does not implement it
+ */
+ { "group-start-register",
+ 0,
+ ISA_V3_0B, USABLE_HV|USABLE_OS,
+ HV_NONE, OS_NONE,
+ -1, -1, -1,
+ NULL, },
+};
+
+static void add_cpu_feature_nodeps(struct dt_node *features,
+ const struct cpu_feature *f)
+{
+ struct dt_node *feature;
+
+ feature = dt_new(features, f->name);
+ assert(feature);
+
+ dt_add_property_cells(feature, "isa", f->isa);
+ dt_add_property_cells(feature, "usable-privilege", f->usable_privilege);
+
+ if (f->usable_privilege & USABLE_HV) {
+ if (f->hv_support != HV_NONE) {
+ uint32_t s = 0;
+ if (f->hv_support == HV_HFSCR)
+ s |= HV_SUPPORT_HFSCR;
+
+ dt_add_property_cells(feature, "hv-support", s);
+ if (f->hfscr_bit_nr != -1)
+ dt_add_property_cells(feature, "hfscr-bit-nr", f->hfscr_bit_nr);
+ } else {
+ assert(f->hfscr_bit_nr == -1);
+ }
+ }
+
+ if (f->usable_privilege & USABLE_OS) {
+ if (f->os_support != OS_NONE) {
+ uint32_t s = 0;
+ if (f->os_support == OS_FSCR)
+ s |= OS_SUPPORT_FSCR;
+ dt_add_property_cells(feature, "os-support", s);
+ if (f->fscr_bit_nr != -1)
+ dt_add_property_cells(feature, "fscr-bit-nr", f->fscr_bit_nr);
+ } else {
+ assert(f->fscr_bit_nr == -1);
+ }
+ }
+
+ if (f->usable_privilege & USABLE_PR) {
+ if (f->hwcap_bit_nr != -1)
+ dt_add_property_cells(feature, "hwcap-bit-nr", f->hwcap_bit_nr);
+ }
+
+ if (f->dependencies_names)
+ dt_add_property(feature, "dependencies", NULL, 0);
+}
+
+static void add_cpufeatures_dependencies(struct dt_node *features)
+{
+ struct dt_node *feature;
+
+ dt_for_each_node(features, feature) {
+ const struct cpu_feature *f;
+ const char *deps_names;
+ struct dt_property *deps;
+ int nr_deps;
+ int i;
+
+ /* Find features with dependencies */
+
+ deps = __dt_find_property(feature, "dependencies");
+ if (!deps)
+ continue;
+
+ /* Find the matching cpu table */
+ for (i = 0; i < ARRAY_SIZE(cpu_features_table); i++) {
+ f = &cpu_features_table[i];
+ if (!strcmp(f->name, feature->name))
+ break;
+ }
+ assert(f->dependencies_names);
+
+ /*
+ * Count number of depended features and allocate space
+ * for phandles in the property.
+ */
+ deps_names = f->dependencies_names;
+ nr_deps = strcount(deps_names, " ") + 1;
+ dt_resize_property(&deps, nr_deps * sizeof(u32));
+ deps->len = nr_deps * sizeof(u32);
+
+ DBG("feature %s has %d dependencies (%s)\n", f->name, nr_deps, deps_names);
+ /*
+ * For each one, find the depended feature then advance to
+ * next name.
+ */
+ for (i = 0; i < nr_deps; i++) {
+ struct dt_node *dep;
+ int len;
+
+ if (nr_deps - i == 1)
+ len = strlen(deps_names);
+ else
+ len = strchr(deps_names, ' ') - deps_names;
+
+ dt_for_each_node(features, dep) {
+ if (!strncmp(deps_names, dep->name, len))
+ goto found_dep;
+ }
+
+ prlog(PR_ERR, "CPUFT: feature %s dependencies not found\n", f->name);
+ break;
+found_dep:
+ DBG(" %s found dep (%s)\n", f->name, dep->name);
+ dt_property_set_cell(deps, i, dep->phandle);
+
+ /* Advance over the name + delimiter */
+ deps_names += len + 1;
+ }
+ }
+}
+
+static void add_cpufeatures(struct dt_node *cpus,
+ uint32_t cpu_feature_isa, uint32_t cpu_feature_cpu,
+ const char *cpu_name)
+{
+ struct dt_node *features;
+ int i;
+
+ DBG("creating cpufeatures for cpu:%d isa:%d\n", cpu_feature_cpu, cpu_feature_isa);
+
+ features = dt_new(cpus, "ibm,powerpc-cpu-features");
+ assert(features);
+
+ dt_add_property_cells(features, "isa", cpu_feature_isa);
+
+ dt_add_property_string(features, "device_type", "cpu-features");
+ dt_add_property_string(features, "compatible", "ibm,powerpc-cpu-features");
+ dt_add_property_string(features, "display-name", cpu_name);
+
+ /* add without dependencies */
+ for (i = 0; i < ARRAY_SIZE(cpu_features_table); i++) {
+ const struct cpu_feature *f = &cpu_features_table[i];
+
+ if (f->cpus_supported & cpu_feature_cpu) {
+ DBG(" '%s'\n", f->name);
+ add_cpu_feature_nodeps(features, f);
+ }
+ }
+
+ /* dependency construction pass */
+ add_cpufeatures_dependencies(features);
+}
+
+void dt_add_cpufeatures(struct dt_node *root)
+{
+ int version;
+ uint32_t cpu_feature_isa = 0;
+ uint32_t cpu_feature_cpu = 0;
+ struct dt_node *cpus;
+ const char *cpu_name = NULL;
+
+ version = mfspr(SPR_PVR);
+ switch(PVR_TYPE(version)) {
+ case PVR_TYPE_P8:
+ if (!cpu_name)
+ cpu_name = "POWER8";
+ /* fallthrough */
+ case PVR_TYPE_P8E:
+ if (!cpu_name)
+ cpu_name = "POWER8E";
+ /* fallthrough */
+ case PVR_TYPE_P8NVL:
+ if (!cpu_name)
+ cpu_name = "POWER8NVL";
+
+ cpu_feature_isa = ISA_V2_07B;
+ if (PVR_VERS_MAJ(version) == 1)
+ cpu_feature_cpu = CPU_P8_DD1;
+ else
+ cpu_feature_cpu = CPU_P8_DD2;
+ break;
+ case PVR_TYPE_P9:
+ if (!cpu_name)
+ cpu_name = "POWER9";
+
+ cpu_feature_isa = ISA_V3_0B;
+ if (is_power9n(version) && (PVR_VERS_MAJ(version) == 1)) {
+ /* P9N DD1 */
+ cpu_feature_cpu = CPU_P9_DD1;
+ } else if (is_power9n(version) &&
+ (PVR_VERS_MAJ(version) == 2)) {
+ /* P9N DD2.x */
+ cpu_feature_cpu = CPU_P9_DD2;
+ } else {
+ assert(0);
+ }
+
+ break;
+ default:
+ return;
+ }
+
+ cpus = dt_new_check(root, "cpus");
+
+ add_cpufeatures(cpus, cpu_feature_isa, cpu_feature_cpu, cpu_name);
+}
diff --git a/core/device.c b/core/device.c
index 50fbb186..38dbdfc0 100644
--- a/core/device.c
+++ b/core/device.c
@@ -598,6 +598,13 @@ u32 dt_property_get_cell(const struct dt_property *prop, u32 index)
return fdt32_to_cpu(((const u32 *)prop->prop)[index]);
}
+void dt_property_set_cell(struct dt_property *prop, u32 index, u32 val)
+{
+ assert(prop->len >= (index+1)*sizeof(u32));
+ /* Always aligned, so this works. */
+ ((u32 *)prop->prop)[index] = cpu_to_fdt32(val);
+}
+
/* First child of this node. */
struct dt_node *dt_first(const struct dt_node *root)
{
diff --git a/core/init.c b/core/init.c
index 5736d330..e8c84a95 100644
--- a/core/init.c
+++ b/core/init.c
@@ -876,6 +876,7 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
} else {
dt_expand(fdt);
}
+ dt_add_cpufeatures(dt_root);
/* Now that we have a full devicetree, verify that we aren't on fire. */
per_thread_sanity_checks();
diff --git a/doc/device-tree/ibm,powerpc-cpu-features/binding.txt b/doc/device-tree/ibm,powerpc-cpu-features/binding.txt
new file mode 100644
index 00000000..4dd327ff
--- /dev/null
+++ b/doc/device-tree/ibm,powerpc-cpu-features/binding.txt
@@ -0,0 +1,245 @@
+ibm,powerpc-cpu-features binding
+================================
+
+This device tree binding describes CPU features available to software, with
+enablement, privilege, and compatibility metadata.
+
+More general description of design and implementation of this binding is
+found in design.txt, which also points to documentation of specific features.
+
+
+/cpus/ibm,powerpc-cpu-features node binding
+-------------------------------------------
+
+Node: ibm,powerpc-cpu-features
+
+Description: Container of CPU feature nodes.
+
+The node name must be "ibm,powerpc-cpu-features".
+
+It is implemented as a child of the node "/cpus", but this must not be
+assumed by parsers.
+
+The node is optional but should be provided by new OPAL firmware.
+
+Properties:
+
+- device_type
+ Usage: required
+ Value type: string
+ Definition: "cpu-features"
+
+- compatible
+ Usage: required
+ Value type: string
+ Definition: "ibm,powerpc-cpu-features"
+
+ This compatibility refers to backwards compatibility of the overall
+ design with parsers that behave according to these guidelines. This can
+ be extended in a backward compatible manner which would not warrant a
+ revision of the compatible property.
+
+- isa
+ Usage: required
+ Value type: <u32>
+ Definition:
+
+ isa that the CPU is currently running in. This provides instruction set
+ compatibility, less the individual feature nodes. For example, an ISA v3.0
+ implementation that lacks the "transactional-memory" cpufeature node
+ should not use transactional memory facilities.
+
+ Value corresponds to the "Power ISA Version" multiplied by 1000.
+ For example, <3000> corresponds to Version 3.0, <2070> to Version 2.07.
+ The minor digit is available for revisions.
+
+/cpus/ibm,powerpc-cpu-features/example-feature node bindings
+----------------------------------------------------------------
+
+Each child node of cpu-features represents a CPU feature / capability.
+
+Node: A string describing an architected CPU feature, e.g., "floating-point".
+
+Description: A feature or capability supported by the CPUs.
+
+The name of the node is a human readable string that forms the interface
+used to describe features to software. Features are currently documented
+in the code where they are implemented in skiboot/core/cpufeatures.c
+
+Presence of the node indicates the feature is available.
+
+Properties:
+
+- isa
+ Usage: required
+ Value type: <u32>
+ Definition:
+
+ First level of the Power ISA that the feature appears in.
+ Software should filter out features when constraining the
+ environment to a particular ISA version.
+
+ Value is defined similarly to /cpus/features/isa
+
+- usable-privilege
+ Usage: required
+ Value type: <u32> bit mask
+ Definition:
+ Bit numbers are LSB0
+ bit 0 - PR (problem state / user mode)
+ bit 1 - OS (privileged state)
+ bit 2 - HV (hypervisor state)
+ All other bits reserved and should be zero.
+
+ This property describes the privilege levels and/or software components
+ that can use the feature.
+
+ If bit 0 is set, then the hwcap-bit-nr property will exist.
+
+
+- hv-support
+ Usage: optional
+ Value type: <u32> bit mask
+ Definition:
+ Bit numbers are LSB0
+ bit 0 - HFSCR
+ All other bits reserved and should be zero.
+
+ This property describes the HV privilege support required to enable the
+ feature to lesser privilege levels. If the property does not exist then no
+ support is required.
+
+ If no bits are set, the hypervisor must have explicit/custom support for
+ this feature.
+
+ If the HFSCR bit is set, then the hfscr-bit-nr property will exist and
+ the feature may be enabled by setting this bit in the HFSCR register.
+
+
+- os-support
+ Usage: optional
+ Value type: <u32> bit mask
+ Definition:
+ Bit numbers are LSB0
+ bit 0 - FSCR
+ All other bits reserved and should be zero.
+
+ This property describes the OS privilege support required to enable the
+ feature to lesser privilege levels. If the property does not exist then no
+ support is required.
+
+ If no bits are set, the operating system must have explicit/custom support
+ for this feature.
+
+ If the FSCR bit is set, then the fscr-bit-nr property will exist and
+ the feature may be enabled by setting this bit in the FSCR register.
+
+
+- hfscr-bit-nr
+ Usage: optional
+ Value type: <u32>
+ Definition: HFSCR bit position (LSB0)
+
+ This property exists when the hv-support property HFSCR bit is set. This
+ property describes the bit number in the HFSCR register that the
+ hypervisor must set in order to enable this feature.
+
+ This property also exists if an HFSCR bit corresponds with this feature.
+ This makes CPU feature parsing slightly simpler.
+
+
+- fscr-bit-nr
+ Usage: optional
+ Value type: <u32>
+ Definition: FSCR bit position (LSB0)
+
+ This property exists when the os-support property FSCR bit is set. This
+ property describes the bit number in the FSCR register that the
+ operating system must set in order to enable this feature.
+
+ This property also exists if an FSCR bit corresponds with this feature.
+ This makes CPU feature parsing slightly simpler.
+
+
+- hwcap-bit-nr
+ Usage: optional
+ Value type: <u32>
+ Definition: Linux ELF AUX vector bit position (LSB0)
+
+ This property may exist when the usable-privilege property value has PR bit set.
+ This property describes the bit number that should be set in the ELF AUX
+ hardware capability vectors in order to advertise this feature to userspace.
+ Bits 0-31 correspond to bits 0-31 in AT_HWCAP vector. Bits 32-63 correspond
+ to 0-31 in AT_HWCAP2 vector, and so on. Missing AT_HWCAPx vectors implies
+ that the feature is not enabled or can not be advertised. Operating systems
+ may provide a number of unassigned hardware capability bits to allow for new
+ features to be advertised.
+
+ Some properties representing features created before this binding are
+ advertised to userspace without a one-to-one hwcap bit number may not specify
+ this bit. Operating system will handle those bits specifically. All new
+ features usable by userspace will have a hwcap-bit-nr property.
+
+
+- dependencies
+ Usage: optional
+ Value type: <prop-encoded-array>
+ Definition:
+
+ If this property exists then it is a list of phandles to cpu feature
+ nodes that must be enabled for this feature to be enabled.
+
+
+- Custom properties of the feature
+ Usage: optional
+ Definition:
+
+ Particular features may define their own properties.
+
+
+Example
+-------
+
+ /cpus/ibm,powerpc-cpu-features {
+ device_type = "ibm,powerpc-cpu-features";
+
+ isa = <3020>;
+
+ darn {
+ isa = <3000>;
+ usable-privilege = <1 | 2 | 4>;
+ hwcap-bit-nr = <xx>;
+ };
+
+ scv {
+ isa = <3000>;
+ usable-privilege = <1 | 2>;
+ os-support = <0>;
+ hwcap-bit-nr = <xx>;
+ };
+
+ stop {
+ isa = <3000>;
+ usable-privilege = <2 | 4>;
+ hv-support = <0>;
+ os-support = <0>;
+ };
+
+ vsx2 (hypothetical) {
+ isa = <3010>;
+ usable-privilege = <1 | 2 | 4>;
+ hv-support = <0>;
+ os-support = <0>;
+ hwcap-bit-nr = <xx>;
+ };
+
+ vsx2-newinsns {
+ isa = <3020>;
+ usable-privilege = <1 | 2 | 4>;
+ os-support = <1>;
+ fscr-bit-nr = <xx>;
+ hwcap-bit-nr = <xx>;
+ dependencies = <&vsx2>;
+ };
+
+ };
diff --git a/doc/device-tree/ibm,powerpc-cpu-features/design.txt b/doc/device-tree/ibm,powerpc-cpu-features/design.txt
new file mode 100644
index 00000000..2f9f870c
--- /dev/null
+++ b/doc/device-tree/ibm,powerpc-cpu-features/design.txt
@@ -0,0 +1,157 @@
+ibm,powerpc-cpu-features binding
+================================
+
+The OPAL / skiboot code is the canonical location for this specification. All
+definitions of features, constant, bit positions, etc. must be documented here
+before being deployed in Linux. This is not presently part of LoPAPR.
+
+
+Interfaces
+----------
+This specification describes the ibm,powerpc-cpu-features binding (the formal
+definition of binding can be found in binding.txt in this directory).
+
+This specification also involves the Linux ELF AUXV AT_HWCAP and AT_HWCAP2
+interfaces for PPC_FEATURE* bits. Allocation of new AT_HWCAP bits should be
+done in coordination with OPAL / skiboot, Linux, and glibc projects.
+
+The binding is passed to the hypervisor by firmware. The hypervisor may
+build a subset with unsupported/disabled features and hypervisor specifics
+removed, and pass that to a guest OS. The OS may advertise features to
+userspace.
+
+
+Background
+----------
+The cpu-features binding (subsequently "cpu-features") aims to provide an
+extensible metadata and protocol between different levels of system software
+(firmware, hypervisor, OS/guest, userspace) to advertise the CPU features
+available on the system. With each level able to shape the features available
+to the next.
+
+The binding specifies features common to all CPUs in the system. Heterogeneous
+CPU features are not supported at present (such could be added by providing
+additional cpu-features nodes and linking those to particular CPUs with
+additional features).
+
+There is no strict definition for what a CPU feature must be, but an
+architectural behaviour or performance characteristic (or group of related
+behaviours). They must be documented in skiboot/core/cpufeatures.c sufficiently
+precisely. More guidelines for feature definitions below.
+
+cpu-features is intended to provide fine grained control of CPU features at
+all levels of the stack (firmware, hypervisor, OS, userspace), with the
+ability for new CPU features to be used by some components without all
+components being upgraded (e.g., a new floating point instruction could be
+used by userspace math library without upgrading kernel and hypervisor).
+
+
+Overview
+--------
+
+The cpu-features node is created by firmware and passed to the hypervisor.
+The hypervisor may create cpu-features node to be passed to guest, based on
+the features that have been enabled, and policy decisions. Hypervisor specific
+features, and hypervisor bits and properties should not be advertised to
+guests. Guest OS may advertise features to userspace using another method
+(e.g., using AUXV vectors, userspace typically does not parse DT).
+
+When the cpu-features node is present, ibm,pa-features and individual feature
+properties (e.g., "ibm,vsx"), and cpu-version under the "cpu" compatible nodes
+can be ignored by the consumer. For compatibility, the provider must continue
+to provide those older properties and the consumer must not assume cpu-features
+exists.
+
+When this node exists, software may assume a base feature set which is ISA
+v2.07B (BookS) minus the explicit features listed in core/cpufeatures.c
+entries in this source tree.
+
+Each feature is advertised as a node underneath the cpu-features node, named
+with a human-readable string name that uniquely identifies specification of
+that capability.
+
+A feature node has a number of metadata properties describing privilege levels
+a feature may be used (HV, OS, PR/user), and information about how it is to
+be enabled and advertised to lesser privilege levels. Enabling means to make
+it available at a lesser privilege level, (how to enable a given feature
+for this privilege level is implicit: if the software know how to use a
+feature, it also knows how to enable it).
+
+Feature node properties:
+
+- "isa", the Power ISA version where this feature first became available.
+ In case of an implementation specific feature
+
+- "usable-privilege", a bitmask (HV, OS, PR/user) specifying which privilege
+ levels this feature may be used in.
+
+- "hv-support", a bitmask. If this exists, the hypervisor must do some work
+ to enable support for lesser privilege levels. Bits can be set in this mask
+ to specify prescription/recipes to enable the feature without custom code.
+ If no bits are set, no recipe exists and custom code must be used. HFSCR
+ register enable bit is the only such recipe currently.
+
+- "os-support", similar to hv-support. FSCR recipe.
+
+- Features may have additional properties associated, must be documented with
+ the feature.
+
+- Recipes may have additional properties associated. HFSCR recipe has
+ hfscr-bit-nr, and FSCR recipe has fscr-bit-nr.
+
+- "dependencies" array of phandles. If this exists, it links to the
+ features that must be enabled in order for this feature to be enabled.
+
+- "hwcap-bit-nr" if it exists provides a Linux ELF AUXV HWCAP bit number that
+ can be used to advertise this feature to userspace.
+
+Together, these compatibility, support, and dependencies properties allow
+unknown features to be enabled and advertised to lesser privilege levels
+(when possible).
+
+All bits not defined in usable, support masks must be 0, and should be ignored
+by consumers. This allows extensibility to add new privilege levels and new
+recipes. Unknown properties should also be ignored. This allows extensibility
+for additional methods and metadata for enablement and advertisement.
+
+The policy for selecting and configuring which features to advertise and use
+is left for implementations.
+
+
+Guidelines for defining features
+--------------------------------
+
+As a rough guide, features should be based on functional groups of changes
+to the ISA, or related performance characteristics.
+
+Grouping should be made by one or a combination of those that:
+- Share common enablement requirements (e.g., share particular registers or
+ firmware setup requirements).
+- Share common usage patterns (e..g, likely to be used together).
+- Are implemented with a particular new hardware unit.
+- Are optional in the ISA.
+
+Granularity can be debated, but fine grained and encompassing is generally
+preferable. For example, memory management unit may be considered fundamental,
+but the MMU in POWER9 is very different and in many ways incompatible from
+that in POWER8 even in hash mode.
+
+For example, "POWER9" would be too general, but a new feature for every
+instruction would be too specific. The "summary of changes" preface in Power
+ISA specification is a good starting point to give a guideline for granularity
+of the architected features.
+
+New features that offer additional or incompatible functionality beyond
+an existing feature may contain an ISA version postfix.
+
+Implementation specific behaviour should contain a CPU type postfix. E.g.,
+"machine-check-power9" gives exact MCE properties. If a future CPU has the same
+MCE architecture, it should define the same property. If it has a
+backward-compatible superset, it could additionally define
+"machine-check-newcpu".
+
+Features should be "positive" as much as possible. That is, the presence of
+a feature should indicate the presence of an additional CPU feature (e.g., a
+new instruction or register). This requires some anticipation and foresight
+for defining CPU features. "Negative" features may be unavoidable in some
+cases.
diff --git a/include/device.h b/include/device.h
index 1e5875dc..fd66df11 100644
--- a/include/device.h
+++ b/include/device.h
@@ -141,6 +141,7 @@ void dt_check_del_prop(struct dt_node *node, const char *name);
/* Warning: moves *prop! */
void dt_resize_property(struct dt_property **prop, size_t len);
+void dt_property_set_cell(struct dt_property *prop, u32 index, u32 val);
u32 dt_property_get_cell(const struct dt_property *prop, u32 index);
/* First child of this node. */
diff --git a/include/skiboot.h b/include/skiboot.h
index d1de10a4..2f81a058 100644
--- a/include/skiboot.h
+++ b/include/skiboot.h
@@ -195,6 +195,11 @@ extern void start_kernel_secondary(uint64_t entry) __noreturn;
/* Get description of machine from HDAT and create device-tree */
extern int parse_hdat(bool is_opal);
+struct dt_node;
+
+/* Add /cpus/features node for boot environment that passes an fdt */
+extern void dt_add_cpufeatures(struct dt_node *root);
+
/* Root of device tree. */
extern struct dt_node *dt_root;
--
2.16.1
^ permalink raw reply related
* [PATCH] pseries/drmem: Check for zero filled ibm, dynamic-memory property.
From: Nathan Fontenot @ 2018-02-16 3:27 UTC (permalink / raw)
To: linuxppc-dev; +Cc: mpe, camb, daniel, ""@gmail.com
Some versions of QEMU will produce an ibm,dynamic-reconfiguration-memory
node with a ibm,dynamic-memory property that is zero-filled. This causes
the drmem code to oops trying to parse this property.
The fix for this is to validate that the property does contain LMB
entries before trying to parse it and bail if the count is zero.
Oops: Kernel access of bad area, sig: 11 [#1]
SMP NR_CPUS=2048
NUMA
pSeries
Modules linked in:
Supported: Yes
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.12.14-11.2-default #1
task: c00000007e639680 task.stack: c00000007e648000
NIP: c000000000c709a4 LR: c000000000c70998 CTR: 0000000000000000
REGS: c00000007e64b8d0 TRAP: 0300 Not tainted (4.12.14-11.2-default)
MSR: 800000010280b033 <SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE,TM[E]>
CR: 84000248 XER: 00000000
CFAR: c00000000067018c DAR: 0000000000000010 DSISR: 42000000 SOFTE: 1
GPR00: c000000000c70998 c00000007e64bb50 c000000001157b00 0000000000000000
GPR04: c00000007e64bb70 0000000000000000 000000000000002f 0000000000000022
GPR08: 0000000000000003 c000000006f63fac c000000006f63fb0 000000000000001e
GPR12: 0000000000000000 c00000000fa80000 c00000000000dca8 0000000000000000
GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
GPR24: c000000000cccb98 c000000000c636f0 c000000000c56cd0 0000000000000007
GPR28: c000000000cccba8 c00000007ffffc30 c00000007e64bbf0 0000000000000010
NIP [c000000000c709a4] read_drconf_v1_cell+0x54/0x9c
LR [c000000000c70998] read_drconf_v1_cell+0x48/0x9c
Call Trace:
[c00000007e64bb50] [c000000000c56cd0] __param_initcall_debug+0x0/0x28 (unreliable)
[c00000007e64bb90] [c000000000c70e24] drmem_init+0x144/0x2f8
[c00000007e64bc40] [c00000000000d034] do_one_initcall+0x64/0x1d0
[c00000007e64bd00] [c000000000c643d0] kernel_init_freeable+0x298/0x38c
[c00000007e64bdc0] [c00000000000dcc4] kernel_init+0x24/0x160
[c00000007e64be30] [c00000000000b428] ret_from_kernel_thread+0x5c/0xb4
Instruction dump:
7c9e2378 60000000 e9429050 e93e0000 7c240b78 7c7f1b78 f9240021 e86a0002
4804e41d 60000000 e9210020 39490004 <f87f0000> f9410020 39490010 7d004c2c
The ibm,dynamic-reconfiguration-memory device tree property
generated that causes this:
ibm,dynamic-reconfiguration-memory {
ibm,lmb-size = <0x0 0x10000000>;
ibm,memory-flags-mask = <0xff>;
ibm,dynamic-memory = <0x0 0x0 0x0 0x0 0x0 0x0>;
linux,phandle = <0x7e57eed8>;
ibm,associativity-lookup-arrays = <0x1 0x4 0x0 0x0 0x0 0x0>;
ibm,memory-preservation-time = <0x0>;
};
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/mm/drmem.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/powerpc/mm/drmem.c b/arch/powerpc/mm/drmem.c
index 1604110c4238..916844f99c64 100644
--- a/arch/powerpc/mm/drmem.c
+++ b/arch/powerpc/mm/drmem.c
@@ -216,6 +216,8 @@ static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm,
u32 i, n_lmbs;
n_lmbs = of_read_number(prop++, 1);
+ if (n_lmbs == 0)
+ return;
for (i = 0; i < n_lmbs; i++) {
read_drconf_v1_cell(&lmb, &prop);
@@ -245,6 +247,8 @@ static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
u32 i, j, lmb_sets;
lmb_sets = of_read_number(prop++, 1);
+ if (lmb_sets == 0)
+ return;
for (i = 0; i < lmb_sets; i++) {
read_drconf_v2_cell(&dr_cell, &prop);
@@ -354,6 +358,8 @@ static void __init init_drmem_v1_lmbs(const __be32 *prop)
struct drmem_lmb *lmb;
drmem_info->n_lmbs = of_read_number(prop++, 1);
+ if (drmem_info->n_lmbs == 0)
+ return;
drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb),
GFP_KERNEL);
@@ -373,6 +379,8 @@ static void __init init_drmem_v2_lmbs(const __be32 *prop)
int lmb_index;
lmb_sets = of_read_number(prop++, 1);
+ if (lmb_sets == 0)
+ return;
/* first pass, calculate the number of LMBs */
p = prop;
^ permalink raw reply related
* Re: [PATCH] pseries/drmem: Check for zero filled ibm, dynamic-memory property.
From: Cyril Bur @ 2018-02-16 4:17 UTC (permalink / raw)
To: Nathan Fontenot, linuxppc-dev; +Cc: daniel
In-Reply-To: <151875166139.16739.9174261168457130221.stgit@ltcalpine2-lp14.aus.stglabs.ibm.com>
On Thu, 2018-02-15 at 21:27 -0600, Nathan Fontenot wrote:
> Some versions of QEMU will produce an ibm,dynamic-reconfiguration-memory
> node with a ibm,dynamic-memory property that is zero-filled. This causes
> the drmem code to oops trying to parse this property.
>
> The fix for this is to validate that the property does contain LMB
> entries before trying to parse it and bail if the count is zero.
>
> Oops: Kernel access of bad area, sig: 11 [#1]
> SMP NR_CPUS=2048
> NUMA
> pSeries
> Modules linked in:
> Supported: Yes
> CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.12.14-11.2-default #1
> task: c00000007e639680 task.stack: c00000007e648000
> NIP: c000000000c709a4 LR: c000000000c70998 CTR: 0000000000000000
> REGS: c00000007e64b8d0 TRAP: 0300 Not tainted (4.12.14-11.2-default)
> MSR: 800000010280b033 <SF,VEC,VSX,EE,FP,ME,IR,DR,RI,LE,TM[E]>
> CR: 84000248 XER: 00000000
> CFAR: c00000000067018c DAR: 0000000000000010 DSISR: 42000000 SOFTE: 1
> GPR00: c000000000c70998 c00000007e64bb50 c000000001157b00 0000000000000000
> GPR04: c00000007e64bb70 0000000000000000 000000000000002f 0000000000000022
> GPR08: 0000000000000003 c000000006f63fac c000000006f63fb0 000000000000001e
> GPR12: 0000000000000000 c00000000fa80000 c00000000000dca8 0000000000000000
> GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> GPR20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000
> GPR24: c000000000cccb98 c000000000c636f0 c000000000c56cd0 0000000000000007
> GPR28: c000000000cccba8 c00000007ffffc30 c00000007e64bbf0 0000000000000010
> NIP [c000000000c709a4] read_drconf_v1_cell+0x54/0x9c
> LR [c000000000c70998] read_drconf_v1_cell+0x48/0x9c
> Call Trace:
> [c00000007e64bb50] [c000000000c56cd0] __param_initcall_debug+0x0/0x28 (unreliable)
> [c00000007e64bb90] [c000000000c70e24] drmem_init+0x144/0x2f8
> [c00000007e64bc40] [c00000000000d034] do_one_initcall+0x64/0x1d0
> [c00000007e64bd00] [c000000000c643d0] kernel_init_freeable+0x298/0x38c
> [c00000007e64bdc0] [c00000000000dcc4] kernel_init+0x24/0x160
> [c00000007e64be30] [c00000000000b428] ret_from_kernel_thread+0x5c/0xb4
> Instruction dump:
> 7c9e2378 60000000 e9429050 e93e0000 7c240b78 7c7f1b78 f9240021 e86a0002
> 4804e41d 60000000 e9210020 39490004 <f87f0000> f9410020 39490010 7d004c2c
>
> The ibm,dynamic-reconfiguration-memory device tree property
> generated that causes this:
>
> ibm,dynamic-reconfiguration-memory {
> ibm,lmb-size = <0x0 0x10000000>;
> ibm,memory-flags-mask = <0xff>;
> ibm,dynamic-memory = <0x0 0x0 0x0 0x0 0x0 0x0>;
> linux,phandle = <0x7e57eed8>;
> ibm,associativity-lookup-arrays = <0x1 0x4 0x0 0x0 0x0 0x0>;
> ibm,memory-preservation-time = <0x0>;
> };
>
> Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Works for me.
Reviewed-by: Cyril Bur <cyrilbur@gmail.com>
> ---
> arch/powerpc/mm/drmem.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/arch/powerpc/mm/drmem.c b/arch/powerpc/mm/drmem.c
> index 1604110c4238..916844f99c64 100644
> --- a/arch/powerpc/mm/drmem.c
> +++ b/arch/powerpc/mm/drmem.c
> @@ -216,6 +216,8 @@ static void __init __walk_drmem_v1_lmbs(const __be32 *prop, const __be32 *usm,
> u32 i, n_lmbs;
>
> n_lmbs = of_read_number(prop++, 1);
> + if (n_lmbs == 0)
> + return;
>
> for (i = 0; i < n_lmbs; i++) {
> read_drconf_v1_cell(&lmb, &prop);
> @@ -245,6 +247,8 @@ static void __init __walk_drmem_v2_lmbs(const __be32 *prop, const __be32 *usm,
> u32 i, j, lmb_sets;
>
> lmb_sets = of_read_number(prop++, 1);
> + if (lmb_sets == 0)
> + return;
>
> for (i = 0; i < lmb_sets; i++) {
> read_drconf_v2_cell(&dr_cell, &prop);
> @@ -354,6 +358,8 @@ static void __init init_drmem_v1_lmbs(const __be32 *prop)
> struct drmem_lmb *lmb;
>
> drmem_info->n_lmbs = of_read_number(prop++, 1);
> + if (drmem_info->n_lmbs == 0)
> + return;
>
> drmem_info->lmbs = kcalloc(drmem_info->n_lmbs, sizeof(*lmb),
> GFP_KERNEL);
> @@ -373,6 +379,8 @@ static void __init init_drmem_v2_lmbs(const __be32 *prop)
> int lmb_index;
>
> lmb_sets = of_read_number(prop++, 1);
> + if (lmb_sets == 0)
> + return;
>
> /* first pass, calculate the number of LMBs */
> p = prop;
>
^ permalink raw reply
* Re: [PATCH] pseries/drmem: Check for zero filled ibm, dynamic-memory property.
From: Daniel Black @ 2018-02-16 4:28 UTC (permalink / raw)
To: Nathan Fontenot, linuxppc-dev; +Cc: mpe, Cyril Bur
In-Reply-To: <151875166139.16739.9174261168457130221.stgit@ltcalpine2-lp14.aus.stglabs.ibm.com>
Looks good to me.
Boots without backtrace.
qemu-system-ppc64 -enable-kvm -cpu POWER8 -m 4G -M pseries -nographic
-vga none -kernel /tmp/vmlinux
qemu-system-ppc64 --version
QEMU emulator version 2.5.0 (Debian 1:2.5+dfsg-5ubuntu10.20)
Tested-by: Daniel Black <daniel@linux.vnet.ibm.com>
^ permalink raw reply
* Re: [PATCH v2] cxl: Check if PSL data-cache is available before issue flush request
From: Frederic Barrat @ 2018-02-16 9:29 UTC (permalink / raw)
To: Vaibhav Jain, linuxppc-dev
Cc: Andrew Donnellan, Christophe Lombard, Philippe Bergheaud,
Alastair D'Silva
In-Reply-To: <20180215154924.22005-1-vaibhav@linux.vnet.ibm.com>
Le 15/02/2018 à 16:49, Vaibhav Jain a écrit :
> PSL9D doesn't have a data-cache that needs to be flushed before
> resetting the card. However when cxl tries to flush data-cache on such
> a card, it times-out as PSL_Control register never indicates flush
> operation complete due to missing data-cache. This is usually
> indicated in the kernel logs with this message:
>
> "WARNING: cache flush timed out"
>
> To fix this the patch checks PSL_Debug register CDC-Field(BIT:27)
> which indicates the absence of a data-cache and sets a flag
> 'no_data_cache' in 'struct cxl_native' to indicate this. When
> cxl_data_cache_flush() is called it checks the flag and if set bails
> out early without requesting a data-cache flush operation to the PSL.
>
> Signed-off-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com>
> ---
Thanks!
Acked-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
> Change-log:
> v2 -> Changed the dev_info to dev_dbg (Fred)
> Removed the check for DD1.0 chips (Fred)
> ---
> drivers/misc/cxl/cxl.h | 4 ++++
> drivers/misc/cxl/native.c | 11 ++++++++++-
> drivers/misc/cxl/pci.c | 18 ++++++++++++------
> 3 files changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
> index 4f015da78f28..4949b8d5a748 100644
> --- a/drivers/misc/cxl/cxl.h
> +++ b/drivers/misc/cxl/cxl.h
> @@ -369,6 +369,9 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0};
> #define CXL_PSL_TFC_An_AE (1ull << (63-30)) /* Restart PSL with address error */
> #define CXL_PSL_TFC_An_R (1ull << (63-31)) /* Restart PSL transaction */
>
> +/****** CXL_PSL_DEBUG *****************************************************/
> +#define CXL_PSL_DEBUG_CDC (1ull << (63-27)) /* Coherent Data cache support */
> +
> /****** CXL_XSL9_IERAT_ERAT - CAIA 2 **********************************/
> #define CXL_XSL9_IERAT_MLPID (1ull << (63-0)) /* Match LPID */
> #define CXL_XSL9_IERAT_MPID (1ull << (63-1)) /* Match PID */
> @@ -669,6 +672,7 @@ struct cxl_native {
> irq_hw_number_t err_hwirq;
> unsigned int err_virq;
> u64 ps_off;
> + bool no_data_cache; /* set if no data cache on the card */
> const struct cxl_service_layer_ops *sl_ops;
> };
>
> diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
> index 1b3d7c65ea3f..98f867fcef24 100644
> --- a/drivers/misc/cxl/native.c
> +++ b/drivers/misc/cxl/native.c
> @@ -353,8 +353,17 @@ int cxl_data_cache_flush(struct cxl *adapter)
> u64 reg;
> unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
>
> - pr_devel("Flushing data cache\n");
> + /*
> + * Do a datacache flush only if datacache is available.
> + * In case of PSL9D datacache absent hence flush operation.
> + * would timeout.
> + */
> + if (adapter->native->no_data_cache) {
> + pr_devel("No PSL data cache. Ignoring cache flush req.\n");
> + return 0;
> + }
>
> + pr_devel("Flushing data cache\n");
> reg = cxl_p1_read(adapter, CXL_PSL_Control);
> reg |= CXL_PSL_Control_Fr;
> cxl_p1_write(adapter, CXL_PSL_Control, reg);
> diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
> index 758842f65a1b..3255f89c85d0 100644
> --- a/drivers/misc/cxl/pci.c
> +++ b/drivers/misc/cxl/pci.c
> @@ -456,6 +456,7 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter,
> u64 chipid;
> u32 phb_index;
> u64 capp_unit_id;
> + u64 psl_debug;
> int rc;
>
> rc = cxl_calc_capp_routing(dev, &chipid, &phb_index, &capp_unit_id);
> @@ -506,6 +507,15 @@ static int init_implementation_adapter_regs_psl9(struct cxl *adapter,
> } else
> cxl_p1_write(adapter, CXL_PSL9_DEBUG, 0x4000000000000000ULL);
>
> + /* Check if PSL has data-cache. We need to flush adapter datacache
> + * when as its about to be removed.
> + */
> + psl_debug = cxl_p1_read(adapter, CXL_PSL9_DEBUG);
> + if (psl_debug & CXL_PSL_DEBUG_CDC) {
> + dev_dbg(&dev->dev, "No data-cache present\n");
> + adapter->native->no_data_cache = true;
> + }
> +
> return 0;
> }
>
> @@ -1449,10 +1459,8 @@ int cxl_pci_reset(struct cxl *adapter)
>
> /*
> * The adapter is about to be reset, so ignore errors.
> - * Not supported on P9 DD1
> */
> - if ((cxl_is_power8()) || (!(cxl_is_power9_dd1())))
> - cxl_data_cache_flush(adapter);
> + cxl_data_cache_flush(adapter);
>
> /* pcie_warm_reset requests a fundamental pci reset which includes a
> * PERST assert/deassert. PERST triggers a loading of the image
> @@ -1936,10 +1944,8 @@ static void cxl_pci_remove_adapter(struct cxl *adapter)
>
> /*
> * Flush adapter datacache as its about to be removed.
> - * Not supported on P9 DD1.
> */
> - if ((cxl_is_power8()) || (!(cxl_is_power9_dd1())))
> - cxl_data_cache_flush(adapter);
> + cxl_data_cache_flush(adapter);
>
> cxl_deconfigure_adapter(adapter);
>
^ permalink raw reply
* Re: [PATCH V2] cxl: Fix timebase synchronization status on P9
From: Frederic Barrat @ 2018-02-16 9:41 UTC (permalink / raw)
To: Christophe Lombard, linuxppc-dev, vaibhav, andrew.donnellan
In-Reply-To: <1518713524-1500-1-git-send-email-clombard@linux.vnet.ibm.com>
Le 15/02/2018 à 17:52, Christophe Lombard a écrit :
> The PSL Timebase register is updated by the PSL to maintain the
> timebase.
> On P9, the Timebase value is only provided by the CAPP as received
> the last time a timebase request was performed.
> The timebase requests are initiated through the adapter configuration or
> application registers.
> The specific sysfs entry "/sys/class/cxl/cardxx/psl_timebase_synced" is
> now dynamically updated according the content of the PSL Timebase
> register.
>
> Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com>
>
> ---
> Changelog[v2]
> - Missing Signed-off-by
> - Spaces required around the ':'
> ---
> drivers/misc/cxl/pci.c | 35 +++++++++++++++++++----------------
> drivers/misc/cxl/sysfs.c | 14 ++++++++++++++
> 2 files changed, 33 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
> index 758842f..270afb5 100644
> --- a/drivers/misc/cxl/pci.c
> +++ b/drivers/misc/cxl/pci.c
> @@ -612,8 +612,6 @@ static u64 timebase_read_xsl(struct cxl *adapter)
>
> static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
> {
> - u64 psl_tb;
> - int delta;
> unsigned int retry = 0;
> struct device_node *np;
>
> @@ -641,20 +639,25 @@ static void cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev)
> cxl_p1_write(adapter, CXL_PSL_Control, 0x0000000000000000);
> cxl_p1_write(adapter, CXL_PSL_Control, CXL_PSL_Control_tb);
>
> - /* Wait until CORE TB and PSL TB difference <= 16usecs */
> - do {
> - msleep(1);
> - if (retry++ > 5) {
> - dev_info(&dev->dev, "PSL timebase can't synchronize\n");
> - return;
> - }
> - psl_tb = adapter->native->sl_ops->timebase_read(adapter);
> - delta = mftb() - psl_tb;
> - if (delta < 0)
> - delta = -delta;
> - } while (tb_to_ns(delta) > 16000);
> -
> - adapter->psl_timebase_synced = true;
> + if (cxl_is_power8()) {
> + u64 psl_tb;
> + int delta;
> +
> + /* Wait until CORE TB and PSL TB difference <= 16usecs */
> + do {
> + msleep(1);
> + if (retry++ > 5) {
> + dev_info(&dev->dev, "PSL timebase can't synchronize\n");
> + return;
> + }
> + psl_tb = adapter->native->sl_ops->timebase_read(adapter);
> + delta = mftb() - psl_tb;
> + if (delta < 0)
> + delta = -delta;
> + } while (tb_to_ns(delta) > 16000);
> +
> + adapter->psl_timebase_synced = true;
> + }
> return;
> }
>
> diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c
> index a8b6d6a..5384c59 100644
> --- a/drivers/misc/cxl/sysfs.c
> +++ b/drivers/misc/cxl/sysfs.c
> @@ -63,6 +63,20 @@ static ssize_t psl_timebase_synced_show(struct device *device,
> {
> struct cxl *adapter = to_cxl_adapter(device);
>
> + /*
> + * On P9, the Timebase value is only updated as a result of
> + * PSL TimeBase command sent to CAPP.
> + */
> + if (cxl_is_power9()) {
> + u64 psl_tb;
> + int delta;
> +
> + psl_tb = cxl_p1_read(adapter, CXL_PSL9_Timebase);
> + delta = mftb() - psl_tb;
> + if (delta < 0)
> + delta = -delta;
> + adapter->psl_timebase_synced = true ? tb_to_ns(delta) < 16000 : false;
I doubt it is what you meant. The syntax is just wrong, though it may
actually work ;-)
The patch also conflicts with Vaibhav's about write_timebase_ctrl
I'm also wondering if it wouldn't be simpler to always update the
timebase_synced flag dynamically, even on p8. That way we wouldn't need
to have the p8 specific code to check for synchronization in
cxl_setup_psl_timebase(). p8 and p9 code would be the same.
Fred
> + }
> return scnprintf(buf, PAGE_SIZE, "%i\n", adapter->psl_timebase_synced);
> }
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox