linux/drivers/misc/cxl/flash.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/kernel.h>
   3#include <linux/fs.h>
   4#include <linux/semaphore.h>
   5#include <linux/slab.h>
   6#include <linux/uaccess.h>
   7#include <asm/rtas.h>
   8
   9#include "cxl.h"
  10#include "hcalls.h"
  11
  12#define DOWNLOAD_IMAGE 1
  13#define VALIDATE_IMAGE 2
  14
  15struct ai_header {
  16        u16 version;
  17        u8  reserved0[6];
  18        u16 vendor;
  19        u16 device;
  20        u16 subsystem_vendor;
  21        u16 subsystem;
  22        u64 image_offset;
  23        u64 image_length;
  24        u8  reserved1[96];
  25};
  26
  27static struct semaphore sem;
  28static unsigned long *buffer[CXL_AI_MAX_ENTRIES];
  29static struct sg_list *le;
  30static u64 continue_token;
  31static unsigned int transfer;
  32
  33struct update_props_workarea {
  34        __be32 phandle;
  35        __be32 state;
  36        __be64 reserved;
  37        __be32 nprops;
  38} __packed;
  39
  40struct update_nodes_workarea {
  41        __be32 state;
  42        __be64 unit_address;
  43        __be32 reserved;
  44} __packed;
  45
  46#define DEVICE_SCOPE 3
  47#define NODE_ACTION_MASK        0xff000000
  48#define NODE_COUNT_MASK         0x00ffffff
  49#define OPCODE_DELETE   0x01000000
  50#define OPCODE_UPDATE   0x02000000
  51#define OPCODE_ADD      0x03000000
  52
  53static int rcall(int token, char *buf, s32 scope)
  54{
  55        int rc;
  56
  57        spin_lock(&rtas_data_buf_lock);
  58
  59        memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
  60        rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
  61        memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
  62
  63        spin_unlock(&rtas_data_buf_lock);
  64        return rc;
  65}
  66
  67static int update_property(struct device_node *dn, const char *name,
  68                           u32 vd, char *value)
  69{
  70        struct property *new_prop;
  71        u32 *val;
  72        int rc;
  73
  74        new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
  75        if (!new_prop)
  76                return -ENOMEM;
  77
  78        new_prop->name = kstrdup(name, GFP_KERNEL);
  79        if (!new_prop->name) {
  80                kfree(new_prop);
  81                return -ENOMEM;
  82        }
  83
  84        new_prop->length = vd;
  85        new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
  86        if (!new_prop->value) {
  87                kfree(new_prop->name);
  88                kfree(new_prop);
  89                return -ENOMEM;
  90        }
  91        memcpy(new_prop->value, value, vd);
  92
  93        val = (u32 *)new_prop->value;
  94        rc = cxl_update_properties(dn, new_prop);
  95        pr_devel("%pOFn: update property (%s, length: %i, value: %#x)\n",
  96                  dn, name, vd, be32_to_cpu(*val));
  97
  98        if (rc) {
  99                kfree(new_prop->name);
 100                kfree(new_prop->value);
 101                kfree(new_prop);
 102        }
 103        return rc;
 104}
 105
 106static int update_node(__be32 phandle, s32 scope)
 107{
 108        struct update_props_workarea *upwa;
 109        struct device_node *dn;
 110        int i, rc, ret;
 111        char *prop_data;
 112        char *buf;
 113        int token;
 114        u32 nprops;
 115        u32 vd;
 116
 117        token = rtas_token("ibm,update-properties");
 118        if (token == RTAS_UNKNOWN_SERVICE)
 119                return -EINVAL;
 120
 121        buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
 122        if (!buf)
 123                return -ENOMEM;
 124
 125        dn = of_find_node_by_phandle(be32_to_cpu(phandle));
 126        if (!dn) {
 127                kfree(buf);
 128                return -ENOENT;
 129        }
 130
 131        upwa = (struct update_props_workarea *)&buf[0];
 132        upwa->phandle = phandle;
 133        do {
 134                rc = rcall(token, buf, scope);
 135                if (rc < 0)
 136                        break;
 137
 138                prop_data = buf + sizeof(*upwa);
 139                nprops = be32_to_cpu(upwa->nprops);
 140
 141                if (*prop_data == 0) {
 142                        prop_data++;
 143                        vd = be32_to_cpu(*(__be32 *)prop_data);
 144                        prop_data += vd + sizeof(vd);
 145                        nprops--;
 146                }
 147
 148                for (i = 0; i < nprops; i++) {
 149                        char *prop_name;
 150
 151                        prop_name = prop_data;
 152                        prop_data += strlen(prop_name) + 1;
 153                        vd = be32_to_cpu(*(__be32 *)prop_data);
 154                        prop_data += sizeof(vd);
 155
 156                        if ((vd != 0x00000000) && (vd != 0x80000000)) {
 157                                ret = update_property(dn, prop_name, vd,
 158                                                prop_data);
 159                                if (ret)
 160                                        pr_err("cxl: Could not update property %s - %i\n",
 161                                               prop_name, ret);
 162
 163                                prop_data += vd;
 164                        }
 165                }
 166        } while (rc == 1);
 167
 168        of_node_put(dn);
 169        kfree(buf);
 170        return rc;
 171}
 172
 173static int update_devicetree(struct cxl *adapter, s32 scope)
 174{
 175        struct update_nodes_workarea *unwa;
 176        u32 action, node_count;
 177        int token, rc, i;
 178        __be32 *data, drc_index, phandle;
 179        char *buf;
 180
 181        token = rtas_token("ibm,update-nodes");
 182        if (token == RTAS_UNKNOWN_SERVICE)
 183                return -EINVAL;
 184
 185        buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
 186        if (!buf)
 187                return -ENOMEM;
 188
 189        unwa = (struct update_nodes_workarea *)&buf[0];
 190        unwa->unit_address = cpu_to_be64(adapter->guest->handle);
 191        do {
 192                rc = rcall(token, buf, scope);
 193                if (rc && rc != 1)
 194                        break;
 195
 196                data = (__be32 *)buf + 4;
 197                while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
 198                        action = be32_to_cpu(*data) & NODE_ACTION_MASK;
 199                        node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
 200                        pr_devel("device reconfiguration - action: %#x, nodes: %#x\n",
 201                                 action, node_count);
 202                        data++;
 203
 204                        for (i = 0; i < node_count; i++) {
 205                                phandle = *data++;
 206
 207                                switch (action) {
 208                                case OPCODE_DELETE:
 209                                        /* nothing to do */
 210                                        break;
 211                                case OPCODE_UPDATE:
 212                                        update_node(phandle, scope);
 213                                        break;
 214                                case OPCODE_ADD:
 215                                        /* nothing to do, just move pointer */
 216                                        drc_index = *data++;
 217                                        break;
 218                                }
 219                        }
 220                }
 221        } while (rc == 1);
 222
 223        kfree(buf);
 224        return 0;
 225}
 226
 227static int handle_image(struct cxl *adapter, int operation,
 228                        long (*fct)(u64, u64, u64, u64 *),
 229                        struct cxl_adapter_image *ai)
 230{
 231        size_t mod, s_copy, len_chunk = 0;
 232        struct ai_header *header = NULL;
 233        unsigned int entries = 0, i;
 234        void *dest, *from;
 235        int rc = 0, need_header;
 236
 237        /* base adapter image header */
 238        need_header = (ai->flags & CXL_AI_NEED_HEADER);
 239        if (need_header) {
 240                header = kzalloc(sizeof(struct ai_header), GFP_KERNEL);
 241                if (!header)
 242                        return -ENOMEM;
 243                header->version = cpu_to_be16(1);
 244                header->vendor = cpu_to_be16(adapter->guest->vendor);
 245                header->device = cpu_to_be16(adapter->guest->device);
 246                header->subsystem_vendor = cpu_to_be16(adapter->guest->subsystem_vendor);
 247                header->subsystem = cpu_to_be16(adapter->guest->subsystem);
 248                header->image_offset = cpu_to_be64(CXL_AI_HEADER_SIZE);
 249                header->image_length = cpu_to_be64(ai->len_image);
 250        }
 251
 252        /* number of entries in the list */
 253        len_chunk = ai->len_data;
 254        if (need_header)
 255                len_chunk += CXL_AI_HEADER_SIZE;
 256
 257        entries = len_chunk / CXL_AI_BUFFER_SIZE;
 258        mod = len_chunk % CXL_AI_BUFFER_SIZE;
 259        if (mod)
 260                entries++;
 261
 262        if (entries > CXL_AI_MAX_ENTRIES) {
 263                rc = -EINVAL;
 264                goto err;
 265        }
 266
 267        /*          < -- MAX_CHUNK_SIZE = 4096 * 256 = 1048576 bytes -->
 268         * chunk 0  ----------------------------------------------------
 269         *          | header   |  data                                 |
 270         *          ----------------------------------------------------
 271         * chunk 1  ----------------------------------------------------
 272         *          | data                                             |
 273         *          ----------------------------------------------------
 274         * ....
 275         * chunk n  ----------------------------------------------------
 276         *          | data                                             |
 277         *          ----------------------------------------------------
 278         */
 279        from = (void *) ai->data;
 280        for (i = 0; i < entries; i++) {
 281                dest = buffer[i];
 282                s_copy = CXL_AI_BUFFER_SIZE;
 283
 284                if ((need_header) && (i == 0)) {
 285                        /* add adapter image header */
 286                        memcpy(buffer[i], header, sizeof(struct ai_header));
 287                        s_copy = CXL_AI_BUFFER_SIZE - CXL_AI_HEADER_SIZE;
 288                        dest += CXL_AI_HEADER_SIZE; /* image offset */
 289                }
 290                if ((i == (entries - 1)) && mod)
 291                        s_copy = mod;
 292
 293                /* copy data */
 294                if (copy_from_user(dest, from, s_copy))
 295                        goto err;
 296
 297                /* fill in the list */
 298                le[i].phys_addr = cpu_to_be64(virt_to_phys(buffer[i]));
 299                le[i].len = cpu_to_be64(CXL_AI_BUFFER_SIZE);
 300                if ((i == (entries - 1)) && mod)
 301                        le[i].len = cpu_to_be64(mod);
 302                from += s_copy;
 303        }
 304        pr_devel("%s (op: %i, need header: %i, entries: %i, token: %#llx)\n",
 305                 __func__, operation, need_header, entries, continue_token);
 306
 307        /*
 308         * download/validate the adapter image to the coherent
 309         * platform facility
 310         */
 311        rc = fct(adapter->guest->handle, virt_to_phys(le), entries,
 312                &continue_token);
 313        if (rc == 0) /* success of download/validation operation */
 314                continue_token = 0;
 315
 316err:
 317        kfree(header);
 318
 319        return rc;
 320}
 321
 322static int transfer_image(struct cxl *adapter, int operation,
 323                        struct cxl_adapter_image *ai)
 324{
 325        int rc = 0;
 326        int afu;
 327
 328        switch (operation) {
 329        case DOWNLOAD_IMAGE:
 330                rc = handle_image(adapter, operation,
 331                                &cxl_h_download_adapter_image, ai);
 332                if (rc < 0) {
 333                        pr_devel("resetting adapter\n");
 334                        cxl_h_reset_adapter(adapter->guest->handle);
 335                }
 336                return rc;
 337
 338        case VALIDATE_IMAGE:
 339                rc = handle_image(adapter, operation,
 340                                &cxl_h_validate_adapter_image, ai);
 341                if (rc < 0) {
 342                        pr_devel("resetting adapter\n");
 343                        cxl_h_reset_adapter(adapter->guest->handle);
 344                        return rc;
 345                }
 346                if (rc == 0) {
 347                        pr_devel("remove current afu\n");
 348                        for (afu = 0; afu < adapter->slices; afu++)
 349                                cxl_guest_remove_afu(adapter->afu[afu]);
 350
 351                        pr_devel("resetting adapter\n");
 352                        cxl_h_reset_adapter(adapter->guest->handle);
 353
 354                        /* The entire image has now been
 355                         * downloaded and the validation has
 356                         * been successfully performed.
 357                         * After that, the partition should call
 358                         * ibm,update-nodes and
 359                         * ibm,update-properties to receive the
 360                         * current configuration
 361                         */
 362                        rc = update_devicetree(adapter, DEVICE_SCOPE);
 363                        transfer = 1;
 364                }
 365                return rc;
 366        }
 367
 368        return -EINVAL;
 369}
 370
 371static long ioctl_transfer_image(struct cxl *adapter, int operation,
 372                                struct cxl_adapter_image __user *uai)
 373{
 374        struct cxl_adapter_image ai;
 375
 376        pr_devel("%s\n", __func__);
 377
 378        if (copy_from_user(&ai, uai, sizeof(struct cxl_adapter_image)))
 379                return -EFAULT;
 380
 381        /*
 382         * Make sure reserved fields and bits are set to 0
 383         */
 384        if (ai.reserved1 || ai.reserved2 || ai.reserved3 || ai.reserved4 ||
 385                (ai.flags & ~CXL_AI_ALL))
 386                return -EINVAL;
 387
 388        return transfer_image(adapter, operation, &ai);
 389}
 390
 391static int device_open(struct inode *inode, struct file *file)
 392{
 393        int adapter_num = CXL_DEVT_ADAPTER(inode->i_rdev);
 394        struct cxl *adapter;
 395        int rc = 0, i;
 396
 397        pr_devel("in %s\n", __func__);
 398
 399        BUG_ON(sizeof(struct ai_header) != CXL_AI_HEADER_SIZE);
 400
 401        /* Allows one process to open the device by using a semaphore */
 402        if (down_interruptible(&sem) != 0)
 403                return -EPERM;
 404
 405        if (!(adapter = get_cxl_adapter(adapter_num))) {
 406                rc = -ENODEV;
 407                goto err_unlock;
 408        }
 409
 410        file->private_data = adapter;
 411        continue_token = 0;
 412        transfer = 0;
 413
 414        for (i = 0; i < CXL_AI_MAX_ENTRIES; i++)
 415                buffer[i] = NULL;
 416
 417        /* aligned buffer containing list entries which describes up to
 418         * 1 megabyte of data (256 entries of 4096 bytes each)
 419         *  Logical real address of buffer 0  -  Buffer 0 length in bytes
 420         *  Logical real address of buffer 1  -  Buffer 1 length in bytes
 421         *  Logical real address of buffer 2  -  Buffer 2 length in bytes
 422         *  ....
 423         *  ....
 424         *  Logical real address of buffer N  -  Buffer N length in bytes
 425         */
 426        le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
 427        if (!le) {
 428                rc = -ENOMEM;
 429                goto err;
 430        }
 431
 432        for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
 433                buffer[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL);
 434                if (!buffer[i]) {
 435                        rc = -ENOMEM;
 436                        goto err1;
 437                }
 438        }
 439
 440        return 0;
 441
 442err1:
 443        for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
 444                if (buffer[i])
 445                        free_page((unsigned long) buffer[i]);
 446        }
 447
 448        if (le)
 449                free_page((unsigned long) le);
 450err:
 451        put_device(&adapter->dev);
 452err_unlock:
 453        up(&sem);
 454
 455        return rc;
 456}
 457
 458static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 459{
 460        struct cxl *adapter = file->private_data;
 461
 462        pr_devel("in %s\n", __func__);
 463
 464        if (cmd == CXL_IOCTL_DOWNLOAD_IMAGE)
 465                return ioctl_transfer_image(adapter,
 466                                        DOWNLOAD_IMAGE,
 467                                        (struct cxl_adapter_image __user *)arg);
 468        else if (cmd == CXL_IOCTL_VALIDATE_IMAGE)
 469                return ioctl_transfer_image(adapter,
 470                                        VALIDATE_IMAGE,
 471                                        (struct cxl_adapter_image __user *)arg);
 472        else
 473                return -EINVAL;
 474}
 475
 476static long device_compat_ioctl(struct file *file, unsigned int cmd,
 477                                unsigned long arg)
 478{
 479        return device_ioctl(file, cmd, arg);
 480}
 481
 482static int device_close(struct inode *inode, struct file *file)
 483{
 484        struct cxl *adapter = file->private_data;
 485        int i;
 486
 487        pr_devel("in %s\n", __func__);
 488
 489        for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
 490                if (buffer[i])
 491                        free_page((unsigned long) buffer[i]);
 492        }
 493
 494        if (le)
 495                free_page((unsigned long) le);
 496
 497        up(&sem);
 498        put_device(&adapter->dev);
 499        continue_token = 0;
 500
 501        /* reload the module */
 502        if (transfer)
 503                cxl_guest_reload_module(adapter);
 504        else {
 505                pr_devel("resetting adapter\n");
 506                cxl_h_reset_adapter(adapter->guest->handle);
 507        }
 508
 509        transfer = 0;
 510        return 0;
 511}
 512
 513static const struct file_operations fops = {
 514        .owner          = THIS_MODULE,
 515        .open           = device_open,
 516        .unlocked_ioctl = device_ioctl,
 517        .compat_ioctl   = device_compat_ioctl,
 518        .release        = device_close,
 519};
 520
 521void cxl_guest_remove_chardev(struct cxl *adapter)
 522{
 523        cdev_del(&adapter->guest->cdev);
 524}
 525
 526int cxl_guest_add_chardev(struct cxl *adapter)
 527{
 528        dev_t devt;
 529        int rc;
 530
 531        devt = MKDEV(MAJOR(cxl_get_dev()), CXL_CARD_MINOR(adapter));
 532        cdev_init(&adapter->guest->cdev, &fops);
 533        if ((rc = cdev_add(&adapter->guest->cdev, devt, 1))) {
 534                dev_err(&adapter->dev,
 535                        "Unable to add chardev on adapter (card%i): %i\n",
 536                        adapter->adapter_num, rc);
 537                goto err;
 538        }
 539        adapter->dev.devt = devt;
 540        sema_init(&sem, 1);
 541err:
 542        return rc;
 543}
 544