* [PATCH v2 4/11] Update firmware_has_feature() to check architecture bits
From: Nathan Fontenot @ 2013-03-25 18:54 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
The firmware_has_feature() function makes it easy to check for supported
features of the hypervisor. This patch extends the capability of the
firmware_has_feature() function to include checking for specified bits
in vector 5 of the architecture vector as is reported in the device tree.
As part of this the #defines used for the architecture vector are
moved to prom.h and re-defined such that the vector 5 options have the vector
index and the feature bits encoded into them. This makes for a much
simpler design to add bits from the architecture vector to be added to
the checking done in firmware_has_feature().
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/firmware.h | 4 +
arch/powerpc/include/asm/prom.h | 45 +++++++++-----------
arch/powerpc/kernel/prom_init.c | 23 +++++++---
arch/powerpc/platforms/pseries/firmware.c | 67 ++++++++++++++++++++++++++----
arch/powerpc/platforms/pseries/pseries.h | 5 +-
arch/powerpc/platforms/pseries/setup.c | 40 ++++++++++++-----
6 files changed, 131 insertions(+), 53 deletions(-)
Index: powerpc/arch/powerpc/include/asm/prom.h
===================================================================
--- powerpc.orig/arch/powerpc/include/asm/prom.h 2013-03-25 10:47:54.000000000 -0500
+++ powerpc/arch/powerpc/include/asm/prom.h 2013-03-25 11:07:56.000000000 -0500
@@ -111,31 +111,27 @@
/* Option vector 4: IBM PAPR implementation */
#define OV4_MIN_ENT_CAP 0x01 /* minimum VP entitled capacity */
-/* Option vector 5: PAPR/OF options supported */
-#define OV5_LPAR 0x80 /* logical partitioning supported */
-#define OV5_SPLPAR 0x40 /* shared-processor LPAR supported */
+/* Option vector 5: PAPR/OF options supported
+ * Thses bits are also used for the platform_has_feature() call so
+ * we encode the vector index in the define and use the OV5_FEAT()
+ * and OV5_INDX() macros to extract the desired information.
+ */
+#define OV5_FEAT(x) ((x) & 0xff)
+#define OV5_INDX(x) ((x) >> 8)
+#define OV5_LPAR 0x0280 /* logical partitioning supported */
+#define OV5_SPLPAR 0x0240 /* shared-processor LPAR supported */
/* ibm,dynamic-reconfiguration-memory property supported */
-#define OV5_DRCONF_MEMORY 0x20
-#define OV5_LARGE_PAGES 0x10 /* large pages supported */
-#define OV5_DONATE_DEDICATE_CPU 0x02 /* donate dedicated CPU support */
-/* PCIe/MSI support. Without MSI full PCIe is not supported */
-#ifdef CONFIG_PCI_MSI
-#define OV5_MSI 0x01 /* PCIe/MSI support */
-#else
-#define OV5_MSI 0x00
-#endif /* CONFIG_PCI_MSI */
-#ifdef CONFIG_PPC_SMLPAR
-#define OV5_CMO 0x80 /* Cooperative Memory Overcommitment */
-#define OV5_XCMO 0x40 /* Page Coalescing */
-#else
-#define OV5_CMO 0x00
-#define OV5_XCMO 0x00
-#endif
-#define OV5_TYPE1_AFFINITY 0x80 /* Type 1 NUMA affinity */
-#define OV5_PFO_HW_RNG 0x80 /* PFO Random Number Generator */
-#define OV5_PFO_HW_842 0x40 /* PFO Compression Accelerator */
-#define OV5_PFO_HW_ENCR 0x20 /* PFO Encryption Accelerator */
-#define OV5_SUB_PROCESSORS 0x01 /* 1,2,or 4 Sub-Processors supported */
+#define OV5_DRCONF_MEMORY 0x0220
+#define OV5_LARGE_PAGES 0x0210 /* large pages supported */
+#define OV5_DONATE_DEDICATE_CPU 0x0202 /* donate dedicated CPU support */
+#define OV5_MSI 0x0201 /* PCIe/MSI support */
+#define OV5_CMO 0x0480 /* Cooperative Memory Overcommitment */
+#define OV5_XCMO 0x0440 /* Page Coalescing */
+#define OV5_TYPE1_AFFINITY 0x0580 /* Type 1 NUMA affinity */
+#define OV5_PFO_HW_RNG 0x0E80 /* PFO Random Number Generator */
+#define OV5_PFO_HW_842 0x0E40 /* PFO Compression Accelerator */
+#define OV5_PFO_HW_ENCR 0x0E20 /* PFO Encryption Accelerator */
+#define OV5_SUB_PROCESSORS 0x0F01 /* 1,2,or 4 Sub-Processors supported */
/* Option Vector 6: IBM PAPR hints */
#define OV6_LINUX 0x02 /* Linux is our OS */
@@ -145,6 +141,7 @@
* followed by # option vectors - 1, followed by the option vectors.
*/
extern unsigned char ibm_architecture_vec[];
+bool platform_has_feature(unsigned int);
#endif
/* These includes are put at the bottom because they may contain things
Index: powerpc/arch/powerpc/kernel/prom_init.c
===================================================================
--- powerpc.orig/arch/powerpc/kernel/prom_init.c 2013-03-25 10:47:54.000000000 -0500
+++ powerpc/arch/powerpc/kernel/prom_init.c 2013-03-25 11:07:56.000000000 -0500
@@ -684,11 +684,21 @@
/* option vector 5: PAPR/OF options */
19 - 2, /* length */
0, /* don't ignore, don't halt */
- OV5_LPAR | OV5_SPLPAR | OV5_LARGE_PAGES | OV5_DRCONF_MEMORY |
- OV5_DONATE_DEDICATE_CPU | OV5_MSI,
+ OV5_FEAT(OV5_LPAR) | OV5_FEAT(OV5_SPLPAR) | OV5_FEAT(OV5_LARGE_PAGES) |
+ OV5_FEAT(OV5_DRCONF_MEMORY) | OV5_FEAT(OV5_DONATE_DEDICATE_CPU) |
+#ifdef CONFIG_PCI_MSI
+ /* PCIe/MSI support. Without MSI full PCIe is not supported */
+ OV5_FEAT(OV5_MSI),
+#else
+ 0,
+#endif
+ 0,
+#ifdef CONFIG_PPC_SMLPAR
+ OV5_FEAT(OV5_CMO) | OV5_FEAT(OV5_XCMO),
+#else
0,
- OV5_CMO | OV5_XCMO,
- OV5_TYPE1_AFFINITY,
+#endif
+ OV5_FEAT(OV5_TYPE1_AFFINITY),
0,
0,
0,
@@ -702,8 +712,9 @@
0,
0,
0,
- OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR | OV5_PFO_HW_842,
- OV5_SUB_PROCESSORS,
+ OV5_FEAT(OV5_PFO_HW_RNG) | OV5_FEAT(OV5_PFO_HW_ENCR) |
+ OV5_FEAT(OV5_PFO_HW_842),
+ OV5_FEAT(OV5_SUB_PROCESSORS),
/* option vector 6: IBM PAPR hints */
4 - 2, /* length */
0,
Index: powerpc/arch/powerpc/platforms/pseries/setup.c
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/setup.c 2013-03-25 10:22:22.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/setup.c 2013-03-25 11:09:45.000000000 -0500
@@ -628,25 +628,39 @@
* Called very early, MMU is off, device-tree isn't unflattened
*/
-static int __init pSeries_probe_hypertas(unsigned long node,
- const char *uname, int depth,
- void *data)
+static int __init pseries_probe_fw_features(unsigned long node,
+ const char *uname, int depth,
+ void *data)
{
- const char *hypertas;
+ const char *prop;
unsigned long len;
+ static int hypertas_found;
+ static int vec5_found;
- if (depth != 1 ||
- (strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0))
+ if (depth != 1)
return 0;
- hypertas = of_get_flat_dt_prop(node, "ibm,hypertas-functions", &len);
- if (!hypertas)
- return 1;
+ if (!strcmp(uname, "rtas") || !strcmp(uname, "rtas@0")) {
+ prop = of_get_flat_dt_prop(node, "ibm,hypertas-functions",
+ &len);
+ if (prop) {
+ powerpc_firmware_features |= FW_FEATURE_LPAR;
+ fw_hypertas_feature_init(prop, len);
+ }
+
+ hypertas_found = 1;
+ }
+
+ if (!strcmp(uname, "chosen")) {
+ prop = of_get_flat_dt_prop(node, "ibm,architecture-vec-5",
+ &len);
+ if (prop)
+ fw_vec5_feature_init(prop, len);
- powerpc_firmware_features |= FW_FEATURE_LPAR;
- fw_feature_init(hypertas, len);
+ vec5_found = 1;
+ }
- return 1;
+ return hypertas_found && vec5_found;
}
static int __init pSeries_probe(void)
@@ -669,7 +683,7 @@
pr_debug("pSeries detected, looking for LPAR capability...\n");
/* Now try to figure out if we are running on LPAR */
- of_scan_flat_dt(pSeries_probe_hypertas, NULL);
+ of_scan_flat_dt(pseries_probe_fw_features, NULL);
if (firmware_has_feature(FW_FEATURE_LPAR))
hpte_init_lpar();
Index: powerpc/arch/powerpc/platforms/pseries/firmware.c
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/firmware.c 2013-03-25 10:22:22.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/firmware.c 2013-03-25 11:11:27.000000000 -0500
@@ -31,15 +31,15 @@
typedef struct {
unsigned long val;
char * name;
-} firmware_feature_t;
+} hypertas_fw_feature_t;
/*
* The names in this table match names in rtas/ibm,hypertas-functions. If the
* entry ends in a '*', only upto the '*' is matched. Otherwise the entire
* string must match.
*/
-static __initdata firmware_feature_t
-firmware_features_table[FIRMWARE_MAX_FEATURES] = {
+static __initdata hypertas_fw_feature_t
+hypertas_fw_features_table[FIRMWARE_MAX_FEATURES] = {
{FW_FEATURE_PFT, "hcall-pft"},
{FW_FEATURE_TCE, "hcall-tce"},
{FW_FEATURE_SPRG0, "hcall-sprg0"},
@@ -69,16 +69,16 @@
* device-tree/ibm,hypertas-functions. Ultimately this functionality may
* be moved into prom.c prom_init().
*/
-void __init fw_feature_init(const char *hypertas, unsigned long len)
+void __init fw_hypertas_feature_init(const char *hypertas, unsigned long len)
{
const char *s;
int i;
- pr_debug(" -> fw_feature_init()\n");
+ pr_debug(" -> fw_hypertas_feature_init()\n");
for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
for (i = 0; i < FIRMWARE_MAX_FEATURES; i++) {
- const char *name = firmware_features_table[i].name;
+ const char *name = hypertas_fw_features_table[i].name;
size_t size;
/* check value against table of strings */
if (!name)
@@ -96,10 +96,61 @@
/* we have a match */
powerpc_firmware_features |=
- firmware_features_table[i].val;
+ hypertas_fw_features_table[i].val;
break;
}
}
- pr_debug(" <- fw_feature_init()\n");
+ pr_debug(" <- fw_hypertas_feature_init()\n");
+}
+
+struct vec5_fw_feature {
+ unsigned long val;
+ unsigned int feature;
+
+};
+
+static __initdata struct vec5_fw_feature
+vec5_fw_features_table[FIRMWARE_MAX_FEATURES] = {
+ {FW_FEATURE_TYPE1_AFFINITY, OV5_TYPE1_AFFINITY},
+};
+
+void __init fw_vec5_feature_init(const char *vec5, unsigned long len)
+{
+ const char *s;
+ int index;
+ int i, j;
+
+ pr_debug(" -> fw_vec5_feature_init()\n");
+
+ /* vec5[0] is the length, no need to check */
+ for (s = &vec5[1], index = 1; s < vec5 + len; s++, index++) {
+ if (*s == 0)
+ continue;
+
+ /* Check each bit for a possible match */
+ for (i = 0; i < 8; i++) {
+ unsigned int feat = (index << 8) | (1 << i);
+
+ if ((*s & OV5_FEAT(feat)) == 0)
+ continue;
+
+ /* Look for a match */
+ for (j = 0; j < FIRMWARE_MAX_FEATURES; j++) {
+ if (vec5_fw_features_table[j].val == 0)
+ continue;
+
+ if (vec5_fw_features_table[j].feature != feat)
+ continue;
+
+ /* we have a match */
+ powerpc_firmware_features |=
+ vec5_fw_features_table[j].val;
+
+ break;
+ }
+ }
+ }
+
+ pr_debug(" <- fw_vec5_feature_init()\n");
}
Index: powerpc/arch/powerpc/include/asm/firmware.h
===================================================================
--- powerpc.orig/arch/powerpc/include/asm/firmware.h 2013-03-25 10:22:22.000000000 -0500
+++ powerpc/arch/powerpc/include/asm/firmware.h 2013-03-25 11:07:56.000000000 -0500
@@ -51,6 +51,7 @@
#define FW_FEATURE_OPALv2 ASM_CONST(0x0000000020000000)
#define FW_FEATURE_SET_MODE ASM_CONST(0x0000000040000000)
#define FW_FEATURE_BEST_ENERGY ASM_CONST(0x0000000080000000)
+#define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000)
#ifndef __ASSEMBLY__
@@ -65,7 +66,8 @@
FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO |
- FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY,
+ FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY |
+ FW_FEATURE_TYPE1_AFFINITY,
FW_FEATURE_PSERIES_ALWAYS = 0,
FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2,
FW_FEATURE_POWERNV_ALWAYS = 0,
Index: powerpc/arch/powerpc/platforms/pseries/pseries.h
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/pseries.h 2013-03-25 10:22:22.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/pseries.h 2013-03-25 11:07:56.000000000 -0500
@@ -19,7 +19,10 @@
#include <linux/of.h>
-extern void __init fw_feature_init(const char *hypertas, unsigned long len);
+extern void __init fw_hypertas_feature_init(const char *hypertas,
+ unsigned long len);
+extern void __init fw_vec5_feature_init(const char *hypertas,
+ unsigned long len);
struct pt_regs;
^ permalink raw reply
* [PATCH v2 5/11] Update numa.c to use updated firmware_has_feature()
From: Nathan Fontenot @ 2013-03-25 18:56 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
Update the numa code to use the updated firmware_has_feature() when checking
for type 1 affinity.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/mm/numa.c | 22 +++-------------------
1 file changed, 3 insertions(+), 19 deletions(-)
Index: powerpc/arch/powerpc/mm/numa.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/numa.c 2013-03-20 12:25:42.000000000 -0500
+++ powerpc/arch/powerpc/mm/numa.c 2013-03-20 12:26:29.000000000 -0500
@@ -291,9 +291,7 @@
static int __init find_min_common_depth(void)
{
int depth;
- struct device_node *chosen;
struct device_node *root;
- const char *vec5;
if (firmware_has_feature(FW_FEATURE_OPAL))
root = of_find_node_by_path("/ibm,opal");
@@ -325,24 +323,10 @@
distance_ref_points_depth /= sizeof(int);
-#define VEC5_AFFINITY_BYTE 5
-#define VEC5_AFFINITY 0x80
-
- if (firmware_has_feature(FW_FEATURE_OPAL))
+ if (firmware_has_feature(FW_FEATURE_OPAL) ||
+ firmware_has_feature(FW_FEATURE_TYPE1_AFFINITY)) {
+ dbg("Using form 1 affinity\n");
form1_affinity = 1;
- else {
- chosen = of_find_node_by_path("/chosen");
- if (chosen) {
- vec5 = of_get_property(chosen,
- "ibm,architecture-vec-5", NULL);
- if (vec5 && (vec5[VEC5_AFFINITY_BYTE] &
- VEC5_AFFINITY)) {
- dbg("Using form 1 affinity\n");
- form1_affinity = 1;
- }
-
- of_node_put(chosen);
- }
}
if (form1_affinity) {
^ permalink raw reply
* [PATCH v2 6/11] Update CPU Maps
From: Nathan Fontenot @ 2013-03-25 18:57 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
From: Jesse Larrew <jlarrew@linux.vnet.ibm.com>
Platform events such as partition migration or the new PRRN firmware
feature can cause the NUMA characteristics of a CPU to change, and these
changes will be reflected in the device tree nodes for the affected
CPUs.
This patch registers a handler for Open Firmware device tree updates
and reconfigures the CPU and node maps whenever the associativity
changes. Currently, this is accomplished by marking the affected CPUs in
the cpu_associativity_changes_mask and allowing
arch_update_cpu_topology() to retrieve the new associativity information
using hcall_vphn().
Protecting the NUMA cpu maps from concurrent access during an update
operation will be addressed in a subsequent patch in this series.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/firmware.h | 3
arch/powerpc/include/asm/prom.h | 1
arch/powerpc/mm/numa.c | 99 ++++++++++++++++++++++--------
arch/powerpc/platforms/pseries/firmware.c | 1
4 files changed, 79 insertions(+), 25 deletions(-)
Index: powerpc/arch/powerpc/include/asm/prom.h
===================================================================
--- powerpc.orig/arch/powerpc/include/asm/prom.h 2013-03-25 11:07:56.000000000 -0500
+++ powerpc/arch/powerpc/include/asm/prom.h 2013-03-25 11:27:11.000000000 -0500
@@ -128,6 +128,7 @@
#define OV5_CMO 0x0480 /* Cooperative Memory Overcommitment */
#define OV5_XCMO 0x0440 /* Page Coalescing */
#define OV5_TYPE1_AFFINITY 0x0580 /* Type 1 NUMA affinity */
+#define OV5_PRRN 0x0540 /* Platform Resource Reassignment */
#define OV5_PFO_HW_RNG 0x0E80 /* PFO Random Number Generator */
#define OV5_PFO_HW_842 0x0E40 /* PFO Compression Accelerator */
#define OV5_PFO_HW_ENCR 0x0E20 /* PFO Encryption Accelerator */
Index: powerpc/arch/powerpc/mm/numa.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/numa.c 2013-03-25 11:22:44.000000000 -0500
+++ powerpc/arch/powerpc/mm/numa.c 2013-03-25 11:27:11.000000000 -0500
@@ -1257,7 +1257,8 @@
static u8 vphn_cpu_change_counts[NR_CPUS][MAX_DISTANCE_REF_POINTS];
static cpumask_t cpu_associativity_changes_mask;
static int vphn_enabled;
-static void set_topology_timer(void);
+static int prrn_enabled;
+static void reset_topology_timer(void);
/*
* Store the current values of the associativity change counters in the
@@ -1293,11 +1294,9 @@
*/
static int update_cpu_associativity_changes_mask(void)
{
- int cpu, nr_cpus = 0;
+ int cpu;
cpumask_t *changes = &cpu_associativity_changes_mask;
- cpumask_clear(changes);
-
for_each_possible_cpu(cpu) {
int i, changed = 0;
u8 *counts = vphn_cpu_change_counts[cpu];
@@ -1311,11 +1310,10 @@
}
if (changed) {
cpumask_set_cpu(cpu, changes);
- nr_cpus++;
}
}
- return nr_cpus;
+ return cpumask_weight(changes);
}
/*
@@ -1416,7 +1414,7 @@
unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
struct device *dev;
- for_each_cpu(cpu,&cpu_associativity_changes_mask) {
+ for_each_cpu(cpu, &cpu_associativity_changes_mask) {
vphn_get_associativity(cpu, associativity);
nid = associativity_to_nid(associativity);
@@ -1438,6 +1436,7 @@
dev = get_cpu_device(cpu);
if (dev)
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
+ cpumask_clear_cpu(cpu, &cpu_associativity_changes_mask);
changed = 1;
}
@@ -1457,37 +1456,80 @@
static void topology_timer_fn(unsigned long ignored)
{
- if (!vphn_enabled)
- return;
- if (update_cpu_associativity_changes_mask() > 0)
+ if (prrn_enabled && cpumask_weight(&cpu_associativity_changes_mask))
topology_schedule_update();
- set_topology_timer();
+ else if (vphn_enabled) {
+ if (update_cpu_associativity_changes_mask() > 0)
+ topology_schedule_update();
+ reset_topology_timer();
+ }
}
static struct timer_list topology_timer =
TIMER_INITIALIZER(topology_timer_fn, 0, 0);
-static void set_topology_timer(void)
+static void reset_topology_timer(void)
{
topology_timer.data = 0;
topology_timer.expires = jiffies + 60 * HZ;
- add_timer(&topology_timer);
+ mod_timer(&topology_timer, topology_timer.expires);
+}
+
+static void stage_topology_update(int core_id)
+{
+ cpumask_or(&cpu_associativity_changes_mask,
+ &cpu_associativity_changes_mask, cpu_sibling_mask(core_id));
+ reset_topology_timer();
}
+static int dt_update_callback(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct of_prop_reconfig *update;
+ int rc = NOTIFY_DONE;
+
+ switch (action) {
+ case OF_RECONFIG_ADD_PROPERTY:
+ case OF_RECONFIG_UPDATE_PROPERTY:
+ update = (struct of_prop_reconfig *)data;
+ if (!of_prop_cmp(update->dn->type, "cpu")) {
+ u32 core_id;
+ of_property_read_u32(update->dn, "reg", &core_id);
+ stage_topology_update(core_id);
+ rc = NOTIFY_OK;
+ }
+ break;
+ }
+
+ return rc;
+}
+
+static struct notifier_block dt_update_nb = {
+ .notifier_call = dt_update_callback,
+};
+
/*
- * Start polling for VPHN associativity changes.
+ * Start polling for associativity changes.
*/
int start_topology_update(void)
{
int rc = 0;
- /* Disabled until races with load balancing are fixed */
- if (0 && firmware_has_feature(FW_FEATURE_VPHN) &&
- get_lppaca()->shared_proc) {
- vphn_enabled = 1;
- setup_cpu_associativity_change_counters();
- init_timer_deferrable(&topology_timer);
- set_topology_timer();
- rc = 1;
+ if (firmware_has_feature(OV5_PRRN)) {
+ if (!prrn_enabled) {
+ prrn_enabled = 1;
+ vphn_enabled = 0;
+ rc = of_reconfig_notifier_register(&dt_update_nb);
+ }
+ } else if (0 && firmware_has_feature(FW_FEATURE_VPHN) &&
+ get_lppaca()->shared_proc) {
+ /* Disabled until races with load balancing are fixed */
+ if (!vphn_enabled) {
+ prrn_enabled = 0;
+ vphn_enabled = 1;
+ setup_cpu_associativity_change_counters();
+ init_timer_deferrable(&topology_timer);
+ reset_topology_timer();
+ }
}
return rc;
@@ -1499,7 +1541,16 @@
*/
int stop_topology_update(void)
{
- vphn_enabled = 0;
- return del_timer_sync(&topology_timer);
+ int rc = 0;
+
+ if (prrn_enabled) {
+ prrn_enabled = 0;
+ rc = of_reconfig_notifier_unregister(&dt_update_nb);
+ } else if (vphn_enabled) {
+ vphn_enabled = 0;
+ rc = del_timer_sync(&topology_timer);
+ }
+
+ return rc;
}
#endif /* CONFIG_PPC_SPLPAR */
Index: powerpc/arch/powerpc/include/asm/firmware.h
===================================================================
--- powerpc.orig/arch/powerpc/include/asm/firmware.h 2013-03-25 11:07:56.000000000 -0500
+++ powerpc/arch/powerpc/include/asm/firmware.h 2013-03-25 11:27:11.000000000 -0500
@@ -52,6 +52,7 @@
#define FW_FEATURE_SET_MODE ASM_CONST(0x0000000040000000)
#define FW_FEATURE_BEST_ENERGY ASM_CONST(0x0000000080000000)
#define FW_FEATURE_TYPE1_AFFINITY ASM_CONST(0x0000000100000000)
+#define FW_FEATURE_PRRN ASM_CONST(0x0000000200000000)
#ifndef __ASSEMBLY__
@@ -67,7 +68,7 @@
FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO |
FW_FEATURE_SET_MODE | FW_FEATURE_BEST_ENERGY |
- FW_FEATURE_TYPE1_AFFINITY,
+ FW_FEATURE_TYPE1_AFFINITY | FW_FEATURE_PRRN,
FW_FEATURE_PSERIES_ALWAYS = 0,
FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2,
FW_FEATURE_POWERNV_ALWAYS = 0,
Index: powerpc/arch/powerpc/platforms/pseries/firmware.c
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/firmware.c 2013-03-25 11:11:27.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/firmware.c 2013-03-25 11:27:11.000000000 -0500
@@ -113,6 +113,7 @@
static __initdata struct vec5_fw_feature
vec5_fw_features_table[FIRMWARE_MAX_FEATURES] = {
{FW_FEATURE_TYPE1_AFFINITY, OV5_TYPE1_AFFINITY},
+ {FW_FEATURE_PRRN, OV5_PRRN},
};
void __init fw_vec5_feature_init(const char *vec5, unsigned long len)
^ permalink raw reply
* [PATCH v2 7/11] Use stop machine to update cpu maps
From: Nathan Fontenot @ 2013-03-25 18:58 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
From: Jesse Larrew <jlarrew@linux.vnet.ibm.com>
The new PRRN firmware feature allows CPU and memory resources to be
transparently reassigned across NUMA boundaries. When this happens, the
kernel must update the node maps to reflect the new affinity
information.
Although the NUMA maps can be protected by locking primitives during the
update itself, this is insufficient to prevent concurrent accesses to these
structures. Since cpumask_of_node() hands out a pointer to these
structures, they can still be modified outside of the lock. Furthermore,
tracking down each usage of these pointers and adding locks would be quite
invasive and difficult to maintain.
Situations like these are best handled using stop_machine(). Since the NUMA
affinity updates are exceptionally rare events, this approach has the
benefit of not adding any overhead while accessing the NUMA maps during
normal operation.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/mm/numa.c | 51 +++++++++++++++++++++++++++++++++----------------
1 file changed, 35 insertions(+), 16 deletions(-)
Index: powerpc/arch/powerpc/mm/numa.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/numa.c 2013-03-20 12:26:36.000000000 -0500
+++ powerpc/arch/powerpc/mm/numa.c 2013-03-20 12:27:43.000000000 -0500
@@ -22,6 +22,7 @@
#include <linux/pfn.h>
#include <linux/cpuset.h>
#include <linux/node.h>
+#include <linux/stop_machine.h>
#include <asm/sparsemem.h>
#include <asm/prom.h>
#include <asm/smp.h>
@@ -1254,6 +1255,12 @@
/* Virtual Processor Home Node (VPHN) support */
#ifdef CONFIG_PPC_SPLPAR
+struct topology_update_data {
+ int cpu;
+ int old_nid;
+ int new_nid;
+};
+
static u8 vphn_cpu_change_counts[NR_CPUS][MAX_DISTANCE_REF_POINTS];
static cpumask_t cpu_associativity_changes_mask;
static int vphn_enabled;
@@ -1405,34 +1412,46 @@
}
/*
+ * Update the CPU maps and sysfs entries for a single CPU when its NUMA
+ * characteristics change. This function doesn't perform any locking and is
+ * only safe to call from stop_machine().
+ */
+static int update_cpu_topology(void *data)
+{
+ struct topology_update_data *update = data;
+
+ if (!update)
+ return -EINVAL;
+
+ unregister_cpu_under_node(update->cpu, update->old_nid);
+ unmap_cpu_from_node(update->cpu);
+ map_cpu_to_node(update->cpu, update->new_nid);
+ register_cpu_under_node(update->cpu, update->new_nid);
+
+ return 0;
+}
+
+/*
* Update the node maps and sysfs entries for each cpu whose home node
* has changed. Returns 1 when the topology has changed, and 0 otherwise.
*/
int arch_update_cpu_topology(void)
{
- int cpu, nid, old_nid, changed = 0;
+ int cpu, changed = 0;
+ struct topology_update_data update;
unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
struct device *dev;
for_each_cpu(cpu, &cpu_associativity_changes_mask) {
+ update.cpu = cpu;
vphn_get_associativity(cpu, associativity);
- nid = associativity_to_nid(associativity);
-
- if (nid < 0 || !node_online(nid))
- nid = first_online_node;
+ update.new_nid = associativity_to_nid(associativity);
- old_nid = numa_cpu_lookup_table[cpu];
-
- /* Disable hotplug while we update the cpu
- * masks and sysfs.
- */
- get_online_cpus();
- unregister_cpu_under_node(cpu, old_nid);
- unmap_cpu_from_node(cpu);
- map_cpu_to_node(cpu, nid);
- register_cpu_under_node(cpu, nid);
- put_online_cpus();
+ if (update.new_nid < 0 || !node_online(update.new_nid))
+ update.new_nid = first_online_node;
+ update.old_nid = numa_cpu_lookup_table[cpu];
+ stop_machine(update_cpu_topology, &update, cpu_online_mask);
dev = get_cpu_device(cpu);
if (dev)
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
^ permalink raw reply
* [PATCH v2 8/11] Update numa cpu vdso info
From: Nathan Fontenot @ 2013-03-25 18:59 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
From: Jesse Larrew <jlarrew@linux.vnet.ibm.com>
The following patch adds vdso_getcpu_init(), which stores the NUMA node for
a cpu in SPRG3:
Commit 18ad51dd34 ("powerpc: Add VDSO version of getcpu") adds
vdso_getcpu_init(), which stores the NUMA node for a cpu in SPRG3.
This patch ensures that this information is also updated when the NUMA
affinity of a cpu changes.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/mm/numa.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
Index: powerpc/arch/powerpc/mm/numa.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/numa.c 2013-03-20 12:27:43.000000000 -0500
+++ powerpc/arch/powerpc/mm/numa.c 2013-03-20 12:27:46.000000000 -0500
@@ -30,6 +30,7 @@
#include <asm/paca.h>
#include <asm/hvcall.h>
#include <asm/setup.h>
+#include <asm/vdso.h>
static int numa_enabled = 1;
@@ -1426,6 +1427,7 @@
unregister_cpu_under_node(update->cpu, update->old_nid);
unmap_cpu_from_node(update->cpu);
map_cpu_to_node(update->cpu, update->new_nid);
+ vdso_getcpu_init();
register_cpu_under_node(update->cpu, update->new_nid);
return 0;
@@ -1440,8 +1442,11 @@
int cpu, changed = 0;
struct topology_update_data update;
unsigned int associativity[VPHN_ASSOC_BUFSIZE] = {0};
+ cpumask_t updated_cpu;
struct device *dev;
+ cpumask_clear(&updated_cpu);
+
for_each_cpu(cpu, &cpu_associativity_changes_mask) {
update.cpu = cpu;
vphn_get_associativity(cpu, associativity);
@@ -1451,7 +1456,8 @@
update.new_nid = first_online_node;
update.old_nid = numa_cpu_lookup_table[cpu];
- stop_machine(update_cpu_topology, &update, cpu_online_mask);
+ cpumask_set_cpu(cpu, &updated_cpu);
+ stop_machine(update_cpu_topology, &update, &updated_cpu);
dev = get_cpu_device(cpu);
if (dev)
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
^ permalink raw reply
* [PATCH v2 9/11] Re-enable Virtual Private Home Node capabilities
From: Nathan Fontenot @ 2013-03-25 19:00 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
From: Jesse Larrew <jlarrew@linux.vnet.ibm.com>
The new PRRN firmware feature provides a more convenient and event-driven
interface than VPHN for notifying Linux of changes to the NUMA affinity of
platform resources. However, for practical reasons, it may not be feasible
for some customers to update to the latest firmware. For these customers,
the VPHN feature supported on previous firmware versions may still be the
best option.
The VPHN feature was previously disabled due to races with the load
balancing code when accessing the NUMA cpu maps, but the new stop_machine()
approach protects the NUMA cpu maps from these concurrent accesses. It
should be safe to re-enable this feature now.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/mm/numa.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
Index: powerpc/arch/powerpc/mm/numa.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/numa.c 2013-03-20 12:27:46.000000000 -0500
+++ powerpc/arch/powerpc/mm/numa.c 2013-03-20 12:27:48.000000000 -0500
@@ -1545,9 +1545,8 @@
vphn_enabled = 0;
rc = of_reconfig_notifier_register(&dt_update_nb);
}
- } else if (0 && firmware_has_feature(FW_FEATURE_VPHN) &&
+ } else if (firmware_has_feature(FW_FEATURE_VPHN) &&
get_lppaca()->shared_proc) {
- /* Disabled until races with load balancing are fixed */
if (!vphn_enabled) {
prrn_enabled = 0;
vphn_enabled = 1;
^ permalink raw reply
* [PATCH v2 11/11] Add /proc interface to control topology updates
From: Nathan Fontenot @ 2013-03-25 19:02 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
There are instances in which we do not want topology updates to occur.
In order to allow this a /proc interface (/proc/powerpc/topology_updates)
is introduced so that topology updates can be enabled and disabled.
This patch also adds a prrn_is_enabled() call so that PRRN events are
handled in the kernel only if topology updating is enabled.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/include/asm/topology.h | 5 ++
arch/powerpc/kernel/rtasd.c | 6 ++-
arch/powerpc/mm/numa.c | 62 +++++++++++++++++++++++++++++++++++-
3 files changed, 70 insertions(+), 3 deletions(-)
Index: powerpc/arch/powerpc/mm/numa.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/numa.c 2013-03-20 12:27:48.000000000 -0500
+++ powerpc/arch/powerpc/mm/numa.c 2013-03-20 12:27:52.000000000 -0500
@@ -23,6 +23,9 @@
#include <linux/cpuset.h>
#include <linux/node.h>
#include <linux/stop_machine.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
#include <asm/sparsemem.h>
#include <asm/prom.h>
#include <asm/smp.h>
@@ -1558,7 +1561,6 @@
return rc;
}
-__initcall(start_topology_update);
/*
* Disable polling for VPHN associativity changes.
@@ -1577,4 +1579,62 @@
return rc;
}
+
+inline int prrn_is_enabled(void)
+{
+ return prrn_enabled;
+}
+
+static int topology_read(struct seq_file *file, void *v)
+{
+ if (vphn_enabled || prrn_enabled)
+ seq_puts(file, "on\n");
+ else
+ seq_puts(file, "off\n");
+
+ return 0;
+}
+
+static int topology_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, topology_read, NULL);
+}
+
+static ssize_t topology_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *off)
+{
+ char kbuf[4]; /* "on" or "off" plus null. */
+ int read_len;
+
+ read_len = count < 3 ? count : 3;
+ if (copy_from_user(kbuf, buf, read_len))
+ return -EINVAL;
+
+ kbuf[read_len] = '\0';
+
+ if (!strncmp(kbuf, "on", 2))
+ start_topology_update();
+ else if (!strncmp(kbuf, "off", 3))
+ stop_topology_update();
+ else
+ return -EINVAL;
+
+ return count;
+}
+
+static const struct file_operations topology_ops = {
+ .read = seq_read,
+ .write = topology_write,
+ .open = topology_open,
+ .release = single_release
+};
+
+static int topology_update_init(void)
+{
+ start_topology_update();
+ proc_create("powerpc/topology_updates", 644, NULL, &topology_ops);
+
+ return 0;
+}
+device_initcall(topology_update_init);
#endif /* CONFIG_PPC_SPLPAR */
Index: powerpc/arch/powerpc/include/asm/topology.h
===================================================================
--- powerpc.orig/arch/powerpc/include/asm/topology.h 2013-03-20 12:25:37.000000000 -0500
+++ powerpc/arch/powerpc/include/asm/topology.h 2013-03-20 12:27:52.000000000 -0500
@@ -71,6 +71,7 @@
#if defined(CONFIG_NUMA) && defined(CONFIG_PPC_SPLPAR)
extern int start_topology_update(void);
extern int stop_topology_update(void);
+extern inline int prrn_is_enabled(void);
#else
static inline int start_topology_update(void)
{
@@ -80,6 +81,10 @@
{
return 0;
}
+static inline int prrn_is_enabled(void)
+{
+ return 0;
+}
#endif /* CONFIG_NUMA && CONFIG_PPC_SPLPAR */
#include <asm-generic/topology.h>
Index: powerpc/arch/powerpc/kernel/rtasd.c
===================================================================
--- powerpc.orig/arch/powerpc/kernel/rtasd.c 2013-03-20 12:25:37.000000000 -0500
+++ powerpc/arch/powerpc/kernel/rtasd.c 2013-03-20 12:27:52.000000000 -0500
@@ -292,11 +292,13 @@
{
pSeries_log_error((char *)log, ERR_TYPE_RTAS_LOG, 0);
- if (log->type == RTAS_TYPE_PRRN)
+ if (log->type == RTAS_TYPE_PRRN) {
/* For PRRN Events the extended log length is used to denote
* the scope for calling rtas update-nodes.
*/
- prrn_schedule_update(log->extended_log_length);
+ if (prrn_is_enabled())
+ prrn_schedule_update(log->extended_log_length);
+ }
return;
}
^ permalink raw reply
* [PATCH v2 10/11] Enable PRRN
From: Nathan Fontenot @ 2013-03-25 19:01 UTC (permalink / raw)
To: linuxppc-dev
In-Reply-To: <51509AE8.8070803@linux.vnet.ibm.com>
The Linux kernel and platform firmware negotiate their mutual support
of the PRRN option via the ibm,client-architecture-support interface.
This patch simply sets the appropriate fields in the client architecture
vector to indicate Linux support and will cause the firmware to begin
sending PRRN events via the RTAS event-scan mechanism.
Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
arch/powerpc/kernel/prom_init.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Index: powerpc/arch/powerpc/kernel/prom_init.c
===================================================================
--- powerpc.orig/arch/powerpc/kernel/prom_init.c 2013-03-20 12:25:38.000000000 -0500
+++ powerpc/arch/powerpc/kernel/prom_init.c 2013-03-20 12:27:50.000000000 -0500
@@ -698,7 +698,7 @@
#else
0,
#endif
- OV5_FEAT(OV5_TYPE1_AFFINITY),
+ OV5_FEAT(OV5_TYPE1_AFFINITY) | OV5_FEAT(OV5_PRRN),
0,
0,
0,
^ permalink raw reply
* repository location (MPC5200b)
From: Maxwell MacLean @ 2013-03-25 20:27 UTC (permalink / raw)
To: linuxppc-dev@lists.ozlabs.org
[-- Attachment #1: Type: text/plain, Size: 686 bytes --]
Hello all,
I have been following this list for a while now and am interested in getting a version of the latest work in progress Linux kernel with fixes for powerpc.
Yes, I am a kernel newbie, but I am learning! I have an inherited project based on version 2.6.28 that is compiled for an MPC5200b and there are some issues I am interested in fixing (or seeing If they are already fixed) .
I know there are many branches of development, but where can I get the 'best' kernel for my processor?
Thank you in advance.
Max
__________________________________
Maxwell MacLean | Senior Firmware Engineer
978.284.2872 | mmaclean@symbotic.com<mailto:mmaclean@symbotic.com>
[-- Attachment #2: Type: text/html, Size: 4388 bytes --]
^ permalink raw reply
* Re: repository location (MPC5200b)
From: Anatolij Gustschin @ 2013-03-25 22:55 UTC (permalink / raw)
To: Maxwell MacLean; +Cc: linuxppc-dev@lists.ozlabs.org
In-Reply-To: <97D2107B9206854998F088796329C879198B644F@AUSP01DAG0203>
Hello,
On Mon, 25 Mar 2013 20:27:17 +0000
Maxwell MacLean <mmaclean@symbotic.com> wrote:
> Hello all,
> I have been following this list for a while now and am interested
> in getting a version of the latest work in progress Linux kernel
> with fixes for powerpc.
For latest work in progress kernel look at master branch in linux-next
tree
http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git
> Yes, I am a kernel newbie, but I am learning! I have an inherited
> project based on version 2.6.28 that is compiled for an MPC5200b
> and there are some issues I am interested in fixing (or seeing If
> they are already fixed) .
>
> I know there are many branches of development, but where can I get
> the 'best' kernel for my processor?
The current mainline kernel supports MPC5200b pretty well, you can
use latest stable release, branch "linux-3.8.y" of the stable tree
http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git
HTH,
Anatolij
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de
^ permalink raw reply
* [git pull] Please pull some powerpc build fixes
From: Stephen Rothwell @ 2013-03-26 2:11 UTC (permalink / raw)
To: Linus; +Cc: Michael Neuling, Chen Gang, LKML, Stuart Yoder, ppc-dev
[-- Attachment #1: Type: text/plain, Size: 1211 bytes --]
The following changes since commit 3912a677f68f6084e0a7b6a1a29310ac1b083713:
Merge tag 'pinctrl-fixes-for-v3.9' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl (2013-03-24 10:11:29 -0700)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/sfr/next-fixes.git tags/for-linus
for you to fetch changes up to f9294e989fa6f2990da155242db03cea1550cac8:
powerpc: define the conditions where the ePAPR idle hcall can be supported (2013-03-26 08:47:27 +1100)
----------------------------------------------------------------
Just a couple of build fixes for powerpc all{mod,yes}config.
Submitted by me since BenH is on vacation.
----------------------------------------------------------------
Chen Gang (1):
powerpc: make additional room in exception vector area
Stuart Yoder (1):
powerpc: define the conditions where the ePAPR idle hcall can be supported
arch/powerpc/kernel/epapr_paravirt.c | 6 ++
arch/powerpc/kernel/exceptions-64s.S | 144 +++++++++++++++++------------------
2 files changed, 78 insertions(+), 72 deletions(-)
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* [PATCH 1/3] powerpc/mpc85xx: Update the clock device tree nodes
From: Yuantian.Tang @ 2013-03-26 2:36 UTC (permalink / raw)
To: rjw; +Cc: Tang Yuantian, linuxppc-dev, cpufreq, linux-pm
From: Tang Yuantian <yuantian.tang@freescale.com>
The following SOCs will be affected: p2041, p3041, p4080,
p5020, p5040
Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
arch/powerpc/boot/dts/fsl/p2041si-post.dtsi | 62 ++++++++++++++++-
arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi | 4 ++
arch/powerpc/boot/dts/fsl/p3041si-post.dtsi | 62 ++++++++++++++++-
arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi | 4 ++
arch/powerpc/boot/dts/fsl/p4080si-post.dtsi | 100 +++++++++++++++++++++++++++-
arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi | 8 +++
arch/powerpc/boot/dts/fsl/p5020si-post.dtsi | 42 +++++++++++-
arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi | 2 +
arch/powerpc/boot/dts/fsl/p5040si-post.dtsi | 54 ++++++++++++++-
arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi | 4 ++
10 files changed, 337 insertions(+), 5 deletions(-)
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
index 69ac1ac..d83de62 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi
@@ -305,9 +305,69 @@
};
clockgen: global-utilities@e1000 {
- compatible = "fsl,p2041-clockgen", "fsl,qoriq-clockgen-1.0";
+ compatible = "fsl,p2041-clockgen", "fsl,qoriq-clockgen-1.0",
+ "fixed-clock";
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ clock-output-names = "sysclk";
+ #clock-cells = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux0";
+ };
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux1";
+ };
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux2";
+ };
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
index 7a2697d..22f3b14 100644
--- a/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
index 9b5a81a..25b19cc 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi
@@ -332,9 +332,69 @@
};
clockgen: global-utilities@e1000 {
- compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0";
+ compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0",
+ "fixed-clock";
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ clock-output-names = "sysclk";
+ #clock-cells = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pll0: pll1@800 {
+ #clock-cells = <1>;
+ reg = <0x800>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux0";
+ };
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux1";
+ };
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux2";
+ };
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
index c9ca2c3..468e8be 100644
--- a/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
@@ -82,6 +82,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -90,6 +91,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -98,6 +100,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -106,6 +109,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
index 19859ad..3596f05 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
@@ -352,9 +352,107 @@
};
clockgen: global-utilities@e1000 {
- compatible = "fsl,p4080-clockgen", "fsl,qoriq-clockgen-1.0";
+ compatible = "fsl,p4080-clockgen", "fsl,qoriq-clockgen-1.0",
+ "fixed-clock";
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ clock-output-names = "sysclk";
+ #clock-cells = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+ pll2: pll2@840 {
+ #clock-cells = <1>;
+ reg = <0x840>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll2", "pll2-div2";
+ };
+ pll3: pll2@860 {
+ #clock-cells = <1>;
+ reg = <0x860>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll3", "pll3-div2";
+ };
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux0";
+ };
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux1";
+ };
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux2";
+ };
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux3";
+ };
+ mux4: mux4@80 {
+ #clock-cells = <0>;
+ reg = <0x80>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+ clock-output-names = "cmux4";
+ };
+ mux5: mux5@a0 {
+ #clock-cells = <0>;
+ reg = <0xa0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+ clock-output-names = "cmux5";
+ };
+ mux6: mux6@c0 {
+ #clock-cells = <0>;
+ reg = <0xc0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+ clock-output-names = "cmux6";
+ };
+ mux7: mux7@e0 {
+ #clock-cells = <0>;
+ reg = <0xe0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll2 0>, <&pll2 1>, <&pll3 0>, <&pll3 1>;
+ clock-names = "pll2_0", "pll2_1", "pll3_0", "pll3_1";
+ clock-output-names = "cmux7";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
index 493d9a0..0040b5a 100644
--- a/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e500mc@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e500mc@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e500mc@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e500mc@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
@@ -113,6 +117,7 @@
cpu4: PowerPC,e500mc@4 {
device_type = "cpu";
reg = <4>;
+ clocks = <&mux4>;
next-level-cache = <&L2_4>;
L2_4: l2-cache {
next-level-cache = <&cpc>;
@@ -121,6 +126,7 @@
cpu5: PowerPC,e500mc@5 {
device_type = "cpu";
reg = <5>;
+ clocks = <&mux5>;
next-level-cache = <&L2_5>;
L2_5: l2-cache {
next-level-cache = <&cpc>;
@@ -129,6 +135,7 @@
cpu6: PowerPC,e500mc@6 {
device_type = "cpu";
reg = <6>;
+ clocks = <&mux6>;
next-level-cache = <&L2_6>;
L2_6: l2-cache {
next-level-cache = <&cpc>;
@@ -137,6 +144,7 @@
cpu7: PowerPC,e500mc@7 {
device_type = "cpu";
reg = <7>;
+ clocks = <&mux7>;
next-level-cache = <&L2_7>;
L2_7: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
index 9ea77c3..3c662bd 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi
@@ -337,9 +337,49 @@
};
clockgen: global-utilities@e1000 {
- compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
+ compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0",
+ "fixed-clock";
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ clock-output-names = "sysclk";
+ #clock-cells = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll0", "pll0-div2", "pll0-div4";
+ };
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll1", "pll1-div2", "pll1-div4";
+ };
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux0";
+ };
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll0 2>,
+ <&pll1 0>, <&pll1 1>, <&pll1 2>;
+ clock-names = "pll0_0", "pll0_1", "pll0_2",
+ "pll1_0", "pll1_1", "pll1_2";
+ clock-output-names = "cmux1";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
index 8df47fc..fe1a2e6 100644
--- a/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
@@ -88,6 +88,7 @@
cpu0: PowerPC,e5500@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -96,6 +97,7 @@
cpu1: PowerPC,e5500@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
index 97f8c26..3870b22 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
@@ -297,9 +297,61 @@
};
clockgen: global-utilities@e1000 {
- compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0";
+ compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0",
+ "fixed-clock";
reg = <0xe1000 0x1000>;
clock-frequency = <0>;
+ clock-output-names = "sysclk";
+ #clock-cells = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pll0: pll0@800 {
+ #clock-cells = <1>;
+ reg = <0x800>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll0", "pll0-div2";
+ };
+ pll1: pll1@820 {
+ #clock-cells = <1>;
+ reg = <0x820>;
+ compatible = "fsl,core-pll-clock";
+ clocks = <&clockgen>;
+ clock-output-names = "pll1", "pll1-div2";
+ };
+ mux0: mux0@0 {
+ #clock-cells = <0>;
+ reg = <0x0>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux0";
+ };
+ mux1: mux1@20 {
+ #clock-cells = <0>;
+ reg = <0x20>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux1";
+ };
+ mux2: mux2@40 {
+ #clock-cells = <0>;
+ reg = <0x40>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux2";
+ };
+ mux3: mux3@60 {
+ #clock-cells = <0>;
+ reg = <0x60>;
+ compatible = "fsl,core-mux-clock";
+ clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+ clock-names = "pll0_0", "pll0_1", "pll1_0", "pll1_1";
+ clock-output-names = "cmux3";
+ };
};
rcpm: global-utilities@e2000 {
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
index 40ca943..3674686 100644
--- a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
+++ b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
@@ -81,6 +81,7 @@
cpu0: PowerPC,e5500@0 {
device_type = "cpu";
reg = <0>;
+ clocks = <&mux0>;
next-level-cache = <&L2_0>;
L2_0: l2-cache {
next-level-cache = <&cpc>;
@@ -89,6 +90,7 @@
cpu1: PowerPC,e5500@1 {
device_type = "cpu";
reg = <1>;
+ clocks = <&mux1>;
next-level-cache = <&L2_1>;
L2_1: l2-cache {
next-level-cache = <&cpc>;
@@ -97,6 +99,7 @@
cpu2: PowerPC,e5500@2 {
device_type = "cpu";
reg = <2>;
+ clocks = <&mux2>;
next-level-cache = <&L2_2>;
L2_2: l2-cache {
next-level-cache = <&cpc>;
@@ -105,6 +108,7 @@
cpu3: PowerPC,e5500@3 {
device_type = "cpu";
reg = <3>;
+ clocks = <&mux3>;
next-level-cache = <&L2_3>;
L2_3: l2-cache {
next-level-cache = <&cpc>;
--
1.8.0
^ permalink raw reply related
* [PATCH 2/3] clk: add PowerPC corenet clock driver support
From: Yuantian.Tang @ 2013-03-26 2:36 UTC (permalink / raw)
To: rjw; +Cc: Tang Yuantian, linuxppc-dev, cpufreq, linux-pm
In-Reply-To: <1364265391-26077-1-git-send-email-Yuantian.Tang@freescale.com>
From: Tang Yuantian <yuantian.tang@freescale.com>
This adds the clock driver for Freescale PowerPC corenet
series SOC using common clock infrastructure.
Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
arch/powerpc/platforms/Kconfig.cputype | 1 +
drivers/clk/Kconfig | 7 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-ppc-corenet.c | 285 +++++++++++++++++++++++++++++++++
4 files changed, 294 insertions(+)
create mode 100644 drivers/clk/clk-ppc-corenet.c
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 18e3b76..cf065b8 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -158,6 +158,7 @@ config E500
config PPC_E500MC
bool "e500mc Support"
select PPC_FPU
+ select COMMON_CLK
depends on E500
help
This must be enabled for running on e500mc (and derivatives
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index a47e6ee..97ec76f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -63,6 +63,13 @@ config CLK_TWL6040
McPDM. McPDM module is using the external bit clock on the McPDM bus
as functional clock.
+config CLK_PPC_CORENET
+ bool "Clock driver for PowerPC corenet platforms"
+ depends on PPC_E500MC
+ ---help---
+ This adds the clock driver support for Freescale PowerPC corenet
+ platforms using common clock framework.
+
endmenu
source "drivers/clk/mvebu/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 300d477..6720319 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_X86) += x86/
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
+obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c
new file mode 100644
index 0000000..6811e03
--- /dev/null
+++ b/drivers/clk/clk-ppc-corenet.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * clock driver for Freescale PowerPC corenet SoCs.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk-provider.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct cmux_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u32 flags;
+};
+
+#define PLL_KILL BIT(31)
+#define CLKSEL_SHIFT 27
+#define CLKSEL_ADJUST BIT(0)
+
+#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
+
+static void __iomem *base;
+static unsigned int clocks_per_pll;
+
+static int cmux_set_parent(struct clk_hw *hw, u8 idx)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel += 8;
+ clksel = (clksel & 0xf) << CLKSEL_SHIFT;
+ iowrite32be(clksel, clk->reg);
+
+ return 0;
+}
+
+static u8 cmux_get_parent(struct clk_hw *hw)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ioread32be(clk->reg);
+ clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel -= 8;
+ clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
+
+ return clksel;
+}
+
+const struct clk_ops cmux_ops = {
+ .get_parent = cmux_get_parent,
+ .set_parent = cmux_set_parent,
+};
+
+static void __init core_mux_init(struct device_node *np)
+{
+ struct clk *clk;
+ struct clk_init_data init;
+ struct cmux_clk *cmux_clk;
+ struct device_node *node;
+ int rc, count, i;
+ u32 offset;
+ const char *clk_name;
+ const char **parent_names;
+
+ rc = of_property_read_u32(np, "reg", &offset);
+ if (rc) {
+ pr_err("%s: could not get reg property\n", np->name);
+ return;
+ }
+
+ /* get the input clock source count */
+ count = of_property_count_strings(np, "clock-names");
+ if (count < 0) {
+ pr_err("%s: get clock count error\n", np->name);
+ return;
+ }
+ parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
+ if (!parent_names) {
+ pr_err("%s: could not allocate parent_names\n", __func__);
+ return;
+ }
+
+ for (i = 0; i < count; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
+ if (!cmux_clk) {
+ pr_err("%s: could not allocate cmux_clk\n", __func__);
+ goto err_name;
+ }
+ cmux_clk->reg = base + offset;
+
+ node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
+ if (node && (offset >= 0x80))
+ cmux_clk->flags = CLKSEL_ADJUST;
+
+ rc = of_property_read_string_index(np, "clock-output-names",
+ 0, &clk_name);
+ if (rc) {
+ pr_err("%s: read clock names error\n", np->name);
+ goto err_clk;
+ }
+
+ init.name = clk_name;
+ init.ops = &cmux_ops;
+ init.parent_names = parent_names;
+ init.num_parents = count;
+ init.flags = 0;
+ cmux_clk->hw.init = &init;
+
+ clk = clk_register(NULL, &cmux_clk->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_clk;
+ }
+
+ rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (rc) {
+ pr_err("Could not register clock provider for node:%s\n",
+ np->name);
+ goto err_clk;
+ }
+ goto err_name;
+
+err_clk:
+ kfree(cmux_clk);
+err_name:
+ /* free *_names because they are reallocated when registered */
+ kfree(parent_names);
+}
+
+static void __init core_pll_init(struct device_node *np)
+{
+ u32 offset, mult;
+ int i, rc, count;
+ const char *clk_name, *parent_name;
+ struct clk_onecell_data *onecell_data;
+ struct clk **subclks;
+
+ rc = of_property_read_u32(np, "reg", &offset);
+ if (rc) {
+ pr_err("%s: could not get reg property\n", np->name);
+ return;
+ }
+
+ /* get the multiple of PLL */
+ mult = ioread32be(base + offset);
+
+ /* check if this PLL is disabled */
+ if (mult & PLL_KILL) {
+ pr_debug("PLL:%s is disabled\n", np->name);
+ return;
+ }
+ mult = (mult >> 1) & 0x3f;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name) {
+ pr_err("PLL: %s must have a parent\n", np->name);
+ return;
+ }
+
+ count = of_property_count_strings(np, "clock-output-names");
+ if (count < 0 || count > 4) {
+ pr_err("%s: clock is not supported\n", np->name);
+ return;
+ }
+
+ /* output clock number per PLL */
+ clocks_per_pll = count;
+
+ subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
+ if (!subclks) {
+ pr_err("%s: could not allocate subclks\n", __func__);
+ return;
+ }
+
+ onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
+ if (!onecell_data) {
+ pr_err("%s: could not allocate onecell_data\n", __func__);
+ goto err_clks;
+ }
+
+ for (i = 0; i < count; i++) {
+ rc = of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+ if (rc) {
+ pr_err("%s: could not get clock names\n", np->name);
+ goto err_cell;
+ }
+
+ /*
+ * when count == 4, there are 4 output clocks:
+ * /1, /2, /3, /4 respectively
+ * when count < 4, there are at least 2 output clocks:
+ * /1, /2, (/4, if count == 3) respectively.
+ */
+ if (count == 4)
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 + i);
+ else
+
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 << i);
+
+ if (IS_ERR(subclks[i])) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_cell;
+ }
+ }
+
+ onecell_data->clks = subclks;
+ onecell_data->clk_num = count;
+
+ rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
+ if (rc) {
+ pr_err("Could not register clk provider for node:%s\n",
+ np->name);
+ goto err_cell;
+ }
+
+ return;
+err_cell:
+ kfree(onecell_data);
+err_clks:
+ kfree(subclks);
+}
+
+static const struct of_device_id clk_match[] __initconst = {
+ { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
+ { .compatible = "fsl,core-pll-clock", .data = core_pll_init, },
+ { .compatible = "fsl,core-mux-clock", .data = core_mux_init, },
+ {}
+};
+
+static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+
+ np = pdev->dev.of_node;
+ base = of_iomap(np, 0);
+ if (!base) {
+ dev_err(&pdev->dev, "iomap error\n");
+ return -ENOMEM;
+ }
+ of_clk_init(clk_match);
+
+ return 0;
+}
+
+static const struct of_device_id ppc_clk_ids[] __initconst = {
+ { .compatible = "fsl,qoriq-clockgen-1.0", },
+ { .compatible = "fsl,qoriq-clockgen-2", },
+ {}
+};
+
+static struct platform_driver ppc_corenet_clk_driver = {
+ .driver = {
+ .name = "ppc_corenet_clock",
+ .owner = THIS_MODULE,
+ .of_match_table = ppc_clk_ids,
+ },
+ .probe = ppc_corenet_clk_probe,
+};
+
+static int __init ppc_corenet_clk_init(void)
+{
+ return platform_driver_register(&ppc_corenet_clk_driver);
+}
+subsys_initcall(ppc_corenet_clk_init);
+
+MODULE_AUTHOR("Tang Yuantian: <Yuantian.Tang@freescale.com>");
+MODULE_DESCRIPTION("Clock Driver for Freescale PowerPC Corenet Platform");
+MODULE_LICENSE("GPL V2");
--
1.8.0
^ permalink raw reply related
* [PATCH 3/3] cpufreq: Add cpufreq driver for Freescale e500mc SOCs
From: Yuantian.Tang @ 2013-03-26 2:36 UTC (permalink / raw)
To: rjw; +Cc: Tang Yuantian, linuxppc-dev, cpufreq, linux-pm
In-Reply-To: <1364265391-26077-1-git-send-email-Yuantian.Tang@freescale.com>
From: Tang Yuantian <yuantian.tang@freescale.com>
Add cpufreq driver for Freescale e500mc, e5500 and e6500 SOCs
which are capable of changing the frequency of CPU dynamically
Signed-off-by: Tang Yuantian <Yuantian.Tang@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
drivers/cpufreq/Kconfig.powerpc | 10 ++
drivers/cpufreq/Makefile | 1 +
drivers/cpufreq/ppc-corenet-cpufreq.c | 237 ++++++++++++++++++++++++++++++++++
3 files changed, 248 insertions(+)
create mode 100644 drivers/cpufreq/ppc-corenet-cpufreq.c
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index e76992f..6339db4 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -5,3 +5,13 @@ config CPU_FREQ_MAPLE
help
This adds support for frequency switching on Maple 970FX
Evaluation Board and compatible boards (IBM JS2x blades).
+
+config PPC_CORENET_CPUFREQ
+ tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
+ depends on PPC_E500MC
+ select CPU_FREQ_TABLE
+ select CLK_PPC_CORENET
+ help
+ This adds the CPUFreq driver support for Freescale e500mc,
+ e5500 and e6500 series SoCs which are capable of changing
+ the CPU's frequency dynamically.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 863fd18..2416559 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -61,3 +61,4 @@ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
##################################################################################
# PowerPC platform drivers
obj-$(CONFIG_CPU_FREQ_MAPLE) += maple-cpufreq.o
+obj-$(CONFIG_PPC_CORENET_CPUFREQ) += ppc-corenet-cpufreq.o
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
new file mode 100644
index 0000000..ad359d4
--- /dev/null
+++ b/drivers/cpufreq/ppc-corenet-cpufreq.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * CPU Frequency Scaling driver for Freescale PowerPC corenet SoCs.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/cpu.h>
+
+/**
+ * struct cpufreq_data - cpufreq driver data
+ * @cpus_per_cluster: CPU numbers per cluster
+ * @cpufreq_lock: the mutex lock
+ */
+struct cpufreq_data {
+ int cpus_per_cluster;
+ struct mutex cpufreq_lock;
+};
+
+/**
+ * struct cpu_data - per CPU data struct
+ * @np: the node of CPU
+ * @parent: the parent node of np
+ * @table: frequency table point
+ */
+struct cpu_data {
+ struct device_node *np;
+ struct device_node *parent;
+ struct cpufreq_frequency_table *table;
+};
+
+static DEFINE_PER_CPU(struct cpu_data, cpu_data);
+static struct cpufreq_data freq_data;
+
+static unsigned int corenet_cpufreq_get_speed(unsigned int cpu)
+{
+ struct clk *clk;
+ struct cpu_data *data = &per_cpu(cpu_data, cpu);
+
+ clk = of_clk_get(data->np, 0);
+
+ return clk_get_rate(clk) / 1000;
+}
+
+/* reduce the duplicated frequency in frequency table */
+static int freq_table_redup(struct cpufreq_frequency_table *freq_table,
+ int cur)
+{
+ int i;
+
+ for (i = 0; i < cur; i++) {
+ if (freq_table[i].frequency == CPUFREQ_ENTRY_INVALID ||
+ freq_table[i].frequency != freq_table[cur].frequency)
+ continue;
+
+ freq_table[cur].index = -1;
+ freq_table[cur].frequency = CPUFREQ_ENTRY_INVALID;
+ break;
+ }
+
+ return (i == cur) ? 0 : 1;
+}
+
+static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ unsigned int cpu = policy->cpu;
+ int i, count;
+ struct clk *clk;
+ struct cpufreq_frequency_table *table;
+ struct cpu_data *data;
+
+ data = &per_cpu(cpu_data, cpu);
+ data->np = of_get_cpu_node(cpu, NULL);
+ if (!data->np)
+ return -ENODEV;
+
+ data->parent = of_parse_phandle(data->np, "clocks", 0);
+ if (!data->parent)
+ return -ENODEV;
+
+ count = of_property_count_strings(data->parent, "clock-names");
+
+ table = kcalloc(count + 1,
+ sizeof(struct cpufreq_frequency_table), GFP_KERNEL);
+ if (!table)
+ return -ENOMEM;
+
+ for (i = cpu; i < freq_data.cpus_per_cluster + cpu; i++)
+ cpumask_set_cpu(i, policy->cpus);
+
+ for (i = 0; i < count; i++) {
+ table[i].index = i;
+ clk = of_clk_get(data->parent, i);
+ table[i].frequency = clk_get_rate(clk) / 1000;
+ freq_table_redup(table, i);
+ }
+ table[i].index = -1;
+ table[i].frequency = CPUFREQ_TABLE_END;
+
+ data->table = table;
+ cpufreq_frequency_table_get_attr(table, cpu);
+
+ /* FIXME: what's the actual transition time? in ns */
+ policy->cpuinfo.transition_latency = 2000;
+
+ policy->cur = corenet_cpufreq_get_speed(policy->cpu);
+
+ /* set the min and max frequency properly */
+ return cpufreq_frequency_table_cpuinfo(policy, table);
+}
+
+static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
+{
+ cpufreq_frequency_table_put_attr(policy->cpu);
+
+ return 0;
+}
+
+static int corenet_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ struct cpufreq_frequency_table *table;
+
+ table = (&per_cpu(cpu_data, policy->cpu))->table;
+ if (!table)
+ return -EINVAL;
+
+ return cpufreq_frequency_table_verify(policy, table);
+}
+
+static int corenet_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq, unsigned int relation)
+{
+ struct cpufreq_freqs freqs;
+ unsigned int new;
+ struct clk *clk, *parent;
+ int ret;
+ struct cpu_data *data = &per_cpu(cpu_data, policy->cpu);
+
+ cpufreq_frequency_table_target(policy, data->table,
+ target_freq, relation, &new);
+
+ if (policy->cur == data->table[new].frequency)
+ return 0;
+
+ freqs.old = policy->cur;
+ freqs.new = data->table[new].frequency;
+ freqs.cpu = policy->cpu;
+
+ mutex_lock(&freq_data.cpufreq_lock);
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ clk = of_clk_get(data->np, 0);
+ parent = of_clk_get(data->parent, new);
+ ret = clk_set_parent(clk, parent);
+ if (ret) {
+ mutex_unlock(&freq_data.cpufreq_lock);
+ return ret;
+ }
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ mutex_unlock(&freq_data.cpufreq_lock);
+
+ return 0;
+}
+
+static struct freq_attr *corenet_cpu_clks_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
+ .name = "ppc_cpufreq",
+ .owner = THIS_MODULE,
+ .flags = CPUFREQ_CONST_LOOPS,
+ .init = corenet_cpufreq_cpu_init,
+ .exit = __exit_p(corenet_cpufreq_cpu_exit),
+ .verify = corenet_cpufreq_verify,
+ .target = corenet_cpufreq_target,
+ .get = corenet_cpufreq_get_speed,
+ .attr = corenet_cpu_clks_attr,
+};
+
+static const struct of_device_id node_matches[] __initconst = {
+ { .compatible = "fsl,qoriq-clockgen-1.0", .data = (void *)1, },
+ { .compatible = "fsl,qoriq-clockgen-2", .data = (void *)8, },
+ {}
+};
+
+static int __init ppc_corenet_cpufreq_init(void)
+{
+ int ret = 0;
+ struct device_node *np;
+ const struct of_device_id *match;
+
+ np = of_find_matching_node(NULL, node_matches);
+ if (!np)
+ return -ENODEV;
+
+ match = of_match_node(node_matches, np);
+ freq_data.cpus_per_cluster = (long)match->data;
+ mutex_init(&freq_data.cpufreq_lock);
+ of_node_put(np);
+
+ ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver);
+ if (ret)
+ return ret;
+
+ pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n");
+
+ return ret;
+}
+
+static void __exit ppc_corenet_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
+}
+
+module_init(ppc_corenet_cpufreq_init);
+module_exit(ppc_corenet_cpufreq_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
+MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SOCs");
--
1.8.0
^ permalink raw reply related
* RE: [PATCH 3/3] powerpc/fsl: add MPIC timer wakeup support
From: Wang Dongsheng-B40534 @ 2013-03-26 3:27 UTC (permalink / raw)
To: Wood Scott-B07421
Cc: Gala Kumar-B11780, linuxppc-dev@lists.ozlabs.org, Li Yang-R58472,
Zhao Chenhui-B35336
In-Reply-To: <1363990268.24790.11@snotra>
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Saturday, March 23, 2013 6:11 AM
> To: Wang Dongsheng-B40534
> Cc: Wood Scott-B07421; Gala Kumar-B11780; linuxppc-dev@lists.ozlabs.org;
> Zhao Chenhui-B35336; Li Yang-R58472
> Subject: Re: [PATCH 3/3] powerpc/fsl: add MPIC timer wakeup support
>=20
> On 03/22/2013 12:46:24 AM, Wang Dongsheng-B40534 wrote:
> >
> >
> > > -----Original Message-----
> > > From: Wood Scott-B07421
> > > Sent: Thursday, March 21, 2013 5:49 AM
> > > To: Wang Dongsheng-B40534
> > > Cc: Wood Scott-B07421; Gala Kumar-B11780;
> > linuxppc-dev@lists.ozlabs.org;
> > > Zhao Chenhui-B35336; Li Yang-R58472
> > > Subject: Re: [PATCH 3/3] powerpc/fsl: add MPIC timer wakeup support
> > >
> > > On 03/19/2013 10:48:53 PM, Wang Dongsheng-B40534 wrote:
> > > > while (*s) {
> > > > if ('0' <=3D *s && *s <=3D '9')
> > > > val =3D *s - '0';
> > > > else if ('a' <=3D _tolower(*s) && _tolower(*s) <=3D 'f')
> > > > val =3D _tolower(*s) - 'a' + 10;
> > > > else
> > > > break; //this will break out to convert.
> > >
> > > Really? How do you know that the next byte after the buffer isn't a
> > > valid hex digit? How do you even know that we won't take a fault
> > > accessing it?
> > >
> > Under what case is unsafe, please make sense.
>=20
> char buffer[1] =3D { '5' };
> write(fd, &buffer, 1);
>=20
> What comes after that '5' byte in the pointer you pass to kstrtol?
>=20
The buffer is userspace. It will fall in the kernel space.
Kernel will get a free page, and copy the buffer to page.
This page has been cleared before copy to page.
The page has already have null-terminated.
> > "kstrtol" is used in almost of sysfs interface, I think it should be
> > accepted in defaule :).
>=20
> Just because a lot of other people copy blindly doesn't make it right.
> Most of the examples I found use sscanf instead, though that has the same
> problem.
>=20
> I do see a few instances of the "strings from sysfs write are not 0
> terminated!" in the comments, though (kernel/time/clocksource.c and
> kernel/rtmutex-tester.c).
>=20
> Also "words written to sysfs files may, or may not, be \n terminated"
> in drivers/md/md.c.
>=20
It's not "kstrtol" doesn't work as well, They do not belong to this kind
of scenarios.
^ permalink raw reply
* RE: [PATCH 2/3] powerpc/mpic: add global timer support
From: Wang Dongsheng-B40534 @ 2013-03-26 3:29 UTC (permalink / raw)
To: Wood Scott-B07421
Cc: Gala Kumar-B11780, linuxppc-dev@lists.ozlabs.org, Li Yang-R58472
In-Reply-To: <1363991395.24790.13@snotra>
> -----Original Message-----
> From: Wood Scott-B07421
> Sent: Saturday, March 23, 2013 6:30 AM
> To: Wang Dongsheng-B40534
> Cc: Wood Scott-B07421; Gala Kumar-B11780; linuxppc-dev@lists.ozlabs.org;
> Li Yang-R58472
> Subject: Re: [PATCH 2/3] powerpc/mpic: add global timer support
>=20
> On 03/22/2013 01:14:51 AM, Wang Dongsheng-B40534 wrote:
> >
> >
> > > -----Original Message-----
> > > From: Wood Scott-B07421
> > > Sent: Thursday, March 21, 2013 7:00 AM
> > > To: Wang Dongsheng-B40534
> > > Cc: Wood Scott-B07421; Gala Kumar-B11780;
> > linuxppc-dev@lists.ozlabs.org;
> > > Li Yang-R58472
> > > Subject: Re: [PATCH 2/3] powerpc/mpic: add global timer support
> > >
> > > BTW, the input clock frequency has been similarly scaled, yet you
> > don't
> > > try to scrounge up that information to get further precision...
> > >
> > Let's go back patch, do you think the code is repeated?
> > I will remove "if (!(priv->flags & FSL_GLOBAL_TIMER))" branch, there
> > will be no redundant code.
>=20
> I'd rather that branch be kept and the more complicated branch deleted,
> and priv->timerfreq frequency be adjusted on initialization to account
> for the scaler.
static void convert_ticks_to_time(struct timer_group_priv *priv,
const u64 ticks, struct timeval *time)
{
u64 tmp_sec;
time->tv_sec =3D (__kernel_time_t)div_u64(ticks, priv->timerfreq);
tmp_sec =3D (u64)time->tv_sec * (u64)priv->timerfreq;
time->tv_usec =3D (__kernel_suseconds_t)
div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq);
return;
}
timer_group_get_freq() {
...
if (priv->flags & FSL_GLOBAL_TIMER) {
div =3D (1 << (MPIC_TIMER_TCR_CLKDIV_64 >> 8)) * 8;
priv->timerfreq /=3D div;
}
...
}
Do you want to do that?
^ permalink raw reply
* [PATCH 1/2] powerpc/MPIC: Add get_version API both for internal and external use
From: Jia Hongtao @ 2013-03-26 3:28 UTC (permalink / raw)
To: linuxppc-dev, galak; +Cc: B07421, hongtao.jia
MPIC version is useful information for both mpic_alloc() and mpic_init().
The patch provide an API to get MPIC version for reusing the code.
Also, some other IP block may need MPIC version for their own use.
The API for external use is also provided.
Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
arch/powerpc/include/asm/mpic.h | 3 +++
arch/powerpc/sysdev/mpic.c | 30 +++++++++++++++++++++++-------
2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index c0f9ef9..95053d6 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -393,6 +393,9 @@ struct mpic
#define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */
#define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */
+/* Get the mpic version */
+extern u32 mpic_primary_get_version(void);
+
/* Allocate the controller structure and setup the linux irq descs
* for the range if interrupts passed in. No HW initialization is
* actually performed.
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index d30e6a6..d6b6fb6 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1165,10 +1165,31 @@ static struct irq_domain_ops mpic_host_ops = {
.xlate = mpic_host_xlate,
};
+static u32 mpic_get_version(struct mpic *mpic)
+{
+ u32 brr1;
+
+ brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+ MPIC_FSL_BRR1);
+
+ return brr1 & MPIC_FSL_BRR1_VER;
+}
+
/*
* Exported functions
*/
+u32 mpic_primary_get_version(void)
+{
+ u32 brr1;
+ struct mpic *mpic = mpic_primary;
+
+ brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+ MPIC_FSL_BRR1);
+
+ return brr1 & MPIC_FSL_BRR1_VER;
+}
+
struct mpic * __init mpic_alloc(struct device_node *node,
phys_addr_t phys_addr,
unsigned int flags,
@@ -1315,7 +1336,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
if (mpic->flags & MPIC_FSL) {
- u32 brr1;
int ret;
/*
@@ -1326,9 +1346,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
MPIC_CPU_THISBASE, 0x1000);
- brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- fsl_version = brr1 & MPIC_FSL_BRR1_VER;
+ fsl_version = mpic_get_version(mpic);
/* Error interrupt mask register (EIMR) is required for
* handling individual device error interrupts. EIMR
@@ -1518,9 +1536,7 @@ void __init mpic_init(struct mpic *mpic)
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
if (mpic->flags & MPIC_FSL) {
- u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- u32 version = brr1 & MPIC_FSL_BRR1_VER;
+ u32 version = mpic_get_version(mpic);
/*
* Timer group B is present at the latest in MPIC 3.1 (e.g.
--
1.8.0
^ permalink raw reply related
* [PATCH 2/2] powerpc/85xx: workaround for chips with MSI hardware errata
From: Jia Hongtao @ 2013-03-26 3:28 UTC (permalink / raw)
To: linuxppc-dev, galak; +Cc: B07421, hongtao.jia
In-Reply-To: <1364268527-32068-1-git-send-email-hongtao.jia@freescale.com>
The MPIC version 2.0 has a MSI errata (errata PIC1 of mpc8544), It causes
that neither MSI nor MSI-X can work fine. This is a workaround to allow
MSI-X to function properly.
Signed-off-by: Liu Shuo <soniccat.liu@gmail.com>
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
---
arch/powerpc/sysdev/fsl_msi.c | 47 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 44 insertions(+), 3 deletions(-)
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 178c994..d2f8040 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -28,6 +28,8 @@
#include "fsl_msi.h"
#include "fsl_pci.h"
+#define MSI_HW_ERRATA_ENDIAN 0x00000010
+
static LIST_HEAD(msi_head);
struct fsl_msi_feature {
@@ -98,8 +100,18 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
- if (type == PCI_CAP_ID_MSIX)
- pr_debug("fslmsi: MSI-X untested, trying anyway.\n");
+ struct fsl_msi *msi;
+
+ if (type == PCI_CAP_ID_MSI) {
+ /*
+ * MPIC version 2.0 has erratum PIC1. For now MSI
+ * could not work. So check to prevent MSI from
+ * being used on the board with this erratum.
+ */
+ list_for_each_entry(msi, &msi_head, list)
+ if (msi->feature & MSI_HW_ERRATA_ENDIAN)
+ return -EINVAL;
+ }
return 0;
}
@@ -142,7 +154,17 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
msg->address_lo = lower_32_bits(address);
msg->address_hi = upper_32_bits(address);
- msg->data = hwirq;
+ /*
+ * MPIC version 2.0 has erratum PIC1. It causes
+ * that neither MSI nor MSI-X can work fine.
+ * This is a workaround to allow MSI-X to function
+ * properly. It only works for MSI-X, we prevent
+ * MSI on buggy chips in fsl_msi_check_device().
+ */
+ if (msi_data->feature & MSI_HW_ERRATA_ENDIAN)
+ msg->data = __swab32(hwirq);
+ else
+ msg->data = hwirq;
pr_debug("%s: allocated srs: %d, ibs: %d\n",
__func__, hwirq / IRQS_PER_MSI_REG, hwirq % IRQS_PER_MSI_REG);
@@ -361,6 +383,15 @@ static int fsl_msi_setup_hwirq(struct fsl_msi *msi, struct platform_device *dev,
return 0;
}
+/* MPIC version 2.0 has erratum PIC1 */
+static int mpic_has_errata(void)
+{
+ if (mpic_primary_get_version() == 0x0200)
+ return 1;
+
+ return 0;
+}
+
static const struct of_device_id fsl_of_msi_ids[];
static int fsl_of_msi_probe(struct platform_device *dev)
{
@@ -423,6 +454,16 @@ static int fsl_of_msi_probe(struct platform_device *dev)
msi->feature = features->fsl_pic_ip;
+ if ((features->fsl_pic_ip & FSL_PIC_IP_MASK) == FSL_PIC_IP_MPIC) {
+ rc = mpic_has_errata();
+ if (rc > 0) {
+ msi->feature |= MSI_HW_ERRATA_ENDIAN;
+ } else if (rc < 0) {
+ err = rc;
+ goto error_out;
+ }
+ }
+
/*
* Remember the phandle, so that we can match with any PCI nodes
* that have an "fsl,msi" property.
--
1.8.0
^ permalink raw reply related
* Re: [PATCH] powerpc: remove two lines of dead code
From: Michael Ellerman @ 2013-03-26 4:12 UTC (permalink / raw)
To: Paul Bolle; +Cc: Paul Mackerras, linuxppc-dev, linux-kernel
In-Reply-To: <1364207531.1390.271.camel@x61.thuisdomein>
On Mon, Mar 25, 2013 at 11:32:11AM +0100, Paul Bolle wrote:
> Commit c1fb6816fb1b78dd94b673b0fdaa9a7a16e97bd1 ("powerpc: Add
> relocation on exception vector handlers") added two lines of code that
> depend on the macro CONFIG_HVC_SCOM. That macro doesn't exist. Perhaps
> it was intended to use CONFIG_PPC_SCOM here. But since
> "maintence_interrupt" is a typo and there's nothing in arch/powerpc that
> looks like maintenance_interrupt it seems best to just delete these
> lines.
It's cruft from our internal tree that snuck into the patch. I was
meaning to remove it but you beat me to it.
Acked-by: Michael Ellerman <michael@ellerman.id.au>
cheers
^ permalink raw reply
* Re: [PATCH 1/2] powerpc/MPIC: Add get_version API both for internal and external use
From: Michael Ellerman @ 2013-03-26 4:14 UTC (permalink / raw)
To: Jia Hongtao; +Cc: B07421, linuxppc-dev
In-Reply-To: <1364268527-32068-1-git-send-email-hongtao.jia@freescale.com>
On Tue, Mar 26, 2013 at 11:28:46AM +0800, Jia Hongtao wrote:
> MPIC version is useful information for both mpic_alloc() and mpic_init().
> The patch provide an API to get MPIC version for reusing the code.
> Also, some other IP block may need MPIC version for their own use.
> The API for external use is also provided.
>
> Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
> Signed-off-by: Li Yang <leoli@freescale.com>
> ---
> arch/powerpc/include/asm/mpic.h | 3 +++
> arch/powerpc/sysdev/mpic.c | 30 +++++++++++++++++++++++-------
> 2 files changed, 26 insertions(+), 7 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
> index c0f9ef9..95053d6 100644
> --- a/arch/powerpc/include/asm/mpic.h
> +++ b/arch/powerpc/include/asm/mpic.h
> @@ -393,6 +393,9 @@ struct mpic
> #define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */
> #define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */
>
> +/* Get the mpic version */
> +extern u32 mpic_primary_get_version(void);
> +
> /* Allocate the controller structure and setup the linux irq descs
> * for the range if interrupts passed in. No HW initialization is
> * actually performed.
> diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> index d30e6a6..d6b6fb6 100644
> --- a/arch/powerpc/sysdev/mpic.c
> +++ b/arch/powerpc/sysdev/mpic.c
> @@ -1165,10 +1165,31 @@ static struct irq_domain_ops mpic_host_ops = {
> .xlate = mpic_host_xlate,
> };
>
> +static u32 mpic_get_version(struct mpic *mpic)
> +{
> + u32 brr1;
> +
> + brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
> + MPIC_FSL_BRR1);
> +
> + return brr1 & MPIC_FSL_BRR1_VER;
> +}
> +
> /*
> * Exported functions
> */
>
> +u32 mpic_primary_get_version(void)
> +{
> + u32 brr1;
> + struct mpic *mpic = mpic_primary;
> +
> + brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
> + MPIC_FSL_BRR1);
> +
> + return brr1 & MPIC_FSL_BRR1_VER;
> +}
Why doesn't mpic_primary_get_version() call mpic_get_version() ?
cheers
^ permalink raw reply
* RE: [PATCH 1/2] powerpc/MPIC: Add get_version API both for internal and external use
From: Jia Hongtao-B38951 @ 2013-03-26 4:16 UTC (permalink / raw)
To: Michael Ellerman; +Cc: Wood Scott-B07421, linuxppc-dev@lists.ozlabs.org
In-Reply-To: <20130326041426.GC22382@concordia>
> -----Original Message-----
> From: Michael Ellerman [mailto:michael@ellerman.id.au]
> Sent: Tuesday, March 26, 2013 12:14 PM
> To: Jia Hongtao-B38951
> Cc: linuxppc-dev@lists.ozlabs.org; galak@kernel.crashing.org; Wood Scott-
> B07421
> Subject: Re: [PATCH 1/2] powerpc/MPIC: Add get_version API both for
> internal and external use
>=20
> On Tue, Mar 26, 2013 at 11:28:46AM +0800, Jia Hongtao wrote:
> > MPIC version is useful information for both mpic_alloc() and
> mpic_init().
> > The patch provide an API to get MPIC version for reusing the code.
> > Also, some other IP block may need MPIC version for their own use.
> > The API for external use is also provided.
> >
> > Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
> > Signed-off-by: Li Yang <leoli@freescale.com>
> > ---
> > arch/powerpc/include/asm/mpic.h | 3 +++
> > arch/powerpc/sysdev/mpic.c | 30 +++++++++++++++++++++++-------
> > 2 files changed, 26 insertions(+), 7 deletions(-)
> >
> > diff --git a/arch/powerpc/include/asm/mpic.h
> > b/arch/powerpc/include/asm/mpic.h index c0f9ef9..95053d6 100644
> > --- a/arch/powerpc/include/asm/mpic.h
> > +++ b/arch/powerpc/include/asm/mpic.h
> > @@ -393,6 +393,9 @@ struct mpic
> > #define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original
> MPIC */
> > #define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109
> PIC */
> >
> > +/* Get the mpic version */
> > +extern u32 mpic_primary_get_version(void);
> > +
> > /* Allocate the controller structure and setup the linux irq descs
> > * for the range if interrupts passed in. No HW initialization is
> > * actually performed.
> > diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
> > index d30e6a6..d6b6fb6 100644
> > --- a/arch/powerpc/sysdev/mpic.c
> > +++ b/arch/powerpc/sysdev/mpic.c
> > @@ -1165,10 +1165,31 @@ static struct irq_domain_ops mpic_host_ops =3D =
{
> > .xlate =3D mpic_host_xlate,
> > };
> >
> > +static u32 mpic_get_version(struct mpic *mpic) {
> > + u32 brr1;
> > +
> > + brr1 =3D _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
> > + MPIC_FSL_BRR1);
> > +
> > + return brr1 & MPIC_FSL_BRR1_VER;
> > +}
> > +
> > /*
> > * Exported functions
> > */
> >
> > +u32 mpic_primary_get_version(void)
> > +{
> > + u32 brr1;
> > + struct mpic *mpic =3D mpic_primary;
> > +
> > + brr1 =3D _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
> > + MPIC_FSL_BRR1);
> > +
> > + return brr1 & MPIC_FSL_BRR1_VER;
> > +}
>=20
> Why doesn't mpic_primary_get_version() call mpic_get_version() ?
>=20
> cheers
Good idea.
Thanks.
-Hongtao.
^ permalink raw reply
* [PATCH] powerpc: fix annotation of fake_numa_create_new_node()
From: Stephen Rothwell @ 2013-03-26 4:44 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: ppc-dev
[-- Attachment #1: Type: text/plain, Size: 1302 bytes --]
This function has always been marked as __cpuinit, but is only called
from functions marked as __init and references an __initdata variable.
So change its annotation to __init.
Fixes this build warning:
WARNING: arch/powerpc/mm/built-in.o(.cpuinit.text+0x86): Section mismatch in reference from the function .fake_numa_create_new_node() to the variable .init.data:cmdline
The function __cpuinit .fake_numa_create_new_node() references
a variable __initdata cmdline.
If cmdline is only used by .fake_numa_create_new_node then
annotate cmdline with a matching annotation.
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
---
arch/powerpc/mm/numa.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index bba87ca..715cab7 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -79,7 +79,7 @@ static void __init setup_node_to_cpumask_map(void)
dbg("Node to cpumask map for %d nodes\n", nr_node_ids);
}
-static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
+static int __init fake_numa_create_new_node(unsigned long end_pfn,
unsigned int *nid)
{
unsigned long long mem;
--
1.8.1
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply related
* Re: [PATCH 3/3] cpufreq: Add cpufreq driver for Freescale e500mc SOCs
From: Viresh Kumar @ 2013-03-26 5:03 UTC (permalink / raw)
To: Yuantian.Tang; +Cc: rjw, linuxppc-dev, cpufreq, linux-pm
In-Reply-To: <1364265391-26077-3-git-send-email-Yuantian.Tang@freescale.com>
On Tue, Mar 26, 2013 at 8:06 AM, <Yuantian.Tang@freescale.com> wrote:
> diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
> index e76992f..6339db4 100644
> --- a/drivers/cpufreq/Kconfig.powerpc
> +++ b/drivers/cpufreq/Kconfig.powerpc
> @@ -5,3 +5,13 @@ config CPU_FREQ_MAPLE
> help
> This adds support for frequency switching on Maple 970FX
> Evaluation Board and compatible boards (IBM JS2x blades).
> +
> +config PPC_CORENET_CPUFREQ
> + tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
> + depends on PPC_E500MC
depends on OF and COMMON_CLK too?
> + select CPU_FREQ_TABLE
> + select CLK_PPC_CORENET
> + help
> + This adds the CPUFreq driver support for Freescale e500mc,
> + e5500 and e6500 series SoCs which are capable of changing
> + the CPU's frequency dynamically.
> diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
> index 863fd18..2416559 100644
> --- a/drivers/cpufreq/Makefile
> +++ b/drivers/cpufreq/Makefile
> diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c
> +#include <linux/module.h>
> +#include <linux/types.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/cpufreq.h>
> +#include <linux/init.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/io.h>
> +#include <linux/clk-provider.h>
You shouldn't need this normally.
> +#include <linux/cpu.h>
Keep them in alphabetical order, so that we don't anyone twice by mistake.
> +/**
> + * struct cpufreq_data - cpufreq driver data
> + * @cpus_per_cluster: CPU numbers per cluster
> + * @cpufreq_lock: the mutex lock
> + */
> +struct cpufreq_data {
> + int cpus_per_cluster;
> + struct mutex cpufreq_lock;
> +};
> +
> +/**
> + * struct cpu_data - per CPU data struct
For your case where you have 8 cpus in a cluster, only one of 8 variables
would be used... Better to create an array of struct with elements:
cpu and data.
> + * @np: the node of CPU
> + * @parent: the parent node of np
> + * @table: frequency table point
> + */
> +struct cpu_data {
> + struct device_node *np;
> + struct device_node *parent;
> + struct cpufreq_frequency_table *table;
> +};
> +
> +static DEFINE_PER_CPU(struct cpu_data, cpu_data);
> +static struct cpufreq_data freq_data;
> +
> +static unsigned int corenet_cpufreq_get_speed(unsigned int cpu)
> +{
> + struct clk *clk;
> + struct cpu_data *data = &per_cpu(cpu_data, cpu);
> +
> + clk = of_clk_get(data->np, 0);
You want to do this everytime? Want to store it?
> + return clk_get_rate(clk) / 1000;
> +}
> +
> +/* reduce the duplicated frequency in frequency table */
> +static int freq_table_redup(struct cpufreq_frequency_table *freq_table,
> + int cur)
> +{
> + int i;
> +
> + for (i = 0; i < cur; i++) {
> + if (freq_table[i].frequency == CPUFREQ_ENTRY_INVALID ||
> + freq_table[i].frequency != freq_table[cur].frequency)
> + continue;
> +
> + freq_table[cur].index = -1;
don't need this.
> + freq_table[cur].frequency = CPUFREQ_ENTRY_INVALID;
> + break;
> + }
> +
> + return (i == cur) ? 0 : 1;
return value isn't used by caller.
> +}
> +
> +static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy)
> +{
> + unsigned int cpu = policy->cpu;
> + int i, count;
> + struct clk *clk;
> + struct cpufreq_frequency_table *table;
> + struct cpu_data *data;
> +
> + data = &per_cpu(cpu_data, cpu);
> + data->np = of_get_cpu_node(cpu, NULL);
> + if (!data->np)
> + return -ENODEV;
> +
> + data->parent = of_parse_phandle(data->np, "clocks", 0);
You need to details your DTB bindings in Documentation/devicetree/bindings and
cc devicetree-discuss@lists.ozlabs.org.
> + if (!data->parent)
> + return -ENODEV;
of_node_put(np)??
> +
> + count = of_property_count_strings(data->parent, "clock-names");
> + table = kcalloc(count + 1,
kzalloc??
> + sizeof(struct cpufreq_frequency_table), GFP_KERNEL);
sizeof(*table)
> + if (!table)
> + return -ENOMEM;
> +
> + for (i = cpu; i < freq_data.cpus_per_cluster + cpu; i++)
> + cpumask_set_cpu(i, policy->cpus);
> +
> + for (i = 0; i < count; i++) {
> + table[i].index = i;
> + clk = of_clk_get(data->parent, i);
> + table[i].frequency = clk_get_rate(clk) / 1000;
> + freq_table_redup(table, i);
Don't call it everytime, fix all these in a single call.
> + }
> + table[i].index = -1;
-1 ??
> + table[i].frequency = CPUFREQ_TABLE_END;
> +
> + data->table = table;
> + cpufreq_frequency_table_get_attr(table, cpu);
This must be done only when init() passed. What if
cpufreq_frequency_table_cpuinfo() failed?
> +
> + /* FIXME: what's the actual transition time? in ns */
> + policy->cpuinfo.transition_latency = 2000;
CPUFREQ_ETERNAL??
> + policy->cur = corenet_cpufreq_get_speed(policy->cpu);
> +
> + /* set the min and max frequency properly */
> + return cpufreq_frequency_table_cpuinfo(policy, table);
> +}
> +
> +static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy)
> +{
> + cpufreq_frequency_table_put_attr(policy->cpu);
> +
> + return 0;
> +}
> +
> +static int corenet_cpufreq_verify(struct cpufreq_policy *policy)
> +{
> + struct cpufreq_frequency_table *table;
> +
> + table = (&per_cpu(cpu_data, policy->cpu))->table;
> + if (!table)
> + return -EINVAL;
This should never be true.
> + return cpufreq_frequency_table_verify(policy, table);
> +}
> +
> +static int corenet_cpufreq_target(struct cpufreq_policy *policy,
> + unsigned int target_freq, unsigned int relation)
> +{
> + struct cpufreq_freqs freqs;
> + unsigned int new;
> + struct clk *clk, *parent;
> + int ret;
> + struct cpu_data *data = &per_cpu(cpu_data, policy->cpu);
> +
> + cpufreq_frequency_table_target(policy, data->table,
> + target_freq, relation, &new);
> +
> + if (policy->cur == data->table[new].frequency)
> + return 0;
> +
> + freqs.old = policy->cur;
> + freqs.new = data->table[new].frequency;
> + freqs.cpu = policy->cpu;
> +
> + mutex_lock(&freq_data.cpufreq_lock);
> + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
> +
> + clk = of_clk_get(data->np, 0);
> + parent = of_clk_get(data->parent, new);
> + ret = clk_set_parent(clk, parent);
> + if (ret) {
> + mutex_unlock(&freq_data.cpufreq_lock);
> + return ret;
> + }
> +
> + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> + mutex_unlock(&freq_data.cpufreq_lock);
> +
> + return 0;
> +}
> +
> +static struct freq_attr *corenet_cpu_clks_attr[] = {
> + &cpufreq_freq_attr_scaling_available_freqs,
> + NULL,
> +};
> +
> +static struct cpufreq_driver ppc_corenet_cpufreq_driver = {
> + .name = "ppc_cpufreq",
> + .owner = THIS_MODULE,
> + .flags = CPUFREQ_CONST_LOOPS,
> + .init = corenet_cpufreq_cpu_init,
> + .exit = __exit_p(corenet_cpufreq_cpu_exit),
> + .verify = corenet_cpufreq_verify,
> + .target = corenet_cpufreq_target,
> + .get = corenet_cpufreq_get_speed,
> + .attr = corenet_cpu_clks_attr,
> +};
> +
> +static const struct of_device_id node_matches[] __initconst = {
> + { .compatible = "fsl,qoriq-clockgen-1.0", .data = (void *)1, },
> + { .compatible = "fsl,qoriq-clockgen-2", .data = (void *)8, },
> + {}
> +};
> +
> +static int __init ppc_corenet_cpufreq_init(void)
> +{
> + int ret = 0;
> + struct device_node *np;
> + const struct of_device_id *match;
> +
> + np = of_find_matching_node(NULL, node_matches);
> + if (!np)
> + return -ENODEV;
> +
> + match = of_match_node(node_matches, np);
> + freq_data.cpus_per_cluster = (long)match->data;
> + mutex_init(&freq_data.cpufreq_lock);
> + of_node_put(np);
> +
> + ret = cpufreq_register_driver(&ppc_corenet_cpufreq_driver);
> + if (ret)
> + return ret;
> +
> + pr_info("Freescale PowerPC corenet CPU frequency scaling driver\n");
> +
> + return ret;
> +}
> +
> +static void __exit ppc_corenet_cpufreq_exit(void)
> +{
> + cpufreq_unregister_driver(&ppc_corenet_cpufreq_driver);
> +}
> +
> +module_init(ppc_corenet_cpufreq_init);
> +module_exit(ppc_corenet_cpufreq_exit);
Place them right below their respective functions without any blank
line in between.
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Tang Yuantian <Yuantian.Tang@freescale.com>");
> +MODULE_DESCRIPTION("cpufreq driver for Freescale e500mc series SOCs");
^ permalink raw reply
* [PATCH V2] powerpc/MPIC: Add get_version API both for internal and external use
From: Jia Hongtao @ 2013-03-26 5:28 UTC (permalink / raw)
To: linuxppc-dev, galak; +Cc: B07421, hongtao.jia
MPIC version is useful information for both mpic_alloc() and mpic_init().
The patch provide an API to get MPIC version for reusing the code.
Also, some other IP block may need MPIC version for their own use.
The API for external use is also provided.
Signed-off-by: Jia Hongtao <hongtao.jia@freescale.com>
Signed-off-by: Li Yang <leoli@freescale.com>
---
Changes for V2:
* Using mpic_get_version() to implement mpic_primary_get_version()
arch/powerpc/include/asm/mpic.h | 3 +++
arch/powerpc/sysdev/mpic.c | 26 +++++++++++++++++++-------
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index c0f9ef9..7d1222d 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -393,6 +393,9 @@ struct mpic
#define MPIC_REGSET_STANDARD MPIC_REGSET(0) /* Original MPIC */
#define MPIC_REGSET_TSI108 MPIC_REGSET(1) /* Tsi108/109 PIC */
+/* Get the version of primary MPIC */
+extern u32 mpic_primary_get_version(void);
+
/* Allocate the controller structure and setup the linux irq descs
* for the range if interrupts passed in. No HW initialization is
* actually performed.
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index d30e6a6..c893a4b 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -1165,10 +1165,27 @@ static struct irq_domain_ops mpic_host_ops = {
.xlate = mpic_host_xlate,
};
+static u32 mpic_get_version(struct mpic *mpic)
+{
+ u32 brr1;
+
+ brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+ MPIC_FSL_BRR1);
+
+ return brr1 & MPIC_FSL_BRR1_VER;
+}
+
/*
* Exported functions
*/
+u32 mpic_primary_get_version(void)
+{
+ struct mpic *mpic = mpic_primary;
+
+ return mpic_get_version(mpic);
+}
+
struct mpic * __init mpic_alloc(struct device_node *node,
phys_addr_t phys_addr,
unsigned int flags,
@@ -1315,7 +1332,6 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
if (mpic->flags & MPIC_FSL) {
- u32 brr1;
int ret;
/*
@@ -1326,9 +1342,7 @@ struct mpic * __init mpic_alloc(struct device_node *node,
mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
MPIC_CPU_THISBASE, 0x1000);
- brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- fsl_version = brr1 & MPIC_FSL_BRR1_VER;
+ fsl_version = mpic_get_version(mpic);
/* Error interrupt mask register (EIMR) is required for
* handling individual device error interrupts. EIMR
@@ -1518,9 +1532,7 @@ void __init mpic_init(struct mpic *mpic)
mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
if (mpic->flags & MPIC_FSL) {
- u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
- MPIC_FSL_BRR1);
- u32 version = brr1 & MPIC_FSL_BRR1_VER;
+ u32 version = mpic_get_version(mpic);
/*
* Timer group B is present at the latest in MPIC 3.1 (e.g.
--
1.8.0
^ permalink raw reply related
* Re: [PATCH v2 1/4] uprobes: add trap variant helper
From: Srikar Dronamraju @ 2013-03-26 12:06 UTC (permalink / raw)
To: Ananth N Mavinakayanahalli; +Cc: ppcdev, lkml, oleg
In-Reply-To: <20130322151627.GB20010@in.ibm.com>
* Ananth N Mavinakayanahalli <ananth@in.ibm.com> [2013-03-22 20:46:27]:
> From: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
>
> Some architectures like powerpc have multiple variants of the trap
> instruction. Introduce an additional helper is_trap_insn() for run-time
> handling of non-uprobe traps on such architectures.
>
> While there, change is_swbp_at_addr() to is_trap_at_addr() for reading
> clarity.
>
> With this change, the uprobe registration path will supercede any trap
> instruction inserted at the requested location, while taking care of
> delivering the SIGTRAP for cases where the trap notification came in
> for an address without a uprobe. See [1] for a more detailed explanation.
>
> [1] https://lists.ozlabs.org/pipermail/linuxppc-dev/2013-March/104771.html
>
> This change was suggested by Oleg Nesterov.
>
> Signed-off-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
> ---
> include/linux/uprobes.h | 1 +
> kernel/events/uprobes.c | 32 ++++++++++++++++++++++++++++----
> 2 files changed, 29 insertions(+), 4 deletions(-)
>
> Index: linux-3.9-rc3/include/linux/uprobes.h
> ===================================================================
> --- linux-3.9-rc3.orig/include/linux/uprobes.h
> +++ linux-3.9-rc3/include/linux/uprobes.h
> @@ -100,6 +100,7 @@ struct uprobes_state {
> extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
> extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr);
> extern bool __weak is_swbp_insn(uprobe_opcode_t *insn);
> +extern bool __weak is_trap_insn(uprobe_opcode_t *insn);
> extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
> extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool);
> extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
> Index: linux-3.9-rc3/kernel/events/uprobes.c
> ===================================================================
> --- linux-3.9-rc3.orig/kernel/events/uprobes.c
> +++ linux-3.9-rc3/kernel/events/uprobes.c
> @@ -173,6 +173,20 @@ bool __weak is_swbp_insn(uprobe_opcode_t
> return *insn == UPROBE_SWBP_INSN;
> }
>
> +/**
> + * is_trap_insn - check if instruction is breakpoint instruction.
> + * @insn: instruction to be checked.
> + * Default implementation of is_trap_insn
> + * Returns true if @insn is a breakpoint instruction.
> + *
> + * This function is needed for the case where an architecture has multiple
> + * trap instructions (like powerpc).
> + */
> +bool __weak is_trap_insn(uprobe_opcode_t *insn)
> +{
> + return is_swbp_insn(insn);
> +}
> +
> static void copy_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t *opcode)
> {
> void *kaddr = kmap_atomic(page);
> @@ -185,6 +199,15 @@ static int verify_opcode(struct page *pa
> uprobe_opcode_t old_opcode;
> bool is_swbp;
>
> + /*
> + * Note: We only check if the old_opcode is UPROBE_SWBP_INSN here.
> + * We do not check if it is any other 'trap variant' which could
> + * be conditional trap instruction such as the one powerpc supports.
> + *
> + * The logic is that we do not care if the underlying instruction
> + * is a trap variant; uprobes always wins over any other (gdb)
> + * breakpoint.
> + */
> copy_opcode(page, vaddr, &old_opcode);
> is_swbp = is_swbp_insn(&old_opcode);
>
> @@ -204,7 +227,7 @@ static int verify_opcode(struct page *pa
> * Expect the breakpoint instruction to be the smallest size instruction for
> * the architecture. If an arch has variable length instruction and the
> * breakpoint instruction is not of the smallest length instruction
> - * supported by that architecture then we need to modify is_swbp_at_addr and
> + * supported by that architecture then we need to modify is_trap_at_addr and
> * write_opcode accordingly. This would never be a problem for archs that
> * have fixed length instructions.
> */
> @@ -1431,7 +1454,7 @@ static void mmf_recalc_uprobes(struct mm
> clear_bit(MMF_HAS_UPROBES, &mm->flags);
> }
>
> -static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr)
> +static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
> {
> struct page *page;
> uprobe_opcode_t opcode;
> @@ -1452,7 +1475,8 @@ static int is_swbp_at_addr(struct mm_str
> copy_opcode(page, vaddr, &opcode);
> put_page(page);
> out:
> - return is_swbp_insn(&opcode);
> + /* This needs to return true for any variant of the trap insn */
> + return is_trap_insn(&opcode);
> }
>
> static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
> @@ -1472,7 +1496,7 @@ static struct uprobe *find_active_uprobe
> }
>
> if (!uprobe)
> - *is_swbp = is_swbp_at_addr(mm, bp_vaddr);
> + *is_swbp = is_trap_at_addr(mm, bp_vaddr);
> } else {
> *is_swbp = -EFAULT;
> }
--
Thanks and Regards
Srikar Dronamraju
^ 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