linux/arch/powerpc/platforms/pseries/firmware.c
<<
>>
Prefs
   1/*
   2 *  pSeries firmware setup code.
   3 *
   4 *  Portions from arch/powerpc/platforms/pseries/setup.c:
   5 *   Copyright (C) 1995  Linus Torvalds
   6 *   Adapted from 'alpha' version by Gary Thomas
   7 *   Modified by Cort Dougan (cort@cs.nmt.edu)
   8 *   Modified by PPC64 Team, IBM Corp
   9 *
  10 *  Portions from arch/powerpc/kernel/firmware.c
  11 *   Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org)
  12 *   Modifications for ppc64:
  13 *    Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com>
  14 *    Copyright (C) 2005 Stephen Rothwell, IBM Corporation
  15 *
  16 *  Copyright 2006 IBM Corporation.
  17 *
  18 * This program is free software; you can redistribute it and/or
  19 * modify it under the terms of the GNU General Public License
  20 * as published by the Free Software Foundation; either version
  21 * 2 of the License, or (at your option) any later version.
  22 */
  23
  24
  25#include <linux/of_fdt.h>
  26#include <asm/firmware.h>
  27#include <asm/prom.h>
  28#include <asm/udbg.h>
  29
  30#include "pseries.h"
  31
  32struct hypertas_fw_feature {
  33    unsigned long val;
  34    char * name;
  35};
  36
  37/*
  38 * The names in this table match names in rtas/ibm,hypertas-functions.  If the
  39 * entry ends in a '*', only upto the '*' is matched.  Otherwise the entire
  40 * string must match.
  41 */
  42static __initdata struct hypertas_fw_feature
  43hypertas_fw_features_table[] = {
  44        {FW_FEATURE_PFT,                "hcall-pft"},
  45        {FW_FEATURE_TCE,                "hcall-tce"},
  46        {FW_FEATURE_SPRG0,              "hcall-sprg0"},
  47        {FW_FEATURE_DABR,               "hcall-dabr"},
  48        {FW_FEATURE_COPY,               "hcall-copy"},
  49        {FW_FEATURE_ASR,                "hcall-asr"},
  50        {FW_FEATURE_DEBUG,              "hcall-debug"},
  51        {FW_FEATURE_PERF,               "hcall-perf"},
  52        {FW_FEATURE_DUMP,               "hcall-dump"},
  53        {FW_FEATURE_INTERRUPT,          "hcall-interrupt"},
  54        {FW_FEATURE_MIGRATE,            "hcall-migrate"},
  55        {FW_FEATURE_PERFMON,            "hcall-perfmon"},
  56        {FW_FEATURE_CRQ,                "hcall-crq"},
  57        {FW_FEATURE_VIO,                "hcall-vio"},
  58        {FW_FEATURE_RDMA,               "hcall-rdma"},
  59        {FW_FEATURE_LLAN,               "hcall-lLAN"},
  60        {FW_FEATURE_BULK_REMOVE,        "hcall-bulk"},
  61        {FW_FEATURE_XDABR,              "hcall-xdabr"},
  62        {FW_FEATURE_MULTITCE,           "hcall-multi-tce"},
  63        {FW_FEATURE_SPLPAR,             "hcall-splpar"},
  64        {FW_FEATURE_VPHN,               "hcall-vphn"},
  65        {FW_FEATURE_SET_MODE,           "hcall-set-mode"},
  66        {FW_FEATURE_BEST_ENERGY,        "hcall-best-energy-1*"},
  67        {FW_FEATURE_HPT_RESIZE,         "hcall-hpt-resize"},
  68};
  69
  70/* Build up the firmware features bitmask using the contents of
  71 * device-tree/ibm,hypertas-functions.  Ultimately this functionality may
  72 * be moved into prom.c prom_init().
  73 */
  74static void __init fw_hypertas_feature_init(const char *hypertas,
  75                                            unsigned long len)
  76{
  77        const char *s;
  78        int i;
  79
  80        pr_debug(" -> fw_hypertas_feature_init()\n");
  81
  82        for (s = hypertas; s < hypertas + len; s += strlen(s) + 1) {
  83                for (i = 0; i < ARRAY_SIZE(hypertas_fw_features_table); i++) {
  84                        const char *name = hypertas_fw_features_table[i].name;
  85                        size_t size;
  86
  87                        /*
  88                         * If there is a '*' at the end of name, only check
  89                         * upto there
  90                         */
  91                        size = strlen(name);
  92                        if (size && name[size - 1] == '*') {
  93                                if (strncmp(name, s, size - 1))
  94                                        continue;
  95                        } else if (strcmp(name, s))
  96                                continue;
  97
  98                        /* we have a match */
  99                        powerpc_firmware_features |=
 100                                hypertas_fw_features_table[i].val;
 101                        break;
 102                }
 103        }
 104
 105        pr_debug(" <- fw_hypertas_feature_init()\n");
 106}
 107
 108struct vec5_fw_feature {
 109        unsigned long   val;
 110        unsigned int    feature;
 111};
 112
 113static __initdata struct vec5_fw_feature
 114vec5_fw_features_table[] = {
 115        {FW_FEATURE_TYPE1_AFFINITY,     OV5_TYPE1_AFFINITY},
 116        {FW_FEATURE_PRRN,               OV5_PRRN},
 117};
 118
 119static void __init fw_vec5_feature_init(const char *vec5, unsigned long len)
 120{
 121        unsigned int index, feat;
 122        int i;
 123
 124        pr_debug(" -> fw_vec5_feature_init()\n");
 125
 126        for (i = 0; i < ARRAY_SIZE(vec5_fw_features_table); i++) {
 127                index = OV5_INDX(vec5_fw_features_table[i].feature);
 128                feat = OV5_FEAT(vec5_fw_features_table[i].feature);
 129
 130                if (index < len && (vec5[index] & feat))
 131                        powerpc_firmware_features |=
 132                                vec5_fw_features_table[i].val;
 133        }
 134
 135        pr_debug(" <- fw_vec5_feature_init()\n");
 136}
 137
 138/*
 139 * Called very early, MMU is off, device-tree isn't unflattened
 140 */
 141static int __init probe_fw_features(unsigned long node, const char *uname, int
 142                                    depth, void *data)
 143{
 144        const char *prop;
 145        int len;
 146        static int hypertas_found;
 147        static int vec5_found;
 148
 149        if (depth != 1)
 150                return 0;
 151
 152        if (!strcmp(uname, "rtas") || !strcmp(uname, "rtas@0")) {
 153                prop = of_get_flat_dt_prop(node, "ibm,hypertas-functions",
 154                                           &len);
 155                if (prop) {
 156                        powerpc_firmware_features |= FW_FEATURE_LPAR;
 157                        fw_hypertas_feature_init(prop, len);
 158                }
 159
 160                hypertas_found = 1;
 161        }
 162
 163        if (!strcmp(uname, "chosen")) {
 164                prop = of_get_flat_dt_prop(node, "ibm,architecture-vec-5",
 165                                           &len);
 166                if (prop)
 167                        fw_vec5_feature_init(prop, len);
 168
 169                vec5_found = 1;
 170        }
 171
 172        return hypertas_found && vec5_found;
 173}
 174
 175void __init pseries_probe_fw_features(void)
 176{
 177        of_scan_flat_dt(probe_fw_features, NULL);
 178}
 179