brintos

brintos / linux-shallow public Read only

0
0
Text · 7.3 KiB · 152bbd8 Raw
341 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// Copyright (c) 2021 Intel Corporation3 4#include <linux/auxiliary_bus.h>5#include <linux/module.h>6#include <linux/peci.h>7#include <linux/peci-cpu.h>8#include <linux/slab.h>9 10#include "internal.h"11 12/**13 * peci_temp_read() - read the maximum die temperature from PECI target device14 * @device: PECI device to which request is going to be sent15 * @temp_raw: where to store the read temperature16 *17 * It uses GetTemp PECI command.18 *19 * Return: 0 if succeeded, other values in case errors.20 */21int peci_temp_read(struct peci_device *device, s16 *temp_raw)22{23	struct peci_request *req;24 25	req = peci_xfer_get_temp(device);26	if (IS_ERR(req))27		return PTR_ERR(req);28 29	*temp_raw = peci_request_temp_read(req);30 31	peci_request_free(req);32 33	return 0;34}35EXPORT_SYMBOL_NS_GPL(peci_temp_read, PECI_CPU);36 37/**38 * peci_pcs_read() - read PCS register39 * @device: PECI device to which request is going to be sent40 * @index: PCS index41 * @param: PCS parameter42 * @data: where to store the read data43 *44 * It uses RdPkgConfig PECI command.45 *46 * Return: 0 if succeeded, other values in case errors.47 */48int peci_pcs_read(struct peci_device *device, u8 index, u16 param, u32 *data)49{50	struct peci_request *req;51	int ret;52 53	req = peci_xfer_pkg_cfg_readl(device, index, param);54	if (IS_ERR(req))55		return PTR_ERR(req);56 57	ret = peci_request_status(req);58	if (ret)59		goto out_req_free;60 61	*data = peci_request_data_readl(req);62out_req_free:63	peci_request_free(req);64 65	return ret;66}67EXPORT_SYMBOL_NS_GPL(peci_pcs_read, PECI_CPU);68 69/**70 * peci_pci_local_read() - read 32-bit memory location using raw address71 * @device: PECI device to which request is going to be sent72 * @bus: bus73 * @dev: device74 * @func: function75 * @reg: register76 * @data: where to store the read data77 *78 * It uses RdPCIConfigLocal PECI command.79 *80 * Return: 0 if succeeded, other values in case errors.81 */82int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev, u8 func,83			u16 reg, u32 *data)84{85	struct peci_request *req;86	int ret;87 88	req = peci_xfer_pci_cfg_local_readl(device, bus, dev, func, reg);89	if (IS_ERR(req))90		return PTR_ERR(req);91 92	ret = peci_request_status(req);93	if (ret)94		goto out_req_free;95 96	*data = peci_request_data_readl(req);97out_req_free:98	peci_request_free(req);99 100	return ret;101}102EXPORT_SYMBOL_NS_GPL(peci_pci_local_read, PECI_CPU);103 104/**105 * peci_ep_pci_local_read() - read 32-bit memory location using raw address106 * @device: PECI device to which request is going to be sent107 * @seg: PCI segment108 * @bus: bus109 * @dev: device110 * @func: function111 * @reg: register112 * @data: where to store the read data113 *114 * Like &peci_pci_local_read, but it uses RdEndpointConfig PECI command.115 *116 * Return: 0 if succeeded, other values in case errors.117 */118int peci_ep_pci_local_read(struct peci_device *device, u8 seg,119			   u8 bus, u8 dev, u8 func, u16 reg, u32 *data)120{121	struct peci_request *req;122	int ret;123 124	req = peci_xfer_ep_pci_cfg_local_readl(device, seg, bus, dev, func, reg);125	if (IS_ERR(req))126		return PTR_ERR(req);127 128	ret = peci_request_status(req);129	if (ret)130		goto out_req_free;131 132	*data = peci_request_data_readl(req);133out_req_free:134	peci_request_free(req);135 136	return ret;137}138EXPORT_SYMBOL_NS_GPL(peci_ep_pci_local_read, PECI_CPU);139 140/**141 * peci_mmio_read() - read 32-bit memory location using 64-bit bar offset address142 * @device: PECI device to which request is going to be sent143 * @bar: PCI bar144 * @seg: PCI segment145 * @bus: bus146 * @dev: device147 * @func: function148 * @address: 64-bit MMIO address149 * @data: where to store the read data150 *151 * It uses RdEndpointConfig PECI command.152 *153 * Return: 0 if succeeded, other values in case errors.154 */155int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg,156		   u8 bus, u8 dev, u8 func, u64 address, u32 *data)157{158	struct peci_request *req;159	int ret;160 161	req = peci_xfer_ep_mmio64_readl(device, bar, seg, bus, dev, func, address);162	if (IS_ERR(req))163		return PTR_ERR(req);164 165	ret = peci_request_status(req);166	if (ret)167		goto out_req_free;168 169	*data = peci_request_data_readl(req);170out_req_free:171	peci_request_free(req);172 173	return ret;174}175EXPORT_SYMBOL_NS_GPL(peci_mmio_read, PECI_CPU);176 177static const char * const peci_adev_types[] = {178	"cputemp",179	"dimmtemp",180};181 182struct peci_cpu {183	struct peci_device *device;184	const struct peci_device_id *id;185};186 187static void adev_release(struct device *dev)188{189	struct auxiliary_device *adev = to_auxiliary_dev(dev);190 191	kfree(adev->name);192	kfree(adev);193}194 195static struct auxiliary_device *adev_alloc(struct peci_cpu *priv, int idx)196{197	struct peci_controller *controller = to_peci_controller(priv->device->dev.parent);198	struct auxiliary_device *adev;199	const char *name;200	int ret;201 202	adev = kzalloc(sizeof(*adev), GFP_KERNEL);203	if (!adev)204		return ERR_PTR(-ENOMEM);205 206	name = kasprintf(GFP_KERNEL, "%s.%s", peci_adev_types[idx], (const char *)priv->id->data);207	if (!name) {208		ret = -ENOMEM;209		goto free_adev;210	}211 212	adev->name = name;213	adev->dev.parent = &priv->device->dev;214	adev->dev.release = adev_release;215	adev->id = (controller->id << 16) | (priv->device->addr);216 217	ret = auxiliary_device_init(adev);218	if (ret)219		goto free_name;220 221	return adev;222 223free_name:224	kfree(name);225free_adev:226	kfree(adev);227	return ERR_PTR(ret);228}229 230static void unregister_adev(void *_adev)231{232	struct auxiliary_device *adev = _adev;233 234	auxiliary_device_delete(adev);235	auxiliary_device_uninit(adev);236}237 238static int devm_adev_add(struct device *dev, int idx)239{240	struct peci_cpu *priv = dev_get_drvdata(dev);241	struct auxiliary_device *adev;242	int ret;243 244	adev = adev_alloc(priv, idx);245	if (IS_ERR(adev))246		return PTR_ERR(adev);247 248	ret = auxiliary_device_add(adev);249	if (ret) {250		auxiliary_device_uninit(adev);251		return ret;252	}253 254	ret = devm_add_action_or_reset(&priv->device->dev, unregister_adev, adev);255	if (ret)256		return ret;257 258	return 0;259}260 261static void peci_cpu_add_adevices(struct peci_cpu *priv)262{263	struct device *dev = &priv->device->dev;264	int ret, i;265 266	for (i = 0; i < ARRAY_SIZE(peci_adev_types); i++) {267		ret = devm_adev_add(dev, i);268		if (ret) {269			dev_warn(dev, "Failed to register PECI auxiliary: %s, ret = %d\n",270				 peci_adev_types[i], ret);271			continue;272		}273	}274}275 276static int277peci_cpu_probe(struct peci_device *device, const struct peci_device_id *id)278{279	struct device *dev = &device->dev;280	struct peci_cpu *priv;281 282	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);283	if (!priv)284		return -ENOMEM;285 286	dev_set_drvdata(dev, priv);287	priv->device = device;288	priv->id = id;289 290	peci_cpu_add_adevices(priv);291 292	return 0;293}294 295static const struct peci_device_id peci_cpu_device_ids[] = {296	{ /* Haswell Xeon */297		.x86_vfm = INTEL_HASWELL_X,298		.data	= "hsx",299	},300	{ /* Broadwell Xeon */301		.x86_vfm = INTEL_BROADWELL_X,302		.data	= "bdx",303	},304	{ /* Broadwell Xeon D */305		.x86_vfm = INTEL_BROADWELL_D,306		.data	= "bdxd",307	},308	{ /* Skylake Xeon */309		.x86_vfm = INTEL_SKYLAKE_X,310		.data	= "skx",311	},312	{ /* Icelake Xeon */313		.x86_vfm = INTEL_ICELAKE_X,314		.data	= "icx",315	},316	{ /* Icelake Xeon D */317		.x86_vfm = INTEL_ICELAKE_D,318		.data	= "icxd",319	},320	{ /* Sapphire Rapids Xeon */321		.x86_vfm = INTEL_SAPPHIRERAPIDS_X,322		.data	= "spr",323	},324	{ }325};326MODULE_DEVICE_TABLE(peci, peci_cpu_device_ids);327 328static struct peci_driver peci_cpu_driver = {329	.probe		= peci_cpu_probe,330	.id_table	= peci_cpu_device_ids,331	.driver		= {332		.name		= "peci-cpu",333	},334};335module_peci_driver(peci_cpu_driver);336 337MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");338MODULE_DESCRIPTION("PECI CPU driver");339MODULE_LICENSE("GPL");340MODULE_IMPORT_NS(PECI);341