mirror of
				https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux
				synced 2025-10-31 17:04:14 +10:00 
			
		
		
		
	Simplify the return expression. Acked-by: Frederic Barrat <fbarrat@linux.ibm.com> Acked-by: Andrew Donnellan <ajd@linux.ibm.com> Signed-off-by: Qinglang Miao <miaoqinglang@huawei.com> Link: https://lore.kernel.org/r/20200921131047.92526-1-miaoqinglang@huawei.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
		
			
				
	
	
		
			570 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			570 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| // Copyright 2019 IBM Corp.
 | |
| #include <linux/idr.h>
 | |
| #include "ocxl_internal.h"
 | |
| 
 | |
| static struct ocxl_fn *ocxl_fn_get(struct ocxl_fn *fn)
 | |
| {
 | |
| 	return (get_device(&fn->dev) == NULL) ? NULL : fn;
 | |
| }
 | |
| 
 | |
| static void ocxl_fn_put(struct ocxl_fn *fn)
 | |
| {
 | |
| 	put_device(&fn->dev);
 | |
| }
 | |
| 
 | |
| static struct ocxl_afu *alloc_afu(struct ocxl_fn *fn)
 | |
| {
 | |
| 	struct ocxl_afu *afu;
 | |
| 
 | |
| 	afu = kzalloc(sizeof(struct ocxl_afu), GFP_KERNEL);
 | |
| 	if (!afu)
 | |
| 		return NULL;
 | |
| 
 | |
| 	kref_init(&afu->kref);
 | |
| 	mutex_init(&afu->contexts_lock);
 | |
| 	mutex_init(&afu->afu_control_lock);
 | |
| 	idr_init(&afu->contexts_idr);
 | |
| 	afu->fn = fn;
 | |
| 	ocxl_fn_get(fn);
 | |
| 	return afu;
 | |
| }
 | |
| 
 | |
| static void free_afu(struct kref *kref)
 | |
| {
 | |
| 	struct ocxl_afu *afu = container_of(kref, struct ocxl_afu, kref);
 | |
| 
 | |
| 	idr_destroy(&afu->contexts_idr);
 | |
| 	ocxl_fn_put(afu->fn);
 | |
| 	kfree(afu);
 | |
| }
 | |
| 
 | |
| void ocxl_afu_get(struct ocxl_afu *afu)
 | |
| {
 | |
| 	kref_get(&afu->kref);
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_afu_get);
 | |
| 
 | |
| void ocxl_afu_put(struct ocxl_afu *afu)
 | |
| {
 | |
| 	kref_put(&afu->kref, free_afu);
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_afu_put);
 | |
| 
 | |
| static int assign_afu_actag(struct ocxl_afu *afu)
 | |
| {
 | |
| 	struct ocxl_fn *fn = afu->fn;
 | |
| 	int actag_count, actag_offset;
 | |
| 	struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
 | |
| 
 | |
| 	/*
 | |
| 	 * if there were not enough actags for the function, each afu
 | |
| 	 * reduces its count as well
 | |
| 	 */
 | |
| 	actag_count = afu->config.actag_supported *
 | |
| 		fn->actag_enabled / fn->actag_supported;
 | |
| 	actag_offset = ocxl_actag_afu_alloc(fn, actag_count);
 | |
| 	if (actag_offset < 0) {
 | |
| 		dev_err(&pci_dev->dev, "Can't allocate %d actags for AFU: %d\n",
 | |
| 			actag_count, actag_offset);
 | |
| 		return actag_offset;
 | |
| 	}
 | |
| 	afu->actag_base = fn->actag_base + actag_offset;
 | |
| 	afu->actag_enabled = actag_count;
 | |
| 
 | |
| 	ocxl_config_set_afu_actag(pci_dev, afu->config.dvsec_afu_control_pos,
 | |
| 				afu->actag_base, afu->actag_enabled);
 | |
| 	dev_dbg(&pci_dev->dev, "actag base=%d enabled=%d\n",
 | |
| 		afu->actag_base, afu->actag_enabled);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void reclaim_afu_actag(struct ocxl_afu *afu)
 | |
| {
 | |
| 	struct ocxl_fn *fn = afu->fn;
 | |
| 	int start_offset, size;
 | |
| 
 | |
| 	start_offset = afu->actag_base - fn->actag_base;
 | |
| 	size = afu->actag_enabled;
 | |
| 	ocxl_actag_afu_free(afu->fn, start_offset, size);
 | |
| }
 | |
| 
 | |
| static int assign_afu_pasid(struct ocxl_afu *afu)
 | |
| {
 | |
| 	struct ocxl_fn *fn = afu->fn;
 | |
| 	int pasid_count, pasid_offset;
 | |
| 	struct pci_dev *pci_dev = to_pci_dev(fn->dev.parent);
 | |
| 
 | |
| 	/*
 | |
| 	 * We only support the case where the function configuration
 | |
| 	 * requested enough PASIDs to cover all AFUs.
 | |
| 	 */
 | |
| 	pasid_count = 1 << afu->config.pasid_supported_log;
 | |
| 	pasid_offset = ocxl_pasid_afu_alloc(fn, pasid_count);
 | |
| 	if (pasid_offset < 0) {
 | |
| 		dev_err(&pci_dev->dev, "Can't allocate %d PASIDs for AFU: %d\n",
 | |
| 			pasid_count, pasid_offset);
 | |
| 		return pasid_offset;
 | |
| 	}
 | |
| 	afu->pasid_base = fn->pasid_base + pasid_offset;
 | |
| 	afu->pasid_count = 0;
 | |
| 	afu->pasid_max = pasid_count;
 | |
| 
 | |
| 	ocxl_config_set_afu_pasid(pci_dev, afu->config.dvsec_afu_control_pos,
 | |
| 				afu->pasid_base,
 | |
| 				afu->config.pasid_supported_log);
 | |
| 	dev_dbg(&pci_dev->dev, "PASID base=%d, enabled=%d\n",
 | |
| 		afu->pasid_base, pasid_count);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void reclaim_afu_pasid(struct ocxl_afu *afu)
 | |
| {
 | |
| 	struct ocxl_fn *fn = afu->fn;
 | |
| 	int start_offset, size;
 | |
| 
 | |
| 	start_offset = afu->pasid_base - fn->pasid_base;
 | |
| 	size = 1 << afu->config.pasid_supported_log;
 | |
| 	ocxl_pasid_afu_free(afu->fn, start_offset, size);
 | |
| }
 | |
| 
 | |
| static int reserve_fn_bar(struct ocxl_fn *fn, int bar)
 | |
| {
 | |
| 	struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 | |
| 	int rc, idx;
 | |
| 
 | |
| 	if (bar != 0 && bar != 2 && bar != 4)
 | |
| 		return -EINVAL;
 | |
| 
 | |
| 	idx = bar >> 1;
 | |
| 	if (fn->bar_used[idx]++ == 0) {
 | |
| 		rc = pci_request_region(dev, bar, "ocxl");
 | |
| 		if (rc)
 | |
| 			return rc;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void release_fn_bar(struct ocxl_fn *fn, int bar)
 | |
| {
 | |
| 	struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 | |
| 	int idx;
 | |
| 
 | |
| 	if (bar != 0 && bar != 2 && bar != 4)
 | |
| 		return;
 | |
| 
 | |
| 	idx = bar >> 1;
 | |
| 	if (--fn->bar_used[idx] == 0)
 | |
| 		pci_release_region(dev, bar);
 | |
| 	WARN_ON(fn->bar_used[idx] < 0);
 | |
| }
 | |
| 
 | |
| static int map_mmio_areas(struct ocxl_afu *afu)
 | |
| {
 | |
| 	int rc;
 | |
| 	struct pci_dev *pci_dev = to_pci_dev(afu->fn->dev.parent);
 | |
| 
 | |
| 	rc = reserve_fn_bar(afu->fn, afu->config.global_mmio_bar);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = reserve_fn_bar(afu->fn, afu->config.pp_mmio_bar);
 | |
| 	if (rc) {
 | |
| 		release_fn_bar(afu->fn, afu->config.global_mmio_bar);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	afu->global_mmio_start =
 | |
| 		pci_resource_start(pci_dev, afu->config.global_mmio_bar) +
 | |
| 		afu->config.global_mmio_offset;
 | |
| 	afu->pp_mmio_start =
 | |
| 		pci_resource_start(pci_dev, afu->config.pp_mmio_bar) +
 | |
| 		afu->config.pp_mmio_offset;
 | |
| 
 | |
| 	afu->global_mmio_ptr = ioremap(afu->global_mmio_start,
 | |
| 				afu->config.global_mmio_size);
 | |
| 	if (!afu->global_mmio_ptr) {
 | |
| 		release_fn_bar(afu->fn, afu->config.pp_mmio_bar);
 | |
| 		release_fn_bar(afu->fn, afu->config.global_mmio_bar);
 | |
| 		dev_err(&pci_dev->dev, "Error mapping global mmio area\n");
 | |
| 		return -ENOMEM;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Leave an empty page between the per-process mmio area and
 | |
| 	 * the AFU interrupt mappings
 | |
| 	 */
 | |
| 	afu->irq_base_offset = afu->config.pp_mmio_stride + PAGE_SIZE;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void unmap_mmio_areas(struct ocxl_afu *afu)
 | |
| {
 | |
| 	if (afu->global_mmio_ptr) {
 | |
| 		iounmap(afu->global_mmio_ptr);
 | |
| 		afu->global_mmio_ptr = NULL;
 | |
| 	}
 | |
| 	afu->global_mmio_start = 0;
 | |
| 	afu->pp_mmio_start = 0;
 | |
| 	release_fn_bar(afu->fn, afu->config.pp_mmio_bar);
 | |
| 	release_fn_bar(afu->fn, afu->config.global_mmio_bar);
 | |
| }
 | |
| 
 | |
| static int configure_afu(struct ocxl_afu *afu, u8 afu_idx, struct pci_dev *dev)
 | |
| {
 | |
| 	int rc;
 | |
| 
 | |
| 	rc = ocxl_config_read_afu(dev, &afu->fn->config, &afu->config, afu_idx);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = assign_afu_actag(afu);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = assign_afu_pasid(afu);
 | |
| 	if (rc)
 | |
| 		goto err_free_actag;
 | |
| 
 | |
| 	rc = map_mmio_areas(afu);
 | |
| 	if (rc)
 | |
| 		goto err_free_pasid;
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| err_free_pasid:
 | |
| 	reclaim_afu_pasid(afu);
 | |
| err_free_actag:
 | |
| 	reclaim_afu_actag(afu);
 | |
| 	return rc;
 | |
| }
 | |
| 
 | |
| static void deconfigure_afu(struct ocxl_afu *afu)
 | |
| {
 | |
| 	unmap_mmio_areas(afu);
 | |
| 	reclaim_afu_pasid(afu);
 | |
| 	reclaim_afu_actag(afu);
 | |
| }
 | |
| 
 | |
| static int activate_afu(struct pci_dev *dev, struct ocxl_afu *afu)
 | |
| {
 | |
| 	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void deactivate_afu(struct ocxl_afu *afu)
 | |
| {
 | |
| 	struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent);
 | |
| 
 | |
| 	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 0);
 | |
| }
 | |
| 
 | |
| static int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx)
 | |
| {
 | |
| 	int rc;
 | |
| 	struct ocxl_afu *afu;
 | |
| 
 | |
| 	afu = alloc_afu(fn);
 | |
| 	if (!afu)
 | |
| 		return -ENOMEM;
 | |
| 
 | |
| 	rc = configure_afu(afu, afu_idx, dev);
 | |
| 	if (rc) {
 | |
| 		ocxl_afu_put(afu);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	rc = activate_afu(dev, afu);
 | |
| 	if (rc) {
 | |
| 		deconfigure_afu(afu);
 | |
| 		ocxl_afu_put(afu);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	list_add_tail(&afu->list, &fn->afu_list);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void remove_afu(struct ocxl_afu *afu)
 | |
| {
 | |
| 	list_del(&afu->list);
 | |
| 	ocxl_context_detach_all(afu);
 | |
| 	deactivate_afu(afu);
 | |
| 	deconfigure_afu(afu);
 | |
| 	ocxl_afu_put(afu); // matches the implicit get in alloc_afu
 | |
| }
 | |
| 
 | |
| static struct ocxl_fn *alloc_function(void)
 | |
| {
 | |
| 	struct ocxl_fn *fn;
 | |
| 
 | |
| 	fn = kzalloc(sizeof(struct ocxl_fn), GFP_KERNEL);
 | |
| 	if (!fn)
 | |
| 		return NULL;
 | |
| 
 | |
| 	INIT_LIST_HEAD(&fn->afu_list);
 | |
| 	INIT_LIST_HEAD(&fn->pasid_list);
 | |
| 	INIT_LIST_HEAD(&fn->actag_list);
 | |
| 
 | |
| 	return fn;
 | |
| }
 | |
| 
 | |
| static void free_function(struct ocxl_fn *fn)
 | |
| {
 | |
| 	WARN_ON(!list_empty(&fn->afu_list));
 | |
| 	WARN_ON(!list_empty(&fn->pasid_list));
 | |
| 	kfree(fn);
 | |
| }
 | |
| 
 | |
| static void free_function_dev(struct device *dev)
 | |
| {
 | |
| 	struct ocxl_fn *fn = container_of(dev, struct ocxl_fn, dev);
 | |
| 
 | |
| 	free_function(fn);
 | |
| }
 | |
| 
 | |
| static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev)
 | |
| {
 | |
| 	fn->dev.parent = &dev->dev;
 | |
| 	fn->dev.release = free_function_dev;
 | |
| 	return dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev));
 | |
| }
 | |
| 
 | |
| static int assign_function_actag(struct ocxl_fn *fn)
 | |
| {
 | |
| 	struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 | |
| 	u16 base, enabled, supported;
 | |
| 	int rc;
 | |
| 
 | |
| 	rc = ocxl_config_get_actag_info(dev, &base, &enabled, &supported);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	fn->actag_base = base;
 | |
| 	fn->actag_enabled = enabled;
 | |
| 	fn->actag_supported = supported;
 | |
| 
 | |
| 	ocxl_config_set_actag(dev, fn->config.dvsec_function_pos,
 | |
| 			fn->actag_base,	fn->actag_enabled);
 | |
| 	dev_dbg(&fn->dev, "actag range starting at %d, enabled %d\n",
 | |
| 		fn->actag_base, fn->actag_enabled);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int set_function_pasid(struct ocxl_fn *fn)
 | |
| {
 | |
| 	struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 | |
| 	int rc, desired_count, max_count;
 | |
| 
 | |
| 	/* A function may not require any PASID */
 | |
| 	if (fn->config.max_pasid_log < 0)
 | |
| 		return 0;
 | |
| 
 | |
| 	rc = ocxl_config_get_pasid_info(dev, &max_count);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	desired_count = 1 << fn->config.max_pasid_log;
 | |
| 
 | |
| 	if (desired_count > max_count) {
 | |
| 		dev_err(&fn->dev,
 | |
| 			"Function requires more PASIDs than is available (%d vs. %d)\n",
 | |
| 			desired_count, max_count);
 | |
| 		return -ENOSPC;
 | |
| 	}
 | |
| 
 | |
| 	fn->pasid_base = 0;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int configure_function(struct ocxl_fn *fn, struct pci_dev *dev)
 | |
| {
 | |
| 	int rc;
 | |
| 
 | |
| 	rc = pci_enable_device(dev);
 | |
| 	if (rc) {
 | |
| 		dev_err(&dev->dev, "pci_enable_device failed: %d\n", rc);
 | |
| 		return rc;
 | |
| 	}
 | |
| 
 | |
| 	/*
 | |
| 	 * Once it has been confirmed to work on our hardware, we
 | |
| 	 * should reset the function, to force the adapter to restart
 | |
| 	 * from scratch.
 | |
| 	 * A function reset would also reset all its AFUs.
 | |
| 	 *
 | |
| 	 * Some hints for implementation:
 | |
| 	 *
 | |
| 	 * - there's not status bit to know when the reset is done. We
 | |
| 	 *   should try reading the config space to know when it's
 | |
| 	 *   done.
 | |
| 	 * - probably something like:
 | |
| 	 *	Reset
 | |
| 	 *	wait 100ms
 | |
| 	 *	issue config read
 | |
| 	 *	allow device up to 1 sec to return success on config
 | |
| 	 *	read before declaring it broken
 | |
| 	 *
 | |
| 	 * Some shared logic on the card (CFG, TLX) won't be reset, so
 | |
| 	 * there's no guarantee that it will be enough.
 | |
| 	 */
 | |
| 	rc = ocxl_config_read_function(dev, &fn->config);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = set_function_device(fn, dev);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = assign_function_actag(fn);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = set_function_pasid(fn);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = ocxl_link_setup(dev, 0, &fn->link);
 | |
| 	if (rc)
 | |
| 		return rc;
 | |
| 
 | |
| 	rc = ocxl_config_set_TL(dev, fn->config.dvsec_tl_pos);
 | |
| 	if (rc) {
 | |
| 		ocxl_link_release(dev, fn->link);
 | |
| 		return rc;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void deconfigure_function(struct ocxl_fn *fn)
 | |
| {
 | |
| 	struct pci_dev *dev = to_pci_dev(fn->dev.parent);
 | |
| 
 | |
| 	ocxl_link_release(dev, fn->link);
 | |
| 	pci_disable_device(dev);
 | |
| }
 | |
| 
 | |
| static struct ocxl_fn *init_function(struct pci_dev *dev)
 | |
| {
 | |
| 	struct ocxl_fn *fn;
 | |
| 	int rc;
 | |
| 
 | |
| 	fn = alloc_function();
 | |
| 	if (!fn)
 | |
| 		return ERR_PTR(-ENOMEM);
 | |
| 
 | |
| 	rc = configure_function(fn, dev);
 | |
| 	if (rc) {
 | |
| 		free_function(fn);
 | |
| 		return ERR_PTR(rc);
 | |
| 	}
 | |
| 
 | |
| 	rc = device_register(&fn->dev);
 | |
| 	if (rc) {
 | |
| 		deconfigure_function(fn);
 | |
| 		put_device(&fn->dev);
 | |
| 		return ERR_PTR(rc);
 | |
| 	}
 | |
| 	return fn;
 | |
| }
 | |
| 
 | |
| // Device detection & initialisation
 | |
| 
 | |
| struct ocxl_fn *ocxl_function_open(struct pci_dev *dev)
 | |
| {
 | |
| 	int rc, afu_count = 0;
 | |
| 	u8 afu;
 | |
| 	struct ocxl_fn *fn;
 | |
| 
 | |
| 	if (!radix_enabled()) {
 | |
| 		dev_err(&dev->dev, "Unsupported memory model (hash)\n");
 | |
| 		return ERR_PTR(-ENODEV);
 | |
| 	}
 | |
| 
 | |
| 	fn = init_function(dev);
 | |
| 	if (IS_ERR(fn)) {
 | |
| 		dev_err(&dev->dev, "function init failed: %li\n",
 | |
| 			PTR_ERR(fn));
 | |
| 		return fn;
 | |
| 	}
 | |
| 
 | |
| 	for (afu = 0; afu <= fn->config.max_afu_index; afu++) {
 | |
| 		rc = ocxl_config_check_afu_index(dev, &fn->config, afu);
 | |
| 		if (rc > 0) {
 | |
| 			rc = init_afu(dev, fn, afu);
 | |
| 			if (rc) {
 | |
| 				dev_err(&dev->dev,
 | |
| 					"Can't initialize AFU index %d\n", afu);
 | |
| 				continue;
 | |
| 			}
 | |
| 			afu_count++;
 | |
| 		}
 | |
| 	}
 | |
| 	dev_info(&dev->dev, "%d AFU(s) configured\n", afu_count);
 | |
| 	return fn;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_function_open);
 | |
| 
 | |
| struct list_head *ocxl_function_afu_list(struct ocxl_fn *fn)
 | |
| {
 | |
| 	return &fn->afu_list;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_function_afu_list);
 | |
| 
 | |
| struct ocxl_afu *ocxl_function_fetch_afu(struct ocxl_fn *fn, u8 afu_idx)
 | |
| {
 | |
| 	struct ocxl_afu *afu;
 | |
| 
 | |
| 	list_for_each_entry(afu, &fn->afu_list, list) {
 | |
| 		if (afu->config.idx == afu_idx)
 | |
| 			return afu;
 | |
| 	}
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_function_fetch_afu);
 | |
| 
 | |
| const struct ocxl_fn_config *ocxl_function_config(struct ocxl_fn *fn)
 | |
| {
 | |
| 	return &fn->config;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_function_config);
 | |
| 
 | |
| void ocxl_function_close(struct ocxl_fn *fn)
 | |
| {
 | |
| 	struct ocxl_afu *afu, *tmp;
 | |
| 
 | |
| 	list_for_each_entry_safe(afu, tmp, &fn->afu_list, list) {
 | |
| 		remove_afu(afu);
 | |
| 	}
 | |
| 
 | |
| 	deconfigure_function(fn);
 | |
| 	device_unregister(&fn->dev);
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_function_close);
 | |
| 
 | |
| // AFU Metadata
 | |
| 
 | |
| struct ocxl_afu_config *ocxl_afu_config(struct ocxl_afu *afu)
 | |
| {
 | |
| 	return &afu->config;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_afu_config);
 | |
| 
 | |
| void ocxl_afu_set_private(struct ocxl_afu *afu, void *private)
 | |
| {
 | |
| 	afu->private = private;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_afu_set_private);
 | |
| 
 | |
| void *ocxl_afu_get_private(struct ocxl_afu *afu)
 | |
| {
 | |
| 	if (afu)
 | |
| 		return afu->private;
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| EXPORT_SYMBOL_GPL(ocxl_afu_get_private);
 |