Unverified Commit 1f7a6bcd authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!13917 intel: backport TPMI base driver and PMT fix and update for 5.10

Merge Pull Request from: @jiayingbao 
 
backport TPMI base driver including tpmi and vsec update from 6.10
backport PMT modules update from 6.10

configs: no change

Test:
tpmi debugfs function ok
pmt test passed
 
 
Link:https://gitee.com/openeuler/kernel/pulls/13917

 

Reviewed-by: default avatarJason Zeng <jason.zeng@intel.com>
Reviewed-by: default avatarLi Nan <linan122@huawei.com>
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
parents b0cd67a0 6933a843
Loading
Loading
Loading
Loading
+30 −13
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@
#include "intel_vsec.h"
#include "intel_pmt_class.h"

#define PMT_XA_START		0
#define PMT_XA_START		1
#define PMT_XA_MAX		INT_MAX
#define PMT_XA_LIMIT		XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
#define GUID_SPR_PUNIT		0x9956f43f
@@ -29,7 +29,7 @@ bool intel_pmt_is_early_client_hw(struct device *dev)
	 * differences from the server platforms (which use the Out Of Band
	 * Management Services Module OOBMSM).
	*/
	return !!(ivdev->info->quirks & VSEC_QUIRK_EARLY_HW);
	return !!(ivdev->quirks & VSEC_QUIRK_EARLY_HW);
}
EXPORT_SYMBOL_NS_GPL(intel_pmt_is_early_client_hw, INTEL_PMT);

@@ -158,11 +158,12 @@ static struct class intel_pmt_class = {
};

static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
				    struct intel_pmt_header *header,
				    struct device *dev,
				    struct intel_vsec_device *ivdev,
				    struct resource *disc_res)
{
	struct pci_dev *pci_dev = to_pci_dev(dev->parent);
	struct pci_dev *pci_dev = ivdev->pcidev;
	struct device *dev = &ivdev->auxdev.dev;
	struct intel_pmt_header *header = &entry->header;
	u8 bir;

	/*
@@ -214,6 +215,13 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,

		break;
	case ACCESS_BARID:
		/* Use the provided base address if it exists */
		if (ivdev->base_addr) {
			entry->base_addr = ivdev->base_addr +
				   GET_ADDRESS(header->base_offset);
			break;
		}

		/*
		 * If another BAR was specified then the base offset
		 * represents the offset within that BAR. SO retrieve the
@@ -238,6 +246,7 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry,
				  struct intel_pmt_namespace *ns,
				  struct device *parent)
{
	struct intel_vsec_device *ivdev = dev_to_ivdev(parent);
	struct resource res = {0};
	struct device *dev;
	int ret;
@@ -261,7 +270,7 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry,
	if (ns->attr_grp) {
		ret = sysfs_create_group(entry->kobj, ns->attr_grp);
		if (ret)
			goto fail_sysfs;
			goto fail_sysfs_create_group;
	}

	/* if size is 0 assume no data buffer, so no file needed */
@@ -286,13 +295,23 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry,
	entry->pmt_bin_attr.size = entry->size;

	ret = sysfs_create_bin_file(&dev->kobj, &entry->pmt_bin_attr);
	if (!ret)
	if (ret)
		goto fail_ioremap;

	if (ns->pmt_add_endpoint) {
		ret = ns->pmt_add_endpoint(entry, ivdev->pcidev);
		if (ret)
			goto fail_add_endpoint;
	}

	return 0;

fail_add_endpoint:
	sysfs_remove_bin_file(entry->kobj, &entry->pmt_bin_attr);
fail_ioremap:
	if (ns->attr_grp)
		sysfs_remove_group(entry->kobj, ns->attr_grp);
fail_sysfs:
fail_sysfs_create_group:
	device_unregister(dev);
fail_dev_create:
	xa_erase(ns->xa, entry->devid);
@@ -304,7 +323,6 @@ int intel_pmt_dev_create(struct intel_pmt_entry *entry, struct intel_pmt_namespa
			 struct intel_vsec_device *intel_vsec_dev, int idx)
{
	struct device *dev = &intel_vsec_dev->auxdev.dev;
	struct intel_pmt_header header;
	struct resource	*disc_res;
	int ret;

@@ -314,16 +332,15 @@ int intel_pmt_dev_create(struct intel_pmt_entry *entry, struct intel_pmt_namespa
	if (IS_ERR(entry->disc_table))
		return PTR_ERR(entry->disc_table);

	ret = ns->pmt_header_decode(entry, &header, dev);
	ret = ns->pmt_header_decode(entry, dev);
	if (ret)
		return ret;

	ret = intel_pmt_populate_entry(entry, &header, dev, disc_res);
	ret = intel_pmt_populate_entry(entry, intel_vsec_dev, disc_res);
	if (ret)
		return ret;

	return intel_pmt_dev_register(entry, ns, dev);

}
EXPORT_SYMBOL_NS_GPL(intel_pmt_dev_create, INTEL_PMT);

+22 −8
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/io.h>

#include "intel_vsec.h"
#include "intel_pmt_telemetry.h"

/* PMT access types */
#define ACCESS_BARID		2
@@ -18,7 +19,26 @@
#define GET_BIR(v)		((v) & GENMASK(2, 0))
#define GET_ADDRESS(v)		((v) & GENMASK(31, 3))

struct pci_dev;

struct telem_endpoint {
	struct pci_dev		*pcidev;
	struct telem_header	header;
	void __iomem		*base;
	bool			present;
	struct kref		kref;
};

struct intel_pmt_header {
	u32	base_offset;
	u32	size;
	u32	guid;
	u8	access_type;
};

struct intel_pmt_entry {
	struct telem_endpoint	*ep;
	struct intel_pmt_header	header;
	struct bin_attribute	pmt_bin_attr;
	struct kobject		*kobj;
	void __iomem		*disc_table;
@@ -29,20 +49,14 @@ struct intel_pmt_entry {
	int			devid;
};

struct intel_pmt_header {
	u32	base_offset;
	u32	size;
	u32	guid;
	u8	access_type;
};

struct intel_pmt_namespace {
	const char *name;
	struct xarray *xa;
	const struct attribute_group *attr_grp;
	int (*pmt_header_decode)(struct intel_pmt_entry *entry,
				 struct intel_pmt_header *header,
				 struct device *dev);
	int (*pmt_add_endpoint)(struct intel_pmt_entry *entry,
				struct pci_dev *pdev);
};

bool intel_pmt_is_early_client_hw(struct device *dev);
+1 −1
Original line number Diff line number Diff line
@@ -223,10 +223,10 @@ static const struct attribute_group pmt_crashlog_group = {
};

static int pmt_crashlog_header_decode(struct intel_pmt_entry *entry,
				      struct intel_pmt_header *header,
				      struct device *dev)
{
	void __iomem *disc_table = entry->disc_table;
	struct intel_pmt_header *header = &entry->header;
	struct crashlog_entry *crashlog;

	if (!pmt_crashlog_supported(entry))
+189 −4
Original line number Diff line number Diff line
@@ -30,6 +30,15 @@
/* Used by client hardware to identify a fixed telemetry entry*/
#define TELEM_CLIENT_FIXED_BLOCK_GUID	0x10000000

#define NUM_BYTES_QWORD(v)	((v) << 3)
#define SAMPLE_ID_OFFSET(v)	((v) << 3)

#define NUM_BYTES_DWORD(v)	((v) << 2)
#define SAMPLE_ID_OFFSET32(v)	((v) << 2)

/* Protects access to the xarray of telemetry endpoint handles */
static DEFINE_MUTEX(ep_lock);

enum telem_type {
	TELEM_TYPE_PUNIT = 0,
	TELEM_TYPE_CRASHLOG,
@@ -58,10 +67,10 @@ static bool pmt_telem_region_overlaps(struct intel_pmt_entry *entry,
}

static int pmt_telem_header_decode(struct intel_pmt_entry *entry,
				   struct intel_pmt_header *header,
				   struct device *dev)
{
	void __iomem *disc_table = entry->disc_table;
	struct intel_pmt_header *header = &entry->header;

	if (pmt_telem_region_overlaps(entry, dev))
		return 1;
@@ -84,21 +93,195 @@ static int pmt_telem_header_decode(struct intel_pmt_entry *entry,
	return 0;
}

static int pmt_telem_add_endpoint(struct intel_pmt_entry *entry,
				  struct pci_dev *pdev)
{
	struct telem_endpoint *ep;

	/* Endpoint lifetimes are managed by kref, not devres */
	entry->ep = kzalloc(sizeof(*(entry->ep)), GFP_KERNEL);
	if (!entry->ep)
		return -ENOMEM;

	ep = entry->ep;
	ep->pcidev = pdev;
	ep->header.access_type = entry->header.access_type;
	ep->header.guid = entry->header.guid;
	ep->header.base_offset = entry->header.base_offset;
	ep->header.size = entry->header.size;
	ep->base = entry->base;
	ep->present = true;

	kref_init(&ep->kref);

	return 0;
}

static DEFINE_XARRAY_ALLOC(telem_array);
static struct intel_pmt_namespace pmt_telem_ns = {
	.name = "telem",
	.xa = &telem_array,
	.pmt_header_decode = pmt_telem_header_decode,
	.pmt_add_endpoint = pmt_telem_add_endpoint,
};

/* Called when all users unregister and the device is removed */
static void pmt_telem_ep_release(struct kref *kref)
{
	struct telem_endpoint *ep;

	ep = container_of(kref, struct telem_endpoint, kref);
	kfree(ep);
}

unsigned long pmt_telem_get_next_endpoint(unsigned long start)
{
	struct intel_pmt_entry *entry;
	unsigned long found_idx;

	mutex_lock(&ep_lock);
	xa_for_each_start(&telem_array, found_idx, entry, start) {
		/*
		 * Return first found index after start.
		 * 0 is not valid id.
		 */
		if (found_idx > start)
			break;
	}
	mutex_unlock(&ep_lock);

	return found_idx == start ? 0 : found_idx;
}
EXPORT_SYMBOL_NS_GPL(pmt_telem_get_next_endpoint, INTEL_PMT_TELEMETRY);

struct telem_endpoint *pmt_telem_register_endpoint(int devid)
{
	struct intel_pmt_entry *entry;
	unsigned long index = devid;

	mutex_lock(&ep_lock);
	entry = xa_find(&telem_array, &index, index, XA_PRESENT);
	if (!entry) {
		mutex_unlock(&ep_lock);
		return ERR_PTR(-ENXIO);
	}

	kref_get(&entry->ep->kref);
	mutex_unlock(&ep_lock);

	return entry->ep;
}
EXPORT_SYMBOL_NS_GPL(pmt_telem_register_endpoint, INTEL_PMT_TELEMETRY);

void pmt_telem_unregister_endpoint(struct telem_endpoint *ep)
{
	kref_put(&ep->kref, pmt_telem_ep_release);
}
EXPORT_SYMBOL_NS_GPL(pmt_telem_unregister_endpoint, INTEL_PMT_TELEMETRY);

int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info)
{
	struct intel_pmt_entry *entry;
	unsigned long index = devid;
	int err = 0;

	if (!info)
		return -EINVAL;

	mutex_lock(&ep_lock);
	entry = xa_find(&telem_array, &index, index, XA_PRESENT);
	if (!entry) {
		err = -ENXIO;
		goto unlock;
	}

	info->pdev = entry->ep->pcidev;
	info->header = entry->ep->header;

unlock:
	mutex_unlock(&ep_lock);
	return err;

}
EXPORT_SYMBOL_NS_GPL(pmt_telem_get_endpoint_info, INTEL_PMT_TELEMETRY);

int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count)
{
	u32 offset, size;

	if (!ep->present)
		return -ENODEV;

	offset = SAMPLE_ID_OFFSET(id);
	size = ep->header.size;

	if (offset + NUM_BYTES_QWORD(count) > size)
		return -EINVAL;

	memcpy_fromio(data, ep->base + offset, NUM_BYTES_QWORD(count));

	return ep->present ? 0 : -EPIPE;
}
EXPORT_SYMBOL_NS_GPL(pmt_telem_read, INTEL_PMT_TELEMETRY);

int pmt_telem_read32(struct telem_endpoint *ep, u32 id, u32 *data, u32 count)
{
	u32 offset, size;

	if (!ep->present)
		return -ENODEV;

	offset = SAMPLE_ID_OFFSET32(id);
	size = ep->header.size;

	if (offset + NUM_BYTES_DWORD(count) > size)
		return -EINVAL;

	memcpy_fromio(data, ep->base + offset, NUM_BYTES_DWORD(count));

	return ep->present ? 0 : -EPIPE;
}
EXPORT_SYMBOL_NS_GPL(pmt_telem_read32, INTEL_PMT_TELEMETRY);

struct telem_endpoint *
pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev, u32 guid, u16 pos)
{
	int devid = 0;
	int inst = 0;
	int err = 0;

	while ((devid = pmt_telem_get_next_endpoint(devid))) {
		struct telem_endpoint_info ep_info;

		err = pmt_telem_get_endpoint_info(devid, &ep_info);
		if (err)
			return ERR_PTR(err);

		if (ep_info.header.guid == guid && ep_info.pdev == pcidev) {
			if (inst == pos)
				return pmt_telem_register_endpoint(devid);
			++inst;
		}
	}

	return ERR_PTR(-ENXIO);
}
EXPORT_SYMBOL_NS_GPL(pmt_telem_find_and_register_endpoint, INTEL_PMT_TELEMETRY);

static void pmt_telem_remove(struct auxiliary_device *auxdev)
{
	struct pmt_telem_priv *priv = auxiliary_get_drvdata(auxdev);
	int i;

	for (i = 0; i < priv->num_entries; i++)
		intel_pmt_dev_destroy(&priv->entry[i], &pmt_telem_ns);
	mutex_lock(&ep_lock);
	for (i = 0; i < priv->num_entries; i++) {
		struct intel_pmt_entry *entry = &priv->entry[i];

		kref_put(&entry->ep->kref, pmt_telem_ep_release);
		intel_pmt_dev_destroy(entry, &pmt_telem_ns);
	}
	mutex_unlock(&ep_lock);
};

static int pmt_telem_probe(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id)
{
@@ -117,7 +300,9 @@ static int pmt_telem_probe(struct auxiliary_device *auxdev, const struct auxilia
	for (i = 0; i < intel_vsec_dev->num_resources; i++) {
		struct intel_pmt_entry *entry = &priv->entry[priv->num_entries];

		mutex_lock(&ep_lock);
		ret = intel_pmt_dev_create(entry, &pmt_telem_ns, intel_vsec_dev, i);
		mutex_unlock(&ep_lock);
		if (ret < 0)
			goto abort_probe;
		if (ret)
+126 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _TELEMETRY_H
#define _TELEMETRY_H

/* Telemetry types */
#define PMT_TELEM_TELEMETRY	0
#define PMT_TELEM_CRASHLOG	1

struct telem_endpoint;
struct pci_dev;

struct telem_header {
	u8	access_type;
	u16	size;
	u32	guid;
	u32	base_offset;
};

struct telem_endpoint_info {
	struct pci_dev		*pdev;
	struct telem_header	header;
};

/**
 * pmt_telem_get_next_endpoint() - Get next device id for a telemetry endpoint
 * @start:  starting devid to look from
 *
 * This functions can be used in a while loop predicate to retrieve the devid
 * of all available telemetry endpoints. Functions pmt_telem_get_next_endpoint()
 * and pmt_telem_register_endpoint() can be used inside of the loop to examine
 * endpoint info and register to receive a pointer to the endpoint. The pointer
 * is then usable in the telemetry read calls to access the telemetry data.
 *
 * Return:
 * * devid       - devid of the next present endpoint from start
 * * 0           - when no more endpoints are present after start
 */
unsigned long pmt_telem_get_next_endpoint(unsigned long start);

/**
 * pmt_telem_register_endpoint() - Register a telemetry endpoint
 * @devid: device id/handle of the telemetry endpoint
 *
 * Increments the kref usage counter for the endpoint.
 *
 * Return:
 * * endpoint    - On success returns pointer to the telemetry endpoint
 * * -ENXIO      - telemetry endpoint not found
 */
struct telem_endpoint *pmt_telem_register_endpoint(int devid);

/**
 * pmt_telem_unregister_endpoint() - Unregister a telemetry endpoint
 * @ep:   ep structure to populate.
 *
 * Decrements the kref usage counter for the endpoint.
 */
void pmt_telem_unregister_endpoint(struct telem_endpoint *ep);

/**
 * pmt_telem_get_endpoint_info() - Get info for an endpoint from its devid
 * @devid:  device id/handle of the telemetry endpoint
 * @info:   Endpoint info structure to be populated
 *
 * Return:
 * * 0           - Success
 * * -ENXIO      - telemetry endpoint not found for the devid
 * * -EINVAL     - @info is NULL
 */
int pmt_telem_get_endpoint_info(int devid, struct telem_endpoint_info *info);

/**
 * pmt_telem_find_and_register_endpoint() - Get a telemetry endpoint from
 * pci_dev device, guid and pos
 * @pdev:   PCI device inside the Intel vsec
 * @guid:   GUID of the telemetry space
 * @pos:    Instance of the guid
 *
 * Return:
 * * endpoint    - On success returns pointer to the telemetry endpoint
 * * -ENXIO      - telemetry endpoint not found
 */
struct telem_endpoint *pmt_telem_find_and_register_endpoint(struct pci_dev *pcidev,
				u32 guid, u16 pos);

/**
 * pmt_telem_read() - Read qwords from counter sram using sample id
 * @ep:     Telemetry endpoint to be read
 * @id:     The beginning sample id of the metric(s) to be read
 * @data:   Allocated qword buffer
 * @count:  Number of qwords requested
 *
 * Callers must ensure reads are aligned. When the call returns -ENODEV,
 * the device has been removed and callers should unregister the telemetry
 * endpoint.
 *
 * Return:
 * * 0           - Success
 * * -ENODEV     - The device is not present.
 * * -EINVAL     - The offset is out bounds
 * * -EPIPE      - The device was removed during the read. Data written
 *                 but should be considered invalid.
 */
int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count);

/**
 * pmt_telem_read32() - Read qwords from counter sram using sample id
 * @ep:     Telemetry endpoint to be read
 * @id:     The beginning sample id of the metric(s) to be read
 * @data:   Allocated dword buffer
 * @count:  Number of dwords requested
 *
 * Callers must ensure reads are aligned. When the call returns -ENODEV,
 * the device has been removed and callers should unregister the telemetry
 * endpoint.
 *
 * Return:
 * * 0           - Success
 * * -ENODEV     - The device is not present.
 * * -EINVAL     - The offset is out bounds
 * * -EPIPE      - The device was removed during the read. Data written
 *                 but should be considered invalid.
 */
int pmt_telem_read32(struct telem_endpoint *ep, u32 id, u32 *data, u32 count);

#endif
Loading