Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cxl: Support to flash a new image on the adapter from a guest

The new flash.c file contains the logic to flash a new image on the
adapter, through a hcall. It is an iterative process, with chunks of
data of 1M at a time. There are also 2 phases: write and verify. The
flash operation itself is driven from a user-land tool.
Once flashing is successful, an rtas call is made to update the device
tree with the new properties values for the adapter and the AFU(s)

Add a new char device for the adapter, so that the flash tool can
access the card, even if there is no valid AFU on it.

Co-authored-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
Signed-off-by: Frederic Barrat <fbarrat@linux.vnet.ibm.com>
Signed-off-by: Christophe Lombard <clombard@linux.vnet.ibm.com>
Reviewed-by: Manoj Kumar <manoj@linux.vnet.ibm.com>
Acked-by: Ian Munsie <imunsie@au1.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Christophe Lombard
Frederic Barrat
and committed by
Michael Ellerman
594ff7d0 4752876c

+653 -5
+55
Documentation/powerpc/cxl.txt
··· 116 116 User API 117 117 ======== 118 118 119 + 1. AFU character devices 120 + 119 121 For AFUs operating in AFU directed mode, two character device 120 122 files will be created. /dev/cxl/afu0.0m will correspond to a 121 123 master context and /dev/cxl/afu0.0s will correspond to a slave ··· 363 361 364 362 reserved fields: 365 363 For future extensions and padding 364 + 365 + 366 + 2. Card character device (powerVM guest only) 367 + 368 + In a powerVM guest, an extra character device is created for the 369 + card. The device is only used to write (flash) a new image on the 370 + FPGA accelerator. Once the image is written and verified, the 371 + device tree is updated and the card is reset to reload the updated 372 + image. 373 + 374 + open 375 + ---- 376 + 377 + Opens the device and allocates a file descriptor to be used with 378 + the rest of the API. The device can only be opened once. 379 + 380 + ioctl 381 + ----- 382 + 383 + CXL_IOCTL_DOWNLOAD_IMAGE: 384 + CXL_IOCTL_VALIDATE_IMAGE: 385 + Starts and controls flashing a new FPGA image. Partial 386 + reconfiguration is not supported (yet), so the image must contain 387 + a copy of the PSL and AFU(s). Since an image can be quite large, 388 + the caller may have to iterate, splitting the image in smaller 389 + chunks. 390 + 391 + Takes a pointer to a struct cxl_adapter_image: 392 + struct cxl_adapter_image { 393 + __u64 flags; 394 + __u64 data; 395 + __u64 len_data; 396 + __u64 len_image; 397 + __u64 reserved1; 398 + __u64 reserved2; 399 + __u64 reserved3; 400 + __u64 reserved4; 401 + }; 402 + 403 + flags: 404 + These flags indicate which optional fields are present in 405 + this struct. Currently all fields are mandatory. 406 + 407 + data: 408 + Pointer to a buffer with part of the image to write to the 409 + card. 410 + 411 + len_data: 412 + Size of the buffer pointed to by data. 413 + 414 + len_image: 415 + Full size of the image. 416 + 366 417 367 418 Sysfs Class 368 419 ===========
+1 -1
drivers/misc/cxl/Makefile
··· 4 4 cxl-y += main.o file.o irq.o fault.o native.o 5 5 cxl-y += context.o sysfs.o debugfs.o pci.o trace.o 6 6 cxl-y += vphb.o api.o 7 - cxl-$(CONFIG_PPC_PSERIES) += guest.o of.o hcalls.o 7 + cxl-$(CONFIG_PPC_PSERIES) += flash.o guest.o of.o hcalls.o 8 8 obj-$(CONFIG_CXL) += cxl.o 9 9 obj-$(CONFIG_CXL_BASE) += base.o 10 10
+7
drivers/misc/cxl/base.c
··· 84 84 synchronize_rcu(); 85 85 } 86 86 EXPORT_SYMBOL_GPL(unregister_cxl_calls); 87 + 88 + int cxl_update_properties(struct device_node *dn, 89 + struct property *new_prop) 90 + { 91 + return of_update_property(dn, new_prop); 92 + } 93 + EXPORT_SYMBOL_GPL(cxl_update_properties);
+6
drivers/misc/cxl/cxl.h
··· 324 324 #define CXL_MODE_TIME_SLICED 0x4 325 325 #define CXL_SUPPORTED_MODES (CXL_MODE_DEDICATED | CXL_MODE_DIRECTED) 326 326 327 + #define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */ 328 + #define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS) 329 + #define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS) 330 + 327 331 enum cxl_context_status { 328 332 CLOSED, 329 333 OPENED, ··· 696 692 }; 697 693 int register_cxl_calls(struct cxl_calls *calls); 698 694 void unregister_cxl_calls(struct cxl_calls *calls); 695 + int cxl_update_properties(struct device_node *dn, struct property *new_prop); 699 696 700 697 void cxl_remove_adapter_nr(struct cxl *adapter); 701 698 702 699 int cxl_alloc_spa(struct cxl_afu *afu); 703 700 void cxl_release_spa(struct cxl_afu *afu); 704 701 702 + dev_t cxl_get_dev(void); 705 703 int cxl_file_init(void); 706 704 void cxl_file_exit(void); 707 705 int cxl_register_adapter(struct cxl *adapter);
+7 -4
drivers/misc/cxl/file.c
··· 26 26 #include "trace.h" 27 27 28 28 #define CXL_NUM_MINORS 256 /* Total to reserve */ 29 - #define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */ 30 29 31 - #define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS) 32 30 #define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice)) 33 31 #define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1) 34 32 #define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2) ··· 34 36 #define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu)) 35 37 #define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu)) 36 38 37 - #define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS) 38 39 #define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3) 39 40 40 41 #define CXL_DEVT_IS_CARD(dev) (MINOR(dev) % CXL_DEV_MINORS == 0) ··· 443 446 444 447 static char *cxl_devnode(struct device *dev, umode_t *mode) 445 448 { 446 - if (CXL_DEVT_IS_CARD(dev->devt)) { 449 + if (cpu_has_feature(CPU_FTR_HVMODE) && 450 + CXL_DEVT_IS_CARD(dev->devt)) { 447 451 /* 448 452 * These minor numbers will eventually be used to program the 449 453 * PSL and AFUs once we have dynamic reprogramming support ··· 543 545 */ 544 546 545 547 return device_register(&adapter->dev); 548 + } 549 + 550 + dev_t cxl_get_dev(void) 551 + { 552 + return cxl_dev; 546 553 } 547 554 548 555 int __init cxl_file_init(void)
+538
drivers/misc/cxl/flash.c
··· 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 + 14 + struct 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 + 26 + static struct semaphore sem; 27 + unsigned long *buffer[CXL_AI_MAX_ENTRIES]; 28 + struct sg_list *le; 29 + static u64 continue_token; 30 + static unsigned int transfer; 31 + 32 + struct update_props_workarea { 33 + __be32 phandle; 34 + __be32 state; 35 + __be64 reserved; 36 + __be32 nprops; 37 + } __packed; 38 + 39 + struct 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 + 52 + static 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 + 66 + static 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 + 105 + static 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 + 172 + static 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 + 226 + static 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 + 315 + err: 316 + kfree(header); 317 + 318 + return rc; 319 + } 320 + 321 + static 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 + 370 + static 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 + 390 + static 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 + 439 + err1: 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); 447 + err: 448 + put_device(&adapter->dev); 449 + 450 + return rc; 451 + } 452 + 453 + static 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 + 471 + static long device_compat_ioctl(struct file *file, unsigned int cmd, 472 + unsigned long arg) 473 + { 474 + return device_ioctl(file, cmd, arg); 475 + } 476 + 477 + static 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 + 508 + static 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 + 516 + void cxl_guest_remove_chardev(struct cxl *adapter) 517 + { 518 + cdev_del(&adapter->guest->cdev); 519 + } 520 + 521 + int 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); 536 + err: 537 + return rc; 538 + }
+15
drivers/misc/cxl/guest.c
··· 889 889 890 890 cxl_sysfs_adapter_remove(adapter); 891 891 892 + cxl_guest_remove_chardev(adapter); 892 893 device_unregister(&adapter->dev); 893 894 } 894 895 ··· 927 926 if ((rc = properties_look_ok(adapter))) 928 927 goto err1; 929 928 929 + if ((rc = cxl_guest_add_chardev(adapter))) 930 + goto err1; 931 + 930 932 /* 931 933 * After we call this function we must not free the adapter directly, 932 934 * even if it returns an error! ··· 945 941 err_put1: 946 942 device_unregister(&adapter->dev); 947 943 free = false; 944 + cxl_guest_remove_chardev(adapter); 948 945 err1: 949 946 if (free) 950 947 free_adapter(adapter); 951 948 return ERR_PTR(rc); 949 + } 950 + 951 + void cxl_guest_reload_module(struct cxl *adapter) 952 + { 953 + struct platform_device *pdev; 954 + 955 + pdev = adapter->guest->pdev; 956 + cxl_guest_remove_adapter(adapter); 957 + 958 + cxl_of_probe(pdev); 952 959 } 953 960 954 961 const struct cxl_backend_ops cxl_guest_ops = {
+24
include/uapi/misc/cxl.h
··· 55 55 __u64 reserved6; 56 56 }; 57 57 58 + /* base adapter image header is included in the image */ 59 + #define CXL_AI_NEED_HEADER 0x0000000000000001ULL 60 + #define CXL_AI_ALL CXL_AI_NEED_HEADER 61 + 62 + #define CXL_AI_HEADER_SIZE 128 63 + #define CXL_AI_BUFFER_SIZE 4096 64 + #define CXL_AI_MAX_ENTRIES 256 65 + #define CXL_AI_MAX_CHUNK_SIZE (CXL_AI_BUFFER_SIZE * CXL_AI_MAX_ENTRIES) 66 + 67 + struct cxl_adapter_image { 68 + __u64 flags; 69 + __u64 data; 70 + __u64 len_data; 71 + __u64 len_image; 72 + __u64 reserved1; 73 + __u64 reserved2; 74 + __u64 reserved3; 75 + __u64 reserved4; 76 + }; 77 + 58 78 /* ioctl numbers */ 59 79 #define CXL_MAGIC 0xCA 80 + /* AFU devices */ 60 81 #define CXL_IOCTL_START_WORK _IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work) 61 82 #define CXL_IOCTL_GET_PROCESS_ELEMENT _IOR(CXL_MAGIC, 0x01, __u32) 62 83 #define CXL_IOCTL_GET_AFU_ID _IOR(CXL_MAGIC, 0x02, struct cxl_afu_id) 84 + /* adapter devices */ 85 + #define CXL_IOCTL_DOWNLOAD_IMAGE _IOW(CXL_MAGIC, 0x0A, struct cxl_adapter_image) 86 + #define CXL_IOCTL_VALIDATE_IMAGE _IOW(CXL_MAGIC, 0x0B, struct cxl_adapter_image) 63 87 64 88 #define CXL_READ_MIN_SIZE 0x1000 /* 4K */ 65 89