From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 56F06EA8558 for ; Mon, 9 Mar 2026 05:23:32 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1667110E48A; Mon, 9 Mar 2026 05:23:32 +0000 (UTC) Authentication-Results: gabe.freedesktop.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.b="JphszGRT"; dkim-atps=neutral Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.13]) by gabe.freedesktop.org (Postfix) with ESMTPS id 095E210E48A for ; Mon, 9 Mar 2026 05:23:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1773033811; x=1804569811; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Jcq9mzk9N/FQxWC19FQ73rJXjftvHqvZJrUGcEvDFBw=; b=JphszGRTBHLeTNwGkUsHScMqB3+Fx8VMFEHWQWZf+a4LjHVyAshe4G3o gsfCPghQXTc6J2cZlFXO8k8ZZD2EAXvgH6hqGIudb+VP8NErhahkhUEJQ wBP5QBGwqJXZswL5+fPFpHkkQXN67eU4letzYWQlPh+7Dk4yXHMQ+S0g4 lOmcmHs4vwd5+H88fIACffvf228INGThAJfAmPwFl6M8RvbckYMTeEqAH Lku+N3OdlodfNErptF6g/inQULVrSfTiSuINcYDQIvJ4BnAgLY9gPbb6s I8a5/Yc1WwZ25D03PzRpXqgpFh4s+eMMYyKpEVlfx4uHIvrONSuSQJSDO A==; X-CSE-ConnectionGUID: f/YMeuAETiiXHgMsJrSNmQ== X-CSE-MsgGUID: RHkiKKN8TDi6EGbiY1iQTg== X-IronPort-AV: E=McAfee;i="6800,10657,11723"; a="85138485" X-IronPort-AV: E=Sophos;i="6.23,109,1770624000"; d="scan'208";a="85138485" Received: from orviesa005.jf.intel.com ([10.64.159.145]) by orvoesa105.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Mar 2026 22:23:31 -0700 X-CSE-ConnectionGUID: JQaMjPxxRdiqDq7uOB7gKA== X-CSE-MsgGUID: yx9T+iumSWex40F1+zQAMQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.23,109,1770624000"; d="scan'208";a="224582927" Received: from psoham-nuc7i7bnh.iind.intel.com ([10.190.216.151]) by orviesa005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Mar 2026 22:23:27 -0700 From: Soham Purkait To: intel-xe@lists.freedesktop.org, riana.tauro@intel.com, anshuman.gupta@intel.com, aravind.iddamsetty@linux.intel.com, badal.nilawar@intel.com, raag.jadav@intel.com, ravi.kishore.koppuravuri@intel.com, mallesh.koujalagi@intel.com Cc: soham.purkait@intel.com, anoop.c.vijay@intel.com Subject: [PATCH 1/3] From: Anoop Vijay Date: Mon, 9 Mar 2026 10:47:03 +0530 Message-Id: <20260309051705.980155-2-soham.purkait@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20260309051705.980155-1-soham.purkait@intel.com> References: <20260309051705.980155-1-soham.purkait@intel.com> MIME-Version: 1.0 Content-Type: text/plain; charset=yes Content-Transfer-Encoding: 8bit X-BeenThere: intel-xe@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Intel Xe graphics driver List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: intel-xe-bounces@lists.freedesktop.org Sender: "Intel-xe" From: Anoop Vijay DO NOT REVIEW. COMPILATION ONLY This patch is from https://patchwork.freedesktop.org/series/159554/ Added only for Compilation. Signed-off-by: Soham Purkait --- drivers/gpu/drm/xe/Makefile | 2 + drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h | 31 ++ drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h | 36 ++ drivers/gpu/drm/xe/xe_device.c | 5 + drivers/gpu/drm/xe/xe_device_types.h | 6 + drivers/gpu/drm/xe/xe_pci.c | 2 + drivers/gpu/drm/xe/xe_pci_types.h | 1 + drivers/gpu/drm/xe/xe_sysctrl.c | 84 ++++ drivers/gpu/drm/xe/xe_sysctrl.h | 21 + drivers/gpu/drm/xe/xe_sysctrl_mailbox.c | 364 ++++++++++++++++++ drivers/gpu/drm/xe/xe_sysctrl_mailbox.h | 31 ++ drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h | 35 ++ drivers/gpu/drm/xe/xe_sysctrl_types.h | 32 ++ 13 files changed, 650 insertions(+) create mode 100644 drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h create mode 100644 drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h create mode 100644 drivers/gpu/drm/xe/xe_sysctrl.c create mode 100644 drivers/gpu/drm/xe/xe_sysctrl.h create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_mailbox.c create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_mailbox.h create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h create mode 100644 drivers/gpu/drm/xe/xe_sysctrl_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index ff778fb2d4ff..1890bbd1b28d 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -122,6 +122,8 @@ xe-y += xe_bb.o \ xe_step.o \ xe_survivability_mode.o \ xe_sync.o \ + xe_sysctrl.o \ + xe_sysctrl_mailbox.o \ xe_tile.o \ xe_tile_sysfs.o \ xe_tlb_inval.o \ diff --git a/drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h b/drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h new file mode 100644 index 000000000000..8eefb0ddafd7 --- /dev/null +++ b/drivers/gpu/drm/xe/abi/xe_sysctrl_abi.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_ABI_H_ +#define _XE_SYSCTRL_ABI_H_ + +#include + +struct xe_sysctrl_mailbox_mkhi_msg_hdr { + __le32 data; +} __packed; + +struct xe_sysctrl_app_msg_hdr { + __le32 data; +} __packed; + +#define MKHI_HDR_GROUP_ID_MASK GENMASK(7, 0) +#define MKHI_HDR_COMMAND_MASK GENMASK(14, 8) +#define MKHI_HDR_COMMAND_MAX 0x7F +#define MKHI_HDR_IS_RESPONSE BIT(15) +#define MKHI_HDR_RESERVED_MASK GENMASK(23, 16) +#define MKHI_HDR_RESULT_MASK GENMASK(31, 24) + +#define APP_HDR_GROUP_ID_MASK GENMASK(7, 0) +#define APP_HDR_COMMAND_MASK GENMASK(15, 8) +#define APP_HDR_VERSION_MASK GENMASK(23, 16) +#define APP_HDR_RESERVED_MASK GENMASK(31, 24) + +#endif diff --git a/drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h b/drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h new file mode 100644 index 000000000000..f3c00f54a2ce --- /dev/null +++ b/drivers/gpu/drm/xe/regs/xe_sysctrl_regs.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_REGS_H_ +#define _XE_SYSCTRL_REGS_H_ + +#include "xe_regs.h" + +#define SYSCTRL_BASE_OFFSET 0xdb000 +#define SYSCTRL_BASE (SOC_BASE + SYSCTRL_BASE_OFFSET) +#define SYSCTRL_MAILBOX_INDEX 0x03 +#define SYSCTRL_BAR_LENGTH 0x1000 + +#define SYSCTRL_MB_CTRL XE_REG(0x10) +#define SYSCTRL_MB_CTRL_RUN_BUSY REG_BIT(31) +#define SYSCTRL_MB_CTRL_IRQ REG_BIT(30) +#define SYSCTRL_MB_CTRL_RUN_BUSY_OUT REG_BIT(29) +#define SYSCTRL_MB_CTRL_PARAM3_MASK REG_GENMASK(28, 24) +#define SYSCTRL_MB_CTRL_PARAM2_MASK REG_GENMASK(23, 16) +#define SYSCTRL_MB_CTRL_PARAM1_MASK REG_GENMASK(15, 8) +#define SYSCTRL_MB_CTRL_COMMAND_MASK REG_GENMASK(7, 0) +#define SYSCTRL_MB_CTRL_MKHI_CMD REG_FIELD_PREP(SYSCTRL_MB_CTRL_COMMAND_MASK, 5) + +#define SYSCTRL_MB_DATA0 XE_REG(0x14) +#define SYSCTRL_MB_DATA1 XE_REG(0x18) +#define SYSCTRL_MB_DATA2 XE_REG(0x1C) +#define SYSCTRL_MB_DATA3 XE_REG(0x20) + +#define MKHI_FRAME_PHASE REG_BIT(24) +#define MKHI_FRAME_CURRENT_MASK REG_GENMASK(21, 16) +#define MKHI_FRAME_TOTAL_MASK REG_GENMASK(13, 8) +#define MKHI_FRAME_COMMAND_MASK REG_GENMASK(7, 0) + +#endif diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 3462645ca13c..1d61bb504e9b 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -65,6 +65,7 @@ #include "xe_survivability_mode.h" #include "xe_sriov.h" #include "xe_svm.h" +#include "xe_sysctrl.h" #include "xe_tile.h" #include "xe_ttm_stolen_mgr.h" #include "xe_ttm_sys_mgr.h" @@ -985,6 +986,10 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err_unregister_display; + err = xe_sysctrl_init(xe); + if (err) + goto err_unregister_display; + err = xe_device_sysfs_init(xe); if (err) goto err_unregister_display; diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index caa8f34a6744..ec66ef772cd6 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -26,6 +26,7 @@ #include "xe_sriov_vf_ccs_types.h" #include "xe_step_types.h" #include "xe_survivability_mode_types.h" +#include "xe_sysctrl_types.h" #include "xe_tile_types.h" #include "xe_validation.h" @@ -203,6 +204,8 @@ struct xe_device { u8 has_soc_remapper_telem:1; /** @info.has_sriov: Supports SR-IOV */ u8 has_sriov:1; + /** @info.has_sysctrl: Supports System Controller */ + u8 has_sysctrl:1; /** @info.has_usm: Device has unified shared memory support */ u8 has_usm:1; /** @info.has_64bit_timestamp: Device supports 64-bit timestamps */ @@ -512,6 +515,9 @@ struct xe_device { /** @i2c: I2C host controller */ struct xe_i2c *i2c; + /** @sc: System Controller */ + struct xe_sysctrl sc; + /** @atomic_svm_timeslice_ms: Atomic SVM fault timeslice MS */ u32 atomic_svm_timeslice_ms; diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 3ac99472d6dd..ad1e5ef2ee89 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -462,6 +462,7 @@ static const struct xe_device_desc cri_desc = { .has_soc_remapper_sysctrl = true, .has_soc_remapper_telem = true, .has_sriov = true, + .has_sysctrl = true, .max_gt_per_tile = 2, MULTI_LRC_MASK, .require_force_probe = true, @@ -761,6 +762,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.has_soc_remapper_telem = desc->has_soc_remapper_telem; xe->info.has_sriov = xe_configfs_primary_gt_allowed(to_pci_dev(xe->drm.dev)) && desc->has_sriov; + xe->info.has_sysctrl = desc->has_sysctrl; xe->info.skip_guc_pc = desc->skip_guc_pc; xe->info.skip_mtcfg = desc->skip_mtcfg; xe->info.skip_pcode = desc->skip_pcode; diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 47e8a1552c2b..6ffef99b7973 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -57,6 +57,7 @@ struct xe_device_desc { u8 has_soc_remapper_sysctrl:1; u8 has_soc_remapper_telem:1; u8 has_sriov:1; + u8 has_sysctrl:1; u8 needs_scratch:1; u8 skip_guc_pc:1; u8 skip_mtcfg:1; diff --git a/drivers/gpu/drm/xe/xe_sysctrl.c b/drivers/gpu/drm/xe/xe_sysctrl.c new file mode 100644 index 000000000000..365f73ef680d --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include +#include + +#include + +#include "regs/xe_sysctrl_regs.h" +#include "xe_assert.h" +#include "xe_device.h" +#include "xe_mmio.h" +#include "xe_printk.h" +#include "xe_soc_remapper.h" +#include "xe_sriov.h" +#include "xe_sysctrl.h" +#include "xe_sysctrl_mailbox.h" +#include "xe_sysctrl_types.h" + +/** + * DOC: System Controller (sysctrl) + * + * The System Controller (sysctrl) is an embedded microcontroller in Intel GPUs + * responsible for managing various low-level platform functions. Communication + * between the driver and the System Controller occurs via a mailbox interface, + * enabling the exchange of commands and responses. + * + * This module provides initialization routines and helper functions to interact + * with the System Controller through the mailbox. + */ +static void sysctrl_fini(void *arg) +{ + struct xe_device *xe = arg; + + xe->soc_remapper.set_sysctrl_region(xe, 0); +} + +/** + * xe_sysctrl_init() - Initialize System Controller subsystem + * @xe: xe device instance + * + * Entry point for System Controller initialization, called from xe_device_probe. + * This function checks platform support and initializes the system controller. + * + * Return: 0 on success, error code on failure + */ +int xe_sysctrl_init(struct xe_device *xe) +{ + struct xe_tile *tile = xe_device_get_root_tile(xe); + struct xe_sysctrl *sc = &xe->sc; + int ret; + + if (!xe->info.has_sysctrl) + return 0; + + if (IS_SRIOV_VF(xe)) + return 0; + + xe_assert(xe, xe->soc_remapper.set_sysctrl_region); + + xe->soc_remapper.set_sysctrl_region(xe, SYSCTRL_MAILBOX_INDEX); + + ret = devm_add_action_or_reset(xe->drm.dev, sysctrl_fini, xe); + if (ret) + return ret; + + sc->mmio = devm_kzalloc(xe->drm.dev, sizeof(*sc->mmio), GFP_KERNEL); + if (!sc->mmio) + return -ENOMEM; + + xe_mmio_init(sc->mmio, tile, tile->mmio.regs, tile->mmio.regs_size); + sc->mmio->adj_offset = SYSCTRL_BASE; + sc->mmio->adj_limit = U32_MAX; + + ret = drmm_mutex_init(&xe->drm, &sc->cmd_lock); + if (ret) + return ret; + + xe_sysctrl_mailbox_init(sc); + + return 0; +} diff --git a/drivers/gpu/drm/xe/xe_sysctrl.h b/drivers/gpu/drm/xe/xe_sysctrl.h new file mode 100644 index 000000000000..d5d8735038ae --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_H_ +#define _XE_SYSCTRL_H_ + +#include + +#include "xe_device_types.h" +#include "xe_sysctrl_types.h" + +static inline struct xe_device *sc_to_xe(struct xe_sysctrl *sc) +{ + return container_of(sc, struct xe_device, sc); +} + +int xe_sysctrl_init(struct xe_device *xe); + +#endif diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c new file mode 100644 index 000000000000..0e154b6dcdc7 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.c @@ -0,0 +1,364 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2026 Intel Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "regs/xe_sysctrl_regs.h" +#include "xe_device.h" +#include "xe_device_types.h" +#include "xe_mmio.h" +#include "xe_pm.h" +#include "xe_printk.h" +#include "xe_sysctrl.h" +#include "xe_sysctrl_mailbox.h" +#include "xe_sysctrl_mailbox_types.h" +#include "xe_sysctrl_types.h" + +#define XE_SYSCTRL_MKHI_HDR_GROUP_ID(hdr) \ + FIELD_GET(MKHI_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_MKHI_HDR_COMMAND(hdr) \ + FIELD_GET(MKHI_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_MKHI_HDR_IS_RESPONSE(hdr) \ + FIELD_GET(MKHI_HDR_IS_RESPONSE, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_MKHI_HDR_RESULT(hdr) \ + FIELD_GET(MKHI_HDR_RESULT_MASK, le32_to_cpu((hdr)->data)) + +static bool sysctrl_wait_bit_clear(struct xe_sysctrl *sc, u32 bit_mask, + unsigned int timeout_ms) +{ + int ret; + + ret = xe_mmio_wait32_not(sc->mmio, SYSCTRL_MB_CTRL, bit_mask, bit_mask, + timeout_ms * 1000, NULL, false); + + return ret == 0; +} + +static bool sysctrl_wait_bit_set(struct xe_sysctrl *sc, u32 bit_mask, + unsigned int timeout_ms) +{ + int ret; + + ret = xe_mmio_wait32(sc->mmio, SYSCTRL_MB_CTRL, bit_mask, bit_mask, + timeout_ms * 1000, NULL, false); + + return ret == 0; +} + +static int sysctrl_write_frame(struct xe_sysctrl *sc, const void *frame, + size_t len) +{ + static const struct xe_reg regs[] = { + SYSCTRL_MB_DATA0, SYSCTRL_MB_DATA1, SYSCTRL_MB_DATA2, SYSCTRL_MB_DATA3 + }; + struct xe_device *xe = sc_to_xe(sc); + u32 val[XE_SYSCTRL_MB_FRAME_SIZE / sizeof(u32)] = {0}; + u32 dw = DIV_ROUND_UP(len, sizeof(u32)); + u32 i; + + xe_assert(xe, len > 0 && len <= XE_SYSCTRL_MB_FRAME_SIZE); + + memcpy(val, frame, len); + + for (i = 0; i < dw; i++) + xe_mmio_write32(sc->mmio, regs[i], val[i]); + + return 0; +} + +static int sysctrl_read_frame(struct xe_sysctrl *sc, void *frame, + size_t len) +{ + static const struct xe_reg regs[] = { + SYSCTRL_MB_DATA0, SYSCTRL_MB_DATA1, SYSCTRL_MB_DATA2, SYSCTRL_MB_DATA3 + }; + struct xe_device *xe = sc_to_xe(sc); + u32 val[XE_SYSCTRL_MB_FRAME_SIZE / sizeof(u32)] = {0}; + u32 dw = DIV_ROUND_UP(len, sizeof(u32)); + u32 i; + + xe_assert(xe, len > 0 && len <= XE_SYSCTRL_MB_FRAME_SIZE); + + for (i = 0; i < dw; i++) + val[i] = xe_mmio_read32(sc->mmio, regs[i]); + + memcpy(frame, val, len); + + return 0; +} + +static void sysctrl_clear_response(struct xe_sysctrl *sc) +{ + xe_mmio_rmw32(sc->mmio, SYSCTRL_MB_CTRL, SYSCTRL_MB_CTRL_RUN_BUSY_OUT, 0); +} + +static int sysctrl_prepare_command(struct xe_device *xe, + u8 group_id, u8 command, + const void *data_in, size_t data_in_len, + u8 **mbox_cmd, size_t *cmd_size) +{ + struct xe_sysctrl_mailbox_mkhi_msg_hdr *mkhi_hdr; + size_t size; + u8 *buffer; + + xe_assert(xe, command <= MKHI_HDR_COMMAND_MAX); + + if (data_in_len > XE_SYSCTRL_MB_MAX_MESSAGE_SIZE - sizeof(*mkhi_hdr)) { + xe_err(xe, "sysctrl: Input data too large: %zu bytes\n", data_in_len); + return -EINVAL; + } + + size = sizeof(*mkhi_hdr) + data_in_len; + + buffer = kmalloc(size, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + mkhi_hdr = (struct xe_sysctrl_mailbox_mkhi_msg_hdr *)buffer; + mkhi_hdr->data = cpu_to_le32(FIELD_PREP(MKHI_HDR_GROUP_ID_MASK, group_id) | + FIELD_PREP(MKHI_HDR_COMMAND_MASK, command)); + + if (data_in && data_in_len) + memcpy(buffer + sizeof(*mkhi_hdr), data_in, data_in_len); + + *mbox_cmd = buffer; + *cmd_size = size; + + return 0; +} + +static int sysctrl_send_frames(struct xe_sysctrl *sc, + const u8 *mbox_cmd, + size_t cmd_size, unsigned int timeout_ms) +{ + struct xe_device *xe = sc_to_xe(sc); + u32 ctrl_reg, total_frames, frame; + size_t bytes_sent, frame_size; + + total_frames = DIV_ROUND_UP(cmd_size, XE_SYSCTRL_MB_FRAME_SIZE); + + if (!sysctrl_wait_bit_clear(sc, SYSCTRL_MB_CTRL_RUN_BUSY, timeout_ms)) { + xe_err(xe, "sysctrl: Mailbox busy\n"); + return -EBUSY; + } + + sc->phase_bit ^= 1; + bytes_sent = 0; + + for (frame = 0; frame < total_frames; frame++) { + frame_size = min_t(size_t, cmd_size - bytes_sent, XE_SYSCTRL_MB_FRAME_SIZE); + + if (sysctrl_write_frame(sc, mbox_cmd + bytes_sent, frame_size)) { + xe_err(xe, "sysctrl: Failed to write frame %u\n", frame); + sc->phase_bit = 0; + return -EIO; + } + + ctrl_reg = SYSCTRL_MB_CTRL_RUN_BUSY | + REG_FIELD_PREP(MKHI_FRAME_CURRENT_MASK, frame) | + REG_FIELD_PREP(MKHI_FRAME_TOTAL_MASK, total_frames - 1) | + SYSCTRL_MB_CTRL_MKHI_CMD | + (sc->phase_bit ? MKHI_FRAME_PHASE : 0); + + xe_mmio_write32(sc->mmio, SYSCTRL_MB_CTRL, ctrl_reg); + + if (!sysctrl_wait_bit_clear(sc, SYSCTRL_MB_CTRL_RUN_BUSY, timeout_ms)) { + xe_err(xe, "sysctrl: Frame %u acknowledgment timeout\n", frame); + sc->phase_bit = 0; + return -ETIMEDOUT; + } + + bytes_sent += frame_size; + } + + return 0; +} + +static int sysctrl_process_frame(struct xe_sysctrl *sc, void *out, + size_t frame_size, unsigned int timeout_ms, + bool *done) +{ + u32 curr_frame, total_frames, ctrl_reg; + struct xe_device *xe = sc_to_xe(sc); + int ret; + + if (!sysctrl_wait_bit_set(sc, SYSCTRL_MB_CTRL_RUN_BUSY_OUT, timeout_ms)) { + xe_err(xe, "sysctrl: Response frame timeout\n"); + return -ETIMEDOUT; + } + + ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL); + total_frames = FIELD_GET(MKHI_FRAME_TOTAL_MASK, ctrl_reg); + curr_frame = FIELD_GET(MKHI_FRAME_CURRENT_MASK, ctrl_reg); + + ret = sysctrl_read_frame(sc, out, frame_size); + if (ret) + return ret; + + sysctrl_clear_response(sc); + + if (curr_frame == total_frames) + *done = true; + + return 0; +} + +static int sysctrl_receive_frames(struct xe_sysctrl *sc, + const struct xe_sysctrl_mailbox_mkhi_msg_hdr *req, + void *data_out, size_t data_out_len, + size_t *rdata_len, unsigned int timeout_ms) +{ + struct xe_sysctrl_mailbox_mkhi_msg_hdr *mkhi_hdr; + struct xe_device *xe = sc_to_xe(sc); + size_t remain = sizeof(*mkhi_hdr) + data_out_len; + + u8 *buffer __free(kfree) = kzalloc(remain, GFP_KERNEL); + size_t frame_size; + bool done = false; + int ret = 0; + u8 *out; + + if (!buffer) + return -ENOMEM; + + out = buffer; + while (!done && remain) { + frame_size = min_t(size_t, remain, XE_SYSCTRL_MB_FRAME_SIZE); + + ret = sysctrl_process_frame(sc, out, frame_size, timeout_ms, + &done); + if (ret) + return ret; + + remain -= frame_size; + out += frame_size; + } + + mkhi_hdr = (struct xe_sysctrl_mailbox_mkhi_msg_hdr *)buffer; + + if (!XE_SYSCTRL_MKHI_HDR_IS_RESPONSE(mkhi_hdr) || + XE_SYSCTRL_MKHI_HDR_GROUP_ID(mkhi_hdr) != XE_SYSCTRL_MKHI_HDR_GROUP_ID(req) || + XE_SYSCTRL_MKHI_HDR_COMMAND(mkhi_hdr) != XE_SYSCTRL_MKHI_HDR_COMMAND(req)) { + xe_err(xe, "sysctrl: Response header mismatch\n"); + return -EPROTO; + } + + if (XE_SYSCTRL_MKHI_HDR_RESULT(mkhi_hdr) != 0) { + xe_err(xe, "sysctrl: Firmware error: 0x%02lx\n", + XE_SYSCTRL_MKHI_HDR_RESULT(mkhi_hdr)); + return -EIO; + } + + memcpy(data_out, mkhi_hdr + 1, data_out_len); + *rdata_len = out - buffer - sizeof(*mkhi_hdr); + + return 0; +} + +static int sysctrl_send_command(struct xe_sysctrl *sc, + const u8 *mbox_cmd, size_t cmd_size, + void *data_out, size_t data_out_len, + size_t *rdata_len, unsigned int timeout_ms) +{ + const struct xe_sysctrl_mailbox_mkhi_msg_hdr *mkhi_hdr; + size_t received; + int ret; + + ret = sysctrl_send_frames(sc, mbox_cmd, cmd_size, timeout_ms); + if (ret) + return ret; + + if (!data_out || !rdata_len) + return 0; + + mkhi_hdr = (const struct xe_sysctrl_mailbox_mkhi_msg_hdr *)mbox_cmd; + + ret = sysctrl_receive_frames(sc, mkhi_hdr, data_out, data_out_len, + &received, timeout_ms); + if (ret) + return ret; + + *rdata_len = received; + + return 0; +} + +/** + * xe_sysctrl_mailbox_init - Initialize System Controller mailbox interface + * @sc: System controller structure + * + * Initialize system controller mailbox interface for communication. + */ +void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc) +{ + u32 ctrl_reg; + + ctrl_reg = xe_mmio_read32(sc->mmio, SYSCTRL_MB_CTRL); + sc->phase_bit = (ctrl_reg & MKHI_FRAME_PHASE) ? 1 : 0; +} + +/** + * xe_sysctrl_send_command() - Send command to System Controller via mailbox + * @sc: System Controller instance + * @cmd: Pointer to xe_sysctrl_mailbox_command structure + * @rdata_len: Pointer to store actual response data size (can be NULL) + * + * Send a command to the System Controller using MKHI protocol. Handles + * command preparation, fragmentation, transmission, and response reception. + * + * Return: 0 on success, negative error code on failure + */ +int xe_sysctrl_send_command(struct xe_sysctrl *sc, + struct xe_sysctrl_mailbox_command *cmd, + size_t *rdata_len) +{ + struct xe_device *xe = sc_to_xe(sc); + u8 group_id, command_code; + u8 *mbox_cmd = NULL; + size_t cmd_size = 0; + int ret = 0; + + xe_assert(xe, xe->info.has_sysctrl); + xe_assert(xe, !cmd->data_in || cmd->data_in_len); + xe_assert(xe, !cmd->data_out || cmd->data_out_len); + + group_id = XE_SYSCTRL_APP_HDR_GROUP_ID(&cmd->header); + command_code = XE_SYSCTRL_APP_HDR_COMMAND(&cmd->header); + + might_sleep(); + + ret = sysctrl_prepare_command(xe, group_id, command_code, + cmd->data_in, cmd->data_in_len, + &mbox_cmd, &cmd_size); + if (ret) { + xe_err(xe, "sysctrl: Failed to prepare command: %pe\n", ERR_PTR(ret)); + return ret; + } + + guard(xe_pm_runtime)(xe); + + guard(mutex)(&sc->cmd_lock); + + ret = sysctrl_send_command(sc, mbox_cmd, cmd_size, + cmd->data_out, cmd->data_out_len, rdata_len, + XE_SYSCTRL_MB_DEFAULT_TIMEOUT_MS); + if (ret) + xe_err(xe, "sysctrl: Mailbox command failed: %pe\n", ERR_PTR(ret)); + + kfree(mbox_cmd); + + return ret; +} diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h new file mode 100644 index 000000000000..91460be9e22c --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_MAILBOX_H_ +#define _XE_SYSCTRL_MAILBOX_H_ + +#include +#include + +#include "abi/xe_sysctrl_abi.h" + +struct xe_sysctrl; +struct xe_sysctrl_mailbox_command; + +#define XE_SYSCTRL_APP_HDR_GROUP_ID(hdr) \ + FIELD_GET(APP_HDR_GROUP_ID_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_APP_HDR_COMMAND(hdr) \ + FIELD_GET(APP_HDR_COMMAND_MASK, le32_to_cpu((hdr)->data)) + +#define XE_SYSCTRL_APP_HDR_VERSION(hdr) \ + FIELD_GET(APP_HDR_VERSION_MASK, le32_to_cpu((hdr)->data)) + +void xe_sysctrl_mailbox_init(struct xe_sysctrl *sc); +int xe_sysctrl_send_command(struct xe_sysctrl *sc, + struct xe_sysctrl_mailbox_command *cmd, + size_t *rdata_len); + +#endif diff --git a/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h new file mode 100644 index 000000000000..32c35a6da1cb --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_mailbox_types.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_MAILBOX_TYPES_H_ +#define _XE_SYSCTRL_MAILBOX_TYPES_H_ + +#include + +#include "abi/xe_sysctrl_abi.h" + +/** + * struct xe_sysctrl_mailbox_command - System Controller mailbox command + * @header: Application message header containing command information + * @data_in: Pointer to input payload data (can be NULL if no input data) + * @data_in_len: Size of input payload in bytes (0 if no input data) + * @data_out: Pointer to output buffer for response data (can be NULL if no response) + * @data_out_len: Size of output buffer in bytes (0 if no response expected) + */ +struct xe_sysctrl_mailbox_command { + struct xe_sysctrl_app_msg_hdr header; + void *data_in; + size_t data_in_len; + void *data_out; + size_t data_out_len; +}; + +#define XE_SYSCTRL_MB_FRAME_SIZE 16 +#define XE_SYSCTRL_MB_MAX_FRAMES 64 +#define XE_SYSCTRL_MB_MAX_MESSAGE_SIZE (XE_SYSCTRL_MB_FRAME_SIZE * XE_SYSCTRL_MB_MAX_FRAMES) + +#define XE_SYSCTRL_MB_DEFAULT_TIMEOUT_MS 500 + +#endif diff --git a/drivers/gpu/drm/xe/xe_sysctrl_types.h b/drivers/gpu/drm/xe/xe_sysctrl_types.h new file mode 100644 index 000000000000..c1a3f4c835b8 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_sysctrl_types.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2026 Intel Corporation + */ + +#ifndef _XE_SYSCTRL_TYPES_H_ +#define _XE_SYSCTRL_TYPES_H_ + +#include +#include + +struct xe_mmio; + +/** + * struct xe_sysctrl - System Controller driver context + * + * This structure maintains the runtime state for System Controller + * communication. All fields are initialized during xe_sysctrl_init() + * and protected appropriately for concurrent access. + */ +struct xe_sysctrl { + /** @mmio: MMIO region for system control registers */ + struct xe_mmio *mmio; + + /** @cmd_lock: Mutex protecting mailbox command operations */ + struct mutex cmd_lock; + + /** @phase_bit: MKHI message boundary phase toggle bit (0 or 1) */ + bool phase_bit; +}; + +#endif -- 2.43.0