Message ID | 20200327071202.2159885-7-alastair@d-silva.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add support for OpenCAPI Persistent Memory devices | expand |
On Sun, Mar 29, 2020 at 10:53 PM Alastair D'Silva <alastair@d-silva.org> wrote: > > OpenCAPI LPC memory is allocated per link, but each link supports > multiple AFUs, and each AFU can have LPC memory assigned to it. Is there an OpenCAPI primer to decode these objects and their associations that I can reference? > > This patch tallys the memory for all AFUs on a link, allowing it > to be mapped in a single operation after the AFUs have been > enumerated. > > Signed-off-by: Alastair D'Silva <alastair@d-silva.org> > --- > drivers/misc/ocxl/core.c | 10 ++++++ > drivers/misc/ocxl/link.c | 60 +++++++++++++++++++++++++++++++ > drivers/misc/ocxl/ocxl_internal.h | 33 +++++++++++++++++ > 3 files changed, 103 insertions(+) > > diff --git a/drivers/misc/ocxl/core.c b/drivers/misc/ocxl/core.c > index b7a09b21ab36..2531c6cf19a0 100644 > --- a/drivers/misc/ocxl/core.c > +++ b/drivers/misc/ocxl/core.c > @@ -230,8 +230,18 @@ static int configure_afu(struct ocxl_afu *afu, u8 afu_idx, struct pci_dev *dev) > if (rc) > goto err_free_pasid; > > + if (afu->config.lpc_mem_size || afu->config.special_purpose_mem_size) { > + rc = ocxl_link_add_lpc_mem(afu->fn->link, afu->config.lpc_mem_offset, > + afu->config.lpc_mem_size + > + afu->config.special_purpose_mem_size); > + if (rc) > + goto err_free_mmio; > + } > + > return 0; > > +err_free_mmio: > + unmap_mmio_areas(afu); > err_free_pasid: > reclaim_afu_pasid(afu); > err_free_actag: > diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c > index 58d111afd9f6..af119d3ef79a 100644 > --- a/drivers/misc/ocxl/link.c > +++ b/drivers/misc/ocxl/link.c > @@ -84,6 +84,11 @@ struct ocxl_link { > int dev; > atomic_t irq_available; > struct spa *spa; > + struct mutex lpc_mem_lock; /* protects lpc_mem & lpc_mem_sz */ > + u64 lpc_mem_sz; /* Total amount of LPC memory presented on the link */ > + u64 lpc_mem; > + int lpc_consumers; > + > void *platform_data; > }; > static struct list_head links_list = LIST_HEAD_INIT(links_list); > @@ -396,6 +401,8 @@ static int alloc_link(struct pci_dev *dev, int PE_mask, struct ocxl_link **out_l > if (rc) > goto err_spa; > > + mutex_init(&link->lpc_mem_lock); > + > /* platform specific hook */ > rc = pnv_ocxl_spa_setup(dev, link->spa->spa_mem, PE_mask, > &link->platform_data); > @@ -711,3 +718,56 @@ void ocxl_link_free_irq(void *link_handle, int hw_irq) > atomic_inc(&link->irq_available); > } > EXPORT_SYMBOL_GPL(ocxl_link_free_irq); > + > +int ocxl_link_add_lpc_mem(void *link_handle, u64 offset, u64 size) > +{ > + struct ocxl_link *link = (struct ocxl_link *)link_handle; > + > + // Check for overflow > + if (offset > (offset + size)) > + return -EINVAL; > + > + mutex_lock(&link->lpc_mem_lock); > + link->lpc_mem_sz = max(link->lpc_mem_sz, offset + size); > + > + mutex_unlock(&link->lpc_mem_lock); > + > + return 0; > +} > + > +u64 ocxl_link_lpc_map(void *link_handle, struct pci_dev *pdev) > +{ > + struct ocxl_link *link = (struct ocxl_link *)link_handle; > + > + mutex_lock(&link->lpc_mem_lock); > + > + if (!link->lpc_mem) > + link->lpc_mem = pnv_ocxl_platform_lpc_setup(pdev, link->lpc_mem_sz); > + > + if (link->lpc_mem) > + link->lpc_consumers++; > + mutex_unlock(&link->lpc_mem_lock); > + > + return link->lpc_mem; > +} > + > +void ocxl_link_lpc_release(void *link_handle, struct pci_dev *pdev) > +{ > + struct ocxl_link *link = (struct ocxl_link *)link_handle; > + > + mutex_lock(&link->lpc_mem_lock); > + > + if (!link->lpc_mem) { > + mutex_unlock(&link->lpc_mem_lock); > + return; > + } > + > + WARN_ON(--link->lpc_consumers < 0); > + > + if (link->lpc_consumers == 0) { > + pnv_ocxl_platform_lpc_release(pdev); > + link->lpc_mem = 0; > + } > + > + mutex_unlock(&link->lpc_mem_lock); > +} > diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h > index 198e4e4bc51d..2d7575225bd7 100644 > --- a/drivers/misc/ocxl/ocxl_internal.h > +++ b/drivers/misc/ocxl/ocxl_internal.h > @@ -142,4 +142,37 @@ int ocxl_irq_offset_to_id(struct ocxl_context *ctx, u64 offset); > u64 ocxl_irq_id_to_offset(struct ocxl_context *ctx, int irq_id); > void ocxl_afu_irq_free_all(struct ocxl_context *ctx); > > +/** > + * ocxl_link_add_lpc_mem() - Increment the amount of memory required by an OpenCAPI link > + * > + * @link_handle: The OpenCAPI link handle > + * @offset: The offset of the memory to add > + * @size: The number of bytes to increment memory on the link by > + * > + * Returns 0 on success, -EINVAL on overflow > + */ > +int ocxl_link_add_lpc_mem(void *link_handle, u64 offset, u64 size); > + > +/** > + * ocxl_link_lpc_map() - Map the LPC memory for an OpenCAPI device > + * Since LPC memory belongs to a link, the whole LPC memory available > + * on the link must be mapped in order to make it accessible to a device. > + * @link_handle: The OpenCAPI link handle > + * @pdev: A device that is on the link > + * > + * Returns the address of the mapped LPC memory, or 0 on error > + */ > +u64 ocxl_link_lpc_map(void *link_handle, struct pci_dev *pdev); > + > +/** > + * ocxl_link_lpc_release() - Release the LPC memory device for an OpenCAPI device > + * > + * Offlines LPC memory on an OpenCAPI link for a device. If this is the > + * last device on the link to release the memory, unmap it from the link. > + * > + * @link_handle: The OpenCAPI link handle > + * @pdev: A device that is on the link > + */ > +void ocxl_link_lpc_release(void *link_handle, struct pci_dev *pdev); > + > #endif /* _OCXL_INTERNAL_H_ */ > -- > 2.24.1 >
On 1/4/20 7:48 pm, Dan Williams wrote: > On Sun, Mar 29, 2020 at 10:53 PM Alastair D'Silva <alastair@d-silva.org> wrote: >> >> OpenCAPI LPC memory is allocated per link, but each link supports >> multiple AFUs, and each AFU can have LPC memory assigned to it. > > Is there an OpenCAPI primer to decode these objects and their > associations that I can reference? There isn't presently a primer that I think addresses these questions nicely (to my knowledge - Fred might have something he can link to?) - there are the specs published by the OpenCAPI Consortium at https://opencapi.org but they're really for hardware implementers. We should probably expand what's currently documented in Documentation/userspace-api/accelerators/ocxl.rst generally, and this series should probably update that to include details on LPC. To explain the specific objects here: - A "link" is a point-to-point link between the host CPU, and a single OpenCAPI card. (We don't currently support cards making use of multiple links for increased bandwidth, though that is supported from a hardware point of view.) - On POWER9, each link appears as a separate PCI domain, with a single bus, and the card appears as a single device. - A device can have up to 8 functions, per PCI. - An Attached Functional Unit (AFU) is the abstraction for a particular application function. Each PCI function defines the number of AFUs it has through a set of OpenCAPI-specific DVSECs, max 64 per function. The ocxl driver handles AFU discovery. - On the host side, LPC memory is mapped by setting a single BAR for the whole link, but on the device side, LPC memory is requested on a per-AFU basis, through an AFU descriptor that is exposed through the aforementioned DVSECs. Hence the need to loop through the AFUs and get the total required LPC memory to work out the correct BAR value.
diff --git a/drivers/misc/ocxl/core.c b/drivers/misc/ocxl/core.c index b7a09b21ab36..2531c6cf19a0 100644 --- a/drivers/misc/ocxl/core.c +++ b/drivers/misc/ocxl/core.c @@ -230,8 +230,18 @@ static int configure_afu(struct ocxl_afu *afu, u8 afu_idx, struct pci_dev *dev) if (rc) goto err_free_pasid; + if (afu->config.lpc_mem_size || afu->config.special_purpose_mem_size) { + rc = ocxl_link_add_lpc_mem(afu->fn->link, afu->config.lpc_mem_offset, + afu->config.lpc_mem_size + + afu->config.special_purpose_mem_size); + if (rc) + goto err_free_mmio; + } + return 0; +err_free_mmio: + unmap_mmio_areas(afu); err_free_pasid: reclaim_afu_pasid(afu); err_free_actag: diff --git a/drivers/misc/ocxl/link.c b/drivers/misc/ocxl/link.c index 58d111afd9f6..af119d3ef79a 100644 --- a/drivers/misc/ocxl/link.c +++ b/drivers/misc/ocxl/link.c @@ -84,6 +84,11 @@ struct ocxl_link { int dev; atomic_t irq_available; struct spa *spa; + struct mutex lpc_mem_lock; /* protects lpc_mem & lpc_mem_sz */ + u64 lpc_mem_sz; /* Total amount of LPC memory presented on the link */ + u64 lpc_mem; + int lpc_consumers; + void *platform_data; }; static struct list_head links_list = LIST_HEAD_INIT(links_list); @@ -396,6 +401,8 @@ static int alloc_link(struct pci_dev *dev, int PE_mask, struct ocxl_link **out_l if (rc) goto err_spa; + mutex_init(&link->lpc_mem_lock); + /* platform specific hook */ rc = pnv_ocxl_spa_setup(dev, link->spa->spa_mem, PE_mask, &link->platform_data); @@ -711,3 +718,56 @@ void ocxl_link_free_irq(void *link_handle, int hw_irq) atomic_inc(&link->irq_available); } EXPORT_SYMBOL_GPL(ocxl_link_free_irq); + +int ocxl_link_add_lpc_mem(void *link_handle, u64 offset, u64 size) +{ + struct ocxl_link *link = (struct ocxl_link *)link_handle; + + // Check for overflow + if (offset > (offset + size)) + return -EINVAL; + + mutex_lock(&link->lpc_mem_lock); + link->lpc_mem_sz = max(link->lpc_mem_sz, offset + size); + + mutex_unlock(&link->lpc_mem_lock); + + return 0; +} + +u64 ocxl_link_lpc_map(void *link_handle, struct pci_dev *pdev) +{ + struct ocxl_link *link = (struct ocxl_link *)link_handle; + + mutex_lock(&link->lpc_mem_lock); + + if (!link->lpc_mem) + link->lpc_mem = pnv_ocxl_platform_lpc_setup(pdev, link->lpc_mem_sz); + + if (link->lpc_mem) + link->lpc_consumers++; + mutex_unlock(&link->lpc_mem_lock); + + return link->lpc_mem; +} + +void ocxl_link_lpc_release(void *link_handle, struct pci_dev *pdev) +{ + struct ocxl_link *link = (struct ocxl_link *)link_handle; + + mutex_lock(&link->lpc_mem_lock); + + if (!link->lpc_mem) { + mutex_unlock(&link->lpc_mem_lock); + return; + } + + WARN_ON(--link->lpc_consumers < 0); + + if (link->lpc_consumers == 0) { + pnv_ocxl_platform_lpc_release(pdev); + link->lpc_mem = 0; + } + + mutex_unlock(&link->lpc_mem_lock); +} diff --git a/drivers/misc/ocxl/ocxl_internal.h b/drivers/misc/ocxl/ocxl_internal.h index 198e4e4bc51d..2d7575225bd7 100644 --- a/drivers/misc/ocxl/ocxl_internal.h +++ b/drivers/misc/ocxl/ocxl_internal.h @@ -142,4 +142,37 @@ int ocxl_irq_offset_to_id(struct ocxl_context *ctx, u64 offset); u64 ocxl_irq_id_to_offset(struct ocxl_context *ctx, int irq_id); void ocxl_afu_irq_free_all(struct ocxl_context *ctx); +/** + * ocxl_link_add_lpc_mem() - Increment the amount of memory required by an OpenCAPI link + * + * @link_handle: The OpenCAPI link handle + * @offset: The offset of the memory to add + * @size: The number of bytes to increment memory on the link by + * + * Returns 0 on success, -EINVAL on overflow + */ +int ocxl_link_add_lpc_mem(void *link_handle, u64 offset, u64 size); + +/** + * ocxl_link_lpc_map() - Map the LPC memory for an OpenCAPI device + * Since LPC memory belongs to a link, the whole LPC memory available + * on the link must be mapped in order to make it accessible to a device. + * @link_handle: The OpenCAPI link handle + * @pdev: A device that is on the link + * + * Returns the address of the mapped LPC memory, or 0 on error + */ +u64 ocxl_link_lpc_map(void *link_handle, struct pci_dev *pdev); + +/** + * ocxl_link_lpc_release() - Release the LPC memory device for an OpenCAPI device + * + * Offlines LPC memory on an OpenCAPI link for a device. If this is the + * last device on the link to release the memory, unmap it from the link. + * + * @link_handle: The OpenCAPI link handle + * @pdev: A device that is on the link + */ +void ocxl_link_lpc_release(void *link_handle, struct pci_dev *pdev); + #endif /* _OCXL_INTERNAL_H_ */
OpenCAPI LPC memory is allocated per link, but each link supports multiple AFUs, and each AFU can have LPC memory assigned to it. This patch tallys the memory for all AFUs on a link, allowing it to be mapped in a single operation after the AFUs have been enumerated. Signed-off-by: Alastair D'Silva <alastair@d-silva.org> --- drivers/misc/ocxl/core.c | 10 ++++++ drivers/misc/ocxl/link.c | 60 +++++++++++++++++++++++++++++++ drivers/misc/ocxl/ocxl_internal.h | 33 +++++++++++++++++ 3 files changed, 103 insertions(+)