Commit 594ff7d0 authored by Christophe Lombard's avatar Christophe Lombard Committed by Michael Ellerman

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: default avatarFrederic Barrat <fbarrat@linux.vnet.ibm.com>
Signed-off-by: default avatarFrederic Barrat <fbarrat@linux.vnet.ibm.com>
Signed-off-by: default avatarChristophe Lombard <clombard@linux.vnet.ibm.com>
Reviewed-by: default avatarManoj Kumar <manoj@linux.vnet.ibm.com>
Acked-by: default avatarIan Munsie <imunsie@au1.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 4752876c
...@@ -116,6 +116,8 @@ Work Element Descriptor (WED) ...@@ -116,6 +116,8 @@ Work Element Descriptor (WED)
User API User API
======== ========
1. AFU character devices
For AFUs operating in AFU directed mode, two character device For AFUs operating in AFU directed mode, two character device
files will be created. /dev/cxl/afu0.0m will correspond to a files will be created. /dev/cxl/afu0.0m will correspond to a
master context and /dev/cxl/afu0.0s will correspond to a slave master context and /dev/cxl/afu0.0s will correspond to a slave
...@@ -362,6 +364,59 @@ read ...@@ -362,6 +364,59 @@ read
reserved fields: reserved fields:
For future extensions and padding For future extensions and padding
2. Card character device (powerVM guest only)
In a powerVM guest, an extra character device is created for the
card. The device is only used to write (flash) a new image on the
FPGA accelerator. Once the image is written and verified, the
device tree is updated and the card is reset to reload the updated
image.
open
----
Opens the device and allocates a file descriptor to be used with
the rest of the API. The device can only be opened once.
ioctl
-----
CXL_IOCTL_DOWNLOAD_IMAGE:
CXL_IOCTL_VALIDATE_IMAGE:
Starts and controls flashing a new FPGA image. Partial
reconfiguration is not supported (yet), so the image must contain
a copy of the PSL and AFU(s). Since an image can be quite large,
the caller may have to iterate, splitting the image in smaller
chunks.
Takes a pointer to a struct cxl_adapter_image:
struct cxl_adapter_image {
__u64 flags;
__u64 data;
__u64 len_data;
__u64 len_image;
__u64 reserved1;
__u64 reserved2;
__u64 reserved3;
__u64 reserved4;
};
flags:
These flags indicate which optional fields are present in
this struct. Currently all fields are mandatory.
data:
Pointer to a buffer with part of the image to write to the
card.
len_data:
Size of the buffer pointed to by data.
len_image:
Full size of the image.
Sysfs Class Sysfs Class
=========== ===========
......
...@@ -4,7 +4,7 @@ ccflags-$(CONFIG_PPC_WERROR) += -Werror ...@@ -4,7 +4,7 @@ ccflags-$(CONFIG_PPC_WERROR) += -Werror
cxl-y += main.o file.o irq.o fault.o native.o cxl-y += main.o file.o irq.o fault.o native.o
cxl-y += context.o sysfs.o debugfs.o pci.o trace.o cxl-y += context.o sysfs.o debugfs.o pci.o trace.o
cxl-y += vphb.o api.o cxl-y += vphb.o api.o
cxl-$(CONFIG_PPC_PSERIES) += guest.o of.o hcalls.o cxl-$(CONFIG_PPC_PSERIES) += flash.o guest.o of.o hcalls.o
obj-$(CONFIG_CXL) += cxl.o obj-$(CONFIG_CXL) += cxl.o
obj-$(CONFIG_CXL_BASE) += base.o obj-$(CONFIG_CXL_BASE) += base.o
......
...@@ -84,3 +84,10 @@ void unregister_cxl_calls(struct cxl_calls *calls) ...@@ -84,3 +84,10 @@ void unregister_cxl_calls(struct cxl_calls *calls)
synchronize_rcu(); synchronize_rcu();
} }
EXPORT_SYMBOL_GPL(unregister_cxl_calls); EXPORT_SYMBOL_GPL(unregister_cxl_calls);
int cxl_update_properties(struct device_node *dn,
struct property *new_prop)
{
return of_update_property(dn, new_prop);
}
EXPORT_SYMBOL_GPL(cxl_update_properties);
...@@ -324,6 +324,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; ...@@ -324,6 +324,10 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0};
#define CXL_MODE_TIME_SLICED 0x4 #define CXL_MODE_TIME_SLICED 0x4
#define CXL_SUPPORTED_MODES (CXL_MODE_DEDICATED | CXL_MODE_DIRECTED) #define CXL_SUPPORTED_MODES (CXL_MODE_DEDICATED | CXL_MODE_DIRECTED)
#define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
#define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS)
#define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS)
enum cxl_context_status { enum cxl_context_status {
CLOSED, CLOSED,
OPENED, OPENED,
...@@ -692,12 +696,14 @@ struct cxl_calls { ...@@ -692,12 +696,14 @@ struct cxl_calls {
}; };
int register_cxl_calls(struct cxl_calls *calls); int register_cxl_calls(struct cxl_calls *calls);
void unregister_cxl_calls(struct cxl_calls *calls); void unregister_cxl_calls(struct cxl_calls *calls);
int cxl_update_properties(struct device_node *dn, struct property *new_prop);
void cxl_remove_adapter_nr(struct cxl *adapter); void cxl_remove_adapter_nr(struct cxl *adapter);
int cxl_alloc_spa(struct cxl_afu *afu); int cxl_alloc_spa(struct cxl_afu *afu);
void cxl_release_spa(struct cxl_afu *afu); void cxl_release_spa(struct cxl_afu *afu);
dev_t cxl_get_dev(void);
int cxl_file_init(void); int cxl_file_init(void);
void cxl_file_exit(void); void cxl_file_exit(void);
int cxl_register_adapter(struct cxl *adapter); int cxl_register_adapter(struct cxl *adapter);
......
...@@ -26,9 +26,7 @@ ...@@ -26,9 +26,7 @@
#include "trace.h" #include "trace.h"
#define CXL_NUM_MINORS 256 /* Total to reserve */ #define CXL_NUM_MINORS 256 /* Total to reserve */
#define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
#define CXL_CARD_MINOR(adapter) (adapter->adapter_num * CXL_DEV_MINORS)
#define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice)) #define CXL_AFU_MINOR_D(afu) (CXL_CARD_MINOR(afu->adapter) + 1 + (3 * afu->slice))
#define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1) #define CXL_AFU_MINOR_M(afu) (CXL_AFU_MINOR_D(afu) + 1)
#define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2) #define CXL_AFU_MINOR_S(afu) (CXL_AFU_MINOR_D(afu) + 2)
...@@ -36,7 +34,6 @@ ...@@ -36,7 +34,6 @@
#define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu)) #define CXL_AFU_MKDEV_M(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_M(afu))
#define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu)) #define CXL_AFU_MKDEV_S(afu) MKDEV(MAJOR(cxl_dev), CXL_AFU_MINOR_S(afu))
#define CXL_DEVT_ADAPTER(dev) (MINOR(dev) / CXL_DEV_MINORS)
#define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3) #define CXL_DEVT_AFU(dev) ((MINOR(dev) % CXL_DEV_MINORS - 1) / 3)
#define CXL_DEVT_IS_CARD(dev) (MINOR(dev) % CXL_DEV_MINORS == 0) #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,7 +443,8 @@ static const struct file_operations afu_master_fops = {
static char *cxl_devnode(struct device *dev, umode_t *mode) static char *cxl_devnode(struct device *dev, umode_t *mode)
{ {
if (CXL_DEVT_IS_CARD(dev->devt)) { if (cpu_has_feature(CPU_FTR_HVMODE) &&
CXL_DEVT_IS_CARD(dev->devt)) {
/* /*
* These minor numbers will eventually be used to program the * These minor numbers will eventually be used to program the
* PSL and AFUs once we have dynamic reprogramming support * PSL and AFUs once we have dynamic reprogramming support
...@@ -547,6 +545,11 @@ int cxl_register_adapter(struct cxl *adapter) ...@@ -547,6 +545,11 @@ int cxl_register_adapter(struct cxl *adapter)
return device_register(&adapter->dev); return device_register(&adapter->dev);
} }
dev_t cxl_get_dev(void)
{
return cxl_dev;
}
int __init cxl_file_init(void) int __init cxl_file_init(void)
{ {
int rc; int rc;
......
This diff is collapsed.
...@@ -889,6 +889,7 @@ void cxl_guest_remove_adapter(struct cxl *adapter) ...@@ -889,6 +889,7 @@ void cxl_guest_remove_adapter(struct cxl *adapter)
cxl_sysfs_adapter_remove(adapter); cxl_sysfs_adapter_remove(adapter);
cxl_guest_remove_chardev(adapter);
device_unregister(&adapter->dev); device_unregister(&adapter->dev);
} }
...@@ -926,6 +927,9 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic ...@@ -926,6 +927,9 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic
if ((rc = properties_look_ok(adapter))) if ((rc = properties_look_ok(adapter)))
goto err1; goto err1;
if ((rc = cxl_guest_add_chardev(adapter)))
goto err1;
/* /*
* After we call this function we must not free the adapter directly, * After we call this function we must not free the adapter directly,
* even if it returns an error! * even if it returns an error!
...@@ -941,12 +945,23 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic ...@@ -941,12 +945,23 @@ struct cxl *cxl_guest_init_adapter(struct device_node *np, struct platform_devic
err_put1: err_put1:
device_unregister(&adapter->dev); device_unregister(&adapter->dev);
free = false; free = false;
cxl_guest_remove_chardev(adapter);
err1: err1:
if (free) if (free)
free_adapter(adapter); free_adapter(adapter);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
void cxl_guest_reload_module(struct cxl *adapter)
{
struct platform_device *pdev;
pdev = adapter->guest->pdev;
cxl_guest_remove_adapter(adapter);
cxl_of_probe(pdev);
}
const struct cxl_backend_ops cxl_guest_ops = { const struct cxl_backend_ops cxl_guest_ops = {
.module = THIS_MODULE, .module = THIS_MODULE,
.adapter_reset = guest_reset, .adapter_reset = guest_reset,
......
...@@ -55,11 +55,35 @@ struct cxl_afu_id { ...@@ -55,11 +55,35 @@ struct cxl_afu_id {
__u64 reserved6; __u64 reserved6;
}; };
/* base adapter image header is included in the image */
#define CXL_AI_NEED_HEADER 0x0000000000000001ULL
#define CXL_AI_ALL CXL_AI_NEED_HEADER
#define CXL_AI_HEADER_SIZE 128
#define CXL_AI_BUFFER_SIZE 4096
#define CXL_AI_MAX_ENTRIES 256
#define CXL_AI_MAX_CHUNK_SIZE (CXL_AI_BUFFER_SIZE * CXL_AI_MAX_ENTRIES)
struct cxl_adapter_image {
__u64 flags;
__u64 data;
__u64 len_data;
__u64 len_image;
__u64 reserved1;
__u64 reserved2;
__u64 reserved3;
__u64 reserved4;
};
/* ioctl numbers */ /* ioctl numbers */
#define CXL_MAGIC 0xCA #define CXL_MAGIC 0xCA
/* AFU devices */
#define CXL_IOCTL_START_WORK _IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work) #define CXL_IOCTL_START_WORK _IOW(CXL_MAGIC, 0x00, struct cxl_ioctl_start_work)
#define CXL_IOCTL_GET_PROCESS_ELEMENT _IOR(CXL_MAGIC, 0x01, __u32) #define CXL_IOCTL_GET_PROCESS_ELEMENT _IOR(CXL_MAGIC, 0x01, __u32)
#define CXL_IOCTL_GET_AFU_ID _IOR(CXL_MAGIC, 0x02, struct cxl_afu_id) #define CXL_IOCTL_GET_AFU_ID _IOR(CXL_MAGIC, 0x02, struct cxl_afu_id)
/* adapter devices */
#define CXL_IOCTL_DOWNLOAD_IMAGE _IOW(CXL_MAGIC, 0x0A, struct cxl_adapter_image)
#define CXL_IOCTL_VALIDATE_IMAGE _IOW(CXL_MAGIC, 0x0B, struct cxl_adapter_image)
#define CXL_READ_MIN_SIZE 0x1000 /* 4K */ #define CXL_READ_MIN_SIZE 0x1000 /* 4K */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment