summaryrefslogtreecommitdiff
path: root/drivers/misc/cxl/flash.c
diff options
context:
space:
mode:
authorAndrew Donnellan <ajd@linux.ibm.com>2025-02-19 18:00:06 +1100
committerMichael Ellerman <mpe@ellerman.id.au>2025-03-16 22:04:27 +1100
commit5a0fcb0ef5584caf7da3f31896e08650c532e4c1 (patch)
treeee0d8d91e3deb181cd97b8e7c89b72228e092ec9 /drivers/misc/cxl/flash.c
parentff443fb402e95f5095dde3c64f7c3249d7c6f993 (diff)
cxl: Remove driver
Remove the cxl driver that provides support for the IBM Coherent Accelerator Processor Interface. Revert or clean up associated code in arch/powerpc that is no longer necessary. cxl has received minimal maintenance for several years, and is not supported on the Power10 processor. We aren't aware of any users who are likely to be using recent kernels. Thanks to Mikey Neuling, Ian Munsie, Daniel Axtens, Frederic Barrat, Christophe Lombard, Philippe Bergheaud, Vaibhav Jain and Alastair D'Silva for their work on this driver over the years. Signed-off-by: Andrew Donnellan <ajd@linux.ibm.com> Acked-by: Frederic Barrat <fbarrat@linux.ibm.com> Acked-by: Madhavan Srinivasan <maddy@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://patch.msgid.link/20250219070007.177725-2-ajd@linux.ibm.com
Diffstat (limited to 'drivers/misc/cxl/flash.c')
-rw-r--r--drivers/misc/cxl/flash.c538
1 files changed, 0 insertions, 538 deletions
diff --git a/drivers/misc/cxl/flash.c b/drivers/misc/cxl/flash.c
deleted file mode 100644
index eee9decc121e..000000000000
--- a/drivers/misc/cxl/flash.c
+++ /dev/null
@@ -1,538 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/semaphore.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/of.h>
-#include <asm/rtas.h>
-
-#include "cxl.h"
-#include "hcalls.h"
-
-#define DOWNLOAD_IMAGE 1
-#define VALIDATE_IMAGE 2
-
-struct ai_header {
- u16 version;
- u8 reserved0[6];
- u16 vendor;
- u16 device;
- u16 subsystem_vendor;
- u16 subsystem;
- u64 image_offset;
- u64 image_length;
- u8 reserved1[96];
-};
-
-static struct semaphore sem;
-static unsigned long *buffer[CXL_AI_MAX_ENTRIES];
-static struct sg_list *le;
-static u64 continue_token;
-static unsigned int transfer;
-
-struct update_props_workarea {
- __be32 phandle;
- __be32 state;
- __be64 reserved;
- __be32 nprops;
-} __packed;
-
-struct update_nodes_workarea {
- __be32 state;
- __be64 unit_address;
- __be32 reserved;
-} __packed;
-
-#define DEVICE_SCOPE 3
-#define NODE_ACTION_MASK 0xff000000
-#define NODE_COUNT_MASK 0x00ffffff
-#define OPCODE_DELETE 0x01000000
-#define OPCODE_UPDATE 0x02000000
-#define OPCODE_ADD 0x03000000
-
-static int rcall(int token, char *buf, s32 scope)
-{
- int rc;
-
- spin_lock(&rtas_data_buf_lock);
-
- memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
- rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
- memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
-
- spin_unlock(&rtas_data_buf_lock);
- return rc;
-}
-
-static int update_property(struct device_node *dn, const char *name,
- u32 vd, char *value)
-{
- struct property *new_prop;
- u32 *val;
- int rc;
-
- new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL);
- if (!new_prop)
- return -ENOMEM;
-
- new_prop->name = kstrdup(name, GFP_KERNEL);
- if (!new_prop->name) {
- kfree(new_prop);
- return -ENOMEM;
- }
-
- new_prop->length = vd;
- new_prop->value = kzalloc(new_prop->length, GFP_KERNEL);
- if (!new_prop->value) {
- kfree(new_prop->name);
- kfree(new_prop);
- return -ENOMEM;
- }
- memcpy(new_prop->value, value, vd);
-
- val = (u32 *)new_prop->value;
- rc = cxl_update_properties(dn, new_prop);
- pr_devel("%pOFn: update property (%s, length: %i, value: %#x)\n",
- dn, name, vd, be32_to_cpu(*val));
-
- if (rc) {
- kfree(new_prop->name);
- kfree(new_prop->value);
- kfree(new_prop);
- }
- return rc;
-}
-
-static int update_node(__be32 phandle, s32 scope)
-{
- struct update_props_workarea *upwa;
- struct device_node *dn;
- int i, rc, ret;
- char *prop_data;
- char *buf;
- int token;
- u32 nprops;
- u32 vd;
-
- token = rtas_token("ibm,update-properties");
- if (token == RTAS_UNKNOWN_SERVICE)
- return -EINVAL;
-
- buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- dn = of_find_node_by_phandle(be32_to_cpu(phandle));
- if (!dn) {
- kfree(buf);
- return -ENOENT;
- }
-
- upwa = (struct update_props_workarea *)&buf[0];
- upwa->phandle = phandle;
- do {
- rc = rcall(token, buf, scope);
- if (rc < 0)
- break;
-
- prop_data = buf + sizeof(*upwa);
- nprops = be32_to_cpu(upwa->nprops);
-
- if (*prop_data == 0) {
- prop_data++;
- vd = be32_to_cpu(*(__be32 *)prop_data);
- prop_data += vd + sizeof(vd);
- nprops--;
- }
-
- for (i = 0; i < nprops; i++) {
- char *prop_name;
-
- prop_name = prop_data;
- prop_data += strlen(prop_name) + 1;
- vd = be32_to_cpu(*(__be32 *)prop_data);
- prop_data += sizeof(vd);
-
- if ((vd != 0x00000000) && (vd != 0x80000000)) {
- ret = update_property(dn, prop_name, vd,
- prop_data);
- if (ret)
- pr_err("cxl: Could not update property %s - %i\n",
- prop_name, ret);
-
- prop_data += vd;
- }
- }
- } while (rc == 1);
-
- of_node_put(dn);
- kfree(buf);
- return rc;
-}
-
-static int update_devicetree(struct cxl *adapter, s32 scope)
-{
- struct update_nodes_workarea *unwa;
- u32 action, node_count;
- int token, rc, i;
- __be32 *data, phandle;
- char *buf;
-
- token = rtas_token("ibm,update-nodes");
- if (token == RTAS_UNKNOWN_SERVICE)
- return -EINVAL;
-
- buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- unwa = (struct update_nodes_workarea *)&buf[0];
- unwa->unit_address = cpu_to_be64(adapter->guest->handle);
- do {
- rc = rcall(token, buf, scope);
- if (rc && rc != 1)
- break;
-
- data = (__be32 *)buf + 4;
- while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
- action = be32_to_cpu(*data) & NODE_ACTION_MASK;
- node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
- pr_devel("device reconfiguration - action: %#x, nodes: %#x\n",
- action, node_count);
- data++;
-
- for (i = 0; i < node_count; i++) {
- phandle = *data++;
-
- switch (action) {
- case OPCODE_DELETE:
- /* nothing to do */
- break;
- case OPCODE_UPDATE:
- update_node(phandle, scope);
- break;
- case OPCODE_ADD:
- /* nothing to do, just move pointer */
- data++;
- break;
- }
- }
- }
- } while (rc == 1);
-
- kfree(buf);
- return 0;
-}
-
-static int handle_image(struct cxl *adapter, int operation,
- long (*fct)(u64, u64, u64, u64 *),
- struct cxl_adapter_image *ai)
-{
- size_t mod, s_copy, len_chunk = 0;
- struct ai_header *header = NULL;
- unsigned int entries = 0, i;
- void *dest, *from;
- int rc = 0, need_header;
-
- /* base adapter image header */
- need_header = (ai->flags & CXL_AI_NEED_HEADER);
- if (need_header) {
- header = kzalloc(sizeof(struct ai_header), GFP_KERNEL);
- if (!header)
- return -ENOMEM;
- header->version = cpu_to_be16(1);
- header->vendor = cpu_to_be16(adapter->guest->vendor);
- header->device = cpu_to_be16(adapter->guest->device);
- header->subsystem_vendor = cpu_to_be16(adapter->guest->subsystem_vendor);
- header->subsystem = cpu_to_be16(adapter->guest->subsystem);
- header->image_offset = cpu_to_be64(CXL_AI_HEADER_SIZE);
- header->image_length = cpu_to_be64(ai->len_image);
- }
-
- /* number of entries in the list */
- len_chunk = ai->len_data;
- if (need_header)
- len_chunk += CXL_AI_HEADER_SIZE;
-
- entries = len_chunk / CXL_AI_BUFFER_SIZE;
- mod = len_chunk % CXL_AI_BUFFER_SIZE;
- if (mod)
- entries++;
-
- if (entries > CXL_AI_MAX_ENTRIES) {
- rc = -EINVAL;
- goto err;
- }
-
- /* < -- MAX_CHUNK_SIZE = 4096 * 256 = 1048576 bytes -->
- * chunk 0 ----------------------------------------------------
- * | header | data |
- * ----------------------------------------------------
- * chunk 1 ----------------------------------------------------
- * | data |
- * ----------------------------------------------------
- * ....
- * chunk n ----------------------------------------------------
- * | data |
- * ----------------------------------------------------
- */
- from = (void *) ai->data;
- for (i = 0; i < entries; i++) {
- dest = buffer[i];
- s_copy = CXL_AI_BUFFER_SIZE;
-
- if ((need_header) && (i == 0)) {
- /* add adapter image header */
- memcpy(buffer[i], header, sizeof(struct ai_header));
- s_copy = CXL_AI_BUFFER_SIZE - CXL_AI_HEADER_SIZE;
- dest += CXL_AI_HEADER_SIZE; /* image offset */
- }
- if ((i == (entries - 1)) && mod)
- s_copy = mod;
-
- /* copy data */
- if (copy_from_user(dest, from, s_copy))
- goto err;
-
- /* fill in the list */
- le[i].phys_addr = cpu_to_be64(virt_to_phys(buffer[i]));
- le[i].len = cpu_to_be64(CXL_AI_BUFFER_SIZE);
- if ((i == (entries - 1)) && mod)
- le[i].len = cpu_to_be64(mod);
- from += s_copy;
- }
- pr_devel("%s (op: %i, need header: %i, entries: %i, token: %#llx)\n",
- __func__, operation, need_header, entries, continue_token);
-
- /*
- * download/validate the adapter image to the coherent
- * platform facility
- */
- rc = fct(adapter->guest->handle, virt_to_phys(le), entries,
- &continue_token);
- if (rc == 0) /* success of download/validation operation */
- continue_token = 0;
-
-err:
- kfree(header);
-
- return rc;
-}
-
-static int transfer_image(struct cxl *adapter, int operation,
- struct cxl_adapter_image *ai)
-{
- int rc = 0;
- int afu;
-
- switch (operation) {
- case DOWNLOAD_IMAGE:
- rc = handle_image(adapter, operation,
- &cxl_h_download_adapter_image, ai);
- if (rc < 0) {
- pr_devel("resetting adapter\n");
- cxl_h_reset_adapter(adapter->guest->handle);
- }
- return rc;
-
- case VALIDATE_IMAGE:
- rc = handle_image(adapter, operation,
- &cxl_h_validate_adapter_image, ai);
- if (rc < 0) {
- pr_devel("resetting adapter\n");
- cxl_h_reset_adapter(adapter->guest->handle);
- return rc;
- }
- if (rc == 0) {
- pr_devel("remove current afu\n");
- for (afu = 0; afu < adapter->slices; afu++)
- cxl_guest_remove_afu(adapter->afu[afu]);
-
- pr_devel("resetting adapter\n");
- cxl_h_reset_adapter(adapter->guest->handle);
-
- /* The entire image has now been
- * downloaded and the validation has
- * been successfully performed.
- * After that, the partition should call
- * ibm,update-nodes and
- * ibm,update-properties to receive the
- * current configuration
- */
- rc = update_devicetree(adapter, DEVICE_SCOPE);
- transfer = 1;
- }
- return rc;
- }
-
- return -EINVAL;
-}
-
-static long ioctl_transfer_image(struct cxl *adapter, int operation,
- struct cxl_adapter_image __user *uai)
-{
- struct cxl_adapter_image ai;
-
- pr_devel("%s\n", __func__);
-
- if (copy_from_user(&ai, uai, sizeof(struct cxl_adapter_image)))
- return -EFAULT;
-
- /*
- * Make sure reserved fields and bits are set to 0
- */
- if (ai.reserved1 || ai.reserved2 || ai.reserved3 || ai.reserved4 ||
- (ai.flags & ~CXL_AI_ALL))
- return -EINVAL;
-
- return transfer_image(adapter, operation, &ai);
-}
-
-static int device_open(struct inode *inode, struct file *file)
-{
- int adapter_num = CXL_DEVT_ADAPTER(inode->i_rdev);
- struct cxl *adapter;
- int rc = 0, i;
-
- pr_devel("in %s\n", __func__);
-
- BUG_ON(sizeof(struct ai_header) != CXL_AI_HEADER_SIZE);
-
- /* Allows one process to open the device by using a semaphore */
- if (down_interruptible(&sem) != 0)
- return -EPERM;
-
- if (!(adapter = get_cxl_adapter(adapter_num))) {
- rc = -ENODEV;
- goto err_unlock;
- }
-
- file->private_data = adapter;
- continue_token = 0;
- transfer = 0;
-
- for (i = 0; i < CXL_AI_MAX_ENTRIES; i++)
- buffer[i] = NULL;
-
- /* aligned buffer containing list entries which describes up to
- * 1 megabyte of data (256 entries of 4096 bytes each)
- * Logical real address of buffer 0 - Buffer 0 length in bytes
- * Logical real address of buffer 1 - Buffer 1 length in bytes
- * Logical real address of buffer 2 - Buffer 2 length in bytes
- * ....
- * ....
- * Logical real address of buffer N - Buffer N length in bytes
- */
- le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
- if (!le) {
- rc = -ENOMEM;
- goto err;
- }
-
- for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
- buffer[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL);
- if (!buffer[i]) {
- rc = -ENOMEM;
- goto err1;
- }
- }
-
- return 0;
-
-err1:
- for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
- if (buffer[i])
- free_page((unsigned long) buffer[i]);
- }
-
- if (le)
- free_page((unsigned long) le);
-err:
- put_device(&adapter->dev);
-err_unlock:
- up(&sem);
-
- return rc;
-}
-
-static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct cxl *adapter = file->private_data;
-
- pr_devel("in %s\n", __func__);
-
- if (cmd == CXL_IOCTL_DOWNLOAD_IMAGE)
- return ioctl_transfer_image(adapter,
- DOWNLOAD_IMAGE,
- (struct cxl_adapter_image __user *)arg);
- else if (cmd == CXL_IOCTL_VALIDATE_IMAGE)
- return ioctl_transfer_image(adapter,
- VALIDATE_IMAGE,
- (struct cxl_adapter_image __user *)arg);
- else
- return -EINVAL;
-}
-
-static int device_close(struct inode *inode, struct file *file)
-{
- struct cxl *adapter = file->private_data;
- int i;
-
- pr_devel("in %s\n", __func__);
-
- for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
- if (buffer[i])
- free_page((unsigned long) buffer[i]);
- }
-
- if (le)
- free_page((unsigned long) le);
-
- up(&sem);
- put_device(&adapter->dev);
- continue_token = 0;
-
- /* reload the module */
- if (transfer)
- cxl_guest_reload_module(adapter);
- else {
- pr_devel("resetting adapter\n");
- cxl_h_reset_adapter(adapter->guest->handle);
- }
-
- transfer = 0;
- return 0;
-}
-
-static const struct file_operations fops = {
- .owner = THIS_MODULE,
- .open = device_open,
- .unlocked_ioctl = device_ioctl,
- .compat_ioctl = compat_ptr_ioctl,
- .release = device_close,
-};
-
-void cxl_guest_remove_chardev(struct cxl *adapter)
-{
- cdev_del(&adapter->guest->cdev);
-}
-
-int cxl_guest_add_chardev(struct cxl *adapter)
-{
- dev_t devt;
- int rc;
-
- devt = MKDEV(MAJOR(cxl_get_dev()), CXL_CARD_MINOR(adapter));
- cdev_init(&adapter->guest->cdev, &fops);
- if ((rc = cdev_add(&adapter->guest->cdev, devt, 1))) {
- dev_err(&adapter->dev,
- "Unable to add chardev on adapter (card%i): %i\n",
- adapter->adapter_num, rc);
- goto err;
- }
- adapter->dev.devt = devt;
- sema_init(&sem, 1);
-err:
- return rc;
-}