History

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.

Christophe Lombard committed 10 years ago

Commit 594ff7d1 parent 47528768 files · +653 −5Browse files

Unified · Split

8 files
  1. Documentation/powerpc/cxl.txt +55 −0
  2. drivers/misc/cxl/Makefile +1 −1
  3. drivers/misc/cxl/base.c +7 −0
  4. drivers/misc/cxl/cxl.h +6 −0
  5. drivers/misc/cxl/file.c +7 −4
  6. drivers/misc/cxl/flash.c +538 −0
  7. drivers/misc/cxl/guest.c +15 −0
  8. include/uapi/misc/cxl.h +24 −0
Documentation/powerpc/cxl.txt+55−0
@@ -116,6 +116,8 @@ Work Element Descriptor (WED) · 115 unmodified lines
116116 User API
117117 ========
118118
119+1. AFU character devices
120+
119121 For AFUs operating in AFU directed mode, two character device
120122 files will be created. /dev/cxl/afu0.0m will correspond to a
121123 master context and /dev/cxl/afu0.0s will correspond to a slave
@@ -362,6 +364,59 @@ read · 240 unmodified lines
362364 reserved fields:
363365 For future extensions and padding
364366
367+
368+2. 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+
376+open
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+
382+ioctl
383+-----
384+
385+CXL_IOCTL_DOWNLOAD_IMAGE:
386+CXL_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+
365420 Sysfs Class
366421 ===========
367422
drivers/misc/cxl/Makefile+1−1
@@ -4,7 +4,7 @@ ccflags-$(CONFIG_PPC_WERROR) += -Werror · 3 unmodified lines
44 cxl-y += main.o file.o irq.o fault.o native.o
55 cxl-y += context.o sysfs.o debugfs.o pci.o trace.o
66 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
88 obj-$(CONFIG_CXL) += cxl.o
99 obj-$(CONFIG_CXL_BASE) += base.o
1010
drivers/misc/cxl/base.c+7−0
@@ -84,3 +84,10 @@ void unregister_cxl_calls(struct cxl_calls *calls) · 83 unmodified lines
8484 synchronize_rcu();
8585 }
8686 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);
drivers/misc/cxl/cxl.h+6−0
@@ -324,6 +324,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; · 323 unmodified lines
324324 #define CXL_MODE_TIME_SLICED 0x4
325325 #define CXL_SUPPORTED_MODES (CXL_MODE_DEDICATED | CXL_MODE_DIRECTED)
326326
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+
327331 enum cxl_context_status {
328332 CLOSED,
329333 OPENED,
@@ -692,12 +696,14 @@ struct cxl_calls { · 362 unmodified lines
692696 };
693697 int register_cxl_calls(struct cxl_calls *calls);
694698 void unregister_cxl_calls(struct cxl_calls *calls);
699+int cxl_update_properties(struct device_node *dn, struct property *new_prop);
695700
696701 void cxl_remove_adapter_nr(struct cxl *adapter);
697702
698703 int cxl_alloc_spa(struct cxl_afu *afu);
699704 void cxl_release_spa(struct cxl_afu *afu);
700705
706+dev_t cxl_get_dev(void);
701707 int cxl_file_init(void);
702708 void cxl_file_exit(void);
703709 int cxl_register_adapter(struct cxl *adapter);
drivers/misc/cxl/file.c+7−4
@@ -26,9 +26,7 @@ · 25 unmodified lines
2626 #include "trace.h"
2727
2828 #define CXL_NUM_MINORS 256 /* Total to reserve */
29−#define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
3029
31−#define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS)
3230 #define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice))
3331 #define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1)
3432 #define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2)
@@ -36,7 +34,6 @@ · 1 unmodified line
3634 #define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu))
3735 #define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu))
3836
39−#define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS)
4037 #define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3)
4138
4239 #define CXL_DEVT_IS_CARD(dev) (MINOR(dev) % CXL_DEV_MINORS == 0)
@@ -446,7 +443,8 @@ static const struct file_operations afu_master_fops = { · 403 unmodified lines
446443
447444 static char *cxl_devnode(struct device *dev, umode_t *mode)
448445 {
449− if (CXL_DEVT_IS_CARD(dev->devt)) {
446+ if (cpu_has_feature(CPU_FTR_HVMODE) &&
447+ CXL_DEVT_IS_CARD(dev->devt)) {
450448 /*
451449 * These minor numbers will eventually be used to program the
452450 * PSL and AFUs once we have dynamic reprogramming support
@@ -547,6 +545,11 @@ int cxl_register_adapter(struct cxl *adapter) · 94 unmodified lines
547545 return device_register(&adapter->dev);
548546 }
549547
548+dev_t cxl_get_dev(void)
549+{
550+ return cxl_dev;
551+}
552+
550553 int __init cxl_file_init(void)
551554 {
552555 int rc;
drivers/misc/cxl/flash.c+538−0
@@ -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+
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+}
drivers/misc/cxl/guest.c+15−0
@@ -889,6 +889,7 @@ void cxl_guest_remove_adapter(struct cxl *adapter) · 888 unmodified lines
889889
890890 cxl_sysfs_adapter_remove(adapter);
891891
892+ cxl_guest_remove_chardev(adapter);
892893 device_unregister(&adapter->dev);
893894 }
894895
@@ -926,6 +927,9 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic · 31 unmodified lines
926927 if ((rc = properties_look_ok(adapter)))
927928 goto err1;
928929
930+ if ((rc = cxl_guest_add_chardev(adapter)))
931+ goto err1;
932+
929933 /*
930934 * After we call this function we must not free the adapter directly,
931935 * even if it returns an error!
@@ -941,12 +945,23 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic · 9 unmodified lines
941945 err_put1:
942946 device_unregister(&adapter->dev);
943947 free = false;
948+ cxl_guest_remove_chardev(adapter);
944949 err1:
945950 if (free)
946951 free_adapter(adapter);
947952 return ERR_PTR(rc);
948953 }
949954
955+void 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+
950965 const struct cxl_backend_ops cxl_guest_ops = {
951966 .module = THIS_MODULE,
952967 .adapter_reset = guest_reset,
include/uapi/misc/cxl.h+24−0
@@ -55,11 +55,35 @@ struct cxl_afu_id { · 54 unmodified lines
5555 __u64 reserved6;
5656 };
5757
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+
5878 /* ioctl numbers */
5979 #define CXL_MAGIC 0xCA
80+/* AFU devices */
6081 #define CXL_IOCTL_START_WORK _IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work)
6182 #define CXL_IOCTL_GET_PROCESS_ELEMENT _IOR(CXL_MAGIC, 0x01, __u32)
6283 #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)
6387
6488 #define CXL_READ_MIN_SIZE 0x1000 /* 4K */
6589

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t