diff --git a/autotools/Makefile.am b/autotools/Makefile.am index 0ef9383ba..3fcf04916 100644 --- a/autotools/Makefile.am +++ b/autotools/Makefile.am @@ -86,7 +86,7 @@ DEF_VER=@DOLLAR_SIGN@(shell cat debian/changelog.in | head -1 | cut -d '(' -f 2 #------------------------------------------------------------------------------ -export KBUILD_ONLYXEDIRS := src/drivers/gpu src/include src/scripts src/drivers/platform src/drivers/mtd +export KBUILD_ONLYXEDIRS := src/drivers/gpu src/include src/scripts src/drivers/platform src/drivers/mtd src/drivers/misc export KBUILD_XEVFIOPCIDIRS := src/drivers/vfio/pci/xe export KBUILD_AUTOTOOLS := m4 AUTHORS ChangeLog configure.ac COPYING INSTALL Makefile Makefile.am NEWS README.md compile.sh XE_TAR_CONTENT=$(KBUILD_ONLYXEDIRS) $(KBUILD_AUTOTOOLS) $(KBUILD_XEVFIOPCIDIRS) src/Makefile* src/local-symbols src/MAINTAINERS src/local-symbols-autoconf \ diff --git a/autotools/m4/mei_cl_device_match.m4 b/autotools/m4/mei_cl_device_match.m4 new file mode 100644 index 000000000..1e6a882c6 --- /dev/null +++ b/autotools/m4/mei_cl_device_match.m4 @@ -0,0 +1,23 @@ +dnl # +dnl # v6.11-d69d80484598 +dnl # driver core: have match() callback in struct bus_type take a const * +dnl # +AC_DEFUN([AC_MEI_CL_DEVICE_MATCH_CONST_ARG_NOT_PRESENT], [ + AC_KERNEL_DO_BACKGROUND([ + AC_KERNEL_TRY_COMPILE([ + #include + #include + ],[ + int mei_cl_device_match(struct device *dev, + const struct device_driver *drv); + struct bus_type test_bus = { + .match = mei_cl_device_match, + }; + (void)test_bus; + ],[ + ],[ + AC_DEFINE([BPM_MEI_CL_DEVICE_MATCH_CONST_ARG_NOT_PRESENT], 1, + [const argument not supported in struct bus_type match callback]) + ]) + ]) +]) diff --git a/autotools/m4/pf_driver_remove.m4 b/autotools/m4/pf_driver_remove.m4 new file mode 100644 index 000000000..d937a6a63 --- /dev/null +++ b/autotools/m4/pf_driver_remove.m4 @@ -0,0 +1,19 @@ +dnl # +dnl # v6.11-0edb555a65d1 +dnl # platform: Make platform_driver::remove() return void +dnl # +AC_DEFUN([AC_PF_DRIVER_REMOVE_RETURN_VOID_NOT_PRESENT], [ + AC_KERNEL_DO_BACKGROUND([ + AC_KERNEL_TRY_COMPILE([ + #include + ],[ + void remove_cb(struct platform_device *pdev); + struct platform_driver pdrv = { .remove = remove_cb }; + (void)pdrv; + ],[ + ],[ + AC_DEFINE([BPM_PF_DRIVER_REMOVE_RETURN_VOID_NOT_PRESENT], 1, + [platform_device.remove callback returns int]) + ]) + ]) +]) diff --git a/autotools/m4/xe.m4 b/autotools/m4/xe.m4 index 26c7af146..ad580dfe3 100644 --- a/autotools/m4/xe.m4 +++ b/autotools/m4/xe.m4 @@ -79,6 +79,8 @@ AC_DEFUN([AC_XE_CONFIG], [ AC_DRM_WEDGE_TASK_INFO_NOT_PRESENT AC_DRM_GEM_GPUVA_MUTEX_NOT_PRESENT AC_DRM_GEM_GPUVA_LOCK_DEP_MAP_NOT_PRESENT + AC_MEI_CL_DEVICE_MATCH_CONST_ARG_NOT_PRESENT + AC_PF_DRIVER_REMOVE_RETURN_VOID_NOT_PRESENT dnl # SVM-related probes AC_SHRINKER_ALLOC_NOT_PRESENT @@ -95,6 +97,8 @@ dnl # Macros to check for header availability AC_KERNEL_CHECK_HEADERS([linux/workqueue_types.h]) dnl # v6.8-d84f31791517 locking/mutex: split out mutex_types.h AC_KERNEL_CHECK_HEADERS([linux/mutex_types.h]) + dnl # v6.12-5f60d5f6bbc1 move asm/unaligned.h to linux/unaligned.h + AC_KERNEL_CHECK_HEADERS([linux/unaligned.h]) AC_KERNEL_WAIT ]) diff --git a/backport/Kconfig.sources b/backport/Kconfig.sources index f809e973a..d2ad42912 100644 --- a/backport/Kconfig.sources +++ b/backport/Kconfig.sources @@ -10,3 +10,9 @@ source "$BACKPORT_DIR/drivers/platform/x86/intel/pmt/Kconfig" #VFIO source "$BACKPORT_DIR/drivers/vfio/pci/xe/Kconfig" + +# MEI +source "$BACKPORT_DIR/drivers/misc/mei/Kconfig" +source "$BACKPORT_DIR/drivers/misc/mei/hdcp/Kconfig" +source "$BACKPORT_DIR/drivers/misc/mei/gsc_proxy/Kconfig" +source "$BACKPORT_DIR/drivers/misc/mei/pxp/Kconfig" diff --git a/backport/Makefile.kernel b/backport/Makefile.kernel index 7a99567d0..72a270f57 100644 --- a/backport/Makefile.kernel +++ b/backport/Makefile.kernel @@ -63,3 +63,5 @@ mtd_intel_dg-y := drivers/mtd/devices/mtd_intel_dg.o obj-$(CPTCFG_MTD_INTEL_DG) += mtd_intel_dg.o #vfio obj-$(CPTCFG_XE_VFIO_PCI) += drivers/vfio/pci/xe/ +#mei +obj-$(CPTCFG_INTEL_MEI) += drivers/misc/mei/ diff --git a/backport/backport-include/linux/unaligned.h b/backport/backport-include/linux/unaligned.h new file mode 100644 index 000000000..ab9a1ef81 --- /dev/null +++ b/backport/backport-include/linux/unaligned.h @@ -0,0 +1,12 @@ +#ifndef __BACKPORT_LINUX_UNALIGNED_H +#define __BACKPORT_LINUX_UNALIGNED_H + +#include + +#ifndef HAVE_LINUX_UNALIGNED_H +#include +#else +#include_next +#endif + +#endif /* __BACKPORT_LINUX_UNALIGNED_H */ diff --git a/backport/defconfigs/xe b/backport/defconfigs/xe index 0564dbdc2..cf91be8fd 100644 --- a/backport/defconfigs/xe +++ b/backport/defconfigs/xe @@ -49,3 +49,15 @@ CPTCFG_DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT=y # VFIO # CPTCFG_XE_VFIO_PCI=m + +# +# MEI +# +CPTCFG_INTEL_MEI_HDCP=m +CPTCFG_INTEL_MEI_PXP=m +CPTCFG_INTEL_MEI_GSC_PROXY=m +CPTCFG_INTEL_MEI_TXE=m +CPTCFG_INTEL_MEI_GSC=m +CPTCFG_INTEL_MEI_VSC_HW=m +CPTCFG_INTEL_MEI_LB=m +CPTCFG_INTEL_MEI_VSC=m diff --git a/backport/scripts/backport-mkdrmdkmsconf b/backport/scripts/backport-mkdrmdkmsconf index 41dd7f999..ee8141b85 100755 --- a/backport/scripts/backport-mkdrmdkmsconf +++ b/backport/scripts/backport-mkdrmdkmsconf @@ -85,4 +85,44 @@ sed -e '/^DEL/d' -e 's/^\t*//' < --- + drivers/misc/mei/platform-vsc.c | 4 ++++ drivers/platform/x86/intel/pmt/crashlog.c | 4 ++++ drivers/platform/x86/intel/pmt/telemetry.c | 5 +++++ - 2 files changed, 9 insertions(+) + 3 files changed, 13 insertions(+) +diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c +index 9787b9c..cfc9646 100644 +--- a/drivers/misc/mei/platform-vsc.c ++++ b/drivers/misc/mei/platform-vsc.c +@@ -456,4 +456,8 @@ MODULE_AUTHOR("Wentong Wu "); + MODULE_AUTHOR("Zhifeng Wang "); + MODULE_DESCRIPTION("Intel Visual Sensing Controller Interface"); + MODULE_LICENSE("GPL"); ++#ifdef BPM_MODULE_IMPORT_TO_STRING_LITERAL_PRESENT ++MODULE_IMPORT_NS(VSC_TP); ++#else + MODULE_IMPORT_NS("VSC_TP"); ++#endif diff --git a/drivers/platform/x86/intel/pmt/crashlog.c b/drivers/platform/x86/intel/pmt/crashlog.c index b0393c9..9a581d3 100644 --- a/drivers/platform/x86/intel/pmt/crashlog.c @@ -35,7 +51,7 @@ index b0393c9..9a581d3 100644 MODULE_IMPORT_NS("INTEL_PMT"); +#endif diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c -index a4dfca6..f70a305 100644 +index a52803b..03d2609 100644 --- a/drivers/platform/x86/intel/pmt/telemetry.c +++ b/drivers/platform/x86/intel/pmt/telemetry.c @@ -438,5 +438,10 @@ module_exit(pmt_telem_exit); @@ -51,4 +67,3 @@ index a4dfca6..f70a305 100644 +#endif -- 2.43.0 - diff --git a/patches/0001-mei-bus-fix-match-callback-const-argument-compatibil.patch b/patches/0001-mei-bus-fix-match-callback-const-argument-compatibil.patch new file mode 100644 index 000000000..fdf9fc6db --- /dev/null +++ b/patches/0001-mei-bus-fix-match-callback-const-argument-compatibil.patch @@ -0,0 +1,36 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kanaka Raju Nayana +Date: Mon, 29 Jun 2026 18:13:32 +0530 +Subject: mei: bus: fix match callback const argument compatibility + +When compiling mei bus driver for kernel 6.6, the mei_cl_device_match() +function signature is incompatible with newer kernels (6.11+) where +struct bus_type.match requires const struct device_driver *. +This causes a compilation error on kernel 6.11+. + +Add conditional compilation to support both older kernels (6.6-6.10) +with non-const parameter and newer kernels (6.11+) with const parameter. + +Signed-off-by: Kanaka Raju Nayana +--- + drivers/misc/mei/bus.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c +index f739dbc..34406ae 100644 +--- a/drivers/misc/mei/bus.c ++++ b/drivers/misc/mei/bus.c +@@ -1085,7 +1085,11 @@ struct mei_cl_device_id *mei_cl_device_find(const struct mei_cl_device *cldev, + * + * Return: 1 if matching device was found 0 otherwise + */ ++#ifdef BPM_MEI_CL_DEVICE_MATCH_CONST_ARG_NOT_PRESENT ++static int mei_cl_device_match(struct device *dev, struct device_driver *drv) ++#else + static int mei_cl_device_match(struct device *dev, const struct device_driver *drv) ++#endif + { + const struct mei_cl_device *cldev = to_mei_cl_device(dev); + const struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); +-- +2.43.0 diff --git a/patches/0001-mei-csc-support-controller-with-separate-PCI-device.patch b/patches/0001-mei-csc-support-controller-with-separate-PCI-device.patch new file mode 100644 index 000000000..c122fe2d1 --- /dev/null +++ b/patches/0001-mei-csc-support-controller-with-separate-PCI-device.patch @@ -0,0 +1,734 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kanaka Raju Nayana +Date: Tue, 23 Jun 2026 17:05:23 +0530 +Subject: [PATCH] mei: csc: support controller with separate PCI device + +Intel PCI driver for chassis controller embedded in Intel graphics +devices. + +An MEI device here called CSC can be embedded in discrete +Intel graphics devices having separate PCI device, to support a range +of chassis tasks such as graphics card firmware update and security +tasks. + +First five patches are cleanups and preparations. +Then the new component added and additional fix for power management +for this new component only. + +Alexander Usyskin (7): + mei: fix idle print specifiers + mei: me: move trace into firmware status read + mei: trace: print return value of pci_cfg_read + mei: convert PCI error to common errno + mei: csc: support controller with separate PCI device + mei: csc: wake device while reading firmware status + +Signed-off-by: Kanaka Raju Nayana +--- + drivers/misc/mei/Kconfig | 11 ++ + drivers/misc/mei/Makefile | 3 + + drivers/misc/mei/gsc-me.c | 3 +- + drivers/misc/mei/hw-me-regs.h | 3 + + drivers/misc/mei/hw-me.c | 53 +++++-- + drivers/misc/mei/hw-me.h | 4 +- + drivers/misc/mei/hw-txe.c | 4 +- + drivers/misc/mei/init.c | 4 +- + drivers/misc/mei/main.c | 18 ++- + drivers/misc/mei/mei-trace.h | 10 +- + drivers/misc/mei/mei_dev.h | 5 + + drivers/misc/mei/pci-csc.c | 261 ++++++++++++++++++++++++++++++++++ + drivers/misc/mei/pci-me.c | 8 +- + 13 files changed, 358 insertions(+), 29 deletions(-) + create mode 100644 drivers/misc/mei/pci-csc.c + +diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig +index 094fb1dde..2d1bc5b4d 100644 +--- a/drivers/misc/mei/Kconfig ++++ b/drivers/misc/mei/Kconfig +@@ -59,6 +59,17 @@ config INTEL_MEI_GSC + tasks such as graphics card firmware update and security + tasks. + ++config INTEL_MEI_CSC ++ tristate "Intel MEI CSC embedded device" ++ depends on INTEL_MEI_ME ++ help ++ Intel PCI driver for the chassis controller embedded in Intel graphics devices. ++ ++ An MEI device here called CSC can be embedded in discrete ++ Intel graphics devices, to support a range of chassis ++ tasks such as graphics card firmware update and security ++ tasks. ++ + config INTEL_MEI_VSC_HW + tristate "Intel visual sensing controller device transport driver" + depends on ACPI && SPI +diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile +index a203ed766..9a6aa3359 100644 +--- a/drivers/misc/mei/Makefile ++++ b/drivers/misc/mei/Makefile +@@ -21,6 +21,9 @@ mei-me-objs += hw-me.o + obj-$(CONFIG_INTEL_MEI_GSC) += mei-gsc.o + mei-gsc-objs := gsc-me.o + ++obj-$(CONFIG_INTEL_MEI_CSC) += mei-csc.o ++mei-csc-objs := pci-csc.o ++ + obj-$(CONFIG_INTEL_MEI_TXE) += mei-txe.o + mei-txe-objs := pci-txe.o + mei-txe-objs += hw-txe.o +diff --git a/drivers/misc/mei/gsc-me.c b/drivers/misc/mei/gsc-me.c +index 93cba090e..73d5beeb9 100644 +--- a/drivers/misc/mei/gsc-me.c ++++ b/drivers/misc/mei/gsc-me.c +@@ -23,11 +23,12 @@ + + #define MEI_GSC_RPM_TIMEOUT 500 + +-static int mei_gsc_read_hfs(const struct mei_device *dev, int where, u32 *val) ++static int mei_gsc_read_hfs(const struct mei_device *dev, int where, const char *name, u32 *val) + { + struct mei_me_hw *hw = to_me_hw(dev); + + *val = ioread32(hw->mem_addr + where + 0xC00); ++ trace_mei_reg_read(&dev->dev, name, where, *val); + + return 0; + } +diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h +index 5967f9589..f145e8e36 100644 +--- a/drivers/misc/mei/hw-me-regs.h ++++ b/drivers/misc/mei/hw-me-regs.h +@@ -125,6 +125,8 @@ + #define PCI_DEVICE_ID_INTEL_MEI_NVL_S 0x6E68 /* Nova Lake Point S */ + #define PCI_DEVICE_ID_INTEL_MEI_NVL_H 0xD370 /* Nova Lake Point H */ + ++#define PCI_DEVICE_ID_INTEL_MEI_CRI 0x6766 /* Crescent Island */ ++ + /* + * MEI HW Section + */ +@@ -135,6 +137,7 @@ + # define PCI_CFG_HFS_1_OPMODE_MSK 0xf0000 /* OP MODE Mask: SPS <= 4.0 */ + # define PCI_CFG_HFS_1_OPMODE_SPS 0xf0000 /* SPS SKU : SPS <= 4.0 */ + #define PCI_CFG_HFS_2 0x48 ++# define PCI_CFG_HFS_2_D3_BLOCK BIT(7) + # define PCI_CFG_HFS_2_PM_CMOFF_TO_CMX_ERROR 0x1000000 /* CMoff->CMx wake after an error */ + # define PCI_CFG_HFS_2_PM_CM_RESET_ERROR 0x5000000 /* CME reset due to exception */ + # define PCI_CFG_HFS_2_PM_EVENT_MASK 0xf000000 +diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c +index 1e4a41ac4..e286763b5 100644 +--- a/drivers/misc/mei/hw-me.c ++++ b/drivers/misc/mei/hw-me.c +@@ -215,11 +215,8 @@ static int mei_me_fw_status(struct mei_device *dev, + + fw_status->count = fw_src->count; + for (i = 0; i < fw_src->count && i < MEI_FW_STATUS_MAX; i++) { +- ret = hw->read_fws(dev, fw_src->status[i], ++ ret = hw->read_fws(dev, fw_src->status[i], "PCI_CFG_HFS_X", + &fw_status->status[i]); +- trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HFS_X", +- fw_src->status[i], +- fw_status->status[i]); + if (ret) + return ret; + } +@@ -227,6 +224,15 @@ static int mei_me_fw_status(struct mei_device *dev, + return 0; + } + ++static bool mei_csc_pg_blocked(struct mei_device *dev) ++{ ++ struct mei_me_hw *hw = to_me_hw(dev); ++ u32 reg = 0; ++ ++ hw->read_fws(dev, PCI_CFG_HFS_2, "PCI_CFG_HFS_2", ®); ++ return (reg & PCI_CFG_HFS_2_D3_BLOCK) == PCI_CFG_HFS_2_D3_BLOCK; ++} ++ + /** + * mei_me_hw_config - configure hw dependent settings + * +@@ -250,8 +256,7 @@ static int mei_me_hw_config(struct mei_device *dev) + hw->hbuf_depth = (hcsr & H_CBD) >> 24; + + reg = 0; +- hw->read_fws(dev, PCI_CFG_HFS_1, ®); +- trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HFS_1", PCI_CFG_HFS_1, reg); ++ hw->read_fws(dev, PCI_CFG_HFS_1, "PCI_CFG_HFS_1", ®); + hw->d0i3_supported = + ((reg & PCI_CFG_HFS_1_D0I3_MSK) == PCI_CFG_HFS_1_D0I3_MSK); + +@@ -446,8 +451,7 @@ static void mei_gsc_pxp_check(struct mei_device *dev) + if (!kind_is_gsc(dev) && !kind_is_gscfi(dev)) + return; + +- hw->read_fws(dev, PCI_CFG_HFS_5, &fwsts5); +- trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HFS_5", PCI_CFG_HFS_5, fwsts5); ++ hw->read_fws(dev, PCI_CFG_HFS_5, "PCI_CFG_HFS_5", &fwsts5); + + if ((fwsts5 & GSC_CFG_HFS_5_BOOT_TYPE_MSK) == GSC_CFG_HFS_5_BOOT_TYPE_PXP) { + if (dev->gsc_reset_to_pxp == MEI_DEV_RESET_TO_PXP_DEFAULT) +@@ -1211,6 +1215,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable) + return ret; + } else { + hw->pg_state = MEI_PG_OFF; ++ dev->pg_blocked = mei_csc_pg_blocked(dev); + } + } + +@@ -1299,6 +1304,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) + { + struct mei_device *dev = (struct mei_device *) dev_id; + struct list_head cmpl_list; ++ bool pg_blocked; + s32 slots; + u32 hcsr; + int rets = 0; +@@ -1350,6 +1356,14 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) + } + goto end; + } ++ ++ pg_blocked = mei_csc_pg_blocked(dev); ++ if (pg_blocked && !dev->pg_blocked) /* PG block requested */ ++ pm_request_resume(&dev->dev); ++ else if (!pg_blocked && dev->pg_blocked) /* PG block lifted */ ++ pm_request_autosuspend(&dev->dev); ++ dev->pg_blocked = pg_blocked; ++ + /* check slots available for reading */ + slots = mei_count_full_read_slots(dev); + while (slots > 0) { +@@ -1504,10 +1518,11 @@ static bool mei_me_fw_type_nm(const struct pci_dev *pdev) + { + u32 reg; + unsigned int devfn; ++ int ret; + + devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); +- pci_bus_read_config_dword(pdev->bus, devfn, PCI_CFG_HFS_2, ®); +- trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_2", PCI_CFG_HFS_2, reg); ++ ret = pci_bus_read_config_dword(pdev->bus, devfn, PCI_CFG_HFS_2, ®); ++ trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_2", PCI_CFG_HFS_2, reg, ret); + /* make sure that bit 9 (NM) is up and bit 10 (DM) is down */ + return (reg & 0x600) == 0x200; + } +@@ -1530,10 +1545,11 @@ static bool mei_me_fw_type_sps_4(const struct pci_dev *pdev) + { + u32 reg; + unsigned int devfn; ++ int ret; + + devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); +- pci_bus_read_config_dword(pdev->bus, devfn, PCI_CFG_HFS_1, ®); +- trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_1", PCI_CFG_HFS_1, reg); ++ ret = pci_bus_read_config_dword(pdev->bus, devfn, PCI_CFG_HFS_1, ®); ++ trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_1", PCI_CFG_HFS_1, reg, ret); + return (reg & PCI_CFG_HFS_1_OPMODE_MSK) == PCI_CFG_HFS_1_OPMODE_SPS; + } + +@@ -1555,10 +1571,11 @@ static bool mei_me_fw_type_sps_ign(const struct pci_dev *pdev) + u32 reg; + u32 fw_type; + unsigned int devfn; ++ int ret; + + devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); +- pci_bus_read_config_dword(pdev->bus, devfn, PCI_CFG_HFS_3, ®); +- trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_3", PCI_CFG_HFS_3, reg); ++ ret = pci_bus_read_config_dword(pdev->bus, devfn, PCI_CFG_HFS_3, ®); ++ trace_mei_pci_cfg_read(&pdev->dev, "PCI_CFG_HFS_3", PCI_CFG_HFS_3, reg, ret); + fw_type = (reg & PCI_CFG_HFS_3_FW_SKU_MSK); + + dev_dbg(&pdev->dev, "fw type is %d\n", fw_type); +@@ -1722,6 +1739,13 @@ static const struct mei_cfg mei_me_gscfi_cfg = { + MEI_CFG_FW_VER_SUPP, + }; + ++/* Chassis System Controller Firmware Interface */ ++static const struct mei_cfg mei_me_csc_cfg = { ++ MEI_CFG_TYPE_GSCFI, ++ MEI_CFG_PCH8_HFS, ++ MEI_CFG_FW_VER_SUPP, ++}; ++ + /* + * mei_cfg_list - A list of platform platform specific configurations. + * Note: has to be synchronized with enum mei_cfg_idx. +@@ -1744,6 +1768,7 @@ static const struct mei_cfg *const mei_cfg_list[] = { + [MEI_ME_PCH15_SPS_CFG] = &mei_me_pch15_sps_cfg, + [MEI_ME_GSC_CFG] = &mei_me_gsc_cfg, + [MEI_ME_GSCFI_CFG] = &mei_me_gscfi_cfg, ++ [MEI_ME_CSC_CFG] = &mei_me_csc_cfg, + }; + + const struct mei_cfg *mei_me_get_cfg(kernel_ulong_t idx) +diff --git a/drivers/misc/mei/hw-me.h b/drivers/misc/mei/hw-me.h +index 843ec2497..8da8662a9 100644 +--- a/drivers/misc/mei/hw-me.h ++++ b/drivers/misc/mei/hw-me.h +@@ -56,7 +56,7 @@ struct mei_me_hw { + enum mei_pg_state pg_state; + bool d0i3_supported; + u8 hbuf_depth; +- int (*read_fws)(const struct mei_device *dev, int where, u32 *val); ++ int (*read_fws)(const struct mei_device *dev, int where, const char *name, u32 *val); + /* polling */ + struct task_struct *polling_thread; + wait_queue_head_t wait_active; +@@ -104,6 +104,7 @@ static inline bool mei_me_hw_use_polling(const struct mei_me_hw *hw) + * SPS firmware exclusion. + * @MEI_ME_GSC_CFG: Graphics System Controller + * @MEI_ME_GSCFI_CFG: Graphics System Controller Firmware Interface ++ * @MEI_ME_CSC_CFG: Chassis System Controller Firmware Interface + * @MEI_ME_NUM_CFG: Upper Sentinel. + */ + enum mei_cfg_idx { +@@ -124,6 +125,7 @@ enum mei_cfg_idx { + MEI_ME_PCH15_SPS_CFG, + MEI_ME_GSC_CFG, + MEI_ME_GSCFI_CFG, ++ MEI_ME_CSC_CFG, + MEI_ME_NUM_CFG, + }; + +diff --git a/drivers/misc/mei/hw-txe.c b/drivers/misc/mei/hw-txe.c +index e4688c391..a83de653c 100644 +--- a/drivers/misc/mei/hw-txe.c ++++ b/drivers/misc/mei/hw-txe.c +@@ -651,9 +651,9 @@ static int mei_txe_fw_status(struct mei_device *dev, + &fw_status->status[i]); + trace_mei_pci_cfg_read(&dev->dev, "PCI_CFG_HSF_X", + fw_src->status[i], +- fw_status->status[i]); ++ fw_status->status[i], ret); + if (ret) +- return ret; ++ return pcibios_err_to_errno(ret); + } + + return 0; +diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c +index b789c4d9c..766f119f7 100644 +--- a/drivers/misc/mei/init.c ++++ b/drivers/misc/mei/init.c +@@ -344,13 +344,15 @@ EXPORT_SYMBOL_GPL(mei_stop); + bool mei_write_is_idle(struct mei_device *dev) + { + bool idle = (dev->dev_state == MEI_DEV_ENABLED && ++ !dev->pg_blocked && + list_empty(&dev->ctrl_wr_list) && + list_empty(&dev->write_list) && + list_empty(&dev->write_waiting_list)); + +- dev_dbg(&dev->dev, "write pg: is idle[%d] state=%s ctrl=%01d write=%01d wwait=%01d\n", ++ dev_dbg(&dev->dev, "write pg: is idle[%d] state=%s blocked=%d ctrl=%d write=%d wwait=%d\n", + idle, + mei_dev_state_str(dev->dev_state), ++ dev->pg_blocked, + list_empty(&dev->ctrl_wr_list), + list_empty(&dev->write_list), + list_empty(&dev->write_waiting_list)); +diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c +index 6f26d5160..54f70f513 100644 +--- a/drivers/misc/mei/main.c ++++ b/drivers/misc/mei/main.c +@@ -4,6 +4,7 @@ + * Intel Management Engine Interface (Intel MEI) Linux driver + */ + ++#include + #include + #include + #include +@@ -13,6 +14,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -982,14 +984,22 @@ static DEVICE_ATTR_RO(trc); + static ssize_t fw_status_show(struct device *device, + struct device_attribute *attr, char *buf) + { +- struct mei_device *dev = dev_get_drvdata(device); ++ struct mei_device *mdev = dev_get_drvdata(device); + struct mei_fw_status fw_status; + int err, i; + ssize_t cnt = 0; + +- mutex_lock(&dev->device_lock); +- err = mei_fw_status(dev, &fw_status); +- mutex_unlock(&dev->device_lock); ++ if (mdev->read_fws_need_resume) { ++ err = pm_runtime_resume_and_get(mdev->parent); ++ if (err) { ++ dev_err(device, "read fw_status resume error = %d\n", err); ++ return err; ++ } ++ } ++ scoped_guard(mutex, &mdev->device_lock) ++ err = mei_fw_status(mdev, &fw_status); ++ if (mdev->read_fws_need_resume) ++ pm_runtime_put_autosuspend(mdev->parent); + if (err) { + dev_err(device, "read fw_status error = %d\n", err); + return err; +diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h +index 24fa321d8..fa5224e53 100644 +--- a/drivers/misc/mei/mei-trace.h ++++ b/drivers/misc/mei/mei-trace.h +@@ -55,22 +55,24 @@ TRACE_EVENT(mei_reg_write, + ); + + TRACE_EVENT(mei_pci_cfg_read, +- TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val), +- TP_ARGS(dev, reg, offs, val), ++ TP_PROTO(const struct device *dev, const char *reg, u32 offs, u32 val, int ret), ++ TP_ARGS(dev, reg, offs, val, ret), + TP_STRUCT__entry( + __string(dev, dev_name(dev)) + __string(reg, reg) + __field(u32, offs) + __field(u32, val) ++ __field(int, ret) + ), + TP_fast_assign( + __assign_str(dev); + __assign_str(reg); + __entry->offs = offs; + __entry->val = val; ++ __entry->ret = ret; + ), +- TP_printk("[%s] pci cfg read %s:[%#x] = %#x", +- __get_str(dev), __get_str(reg), __entry->offs, __entry->val) ++ TP_printk("[%s] pci cfg read %s:[%#x] = %#x, ret = %d", ++ __get_str(dev), __get_str(reg), __entry->offs, __entry->val, __entry->ret) + ); + + #endif /* _MEI_TRACE_H_ */ +diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h +index 0bf8d552c..d8634a726 100644 +--- a/drivers/misc/mei/mei_dev.h ++++ b/drivers/misc/mei/mei_dev.h +@@ -490,6 +490,8 @@ struct mei_dev_timeouts { + * @timer_work : MEI timer delayed work (timeouts) + * + * @recvd_hw_ready : hw ready message received flag ++ * @pg_blocked : low power mode is not allowed ++ * @read_fws_need_resume: the FW status handler needs HW woken from sleep + * + * @wait_hw_ready : wait queue for receive HW ready message form FW + * @wait_pg : wait queue for receive PG message from FW +@@ -575,6 +577,9 @@ struct mei_device { + struct delayed_work timer_work; + + bool recvd_hw_ready; ++ bool pg_blocked; ++ bool read_fws_need_resume; ++ + /* + * waiting queue for receive message from FW + */ +diff --git a/drivers/misc/mei/pci-csc.c b/drivers/misc/mei/pci-csc.c +new file mode 100644 +index 000000000..70792bf9b +--- /dev/null ++++ b/drivers/misc/mei/pci-csc.c +@@ -0,0 +1,261 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * Copyright (C) 2025-2026, Intel Corporation. All rights reserved. ++ * Intel Management Engine Interface (Intel MEI) Linux driver ++ * for CSC platforms. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "client.h" ++#include "hw-me-regs.h" ++#include "hw-me.h" ++#include "mei_dev.h" ++#include "mei-trace.h" ++ ++#define MEI_CSC_HECI2_OFFSET 0x1000 ++ ++static int mei_csc_read_fws(const struct mei_device *mdev, int where, const char *name, u32 *val) ++{ ++ struct mei_me_hw *hw = to_me_hw(mdev); ++ ++ *val = ioread32(hw->mem_addr + where + 0xC00); ++ trace_mei_reg_read(&mdev->dev, name, where, *val); ++ return 0; ++} ++ ++static int mei_csc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ++{ ++ struct device *dev = &pdev->dev; ++ const struct mei_cfg *cfg; ++ char __iomem *registers; ++ struct mei_device *mdev; ++ struct mei_me_hw *hw; ++ int err; ++ ++ cfg = mei_me_get_cfg(ent->driver_data); ++ if (!cfg) ++ return -ENODEV; ++ ++ err = pcim_enable_device(pdev); ++ if (err) ++ return dev_err_probe(dev, err, "Failed to enable PCI device.\n"); ++ ++ pci_set_master(pdev); ++ ++ registers = pcim_iomap_region(pdev, 0, KBUILD_MODNAME); ++ if (IS_ERR(registers)) ++ return dev_err_probe(dev, PTR_ERR(registers), "Failed to get PCI region.\n"); ++ ++ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); ++ if (err) ++ return dev_err_probe(dev, err, "No usable DMA configuration.\n"); ++ ++ /* allocates and initializes the mei dev structure */ ++ mdev = mei_me_dev_init(dev, cfg, false); ++ if (!mdev) ++ return -ENOMEM; ++ ++ mdev->read_fws_need_resume = true; ++ ++ hw = to_me_hw(mdev); ++ ++ /* ++ * Both HECI1 and HECI2 are on this device, but only HECI2 is supported. ++ */ ++ hw->mem_addr = registers + MEI_CSC_HECI2_OFFSET; ++ hw->read_fws = mei_csc_read_fws; ++ ++ /* ++ * mei_register() assumes ownership of mdev. ++ * No need to release it explicitly in error path. ++ */ ++ err = mei_register(mdev, dev); ++ if (err) ++ return err; ++ ++ pci_set_drvdata(pdev, mdev); ++ ++ err = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX | PCI_IRQ_MSI); ++ if (err < 0) { ++ dev_err_probe(dev, err, "Failed to allocate IRQ.\n"); ++ goto err_mei_unreg; ++ } ++ ++ hw->irq = pci_irq_vector(pdev, 0); ++ ++ /* request and enable interrupt */ ++ err = request_threaded_irq(hw->irq, ++ mei_me_irq_quick_handler, mei_me_irq_thread_handler, ++ IRQF_SHARED | IRQF_ONESHOT, KBUILD_MODNAME, mdev); ++ if (err) ++ goto err_free_irq_vectors; ++ ++ /* ++ * Continue to char device setup in spite of firmware handshake failure. ++ * In order to provide access to the firmware status registers to the user ++ * space via sysfs. The firmware status registers required to understand ++ * firmware error state and possible recovery flow. ++ */ ++ if (mei_start(mdev)) ++ dev_warn(dev, "Failed to initialize HECI hardware.\n"); ++ ++ pm_runtime_set_autosuspend_delay(dev, MEI_ME_RPM_TIMEOUT); ++ pm_runtime_use_autosuspend(dev); ++ ++ /* ++ * MEI requires to resume from runtime suspend mode ++ * in order to perform link reset flow upon system suspend. ++ */ ++ dev_pm_set_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE); ++ ++ pm_runtime_allow(dev); ++ pm_runtime_put_noidle(dev); ++ ++ return 0; ++ ++err_free_irq_vectors: ++ pci_free_irq_vectors(pdev); ++err_mei_unreg: ++ mei_deregister(mdev); ++ return err; ++} ++ ++static void mei_csc_shutdown(struct pci_dev *pdev) ++{ ++ struct mei_device *mdev = pci_get_drvdata(pdev); ++ struct mei_me_hw *hw = to_me_hw(mdev); ++ ++ pm_runtime_get_noresume(&pdev->dev); ++ ++ mei_stop(mdev); ++ ++ mei_disable_interrupts(mdev); ++ free_irq(hw->irq, mdev); ++ pci_free_irq_vectors(pdev); ++} ++ ++static void mei_csc_remove(struct pci_dev *pdev) ++{ ++ struct mei_device *mdev = pci_get_drvdata(pdev); ++ ++ mei_csc_shutdown(pdev); ++ ++ mei_deregister(mdev); ++} ++ ++static int mei_csc_pci_prepare(struct device *dev) ++{ ++ pm_runtime_resume(dev); ++ return 0; ++} ++ ++static int mei_csc_pci_suspend(struct device *dev) ++{ ++ struct mei_device *mdev = dev_get_drvdata(dev); ++ ++ mei_stop(mdev); ++ ++ mei_disable_interrupts(mdev); ++ ++ return 0; ++} ++ ++static int mei_csc_pci_resume(struct device *dev) ++{ ++ struct mei_device *mdev = dev_get_drvdata(dev); ++ int err; ++ ++ err = mei_restart(mdev); ++ if (err) ++ return err; ++ ++ /* Start timer if stopped in suspend */ ++ schedule_delayed_work(&mdev->timer_work, HZ); ++ ++ return 0; ++} ++ ++static void mei_csc_pci_complete(struct device *dev) ++{ ++ pm_runtime_suspend(dev); ++} ++ ++static int mei_csc_pm_runtime_idle(struct device *dev) ++{ ++ struct mei_device *mdev = dev_get_drvdata(dev); ++ ++ return mei_write_is_idle(mdev) ? 0 : -EBUSY; ++} ++ ++static int mei_csc_pm_runtime_suspend(struct device *dev) ++{ ++ struct mei_device *mdev = dev_get_drvdata(dev); ++ struct mei_me_hw *hw = to_me_hw(mdev); ++ ++ guard(mutex)(&mdev->device_lock); ++ ++ if (!mei_write_is_idle(mdev)) ++ return -EAGAIN; ++ ++ hw->pg_state = MEI_PG_ON; ++ return 0; ++} ++ ++static int mei_csc_pm_runtime_resume(struct device *dev) ++{ ++ struct mei_device *mdev = dev_get_drvdata(dev); ++ struct mei_me_hw *hw = to_me_hw(mdev); ++ irqreturn_t irq_ret; ++ ++ scoped_guard(mutex, &mdev->device_lock) ++ hw->pg_state = MEI_PG_OFF; ++ ++ /* Process all queues that wait for resume */ ++ irq_ret = mei_me_irq_thread_handler(1, mdev); ++ if (irq_ret != IRQ_HANDLED) ++ dev_err(dev, "thread handler fail %d\n", irq_ret); ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops mei_csc_pm_ops = { ++ .prepare = pm_sleep_ptr(mei_csc_pci_prepare), ++ .complete = pm_sleep_ptr(mei_csc_pci_complete), ++ SYSTEM_SLEEP_PM_OPS(mei_csc_pci_suspend, mei_csc_pci_resume) ++ RUNTIME_PM_OPS(mei_csc_pm_runtime_suspend, ++ mei_csc_pm_runtime_resume, mei_csc_pm_runtime_idle) ++}; ++ ++static const struct pci_device_id mei_csc_pci_tbl[] = { ++ { PCI_DEVICE_DATA(INTEL, MEI_CRI, MEI_ME_CSC_CFG) }, ++ {} ++}; ++MODULE_DEVICE_TABLE(pci, mei_csc_pci_tbl); ++ ++static struct pci_driver mei_csc_driver = { ++ .name = KBUILD_MODNAME, ++ .id_table = mei_csc_pci_tbl, ++ .probe = mei_csc_probe, ++ .remove = mei_csc_remove, ++ .shutdown = mei_csc_shutdown, ++ .driver = { ++ .pm = &mei_csc_pm_ops, ++ .probe_type = PROBE_PREFER_ASYNCHRONOUS, ++ } ++}; ++module_pci_driver(mei_csc_driver); ++ ++MODULE_DESCRIPTION("Intel(R) Management Engine Interface for discrete graphics (CSC)"); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c +index 5b6aaa4d3..9efeafa8f 100644 +--- a/drivers/misc/mei/pci-me.c ++++ b/drivers/misc/mei/pci-me.c +@@ -23,6 +23,7 @@ + #include "client.h" + #include "hw-me-regs.h" + #include "hw-me.h" ++#include "mei-trace.h" + + /* mei_pci_tbl - PCI Device ID Table */ + static const struct pci_device_id mei_me_pci_tbl[] = { +@@ -146,11 +147,14 @@ static inline void mei_me_set_pm_domain(struct mei_device *dev) {} + static inline void mei_me_unset_pm_domain(struct mei_device *dev) {} + #endif /* CONFIG_PM */ + +-static int mei_me_read_fws(const struct mei_device *dev, int where, u32 *val) ++static int mei_me_read_fws(const struct mei_device *dev, int where, const char *name, u32 *val) + { + struct pci_dev *pdev = to_pci_dev(dev->parent); ++ int ret; + +- return pci_read_config_dword(pdev, where, val); ++ ret = pci_read_config_dword(pdev, where, val); ++ trace_mei_pci_cfg_read(&dev->dev, name, where, *val, ret); ++ return pcibios_err_to_errno(ret); + } + + /** +-- +2.43.0 + diff --git a/patches/0001-mei-handle-platform-remove-callback-change.patch b/patches/0001-mei-handle-platform-remove-callback-change.patch new file mode 100644 index 000000000..caacb0347 --- /dev/null +++ b/patches/0001-mei-handle-platform-remove-callback-change.patch @@ -0,0 +1,46 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kanaka Raju Nayana +Date: Mon, 29 Jun 2026 21:06:26 +0530 +Subject: mei: handle platform remove callback change + +Kernel 6.11 changed platform_driver::remove() from int to void. +This breaks builds on older kernels if the remove callback +signature is not matched to the target kernel. + +Add a compatibility check and switch mei_vsc_remove() to the +appropriate signature so the driver builds on both 6.6 and +newer kernels. + +Signed-off-by: Kanaka Raju Nayana +--- + drivers/misc/mei/platform-vsc.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/misc/mei/platform-vsc.c b/drivers/misc/mei/platform-vsc.c +index 9787b9c..9e2cd93 100644 +--- a/drivers/misc/mei/platform-vsc.c ++++ b/drivers/misc/mei/platform-vsc.c +@@ -386,7 +386,11 @@ err: + return ret; + } + ++#ifdef BPM_PF_DRIVER_REMOVE_RETURN_VOID_NOT_PRESENT ++static int mei_vsc_remove(struct platform_device *pdev) ++#else + static void mei_vsc_remove(struct platform_device *pdev) ++#endif + { + struct mei_device *mei_dev = platform_get_drvdata(pdev); + struct mei_vsc_hw *hw = mei_dev_to_vsc_hw(mei_dev); +@@ -400,6 +404,9 @@ static void mei_vsc_remove(struct platform_device *pdev) + mei_disable_interrupts(mei_dev); + + mei_deregister(mei_dev); ++#ifdef BPM_PF_DRIVER_REMOVE_RETURN_VOID_NOT_PRESENT ++ return 0; ++#endif + } + + static int mei_vsc_suspend(struct device *dev) +-- +2.43.0 diff --git a/patches/0001-mei-trace-Make-code-compatible-for-older-assign_str-.patch b/patches/0001-mei-trace-Make-code-compatible-for-older-assign_str-.patch new file mode 100644 index 000000000..6cc1b309e --- /dev/null +++ b/patches/0001-mei-trace-Make-code-compatible-for-older-assign_str-.patch @@ -0,0 +1,63 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Kanaka Raju Nayana +Date: Mon, 29 Jun 2026 20:11:06 +0530 +Subject: mei: trace: Make code compatible for older assign_str + arguments + +After changing assign_str to one argument in KV6.10, backporting to +older version need to change parameters with in trace definition. +Go back to old handling. + +Signed-off-by: Kanaka Raju Nayana +--- + drivers/misc/mei/mei-trace.h | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/drivers/misc/mei/mei-trace.h b/drivers/misc/mei/mei-trace.h +index 24fa321..0f9ca96 100644 +--- a/drivers/misc/mei/mei-trace.h ++++ b/drivers/misc/mei/mei-trace.h +@@ -26,8 +26,13 @@ TRACE_EVENT(mei_reg_read, + __field(u32, val) + ), + TP_fast_assign( ++#ifdef BPM_ASSIGN_STR_SECOND_ARG_PRESENT ++ __assign_str(dev, dev_name(dev)); ++ __assign_str(reg,reg); ++#else + __assign_str(dev); + __assign_str(reg); ++#endif + __entry->offs = offs; + __entry->val = val; + ), +@@ -45,8 +50,13 @@ TRACE_EVENT(mei_reg_write, + __field(u32, val) + ), + TP_fast_assign( ++#ifdef BPM_ASSIGN_STR_SECOND_ARG_PRESENT ++ __assign_str(dev, dev_name(dev)); ++ __assign_str(reg,reg); ++#else + __assign_str(dev); + __assign_str(reg); ++#endif + __entry->offs = offs; + __entry->val = val; + ), +@@ -64,8 +74,13 @@ TRACE_EVENT(mei_pci_cfg_read, + __field(u32, val) + ), + TP_fast_assign( ++#ifdef BPM_ASSIGN_STR_SECOND_ARG_PRESENT ++ __assign_str(dev, dev_name(dev)); ++ __assign_str(reg,reg); ++#else + __assign_str(dev); + __assign_str(reg); ++#endif + __entry->offs = offs; + __entry->val = val; + ), +-- +2.43.0