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;
>
next prev parent reply other threads:[~2019-03-25 10:01 UTC|newest]
Thread overview: 81+ 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 ` [PATCH 1/5] ocxl: Rename struct link to ocxl_link Alastair D'Silva
2019-02-27 7:15 ` Andrew Donnellan
2019-02-27 7:34 ` Alastair D'Silva
2019-02-27 7:54 ` Andrew Donnellan
2019-02-27 8:04 ` Alastair D'Silva
2019-02-27 8:18 ` Andrew Donnellan
2019-02-27 13:45 ` Frederic Barrat
2019-02-27 13:59 ` 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 13:40 ` Frederic Barrat
2019-02-28 5:02 ` Andrew Donnellan
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 13:25 ` Frederic Barrat
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 13:36 ` Frederic Barrat
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 13:39 ` Frederic Barrat
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 ` [PATCH 1/5] ocxl: Rename struct link to ocxl_link Alastair D'Silva
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 8:24 ` Greg Kurz
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-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 8:28 ` Greg Kurz
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 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 5:07 ` Andrew Donnellan
2019-03-20 5:34 ` [PATCH v3 0/5] ocxl: OpenCAPI Cleanup 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 ` [PATCH v3 2/5] ocxl: Clean up printf formats Alastair D'Silva
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 ` [PATCH v3 4/5] ocxl: Remove superfluous 'extern' from headers Alastair D'Silva
2019-03-20 5:34 ` [PATCH v3 5/5] ocxl: Remove some unused exported symbols Alastair D'Silva
2019-03-25 5:34 ` [PATCH v4 0/4] ocxl: OpenCAPI Cleanup Alastair D'Silva
2019-03-25 5:34 ` [PATCH v4 1/4] ocxl: Rename struct link to ocxl_link Alastair D'Silva
2019-04-03 14:18 ` Frederic Barrat
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-04-03 14:20 ` Frederic Barrat
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 16:55 ` Greg Kurz
2019-04-03 14:20 ` Frederic Barrat
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 16:57 ` Greg Kurz
2019-04-03 14:23 ` Frederic Barrat
2019-04-05 7:28 ` Andrew Donnellan
2019-03-25 16:49 ` [PATCH v4 0/4] ocxl: OpenCAPI Cleanup Greg Kurz
2019-03-25 17:34 ` Frederic Barrat
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 ` [PATCH v3 1/7] ocxl: Split pci.c Alastair D'Silva
2019-03-25 10:01 ` Frederic Barrat [this message]
2019-03-25 5:44 ` [PATCH v3 2/7] ocxl: Don't pass pci_dev around Alastair D'Silva
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 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 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 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 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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).