linux/arch/powerpc/platforms/pseries/mobility.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Support for Partition Mobility/Migration
   4 *
   5 * Copyright (C) 2010 Nathan Fontenot
   6 * Copyright (C) 2010 IBM Corporation
   7 */
   8
   9
  10#define pr_fmt(fmt) "mobility: " fmt
  11
  12#include <linux/cpu.h>
  13#include <linux/kernel.h>
  14#include <linux/kobject.h>
  15#include <linux/sched.h>
  16#include <linux/smp.h>
  17#include <linux/stat.h>
  18#include <linux/completion.h>
  19#include <linux/device.h>
  20#include <linux/delay.h>
  21#include <linux/slab.h>
  22#include <linux/stringify.h>
  23
  24#include <asm/machdep.h>
  25#include <asm/rtas.h>
  26#include "pseries.h"
  27#include "../../kernel/cacheinfo.h"
  28
  29static struct kobject *mobility_kobj;
  30
  31struct update_props_workarea {
  32        __be32 phandle;
  33        __be32 state;
  34        __be64 reserved;
  35        __be32 nprops;
  36} __packed;
  37
  38#define NODE_ACTION_MASK        0xff000000
  39#define NODE_COUNT_MASK         0x00ffffff
  40
  41#define DELETE_DT_NODE  0x01000000
  42#define UPDATE_DT_NODE  0x02000000
  43#define ADD_DT_NODE     0x03000000
  44
  45#define MIGRATION_SCOPE (1)
  46#define PRRN_SCOPE -2
  47
  48static int mobility_rtas_call(int token, char *buf, s32 scope)
  49{
  50        int rc;
  51
  52        spin_lock(&rtas_data_buf_lock);
  53
  54        memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
  55        rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
  56        memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
  57
  58        spin_unlock(&rtas_data_buf_lock);
  59        return rc;
  60}
  61
  62static int delete_dt_node(__be32 phandle)
  63{
  64        struct device_node *dn;
  65
  66        dn = of_find_node_by_phandle(be32_to_cpu(phandle));
  67        if (!dn)
  68                return -ENOENT;
  69
  70        pr_debug("removing node %pOFfp\n", dn);
  71
  72        dlpar_detach_node(dn);
  73        of_node_put(dn);
  74        return 0;
  75}
  76
  77static int update_dt_property(struct device_node *dn, struct property **prop,
  78                              const char *name, u32 vd, char *value)
  79{
  80        struct property *new_prop = *prop;
  81        int more = 0;
  82
  83        /* A negative 'vd' value indicates that only part of the new property
  84         * value is contained in the buffer and we need to call
  85         * ibm,update-properties again to get the rest of the value.
  86         *
  87         * A negative value is also the two's compliment of the actual value.
  88         */
  89        if (vd & 0x80000000) {
  90                vd = ~vd + 1;
  91                more = 1;
  92        }
  93
  94        if (new_prop) {
  95                /* partial property fixup */
  96                char *new_data = kzalloc(new_prop->length + vd, GFP_KERNEL);
  97                if (!new_data)
  98                        return -ENOMEM;
  99
 100                memcpy(new_data, new_prop->value, new_prop->length);
 101                memcpy(new_data + new_prop->length, value, vd);
 102
 103                kfree(new_prop->value);
 104                new_prop->value = new_data;
 105                new_prop->length += vd;
 106        } else {
 107                new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
 108                if (!new_prop)
 109                        return -ENOMEM;
 110
 111                new_prop->name = kstrdup(name, GFP_KERNEL);
 112                if (!new_prop->name) {
 113                        kfree(new_prop);
 114                        return -ENOMEM;
 115                }
 116
 117                new_prop->length = vd;
 118                new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
 119                if (!new_prop->value) {
 120                        kfree(new_prop->name);
 121                        kfree(new_prop);
 122                        return -ENOMEM;
 123                }
 124
 125                memcpy(new_prop->value, value, vd);
 126                *prop = new_prop;
 127        }
 128
 129        if (!more) {
 130                pr_debug("updating node %pOF property %s\n", dn, name);
 131                of_update_property(dn, new_prop);
 132                *prop = NULL;
 133        }
 134
 135        return 0;
 136}
 137
 138static int update_dt_node(__be32 phandle, s32 scope)
 139{
 140        struct update_props_workarea *upwa;
 141        struct device_node *dn;
 142        struct property *prop = NULL;
 143        int i, rc, rtas_rc;
 144        char *prop_data;
 145        char *rtas_buf;
 146        int update_properties_token;
 147        u32 nprops;
 148        u32 vd;
 149
 150        update_properties_token = rtas_token("ibm,update-properties");
 151        if (update_properties_token == RTAS_UNKNOWN_SERVICE)
 152                return -EINVAL;
 153
 154        rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
 155        if (!rtas_buf)
 156                return -ENOMEM;
 157
 158        dn = of_find_node_by_phandle(be32_to_cpu(phandle));
 159        if (!dn) {
 160                kfree(rtas_buf);
 161                return -ENOENT;
 162        }
 163
 164        upwa = (struct update_props_workarea *)&rtas_buf[0];
 165        upwa->phandle = phandle;
 166
 167        do {
 168                rtas_rc = mobility_rtas_call(update_properties_token, rtas_buf,
 169                                        scope);
 170                if (rtas_rc < 0)
 171                        break;
 172
 173                prop_data = rtas_buf + sizeof(*upwa);
 174                nprops = be32_to_cpu(upwa->nprops);
 175
 176                /* On the first call to ibm,update-properties for a node the
 177                 * the first property value descriptor contains an empty
 178                 * property name, the property value length encoded as u32,
 179                 * and the property value is the node path being updated.
 180                 */
 181                if (*prop_data == 0) {
 182                        prop_data++;
 183                        vd = be32_to_cpu(*(__be32 *)prop_data);
 184                        prop_data += vd + sizeof(vd);
 185                        nprops--;
 186                }
 187
 188                for (i = 0; i < nprops; i++) {
 189                        char *prop_name;
 190
 191                        prop_name = prop_data;
 192                        prop_data += strlen(prop_name) + 1;
 193                        vd = be32_to_cpu(*(__be32 *)prop_data);
 194                        prop_data += sizeof(vd);
 195
 196                        switch (vd) {
 197                        case 0x00000000:
 198                                /* name only property, nothing to do */
 199                                break;
 200
 201                        case 0x80000000:
 202                                of_remove_property(dn, of_find_property(dn,
 203                                                        prop_name, NULL));
 204                                prop = NULL;
 205                                break;
 206
 207                        default:
 208                                rc = update_dt_property(dn, &prop, prop_name,
 209                                                        vd, prop_data);
 210                                if (rc) {
 211                                        printk(KERN_ERR "Could not update %s"
 212                                               " property\n", prop_name);
 213                                }
 214
 215                                prop_data += vd;
 216                        }
 217
 218                        cond_resched();
 219                }
 220
 221                cond_resched();
 222        } while (rtas_rc == 1);
 223
 224        of_node_put(dn);
 225        kfree(rtas_buf);
 226        return 0;
 227}
 228
 229static int add_dt_node(__be32 parent_phandle, __be32 drc_index)
 230{
 231        struct device_node *dn;
 232        struct device_node *parent_dn;
 233        int rc;
 234
 235        parent_dn = of_find_node_by_phandle(be32_to_cpu(parent_phandle));
 236        if (!parent_dn)
 237                return -ENOENT;
 238
 239        dn = dlpar_configure_connector(drc_index, parent_dn);
 240        if (!dn) {
 241                of_node_put(parent_dn);
 242                return -ENOENT;
 243        }
 244
 245        rc = dlpar_attach_node(dn, parent_dn);
 246        if (rc)
 247                dlpar_free_cc_nodes(dn);
 248
 249        pr_debug("added node %pOFfp\n", dn);
 250
 251        of_node_put(parent_dn);
 252        return rc;
 253}
 254
 255int pseries_devicetree_update(s32 scope)
 256{
 257        char *rtas_buf;
 258        __be32 *data;
 259        int update_nodes_token;
 260        int rc;
 261
 262        update_nodes_token = rtas_token("ibm,update-nodes");
 263        if (update_nodes_token == RTAS_UNKNOWN_SERVICE)
 264                return -EINVAL;
 265
 266        rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
 267        if (!rtas_buf)
 268                return -ENOMEM;
 269
 270        do {
 271                rc = mobility_rtas_call(update_nodes_token, rtas_buf, scope);
 272                if (rc && rc != 1)
 273                        break;
 274
 275                data = (__be32 *)rtas_buf + 4;
 276                while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
 277                        int i;
 278                        u32 action = be32_to_cpu(*data) & NODE_ACTION_MASK;
 279                        u32 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
 280
 281                        data++;
 282
 283                        for (i = 0; i < node_count; i++) {
 284                                __be32 phandle = *data++;
 285                                __be32 drc_index;
 286
 287                                switch (action) {
 288                                case DELETE_DT_NODE:
 289                                        delete_dt_node(phandle);
 290                                        break;
 291                                case UPDATE_DT_NODE:
 292                                        update_dt_node(phandle, scope);
 293                                        break;
 294                                case ADD_DT_NODE:
 295                                        drc_index = *data++;
 296                                        add_dt_node(phandle, drc_index);
 297                                        break;
 298                                }
 299
 300                                cond_resched();
 301                        }
 302                }
 303
 304                cond_resched();
 305        } while (rc == 1);
 306
 307        kfree(rtas_buf);
 308        return rc;
 309}
 310
 311void post_mobility_fixup(void)
 312{
 313        int rc;
 314        int activate_fw_token;
 315
 316        activate_fw_token = rtas_token("ibm,activate-firmware");
 317        if (activate_fw_token == RTAS_UNKNOWN_SERVICE) {
 318                printk(KERN_ERR "Could not make post-mobility "
 319                       "activate-fw call.\n");
 320                return;
 321        }
 322
 323        do {
 324                rc = rtas_call(activate_fw_token, 0, 1, NULL);
 325        } while (rtas_busy_delay(rc));
 326
 327        if (rc)
 328                printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc);
 329
 330        /*
 331         * We don't want CPUs to go online/offline while the device
 332         * tree is being updated.
 333         */
 334        cpus_read_lock();
 335
 336        /*
 337         * It's common for the destination firmware to replace cache
 338         * nodes.  Release all of the cacheinfo hierarchy's references
 339         * before updating the device tree.
 340         */
 341        cacheinfo_teardown();
 342
 343        rc = pseries_devicetree_update(MIGRATION_SCOPE);
 344        if (rc)
 345                printk(KERN_ERR "Post-mobility device tree update "
 346                        "failed: %d\n", rc);
 347
 348        cacheinfo_rebuild();
 349
 350        cpus_read_unlock();
 351
 352        /* Possibly switch to a new RFI flush type */
 353        pseries_setup_rfi_flush();
 354
 355        /* Reinitialise system information for hv-24x7 */
 356        read_24x7_sys_info();
 357
 358        return;
 359}
 360
 361static ssize_t migration_store(struct class *class,
 362                               struct class_attribute *attr, const char *buf,
 363                               size_t count)
 364{
 365        u64 streamid;
 366        int rc;
 367
 368        rc = kstrtou64(buf, 0, &streamid);
 369        if (rc)
 370                return rc;
 371
 372        do {
 373                rc = rtas_ibm_suspend_me(streamid);
 374                if (rc == -EAGAIN)
 375                        ssleep(1);
 376        } while (rc == -EAGAIN);
 377
 378        if (rc)
 379                return rc;
 380
 381        post_mobility_fixup();
 382
 383        return count;
 384}
 385
 386/*
 387 * Used by drmgr to determine the kernel behavior of the migration interface.
 388 *
 389 * Version 1: Performs all PAPR requirements for migration including
 390 *      firmware activation and device tree update.
 391 */
 392#define MIGRATION_API_VERSION   1
 393
 394static CLASS_ATTR_WO(migration);
 395static CLASS_ATTR_STRING(api_version, 0444, __stringify(MIGRATION_API_VERSION));
 396
 397static int __init mobility_sysfs_init(void)
 398{
 399        int rc;
 400
 401        mobility_kobj = kobject_create_and_add("mobility", kernel_kobj);
 402        if (!mobility_kobj)
 403                return -ENOMEM;
 404
 405        rc = sysfs_create_file(mobility_kobj, &class_attr_migration.attr);
 406        if (rc)
 407                pr_err("unable to create migration sysfs file (%d)\n", rc);
 408
 409        rc = sysfs_create_file(mobility_kobj, &class_attr_api_version.attr.attr);
 410        if (rc)
 411                pr_err("unable to create api_version sysfs file (%d)\n", rc);
 412
 413        return 0;
 414}
 415machine_device_initcall(pseries, mobility_sysfs_init);
 416