Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright(c) 2019-2022, Intel Corporation. All rights reserved.
0004  *
0005  * Intel Management Engine Interface (Intel MEI) Linux driver
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/mei_aux.h>
0010 #include <linux/device.h>
0011 #include <linux/irqreturn.h>
0012 #include <linux/jiffies.h>
0013 #include <linux/ktime.h>
0014 #include <linux/delay.h>
0015 #include <linux/pm_runtime.h>
0016 
0017 #include "mei_dev.h"
0018 #include "hw-me.h"
0019 #include "hw-me-regs.h"
0020 
0021 #include "mei-trace.h"
0022 
0023 #define MEI_GSC_RPM_TIMEOUT 500
0024 
0025 static int mei_gsc_read_hfs(const struct mei_device *dev, int where, u32 *val)
0026 {
0027     struct mei_me_hw *hw = to_me_hw(dev);
0028 
0029     *val = ioread32(hw->mem_addr + where + 0xC00);
0030 
0031     return 0;
0032 }
0033 
0034 static int mei_gsc_probe(struct auxiliary_device *aux_dev,
0035              const struct auxiliary_device_id *aux_dev_id)
0036 {
0037     struct mei_aux_device *adev = auxiliary_dev_to_mei_aux_dev(aux_dev);
0038     struct mei_device *dev;
0039     struct mei_me_hw *hw;
0040     struct device *device;
0041     const struct mei_cfg *cfg;
0042     int ret;
0043 
0044     cfg = mei_me_get_cfg(aux_dev_id->driver_data);
0045     if (!cfg)
0046         return -ENODEV;
0047 
0048     device = &aux_dev->dev;
0049 
0050     dev = mei_me_dev_init(device, cfg);
0051     if (!dev) {
0052         ret = -ENOMEM;
0053         goto err;
0054     }
0055 
0056     hw = to_me_hw(dev);
0057     hw->mem_addr = devm_ioremap_resource(device, &adev->bar);
0058     if (IS_ERR(hw->mem_addr)) {
0059         dev_err(device, "mmio not mapped\n");
0060         ret = PTR_ERR(hw->mem_addr);
0061         goto err;
0062     }
0063 
0064     hw->irq = adev->irq;
0065     hw->read_fws = mei_gsc_read_hfs;
0066 
0067     dev_set_drvdata(device, dev);
0068 
0069     ret = devm_request_threaded_irq(device, hw->irq,
0070                     mei_me_irq_quick_handler,
0071                     mei_me_irq_thread_handler,
0072                     IRQF_ONESHOT, KBUILD_MODNAME, dev);
0073     if (ret) {
0074         dev_err(device, "irq register failed %d\n", ret);
0075         goto err;
0076     }
0077 
0078     pm_runtime_get_noresume(device);
0079     pm_runtime_set_active(device);
0080     pm_runtime_enable(device);
0081 
0082     /* Continue to char device setup in spite of firmware handshake failure.
0083      * In order to provide access to the firmware status registers to the user
0084      * space via sysfs.
0085      */
0086     if (mei_start(dev))
0087         dev_warn(device, "init hw failure.\n");
0088 
0089     pm_runtime_set_autosuspend_delay(device, MEI_GSC_RPM_TIMEOUT);
0090     pm_runtime_use_autosuspend(device);
0091 
0092     ret = mei_register(dev, device);
0093     if (ret)
0094         goto register_err;
0095 
0096     pm_runtime_put_noidle(device);
0097     return 0;
0098 
0099 register_err:
0100     mei_stop(dev);
0101     devm_free_irq(device, hw->irq, dev);
0102 
0103 err:
0104     dev_err(device, "probe failed: %d\n", ret);
0105     dev_set_drvdata(device, NULL);
0106     return ret;
0107 }
0108 
0109 static void mei_gsc_remove(struct auxiliary_device *aux_dev)
0110 {
0111     struct mei_device *dev;
0112     struct mei_me_hw *hw;
0113 
0114     dev = dev_get_drvdata(&aux_dev->dev);
0115     if (!dev)
0116         return;
0117 
0118     hw = to_me_hw(dev);
0119 
0120     mei_stop(dev);
0121 
0122     mei_deregister(dev);
0123 
0124     pm_runtime_disable(&aux_dev->dev);
0125 
0126     mei_disable_interrupts(dev);
0127     devm_free_irq(&aux_dev->dev, hw->irq, dev);
0128 }
0129 
0130 static int __maybe_unused mei_gsc_pm_suspend(struct device *device)
0131 {
0132     struct mei_device *dev = dev_get_drvdata(device);
0133 
0134     if (!dev)
0135         return -ENODEV;
0136 
0137     mei_stop(dev);
0138 
0139     mei_disable_interrupts(dev);
0140 
0141     return 0;
0142 }
0143 
0144 static int __maybe_unused mei_gsc_pm_resume(struct device *device)
0145 {
0146     struct mei_device *dev = dev_get_drvdata(device);
0147     int err;
0148 
0149     if (!dev)
0150         return -ENODEV;
0151 
0152     err = mei_restart(dev);
0153     if (err)
0154         return err;
0155 
0156     /* Start timer if stopped in suspend */
0157     schedule_delayed_work(&dev->timer_work, HZ);
0158 
0159     return 0;
0160 }
0161 
0162 static int __maybe_unused mei_gsc_pm_runtime_idle(struct device *device)
0163 {
0164     struct mei_device *dev = dev_get_drvdata(device);
0165 
0166     if (!dev)
0167         return -ENODEV;
0168     if (mei_write_is_idle(dev))
0169         pm_runtime_autosuspend(device);
0170 
0171     return -EBUSY;
0172 }
0173 
0174 static int  __maybe_unused mei_gsc_pm_runtime_suspend(struct device *device)
0175 {
0176     struct mei_device *dev = dev_get_drvdata(device);
0177     struct mei_me_hw *hw;
0178     int ret;
0179 
0180     if (!dev)
0181         return -ENODEV;
0182 
0183     mutex_lock(&dev->device_lock);
0184 
0185     if (mei_write_is_idle(dev)) {
0186         hw = to_me_hw(dev);
0187         hw->pg_state = MEI_PG_ON;
0188         ret = 0;
0189     } else {
0190         ret = -EAGAIN;
0191     }
0192 
0193     mutex_unlock(&dev->device_lock);
0194 
0195     return ret;
0196 }
0197 
0198 static int __maybe_unused mei_gsc_pm_runtime_resume(struct device *device)
0199 {
0200     struct mei_device *dev = dev_get_drvdata(device);
0201     struct mei_me_hw *hw;
0202     irqreturn_t irq_ret;
0203 
0204     if (!dev)
0205         return -ENODEV;
0206 
0207     mutex_lock(&dev->device_lock);
0208 
0209     hw = to_me_hw(dev);
0210     hw->pg_state = MEI_PG_OFF;
0211 
0212     mutex_unlock(&dev->device_lock);
0213 
0214     irq_ret = mei_me_irq_thread_handler(1, dev);
0215     if (irq_ret != IRQ_HANDLED)
0216         dev_err(dev->dev, "thread handler fail %d\n", irq_ret);
0217 
0218     return 0;
0219 }
0220 
0221 static const struct dev_pm_ops mei_gsc_pm_ops = {
0222     SET_SYSTEM_SLEEP_PM_OPS(mei_gsc_pm_suspend,
0223                 mei_gsc_pm_resume)
0224     SET_RUNTIME_PM_OPS(mei_gsc_pm_runtime_suspend,
0225                mei_gsc_pm_runtime_resume,
0226                mei_gsc_pm_runtime_idle)
0227 };
0228 
0229 static const struct auxiliary_device_id mei_gsc_id_table[] = {
0230     {
0231         .name = "i915.mei-gsc",
0232         .driver_data = MEI_ME_GSC_CFG,
0233 
0234     },
0235     {
0236         .name = "i915.mei-gscfi",
0237         .driver_data = MEI_ME_GSCFI_CFG,
0238     },
0239     {
0240         /* sentinel */
0241     }
0242 };
0243 MODULE_DEVICE_TABLE(auxiliary, mei_gsc_id_table);
0244 
0245 static struct auxiliary_driver mei_gsc_driver = {
0246     .probe  = mei_gsc_probe,
0247     .remove = mei_gsc_remove,
0248     .driver = {
0249         /* auxiliary_driver_register() sets .name to be the modname */
0250         .pm = &mei_gsc_pm_ops,
0251     },
0252     .id_table = mei_gsc_id_table
0253 };
0254 module_auxiliary_driver(mei_gsc_driver);
0255 
0256 MODULE_AUTHOR("Intel Corporation");
0257 MODULE_ALIAS("auxiliary:i915.mei-gsc");
0258 MODULE_ALIAS("auxiliary:i915.mei-gscfi");
0259 MODULE_LICENSE("GPL");