brintos

brintos / linux-shallow public Read only

0
0
Text · 5.2 KiB · f52fe23 Raw
211 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2022-2023 Intel Corporation4 */5 6/**7 * DOC: MEI_GSC_PROXY Client Driver8 *9 * The mei_gsc_proxy driver acts as a translation layer between10 * proxy user (I915) and ME FW by proxying messages to ME FW11 */12 13#include <linux/component.h>14#include <linux/mei_cl_bus.h>15#include <linux/module.h>16#include <linux/pci.h>17#include <linux/slab.h>18#include <linux/uuid.h>19#include <drm/drm_connector.h>20#include <drm/intel/i915_component.h>21#include <drm/intel/i915_gsc_proxy_mei_interface.h>22 23/**24 * mei_gsc_proxy_send - Sends a proxy message to ME FW.25 * @dev: device corresponding to the mei_cl_device26 * @buf: a message buffer to send27 * @size: size of the message28 * Return: bytes sent on Success, <0 on Failure29 */30static int mei_gsc_proxy_send(struct device *dev, const void *buf, size_t size)31{32	ssize_t ret;33 34	if (!dev || !buf)35		return -EINVAL;36 37	ret = mei_cldev_send(to_mei_cl_device(dev), buf, size);38	if (ret < 0)39		dev_dbg(dev, "mei_cldev_send failed. %zd\n", ret);40 41	return ret;42}43 44/**45 * mei_gsc_proxy_recv - Receives a proxy message from ME FW.46 * @dev: device corresponding to the mei_cl_device47 * @buf: a message buffer to contain the received message48 * @size: size of the buffer49 * Return: bytes received on Success, <0 on Failure50 */51static int mei_gsc_proxy_recv(struct device *dev, void *buf, size_t size)52{53	ssize_t ret;54 55	if (!dev || !buf)56		return -EINVAL;57 58	ret = mei_cldev_recv(to_mei_cl_device(dev), buf, size);59	if (ret < 0)60		dev_dbg(dev, "mei_cldev_recv failed. %zd\n", ret);61 62	return ret;63}64 65static const struct i915_gsc_proxy_component_ops mei_gsc_proxy_ops = {66	.owner = THIS_MODULE,67	.send = mei_gsc_proxy_send,68	.recv = mei_gsc_proxy_recv,69};70 71static int mei_component_master_bind(struct device *dev)72{73	struct mei_cl_device *cldev = to_mei_cl_device(dev);74	struct i915_gsc_proxy_component *comp_master = mei_cldev_get_drvdata(cldev);75 76	comp_master->ops = &mei_gsc_proxy_ops;77	comp_master->mei_dev = dev;78	return component_bind_all(dev, comp_master);79}80 81static void mei_component_master_unbind(struct device *dev)82{83	struct mei_cl_device *cldev = to_mei_cl_device(dev);84	struct i915_gsc_proxy_component *comp_master = mei_cldev_get_drvdata(cldev);85 86	component_unbind_all(dev, comp_master);87}88 89static const struct component_master_ops mei_component_master_ops = {90	.bind = mei_component_master_bind,91	.unbind = mei_component_master_unbind,92};93 94/**95 * mei_gsc_proxy_component_match - compare function for matching mei.96 *97 *    The function checks if the device is pci device and98 *    Intel VGA adapter, the subcomponent is SW Proxy99 *    and the VGA is on the bus 0 reserved for built-in devices100 *    to reject discrete GFX.101 *102 * @dev: master device103 * @subcomponent: subcomponent to match (I915_COMPONENT_SWPROXY)104 * @data: compare data (mei pci parent)105 *106 * Return:107 * * 1 - if components match108 * * 0 - otherwise109 */110static int mei_gsc_proxy_component_match(struct device *dev, int subcomponent,111					 void *data)112{113	struct pci_dev *pdev;114 115	if (!dev_is_pci(dev))116		return 0;117 118	pdev = to_pci_dev(dev);119 120	if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8) ||121	    pdev->vendor != PCI_VENDOR_ID_INTEL)122		return 0;123 124	if (subcomponent != I915_COMPONENT_GSC_PROXY)125		return 0;126 127	/* Only built-in GFX */128	return (pdev->bus->number == 0);129}130 131static int mei_gsc_proxy_probe(struct mei_cl_device *cldev,132			       const struct mei_cl_device_id *id)133{134	struct i915_gsc_proxy_component *comp_master;135	struct component_match *master_match = NULL;136	int ret;137 138	ret = mei_cldev_enable(cldev);139	if (ret < 0) {140		dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret);141		goto enable_err_exit;142	}143 144	comp_master = kzalloc(sizeof(*comp_master), GFP_KERNEL);145	if (!comp_master) {146		ret = -ENOMEM;147		goto err_exit;148	}149 150	component_match_add_typed(&cldev->dev, &master_match,151				  mei_gsc_proxy_component_match, NULL);152	if (IS_ERR_OR_NULL(master_match)) {153		ret = -ENOMEM;154		goto err_exit;155	}156 157	mei_cldev_set_drvdata(cldev, comp_master);158	ret = component_master_add_with_match(&cldev->dev,159					      &mei_component_master_ops,160					      master_match);161	if (ret < 0) {162		dev_err(&cldev->dev, "Master comp add failed %d\n", ret);163		goto err_exit;164	}165 166	return 0;167 168err_exit:169	mei_cldev_set_drvdata(cldev, NULL);170	kfree(comp_master);171	mei_cldev_disable(cldev);172enable_err_exit:173	return ret;174}175 176static void mei_gsc_proxy_remove(struct mei_cl_device *cldev)177{178	struct i915_gsc_proxy_component *comp_master = mei_cldev_get_drvdata(cldev);179	int ret;180 181	component_master_del(&cldev->dev, &mei_component_master_ops);182	kfree(comp_master);183	mei_cldev_set_drvdata(cldev, NULL);184 185	ret = mei_cldev_disable(cldev);186	if (ret)187		dev_warn(&cldev->dev, "mei_cldev_disable() failed %d\n", ret);188}189 190#define MEI_UUID_GSC_PROXY UUID_LE(0xf73db04, 0x97ab, 0x4125, \191				   0xb8, 0x93, 0xe9, 0x4, 0xad, 0xd, 0x54, 0x64)192 193static struct mei_cl_device_id mei_gsc_proxy_tbl[] = {194	{ .uuid = MEI_UUID_GSC_PROXY, .version = MEI_CL_VERSION_ANY },195	{ }196};197MODULE_DEVICE_TABLE(mei, mei_gsc_proxy_tbl);198 199static struct mei_cl_driver mei_gsc_proxy_driver = {200	.id_table = mei_gsc_proxy_tbl,201	.name = KBUILD_MODNAME,202	.probe = mei_gsc_proxy_probe,203	.remove	= mei_gsc_proxy_remove,204};205 206module_mei_cl_driver(mei_gsc_proxy_driver);207 208MODULE_AUTHOR("Intel Corporation");209MODULE_LICENSE("GPL");210MODULE_DESCRIPTION("MEI GSC PROXY");211