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