summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2016-06-27 15:07:43 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-07-01 18:15:38 +1000
commitad53085acc6264b5673fbb8055a3e7feecee6159 (patch)
tree517d366aa7a3589df10b5569f3e45e148e8a7655
parent16ef1b8217ba437df7cf3c8893f0c5b9ef094cbe (diff)
downloadblackbird-skiboot-ad53085acc6264b5673fbb8055a3e7feecee6159.tar.gz
blackbird-skiboot-ad53085acc6264b5673fbb8055a3e7feecee6159.zip
cpu: supply ibm,dec-bits via devicetree
ISAv3 adds a mode to increase the size of the decrementer from 32 bits. The enlarged decrementer can be between 32 and 64 bits wide with the exact value being implementation dependent. This patch adds support for detecting the size of the large decrementer and populating each CPU node with the "ibm,dec-bits" property. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Reviewed-by: Vaidyanathan Srinivasan <svaidy@linux.vnet.ibm.com> [stewart@linux.vnet.ibm.com: rename enable_ld() to enable_large_dec()] Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/cpu.c48
-rw-r--r--include/processor.h1
2 files changed, 49 insertions, 0 deletions
diff --git a/core/cpu.c b/core/cpu.c
index ffc264f9..8a7a43f7 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -524,10 +524,55 @@ void init_boot_cpu(void)
list_head_init(&global_job_queue);
}
+static void enable_large_dec(bool on)
+{
+ u64 lpcr = mfspr(SPR_LPCR);
+
+ if (on)
+ lpcr |= SPR_LPCR_P9_LD;
+ else
+ lpcr &= ~SPR_LPCR_P9_LD;
+
+ mtspr(SPR_LPCR, lpcr);
+}
+
+#define HIGH_BIT (1ull << 63)
+
+static int find_dec_bits(void)
+{
+ int bits = 65; /* we always decrement once */
+ u64 mask = ~0ull;
+
+ if (proc_gen < proc_gen_p9)
+ return 32;
+
+ /* The ISA doesn't specify the width of the decrementer register so we
+ * need to discover it. When in large mode (LPCR.LD = 1) reads from the
+ * DEC SPR are sign extended to 64 bits and writes are truncated to the
+ * physical register width. We can use this behaviour to detect the
+ * width by starting from an all 1s value and left shifting until we
+ * read a value from the DEC with it's high bit cleared.
+ */
+
+ enable_large_dec(true);
+
+ do {
+ bits--;
+ mask = mask >> 1;
+ mtspr(SPR_DEC, mask);
+ } while (mfspr(SPR_DEC) & HIGH_BIT);
+
+ enable_large_dec(false);
+
+ prlog(PR_DEBUG, "CPU: decrementer bits %d\n", bits);
+ return bits;
+}
+
void init_all_cpus(void)
{
struct dt_node *cpus, *cpu;
unsigned int thread, new_max_pir = 0;
+ int dec_bits = find_dec_bits();
cpus = dt_find_by_path(dt_root, "/cpus");
assert(cpus);
@@ -582,6 +627,9 @@ void init_all_cpus(void)
/* Add associativity properties */
add_core_associativity(t);
+ /* Add the decrementer width property */
+ dt_add_property_cells(cpu, "ibm,dec-bits", dec_bits);
+
/* Adjust max PIR */
if (new_max_pir < (pir + cpu_thread_count - 1))
new_max_pir = pir + cpu_thread_count - 1;
diff --git a/include/processor.h b/include/processor.h
index 1236c779..48bbf903 100644
--- a/include/processor.h
+++ b/include/processor.h
@@ -96,6 +96,7 @@
#define SPR_LPCR_P8_PECE2 PPC_BIT(49) /* Wake on external interrupts */
#define SPR_LPCR_P8_PECE3 PPC_BIT(50) /* Wake on decrementer */
#define SPR_LPCR_P8_PECE4 PPC_BIT(51) /* Wake on MCs, HMIs, etc... */
+#define SPR_LPCR_P9_LD PPC_BIT(46) /* Large decrementer mode bit */
/* Bits in TFMR - control bits */
OpenPOWER on IntegriCloud