[Intel-xe] [PATCH 2/3] drm/xe: Introduce XeLink device

Rodrigo Vivi rodrigo.vivi at intel.com
Tue Aug 8 18:43:14 UTC 2023


On Tue, Aug 08, 2023 at 12:45:33PM -0400, David Kershner wrote:
> Add XeLink support for PVC devices.
> 
> Introduce the initial platform data structure that will be shared
> between the Xe driver and the XeLink driver.
> 
> If the device is PVC, and there is an XeLink device present, add
> and initialize an Auxbus device with the appropriate resources.
> 
> Add the XeLink information register.
> 
> Add package address register for defining the Device Physical Address
> space (DPA).
> 
> Add initial interrupt support.
> 
> The package address register defines the device physical
> address (DPA) space for the given device.
> 
> Using the "unique" xa_array index, generate a DPA address
> for the device and program the package register appropriately.
> 
> Update the LMEM offset to use the DPA address.
> 
> Signed-off-by: David Kershner <david.kershner at intel.com>
> ---
>  drivers/gpu/drm/xe/Kconfig           |   1 +
>  drivers/gpu/drm/xe/regs/xe_gt_regs.h |  20 ++
>  drivers/gpu/drm/xe/xe_device.c       |  13 +-
>  drivers/gpu/drm/xe/xe_device_types.h |  27 ++
>  drivers/gpu/drm/xe/xe_gt_types.h     |   2 +
>  drivers/gpu/drm/xe/xe_irq.c          |  28 +-
>  drivers/gpu/drm/xe/xe_mmio.c         |   2 +-
>  drivers/gpu/drm/xe/xe_pci.c          |   2 +
>  drivers/gpu/drm/xe/xe_pci_types.h    |   1 +
>  drivers/gpu/drm/xe/xe_xelink.c       | 447 +++++++++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_xelink.h       |  36 +++
>  include/drm/intel_xelink_platform.h  | 140 +++++++++
>  12 files changed, 716 insertions(+), 3 deletions(-)
>  create mode 100644 drivers/gpu/drm/xe/xe_xelink.h
>  create mode 100644 include/drm/intel_xelink_platform.h
> 
> diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
> index 0a4ea965645b..9d396ca7708a 100644
> --- a/drivers/gpu/drm/xe/Kconfig
> +++ b/drivers/gpu/drm/xe/Kconfig
> @@ -36,6 +36,7 @@ config DRM_XE
>  	select DRM_SCHED
>  	select MMU_NOTIFIER
>  	select WANT_DEV_COREDUMP
> +	select AUXILIARY_BUS
>  	help
>  	  Experimental driver for Intel Xe series GPUs
>  
> diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> index d654f3311351..fa78cbcd1058 100644
> --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h
> @@ -81,6 +81,11 @@
>  #define GLOBAL_MOCS(i)				XE_REG(0x4000 + (i) * 4) /* Global MOCS regs */
>  #define GFX_CCS_AUX_NV				XE_REG(0x4208)
>  
> +#define PKG_ADDR_RANGE				XE_REG(0x41B0)
> +#define   PKG_ADDR_RANGE_RANGE_SHIFT		20
> +#define   PKG_ADDR_RANGE_BASE_SHIFT		1
> +#define   PKG_ADDR_RANGE_ENABLE			1
> +
>  #define VD0_AUX_NV				XE_REG(0x4218)
>  #define VE0_AUX_NV				XE_REG(0x4238)
>  
> @@ -88,6 +93,11 @@
>  #define   AUX_INV				REG_BIT(0)
>  
>  #define XEHP_TILE_ADDR_RANGE(_idx)		XE_REG_MCR(0x4900 + (_idx) * 4)
> +#define   XEHP_TILE_LMEM_RANGE_SHIFT            8
> +#define   XEHP_TILE_LMEM_BASE_SHIFT             1
> +#define   XEHP_TILE_LMEM_BASE_MASK              REG_GENMASK(7, 1)
> +#define   XEHP_TILE_LMEM_RANGE_MASK             REG_GENMASK(14, 8)
> +
>  #define XEHP_FLAT_CCS_BASE_ADDR			XE_REG_MCR(0x4910)
>  
>  #define CHICKEN_RASTER_1			XE_REG_MCR(0x6204, XE_REG_OPTION_MASKED)
> @@ -349,6 +359,11 @@
>  #define RCU_MODE				XE_REG(0x14800, XE_REG_OPTION_MASKED)
>  #define   RCU_MODE_CCS_ENABLE			REG_BIT(0)
>  
> +#define PKG_ADDR_BASE				XE_REG(0x108390)
> +#define   PKG_ADDR_BASE_RANGE_SHIFT		20
> +#define   PKG_ADDR_BASE_BASE_SHIFT		1
> +#define   PKG_ADDR_BASE_ENABLE			1
> +
>  #define FORCEWAKE_ACK_GT			XE_REG(0x130044)
>  #define   FORCEWAKE_KERNEL			BIT(0)
>  #define   FORCEWAKE_USER			BIT(1)
> @@ -397,4 +412,9 @@
>  #define XEHPC_BCS5_BCS6_INTR_MASK		XE_REG(0x190118)
>  #define XEHPC_BCS7_BCS8_INTR_MASK		XE_REG(0x19011c)
>  
> +#define PUNIT_MMIO_CR_POC_STRAPS		XE_REG(0x281078)
> +#define NUM_TILES_MASK				REG_GENMASK(1, 0)
> +#define CD_ALIVE				REG_BIT(2)
> +#define SOCKET_ID_MASK				REG_GENMASK(7, 3)
> +
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c
> index 766df07de979..296953b7d512 100644
> --- a/drivers/gpu/drm/xe/xe_device.c
> +++ b/drivers/gpu/drm/xe/xe_device.c
> @@ -1,6 +1,6 @@
>  // SPDX-License-Identifier: MIT
>  /*
> - * Copyright © 2021 Intel Corporation
> + * Copyright © 2021 - 2023 Intel Corporation

we should probably do a fixup patch on the original files changing everything to 2023...

>   */
>  
>  #include "xe_device.h"
> @@ -34,6 +34,7 @@
>  #include "xe_vm.h"
>  #include "xe_vm_madvise.h"
>  #include "xe_wait_user_fence.h"
> +#include "xe_xelink.h"
>  
>  #ifdef CONFIG_LOCKDEP
>  struct lockdep_map xe_device_mem_access_lockdep_map = {
> @@ -262,6 +263,8 @@ int xe_device_probe(struct xe_device *xe)
>  	if (err)
>  		return err;
>  
> +	xe_xelink_init_early(xe);
> +
>  	for_each_tile(tile, xe, id) {
>  		err = xe_tile_alloc(tile);
>  		if (err)
> @@ -272,6 +275,8 @@ int xe_device_probe(struct xe_device *xe)
>  	if (err)
>  		return err;
>  
> +	xe_xelink_init_mmio(xe);
> +
>  	for_each_gt(gt, xe, id) {
>  		err = xe_pcode_probe(gt);
>  		if (err)
> @@ -292,6 +297,8 @@ int xe_device_probe(struct xe_device *xe)
>  			goto err_irq_shutdown;
>  	}
>  
> +	xe_xelink_init(xe);
> +
>  	err = xe_mmio_probe_vram(xe);
>  	if (err)
>  		goto err_irq_shutdown;
> @@ -333,6 +340,8 @@ int xe_device_probe(struct xe_device *xe)
>  
>  	xe_display_register(xe);
>  
> +	xe_xelink_init_aux(xe);
> +
>  	xe_debugfs_register(xe);
>  
>  	err = drmm_add_action_or_reset(&xe->drm, xe_device_sanitize, xe);
> @@ -365,6 +374,8 @@ void xe_device_remove(struct xe_device *xe)
>  
>  	xe_display_unlink(xe);
>  
> +	xe_xelink_remove(xe);
> +
>  	xe_irq_shutdown(xe);
>  }
>  
> diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h
> index f84ecb976f5d..7b27a5178aca 100644
> --- a/drivers/gpu/drm/xe/xe_device_types.h
> +++ b/drivers/gpu/drm/xe/xe_device_types.h
> @@ -16,6 +16,7 @@
>  #include "xe_gt_types.h"
>  #include "xe_platform_types.h"
>  #include "xe_step_types.h"
> +#include "xe_xelink.h"
>  
>  #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
>  #include "ext/intel_device_info.h"
> @@ -219,6 +220,10 @@ struct xe_device {
>  		u8 has_asid:1;
>  		/** @force_execlist: Forced execlist submission */
>  		u8 force_execlist:1;
> +		/** @has_xelink: Has XeLink */
> +		u8 has_xelink:1;
> +		/** @enable_guc: GuC submission enabled */
> +		u8 enable_guc:1;
>  		/** @has_flat_ccs: Whether flat CCS metadata is used */
>  		u8 has_flat_ccs:1;
>  		/** @has_4tile: Whether tile-4 tiling is supported */
> @@ -376,6 +381,28 @@ struct xe_device {
>  	 */
>  	struct task_struct *pm_callback_task;
>  
> +	/** @intel_xelink: XeLink information, for those gpus with XeLink connectivity */
> +	struct {
> +		/** @ops: shared interface operations */
> +		const struct xelink_ops *ops;
> +		/** @handle: XeLink device handle */
> +		void *handle;
> +		/** @pd: platform data needed for auxiliary bus */
> +		struct xelink_pdata *pd;
> +		/** @dpa: base device physical address */
> +		u64 dpa;
> +		/** @irq_base: base IRQ for multi tile devices */
> +		int irq_base;
> +		/** @index: internal index for xe devices */
> +		int index;
> +		/** @xelink_id: XeLink id generated by the XeLink device */
> +		u32 xelink_id;
> +		/** @socket_id: socket from certain platforms */
> +		u8 socket_id;
> +		/* @present: Reflect PUNIT presence information */
> +		bool present;
> +	} intel_xelink;
> +
>  	/* private: */
>  
>  #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
> diff --git a/drivers/gpu/drm/xe/xe_gt_types.h b/drivers/gpu/drm/xe/xe_gt_types.h
> index 35b8c19fa8bf..e9e551fea95b 100644
> --- a/drivers/gpu/drm/xe/xe_gt_types.h
> +++ b/drivers/gpu/drm/xe/xe_gt_types.h
> @@ -346,6 +346,8 @@ struct xe_gt {
>  		/** @oob: bitmap with active OOB workaroudns */
>  		unsigned long *oob;
>  	} wa_active;
> +	/** @xelink_irq: IRQ value assigned to the ANR HW */
> +	int xelink_irq;
>  };
>  
>  #endif
> diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c
> index 2022a5643e01..aaf9569426cc 100644
> --- a/drivers/gpu/drm/xe/xe_irq.c
> +++ b/drivers/gpu/drm/xe/xe_irq.c
> @@ -1,10 +1,11 @@
>  // SPDX-License-Identifier: MIT
>  /*
> - * Copyright © 2021 Intel Corporation
> + * Copyright © 2021 - 2023 Intel Corporation
>   */
>  
>  #include "xe_irq.h"
>  
> +#include <linux/irq.h>
>  #include <linux/sched/clock.h>
>  
>  #include <drm/drm_managed.h>
> @@ -27,6 +28,15 @@
>  #define IIR(offset)				XE_REG(offset + 0x8)
>  #define IER(offset)				XE_REG(offset + 0xc)
>  
> +/* Define the BAR and offset for XeLink CSRs */
> +#define XE_XELINK_IRQ BIT(8)
> +#define CD_BASE_OFFSET 0x291000
> +#define CD_BAR_SIZE (256 * 1024)
> +
> +#define CPORT_MBDB_CSRS				XE_REG(CD_BASE_OFFSET + 0x6000)
> +#define CPORT_MBDB_CSRS_END			XE_REG(CD_BASE_OFFSET + 0x1000)
> +#define CPORT_MBDB_INT_ENABLE_MASK		XE_REG(CD_BASE_OFFSET + 0x8)
> +
>  static void assert_iir_is_zero(struct xe_gt *mmio, struct xe_reg reg)
>  {
>  	u32 val = xe_mmio_read32(mmio, reg);
> @@ -362,6 +372,18 @@ static void dg1_intr_enable(struct xe_device *xe, bool stall)
>  		xe_mmio_read32(mmio, DG1_MSTR_TILE_INTR);
>  }
>  
> +/*
> + * xelink_irq_handler - handle XeLink IRQs
> + *
> + * PVC can have an XeLink attached.  Handle the IRQs that are sourced by
> + * the device supporting the XeLink.
> + */
> +static void xelink_irq_handler(struct xe_gt *gt, const u32 master_ctl)
> +{
> +	if (master_ctl & XE_XELINK_IRQ)
> +		generic_handle_irq(gt->xelink_irq);
> +}
> +
>  /*
>   * Top-level interrupt handler for Xe_LP+ and beyond.  These platforms have
>   * a "master tile" interrupt register which must be consulted before the
> @@ -423,6 +445,7 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg)
>  			xe_display_irq_handler(xe, master_ctl);
>  			gu_misc_iir = gu_misc_irq_ack(xe, master_ctl);
>  		}
> +		xelink_irq_handler(mmio, master_ctl);
>  	}
>  
>  	dg1_intr_enable(xe, false);
> @@ -469,6 +492,9 @@ static void gt_irq_reset(struct xe_tile *tile)
>  	xe_mmio_write32(mmio, GPM_WGBOXPERF_INTR_MASK,  ~0);
>  	xe_mmio_write32(mmio, GUC_SG_INTR_ENABLE,	 0);
>  	xe_mmio_write32(mmio, GUC_SG_INTR_MASK,		~0);
> +
> +	if (tile->xe->intel_xelink.present)
> +		xe_mmio_write64(mmio, CPORT_MBDB_INT_ENABLE_MASK, 0);
>  }
>  
>  static void xelp_irq_reset(struct xe_tile *tile)
> diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c
> index aa9c573b1243..1b0184135d45 100644
> --- a/drivers/gpu/drm/xe/xe_mmio.c
> +++ b/drivers/gpu/drm/xe/xe_mmio.c
> @@ -173,7 +173,7 @@ static int xe_determine_lmem_bar_size(struct xe_device *xe)
>  	if (!xe->mem.vram.io_size)
>  		return -EIO;
>  
> -	xe->mem.vram.base = 0; /* DPA offset */
> +	xe->mem.vram.base = xe->intel_xelink.dpa;
>  
>  	/* set up a map to the total memory area. */
>  	xe->mem.vram.mapping = ioremap_wc(xe->mem.vram.io_start, xe->mem.vram.io_size);
> diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
> index 46e3a9632efe..a2258524c577 100644
> --- a/drivers/gpu/drm/xe/xe_pci.c
> +++ b/drivers/gpu/drm/xe/xe_pci.c
> @@ -162,6 +162,7 @@ static const struct xe_graphics_desc graphics_xehpc = {
>  
>  	.has_asid = 1,
>  	.has_flat_ccs = 0,
> +	.has_xelink = 1,
>  	.has_link_copy_engine = 1,
>  	.supports_usm = 1,
>  };
> @@ -563,6 +564,7 @@ static int xe_info_init(struct xe_device *xe,
>  	xe->info.vm_max_level = graphics_desc->vm_max_level;
>  	xe->info.supports_usm = graphics_desc->supports_usm;
>  	xe->info.has_asid = graphics_desc->has_asid;
> +	xe->info.has_xelink = graphics_desc->has_xelink;
>  	xe->info.has_flat_ccs = graphics_desc->has_flat_ccs;
>  	xe->info.has_range_tlb_invalidation = graphics_desc->has_range_tlb_invalidation;
>  	xe->info.has_link_copy_engine = graphics_desc->has_link_copy_engine;
> diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h
> index ba31b933eb8e..85fec0c9e638 100644
> --- a/drivers/gpu/drm/xe/xe_pci_types.h
> +++ b/drivers/gpu/drm/xe/xe_pci_types.h
> @@ -22,6 +22,7 @@ struct xe_graphics_desc {
>  	u8 max_remote_tiles:2;
>  
>  	u8 has_asid:1;
> +	u8 has_xelink:1;
>  	u8 has_flat_ccs:1;
>  	u8 has_link_copy_engine:1;
>  	u8 has_range_tlb_invalidation:1;
> diff --git a/drivers/gpu/drm/xe/xe_xelink.c b/drivers/gpu/drm/xe/xe_xelink.c
> index 51a31f6a4740..ac4cff76f81d 100644
> --- a/drivers/gpu/drm/xe/xe_xelink.c
> +++ b/drivers/gpu/drm/xe/xe_xelink.c
> @@ -3,7 +3,20 @@
>   * Copyright © 2023 Intel Corporation
>   */
>  
> +#include <linux/auxiliary_bus.h>
> +#include <linux/firmware.h>
> +#include <linux/irq.h>
>  #include <linux/moduleparam.h>
> +#include <linux/xarray.h>
> +
> +#include <drm/intel_xelink_platform.h>
> +
> +#include "xe_device.h"
> +#include "xe_mmio.h"
> +#include "xe_gt_mcr.h"
> +#include "xe_xelink.h"
> +#include "regs/xe_reg_defs.h"
> +#include "regs/xe_gt_regs.h"
>  
>  /*
>   * This module parameter is needed because SRIOV PF and XeLink are mutually
> @@ -15,3 +28,437 @@
>  static bool xe_enable_xelink = true;
>  module_param_named(enable_xelink, xe_enable_xelink, bool, 0400);
>  MODULE_PARM_DESC(enable_xelink, "Enable XeLink feature (default: true)");
> +
> +#define HAS_XELINK(xe) ((xe)->info.has_xelink)
> +/* Define the BAR and offset for the XeLink CSRs */
> +#define GTTMMADR_BAR 0
> +#define CD_BASE_OFFSET 0x291000
> +#define CD_BAR_SIZE (256 * 1024)
> +
> +/* Xarray of XeLink devices */
> +static DEFINE_XARRAY_ALLOC(intel_fdevs);
> +
> +static struct query_info *default_query(void *handle, u32 xelink_id)
> +{
> +	return ERR_PTR(-EOPNOTSUPP);
> +}
> +
> +static int default_handle_event(void *handle, enum xelink_parent_event event)
> +{
> +	return -EOPNOTSUPP;
> +}
> +
> +static const struct xelink_ops default_ops = {
> +	.connectivity_query = default_query,
> +	.parent_event = default_handle_event,
> +};
> +
> +static int register_dev(void *parent, void *handle, u32 xelink_id,
> +			const struct xelink_ops *ops)
> +{
> +	struct xe_device *xe = parent;
> +
> +	WARN(xe->intel_xelink.ops != &default_ops, "XeLink: already registered");
> +
> +	xe->intel_xelink.handle = handle;
> +	xe->intel_xelink.xelink_id = xelink_id;
> +	xe->intel_xelink.ops = ops;
> +
> +	drm_info(&xe->drm, "XeLink: registered: 0x%x\n", xelink_id);
> +
> +	return 0;
> +}
> +
> +static void unregister_dev(void *parent, const void *handle)
> +{
> +	struct xe_device *xe = parent;
> +
> +	WARN(xe->intel_xelink.handle != handle, "XeLink: invalid handle");
> +
> +	drm_info(&xe->drm, "XeLink: unregistered: 0x%x\n",
> +		 xe->intel_xelink.xelink_id);
> +	xe->intel_xelink.handle = NULL;
> +	xe->intel_xelink.ops = &default_ops;
> +}
> +
> +static int dev_event(void *parent, void *handle, enum xelink_dev_event event,
> +		     void *event_data)
> +{
> +	return 0;
> +}
> +
> +/**
> + * init_pd - Allocate and initialize platform specific data
> + * @xe: Valid xe instance
> + *
> + * Return:
> + * * pd - initialized xelink_pdata,
> + * * NULL - Allocation failure
> + */
> +static struct xelink_pdata *init_pd(struct xe_device *xe)
> +{
> +	struct xelink_pdata *pd;
> +	u32 reg;
> +
> +	pd = kzalloc(sizeof(*pd), GFP_KERNEL);
> +	if (!pd)
> +		return NULL;
> +
> +	pd->version = XELINK_VERSION;
> +	pd->parent = xe;
> +	pd->product = XELINK_PONTEVECCHIO;
> +	pd->index = xe->intel_xelink.index & 0xFFFF;
> +	pd->sd_cnt = xe->info.tile_count;
> +	pd->socket_id = xe->intel_xelink.socket_id;
> +	pd->slot = PCI_SLOT(to_pci_dev(xe->drm.dev)->devfn);
> +
> +	pd->resources = NULL;
> +	pd->num_resources = 0;
> +	pd->register_dev = register_dev;
> +	pd->unregister_dev = unregister_dev;
> +	pd->dev_event = dev_event;
> +
> +	/*
> +	 * Calculate the actual DPA offset and size (in GB) for the device.
> +	 * Each tile will have the same amount of memory, so we only need to
> +	 * read the first one.
> +	 */
> +	reg = xe_gt_mcr_unicast_read_any(xe_device_get_root_tile(xe)->primary_gt,
> +					 XEHP_TILE_ADDR_RANGE(0)) & XEHP_TILE_LMEM_RANGE_MASK;
> +
> +	// TILE0 is < 8Gb, PVC needs 8GB, so fake it.
> +	if (reg >> XEHP_TILE_LMEM_RANGE_SHIFT < 8) {
> +		drm_err(&xe->drm, "XEHP_TILE0_ADDR_RANGE: %x\n", reg);
> +		reg = 8 << XEHP_TILE_LMEM_RANGE_SHIFT;
> +	}
> +	pd->dpa.pkg_offset = (u32)xe->intel_xelink.index * MAX_DPA_SIZE;
> +	pd->dpa.pkg_size = (reg >> XEHP_TILE_LMEM_RANGE_SHIFT) * pd->sd_cnt;
> +
> +	return pd;
> +}
> +
> +/**
> + * init_resource - Create the resource array, and apply the appropriate data
> + * @xe: valid xe instance
> + * @res_cnt: pointer to return number of allocated resources
> + *
> + * First resource [0] is for the IRQ(s).  Each device gets 1 IRQ. Subsequent
> + * resources describe the IO memory space for the device(s).
> + *
> + * Make sure to set the gt->xelink_irq value.
> + *
> + * Return:
> + * * res - Initialized resource array
> + * * NULL - Allocaction failure
> + */
> +static struct resource *init_resource(struct xe_device *xe,
> +				      u32 *res_cnt)
> +{
> +	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
> +	struct xe_gt *gt;
> +	struct resource *res_base, *res;
> +	u32 cnt = xe->info.tile_count * 2;
> +	unsigned int i;
> +
> +	/* Each sd gets one resource for IRQ and one for MEM */
> +	res_base = kcalloc(cnt, sizeof(*res_base), GFP_KERNEL);
> +	if (!res_base)
> +		return NULL;
> +
> +	res = res_base;
> +	for_each_gt(gt, xe, i) {
> +		res->start = xe->intel_xelink.irq_base + i;
> +		res->end = xe->intel_xelink.irq_base + i;
> +		res->flags = IORESOURCE_IRQ;
> +		res++;
> +
> +		res->start = pci_resource_start(pdev, GTTMMADR_BAR) + CD_BASE_OFFSET +
> +			     i * gt_to_tile(gt)->mmio.size;
> +		res->end = res->start + CD_BAR_SIZE - 1;
> +		res->flags = IORESOURCE_MEM;
> +		drm_info(&xe->drm, "XeLink: mem_resource = %pR\n", res);
> +		res++;
> +		gt->xelink_irq = xe->intel_xelink.irq_base + i;
> +	}
> +
> +	*res_cnt = cnt;
> +	return res_base;
> +}
> +
> +/**
> + * xelink_irq_mask - Null callback.  Masking/unmasking happens in the parent
> + * driver
> + * @d: Valid irq_data information
> + */
> +static void xelink_irq_mask(struct irq_data *d)
> +{
> +}
> +
> +static void xelink_irq_unmask(struct irq_data *d)
> +{
> +}
> +
> +static struct irq_chip xelink_irq_chip = {
> +	.name = "xelink_irq_chip",
> +	.irq_mask = xelink_irq_mask,
> +	.irq_unmask = xelink_irq_unmask,
> +};
> +
> +/**
> + * init_irq_desc - Allocate IRQ descriptors to use for the xelink
> + * @xe: Valid xe instance
> + *
> + * Allocate the required IRQ descriptor(s) and initialize the
> + * appropriate state.
> + *
> + * Return:
> + * * 0 - Success
> + * * errno - Error that occurred
> + */
> +static int init_irq_desc(struct xe_device *xe)
> +{
> +	unsigned int num_subdevs = xe->info.tile_count;
> +	int err;
> +	int irq;
> +	int irq_base;
> +
> +	irq_base = irq_alloc_descs(-1, 0, num_subdevs, 0);
> +	if (irq_base < 0) {
> +		err = irq_base;
> +		goto cleanup;
> +	}
> +
> +	err = 0;
> +	for (irq = irq_base; !err && irq < irq_base + num_subdevs; irq++) {
> +		irq_set_chip_and_handler_name(irq, &xelink_irq_chip,
> +					      handle_simple_irq,
> +					      "xelink_irq_handler");
> +		err = irq_set_chip_data(irq, xe);
> +	}
> +
> +	if (err) {
> +		irq_free_descs(irq_base, num_subdevs);
> +		goto cleanup;
> +	}
> +
> +	drm_info(&xe->drm, "XeLink: IRQ base: %d  cnt: %d\n", irq_base,
> +		 num_subdevs);
> +
> +	xe->intel_xelink.irq_base = irq_base;
> +
> +	return 0;
> +
> +cleanup:
> +	xe->intel_xelink.index = err;
> +	drm_err(&xe->drm, "XeLink: Failed to allocate IRQ data: %d\n", err);
> +	return err;
> +}
> +
> +/**
> + * xe_xelink_init_early - Set the XeLink info to the defaults
> + * @xe: valid xe instance
> + *
> + * index is set to ENODEV to show that, by default, there is no device.
> + * If any of the initialization steps fail, it will be set to the appropriate
> + * errno value.
> + */
> +void xe_xelink_init_early(struct xe_device *xe)
> +{
> +	xe->intel_xelink.ops = &default_ops;
> +	xe->intel_xelink.index = -ENODEV;
> +}
> +
> +/**
> + * xe_xelink_init_mmio - check if XeLink is available via MMIO
> + * @xe: valid xe instance
> + *
> + * Read the relevant regs to check for XeLink availability and get the socket id
> + */
> +void xe_xelink_init_mmio(struct xe_device *xe)
> +{
> +	u32 xelink_info;
> +
> +	if (!HAS_XELINK(xe) || !xe_enable_xelink)
> +		return;
> +
> +	xelink_info = xe_mmio_read32(xe_device_get_root_tile(xe)->primary_gt,
> +				     PUNIT_MMIO_CR_POC_STRAPS);
> +
> +	xe->intel_xelink.socket_id = REG_FIELD_GET(SOCKET_ID_MASK, xelink_info);
> +
> +	if (REG_FIELD_GET(CD_ALIVE, xelink_info)) {
> +		drm_info(&xe->drm, "XeLink available\n");
> +		xe->intel_xelink.present = true;
> +	}
> +}
> +
> +/**
> + * xe_xelink_init - Allocate device index and complete initial HW setup
> + * @xe: valid device instance
> + *
> + * NOTE: index is zero inited.  If the XeLink is not present, or an error occurs
> + * during setup, this must be 0 for the range registers.
> + *
> + */
> +void xe_xelink_init(struct xe_device *xe)
> +{
> +	struct xe_gt *gt;
> +	static u32 last_id;
> +	unsigned int i;
> +	u32 index = 0;
> +	u32 range;
> +	u32 base;
> +	int err;
> +
> +	if (!HAS_XELINK(xe))
> +		return;
> +
> +	if (!xe->intel_xelink.present)
> +		goto set_range;
> +
> +	err = init_irq_desc(xe);
> +	if (err) {
> +		xe->intel_xelink.index = err;
> +		goto set_range;
> +	}
> +
> +	/*
> +	 * Try the socket id first.  Systems with this feature, will
> +	 * get a deterministic value.  If not, try with the cyclic.
> +	 */
> +	err = xa_insert(&intel_fdevs, xe->intel_xelink.socket_id, xe,
> +			GFP_KERNEL);
> +	if (!err)
> +		index = xe->intel_xelink.socket_id;
> +
> +	/* socket_id is not available */
> +	if (err == -EBUSY) {
> +		/*
> +		 * NOTE: index is only updated on success i.e. >= 0
> +		 * < 0 err, 0 ok, > 0 wrapped
> +		 */
> +		err = xa_alloc_cyclic(&intel_fdevs, &index, xe,
> +				      XA_LIMIT(0, MAX_DEVICE_COUNT - 1),
> +				      &last_id, GFP_KERNEL);
> +	}
> +	if (err < 0) {
> +		index = 0;
> +		xe->intel_xelink.index = err;
> +		drm_err(&xe->drm,
> +			"XeLink: Failed to allocate index: %d\n",
> +			err);
> +		irq_free_descs(xe->intel_xelink.irq_base,
> +			       xe->info.tile_count);
> +		goto set_range;
> +	}
> +	xe->intel_xelink.index = index;
> +	xe->intel_xelink.dpa = (u64)index * MAX_DPA_SIZE * SZ_1G;
> +	drm_info(&xe->drm, "XeLink: [dpa 0x%llx-0x%llx\n", xe->intel_xelink.dpa,
> +		 ((u64)index + 1) * MAX_DPA_SIZE * SZ_1G - 1);
> +
> +	/*
> +	 * Set range has to be done for all devices that support device
> +	 * address space, regardless of presence or error.
> +	 */
> +set_range:
> +	/* Set GAM address range registers */
> +	range = index * MAX_DPA_SIZE << PKG_ADDR_RANGE_BASE_SHIFT;
> +	range |= MAX_DPA_SIZE << PKG_ADDR_RANGE_RANGE_SHIFT;
> +	range |= PKG_ADDR_RANGE_ENABLE;
> +
> +	/* set SGunit address range register */
> +	base = index * MAX_DPA_SIZE << PKG_ADDR_BASE_BASE_SHIFT;
> +	base |= MAX_DPA_SIZE << PKG_ADDR_BASE_RANGE_SHIFT;
> +	base |= PKG_ADDR_BASE_ENABLE;
> +
> +	/* Needs to be set for each gt */
> +	for_each_gt(gt, xe, i) {
> +		xe_mmio_write32(gt, PKG_ADDR_RANGE, range);
> +		xe_mmio_write32(gt, PKG_ADDR_BASE, base);
> +	}
> +}
> +
> +static void xe_xelink_release_dev(struct device *dev)
> +{
> +	struct auxiliary_device *aux = to_auxiliary_dev(dev);
> +	struct xelink_pdata *pd = container_of(aux, struct xelink_pdata, aux_dev);
> +
> +	kfree(pd->resources);
> +	pd->resources = NULL;
> +
> +	kfree(pd);
> +}
> +
> +/**
> + * xe_xelink_init_aux - Initialize resources and add auxiliary bus interface
> + * @xe: valid xe instance
> + *
> + */
> +void xe_xelink_init_aux(struct xe_device *xe)
> +{
> +	struct device *dev = &to_pci_dev(xe->drm.dev)->dev;
> +	struct resource *res = NULL;
> +	struct xelink_pdata *pd;
> +	int err = -ENOMEM;
> +	u32 res_cnt;
> +
> +	if (!xe->intel_xelink.present)
> +		return;
> +
> +	if (xe->intel_xelink.index < 0) {
> +		err = xe->intel_xelink.index;
> +		goto fail;
> +	}
> +
> +	pd = init_pd(xe);
> +	if (!pd)
> +		goto cleanup;
> +
> +	res = init_resource(xe, &res_cnt);
> +	if (!res)
> +		goto cleanup;
> +
> +	pd->resources = res;
> +	pd->num_resources = res_cnt;
> +
> +	pd->aux_dev.name = "xelink";
> +	pd->aux_dev.id = pd->index;
> +	pd->aux_dev.dev.parent = dev;
> +	pd->aux_dev.dev.release = xe_xelink_release_dev;
> +
> +	err = auxiliary_device_init(&pd->aux_dev);
> +	if (err)
> +		goto cleanup;
> +
> +	err = auxiliary_device_add(&pd->aux_dev);
> +	if (err) {
> +		auxiliary_device_uninit(&pd->aux_dev);
> +		goto cleanup;
> +	}
> +
> +	xe->intel_xelink.pd = pd;
> +
> +	return;
> +
> +cleanup:
> +	xa_erase(&intel_fdevs, xe->intel_xelink.index);
> +	irq_free_descs(xe->intel_xelink.irq_base, xe->info.tile_count);
> +	kfree(res);
> +	kfree(pd);
> +	xe->intel_xelink.index = err;
> +fail:
> +	drm_err(&xe->drm, "XeLink: Failed to initialize err: %d\n", err);
> +}
> +
> +void xe_xelink_remove(struct xe_device *xe)
> +{
> +	if (xe->intel_xelink.index < 0)
> +		return;
> +
> +	auxiliary_device_delete(&xe->intel_xelink.pd->aux_dev);
> +	auxiliary_device_uninit(&xe->intel_xelink.pd->aux_dev);
> +	xa_erase(&intel_fdevs, xe->intel_xelink.index);
> +	irq_free_descs(xe->intel_xelink.irq_base, xe->info.tile_count);
> +
> +	xe->intel_xelink.ops = &default_ops;
> +}
> diff --git a/drivers/gpu/drm/xe/xe_xelink.h b/drivers/gpu/drm/xe/xe_xelink.h
> new file mode 100644
> index 000000000000..e17faacc7b1c
> --- /dev/null
> +++ b/drivers/gpu/drm/xe/xe_xelink.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright © 2019 - 2023 Intel Corporation
> + */
> +
> +#ifndef _XE_XELINK_H_
> +#define _XE_XELINK_H_
> +
> +/*
> + * Define the maximum number of devices instances based on the amount of
> + * FID space.
> + *
> + * XARRAY limits are "inclusive", but using this value as a range check
> + * outside of xarray, makes the exclusive upper bound a little easier to
> + * deal with.
> + *
> + * I.e.:
> + * [0 - 256)
> + *
> + * Less than HW supports, but more than will be currently possible.
> + *
> + */
> +#define MAX_DEVICE_COUNT 256
> +
> +/* Fixed Device Physical Address (DPA) size for a device/package (in GB) */
> +#define MAX_DPA_SIZE 128
> +
> +struct xe_device;
> +
> +void xe_xelink_init_early(struct xe_device *xe);
> +void xe_xelink_init_mmio(struct xe_device *xe);
> +void xe_xelink_init(struct xe_device *xe);
> +void xe_xelink_init_aux(struct xe_device *xe);
> +void xe_xelink_remove(struct xe_device *xe);
> +
> +#endif
> diff --git a/include/drm/intel_xelink_platform.h b/include/drm/intel_xelink_platform.h
> new file mode 100644
> index 000000000000..86eeb10fdc1e
> --- /dev/null
> +++ b/include/drm/intel_xelink_platform.h
> @@ -0,0 +1,140 @@
> +/* SPDX-License-Identifier: MIT */
> +/*
> + * Copyright(c) 2019 - 2023 Intel Corporation.
> + */
> +
> +#ifndef __INTEL_XELINK_PLATFORM_H
> +#define __INTEL_XELINK_PLATFORM_H
> +
> +#define XELINK_VERSION 1
> +
> +#include <linux/auxiliary_bus.h>
> +#include <linux/types.h>
> +
> +/**
> + * enum product_type - Product type identifying the parent
> + * @XELINK_UNDEFINED: no product type hints
> + * @XELINK_PONTEVECCHIO: parent is a PVC
> + * @XELINK_PRODUCTS: end of the list
> + *
> + */
> +enum product_type {
> +	XELINK_UNDEFINED,
> +	XELINK_PONTEVECCHIO,
> +	XELINK_PRODUCTS
> +};
> +
> +/**
> + * enum xelink_dev_event - events generated to the parent device
> + * @XELINK_DEV_REMOVE: Xelink device was removed
> + * @XELINK_DEV_ERROR: An error occurred
> + * @XELINK_DEV_EVENTS: end of list
> + *
> + * Connectivity events, possible errors, etc.
> + */
> +enum xelink_dev_event {
> +	XELINK_DEV_REMOVE,
> +	XELINK_DEV_EVENTS
> +};
> +
> +/**
> + * enum xelink_parent_event - Events generated by the parent device
> + * @XELINK_PARENT_PCIE_ERR: Parent had a PCI error
> + * @XELINK_PARENT_MAPPING_GET: Notify XeLink of buffer mapping
> + * @XELINK_PARENT_MAPPING_PUT: Notify XeLink of buffer unmapping
> + *
> + * These are examples.
> + */
> +enum xelink_parent_event {
> +	XELINK_PARENT_PCIE_ERR,
> +	XELINK_PARENT_MAPPING_GET,
> +	XELINK_PARENT_MAPPING_PUT,
> +};
> +
> +/**
> + * struct sd2sd_info - Subdevice to subdevice connectivity info
> + * @bandwidth: in Gbps units not factoring in width or quality degredation
> + * @latency: in 1/10 hops units
> + */
> +struct sd2sd_info {
> +	u16 bandwidth;
> +	u16 latency;
> +};
> +
> +/**
> + * struct query_info - connectivity query response information
> + * @src_cnt: Requester subdevice count
> + * @dst_cnt: Destination path count
> + * @sd2sd: array of src/dst bandwidth/latency information
> + *
> + * Query info will be a variably sized data structure allocated by the
> + * XeLink driver.  The access will be indexed by
> + *    (src_index * dst_cnt) + dst_index
> + *
> + * The caller will need to free the buffer when done.
> + */
> +struct query_info {
> +	u8 src_cnt;
> +	u8 dst_cnt;
> +	struct sd2sd_info sd2sd[];
> +};
> +
> +/**
> + * struct xelink_ops - Communication path from parent to XeLink instance
> + * @connectivity_query: Query a device for xelink_id connectivity
> + * @parent_event: Any events needed by the XeLink device
> + *
> + * connectivity_query() returns:
> + *   a populated query_info on success,
> + *   an ERR_PTR() on failure
> + *
> + */
> +struct xelink_ops {
> +	struct query_info *(*connectivity_query)(void *handle, u32 xelink_id);
> +	int (*parent_event)(void *handle, enum xelink_parent_event event);
> +};
> +
> +struct dpa_space {
> +	u32 pkg_offset;
> +	u16 pkg_size;
> +};
> +
> +/**
> + * struct xelink_pdata - Platform specific data that needs to be shared
> + * @version: PSD version information
> + * @parent: Handle to use when calling the parent device
> + * @product: a product hint for any necessary special case requirements
> + * @index: unique device index. This will be part of the device name
> + * @dpa: Device physical address offset and size
> + * @sd_cnt: parent subdevice count
> + * @socket_id: device socket information
> + * @slot: PCI/CXL slot number
> + * @aux_dev: Auxiliary bus device
> + * @resources: Array of resources (Assigned by Xe, the IRQ/MEM for the device)
> + * @num_resources: number of resources in resources array
> + * @register_dev: Register a XeLink instance and ops with the parent device
> + * @unregister_dev: Unregister a XeLink instance from the parent device
> + * @dev_event: Notify parent that an event has occurred
> + */
> +struct xelink_pdata {
> +	u16 version;
> +	void *parent;
> +	enum product_type product;
> +	u16 index;
> +	struct dpa_space dpa;
> +	u8 sd_cnt;
> +	u8 socket_id;
> +	u8 slot;
> +
> +	struct auxiliary_device aux_dev;
> +	struct resource *resources;
> +	u32 num_resources;
> +
> +	int (*register_dev)(void *parent, void *handle, u32 xelink_id,
> +			    const struct xelink_ops *ops);
> +	void (*unregister_dev)(void *parent, const void *handle);
> +	int (*dev_event)(void *parent, void *handle,
> +			 enum xelink_dev_event event, void *event_data);
> +};
> +
> +#endif /* __INTEL_XELINK_PLATFORM_H */
> -- 
> 2.35.1
> 

Everything else looks good to me. It would be good to get a deeper reviewer from
the Xelink team.

Acked-by: Rodrigo Vivi <rodrigo.vivi at intel.com>



More information about the Intel-xe mailing list