root/drivers/misc/cxl/flash.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rcall
  2. update_property
  3. update_node
  4. update_devicetree
  5. handle_image
  6. transfer_image
  7. ioctl_transfer_image
  8. device_open
  9. device_ioctl
  10. device_compat_ioctl
  11. device_close
  12. cxl_guest_remove_chardev
  13. cxl_guest_add_chardev

   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 
  15 struct 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 
  27 static struct semaphore sem;
  28 static unsigned long *buffer[CXL_AI_MAX_ENTRIES];
  29 static struct sg_list *le;
  30 static u64 continue_token;
  31 static unsigned int transfer;
  32 
  33 struct update_props_workarea {
  34         __be32 phandle;
  35         __be32 state;
  36         __be64 reserved;
  37         __be32 nprops;
  38 } __packed;
  39 
  40 struct 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 
  53 static 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 
  67 static 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 
 106 static 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 
 173 static 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 
 227 static 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 
 316 err:
 317         kfree(header);
 318 
 319         return rc;
 320 }
 321 
 322 static 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 
 371 static 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 
 391 static 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 
 442 err1:
 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);
 450 err:
 451         put_device(&adapter->dev);
 452 err_unlock:
 453         up(&sem);
 454 
 455         return rc;
 456 }
 457 
 458 static 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 
 476 static long device_compat_ioctl(struct file *file, unsigned int cmd,
 477                                 unsigned long arg)
 478 {
 479         return device_ioctl(file, cmd, arg);
 480 }
 481 
 482 static 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 
 513 static 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 
 521 void cxl_guest_remove_chardev(struct cxl *adapter)
 522 {
 523         cdev_del(&adapter->guest->cdev);
 524 }
 525 
 526 int 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);
 541 err:
 542         return rc;
 543 }

/* [<][>][^][v][top][bottom][index][help] */