[Intel-xe] [PATCH v3 3/3] drm/xe: Introduce Intel Accelerator fabric driver
David Kershner
david.kershner at intel.com
Fri Jun 23 04:12:57 UTC 2023
Add the Intel accelerated fabric driver infrastructure and driver
framework.
Signed-off-by: David Kershner <david.kershner at intel.com>
---
drivers/gpu/drm/xe/Kconfig | 5 +
drivers/gpu/drm/xe/Makefile | 1 +
drivers/gpu/drm/xe/fabric/Kconfig | 18 +
drivers/gpu/drm/xe/fabric/Makefile | 12 +
drivers/gpu/drm/xe/fabric/csr.h | 493 ++++++++++++++++++++++
drivers/gpu/drm/xe/fabric/iaf_drv.h | 278 ++++++++++++
drivers/gpu/drm/xe/fabric/main.c | 632 ++++++++++++++++++++++++++++
drivers/gpu/drm/xe/fabric/sysfs.c | 114 +++++
drivers/gpu/drm/xe/fabric/sysfs.h | 16 +
9 files changed, 1569 insertions(+)
create mode 100644 drivers/gpu/drm/xe/fabric/Kconfig
create mode 100644 drivers/gpu/drm/xe/fabric/Makefile
create mode 100644 drivers/gpu/drm/xe/fabric/csr.h
create mode 100644 drivers/gpu/drm/xe/fabric/iaf_drv.h
create mode 100644 drivers/gpu/drm/xe/fabric/main.c
create mode 100644 drivers/gpu/drm/xe/fabric/sysfs.c
create mode 100644 drivers/gpu/drm/xe/fabric/sysfs.h
diff --git a/drivers/gpu/drm/xe/Kconfig b/drivers/gpu/drm/xe/Kconfig
index e4be3749778a..21a4daa3b6d6 100644
--- a/drivers/gpu/drm/xe/Kconfig
+++ b/drivers/gpu/drm/xe/Kconfig
@@ -84,3 +84,8 @@ depends on DRM_XE
depends on EXPERT
source "drivers/gpu/drm/xe/Kconfig.debug"
endmenu
+
+menu "drm/xe/fabric Intel Fabric Connectivity driver support"
+ depends on DRM_XE
+ source "drivers/gpu/drm/xe/fabric/Kconfig"
+endmenu
diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile
index b2a992884c0f..4fa00b9a8f24 100644
--- a/drivers/gpu/drm/xe/Makefile
+++ b/drivers/gpu/drm/xe/Makefile
@@ -230,6 +230,7 @@ endif
obj-$(CONFIG_DRM_XE) += xe.o
obj-$(CONFIG_DRM_XE_KUNIT_TEST) += tests/
+obj-$(CONFIG_DRM_XE_INTEL_FABRIC) += fabric/
# header test
hdrtest_find_args := -not -path xe_rtp_helpers.h
diff --git a/drivers/gpu/drm/xe/fabric/Kconfig b/drivers/gpu/drm/xe/fabric/Kconfig
new file mode 100644
index 000000000000..082df4771545
--- /dev/null
+++ b/drivers/gpu/drm/xe/fabric/Kconfig
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DRM_XE_INTEL_FABRIC
+ tristate "Intel Fabric Connectivity driver support"
+ depends on 64BIT
+ depends on NET
+ select LIBCRC32C
+ default m
+ help
+ This kernel driver provides support for the Intel glueless
+ fabric adapter. The Intel fabric adapter allows GPUs to share
+ device memory space in a device specific address space.
+
+config IAF_DEBUG_ENABLE
+ bool "Enable Intel Accelerator Fabric debug configurations"
+ depends on DRM_XE_INTEL_FABRIC
+ default n
+ help
+ Support Intel Accelerator Fabric debug Kconfig options
diff --git a/drivers/gpu/drm/xe/fabric/Makefile b/drivers/gpu/drm/xe/fabric/Makefile
new file mode 100644
index 000000000000..2f753efffc5d
--- /dev/null
+++ b/drivers/gpu/drm/xe/fabric/Makefile
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: MIT
+#
+# Copyright(c) 2020 - 2023 Intel Corporation.
+#
+# Intel Connectivity fabric driver
+#
+#
+
+obj-$(CONFIG_DRM_XE_INTEL_FABRIC) += iaf.o
+
+iaf-y := main.o \
+ sysfs.o \
diff --git a/drivers/gpu/drm/xe/fabric/csr.h b/drivers/gpu/drm/xe/fabric/csr.h
new file mode 100644
index 000000000000..6c5a831a92bd
--- /dev/null
+++ b/drivers/gpu/drm/xe/fabric/csr.h
@@ -0,0 +1,493 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2019 - 2023 Intel Corporation.
+ *
+ */
+
+#ifndef IAF_CSR_H_INCLUDED
+#define IAF_CSR_H_INCLUDED
+
+#include <linux/types.h>
+
+#define CSR_SIZE sizeof(u64)
+
+/*
+ * TOP CSRs
+ */
+
+#define CP_ADDR_TOP_BASE (0)
+#define CPORT_INIT_CTRL_ADDR (CP_ADDR_TOP_BASE + 0)
+#define RISC_RESET_BIT BIT_ULL(0)
+#define RISC_NMI_BIT BIT_ULL(2)
+#define RISC_PAUSED_BIT BIT_ULL(3)
+#define BOOTROM_PARITY_ERROR_BIT BIT_ULL(4)
+#define WATCHDOG_STATUS_BIT BIT_ULL(5)
+#define RISC_RESET_CAUSE_BIT BIT_ULL(7)
+#define DINIT_FSM_STATE_MASK GENMASK_ULL(31, 8)
+#define CSR_GPIO_CTRL (CP_ADDR_TOP_BASE + 0x18)
+#define GPIO_CTRL_PIN_LINK_CONFIG GENMASK_ULL(7, 3)
+#define GPIO_CTRL_OE_LINK_CONFIG GENMASK_ULL(15, 11)
+#define CSR_ASIC_REV_INFO (CP_ADDR_TOP_BASE + 0x40)
+#define MASK_ARI_PLATFORM GENMASK_ULL(55, 40)
+#define MASK_ARI_STEP GENMASK_ULL(39, 32)
+#define ARB_REG_BASE (CP_ADDR_TOP_BASE + 0x100)
+#define FW_MIN_SVN_ADDR (ARB_REG_BASE + 0x0)
+#define FW_UPDATED_SVN_ADDR (ARB_REG_BASE + 0x8)
+#define FW_SVN_MASK GENMASK_ULL(15, 0)
+
+#define CSR_ROPTION 0x80000008
+#define ROPTION_FORCE_FEC_HEAVY_ON BIT(0)
+#define ROPTION_CBUF_MGR_TRACE_XBAR BIT(1)
+#define ROPTION_CBUF_MGR_TRACE_PCI BIT(2)
+#define ROPTION_CBUF_MGR_TRACE_ATTRIBUTES BIT(3)
+#define ROPTION_PD_PHASE GENMASK(5, 4)
+#define ROPTION_STOP_IN_CONFIGLT_WITH_BCC BIT(6)
+#define ROPTION_TRACE_ERROR_RECOVERY BIT(7)
+#define ROPTION_EV_MODE BIT(8)
+#define ROPTION_TRACE_LNI_DEBUG BIT(9)
+#define ROPTION_TRACE_SBUS_OPS BIT(10)
+#define ROPTION_TRACE_STOP_ON_FULL BIT(11)
+#define ROPTION_12G_ALLOWED BIT(12)
+#define ROPTION_NO_DLA BIT(13)
+#define ROPTION_DYNAMIC_SCREEN BIT(14)
+#define ROPTION_UNUSED15 BIT(15)
+#define ROPTION_LOOP_BANDWIDTH GENMASK(20, 16)
+#define ROPTION_1D_CODING BIT(21)
+#define ROPTION_LCB_LOOPBACK GENMASK(23, 22)
+#define ROPTION_TX_PRBS_GEN BIT(24)
+#define ROPTION_STOP_IN_DEBOUNCE BIT(25)
+#define ROPTION_NO_TUNING_IN_DEBOUNCE BIT(26)
+#define ROPTION_CONFIGLT_NO_HAMMERS BIT(27)
+#define ROPTION_FORCE_LNI BIT(28)
+#define ROPTION_ALLOW_MARGINAL_LINKS BIT(29)
+#define ROPTION_FORCE_FEC_LIGHT_ON BIT(30)
+#define ROPTION_SERDES_ILB BIT(31)
+
+/*
+ * PORT CSRs
+ */
+
+#define CSR_PORTS_BASE 0x10000000
+
+/*
+ * Each port is at a 4MB offset from CSR_PORTS_BASE, index by physical port
+ * number.
+ */
+#define CSR_PORT_OFFSET 0x400000
+
+/*
+ * Fabric ports are in memory region 0, while bridge ports are in region 1.
+ *
+ * When referencing bridge port addresses, both when using the raw CSR ops
+ * as well as the LINK_MGR_PORT_CSR ops, you must add this offset to
+ * addresses.
+ */
+#define CSR_REGION1_OFFSET 0x20000000
+
+/**
+ * get_raw_port_base - Calculates the base address of the given port for
+ * use with the CSR_RAW ops.
+ * @ppn: physical port number
+ *
+ * Return: The base address required for the CSR_RAW ops.
+ */
+static inline u32 get_raw_port_base(u8 ppn)
+{
+ return CSR_PORTS_BASE + ((ppn) - 1) * CSR_PORT_OFFSET;
+}
+
+#define CSR_FIDGEN_BASE 0
+
+#define CSR_FIDGEN_MASK_A (CSR_FIDGEN_BASE + 0x00)
+#define CSR_FIDGEN_SHIFT_A (CSR_FIDGEN_BASE + 0x08)
+#define CSR_FIDGEN_MASK_B (CSR_FIDGEN_BASE + 0x10)
+#define CSR_FIDGEN_SHIFT_B (CSR_FIDGEN_BASE + 0x18)
+#define CSR_FIDGEN_RSVD0 (CSR_FIDGEN_BASE + 0x20)
+#define CSR_FIDGEN_RSVD1 (CSR_FIDGEN_BASE + 0x28)
+#define CSR_FIDGEN_MASK_H (CSR_FIDGEN_BASE + 0x30)
+#define CSR_FIDGEN_SHIFT_H (CSR_FIDGEN_BASE + 0x38)
+#define CSR_FIDGEN_MODULO (CSR_FIDGEN_BASE + 0x40)
+#define CSR_FIDGEN_WHOAMI (CSR_FIDGEN_BASE + 0x48)
+#define CSR_FIDGEN_MASK_D (CSR_FIDGEN_BASE + 0x50)
+#define CSR_FIDGEN_STATIC_RND (CSR_FIDGEN_BASE + 0x58)
+
+/*
+ * These apply to all of the shift registers. Bit 6 is the direction of
+ * shift, while bits 5 through 0 are the amount to shift by.
+ */
+#define MASK_FIDGEN_SHIFT_BY GENMASK(5, 0)
+#define MASK_FIDGEN_SHIFT_RIGHT GENMASK(6, 6)
+
+/*
+ * The LUT contains 8192 64-bit registers, each mapping a lookup index
+ * to a 20-bit DFID.
+ */
+#define CSR_FIDGEN_LUT_BASE (CSR_FIDGEN_BASE + 0x10000)
+
+#define CSR_FIDGEN_LUT_INDEX_WIDTH 13
+
+#define CSR_BRIDGE_TOP_BASE 0x30000
+
+#define CSR_BT_CTX_TRACKER_CFG CSR_BRIDGE_TOP_BASE
+#define MASK_BT_CTC_ENABLE_SRC GENMASK(0, 0)
+#define MASK_BT_CTC_ENABLE_DST GENMASK(1, 1)
+#define MASK_BT_CTC_DISABLE_TIMEOUT_SRC GENMASK(2, 2)
+#define MASK_BT_CTC_DISABLE_TIMEOUT_DST GENMASK(3, 3)
+
+#define CSR_BT_PORT_CTRL (CSR_BRIDGE_TOP_BASE + 0x08)
+#define MASK_BT_POC_DROP_FBRC_REQ GENMASK(0, 0)
+#define MASK_BT_POC_DROP_FBRC_REQ_ERR GENMASK(1, 1)
+#define MASK_BT_POC_DROP_MDFI_REQ GENMASK(2, 2)
+#define MASK_BT_POC_DROP_MDFI_REQ_ERR GENMASK(3, 3)
+#define MASK_BT_POC_DROP_FBRC_RSP GENMASK(4, 4)
+#define MASK_BT_POC_DROP_MDFI_RSP GENMASK(5, 5)
+
+#define CSR_BT_OUTSTANDING_TX (CSR_BRIDGE_TOP_BASE + 0x10)
+#define MASK_BT_OT_FBRC GENMASK(15, 0)
+#define MASK_BT_OT_MDFI GENMASK(31, 16)
+
+#define CSR_BT_FLUSH_CONTEXT (CSR_BRIDGE_TOP_BASE + 0x18)
+#define MASK_BT_FC_INITIATE GENMASK(0, 0)
+#define MASK_BT_FC_IN_PROGRESS GENMASK(1, 1)
+
+#define CSR_BT_PAUSE_CTRL (CSR_BRIDGE_TOP_BASE + 0x20)
+#define MASK_BT_PAC_FBRC_REQ GENMASK(0, 0)
+#define MASK_BT_PAC_MDFI_REQ GENMASK(1, 1)
+#define MASK_BT_PAC_FBRC_RSP GENMASK(2, 2)
+#define MASK_BT_PAC_MDFI_RSP GENMASK(3, 3)
+
+#define CSR_BT_PKG_ADDR_RANGE (CSR_BRIDGE_TOP_BASE + 0x28)
+#define MASK_BT_PAR_BASE GENMASK(18, 1)
+#define MASK_BT_PAR_RANGE GENMASK(29, 20)
+
+/* csr encodes address bits [45:32] in register bits [13:0] */
+#define BT_ADDR_RANGE_SHIFT 32
+
+#define CSR_BT_VC2SC_MAP (CSR_BRIDGE_TOP_BASE + 0x50)
+
+#define CSR_BT_TILE0_RANGE (CSR_BRIDGE_TOP_BASE + 0x58)
+#define MASK_BT_T0_VALID GENMASK(0, 0)
+#define MASK_BT_T0_BASE GENMASK(7, 1)
+#define MASK_BT_T0_RANGE GENMASK(14, 8)
+
+#define CSR_BT_TILE1_RANGE (CSR_BRIDGE_TOP_BASE + 0x60)
+#define MASK_BT_T1_VALID GENMASK(0, 0)
+#define MASK_BT_T1_BASE GENMASK(7, 1)
+#define MASK_BT_T1_RANGE GENMASK(14, 8)
+
+/* xmit/recv flit/packet counter register offsets */
+#define O_FPC_PORTRCV_DATA_CNT 0x100490
+#define O_FPC_PORTRCV_PKT_CNT 0x100438
+#define TP_PRF_XMIT_DATA_OFFSET 0x200458
+#define TP_PRF_XMIT_PKTS_OFFSET 0x200400
+
+/* LCB counter offsets */
+#define O_LCB_ERR_INFO_OFFSET 0x308500
+#define O_LCB_STS_RX_CRC_FEC_MODE 0x3087A8
+#define O_LCB_STS_RX_LOGICAL_ID 0x3087B0
+#define O_LCB_PRF_OFFSET 0x308700
+
+#define BRG_PERF_OFFSET 0x34000
+#define BRG_PERF_END (BRG_PERF_OFFSET + 0xB8)
+#define BRG_ERR_OFFSET 0x36000
+#define BRG_ERR_END (BRG_ERR_OFFSET + 0x198)
+#define BRG_1_ERR_OFFSET (BRG_ERR_OFFSET + 0x200)
+#define BRG_1_ERR_END (BRG_ERR_OFFSET + 0x228)
+#define BRG_2_ERR_OFFSET (BRG_ERR_OFFSET + 0x300)
+#define BRG_2_ERR_END (BRG_ERR_OFFSET + 0x328)
+#define BRG_3_ERR_OFFSET (BRG_ERR_OFFSET + 0x400)
+#define BRG_3_ERR_END (BRG_ERR_OFFSET + 0x428)
+#define BRG_RTP_ERR_OFFSET (0x200000 + 0x1000)
+#define BRG_RTP_ERR_END (BRG_RTP_ERR_OFFSET + 0x28)
+#define BRG_RTP_STS_OFFSET (0x200000 + 0x2000)
+#define BRG_RTP_STS_START_1 (BRG_RTP_STS_OFFSET + 0x10)
+#define BRG_RTP_STS_END_1 (BRG_RTP_STS_OFFSET + 0x40)
+#define BRG_RTP_STS_START_2 (BRG_RTP_STS_OFFSET + 0x80)
+#define BRG_RTP_STS_END_2 (BRG_RTP_STS_OFFSET + 0xA0)
+#define TPM_ERR_START (0x100000 + 0x300)
+#define TPM_ERR_END (TPM_ERR_START + 0x108)
+#define TPM_ERR_MBE_START (0x100000 + 0x4A0)
+#define TPM_ERR_MBE_END (TPM_ERR_MBE_START + 0x88)
+#define TPM_PRF_START (0x100000 + 0x840)
+#define TPM_PRF_END (TPM_PRF_START + 0x108)
+
+#define RPM_OFFSET 0x180000
+#define RPM_INQ_ERR_OFFSET (RPM_OFFSET + 0x2000)
+#define RPM_INQ_STS_OFFSET (RPM_OFFSET + 0x2900)
+#define RPM_INQ_PRF_OFFSET (RPM_OFFSET + 0x2D00)
+
+#define RPM_PORT_ERR_COUNTERS_START (RPM_INQ_PRF_OFFSET + 0x100)
+#define RPM_PORT_ERR_COUNTERS_END (RPM_INQ_PRF_OFFSET + 0x7F8)
+
+#define RPM_INQ_PORT0_ERR_START (RPM_INQ_ERR_OFFSET)
+#define RPM_INQ_PORT0_ERR_END (RPM_INQ_ERR_OFFSET + 0x20)
+
+#define RPM_INQ_PORT1_ERR_START (RPM_INQ_ERR_OFFSET + 0x80)
+#define RPM_INQ_PORT1_ERR_END (RPM_INQ_ERR_OFFSET + 0xA0)
+
+#define RPM_INQ_PORT2_ERR_START (RPM_INQ_ERR_OFFSET + 0x100)
+#define RPM_INQ_PORT2_ERR_END (RPM_INQ_ERR_OFFSET + 0x120)
+
+#define RPM_INQ_PORT3_ERR_START (RPM_INQ_ERR_OFFSET + 0x180)
+#define RPM_INQ_PORT3_ERR_END (RPM_INQ_ERR_OFFSET + 0x1A0)
+
+#define RPM_INQ_PORT4_ERR_START (RPM_INQ_ERR_OFFSET + 0x200)
+#define RPM_INQ_PORT4_ERR_END (RPM_INQ_ERR_OFFSET + 0x220)
+
+#define RPM_INQ_PORT5_ERR_START (RPM_INQ_ERR_OFFSET + 0x280)
+#define RPM_INQ_PORT5_ERR_END (RPM_INQ_ERR_OFFSET + 0x2A0)
+
+#define RPM_INQ_PORT6_ERR_START (RPM_INQ_ERR_OFFSET + 0x300)
+#define RPM_INQ_PORT6_ERR_END (RPM_INQ_ERR_OFFSET + 0x320)
+
+#define RPM_INQ_PORT7_ERR_START (RPM_INQ_ERR_OFFSET + 0x380)
+#define RPM_INQ_PORT7_ERR_END (RPM_INQ_ERR_OFFSET + 0x3A0)
+
+#define RPM_INQ_FLSTOR_ERR_START (RPM_INQ_ERR_OFFSET + 0x400)
+#define RPM_INQ_FLSTOR_ERR_END (RPM_INQ_ERR_OFFSET + 0x420)
+
+#define RPM_PORT_STS_START (RPM_INQ_STS_OFFSET + 0x200)
+#define RPM_PORT_STS_END (RPM_INQ_STS_OFFSET + 0x2F8)
+
+#define RPM_SBE_ERR_COUNTERS_START (RPM_INQ_PRF_OFFSET)
+#define RPM_SBE_ERR_COUNTERS_END (RPM_INQ_PRF_OFFSET + 0x78)
+
+#define RPM_MBE_ERR_COUNTERS_START (RPM_INQ_PRF_OFFSET + 0x80)
+#define RPM_MBE_ERR_COUNTERS_END (RPM_INQ_PRF_OFFSET + 0xF8)
+
+#define RPM_ARB_PERF_COUNTERS_START (RPM_INQ_PRF_OFFSET + 0x8C0)
+#define RPM_ARB_PERF_COUNTERS_END (RPM_INQ_PRF_OFFSET + 0x938)
+
+#define RPM_PERF_COUNTERS_START (RPM_INQ_PRF_OFFSET + 0x800)
+#define RPM_PERF_COUNTERS_END (RPM_INQ_PRF_OFFSET + 0x8B8)
+
+#define CRC_MODE GENMASK(1, 0)
+#define FEC_MODE GENMASK(5, 4)
+
+#define PEER_TX_ID_LN0 GENMASK(2, 0)
+#define PEER_TX_ID_LN1 GENMASK(6, 4)
+#define PEER_TX_ID_LN2 GENMASK(10, 8)
+#define PEER_TX_ID_LN3 GENMASK(14, 12)
+
+/* error csrs for sticky error reporting */
+#define O_FPC_ERR_STS 0x100000
+#define O_FPC_ERR_CLR 0x100008
+#define O_FPC_ERR_FIRST_HOST 0x100020
+#define O_FPC_ERR_INFO_PORTRCV 0x100028
+#define O_FPC_ERR_INFO_PORTRCV_HDR0_A 0x100030
+#define O_FPC_ERR_INFO_PORTRCV_HDR0_B 0x100038
+#define O_FPC_ERR_INFO_PORTRCV_HDR1_A 0x100040
+#define O_FPC_ERR_INFO_PORTRCV_HDR1_B 0x100048
+#define O_FPC_ERR_INFO_FMCONFIG 0x100050
+#define O_FPC_ERR_INFO_FLOW_CTRL 0x100058
+#define O_FPC_ERR_INFO_UNCORRECTABLE 0x100060
+#define O_FPC_ERR_INFO_PORTRCVCONSTRAINT 0x100068
+#define O_RTP_ERR_STS 0x141000
+#define O_RTP_ERR_CLR 0x141008
+#define O_RTP_ERR_FIRST_HOST 0x141020
+#define O_RTP_ERR_FIRST_INFO 0x141028
+#define O_INQ_ERR_STS 0x182000
+#define O_INQ_ERR_CLR 0x182008
+#define O_INQ_ERR_EN_HOST 0x182018
+#define O_INQ_ERR_FIRST_HOST 0x182020
+#define O_TP_ERR_STS_0 0x200180
+#define O_TP_ERR_CLR_0 0x200188
+#define O_TP_ERR_EN_HOST_0 0x200198
+#define O_TP_ERR_FIRST_HOST_0 0x2001a0
+#define O_TP_ERR_STS_1 0x200200
+#define O_TP_ERR_CLR_1 0x200208
+#define O_TP_ERR_EN_HOST_1 0x200218
+#define O_TP_ERR_FIRST_HOST_1 0x200220
+#define O_TP_ERR_ERROR_INFO 0x200230
+#define O_TP_ERR_PKEY_ERROR_INFO 0x200248
+#define O_TP_ERR_SBE_ERROR_CNT 0x200250
+#define O_TP_ERR_MBE_ERROR_CNT 0x200258
+#define O_TP_PE_ERROR_CNT 0x200260
+#define O_8051_ERR_STS 0x300100
+#define O_8051_ERR_CLR 0x300108
+#define O_8051_FIRST_HOST 0x300120
+#define O_LCB_ERR_STS 0x308480
+#define O_LCB_ERR_CLR 0x308488
+#define O_LCB_ERR_FIRST_HOST 0x3084a0
+#define O_LCB_ERR_INFO_TOTAL_CRC_ERR 0x308500
+#define O_LCB_ERR_INFO_CRC_ERR_LN0 0x308508
+#define O_LCB_ERR_INFO_CRC_ERR_LN1 0x308510
+#define O_LCB_ERR_INFO_CRC_ERR_LN2 0x308518
+#define O_LCB_ERR_INFO_CRC_ERR_LN3 0x308520
+#define O_LCB_ERR_INFO_CRC_ERR_MULTI_LN 0x308528
+#define O_LCB_ERR_INFO_TX_REPLAY_CNT 0x308530
+#define O_LCB_ERR_INFO_RX_REPLAY_CNT 0x308538
+#define O_LCB_ERR_INFO_SEQ_CRC_CNT 0x308540
+#define O_LCB_ERR_INFO_ESCAPE_0_ONLY_CNT 0x308548
+#define O_LCB_ERR_INFO_ESCAPE_0_PLUS1_CNT 0x308550
+#define O_LCB_ERR_INFO_ESCAPE_0_PLUS2_CNT 0x308558
+#define O_LCB_ERR_INFO_REINIT_FROM_PEER_CNT 0x308560
+#define O_LCB_ERR_INFO_SBE_CNT 0x308568
+#define O_LCB_ERR_INFO_MISC_FLG_CNT 0x308570
+#define O_LCB_ERR_INFO_ECC_INPUT_BUF 0x308578
+#define O_LCB_ERR_INFO_ECC_INPUT_BUF_HGH 0x308580
+#define O_LCB_ERR_INFO_ECC_INPUT_BUF_LOW 0x308588
+#define O_LCB_ERR_INFO_ECC_REPLAY_BUF 0x308590
+#define O_LCB_ERR_INFO_ECC_REPLAY_BUF_HGH 0x308598
+#define O_LCB_ERR_INFO_ECC_REPLAY_BUF_LOW 0x3085A0
+#define O_LCB_ERR_INFO_ECC_PM_TIME 0x3085A8
+#define O_LCB_ERR_INFO_ECC_PM_TIME_HGH 0x3085B0
+#define O_LCB_ERR_INFO_ECC_PM_TIME_LOW 0x3085B8
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_1 0x3085C0
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_2 0x3085C8
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_3 0x3085D0
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_4 0x3085D8
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_5 0x3085E0
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_6 0x3085E8
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_7 0x3085F0
+#define O_LCB_ERR_INFO_FEC_CERR_CNT_8 0x3085F8
+#define O_LCB_ERR_INFO_FEC_UERR_CNT 0x308600
+#define O_LCB_ERR_INFO_FEC_CERR_MASK_0 0x308608
+#define O_LCB_ERR_INFO_FEC_CERR_MASK_1 0x308610
+#define O_LCB_ERR_INFO_FEC_CERR_MASK_2 0x308618
+#define O_LCB_ERR_INFO_FEC_CERR_MASK_3 0x308620
+#define O_LCB_ERR_INFO_FEC_CERR_MASK_4 0x308628
+#define O_LCB_ERR_INFO_FEC_CERR_MASK_VLD 0x308630
+#define O_LCB_ERR_INFO_FEC_CERR_MASK_MISS_CNT 0x308638
+#define O_LCB_ERR_INFO_FEC_ERR_LN0 0x308640
+#define O_LCB_ERR_INFO_FEC_ERR_LN1 0x308648
+#define O_LCB_ERR_INFO_FEC_ERR_LN2 0x308650
+#define O_LCB_ERR_INFO_FEC_ERR_LN3 0x308658
+#define O_LCB_ERR_INFO_FX_RESYNC_CNT 0x308660
+#define O_BRG_CTX_ERR_STS 0x036000
+#define O_BRG_CTX_ERR_CLR 0x036008
+#define O_BRG_CTX_ERR_FIRST_HOST 0x036020
+#define O_BRG_CTX_ERR_FIRST_INFO 0x036028
+#define O_SRC_CTXT_SBE_CNT 0x036040
+#define O_DST_CTXT_SBE_CNT 0x036048
+#define O_SRC_CTXT_MBE_CNT 0x036050
+#define O_DST_CTXT_MBE_CNT 0x036058
+#define O_BRG_INCMD_PKTPAR_ERR 0x036060
+#define O_BRG_INPKT_POISON_SET 0x036068
+#define O_BRG_INRSP_PKTPAR_ERR 0x036070
+#define O_BRG_INDATA_PKTPAR_ERR 0x036078
+#define O_BRG_OUTPKT_POISON_SET 0x036080
+#define O_BRG_RPM_POISON_SET 0x036088
+#define O_TPM_BRG_POISON_SET 0x036090
+#define O_BRG_DROP_FABRIC_REQ 0x036098
+#define O_BRG_DROP_MDFI_REQ 0x0360a0
+#define O_BRG_DROP_FABRIC_RSP 0x0360a8
+#define O_BRG_DROP_MDFI_RSP 0x0360b0
+#define O_BRG_SRCCTXT_TO 0x0360b8
+#define O_BRG_DSTCTXT_TO 0x0360c0
+#define O_BRG_FIDMISS 0x0360c8
+#define O_BRG_FIDMISS_INFO 0x0360d0
+#define O_BRG_SRCCTXT_DUP_RSP 0x0360d8
+#define O_BRG_SRCCTXT_DUP_RSPINFO 0x0360e0
+#define O_BRG_DSTCTXT_DUP_RSP 0x0360e8
+#define O_BRG_DSTCTXT_DUP_RSPINFO 0x0360f0
+#define O_BRG_SFID_FILTER_DROP 0x0360f8
+#define O_BRG_0_ERR_STS 0x036100
+#define O_BRG_0_ERR_CLR 0x036108
+#define O_BRG_0_ERR_FIRST_HOST 0x036120
+#define O_BRG_0_ERR_FIRST_INFO 0x036128
+#define O_BRG_SBE_ADDR2FID_ERR 0x036130
+#define O_BRG_SBE_RSPARB_ERR 0x036138
+#define O_BRG_SBE_EGRQ_ERR 0x036140
+#define O_BRG_SBE_INGRQ_ERR 0x036148
+#define O_BRG_SBE_TPMEGRQ_ERR 0x036150
+#define O_BRG_SBE_TPMINGRQ_ERR 0x036158
+#define O_BRG_MBE_ADDR2FID_ERR 0x036160
+#define O_BRG_MBE_RSPARB_ERR 0x036168
+#define O_BRG_MBE_EGRQ_ERR 0x036170
+#define O_BRG_MBE_INGRQ_ERR 0x036178
+#define O_BRG_MBE_TPMEGRQ_ERR 0x036180
+#define O_BRG_MBE_TPMINGRQ_ERR 0x036188
+#define O_BRG_SBE_TPMDECAP_ERR 0x036190
+#define O_BRG_MBE_TPMDECAP_ERR 0x036198
+#define O_BRG_1_ERR_STS 0x036200
+#define O_BRG_1_ERR_CLR 0x036208
+#define O_BRG_1_ERR_FIRST_HOST 0x036220
+#define O_BRG_1_ERR_FIRST_INFO 0x036228
+#define O_BRG_2_ERR_STS 0x036300
+#define O_BRG_2_ERR_CLR 0x036308
+#define O_BRG_2_ERR_FIRST_HOST 0x036320
+#define O_BRG_2_ERR_FIRST_INFO 0x036328
+#define O_TPM_ERR_STS 0x100300
+#define O_TPM_ERR_CLR 0x100308
+#define O_TPM_ERR_FIRST_HOST 0x100320
+#define O_TPM_ERR_RINFO_SBE_COUNT 0x100328
+#define O_TPM_ERR_RINFO_SBE_INFO 0x100330
+#define O_TPM_ERR_RINFO_MBE_COUNT 0x100338
+#define O_TPM_ERR_RINFO_MBE_INFO 0x100340
+#define O_TPM_ERR_QFLITDATA_SBE_COUNT 0x100348
+#define O_TPM_ERR_QFLITDATA_SBE_INFO 0x100350
+#define O_TPM_ERR_QFLITDATA_MBE_COUNT 0x100358
+#define O_TPM_ERR_QFLITDATA_MBE_INFO 0x100360
+#define O_TPM_ERR_RINFO_PE_COUNT 0x100368
+#define O_TPM_ERR_RINFO_PE_INFO 0x100370
+#define O_TPM_ERR_TAILLESS_PKT_CNT 0x100378
+#define O_TPM_ERR_RSVD_VL_CNT 0x100380
+#define O_TPM_ERR_RSVD_VL_INFO 0x100388
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_0 0x100390
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_1 0x100398
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_2 0x1003a0
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_3 0x1003a8
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_4 0x1003b0
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_5 0x1003b8
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_6 0x1003c0
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_7 0x1003c8
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_8 0x1003d0
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_9 0x1003d8
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_10 0x1003e0
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_11 0x1003e8
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_12 0x1003f0
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_13 0x1003f8
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_14 0x100400
+#define O_TPM_ERR_STORG_SBE_ERR_CNT_15 0x100408
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_0 0x1004a0
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_1 0x1004a8
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_2 0x1004b0
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_3 0x1004b8
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_4 0x1004c0
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_5 0x1004c8
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_6 0x1004d0
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_7 0x1004d8
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_8 0x1004e0
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_9 0x1004e8
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_10 0x1004f0
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_11 0x1004f8
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_12 0x100500
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_13 0x100508
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_14 0x100510
+#define O_TPM_ERR_STORG_MBE_ERR_CNT_15 0x100518
+#define O_TPM_ERR_INQ_SBE_ERR_INFO 0x100520
+#define O_TPM_ERR_INQ_MBE_ERR_INFO 0x100528
+#define O_RPM_INQ_PORT0_ERR_STS 0x182000
+#define O_RPM_INQ_PORT0_ERR_CLR 0x182008
+#define O_RPM_INQ_PORT0_ERR_FIRST_HOST 0x182020
+#define O_RPM_INQ_PORT1_ERR_STS 0x182080
+#define O_RPM_INQ_PORT1_ERR_CLR 0x182088
+#define O_RPM_INQ_PORT1_ERR_FIRST_HOST 0x1820A0
+#define O_RPM_INQ_PORT2_ERR_STS 0x182100
+#define O_RPM_INQ_PORT2_ERR_CLR 0x182108
+#define O_RPM_INQ_PORT2_ERR_FIRST_HOST 0x182120
+#define O_RPM_INQ_PORT3_ERR_STS 0x182180
+#define O_RPM_INQ_PORT3_ERR_CLR 0x182188
+#define O_RPM_INQ_PORT3_ERR_FIRST_HOST 0x1821A0
+#define O_RPM_INQ_PORT4_ERR_STS 0x182200
+#define O_RPM_INQ_PORT4_ERR_CLR 0x182208
+#define O_RPM_INQ_PORT4_ERR_FIRST_HOST 0x182220
+#define O_RPM_INQ_PORT5_ERR_STS 0x182280
+#define O_RPM_INQ_PORT5_ERR_CLR 0x182288
+#define O_RPM_INQ_PORT5_ERR_FIRST_HOST 0x1822A0
+#define O_RPM_INQ_PORT6_ERR_STS 0x182300
+#define O_RPM_INQ_PORT6_ERR_CLR 0x182308
+#define O_RPM_INQ_PORT6_ERR_FIRST_HOST 0x182320
+#define O_RPM_INQ_PORT7_ERR_STS 0x182380
+#define O_RPM_INQ_PORT7_ERR_CLR 0x182388
+#define O_RPM_INQ_PORT7_ERR_FIRST_HOST 0x1823A0
+#define O_RPM_INQ_FLSTOR_ERR_STS 0x182400
+#define O_RPM_INQ_FLSTOR_ERR_CLR 0x182408
+#define O_RPM_INQ_FLSTOR_ERR_FIRST_HOST 0x182420
+#define O_BRG_RTP_ERR_STS 0x201000
+#define O_BRG_RTP_ERR_CLR 0x201008
+#define O_BRG_RTP_ERR_FIRST_HOST 0x201020
+#define O_BRG_RTP_ERR_FIRST_INFO 0x201028
+
+#endif /* IAF_CSR_H_INCLUDED */
diff --git a/drivers/gpu/drm/xe/fabric/iaf_drv.h b/drivers/gpu/drm/xe/fabric/iaf_drv.h
new file mode 100644
index 000000000000..0486d4b86b6f
--- /dev/null
+++ b/drivers/gpu/drm/xe/fabric/iaf_drv.h
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2020 - 2023 Intel Corporation.
+ */
+
+#ifndef IAF_DRV_H_INCLUDED
+#define IAF_DRV_H_INCLUDED
+
+#include <linux/auxiliary_bus.h>
+#include <linux/irqreturn.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/kref.h>
+
+#include <drm/intel_iaf_platform.h>
+
+#define DRIVER_NAME "iaf"
+
+#undef pr_fmt
+#define pr_fmt(fmt) DRIVER_NAME ": " fmt
+
+/*
+ * The maximum number of tiles for the PVC product type.
+ *
+ * Revisit if future product types or variations are developed that require
+ * a product type table.
+ */
+#define IAF_MAX_SUB_DEVS 2
+
+/*
+ * Recognized discrete socket IDs
+ */
+#define MAX_SOCKET_IDS (32)
+
+/*
+ * Platforms and revisions.
+ *
+ * Note that these conform to the ANR ASIC_REV_INFO (ARI) register values,
+ * not the PCI revision IDs reported by the packaged product.
+ */
+
+#define ANR_ARI_PLATFORM 0x0101
+
+#define ANR_ARI_STEP_A0 0x00
+#define ANR_ARI_STEP_A1 0x01
+#define ANR_ARI_STEP_A_LAST ANR_ARI_STEP_A1
+#define ANR_ARI_STEP_B0 0x10
+#define ANR_ARI_STEP_B_LAST ANR_ARI_STEP_B0
+
+#define IS_ANR(sd) \
+ (FIELD_GET(MASK_ARI_PLATFORM, (sd)->asic_rev_info) == ANR_ARI_PLATFORM)
+
+#define IS_ANR_STEP(sd, since, until) (IS_ANR(sd) && \
+ FIELD_GET(MASK_ARI_STEP, (sd)->asic_rev_info) >= (since) && \
+ FIELD_GET(MASK_ARI_STEP, (sd)->asic_rev_info) <= (until))
+
+/*
+ * Device and subdevice message formats
+ *
+ * Device expands dev->name, sd expand relevant indices
+ * ": " separates info. *_FMT ends in ": ", *_ID_FMT does not
+ */
+
+#define DEV_ID_FMT "iaf.%d"
+#define SD_ID_FMT "sd.%d"
+
+#define DEV_FMT DEV_ID_FMT ": "
+#define SD_FMT SD_ID_FMT ": "
+
+#define DEV_SD_FMT DEV_FMT "" SD_FMT
+
+/*
+ * Subdevice-specific messaging
+ */
+
+#define sd_emerg(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_emerg(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+#define sd_alert(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_alert(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+#define sd_crit(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_crit(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+#define sd_err(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_err(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+#define sd_warn(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_warn(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+#define sd_notice(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_notice(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+#define sd_info(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_info(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+#define sd_dbg(__sd, _fmt, ...) \
+ do { \
+ struct fsubdev *_sd = (__sd); \
+ dev_dbg(sd_dev(_sd), SD_FMT _fmt, \
+ sd_index(_sd), ##__VA_ARGS__); \
+ } while (0)
+
+enum iaf_startup_mode {
+ STARTUP_MODE_DEFAULT = 0,
+ STARTUP_MODE_PRELOAD = 1,
+};
+
+struct fsubdev; /* from this file */
+
+struct fdev; /* from this file */
+
+/**
+ * enum sd_error - Subdevice error conditions
+ * @SD_ERROR_FAILED: Subdevice has been marked as FAILED
+ * @SD_ERROR_FW: Firmware error
+ * @NUM_SD_ERRORS: Number of error conditions (always last)
+ */
+enum sd_error {
+ SD_ERROR_FAILED,
+ SD_ERROR_FW,
+ NUM_SD_ERRORS
+};
+
+/**
+ * struct fsubdev - Per-subdevice state
+ * @fdev: link to containing device
+ * @csr_base: base address of this subdevice's memory
+ * @irq: assigned interrupt
+ * @name: small string to describe SD
+ * @asic_rev_info: raw contents of the asic rev info register
+ * @kobj: kobject for this sd in the sysfs tree
+ * @sd_failure: attribute for sd_failure sysfs file
+ * @guid: GUID retrieved from firmware
+ * @port_cnt: count of all fabric ports
+ * @errors: bitmap of active error states
+ *
+ * Used throughout the driver to maintain information about a given subdevice.
+ *
+ * Protection mechanisms used outside of init/destroy are documented inline. Sync probe is the
+ * context of the initial probe function. Async probe includes the initialization threads used to
+ * load the firmware and platform configuration before enabling general processing.
+ */
+struct fsubdev {
+ /* pointers const after sync probe, content protection is by object type */
+ struct fdev *fdev;
+ char __iomem *csr_base;
+
+ /* values const after sync probe */
+ int irq;
+ char name[8];
+ u64 asic_rev_info;
+
+ /* values const after async probe */
+ struct kobject *kobj;
+ struct device_attribute sd_failure;
+
+ u64 guid;
+ u8 port_cnt;
+
+ /* atomic, never cleared after sync probe */
+ DECLARE_BITMAP(errors, NUM_SD_ERRORS);
+};
+
+/**
+ * struct fdev - Device structure for IAF/fabric device component
+ * @sd: subdevice structures
+ * @dev_disabled: On a PCIe error, disable access to the PCI bus
+ * @pdev: bus device passed in probe
+ * @pd: platform specific data
+ * @fabric_id: xarray index based on parent index and product type
+ * @mappings_ref.lock: protect the mappings_ref data
+ * @mappings_ref.count: current mapped buffer count
+ * @mappings_ref.remove_in_progress: indicate unmap should show completion
+ * @mappings_ref.complete: completion after all buffers are unmapped
+ * @mappings_ref: Reference count of parent mapped buffers
+ * @refs: references on this instance
+ * @fdev_released: signals fdev has been erased from the xarray
+ * @startup_mode: startup mode
+ *
+ * Used throughout the driver to maintain information about a given device.
+ */
+struct fdev {
+ struct fsubdev sd[IAF_MAX_SUB_DEVS];
+ bool dev_disabled;
+ struct auxiliary_device *pdev;
+ const struct iaf_pdata *pd;
+ u32 fabric_id;
+
+ struct {
+ /* protect the mapping count and remove_in_progress flag */
+ struct mutex lock;
+ int count;
+ bool remove_in_progress;
+ struct completion complete;
+ } mappings_ref;
+
+ struct kref refs;
+ struct completion fdev_released;
+ enum iaf_startup_mode startup_mode;
+};
+
+void fdev_put(struct fdev *dev);
+int fdev_insert(struct fdev *dev);
+
+/*
+ * This is the fdev_process_each callback function signature
+ * Returning 0 indicates continue
+ * Any other return value indicates terminate
+ */
+typedef int (*fdev_process_each_cb_t)(struct fdev *dev, void *args);
+
+int fdev_process_each(fdev_process_each_cb_t cb, void *args);
+
+struct fdev *fdev_find(u32 fabric_id);
+
+/*
+ * Returns the sd index/offset relative to its device.
+ */
+static inline u8 sd_index(struct fsubdev *sd)
+{
+ return sd - sd->fdev->sd;
+}
+
+/*
+ * dev_is_preload - Test for preload startup mode.
+ * @dev: device
+ *
+ * Return: True if the device is in preload startup mode.
+ */
+static inline bool dev_is_preload(struct fdev *dev)
+{
+ return dev && dev->startup_mode == STARTUP_MODE_PRELOAD;
+}
+
+static inline struct device *sd_dev(const struct fsubdev *sd)
+{
+ return &sd->fdev->pdev->dev;
+}
+
+static inline struct device *fdev_dev(const struct fdev *dev)
+{
+ return &dev->pdev->dev;
+}
+
+/* The following two functions increase device reference count: */
+struct fdev *fdev_find_by_sd_guid(u64 guid);
+struct fsubdev *find_sd_id(u32 fabric_id, u8 sd_index);
+
+#endif
diff --git a/drivers/gpu/drm/xe/fabric/main.c b/drivers/gpu/drm/xe/fabric/main.c
new file mode 100644
index 000000000000..2048546712d5
--- /dev/null
+++ b/drivers/gpu/drm/xe/fabric/main.c
@@ -0,0 +1,632 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2020 - 2023 Intel Corporation.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/rwsem.h>
+#include <linux/xarray.h>
+#include <generated/utsrelease.h>
+
+#include <drm/intel_iaf_platform.h>
+
+#include "csr.h"
+#include "iaf_drv.h"
+#include "sysfs.h"
+
+#define MODULEDETAILS "Intel Corp. Intel fabric Driver"
+
+/* xarray of IAF devices */
+static DEFINE_XARRAY_ALLOC(intel_fdevs);
+
+/*
+ * Used for creating unique xarray hash. Products need to be defined
+ * in the intel_iaf_platform.h file.
+ */
+#define PRODUCT_SHIFT 16
+
+static enum iaf_startup_mode param_startup_mode = STARTUP_MODE_DEFAULT;
+
+static const char *startup_mode_name(enum iaf_startup_mode m)
+{
+ switch (m) {
+ case STARTUP_MODE_DEFAULT: return "default";
+ case STARTUP_MODE_PRELOAD: return "preload";
+ }
+
+ return "(unknown)";
+}
+
+static int mode_set(const char *val, const struct kernel_param *kp)
+{
+ enum iaf_startup_mode new_mode;
+
+ if (sysfs_streq(val, "default"))
+ new_mode = STARTUP_MODE_DEFAULT;
+ else if (sysfs_streq(val, "preload"))
+ new_mode = STARTUP_MODE_PRELOAD;
+ else
+ return -EINVAL;
+
+ param_startup_mode = new_mode;
+
+ return 0;
+}
+
+static int mode_get(char *val, const struct kernel_param *kp)
+{
+ return snprintf(val, PAGE_SIZE, startup_mode_name(param_startup_mode));
+}
+
+static const struct kernel_param_ops startup_mode_ops = {
+ .set = mode_set,
+ .get = mode_get,
+};
+
+module_param_cb(startup_mode, &startup_mode_ops, ¶m_startup_mode, 0600);
+MODULE_PARM_DESC(startup_mode,
+ "Operational mode for newly probed devices:\n"
+ "\t\t - default: Operate normally\n"
+ "\t\t - preload: Assume firmware/ini has already been loaded"
+ );
+
+#define RELEASE_TIMEOUT (HZ * 60)
+
+static void fdev_release(struct kref *kref)
+{
+ struct fdev *dev = container_of(kref, typeof(*dev), refs);
+
+ xa_erase(&intel_fdevs, dev->fabric_id);
+ complete(&dev->fdev_released);
+}
+
+void fdev_put(struct fdev *dev)
+{
+ kref_put(&dev->refs, fdev_release);
+}
+
+static struct fdev *fdev_get(struct fdev *dev)
+{
+ if (dev && kref_get_unless_zero(&dev->refs))
+ return dev;
+
+ return NULL;
+}
+
+int fdev_insert(struct fdev *dev)
+{
+ int err;
+
+ kref_init(&dev->refs);
+ init_completion(&dev->fdev_released);
+
+ err = xa_insert(&intel_fdevs, dev->fabric_id, dev, GFP_KERNEL);
+ if (err)
+ dev_warn(fdev_dev(dev), "fabric_id 0x%08x already in use\n",
+ dev->fabric_id);
+
+ return err;
+}
+
+int fdev_process_each(fdev_process_each_cb_t cb, void *args)
+{
+ struct fdev *dev;
+ unsigned long i;
+
+ xa_lock(&intel_fdevs);
+ xa_for_each(&intel_fdevs, i, dev) {
+ int ret;
+
+ if (!fdev_get(dev))
+ continue;
+
+ xa_unlock(&intel_fdevs);
+ ret = cb(dev, args);
+ fdev_put(dev);
+ if (ret)
+ return ret;
+
+ xa_lock(&intel_fdevs);
+ }
+ xa_unlock(&intel_fdevs);
+
+ return 0;
+}
+
+static void fdev_wait_on_release(struct fdev *dev)
+{
+ fdev_put(dev);
+
+ wait_for_completion_killable_timeout(&dev->fdev_released,
+ RELEASE_TIMEOUT);
+}
+
+/*
+ * Returns with reference count for the fdev incremented when found.
+ * It is the callers responsibility to decrement the reference count.
+ */
+struct fdev *fdev_find(u32 fabric_id)
+{
+ struct fdev *dev;
+
+ xa_lock(&intel_fdevs);
+ dev = fdev_get(xa_load(&intel_fdevs, fabric_id));
+ xa_unlock(&intel_fdevs);
+
+ return dev;
+}
+
+struct fdev *fdev_find_by_sd_guid(u64 guid)
+{
+ struct fdev *dev, *referenced_dev;
+ unsigned long d;
+ u8 s;
+
+ xa_lock(&intel_fdevs);
+
+ /* dev becomes NULL if xa_for_each() completes */
+ xa_for_each(&intel_fdevs, d, dev)
+ for (s = 0; s < dev->pd->sd_cnt; ++s)
+ if (dev->sd[s].guid == guid)
+ goto end_iteration;
+
+end_iteration:
+
+ referenced_dev = fdev_get(dev);
+
+ xa_unlock(&intel_fdevs);
+
+ return referenced_dev;
+}
+
+struct fsubdev *find_sd_id(u32 fabric_id, u8 sd_index)
+{
+ struct fdev *dev = fdev_find(fabric_id);
+
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+
+ if (sd_index < dev->pd->sd_cnt)
+ return &dev->sd[sd_index];
+
+ fdev_put(dev);
+
+ return ERR_PTR(-EINVAL);
+}
+
+/* configured by request_irq() to refer to corresponding struct fsubdev */
+static irqreturn_t handle_iaf_irq(int irq, void *arg)
+{
+ return IRQ_HANDLED;
+}
+
+static struct query_info *handle_query(void *handle, u32 fabric_id)
+{
+ struct fdev *src, *dst;
+ struct query_info *qi;
+
+ /*
+ * src fdev is guaranteed to never be removed during this invocation by
+ * the caller
+ */
+ src = handle;
+
+ dst = fdev_find(fabric_id);
+ if (!dst)
+ return ERR_PTR(-ENODEV);
+
+ qi = kmalloc(struct_size(qi, sd2sd, src->pd->sd_cnt * dst->pd->sd_cnt),
+ GFP_KERNEL);
+ if (qi) {
+ qi->src_cnt = src->pd->sd_cnt;
+ qi->dst_cnt = dst->pd->sd_cnt;
+ } else {
+ qi = ERR_PTR(-ENOMEM);
+ }
+
+ fdev_put(dst);
+
+ return qi;
+}
+
+/**
+ * mappings_ref_get - Increment mapping reference count
+ * @dev: pointer to a valid fdev
+ *
+ * Allow the parent to indicate that a buffer has been mapped
+ *
+ * return: -1 reference count failed, do not allow mapping
+ */
+static int mappings_ref_get(struct fdev *dev)
+{
+ mutex_lock(&dev->mappings_ref.lock);
+
+ dev_dbg(fdev_dev(dev), "count: %d\n", dev->mappings_ref.count);
+
+ if (dev->mappings_ref.remove_in_progress) {
+ mutex_unlock(&dev->mappings_ref.lock);
+ return -1;
+ }
+
+ dev->mappings_ref.count++;
+
+ mutex_unlock(&dev->mappings_ref.lock);
+
+ return 0;
+}
+
+/**
+ * mappings_ref_put - Decrement mapping reference count
+ * @dev: pointer to a valid fdev
+ *
+ * Allow the parent to indicate that a buffer has been unmapped
+ *
+ * A negative value allows remove to proceed.
+ *
+ * return: -1 indicate an unbalanced put call
+ */
+static int mappings_ref_put(struct fdev *dev)
+{
+ int ret = 0;
+
+ mutex_lock(&dev->mappings_ref.lock);
+
+ dev_dbg(fdev_dev(dev), "count: %d\n", dev->mappings_ref.count);
+
+ /*
+ * in the case of device removal, permit an extra decrement, which is
+ * used to signal completion to the remove context.
+ */
+ if (dev->mappings_ref.count > 1 ||
+ dev->mappings_ref.remove_in_progress) {
+ dev->mappings_ref.count--;
+
+ if (dev->mappings_ref.count == 0)
+ complete(&dev->mappings_ref.complete);
+
+ } else {
+ ret = -1;
+ }
+
+ mutex_unlock(&dev->mappings_ref.lock);
+
+ return ret;
+}
+
+/**
+ * mappings_ref_wait - Driver decrement (inited to 1), and wait for zero count
+ * @dev: valid device
+ *
+ */
+static void mappings_ref_wait(struct fdev *dev)
+{
+ mutex_lock(&dev->mappings_ref.lock);
+
+ dev->mappings_ref.remove_in_progress = true;
+ dev->mappings_ref.count--;
+
+ if (dev->mappings_ref.count == 0) {
+ mutex_unlock(&dev->mappings_ref.lock);
+ return;
+ }
+
+ dev_warn(fdev_dev(dev), "mappings_ref_map != 0 (%d) will wait\n",
+ dev->mappings_ref.count);
+
+ mutex_unlock(&dev->mappings_ref.lock);
+
+ wait_for_completion_killable(&dev->mappings_ref.complete);
+}
+
+static int handle_parent_event(void *handle, enum iaf_parent_event event)
+{
+ struct fdev *dev = handle;
+
+ switch (event) {
+ case IAF_PARENT_PCIE_ERR:
+ dev_err(fdev_dev(dev), "PCIE error received\n");
+ WRITE_ONCE(dev->dev_disabled, true);
+ return 0;
+
+ case IAF_PARENT_MAPPING_GET:
+ return mappings_ref_get(dev);
+
+ case IAF_PARENT_MAPPING_PUT:
+ return mappings_ref_put(dev);
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static const struct iaf_ops iaf_ops = {
+ .connectivity_query = handle_query,
+ .parent_event = handle_parent_event,
+};
+
+static int validate_product(struct fsubdev *sd)
+{
+ if (unlikely(READ_ONCE(sd->fdev->dev_disabled)))
+ return -EIO;
+
+ switch (sd->fdev->pd->product) {
+ case IAF_PONTEVECCHIO:
+ sd->asic_rev_info = readq(sd->csr_base + CSR_ASIC_REV_INFO);
+ if (!IS_ANR(sd)) {
+ sd_err(sd, "Unsupported subdevice revision 0x%016llx\n",
+ sd->asic_rev_info);
+ return -EINVAL;
+ }
+ sd_dbg(sd, "asic rev info 0x%016llx\n", sd->asic_rev_info);
+ break;
+ default:
+ sd_err(sd, "Unrecognized product type %d for subdevice\n",
+ sd->fdev->pd->product);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct resource *iaf_find_res(struct fdev *dev, unsigned int type,
+ int index)
+{
+ int i;
+ int offset;
+
+ for (i = 0; i < dev->pd->num_resources; i++) {
+ offset = index * dev->pd->sd_cnt + i;
+ if (resource_type(&dev->pd->resources[offset]) == type)
+ return &dev->pd->resources[offset];
+ }
+
+ return NULL;
+}
+
+static int add_subdevice(struct fsubdev *sd, struct fdev *dev, int index)
+{
+ struct resource *res;
+ int err;
+
+ sd->fdev = dev;
+
+ snprintf(sd->name, sizeof(sd->name), SD_ID_FMT, index);
+
+ res = iaf_find_res(dev, IORESOURCE_MEM, index);
+ if (!res) {
+ sd_err(sd, "No MEM resource available\n");
+ return -ENOMEM;
+ }
+ sd->csr_base = ioremap(res->start, resource_size(res));
+ if (!sd->csr_base) {
+ sd_err(sd, "Unable to map resource %pR to kvirt\n", res);
+ return -ENOMEM;
+ }
+ sd_dbg(sd, "mapped resource %pR to mb_base %p\n", res, sd->csr_base);
+
+ err = validate_product(sd);
+ if (err) {
+ iounmap(sd->csr_base);
+ return err;
+ }
+
+ res = iaf_find_res(dev, IORESOURCE_IRQ, index);
+ if (!res) {
+ sd_err(sd, "No IRQ resource available\n");
+ iounmap(sd->csr_base);
+ return -EINVAL;
+ }
+ sd_dbg(sd, "IRQ resource %pR\n", res);
+
+ sd->irq = res->start;
+ err = request_irq(sd->irq, handle_iaf_irq, 0, "intel_sd_irq", sd);
+ if (err) {
+ sd_err(sd, "failed to request_irq %d err: %d\n", sd->irq, err);
+ iounmap(sd->csr_base);
+ return err;
+ }
+
+ sd_dbg(sd, "Adding IAF subdevice: %d\n", index);
+
+ return 0;
+}
+
+static void remove_subdevice(struct fsubdev *sd)
+{
+ free_irq(sd->irq, sd);
+ iounmap(sd->csr_base);
+ sd_dbg(sd, "Removed IAF resource: %p\n", sd->csr_base);
+ sd->csr_base = NULL;
+}
+
+static void iaf_remove(struct auxiliary_device *pdev)
+{
+ struct iaf_pdata *pd = container_of(pdev, struct iaf_pdata, aux_dev);
+ struct fdev *dev = dev_get_drvdata(&pdev->dev);
+ u8 i;
+
+ dev_dbg(&pdev->dev, "Removing %s\n", dev_name(&pdev->dev));
+
+ mappings_ref_wait(dev);
+
+ iaf_sysfs_remove(dev);
+
+ pd->unregister_dev(pd->parent, dev);
+
+ fdev_wait_on_release(dev);
+
+ for (i = 0; i < pd->sd_cnt; i++)
+ remove_subdevice(&dev->sd[i]);
+
+ pm_runtime_put(fdev_dev(dev));
+ pm_runtime_allow(fdev_dev(dev));
+ pm_runtime_disable(fdev_dev(dev));
+
+ WARN(kref_read(&dev->refs), "fabric_id 0x%08x has %u references",
+ dev->fabric_id, kref_read(&dev->refs));
+
+ kfree(dev);
+}
+
+static u32 dev_fabric_id(struct iaf_pdata *pd)
+{
+ return pd->product << PRODUCT_SHIFT | pd->index;
+}
+
+static int iaf_probe(struct auxiliary_device *pdev, const struct auxiliary_device_id *id)
+{
+ struct iaf_pdata *pd = container_of(pdev, struct iaf_pdata, aux_dev);
+ struct device *dev_parent = pdev->dev.parent;
+ struct fdev *dev;
+ u8 sds_added = 0;
+ int err;
+ u8 i;
+
+ dev_info(&pdev->dev,
+ "Probing %s, connection point for %s, fabric_id 0x%08x socket_id 0x%02x, sd_cnt %u\n",
+ dev_name(&pdev->dev),
+ dev_parent ? dev_name(dev_parent) : "UNKNOWN SOURCE",
+ dev_fabric_id(pd), pd->socket_id, pd->sd_cnt);
+
+ if (pd->version != IAF_VERSION)
+ return -EPERM;
+
+ if (!pd->register_dev || !pd->unregister_dev)
+ return -EINVAL;
+
+ if (pd->socket_id >= MAX_SOCKET_IDS)
+ return -EINVAL;
+
+ if (!pd->sd_cnt || pd->sd_cnt > IAF_MAX_SUB_DEVS)
+ return -EINVAL;
+
+ if (!pd->dpa.pkg_size)
+ return -EINVAL;
+
+ dev_dbg(&pdev->dev, "DPA offset: %dGB size: %dGB\n",
+ pd->dpa.pkg_offset, pd->dpa.pkg_size);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ kernel_param_lock(THIS_MODULE);
+ dev->startup_mode = param_startup_mode;
+ kernel_param_unlock(THIS_MODULE);
+
+ if (dev->startup_mode != STARTUP_MODE_DEFAULT)
+ dev_info(&pdev->dev, "startup_mode: %s",
+ startup_mode_name(dev->startup_mode));
+
+ dev->fabric_id = dev_fabric_id(pd);
+ dev->pd = pd;
+ dev->pdev = pdev;
+
+ dev_set_drvdata(&pdev->dev, dev);
+
+ err = fdev_insert(dev);
+ if (err) {
+ kfree(dev);
+ return err;
+ }
+
+ err = iaf_sysfs_probe(dev);
+ if (err)
+ goto sysfs_error;
+
+ dev->mappings_ref.count = 1;
+ mutex_init(&dev->mappings_ref.lock);
+ init_completion(&dev->mappings_ref.complete);
+
+ /*
+ * The IAF cannot be suspended via runtime, but the parent could have
+ * the capability. Set runtime to forbid to be explicit about what
+ * the requirement is. Do a get to make sure that suspend cannot be
+ * started externally (i.e. sysfs), to keep the parent from going to
+ * sleep.
+ * If the parent is asleep at this time, pm_runtime_forbid will cause
+ * it to resume.
+ */
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_forbid(&pdev->dev);
+ pm_runtime_get(&pdev->dev);
+
+ err = pd->register_dev(pd->parent, dev, dev->fabric_id, &iaf_ops);
+ if (err) {
+ iaf_sysfs_remove(dev);
+ goto sysfs_error;
+ }
+
+ for (sds_added = 0; sds_added < pd->sd_cnt; ++sds_added) {
+ err = add_subdevice(&dev->sd[sds_added], dev, sds_added);
+ if (err)
+ goto add_error;
+ }
+
+ return 0;
+
+add_error:
+ iaf_sysfs_remove(dev);
+ for (i = 0; i < sds_added; ++i)
+ remove_subdevice(&dev->sd[i]);
+
+ pd->unregister_dev(pd->parent, dev);
+
+sysfs_error:
+ fdev_wait_on_release(dev);
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ kfree(dev);
+ return err;
+}
+
+static const struct auxiliary_device_id iaf_id_table[] = {
+ { .name = "xe.iaf", },
+ {},
+};
+
+static struct auxiliary_driver iaf_driver = {
+ .probe = iaf_probe,
+ .remove = iaf_remove,
+ .id_table = iaf_id_table,
+};
+
+static void __exit iaf_unload_module(void)
+{
+ pr_notice("Unloading %s\n", MODULEDETAILS);
+
+ auxiliary_driver_unregister(&iaf_driver);
+ pr_notice("%s Unloaded\n", MODULEDETAILS);
+}
+module_exit(iaf_unload_module);
+
+/*
+ * \brief Loads the module into kernel space and does global initializations.
+ * Called by insmod or modprobe.
+ */
+static int __init iaf_load_module(void)
+{
+ int err;
+
+ pr_notice("Initializing %s\n", MODULEDETAILS);
+ pr_debug("Built for Linux Kernel %s\n", UTS_RELEASE);
+
+ err = auxiliary_driver_register(&iaf_driver);
+ if (err)
+ pr_err("Cannot register with auxiliary bus\n");
+
+ return err;
+}
+module_init(iaf_load_module);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_DESCRIPTION(MODULEDETAILS);
+MODULE_LICENSE("GPL and additional rights");
+MODULE_ALIAS("auxiliary:xe.iaf");
diff --git a/drivers/gpu/drm/xe/fabric/sysfs.c b/drivers/gpu/drm/xe/fabric/sysfs.c
new file mode 100644
index 000000000000..b7af3fdace1a
--- /dev/null
+++ b/drivers/gpu/drm/xe/fabric/sysfs.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright(c) 2020 - 2023 Intel Corporation.
+ *
+ */
+
+#include <linux/device.h>
+#include "csr.h"
+#include "iaf_drv.h"
+#include "sysfs.h"
+
+static ssize_t sd_failure_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct fsubdev *sd;
+
+ sd = container_of(attr, struct fsubdev, sd_failure);
+
+ return sysfs_emit(buf, "%u\n", test_bit(SD_ERROR_FAILED, sd->errors));
+}
+
+static ssize_t iaf_fabric_id_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct fdev *fdev = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "0x%x\n", fdev->fabric_id);
+}
+
+static DEVICE_ATTR_RO(iaf_fabric_id);
+
+static const struct attribute *iaf_attrs[] = {
+ &dev_attr_iaf_fabric_id.attr,
+ NULL,
+};
+
+static void iaf_sysfs_cleanup(struct fsubdev *sd)
+{
+ kobject_put(sd->kobj);
+ sd->kobj = NULL;
+}
+
+typedef ssize_t (*show_fn)(struct device *dev, struct device_attribute *attr, char *buf);
+
+static int iaf_sysfs_add_node(const char *name, umode_t mode, show_fn show,
+ struct device_attribute *attr, struct kobject *parent)
+{
+ sysfs_attr_init(&attr->attr);
+ attr->attr.name = name;
+ attr->attr.mode = mode;
+ attr->show = show;
+
+ return sysfs_create_file(parent, &attr->attr);
+}
+
+static int iaf_sysfs_add_sd_nodes(struct fsubdev *sd)
+{
+ int err;
+
+ err = iaf_sysfs_add_node("sd_failure", 0400, sd_failure_show, &sd->sd_failure, sd->kobj);
+ if (err)
+ sd_warn(sd, "Failed to add sysfs node %s for %s\n", "sd_failure", sd->name);
+
+ return err;
+}
+
+static void iaf_sysfs_sd_init(struct fsubdev *sd)
+{
+ int err;
+
+ sd->kobj = kobject_create_and_add(sd->name, &sd->fdev->pdev->dev.kobj);
+ if (!sd->kobj) {
+ sd_warn(sd, "Failed to add sysfs directory %s\n", sd->name);
+ return;
+ }
+
+ err = iaf_sysfs_add_sd_nodes(sd);
+ if (err)
+ goto error_return;
+
+ return;
+
+error_return:
+ iaf_sysfs_cleanup(sd);
+}
+
+void iaf_sysfs_init(struct fdev *fdev)
+{
+ u8 i;
+
+ for (i = 0; i < fdev->pd->sd_cnt; i++)
+ iaf_sysfs_sd_init(&fdev->sd[i]);
+}
+
+void iaf_sysfs_remove(struct fdev *fdev)
+{
+ u8 i;
+
+ for (i = 0; i < fdev->pd->sd_cnt; i++)
+ iaf_sysfs_cleanup(&fdev->sd[i]);
+
+ sysfs_remove_files(&fdev->pdev->dev.kobj, iaf_attrs);
+}
+
+int iaf_sysfs_probe(struct fdev *fdev)
+{
+ int err;
+
+ err = sysfs_create_files(&fdev->pdev->dev.kobj, iaf_attrs);
+ if (err) {
+ dev_err(&fdev->pdev->dev, "Failed to add sysfs\n");
+ return err;
+ }
+ return 0;
+}
diff --git a/drivers/gpu/drm/xe/fabric/sysfs.h b/drivers/gpu/drm/xe/fabric/sysfs.h
new file mode 100644
index 000000000000..e42ccdd5b0fd
--- /dev/null
+++ b/drivers/gpu/drm/xe/fabric/sysfs.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright(c) 2020 - 2023 Intel Corporation.
+ *
+ */
+
+#ifndef SYSFS_H_INCLUDED
+#define SYSFS_H_INCLUDED
+
+#include "iaf_drv.h"
+
+void iaf_sysfs_init(struct fdev *fdev);
+void iaf_sysfs_remove(struct fdev *fdev);
+int iaf_sysfs_probe(struct fdev *fdev);
+
+#endif
--
2.35.1
More information about the Intel-xe
mailing list