Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 // Copyright (c) 2021 Intel Corporation
0003 
0004 #include <linux/auxiliary_bus.h>
0005 #include <linux/module.h>
0006 #include <linux/peci.h>
0007 #include <linux/peci-cpu.h>
0008 #include <linux/slab.h>
0009 
0010 #include "internal.h"
0011 
0012 /**
0013  * peci_temp_read() - read the maximum die temperature from PECI target device
0014  * @device: PECI device to which request is going to be sent
0015  * @temp_raw: where to store the read temperature
0016  *
0017  * It uses GetTemp PECI command.
0018  *
0019  * Return: 0 if succeeded, other values in case errors.
0020  */
0021 int peci_temp_read(struct peci_device *device, s16 *temp_raw)
0022 {
0023     struct peci_request *req;
0024 
0025     req = peci_xfer_get_temp(device);
0026     if (IS_ERR(req))
0027         return PTR_ERR(req);
0028 
0029     *temp_raw = peci_request_temp_read(req);
0030 
0031     peci_request_free(req);
0032 
0033     return 0;
0034 }
0035 EXPORT_SYMBOL_NS_GPL(peci_temp_read, PECI_CPU);
0036 
0037 /**
0038  * peci_pcs_read() - read PCS register
0039  * @device: PECI device to which request is going to be sent
0040  * @index: PCS index
0041  * @param: PCS parameter
0042  * @data: where to store the read data
0043  *
0044  * It uses RdPkgConfig PECI command.
0045  *
0046  * Return: 0 if succeeded, other values in case errors.
0047  */
0048 int peci_pcs_read(struct peci_device *device, u8 index, u16 param, u32 *data)
0049 {
0050     struct peci_request *req;
0051     int ret;
0052 
0053     req = peci_xfer_pkg_cfg_readl(device, index, param);
0054     if (IS_ERR(req))
0055         return PTR_ERR(req);
0056 
0057     ret = peci_request_status(req);
0058     if (ret)
0059         goto out_req_free;
0060 
0061     *data = peci_request_data_readl(req);
0062 out_req_free:
0063     peci_request_free(req);
0064 
0065     return ret;
0066 }
0067 EXPORT_SYMBOL_NS_GPL(peci_pcs_read, PECI_CPU);
0068 
0069 /**
0070  * peci_pci_local_read() - read 32-bit memory location using raw address
0071  * @device: PECI device to which request is going to be sent
0072  * @bus: bus
0073  * @dev: device
0074  * @func: function
0075  * @reg: register
0076  * @data: where to store the read data
0077  *
0078  * It uses RdPCIConfigLocal PECI command.
0079  *
0080  * Return: 0 if succeeded, other values in case errors.
0081  */
0082 int peci_pci_local_read(struct peci_device *device, u8 bus, u8 dev, u8 func,
0083             u16 reg, u32 *data)
0084 {
0085     struct peci_request *req;
0086     int ret;
0087 
0088     req = peci_xfer_pci_cfg_local_readl(device, bus, dev, func, reg);
0089     if (IS_ERR(req))
0090         return PTR_ERR(req);
0091 
0092     ret = peci_request_status(req);
0093     if (ret)
0094         goto out_req_free;
0095 
0096     *data = peci_request_data_readl(req);
0097 out_req_free:
0098     peci_request_free(req);
0099 
0100     return ret;
0101 }
0102 EXPORT_SYMBOL_NS_GPL(peci_pci_local_read, PECI_CPU);
0103 
0104 /**
0105  * peci_ep_pci_local_read() - read 32-bit memory location using raw address
0106  * @device: PECI device to which request is going to be sent
0107  * @seg: PCI segment
0108  * @bus: bus
0109  * @dev: device
0110  * @func: function
0111  * @reg: register
0112  * @data: where to store the read data
0113  *
0114  * Like &peci_pci_local_read, but it uses RdEndpointConfig PECI command.
0115  *
0116  * Return: 0 if succeeded, other values in case errors.
0117  */
0118 int peci_ep_pci_local_read(struct peci_device *device, u8 seg,
0119                u8 bus, u8 dev, u8 func, u16 reg, u32 *data)
0120 {
0121     struct peci_request *req;
0122     int ret;
0123 
0124     req = peci_xfer_ep_pci_cfg_local_readl(device, seg, bus, dev, func, reg);
0125     if (IS_ERR(req))
0126         return PTR_ERR(req);
0127 
0128     ret = peci_request_status(req);
0129     if (ret)
0130         goto out_req_free;
0131 
0132     *data = peci_request_data_readl(req);
0133 out_req_free:
0134     peci_request_free(req);
0135 
0136     return ret;
0137 }
0138 EXPORT_SYMBOL_NS_GPL(peci_ep_pci_local_read, PECI_CPU);
0139 
0140 /**
0141  * peci_mmio_read() - read 32-bit memory location using 64-bit bar offset address
0142  * @device: PECI device to which request is going to be sent
0143  * @bar: PCI bar
0144  * @seg: PCI segment
0145  * @bus: bus
0146  * @dev: device
0147  * @func: function
0148  * @address: 64-bit MMIO address
0149  * @data: where to store the read data
0150  *
0151  * It uses RdEndpointConfig PECI command.
0152  *
0153  * Return: 0 if succeeded, other values in case errors.
0154  */
0155 int peci_mmio_read(struct peci_device *device, u8 bar, u8 seg,
0156            u8 bus, u8 dev, u8 func, u64 address, u32 *data)
0157 {
0158     struct peci_request *req;
0159     int ret;
0160 
0161     req = peci_xfer_ep_mmio64_readl(device, bar, seg, bus, dev, func, address);
0162     if (IS_ERR(req))
0163         return PTR_ERR(req);
0164 
0165     ret = peci_request_status(req);
0166     if (ret)
0167         goto out_req_free;
0168 
0169     *data = peci_request_data_readl(req);
0170 out_req_free:
0171     peci_request_free(req);
0172 
0173     return ret;
0174 }
0175 EXPORT_SYMBOL_NS_GPL(peci_mmio_read, PECI_CPU);
0176 
0177 static const char * const peci_adev_types[] = {
0178     "cputemp",
0179     "dimmtemp",
0180 };
0181 
0182 struct peci_cpu {
0183     struct peci_device *device;
0184     const struct peci_device_id *id;
0185 };
0186 
0187 static void adev_release(struct device *dev)
0188 {
0189     struct auxiliary_device *adev = to_auxiliary_dev(dev);
0190 
0191     kfree(adev->name);
0192     kfree(adev);
0193 }
0194 
0195 static struct auxiliary_device *adev_alloc(struct peci_cpu *priv, int idx)
0196 {
0197     struct peci_controller *controller = to_peci_controller(priv->device->dev.parent);
0198     struct auxiliary_device *adev;
0199     const char *name;
0200     int ret;
0201 
0202     adev = kzalloc(sizeof(*adev), GFP_KERNEL);
0203     if (!adev)
0204         return ERR_PTR(-ENOMEM);
0205 
0206     name = kasprintf(GFP_KERNEL, "%s.%s", peci_adev_types[idx], (const char *)priv->id->data);
0207     if (!name) {
0208         ret = -ENOMEM;
0209         goto free_adev;
0210     }
0211 
0212     adev->name = name;
0213     adev->dev.parent = &priv->device->dev;
0214     adev->dev.release = adev_release;
0215     adev->id = (controller->id << 16) | (priv->device->addr);
0216 
0217     ret = auxiliary_device_init(adev);
0218     if (ret)
0219         goto free_name;
0220 
0221     return adev;
0222 
0223 free_name:
0224     kfree(name);
0225 free_adev:
0226     kfree(adev);
0227     return ERR_PTR(ret);
0228 }
0229 
0230 static void unregister_adev(void *_adev)
0231 {
0232     struct auxiliary_device *adev = _adev;
0233 
0234     auxiliary_device_delete(adev);
0235     auxiliary_device_uninit(adev);
0236 }
0237 
0238 static int devm_adev_add(struct device *dev, int idx)
0239 {
0240     struct peci_cpu *priv = dev_get_drvdata(dev);
0241     struct auxiliary_device *adev;
0242     int ret;
0243 
0244     adev = adev_alloc(priv, idx);
0245     if (IS_ERR(adev))
0246         return PTR_ERR(adev);
0247 
0248     ret = auxiliary_device_add(adev);
0249     if (ret) {
0250         auxiliary_device_uninit(adev);
0251         return ret;
0252     }
0253 
0254     ret = devm_add_action_or_reset(&priv->device->dev, unregister_adev, adev);
0255     if (ret)
0256         return ret;
0257 
0258     return 0;
0259 }
0260 
0261 static void peci_cpu_add_adevices(struct peci_cpu *priv)
0262 {
0263     struct device *dev = &priv->device->dev;
0264     int ret, i;
0265 
0266     for (i = 0; i < ARRAY_SIZE(peci_adev_types); i++) {
0267         ret = devm_adev_add(dev, i);
0268         if (ret) {
0269             dev_warn(dev, "Failed to register PECI auxiliary: %s, ret = %d\n",
0270                  peci_adev_types[i], ret);
0271             continue;
0272         }
0273     }
0274 }
0275 
0276 static int
0277 peci_cpu_probe(struct peci_device *device, const struct peci_device_id *id)
0278 {
0279     struct device *dev = &device->dev;
0280     struct peci_cpu *priv;
0281 
0282     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0283     if (!priv)
0284         return -ENOMEM;
0285 
0286     dev_set_drvdata(dev, priv);
0287     priv->device = device;
0288     priv->id = id;
0289 
0290     peci_cpu_add_adevices(priv);
0291 
0292     return 0;
0293 }
0294 
0295 static const struct peci_device_id peci_cpu_device_ids[] = {
0296     { /* Haswell Xeon */
0297         .family = 6,
0298         .model  = INTEL_FAM6_HASWELL_X,
0299         .data   = "hsx",
0300     },
0301     { /* Broadwell Xeon */
0302         .family = 6,
0303         .model  = INTEL_FAM6_BROADWELL_X,
0304         .data   = "bdx",
0305     },
0306     { /* Broadwell Xeon D */
0307         .family = 6,
0308         .model  = INTEL_FAM6_BROADWELL_D,
0309         .data   = "bdxd",
0310     },
0311     { /* Skylake Xeon */
0312         .family = 6,
0313         .model  = INTEL_FAM6_SKYLAKE_X,
0314         .data   = "skx",
0315     },
0316     { /* Icelake Xeon */
0317         .family = 6,
0318         .model  = INTEL_FAM6_ICELAKE_X,
0319         .data   = "icx",
0320     },
0321     { /* Icelake Xeon D */
0322         .family = 6,
0323         .model  = INTEL_FAM6_ICELAKE_D,
0324         .data   = "icxd",
0325     },
0326     { }
0327 };
0328 MODULE_DEVICE_TABLE(peci, peci_cpu_device_ids);
0329 
0330 static struct peci_driver peci_cpu_driver = {
0331     .probe      = peci_cpu_probe,
0332     .id_table   = peci_cpu_device_ids,
0333     .driver     = {
0334         .name       = "peci-cpu",
0335     },
0336 };
0337 module_peci_driver(peci_cpu_driver);
0338 
0339 MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
0340 MODULE_DESCRIPTION("PECI CPU driver");
0341 MODULE_LICENSE("GPL");
0342 MODULE_IMPORT_NS(PECI);