Commit 1e3dc1d8 authored by Tomas Winkler's avatar Tomas Winkler Committed by Daniele Ceraolo Spurio
Browse files

drm/i915/gsc: add gsc as a mei auxiliary device



GSC is a graphics system controller, it provides
a chassis controller for graphics discrete cards.

There are two MEI interfaces in GSC: HECI1 and HECI2.

Both interfaces are on the BAR0 at offsets 0x00258000 and 0x00259000.
GSC is a GT Engine (class 4: instance 6). HECI1 interrupt is signaled
via bit 15 and HECI2 via bit 14 in the interrupt register.

This patch exports GSC as auxiliary device for mei driver to bind to
for HECI2 interface and prepares for HECI1 interface as
it will follow up soon.

CC: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: default avatarTomas Winkler <tomas.winkler@intel.com>
Signed-off-by: default avatarVitaly Lubart <vitaly.lubart@intel.com>
Signed-off-by: default avatarAlexander Usyskin <alexander.usyskin@intel.com>
Acked-by: default avatarTvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Signed-off-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220419193314.526966-2-daniele.ceraolospurio@intel.com
parent e1e1f4e3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9996,6 +9996,7 @@ S: Supported
F:	Documentation/driver-api/mei/*
F:	drivers/misc/mei/
F:	drivers/watchdog/mei_wdt.c
F:	include/linux/mei_aux.h
F:	include/linux/mei_cl_bus.h
F:	include/uapi/linux/mei.h
F:	samples/mei/*
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ config DRM_I915
	select VMAP_PFN
	select DRM_TTM
	select DRM_BUDDY
	select AUXILIARY_BUS
	help
	  Choose this option if you have a system that has "Intel Graphics
	  Media Accelerator" or "HD Graphics" integrated graphics,
+3 −0
Original line number Diff line number Diff line
@@ -204,6 +204,9 @@ i915-y += gt/uc/intel_uc.o \
	  gt/uc/intel_huc_debugfs.o \
	  gt/uc/intel_huc_fw.o

# graphics system controller (GSC) support
i915-y += gt/intel_gsc.o

# modesetting core code
i915-y += \
	display/hsw_ips.o \
+204 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: MIT
/*
 * Copyright(c) 2019-2022, Intel Corporation. All rights reserved.
 */

#include <linux/irq.h>
#include <linux/mei_aux.h>
#include "i915_drv.h"
#include "i915_reg.h"
#include "gt/intel_gsc.h"
#include "gt/intel_gt.h"

#define GSC_BAR_LENGTH  0x00000FFC

static void gsc_irq_mask(struct irq_data *d)
{
	/* generic irq handling */
}

static void gsc_irq_unmask(struct irq_data *d)
{
	/* generic irq handling */
}

static struct irq_chip gsc_irq_chip = {
	.name = "gsc_irq_chip",
	.irq_mask = gsc_irq_mask,
	.irq_unmask = gsc_irq_unmask,
};

static int gsc_irq_init(int irq)
{
	irq_set_chip_and_handler_name(irq, &gsc_irq_chip,
				      handle_simple_irq, "gsc_irq_handler");

	return irq_set_chip_data(irq, NULL);
}

struct gsc_def {
	const char *name;
	unsigned long bar;
	size_t bar_size;
};

/* gsc resources and definitions (HECI1 and HECI2) */
static const struct gsc_def gsc_def_dg1[] = {
	{
		/* HECI1 not yet implemented. */
	},
	{
		.name = "mei-gscfi",
		.bar = DG1_GSC_HECI2_BASE,
		.bar_size = GSC_BAR_LENGTH,
	}
};

static void gsc_release_dev(struct device *dev)
{
	struct auxiliary_device *aux_dev = to_auxiliary_dev(dev);
	struct mei_aux_device *adev = auxiliary_dev_to_mei_aux_dev(aux_dev);

	kfree(adev);
}

static void gsc_destroy_one(struct intel_gsc_intf *intf)
{
	if (intf->adev) {
		auxiliary_device_delete(&intf->adev->aux_dev);
		auxiliary_device_uninit(&intf->adev->aux_dev);
		intf->adev = NULL;
	}
	if (intf->irq >= 0)
		irq_free_desc(intf->irq);
	intf->irq = -1;
}

static void gsc_init_one(struct drm_i915_private *i915,
			 struct intel_gsc_intf *intf,
			 unsigned int intf_id)
{
	struct pci_dev *pdev = to_pci_dev(i915->drm.dev);
	struct mei_aux_device *adev;
	struct auxiliary_device *aux_dev;
	const struct gsc_def *def;
	int ret;

	intf->irq = -1;
	intf->id = intf_id;

	if (intf_id == 0 && !HAS_HECI_PXP(i915))
		return;

	def = &gsc_def_dg1[intf_id];

	if (!def->name) {
		drm_warn_once(&i915->drm, "HECI%d is not implemented!\n", intf_id + 1);
		return;
	}

	intf->irq = irq_alloc_desc(0);
	if (intf->irq < 0) {
		drm_err(&i915->drm, "gsc irq error %d\n", intf->irq);
		return;
	}

	ret = gsc_irq_init(intf->irq);
	if (ret < 0) {
		drm_err(&i915->drm, "gsc irq init failed %d\n", ret);
		goto fail;
	}

	adev = kzalloc(sizeof(*adev), GFP_KERNEL);
	if (!adev)
		goto fail;

	adev->irq = intf->irq;
	adev->bar.parent = &pdev->resource[0];
	adev->bar.start = def->bar + pdev->resource[0].start;
	adev->bar.end = adev->bar.start + def->bar_size - 1;
	adev->bar.flags = IORESOURCE_MEM;
	adev->bar.desc = IORES_DESC_NONE;

	aux_dev = &adev->aux_dev;
	aux_dev->name = def->name;
	aux_dev->id = (pci_domain_nr(pdev->bus) << 16) |
		      PCI_DEVID(pdev->bus->number, pdev->devfn);
	aux_dev->dev.parent = &pdev->dev;
	aux_dev->dev.release = gsc_release_dev;

	ret = auxiliary_device_init(aux_dev);
	if (ret < 0) {
		drm_err(&i915->drm, "gsc aux init failed %d\n", ret);
		kfree(adev);
		goto fail;
	}

	ret = auxiliary_device_add(aux_dev);
	if (ret < 0) {
		drm_err(&i915->drm, "gsc aux add failed %d\n", ret);
		/* adev will be freed with the put_device() and .release sequence */
		auxiliary_device_uninit(aux_dev);
		goto fail;
	}
	intf->adev = adev;

	return;
fail:
	gsc_destroy_one(intf);
}

static void gsc_irq_handler(struct intel_gt *gt, unsigned int intf_id)
{
	int ret;

	if (intf_id >= INTEL_GSC_NUM_INTERFACES) {
		drm_warn_once(&gt->i915->drm, "GSC irq: intf_id %d is out of range", intf_id);
		return;
	}

	if (!HAS_HECI_GSC(gt->i915)) {
		drm_warn_once(&gt->i915->drm, "GSC irq: not supported");
		return;
	}

	if (gt->gsc.intf[intf_id].irq < 0) {
		drm_err_ratelimited(&gt->i915->drm, "GSC irq: irq not set");
		return;
	}

	ret = generic_handle_irq(gt->gsc.intf[intf_id].irq);
	if (ret)
		drm_err_ratelimited(&gt->i915->drm, "error handling GSC irq: %d\n", ret);
}

void intel_gsc_irq_handler(struct intel_gt *gt, u32 iir)
{
	if (iir & GSC_IRQ_INTF(0))
		gsc_irq_handler(gt, 0);
	if (iir & GSC_IRQ_INTF(1))
		gsc_irq_handler(gt, 1);
}

void intel_gsc_init(struct intel_gsc *gsc, struct drm_i915_private *i915)
{
	unsigned int i;

	if (!HAS_HECI_GSC(i915))
		return;

	for (i = 0; i < INTEL_GSC_NUM_INTERFACES; i++)
		gsc_init_one(i915, &gsc->intf[i], i);
}

void intel_gsc_fini(struct intel_gsc *gsc)
{
	struct intel_gt *gt = gsc_to_gt(gsc);
	unsigned int i;

	if (!HAS_HECI_GSC(gt->i915))
		return;

	for (i = 0; i < INTEL_GSC_NUM_INTERFACES; i++)
		gsc_destroy_one(&gsc->intf[i]);
}
+37 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: MIT */
/*
 * Copyright(c) 2019-2022, Intel Corporation. All rights reserved.
 */
#ifndef __INTEL_GSC_DEV_H__
#define __INTEL_GSC_DEV_H__

#include <linux/types.h>

struct drm_i915_private;
struct intel_gt;
struct mei_aux_device;

#define INTEL_GSC_NUM_INTERFACES 2
/*
 * The HECI1 bit corresponds to bit15 and HECI2 to bit14.
 * The reason for this is to allow growth for more interfaces in the future.
 */
#define GSC_IRQ_INTF(_x)  BIT(15 - (_x))

/**
 * struct intel_gsc - graphics security controller
 * @intf : gsc interface
 */
struct intel_gsc {
	struct intel_gsc_intf {
		struct mei_aux_device *adev;
		int irq;
		unsigned int id;
	} intf[INTEL_GSC_NUM_INTERFACES];
};

void intel_gsc_init(struct intel_gsc *gsc, struct drm_i915_private *dev_priv);
void intel_gsc_fini(struct intel_gsc *gsc);
void intel_gsc_irq_handler(struct intel_gt *gt, u32 iir);

#endif /* __INTEL_GSC_DEV_H__ */
Loading