// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( c ) 2022 - 2023 Intel Corporation
*/
/**
* DOC : MEI_GSC_PROXY Client Driver
*
* The mei_gsc_proxy driver acts as a translation layer between
* proxy user ( I915 ) and ME FW by proxying messages to ME FW
*/
#include <linux/component.h>
#include <linux/mei_cl_bus.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/uuid.h>
#include <drm/drm_connector.h>
#include <drm/intel/i915_component.h>
#include <drm/intel/i915_gsc_proxy_mei_interface.h>
/**
* mei_gsc_proxy_send - Sends a proxy message to ME FW .
* @ dev : device corresponding to the mei_cl_device
* @ buf : a message buffer to send
* @ size : size of the message
* Return : bytes sent on Success , < 0 on Failure
*/
static int mei_gsc_proxy_send(struct device *dev, const void *buf, size_t size)
{
ssize_t ret;
if (!dev || !buf)
return -EINVAL;
ret = mei_cldev_send(to_mei_cl_device(dev), buf, size);
if (ret < 0 )
dev_dbg(dev, "mei_cldev_send failed. %zd\n" , ret);
return ret;
}
/**
* mei_gsc_proxy_recv - Receives a proxy message from ME FW .
* @ dev : device corresponding to the mei_cl_device
* @ buf : a message buffer to contain the received message
* @ size : size of the buffer
* Return : bytes received on Success , < 0 on Failure
*/
static int mei_gsc_proxy_recv(struct device *dev, void *buf, size_t size)
{
ssize_t ret;
if (!dev || !buf)
return -EINVAL;
ret = mei_cldev_recv(to_mei_cl_device(dev), buf, size);
if (ret < 0 )
dev_dbg(dev, "mei_cldev_recv failed. %zd\n" , ret);
return ret;
}
static const struct i915_gsc_proxy_component_ops mei_gsc_proxy_ops = {
.owner = THIS_MODULE,
.send = mei_gsc_proxy_send,
.recv = mei_gsc_proxy_recv,
};
static int mei_component_master_bind(struct device *dev)
{
struct mei_cl_device *cldev = to_mei_cl_device(dev);
struct i915_gsc_proxy_component *comp_master = mei_cldev_get_drvdata(cldev);
comp_master->ops = &mei_gsc_proxy_ops;
comp_master->mei_dev = dev;
return component_bind_all(dev, comp_master);
}
static void mei_component_master_unbind(struct device *dev)
{
struct mei_cl_device *cldev = to_mei_cl_device(dev);
struct i915_gsc_proxy_component *comp_master = mei_cldev_get_drvdata(cldev);
component_unbind_all(dev, comp_master);
}
static const struct component_master_ops mei_component_master_ops = {
.bind = mei_component_master_bind,
.unbind = mei_component_master_unbind,
};
/**
* mei_gsc_proxy_component_match - compare function for matching mei .
*
* The function checks if the device is pci device and
* Intel VGA adapter , the subcomponent is SW Proxy
* and the VGA is on the bus 0 reserved for built - in devices
* to reject discrete GFX .
*
* @ dev : master device
* @ subcomponent : subcomponent to match ( I915_COMPONENT_SWPROXY )
* @ data : compare data ( mei pci parent )
*
* Return :
* * 1 - if components match
* * 0 - otherwise
*/
static int mei_gsc_proxy_component_match(struct device *dev, int subcomponent,
void *data)
{
struct pci_dev *pdev;
if (!dev_is_pci(dev))
return 0 ;
pdev = to_pci_dev(dev);
if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8 ) ||
pdev->vendor != PCI_VENDOR_ID_INTEL)
return 0 ;
if (subcomponent != I915_COMPONENT_GSC_PROXY)
return 0 ;
/* Only built-in GFX */
return (pdev->bus->number == 0 );
}
static int mei_gsc_proxy_probe(struct mei_cl_device *cldev,
const struct mei_cl_device_id *id)
{
struct i915_gsc_proxy_component *comp_master;
struct component_match *master_match = NULL;
int ret;
ret = mei_cldev_enable(cldev);
if (ret < 0 ) {
dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n" , ret);
goto enable_err_exit;
}
comp_master = kzalloc(sizeof (*comp_master), GFP_KERNEL);
if (!comp_master) {
ret = -ENOMEM;
goto err_exit;
}
component_match_add_typed(&cldev->dev, &master_match,
mei_gsc_proxy_component_match, NULL);
if (IS_ERR_OR_NULL(master_match)) {
ret = -ENOMEM;
goto err_exit;
}
mei_cldev_set_drvdata(cldev, comp_master);
ret = component_master_add_with_match(&cldev->dev,
&mei_component_master_ops,
master_match);
if (ret < 0 ) {
dev_err(&cldev->dev, "Master comp add failed %d\n" , ret);
goto err_exit;
}
return 0 ;
err_exit:
mei_cldev_set_drvdata(cldev, NULL);
kfree(comp_master);
mei_cldev_disable(cldev);
enable_err_exit:
return ret;
}
static void mei_gsc_proxy_remove(struct mei_cl_device *cldev)
{
struct i915_gsc_proxy_component *comp_master = mei_cldev_get_drvdata(cldev);
int ret;
component_master_del(&cldev->dev, &mei_component_master_ops);
kfree(comp_master);
mei_cldev_set_drvdata(cldev, NULL);
ret = mei_cldev_disable(cldev);
if (ret)
dev_warn(&cldev->dev, "mei_cldev_disable() failed %d\n" , ret);
}
#define MEI_UUID_GSC_PROXY UUID_LE(0 xf73db04, 0 x97ab, 0 x4125, \
0 xb8, 0 x93, 0 xe9, 0 x4, 0 xad, 0 xd, 0 x54, 0 x64)
static struct mei_cl_device_id mei_gsc_proxy_tbl[] = {
{ .uuid = MEI_UUID_GSC_PROXY, .version = MEI_CL_VERSION_ANY },
{ }
};
MODULE_DEVICE_TABLE(mei, mei_gsc_proxy_tbl);
static struct mei_cl_driver mei_gsc_proxy_driver = {
.id_table = mei_gsc_proxy_tbl,
.name = KBUILD_MODNAME,
.probe = mei_gsc_proxy_probe,
.remove = mei_gsc_proxy_remove,
};
module_mei_cl_driver(mei_gsc_proxy_driver);
MODULE_AUTHOR("Intel Corporation" );
MODULE_LICENSE("GPL" );
MODULE_DESCRIPTION("MEI GSC PROXY" );
Messung V0.5 in Prozent C=92 H=100 G=95
¤ Dauer der Verarbeitung: 0.3 Sekunden
¤
*© Formatika GbR, Deutschland