summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Lombard <clombard@linux.vnet.ibm.com>2016-03-04 06:26:38 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2016-03-09 07:39:56 -0500
commit594ff7d067ca42676e27e2a7b5dcc0ff039d08ca (patch)
tree45824c4fb92c9450b86bfbb9ff19a0dd17cd2c93
parent4752876c71701b7663a5ded789058ab2c05f7d0f (diff)
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>
-rw-r--r--Documentation/powerpc/cxl.txt55
-rw-r--r--drivers/misc/cxl/Makefile2
-rw-r--r--drivers/misc/cxl/base.c7
-rw-r--r--drivers/misc/cxl/cxl.h6
-rw-r--r--drivers/misc/cxl/file.c11
-rw-r--r--drivers/misc/cxl/flash.c538
-rw-r--r--drivers/misc/cxl/guest.c15
-rw-r--r--include/uapi/misc/cxl.h24
8 files changed, 653 insertions, 5 deletions
diff --git a/Documentation/powerpc/cxl.txt b/Documentation/powerpc/cxl.txt
index 205c1b81625c..d5506ba0fef7 100644
--- a/Documentation/powerpc/cxl.txt
+++ b/Documentation/powerpc/cxl.txt
@@ -116,6 +116,8 @@ Work Element Descriptor (WED)
116User API 116User API
117======== 117========
118 118
1191. AFU character devices
120
119 For AFUs operating in AFU directed mode, two character device 121 For AFUs operating in AFU directed mode, two character device
120 files will be created. /dev/cxl/afu0.0m will correspond to a 122 files will be created. /dev/cxl/afu0.0m will correspond to a
121 master context and /dev/cxl/afu0.0s will correspond to a slave 123 master context and /dev/cxl/afu0.0s will correspond to a slave
@@ -362,6 +364,59 @@ read
362 reserved fields: 364 reserved fields:
363 For future extensions and padding 365 For future extensions and padding
364 366
367
3682. Card character device (powerVM guest only)
369
370 In a powerVM guest, an extra character device is created for the
371 card. The device is only used to write (flash) a new image on the
372 FPGA accelerator. Once the image is written and verified, the
373 device tree is updated and the card is reset to reload the updated
374 image.
375
376open
377----
378
379 Opens the device and allocates a file descriptor to be used with
380 the rest of the API. The device can only be opened once.
381
382ioctl
383-----
384
385CXL_IOCTL_DOWNLOAD_IMAGE:
386CXL_IOCTL_VALIDATE_IMAGE:
387 Starts and controls flashing a new FPGA image. Partial
388 reconfiguration is not supported (yet), so the image must contain
389 a copy of the PSL and AFU(s). Since an image can be quite large,
390 the caller may have to iterate, splitting the image in smaller
391 chunks.
392
393 Takes a pointer to a struct cxl_adapter_image:
394 struct cxl_adapter_image {
395 __u64 flags;
396 __u64 data;
397 __u64 len_data;
398 __u64 len_image;
399 __u64 reserved1;
400 __u64 reserved2;
401 __u64 reserved3;
402 __u64 reserved4;
403 };
404
405 flags:
406 These flags indicate which optional fields are present in
407 this struct. Currently all fields are mandatory.
408
409 data:
410 Pointer to a buffer with part of the image to write to the
411 card.
412
413 len_data:
414 Size of the buffer pointed to by data.
415
416 len_image:
417 Full size of the image.
418
419
365Sysfs Class 420Sysfs Class
366=========== 421===========
367 422
diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile
index a2f49cf4a168..8a55c1aa11aa 100644
--- a/drivers/misc/cxl/Makefile
+++ b/drivers/misc/cxl/Makefile
@@ -4,7 +4,7 @@ ccflags-$(CONFIG_PPC_WERROR) += -Werror
4cxl-y += main.o file.o irq.o fault.o native.o 4cxl-y += main.o file.o irq.o fault.o native.o
5cxl-y += context.o sysfs.o debugfs.o pci.o trace.o 5cxl-y += context.o sysfs.o debugfs.o pci.o trace.o
6cxl-y += vphb.o api.o 6cxl-y += vphb.o api.o
7cxl-$(CONFIG_PPC_PSERIES) += guest.o of.o hcalls.o 7cxl-$(CONFIG_PPC_PSERIES) += flash.o guest.o of.o hcalls.o
8obj-$(CONFIG_CXL) += cxl.o 8obj-$(CONFIG_CXL) += cxl.o
9obj-$(CONFIG_CXL_BASE) += base.o 9obj-$(CONFIG_CXL_BASE) += base.o
10 10
diff --git a/drivers/misc/cxl/base.c b/drivers/misc/cxl/base.c
index a9f0dd3255a2..957f4dd23f40 100644
--- a/drivers/misc/cxl/base.c
+++ b/drivers/misc/cxl/base.c
@@ -84,3 +84,10 @@ void unregister_cxl_calls(struct cxl_calls *calls)
84 synchronize_rcu(); 84 synchronize_rcu();
85} 85}
86EXPORT_SYMBOL_GPL(unregister_cxl_calls); 86EXPORT_SYMBOL_GPL(unregister_cxl_calls);
87
88int cxl_update_properties(struct device_node *dn,
89 struct property *new_prop)
90{
91 return of_update_property(dn, new_prop);
92}
93EXPORT_SYMBOL_GPL(cxl_update_properties);
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index a7e75f1cc903..24bd4cab02c2 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -324,6 +324,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0};
324#define CXL_MODE_TIME_SLICED 0x4 324#define CXL_MODE_TIME_SLICED 0x4
325#define CXL_SUPPORTED_MODES (CXL_MODE_DEDICATED | CXL_MODE_DIRECTED) 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
327enum cxl_context_status { 331enum cxl_context_status {
328 CLOSED, 332 CLOSED,
329 OPENED, 333 OPENED,
@@ -692,12 +696,14 @@ struct cxl_calls {
692}; 696};
693int register_cxl_calls(struct cxl_calls *calls); 697int register_cxl_calls(struct cxl_calls *calls);
694void unregister_cxl_calls(struct cxl_calls *calls); 698void unregister_cxl_calls(struct cxl_calls *calls);
699int cxl_update_properties(struct device_node *dn, struct property *new_prop);
695 700
696void cxl_remove_adapter_nr(struct cxl *adapter); 701void cxl_remove_adapter_nr(struct cxl *adapter);
697 702
698int cxl_alloc_spa(struct cxl_afu *afu); 703int cxl_alloc_spa(struct cxl_afu *afu);
699void cxl_release_spa(struct cxl_afu *afu); 704void cxl_release_spa(struct cxl_afu *afu);
700 705
706dev_t cxl_get_dev(void);
701int cxl_file_init(void); 707int cxl_file_init(void);
702void cxl_file_exit(void); 708void cxl_file_exit(void);
703int cxl_register_adapter(struct cxl *adapter); 709int cxl_register_adapter(struct cxl *adapter);
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index df4d49a6c67a..e16046292dd6 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -26,9 +26,7 @@
26#include "trace.h" 26#include "trace.h"
27 27
28#define CXL_NUM_MINORS 256 /* Total to reserve */ 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#define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice)) 30#define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice))
33#define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1) 31#define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1)
34#define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2) 32#define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2)
@@ -36,7 +34,6 @@
36#define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu)) 34#define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu))
37#define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu)) 35#define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu))
38 36
39#define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS)
40#define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3) 37#define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3)
41 38
42#define CXL_DEVT_IS_CARD(dev) (MINOR(dev) % CXL_DEV_MINORS == 0) 39#define CXL_DEVT_IS_CARD(dev) (MINOR(dev) % CXL_DEV_MINORS == 0)
@@ -446,7 +443,8 @@ static const struct file_operations afu_master_fops = {
446 443
447static char *cxl_devnode(struct device *dev, umode_t *mode) 444static char *cxl_devnode(struct device *dev, umode_t *mode)
448{ 445{
449 if (CXL_DEVT_IS_CARD(dev->devt)) { 446 if (cpu_has_feature(CPU_FTR_HVMODE) &&
447 CXL_DEVT_IS_CARD(dev->devt)) {
450 /* 448 /*
451 * These minor numbers will eventually be used to program the 449 * These minor numbers will eventually be used to program the
452 * PSL and AFUs once we have dynamic reprogramming support 450 * PSL and AFUs once we have dynamic reprogramming support
@@ -547,6 +545,11 @@ int cxl_register_adapter(struct cxl *adapter)
547 return device_register(&adapter->dev); 545 return device_register(&adapter->dev);
548} 546}
549 547
548dev_t cxl_get_dev(void)
549{
550 return cxl_dev;
551}
552
550int __init cxl_file_init(void) 553int __init cxl_file_init(void)
551{ 554{
552 int rc; 555 int rc;
diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c
new file mode 100644
index 000000000000..68dd0b7da471
--- /dev/null
+++ b/drivers/misc/cxl/flash.c
@@ -0,0 +1,538 @@
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}
diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c
index b1b8ac5195e7..816113d9d19b 100644
--- a/drivers/misc/cxl/guest.c
+++ b/drivers/misc/cxl/guest.c
@@ -889,6 +889,7 @@ void cxl_guest_remove_adapter(struct cxl *adapter)
889 889
890 cxl_sysfs_adapter_remove(adapter); 890 cxl_sysfs_adapter_remove(adapter);
891 891
892 cxl_guest_remove_chardev(adapter);
892 device_unregister(&adapter->dev); 893 device_unregister(&adapter->dev);
893} 894}
894 895
@@ -926,6 +927,9 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic
926 if ((rc = properties_look_ok(adapter))) 927 if ((rc = properties_look_ok(adapter)))
927 goto err1; 928 goto err1;
928 929
930 if ((rc = cxl_guest_add_chardev(adapter)))
931 goto err1;
932
929 /* 933 /*
930 * After we call this function we must not free the adapter directly, 934 * After we call this function we must not free the adapter directly,
931 * even if it returns an error! 935 * even if it returns an error!
@@ -941,12 +945,23 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic
941err_put1: 945err_put1:
942 device_unregister(&adapter->dev); 946 device_unregister(&adapter->dev);
943 free = false; 947 free = false;
948 cxl_guest_remove_chardev(adapter);
944err1: 949err1:
945 if (free) 950 if (free)
946 free_adapter(adapter); 951 free_adapter(adapter);
947 return ERR_PTR(rc); 952 return ERR_PTR(rc);
948} 953}
949 954
955void cxl_guest_reload_module(struct cxl *adapter)
956{
957 struct platform_device *pdev;
958
959 pdev = adapter->guest->pdev;
960 cxl_guest_remove_adapter(adapter);
961
962 cxl_of_probe(pdev);
963}
964
950const struct cxl_backend_ops cxl_guest_ops = { 965const struct cxl_backend_ops cxl_guest_ops = {
951 .module = THIS_MODULE, 966 .module = THIS_MODULE,
952 .adapter_reset = guest_reset, 967 .adapter_reset = guest_reset,
diff --git a/include/uapi/misc/cxl.h b/include/uapi/misc/cxl.h
index 1e889aa8a36e..8cd334f99ddc 100644
--- a/include/uapi/misc/cxl.h
+++ b/include/uapi/misc/cxl.h
@@ -55,11 +55,35 @@ struct cxl_afu_id {
55 __u64 reserved6; 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
67struct 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/* ioctl numbers */ 78/* ioctl numbers */
59#define CXL_MAGIC 0xCA 79#define CXL_MAGIC 0xCA
80/* AFU devices */
60#define CXL_IOCTL_START_WORK _IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work) 81#define CXL_IOCTL_START_WORK _IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work)
61#define CXL_IOCTL_GET_PROCESS_ELEMENT _IOR(CXL_MAGIC, 0x01, __u32) 82#define CXL_IOCTL_GET_PROCESS_ELEMENT _IOR(CXL_MAGIC, 0x01, __u32)
62#define CXL_IOCTL_GET_AFU_ID _IOR(CXL_MAGIC, 0x02, struct cxl_afu_id) 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#define CXL_READ_MIN_SIZE 0x1000 /* 4K */ 88#define CXL_READ_MIN_SIZE 0x1000 /* 4K */
65 89