powerpc/pseries: Pass more accurate number of supported cores to firmware
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 4 Feb 2010 03:33:54 +0000 (14:33 +1100)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Thu, 4 Feb 2010 03:33:54 +0000 (14:33 +1100)
Updated variant of a patch by Joel Schopp.

The field containing the number of supported cores which we pass to
firmware via the ibm,client-architecture call was set by a previous
patch statically as high as is possible (NR_CPUS).

However, that value isn't quite right for a system that supports
multiple threads per core, thus permitting the firmware to assign
more cores to a Linux partition than it can really cope with.

This patch improves it by using the device-tree to determine the
number of threads supported by the processors in order to adjust
the value passed to firmware.

Signed-off-by: Joel Schopp <jschopp@austin.ibm.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/kernel/prom_init.c

index 59d5bd1..5f306c4 100644 (file)
@@ -710,7 +710,12 @@ static unsigned char ibm_architecture_vec[] = {
        0,
        0,
        0,
-       W(NR_CPUS),                     /* number of cores supported*/
+       /* WARNING: The offset of the "number of cores" field below
+        * must match by the macro below. Update the definition if
+        * the structure layout changes.
+        */
+#define IBM_ARCH_VEC_NRCORES_OFFSET    100
+       W(NR_CPUS),                     /* number of cores supported */
 
        /* option vector 6: IBM PAPR hints */
        4 - 2,                          /* length */
@@ -807,13 +812,70 @@ static struct fake_elf {
        }
 };
 
+static int __init prom_count_smt_threads(void)
+{
+       phandle node;
+       char type[64];
+       unsigned int plen;
+
+       /* Pick up th first CPU node we can find */
+       for (node = 0; prom_next_node(&node); ) {
+               type[0] = 0;
+               prom_getprop(node, "device_type", type, sizeof(type));
+
+               if (strcmp(type, RELOC("cpu")))
+                       continue;
+               /*
+                * There is an entry for each smt thread, each entry being
+                * 4 bytes long.  All cpus should have the same number of
+                * smt threads, so return after finding the first.
+                */
+               plen = prom_getproplen(node, "ibm,ppc-interrupt-server#s");
+               if (plen == PROM_ERROR)
+                       break;
+               plen >>= 2;
+               prom_debug("Found 0x%x smt threads per core\n", (unsigned long)plen);
+
+               /* Sanity check */
+               if (plen < 1 || plen > 64) {
+                       prom_printf("Threads per core 0x%x out of bounds, assuming 1\n",
+                                   (unsigned long)plen);
+                       return 1;
+               }
+               return plen;
+       }
+       prom_debug("No threads found, assuming 1 per core\n");
+
+       return 1;
+
+}
+
+
 static void __init prom_send_capabilities(void)
 {
        ihandle elfloader, root;
        prom_arg_t ret;
+       u32 *cores;
 
        root = call_prom("open", 1, 1, ADDR("/"));
        if (root != 0) {
+               /* We need to tell the FW about the number of cores we support.
+                *
+                * To do that, we count the number of threads on the first core
+                * (we assume this is the same for all cores) and use it to
+                * divide NR_CPUS.
+                */
+               cores = (u32 *)PTRRELOC(&ibm_architecture_vec[IBM_ARCH_VEC_NRCORES_OFFSET]);
+               if (*cores != NR_CPUS) {
+                       prom_printf("WARNING ! "
+                                   "ibm_architecture_vec structure inconsistent: 0x%x !\n",
+                                   *cores);
+               } else {
+                       *cores = NR_CPUS / prom_count_smt_threads();
+                       prom_printf("Max number of cores passed to firmware: 0x%x\n",
+                                   (unsigned long)*cores);
+               }
+
                /* try calling the ibm,client-architecture-support method */
                prom_printf("Calling ibm,client-architecture-support...");
                if (call_prom_ret("call-method", 3, 2, &ret,