linux/drivers/misc/mei/pci-txe.c
<<
>>
Prefs
   1/*
   2 *
   3 * Intel Management Engine Interface (Intel MEI) Linux driver
   4 * Copyright (c) 2013-2014, Intel Corporation.
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/kernel.h>
  19#include <linux/device.h>
  20#include <linux/fs.h>
  21#include <linux/errno.h>
  22#include <linux/types.h>
  23#include <linux/pci.h>
  24#include <linux/init.h>
  25#include <linux/sched.h>
  26#include <linux/uuid.h>
  27#include <linux/jiffies.h>
  28#include <linux/interrupt.h>
  29#include <linux/workqueue.h>
  30#include <linux/pm_domain.h>
  31#include <linux/pm_runtime.h>
  32
  33#include <linux/mei.h>
  34
  35
  36#include "mei_dev.h"
  37#include "hw-txe.h"
  38
  39static const struct pci_device_id mei_txe_pci_tbl[] = {
  40        {PCI_VDEVICE(INTEL, 0x0F18)}, /* Baytrail */
  41        {PCI_VDEVICE(INTEL, 0x2298)}, /* Cherrytrail */
  42
  43        {0, }
  44};
  45MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
  46
  47#ifdef CONFIG_PM
  48static inline void mei_txe_set_pm_domain(struct mei_device *dev);
  49static inline void mei_txe_unset_pm_domain(struct mei_device *dev);
  50#else
  51static inline void mei_txe_set_pm_domain(struct mei_device *dev) {}
  52static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {}
  53#endif /* CONFIG_PM */
  54
  55/**
  56 * mei_txe_probe - Device Initialization Routine
  57 *
  58 * @pdev: PCI device structure
  59 * @ent: entry in mei_txe_pci_tbl
  60 *
  61 * Return: 0 on success, <0 on failure.
  62 */
  63static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  64{
  65        struct mei_device *dev;
  66        struct mei_txe_hw *hw;
  67        const int mask = BIT(SEC_BAR) | BIT(BRIDGE_BAR);
  68        int err;
  69
  70        /* enable pci dev */
  71        err = pcim_enable_device(pdev);
  72        if (err) {
  73                dev_err(&pdev->dev, "failed to enable pci device.\n");
  74                goto end;
  75        }
  76        /* set PCI host mastering  */
  77        pci_set_master(pdev);
  78        /* pci request regions and mapping IO device memory for mei driver */
  79        err = pcim_iomap_regions(pdev, mask, KBUILD_MODNAME);
  80        if (err) {
  81                dev_err(&pdev->dev, "failed to get pci regions.\n");
  82                goto end;
  83        }
  84
  85        err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
  86        if (err) {
  87                err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
  88                if (err) {
  89                        dev_err(&pdev->dev, "No suitable DMA available.\n");
  90                        goto end;
  91                }
  92        }
  93
  94        /* allocates and initializes the mei dev structure */
  95        dev = mei_txe_dev_init(pdev);
  96        if (!dev) {
  97                err = -ENOMEM;
  98                goto end;
  99        }
 100        hw = to_txe_hw(dev);
 101        hw->mem_addr = pcim_iomap_table(pdev);
 102
 103        pci_enable_msi(pdev);
 104
 105        /* clear spurious interrupts */
 106        mei_clear_interrupts(dev);
 107
 108        /* request and enable interrupt  */
 109        if (pci_dev_msi_enabled(pdev))
 110                err = request_threaded_irq(pdev->irq,
 111                        NULL,
 112                        mei_txe_irq_thread_handler,
 113                        IRQF_ONESHOT, KBUILD_MODNAME, dev);
 114        else
 115                err = request_threaded_irq(pdev->irq,
 116                        mei_txe_irq_quick_handler,
 117                        mei_txe_irq_thread_handler,
 118                        IRQF_SHARED, KBUILD_MODNAME, dev);
 119        if (err) {
 120                dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
 121                        pdev->irq);
 122                goto end;
 123        }
 124
 125        if (mei_start(dev)) {
 126                dev_err(&pdev->dev, "init hw failure.\n");
 127                err = -ENODEV;
 128                goto release_irq;
 129        }
 130
 131        pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT);
 132        pm_runtime_use_autosuspend(&pdev->dev);
 133
 134        err = mei_register(dev, &pdev->dev);
 135        if (err)
 136                goto stop;
 137
 138        pci_set_drvdata(pdev, dev);
 139
 140        /*
 141         * MEI requires to resume from runtime suspend mode
 142         * in order to perform link reset flow upon system suspend.
 143         */
 144        dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP);
 145
 146        /*
 147         * TXE maps runtime suspend/resume to own power gating states,
 148         * hence we need to go around native PCI runtime service which
 149         * eventually brings the device into D3cold/hot state.
 150         * But the TXE device cannot wake up from D3 unlike from own
 151         * power gating. To get around PCI device native runtime pm,
 152         * TXE uses runtime pm domain handlers which take precedence.
 153         */
 154        mei_txe_set_pm_domain(dev);
 155
 156        pm_runtime_put_noidle(&pdev->dev);
 157
 158        return 0;
 159
 160stop:
 161        mei_stop(dev);
 162release_irq:
 163        mei_cancel_work(dev);
 164        mei_disable_interrupts(dev);
 165        free_irq(pdev->irq, dev);
 166end:
 167        dev_err(&pdev->dev, "initialization failed.\n");
 168        return err;
 169}
 170
 171/**
 172 * mei_txe_remove - Device Shutdown Routine
 173 *
 174 * @pdev: PCI device structure
 175 *
 176 *  mei_txe_shutdown is called from the reboot notifier
 177 *  it's a simplified version of remove so we go down
 178 *  faster.
 179 */
 180static void mei_txe_shutdown(struct pci_dev *pdev)
 181{
 182        struct mei_device *dev;
 183
 184        dev = pci_get_drvdata(pdev);
 185        if (!dev)
 186                return;
 187
 188        dev_dbg(&pdev->dev, "shutdown\n");
 189        mei_stop(dev);
 190
 191        mei_txe_unset_pm_domain(dev);
 192
 193        mei_disable_interrupts(dev);
 194        free_irq(pdev->irq, dev);
 195}
 196
 197/**
 198 * mei_txe_remove - Device Removal Routine
 199 *
 200 * @pdev: PCI device structure
 201 *
 202 * mei_remove is called by the PCI subsystem to alert the driver
 203 * that it should release a PCI device.
 204 */
 205static void mei_txe_remove(struct pci_dev *pdev)
 206{
 207        struct mei_device *dev;
 208
 209        dev = pci_get_drvdata(pdev);
 210        if (!dev) {
 211                dev_err(&pdev->dev, "mei: dev == NULL\n");
 212                return;
 213        }
 214
 215        pm_runtime_get_noresume(&pdev->dev);
 216
 217        mei_stop(dev);
 218
 219        mei_txe_unset_pm_domain(dev);
 220
 221        mei_disable_interrupts(dev);
 222        free_irq(pdev->irq, dev);
 223
 224        mei_deregister(dev);
 225}
 226
 227
 228#ifdef CONFIG_PM_SLEEP
 229static int mei_txe_pci_suspend(struct device *device)
 230{
 231        struct pci_dev *pdev = to_pci_dev(device);
 232        struct mei_device *dev = pci_get_drvdata(pdev);
 233
 234        if (!dev)
 235                return -ENODEV;
 236
 237        dev_dbg(&pdev->dev, "suspend\n");
 238
 239        mei_stop(dev);
 240
 241        mei_disable_interrupts(dev);
 242
 243        free_irq(pdev->irq, dev);
 244        pci_disable_msi(pdev);
 245
 246        return 0;
 247}
 248
 249static int mei_txe_pci_resume(struct device *device)
 250{
 251        struct pci_dev *pdev = to_pci_dev(device);
 252        struct mei_device *dev;
 253        int err;
 254
 255        dev = pci_get_drvdata(pdev);
 256        if (!dev)
 257                return -ENODEV;
 258
 259        pci_enable_msi(pdev);
 260
 261        mei_clear_interrupts(dev);
 262
 263        /* request and enable interrupt */
 264        if (pci_dev_msi_enabled(pdev))
 265                err = request_threaded_irq(pdev->irq,
 266                        NULL,
 267                        mei_txe_irq_thread_handler,
 268                        IRQF_ONESHOT, KBUILD_MODNAME, dev);
 269        else
 270                err = request_threaded_irq(pdev->irq,
 271                        mei_txe_irq_quick_handler,
 272                        mei_txe_irq_thread_handler,
 273                        IRQF_SHARED, KBUILD_MODNAME, dev);
 274        if (err) {
 275                dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
 276                                pdev->irq);
 277                return err;
 278        }
 279
 280        err = mei_restart(dev);
 281
 282        return err;
 283}
 284#endif /* CONFIG_PM_SLEEP */
 285
 286#ifdef CONFIG_PM
 287static int mei_txe_pm_runtime_idle(struct device *device)
 288{
 289        struct pci_dev *pdev = to_pci_dev(device);
 290        struct mei_device *dev;
 291
 292        dev_dbg(&pdev->dev, "rpm: txe: runtime_idle\n");
 293
 294        dev = pci_get_drvdata(pdev);
 295        if (!dev)
 296                return -ENODEV;
 297        if (mei_write_is_idle(dev))
 298                pm_runtime_autosuspend(device);
 299
 300        return -EBUSY;
 301}
 302static int mei_txe_pm_runtime_suspend(struct device *device)
 303{
 304        struct pci_dev *pdev = to_pci_dev(device);
 305        struct mei_device *dev;
 306        int ret;
 307
 308        dev_dbg(&pdev->dev, "rpm: txe: runtime suspend\n");
 309
 310        dev = pci_get_drvdata(pdev);
 311        if (!dev)
 312                return -ENODEV;
 313
 314        mutex_lock(&dev->device_lock);
 315
 316        if (mei_write_is_idle(dev))
 317                ret = mei_txe_aliveness_set_sync(dev, 0);
 318        else
 319                ret = -EAGAIN;
 320
 321        /* keep irq on we are staying in D0 */
 322
 323        dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret);
 324
 325        mutex_unlock(&dev->device_lock);
 326
 327        if (ret && ret != -EAGAIN)
 328                schedule_work(&dev->reset_work);
 329
 330        return ret;
 331}
 332
 333static int mei_txe_pm_runtime_resume(struct device *device)
 334{
 335        struct pci_dev *pdev = to_pci_dev(device);
 336        struct mei_device *dev;
 337        int ret;
 338
 339        dev_dbg(&pdev->dev, "rpm: txe: runtime resume\n");
 340
 341        dev = pci_get_drvdata(pdev);
 342        if (!dev)
 343                return -ENODEV;
 344
 345        mutex_lock(&dev->device_lock);
 346
 347        mei_enable_interrupts(dev);
 348
 349        ret = mei_txe_aliveness_set_sync(dev, 1);
 350
 351        mutex_unlock(&dev->device_lock);
 352
 353        dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret);
 354
 355        if (ret)
 356                schedule_work(&dev->reset_work);
 357
 358        return ret;
 359}
 360
 361/**
 362 * mei_txe_set_pm_domain - fill and set pm domain structure for device
 363 *
 364 * @dev: mei_device
 365 */
 366static inline void mei_txe_set_pm_domain(struct mei_device *dev)
 367{
 368        struct pci_dev *pdev  = to_pci_dev(dev->dev);
 369
 370        if (pdev->dev.bus && pdev->dev.bus->pm) {
 371                dev->pg_domain.ops = *pdev->dev.bus->pm;
 372
 373                dev->pg_domain.ops.runtime_suspend = mei_txe_pm_runtime_suspend;
 374                dev->pg_domain.ops.runtime_resume = mei_txe_pm_runtime_resume;
 375                dev->pg_domain.ops.runtime_idle = mei_txe_pm_runtime_idle;
 376
 377                dev_pm_domain_set(&pdev->dev, &dev->pg_domain);
 378        }
 379}
 380
 381/**
 382 * mei_txe_unset_pm_domain - clean pm domain structure for device
 383 *
 384 * @dev: mei_device
 385 */
 386static inline void mei_txe_unset_pm_domain(struct mei_device *dev)
 387{
 388        /* stop using pm callbacks if any */
 389        dev_pm_domain_set(dev->dev, NULL);
 390}
 391
 392static const struct dev_pm_ops mei_txe_pm_ops = {
 393        SET_SYSTEM_SLEEP_PM_OPS(mei_txe_pci_suspend,
 394                                mei_txe_pci_resume)
 395        SET_RUNTIME_PM_OPS(
 396                mei_txe_pm_runtime_suspend,
 397                mei_txe_pm_runtime_resume,
 398                mei_txe_pm_runtime_idle)
 399};
 400
 401#define MEI_TXE_PM_OPS  (&mei_txe_pm_ops)
 402#else
 403#define MEI_TXE_PM_OPS  NULL
 404#endif /* CONFIG_PM */
 405
 406/*
 407 *  PCI driver structure
 408 */
 409static struct pci_driver mei_txe_driver = {
 410        .name = KBUILD_MODNAME,
 411        .id_table = mei_txe_pci_tbl,
 412        .probe = mei_txe_probe,
 413        .remove = mei_txe_remove,
 414        .shutdown = mei_txe_shutdown,
 415        .driver.pm = MEI_TXE_PM_OPS,
 416};
 417
 418module_pci_driver(mei_txe_driver);
 419
 420MODULE_AUTHOR("Intel Corporation");
 421MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface");
 422MODULE_LICENSE("GPL v2");
 423