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