All of lore.kernel.org
 help / color / mirror / Atom feed
From: Frederic Barrat <fbarrat@linux.ibm.com>
To: "Alastair D'Silva" <alastair@au1.ibm.com>, alastair@d-silva.org
Cc: Andrew Donnellan <andrew.donnellan@au1.ibm.com>,
	Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-kernel@vger.kernel.org, linuxppc-dev@lists.ozlabs.org
Subject: Re: [PATCH v3 1/7] ocxl: Split pci.c
Date: Mon, 25 Mar 2019 11:01:40 +0100	[thread overview]
Message-ID: <2fcb3d9c-8791-74b5-b3f4-7397fa31fde2@linux.ibm.com> (raw)
In-Reply-To: <20190325054438.15022-2-alastair@au1.ibm.com>



Le 25/03/2019 à 06:44, Alastair D'Silva a écrit :
> From: Alastair D'Silva <alastair@d-silva.org>
> 
> In preparation for making core code available for external drivers,
> move the core code out of pci.c and into core.c
> 
> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> ---

Acked-by: Frederic Barrat <fbarrat@linux.ibm.com>


>   drivers/misc/ocxl/Makefile        |   1 +
>   drivers/misc/ocxl/core.c          | 517 +++++++++++++++++++++++++++++
>   drivers/misc/ocxl/ocxl_internal.h |   5 +
>   drivers/misc/ocxl/pci.c           | 519 +-----------------------------
>   4 files changed, 524 insertions(+), 518 deletions(-)
>   create mode 100644 drivers/misc/ocxl/core.c
> 
> diff --git a/drivers/misc/ocxl/Makefile b/drivers/misc/ocxl/Makefile
> index 5229dcda8297..bc4e39bfda7b 100644
> --- a/drivers/misc/ocxl/Makefile
> +++ b/drivers/misc/ocxl/Makefile
> @@ -3,6 +3,7 @@ ccflags-$(CONFIG_PPC_WERROR)	+= -Werror
>   
>   ocxl-y				+= main.o pci.o config.o file.o pasid.o
>   ocxl-y				+= link.o context.o afu_irq.o sysfs.o trace.o
> +ocxl-y				+= core.o
>   obj-$(CONFIG_OCXL)		+= ocxl.o
>   
>   # For tracepoints to include our trace.h from tracepoint infrastructure:
> diff --git a/drivers/misc/ocxl/core.c b/drivers/misc/ocxl/core.c
> new file mode 100644
> index 000000000000..1a4411b72d35
> --- /dev/null
> +++ b/drivers/misc/ocxl/core.c
> @@ -0,0 +1,517 @@
> +// 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);
> +}
> +
> +struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu)
> +{
> +	return (get_device(&afu->dev) == NULL) ? NULL : afu;
> +}
> +
> +void ocxl_afu_put(struct ocxl_afu *afu)
> +{
> +	put_device(&afu->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;
> +
> +	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 ocxl_afu *afu)
> +{
> +	idr_destroy(&afu->contexts_idr);
> +	ocxl_fn_put(afu->fn);
> +	kfree(afu);
> +}
> +
> +static void free_afu_dev(struct device *dev)
> +{
> +	struct ocxl_afu *afu = to_ocxl_afu(dev);
> +
> +	ocxl_unregister_afu(afu);
> +	free_afu(afu);
> +}
> +
> +static int set_afu_device(struct ocxl_afu *afu, const char *location)
> +{
> +	struct ocxl_fn *fn = afu->fn;
> +	int rc;
> +
> +	afu->dev.parent = &fn->dev;
> +	afu->dev.release = free_afu_dev;
> +	rc = dev_set_name(&afu->dev, "%s.%s.%hhu", afu->config.name, location,
> +		afu->config.idx);
> +	return rc;
> +}
> +
> +static int assign_afu_actag(struct ocxl_afu *afu, struct pci_dev *dev)
> +{
> +	struct ocxl_fn *fn = afu->fn;
> +	int actag_count, actag_offset;
> +
> +	/*
> +	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> +				afu->actag_base, afu->actag_enabled);
> +	dev_dbg(&afu->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 pci_dev *dev)
> +{
> +	struct ocxl_fn *fn = afu->fn;
> +	int pasid_count, pasid_offset;
> +
> +	/*
> +	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> +				afu->pasid_base,
> +				afu->config.pasid_supported_log);
> +	dev_dbg(&afu->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, struct pci_dev *dev)
> +{
> +	int rc;
> +
> +	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(dev, afu->config.global_mmio_bar) +
> +		afu->config.global_mmio_offset;
> +	afu->pp_mmio_start =
> +		pci_resource_start(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(&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 = set_afu_device(afu, dev_name(&dev->dev));
> +	if (rc)
> +		return rc;
> +
> +	rc = assign_afu_actag(afu, dev);
> +	if (rc)
> +		return rc;
> +
> +	rc = assign_afu_pasid(afu, dev);
> +	if (rc) {
> +		reclaim_afu_actag(afu);
> +		return rc;
> +	}
> +
> +	rc = map_mmio_areas(afu, dev);
> +	if (rc) {
> +		reclaim_afu_pasid(afu);
> +		reclaim_afu_actag(afu);
> +		return rc;
> +	}
> +	return 0;
> +}
> +
> +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)
> +{
> +	int rc;
> +
> +	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1);
> +	/*
> +	 * Char device creation is the last step, as processes can
> +	 * call our driver immediately, so all our inits must be finished.
> +	 */
> +	rc = ocxl_create_cdev(afu);
> +	if (rc)
> +		return rc;
> +	return 0;
> +}
> +
> +static void deactivate_afu(struct ocxl_afu *afu)
> +{
> +	struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent);
> +
> +	ocxl_destroy_cdev(afu);
> +	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 0);
> +}
> +
> +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) {
> +		free_afu(afu);
> +		return rc;
> +	}
> +
> +	rc = ocxl_register_afu(afu);
> +	if (rc)
> +		goto err;
> +
> +	rc = ocxl_sysfs_add_afu(afu);
> +	if (rc)
> +		goto err;
> +
> +	rc = activate_afu(dev, afu);
> +	if (rc)
> +		goto err_sys;
> +
> +	list_add_tail(&afu->list, &fn->afu_list);
> +	return 0;
> +
> +err_sys:
> +	ocxl_sysfs_remove_afu(afu);
> +err:
> +	deconfigure_afu(afu);
> +	device_unregister(&afu->dev);
> +	return rc;
> +}
> +
> +void remove_afu(struct ocxl_afu *afu)
> +{
> +	list_del(&afu->list);
> +	ocxl_context_detach_all(afu);
> +	deactivate_afu(afu);
> +	ocxl_sysfs_remove_afu(afu);
> +	deconfigure_afu(afu);
> +	device_unregister(&afu->dev);
> +}
> +
> +static struct ocxl_fn *alloc_function(struct pci_dev *dev)
> +{
> +	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 = to_ocxl_function(dev);
> +
> +	free_function(fn);
> +}
> +
> +static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev)
> +{
> +	int rc;
> +
> +	fn->dev.parent = &dev->dev;
> +	fn->dev.release = free_function_dev;
> +	rc = dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev));
> +	if (rc)
> +		return rc;
> +	pci_set_drvdata(dev, fn);
> +	return 0;
> +}
> +
> +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);
> +}
> +
> +struct ocxl_fn *init_function(struct pci_dev *dev)
> +{
> +	struct ocxl_fn *fn;
> +	int rc;
> +
> +	fn = alloc_function(dev);
> +	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;
> +}
> +
> +void remove_function(struct ocxl_fn *fn)
> +{
> +	deconfigure_function(fn);
> +	device_unregister(&fn->dev);
> +}
> diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h
> index 06fd98c989c8..81086534dab5 100644
> --- a/drivers/misc/ocxl/ocxl_internal.h
> +++ b/drivers/misc/ocxl/ocxl_internal.h
> @@ -150,4 +150,9 @@ int ocxl_afu_irq_set_fd(struct ocxl_context *ctx, u64 irq_offset,
>   			int eventfd);
>   u64 ocxl_afu_irq_get_addr(struct ocxl_context *ctx, u64 irq_offset);
>   
> +struct ocxl_fn *init_function(struct pci_dev *dev);
> +void remove_function(struct ocxl_fn *fn);
> +int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx);
> +void remove_afu(struct ocxl_afu *afu);
> +
>   #endif /* _OCXL_INTERNAL_H_ */
> diff --git a/drivers/misc/ocxl/pci.c b/drivers/misc/ocxl/pci.c
> index 21f425472a82..4ed7cb1a667f 100644
> --- a/drivers/misc/ocxl/pci.c
> +++ b/drivers/misc/ocxl/pci.c
> @@ -1,9 +1,6 @@
>   // SPDX-License-Identifier: GPL-2.0+
> -// Copyright 2017 IBM Corp.
> +// Copyright 2019 IBM Corp.
>   #include <linux/module.h>
> -#include <linux/pci.h>
> -#include <linux/idr.h>
> -#include <asm/pnv-ocxl.h>
>   #include "ocxl_internal.h"
>   
>   /*
> @@ -17,520 +14,6 @@ static const struct pci_device_id ocxl_pci_tbl[] = {
>   };
>   MODULE_DEVICE_TABLE(pci, ocxl_pci_tbl);
>   
> -
> -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);
> -}
> -
> -struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu)
> -{
> -	return (get_device(&afu->dev) == NULL) ? NULL : afu;
> -}
> -
> -void ocxl_afu_put(struct ocxl_afu *afu)
> -{
> -	put_device(&afu->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;
> -
> -	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 ocxl_afu *afu)
> -{
> -	idr_destroy(&afu->contexts_idr);
> -	ocxl_fn_put(afu->fn);
> -	kfree(afu);
> -}
> -
> -static void free_afu_dev(struct device *dev)
> -{
> -	struct ocxl_afu *afu = to_ocxl_afu(dev);
> -
> -	ocxl_unregister_afu(afu);
> -	free_afu(afu);
> -}
> -
> -static int set_afu_device(struct ocxl_afu *afu, const char *location)
> -{
> -	struct ocxl_fn *fn = afu->fn;
> -	int rc;
> -
> -	afu->dev.parent = &fn->dev;
> -	afu->dev.release = free_afu_dev;
> -	rc = dev_set_name(&afu->dev, "%s.%s.%hhu", afu->config.name, location,
> -		afu->config.idx);
> -	return rc;
> -}
> -
> -static int assign_afu_actag(struct ocxl_afu *afu, struct pci_dev *dev)
> -{
> -	struct ocxl_fn *fn = afu->fn;
> -	int actag_count, actag_offset;
> -
> -	/*
> -	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> -				afu->actag_base, afu->actag_enabled);
> -	dev_dbg(&afu->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 pci_dev *dev)
> -{
> -	struct ocxl_fn *fn = afu->fn;
> -	int pasid_count, pasid_offset;
> -
> -	/*
> -	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> -				afu->pasid_base,
> -				afu->config.pasid_supported_log);
> -	dev_dbg(&afu->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, struct pci_dev *dev)
> -{
> -	int rc;
> -
> -	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(dev, afu->config.global_mmio_bar) +
> -		afu->config.global_mmio_offset;
> -	afu->pp_mmio_start =
> -		pci_resource_start(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(&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 = set_afu_device(afu, dev_name(&dev->dev));
> -	if (rc)
> -		return rc;
> -
> -	rc = assign_afu_actag(afu, dev);
> -	if (rc)
> -		return rc;
> -
> -	rc = assign_afu_pasid(afu, dev);
> -	if (rc) {
> -		reclaim_afu_actag(afu);
> -		return rc;
> -	}
> -
> -	rc = map_mmio_areas(afu, dev);
> -	if (rc) {
> -		reclaim_afu_pasid(afu);
> -		reclaim_afu_actag(afu);
> -		return rc;
> -	}
> -	return 0;
> -}
> -
> -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)
> -{
> -	int rc;
> -
> -	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1);
> -	/*
> -	 * Char device creation is the last step, as processes can
> -	 * call our driver immediately, so all our inits must be finished.
> -	 */
> -	rc = ocxl_create_cdev(afu);
> -	if (rc)
> -		return rc;
> -	return 0;
> -}
> -
> -static void deactivate_afu(struct ocxl_afu *afu)
> -{
> -	struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent);
> -
> -	ocxl_destroy_cdev(afu);
> -	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) {
> -		free_afu(afu);
> -		return rc;
> -	}
> -
> -	rc = ocxl_register_afu(afu);
> -	if (rc)
> -		goto err;
> -
> -	rc = ocxl_sysfs_add_afu(afu);
> -	if (rc)
> -		goto err;
> -
> -	rc = activate_afu(dev, afu);
> -	if (rc)
> -		goto err_sys;
> -
> -	list_add_tail(&afu->list, &fn->afu_list);
> -	return 0;
> -
> -err_sys:
> -	ocxl_sysfs_remove_afu(afu);
> -err:
> -	deconfigure_afu(afu);
> -	device_unregister(&afu->dev);
> -	return rc;
> -}
> -
> -static void remove_afu(struct ocxl_afu *afu)
> -{
> -	list_del(&afu->list);
> -	ocxl_context_detach_all(afu);
> -	deactivate_afu(afu);
> -	ocxl_sysfs_remove_afu(afu);
> -	deconfigure_afu(afu);
> -	device_unregister(&afu->dev);
> -}
> -
> -static struct ocxl_fn *alloc_function(struct pci_dev *dev)
> -{
> -	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 = to_ocxl_function(dev);
> -
> -	free_function(fn);
> -}
> -
> -static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev)
> -{
> -	int rc;
> -
> -	fn->dev.parent = &dev->dev;
> -	fn->dev.release = free_function_dev;
> -	rc = dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev));
> -	if (rc)
> -		return rc;
> -	pci_set_drvdata(dev, fn);
> -	return 0;
> -}
> -
> -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(dev);
> -	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;
> -}
> -
> -static void remove_function(struct ocxl_fn *fn)
> -{
> -	deconfigure_function(fn);
> -	device_unregister(&fn->dev);
> -}
> -
>   static int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
>   {
>   	int rc, afu_count = 0;
> 


WARNING: multiple messages have this Message-ID (diff)
From: Frederic Barrat <fbarrat@linux.ibm.com>
To: "Alastair D'Silva" <alastair@au1.ibm.com>, alastair@d-silva.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linuxppc-dev@lists.ozlabs.org, Arnd Bergmann <arnd@arndb.de>,
	Andrew Donnellan <andrew.donnellan@au1.ibm.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v3 1/7] ocxl: Split pci.c
Date: Mon, 25 Mar 2019 11:01:40 +0100	[thread overview]
Message-ID: <2fcb3d9c-8791-74b5-b3f4-7397fa31fde2@linux.ibm.com> (raw)
In-Reply-To: <20190325054438.15022-2-alastair@au1.ibm.com>



Le 25/03/2019 à 06:44, Alastair D'Silva a écrit :
> From: Alastair D'Silva <alastair@d-silva.org>
> 
> In preparation for making core code available for external drivers,
> move the core code out of pci.c and into core.c
> 
> Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
> ---

Acked-by: Frederic Barrat <fbarrat@linux.ibm.com>


>   drivers/misc/ocxl/Makefile        |   1 +
>   drivers/misc/ocxl/core.c          | 517 +++++++++++++++++++++++++++++
>   drivers/misc/ocxl/ocxl_internal.h |   5 +
>   drivers/misc/ocxl/pci.c           | 519 +-----------------------------
>   4 files changed, 524 insertions(+), 518 deletions(-)
>   create mode 100644 drivers/misc/ocxl/core.c
> 
> diff --git a/drivers/misc/ocxl/Makefile b/drivers/misc/ocxl/Makefile
> index 5229dcda8297..bc4e39bfda7b 100644
> --- a/drivers/misc/ocxl/Makefile
> +++ b/drivers/misc/ocxl/Makefile
> @@ -3,6 +3,7 @@ ccflags-$(CONFIG_PPC_WERROR)	+= -Werror
>   
>   ocxl-y				+= main.o pci.o config.o file.o pasid.o
>   ocxl-y				+= link.o context.o afu_irq.o sysfs.o trace.o
> +ocxl-y				+= core.o
>   obj-$(CONFIG_OCXL)		+= ocxl.o
>   
>   # For tracepoints to include our trace.h from tracepoint infrastructure:
> diff --git a/drivers/misc/ocxl/core.c b/drivers/misc/ocxl/core.c
> new file mode 100644
> index 000000000000..1a4411b72d35
> --- /dev/null
> +++ b/drivers/misc/ocxl/core.c
> @@ -0,0 +1,517 @@
> +// 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);
> +}
> +
> +struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu)
> +{
> +	return (get_device(&afu->dev) == NULL) ? NULL : afu;
> +}
> +
> +void ocxl_afu_put(struct ocxl_afu *afu)
> +{
> +	put_device(&afu->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;
> +
> +	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 ocxl_afu *afu)
> +{
> +	idr_destroy(&afu->contexts_idr);
> +	ocxl_fn_put(afu->fn);
> +	kfree(afu);
> +}
> +
> +static void free_afu_dev(struct device *dev)
> +{
> +	struct ocxl_afu *afu = to_ocxl_afu(dev);
> +
> +	ocxl_unregister_afu(afu);
> +	free_afu(afu);
> +}
> +
> +static int set_afu_device(struct ocxl_afu *afu, const char *location)
> +{
> +	struct ocxl_fn *fn = afu->fn;
> +	int rc;
> +
> +	afu->dev.parent = &fn->dev;
> +	afu->dev.release = free_afu_dev;
> +	rc = dev_set_name(&afu->dev, "%s.%s.%hhu", afu->config.name, location,
> +		afu->config.idx);
> +	return rc;
> +}
> +
> +static int assign_afu_actag(struct ocxl_afu *afu, struct pci_dev *dev)
> +{
> +	struct ocxl_fn *fn = afu->fn;
> +	int actag_count, actag_offset;
> +
> +	/*
> +	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> +				afu->actag_base, afu->actag_enabled);
> +	dev_dbg(&afu->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 pci_dev *dev)
> +{
> +	struct ocxl_fn *fn = afu->fn;
> +	int pasid_count, pasid_offset;
> +
> +	/*
> +	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> +				afu->pasid_base,
> +				afu->config.pasid_supported_log);
> +	dev_dbg(&afu->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, struct pci_dev *dev)
> +{
> +	int rc;
> +
> +	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(dev, afu->config.global_mmio_bar) +
> +		afu->config.global_mmio_offset;
> +	afu->pp_mmio_start =
> +		pci_resource_start(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(&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 = set_afu_device(afu, dev_name(&dev->dev));
> +	if (rc)
> +		return rc;
> +
> +	rc = assign_afu_actag(afu, dev);
> +	if (rc)
> +		return rc;
> +
> +	rc = assign_afu_pasid(afu, dev);
> +	if (rc) {
> +		reclaim_afu_actag(afu);
> +		return rc;
> +	}
> +
> +	rc = map_mmio_areas(afu, dev);
> +	if (rc) {
> +		reclaim_afu_pasid(afu);
> +		reclaim_afu_actag(afu);
> +		return rc;
> +	}
> +	return 0;
> +}
> +
> +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)
> +{
> +	int rc;
> +
> +	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1);
> +	/*
> +	 * Char device creation is the last step, as processes can
> +	 * call our driver immediately, so all our inits must be finished.
> +	 */
> +	rc = ocxl_create_cdev(afu);
> +	if (rc)
> +		return rc;
> +	return 0;
> +}
> +
> +static void deactivate_afu(struct ocxl_afu *afu)
> +{
> +	struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent);
> +
> +	ocxl_destroy_cdev(afu);
> +	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 0);
> +}
> +
> +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) {
> +		free_afu(afu);
> +		return rc;
> +	}
> +
> +	rc = ocxl_register_afu(afu);
> +	if (rc)
> +		goto err;
> +
> +	rc = ocxl_sysfs_add_afu(afu);
> +	if (rc)
> +		goto err;
> +
> +	rc = activate_afu(dev, afu);
> +	if (rc)
> +		goto err_sys;
> +
> +	list_add_tail(&afu->list, &fn->afu_list);
> +	return 0;
> +
> +err_sys:
> +	ocxl_sysfs_remove_afu(afu);
> +err:
> +	deconfigure_afu(afu);
> +	device_unregister(&afu->dev);
> +	return rc;
> +}
> +
> +void remove_afu(struct ocxl_afu *afu)
> +{
> +	list_del(&afu->list);
> +	ocxl_context_detach_all(afu);
> +	deactivate_afu(afu);
> +	ocxl_sysfs_remove_afu(afu);
> +	deconfigure_afu(afu);
> +	device_unregister(&afu->dev);
> +}
> +
> +static struct ocxl_fn *alloc_function(struct pci_dev *dev)
> +{
> +	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 = to_ocxl_function(dev);
> +
> +	free_function(fn);
> +}
> +
> +static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev)
> +{
> +	int rc;
> +
> +	fn->dev.parent = &dev->dev;
> +	fn->dev.release = free_function_dev;
> +	rc = dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev));
> +	if (rc)
> +		return rc;
> +	pci_set_drvdata(dev, fn);
> +	return 0;
> +}
> +
> +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);
> +}
> +
> +struct ocxl_fn *init_function(struct pci_dev *dev)
> +{
> +	struct ocxl_fn *fn;
> +	int rc;
> +
> +	fn = alloc_function(dev);
> +	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;
> +}
> +
> +void remove_function(struct ocxl_fn *fn)
> +{
> +	deconfigure_function(fn);
> +	device_unregister(&fn->dev);
> +}
> diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h
> index 06fd98c989c8..81086534dab5 100644
> --- a/drivers/misc/ocxl/ocxl_internal.h
> +++ b/drivers/misc/ocxl/ocxl_internal.h
> @@ -150,4 +150,9 @@ int ocxl_afu_irq_set_fd(struct ocxl_context *ctx, u64 irq_offset,
>   			int eventfd);
>   u64 ocxl_afu_irq_get_addr(struct ocxl_context *ctx, u64 irq_offset);
>   
> +struct ocxl_fn *init_function(struct pci_dev *dev);
> +void remove_function(struct ocxl_fn *fn);
> +int init_afu(struct pci_dev *dev, struct ocxl_fn *fn, u8 afu_idx);
> +void remove_afu(struct ocxl_afu *afu);
> +
>   #endif /* _OCXL_INTERNAL_H_ */
> diff --git a/drivers/misc/ocxl/pci.c b/drivers/misc/ocxl/pci.c
> index 21f425472a82..4ed7cb1a667f 100644
> --- a/drivers/misc/ocxl/pci.c
> +++ b/drivers/misc/ocxl/pci.c
> @@ -1,9 +1,6 @@
>   // SPDX-License-Identifier: GPL-2.0+
> -// Copyright 2017 IBM Corp.
> +// Copyright 2019 IBM Corp.
>   #include <linux/module.h>
> -#include <linux/pci.h>
> -#include <linux/idr.h>
> -#include <asm/pnv-ocxl.h>
>   #include "ocxl_internal.h"
>   
>   /*
> @@ -17,520 +14,6 @@ static const struct pci_device_id ocxl_pci_tbl[] = {
>   };
>   MODULE_DEVICE_TABLE(pci, ocxl_pci_tbl);
>   
> -
> -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);
> -}
> -
> -struct ocxl_afu *ocxl_afu_get(struct ocxl_afu *afu)
> -{
> -	return (get_device(&afu->dev) == NULL) ? NULL : afu;
> -}
> -
> -void ocxl_afu_put(struct ocxl_afu *afu)
> -{
> -	put_device(&afu->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;
> -
> -	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 ocxl_afu *afu)
> -{
> -	idr_destroy(&afu->contexts_idr);
> -	ocxl_fn_put(afu->fn);
> -	kfree(afu);
> -}
> -
> -static void free_afu_dev(struct device *dev)
> -{
> -	struct ocxl_afu *afu = to_ocxl_afu(dev);
> -
> -	ocxl_unregister_afu(afu);
> -	free_afu(afu);
> -}
> -
> -static int set_afu_device(struct ocxl_afu *afu, const char *location)
> -{
> -	struct ocxl_fn *fn = afu->fn;
> -	int rc;
> -
> -	afu->dev.parent = &fn->dev;
> -	afu->dev.release = free_afu_dev;
> -	rc = dev_set_name(&afu->dev, "%s.%s.%hhu", afu->config.name, location,
> -		afu->config.idx);
> -	return rc;
> -}
> -
> -static int assign_afu_actag(struct ocxl_afu *afu, struct pci_dev *dev)
> -{
> -	struct ocxl_fn *fn = afu->fn;
> -	int actag_count, actag_offset;
> -
> -	/*
> -	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> -				afu->actag_base, afu->actag_enabled);
> -	dev_dbg(&afu->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 pci_dev *dev)
> -{
> -	struct ocxl_fn *fn = afu->fn;
> -	int pasid_count, pasid_offset;
> -
> -	/*
> -	 * 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(&afu->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(dev, afu->config.dvsec_afu_control_pos,
> -				afu->pasid_base,
> -				afu->config.pasid_supported_log);
> -	dev_dbg(&afu->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, struct pci_dev *dev)
> -{
> -	int rc;
> -
> -	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(dev, afu->config.global_mmio_bar) +
> -		afu->config.global_mmio_offset;
> -	afu->pp_mmio_start =
> -		pci_resource_start(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(&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 = set_afu_device(afu, dev_name(&dev->dev));
> -	if (rc)
> -		return rc;
> -
> -	rc = assign_afu_actag(afu, dev);
> -	if (rc)
> -		return rc;
> -
> -	rc = assign_afu_pasid(afu, dev);
> -	if (rc) {
> -		reclaim_afu_actag(afu);
> -		return rc;
> -	}
> -
> -	rc = map_mmio_areas(afu, dev);
> -	if (rc) {
> -		reclaim_afu_pasid(afu);
> -		reclaim_afu_actag(afu);
> -		return rc;
> -	}
> -	return 0;
> -}
> -
> -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)
> -{
> -	int rc;
> -
> -	ocxl_config_set_afu_state(dev, afu->config.dvsec_afu_control_pos, 1);
> -	/*
> -	 * Char device creation is the last step, as processes can
> -	 * call our driver immediately, so all our inits must be finished.
> -	 */
> -	rc = ocxl_create_cdev(afu);
> -	if (rc)
> -		return rc;
> -	return 0;
> -}
> -
> -static void deactivate_afu(struct ocxl_afu *afu)
> -{
> -	struct pci_dev *dev = to_pci_dev(afu->fn->dev.parent);
> -
> -	ocxl_destroy_cdev(afu);
> -	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) {
> -		free_afu(afu);
> -		return rc;
> -	}
> -
> -	rc = ocxl_register_afu(afu);
> -	if (rc)
> -		goto err;
> -
> -	rc = ocxl_sysfs_add_afu(afu);
> -	if (rc)
> -		goto err;
> -
> -	rc = activate_afu(dev, afu);
> -	if (rc)
> -		goto err_sys;
> -
> -	list_add_tail(&afu->list, &fn->afu_list);
> -	return 0;
> -
> -err_sys:
> -	ocxl_sysfs_remove_afu(afu);
> -err:
> -	deconfigure_afu(afu);
> -	device_unregister(&afu->dev);
> -	return rc;
> -}
> -
> -static void remove_afu(struct ocxl_afu *afu)
> -{
> -	list_del(&afu->list);
> -	ocxl_context_detach_all(afu);
> -	deactivate_afu(afu);
> -	ocxl_sysfs_remove_afu(afu);
> -	deconfigure_afu(afu);
> -	device_unregister(&afu->dev);
> -}
> -
> -static struct ocxl_fn *alloc_function(struct pci_dev *dev)
> -{
> -	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 = to_ocxl_function(dev);
> -
> -	free_function(fn);
> -}
> -
> -static int set_function_device(struct ocxl_fn *fn, struct pci_dev *dev)
> -{
> -	int rc;
> -
> -	fn->dev.parent = &dev->dev;
> -	fn->dev.release = free_function_dev;
> -	rc = dev_set_name(&fn->dev, "ocxlfn.%s", dev_name(&dev->dev));
> -	if (rc)
> -		return rc;
> -	pci_set_drvdata(dev, fn);
> -	return 0;
> -}
> -
> -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(dev);
> -	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;
> -}
> -
> -static void remove_function(struct ocxl_fn *fn)
> -{
> -	deconfigure_function(fn);
> -	device_unregister(&fn->dev);
> -}
> -
>   static int ocxl_probe(struct pci_dev *dev, const struct pci_device_id *id)
>   {
>   	int rc, afu_count = 0;
> 


  reply	other threads:[~2019-03-25 10:01 UTC|newest]

Thread overview: 156+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-02-27  4:57 [PATCH 0/5] ocxl: OpenCAPI Cleanup Alastair D'Silva
2019-02-27  4:57 ` Alastair D'Silva
2019-02-27  4:57 ` [PATCH 1/5] ocxl: Rename struct link to ocxl_link Alastair D'Silva
2019-02-27  4:57   ` Alastair D'Silva
2019-02-27  7:15   ` Andrew Donnellan
2019-02-27  7:15     ` Andrew Donnellan
2019-02-27  7:34     ` Alastair D'Silva
2019-02-27  7:34       ` Alastair D'Silva
2019-02-27  7:54       ` Andrew Donnellan
2019-02-27  7:54         ` Andrew Donnellan
2019-02-27  8:04         ` Alastair D'Silva
2019-02-27  8:04           ` Alastair D'Silva
2019-02-27  8:18           ` Andrew Donnellan
2019-02-27  8:18             ` Andrew Donnellan
2019-02-27 13:45             ` Frederic Barrat
2019-02-27 13:45               ` Frederic Barrat
2019-02-27 13:59               ` Greg Kurz
2019-02-27 13:59                 ` Greg Kurz
2019-02-27 13:53   ` Greg Kurz
2019-02-27 13:53     ` Greg Kurz
2019-02-27  4:57 ` [PATCH 2/5] ocxl: Clean up printf formats Alastair D'Silva
2019-02-27  4:57   ` Alastair D'Silva
2019-02-27 13:40   ` Frederic Barrat
2019-02-27 13:40     ` Frederic Barrat
2019-02-28  5:02   ` Andrew Donnellan
2019-02-28  5:02     ` Andrew Donnellan
2019-03-02  1:13   ` Joe Perches
2019-03-02  1:13     ` Joe Perches
2019-02-27  4:57 ` [PATCH 3/5] ocxl: read_pasid never returns an error, so make it void Alastair D'Silva
2019-02-27  4:57   ` Alastair D'Silva
2019-02-27 13:25   ` Frederic Barrat
2019-02-27 13:25     ` Frederic Barrat
2019-02-28  5:03   ` Andrew Donnellan
2019-02-28  5:03     ` Andrew Donnellan
2019-02-27  4:57 ` [PATCH 4/5] ocxl: Remove superfluous 'extern' from headers Alastair D'Silva
2019-02-27  4:57   ` Alastair D'Silva
2019-02-27 13:36   ` Frederic Barrat
2019-02-27 13:36     ` Frederic Barrat
2019-02-28  5:05   ` Andrew Donnellan
2019-02-28  5:05     ` Andrew Donnellan
2019-02-27  4:57 ` [PATCH 5/5] ocxl: Remove some unused exported symbols Alastair D'Silva
2019-02-27  4:57   ` Alastair D'Silva
2019-02-27 13:39   ` Frederic Barrat
2019-02-27 13:39     ` Frederic Barrat
2019-02-28  5:23   ` Andrew Donnellan
2019-02-28  5:23     ` Andrew Donnellan
2019-03-13  4:06 ` [PATCH v2 0/5] ocxl: OpenCAPI Cleanup Alastair D'Silva
2019-03-13  4:06   ` Alastair D'Silva
2019-03-13  4:06   ` [PATCH 1/5] ocxl: Rename struct link to ocxl_link Alastair D'Silva
2019-03-13  4:06     ` Alastair D'Silva
2019-03-15  6:58     ` Andrew Donnellan
2019-03-15  6:58       ` Andrew Donnellan
2019-03-13  4:06   ` [PATCH 2/5] ocxl: Clean up printf formats Alastair D'Silva
2019-03-13  4:06     ` Alastair D'Silva
2019-03-13  8:24     ` Greg Kurz
2019-03-14  4:58     ` Andrew Donnellan
2019-03-14  4:58       ` Andrew Donnellan
2019-03-13  4:06   ` [PATCH 3/5] ocxl: read_pasid never returns an error, so make it void Alastair D'Silva
2019-03-13  4:06     ` Alastair D'Silva
2019-03-14  4:59     ` Andrew Donnellan
2019-03-14  4:59       ` Andrew Donnellan
2019-03-13  4:07   ` [PATCH 4/5] ocxl: Remove superfluous 'extern' from headers Alastair D'Silva
2019-03-13  4:07     ` Alastair D'Silva
2019-03-13  8:28     ` Greg Kurz
2019-03-14  5:08     ` Andrew Donnellan
2019-03-14  5:08       ` Andrew Donnellan
2019-03-13  4:07   ` [PATCH 5/5] ocxl: Remove some unused exported symbols Alastair D'Silva
2019-03-13  4:07     ` Alastair D'Silva
2019-03-13  9:10     ` Greg Kurz
2019-03-14  2:23       ` Alastair D'Silva
2019-03-14  6:50         ` Greg Kurz
2019-03-15  4:49     ` Andrew Donnellan
2019-03-15  4:49       ` Andrew Donnellan
2019-03-15  5:07       ` Andrew Donnellan
2019-03-15  5:07         ` Andrew Donnellan
2019-03-20  5:34   ` [PATCH v3 0/5] ocxl: OpenCAPI Cleanup Alastair D'Silva
2019-03-20  5:34     ` Alastair D'Silva
2019-03-20  5:34     ` [PATCH v3 1/5] ocxl: Rename struct link to ocxl_link Alastair D'Silva
2019-03-20  5:34       ` Alastair D'Silva
2019-03-20  5:34     ` [PATCH v3 2/5] ocxl: Clean up printf formats Alastair D'Silva
2019-03-20  5:34       ` Alastair D'Silva
2019-03-20 17:24       ` Joe Perches
2019-03-20 17:24         ` Joe Perches
2019-03-20  5:34     ` [PATCH v3 3/5] ocxl: read_pasid never returns an error, so make it void Alastair D'Silva
2019-03-20  5:34       ` Alastair D'Silva
2019-03-20  5:34     ` [PATCH v3 4/5] ocxl: Remove superfluous 'extern' from headers Alastair D'Silva
2019-03-20  5:34       ` Alastair D'Silva
2019-03-20  5:34     ` [PATCH v3 5/5] ocxl: Remove some unused exported symbols Alastair D'Silva
2019-03-20  5:34       ` Alastair D'Silva
2019-03-25  5:34     ` [PATCH v4 0/4] ocxl: OpenCAPI Cleanup Alastair D'Silva
2019-03-25  5:34       ` Alastair D'Silva
2019-03-25  5:34       ` [PATCH v4 1/4] ocxl: Rename struct link to ocxl_link Alastair D'Silva
2019-03-25  5:34         ` Alastair D'Silva
2019-04-03 14:18         ` Frederic Barrat
2019-04-03 14:18           ` Frederic Barrat
2019-04-05  7:05         ` Andrew Donnellan
2019-04-05  7:05           ` Andrew Donnellan
2019-05-03  6:59         ` Michael Ellerman
2019-03-25  5:34       ` [PATCH v4 2/4] ocxl: read_pasid never returns an error, so make it void Alastair D'Silva
2019-03-25  5:34         ` Alastair D'Silva
2019-04-03 14:20         ` Frederic Barrat
2019-04-03 14:20           ` Frederic Barrat
2019-04-05  7:05         ` Andrew Donnellan
2019-04-05  7:05           ` Andrew Donnellan
2019-03-25  5:34       ` [PATCH v4 3/4] ocxl: Remove superfluous 'extern' from headers Alastair D'Silva
2019-03-25  5:34         ` Alastair D'Silva
2019-03-25 16:55         ` Greg Kurz
2019-03-25 16:55           ` Greg Kurz
2019-04-03 14:20         ` Frederic Barrat
2019-04-03 14:20           ` Frederic Barrat
2019-04-05  7:09         ` Andrew Donnellan
2019-04-05  7:09           ` Andrew Donnellan
2019-03-25  5:34       ` [PATCH v4 4/4] ocxl: Remove some unused exported symbols Alastair D'Silva
2019-03-25  5:34         ` Alastair D'Silva
2019-03-25 16:57         ` Greg Kurz
2019-03-25 16:57           ` Greg Kurz
2019-04-03 14:23         ` Frederic Barrat
2019-04-03 14:23           ` Frederic Barrat
2019-04-05  7:28         ` Andrew Donnellan
2019-04-05  7:28           ` Andrew Donnellan
2019-03-25 16:49       ` [PATCH v4 0/4] ocxl: OpenCAPI Cleanup Greg Kurz
2019-03-25 16:49         ` Greg Kurz
2019-03-25 17:34         ` Frederic Barrat
2019-03-25 17:34           ` Frederic Barrat
2019-03-25 21:45           ` Alastair D'Silva
2019-03-25 21:45             ` Alastair D'Silva
2019-03-25  5:44     ` [PATCH v3 0/7] Refactor OCXL driver to allow external drivers to use it Alastair D'Silva
2019-03-25  5:44       ` Alastair D'Silva
2019-03-25  5:44       ` [PATCH v3 1/7] ocxl: Split pci.c Alastair D'Silva
2019-03-25  5:44         ` Alastair D'Silva
2019-03-25 10:01         ` Frederic Barrat [this message]
2019-03-25 10:01           ` Frederic Barrat
2019-03-25  5:44       ` [PATCH v3 2/7] ocxl: Don't pass pci_dev around Alastair D'Silva
2019-03-25  5:44         ` Alastair D'Silva
2019-03-25 10:04         ` Frederic Barrat
2019-03-25 10:04           ` Frederic Barrat
2019-03-25  5:44       ` [PATCH v3 3/7] ocxl: Create a clear delineation between ocxl backend & frontend Alastair D'Silva
2019-03-25  5:44         ` Alastair D'Silva
2019-03-25 15:11         ` Frederic Barrat
2019-03-25 15:11           ` Frederic Barrat
2019-03-25  5:44       ` [PATCH v3 4/7] ocxl: Allow external drivers to use OpenCAPI contexts Alastair D'Silva
2019-03-25  5:44         ` Alastair D'Silva
2019-03-25 15:13         ` Frederic Barrat
2019-03-25 15:13           ` Frederic Barrat
2019-03-25  5:44       ` [PATCH v3 5/7] ocxl: afu_irq only deals with IRQ IDs, not offsets Alastair D'Silva
2019-03-25  5:44         ` Alastair D'Silva
2019-03-25 15:24         ` Frederic Barrat
2019-03-25 15:24           ` Frederic Barrat
2019-03-25  5:44       ` [PATCH v3 6/7] ocxl: move event_fd handling to frontend Alastair D'Silva
2019-03-25  5:44         ` Alastair D'Silva
2019-03-25 15:41         ` Frederic Barrat
2019-03-25 15:41           ` Frederic Barrat
2019-03-25  5:44       ` [PATCH v3 7/7] ocxl: Provide global MMIO accessors for external drivers Alastair D'Silva
2019-03-25  5:44         ` Alastair D'Silva
2019-03-25 15:49         ` Frederic Barrat
2019-03-25 15:49           ` Frederic Barrat

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=2fcb3d9c-8791-74b5-b3f4-7397fa31fde2@linux.ibm.com \
    --to=fbarrat@linux.ibm.com \
    --cc=alastair@au1.ibm.com \
    --cc=alastair@d-silva.org \
    --cc=andrew.donnellan@au1.ibm.com \
    --cc=arnd@arndb.de \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.