19fff0425STomas Winkler // SPDX-License-Identifier: GPL-2.0 2795536acSTomas Winkler /* 31e55b609STomas Winkler * Copyright (c) 2013-2017, Intel Corporation. All rights reserved. 4795536acSTomas Winkler * Intel Management Engine Interface (Intel MEI) Linux driver 5795536acSTomas Winkler */ 6795536acSTomas Winkler 7795536acSTomas Winkler #include <linux/module.h> 8795536acSTomas Winkler #include <linux/kernel.h> 9795536acSTomas Winkler #include <linux/device.h> 10795536acSTomas Winkler #include <linux/fs.h> 11795536acSTomas Winkler #include <linux/errno.h> 12795536acSTomas Winkler #include <linux/types.h> 13795536acSTomas Winkler #include <linux/pci.h> 14795536acSTomas Winkler #include <linux/init.h> 15795536acSTomas Winkler #include <linux/sched.h> 16795536acSTomas Winkler #include <linux/uuid.h> 17795536acSTomas Winkler #include <linux/jiffies.h> 18795536acSTomas Winkler #include <linux/interrupt.h> 19795536acSTomas Winkler #include <linux/workqueue.h> 20989561deSTomeu Vizoso #include <linux/pm_domain.h> 21cfe5ab85SAlexander Usyskin #include <linux/pm_runtime.h> 22795536acSTomas Winkler 23795536acSTomas Winkler #include <linux/mei.h> 24795536acSTomas Winkler 25795536acSTomas Winkler 26795536acSTomas Winkler #include "mei_dev.h" 27795536acSTomas Winkler #include "hw-txe.h" 28795536acSTomas Winkler 29a05f8f86STomas Winkler static const struct pci_device_id mei_txe_pci_tbl[] = { 304ad96db6STomas Winkler {PCI_VDEVICE(INTEL, 0x0F18)}, /* Baytrail */ 31e88281edSTomas Winkler {PCI_VDEVICE(INTEL, 0x2298)}, /* Cherrytrail */ 324ad96db6STomas Winkler 33795536acSTomas Winkler {0, } 34795536acSTomas Winkler }; 35795536acSTomas Winkler MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl); 36795536acSTomas Winkler 37bbd6d050SRafael J. Wysocki #ifdef CONFIG_PM 38d2d56faeSAlexander Usyskin static inline void mei_txe_set_pm_domain(struct mei_device *dev); 39d2d56faeSAlexander Usyskin static inline void mei_txe_unset_pm_domain(struct mei_device *dev); 40d2d56faeSAlexander Usyskin #else 41d2d56faeSAlexander Usyskin static inline void mei_txe_set_pm_domain(struct mei_device *dev) {} 42d2d56faeSAlexander Usyskin static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {} 43bbd6d050SRafael J. Wysocki #endif /* CONFIG_PM */ 44795536acSTomas Winkler 45795536acSTomas Winkler /** 463908be6fSAlexander Usyskin * mei_txe_probe - Device Initialization Routine 47795536acSTomas Winkler * 48795536acSTomas Winkler * @pdev: PCI device structure 49795536acSTomas Winkler * @ent: entry in mei_txe_pci_tbl 50795536acSTomas Winkler * 51a8605ea2SAlexander Usyskin * Return: 0 on success, <0 on failure. 52795536acSTomas Winkler */ 53795536acSTomas Winkler static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 54795536acSTomas Winkler { 55795536acSTomas Winkler struct mei_device *dev; 56795536acSTomas Winkler struct mei_txe_hw *hw; 57f8a09605STomas Winkler const int mask = BIT(SEC_BAR) | BIT(BRIDGE_BAR); 58795536acSTomas Winkler int err; 59795536acSTomas Winkler 60795536acSTomas Winkler /* enable pci dev */ 61f8a09605STomas Winkler err = pcim_enable_device(pdev); 62795536acSTomas Winkler if (err) { 63795536acSTomas Winkler dev_err(&pdev->dev, "failed to enable pci device.\n"); 64795536acSTomas Winkler goto end; 65795536acSTomas Winkler } 66795536acSTomas Winkler /* set PCI host mastering */ 67795536acSTomas Winkler pci_set_master(pdev); 68f8a09605STomas Winkler /* pci request regions and mapping IO device memory for mei driver */ 69f8a09605STomas Winkler err = pcim_iomap_regions(pdev, mask, KBUILD_MODNAME); 70795536acSTomas Winkler if (err) { 71795536acSTomas Winkler dev_err(&pdev->dev, "failed to get pci regions.\n"); 72f8a09605STomas Winkler goto end; 73795536acSTomas Winkler } 74795536acSTomas Winkler 75795536acSTomas Winkler err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); 76795536acSTomas Winkler if (err) { 77795536acSTomas Winkler err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 78795536acSTomas Winkler if (err) { 79795536acSTomas Winkler dev_err(&pdev->dev, "No suitable DMA available.\n"); 80f8a09605STomas Winkler goto end; 81795536acSTomas Winkler } 82795536acSTomas Winkler } 83795536acSTomas Winkler 84795536acSTomas Winkler /* allocates and initializes the mei dev structure */ 854ad96db6STomas Winkler dev = mei_txe_dev_init(pdev); 86795536acSTomas Winkler if (!dev) { 87795536acSTomas Winkler err = -ENOMEM; 88f8a09605STomas Winkler goto end; 89795536acSTomas Winkler } 90795536acSTomas Winkler hw = to_txe_hw(dev); 91f8a09605STomas Winkler hw->mem_addr = pcim_iomap_table(pdev); 92795536acSTomas Winkler 93795536acSTomas Winkler pci_enable_msi(pdev); 94795536acSTomas Winkler 95795536acSTomas Winkler /* clear spurious interrupts */ 96795536acSTomas Winkler mei_clear_interrupts(dev); 97795536acSTomas Winkler 98795536acSTomas Winkler /* request and enable interrupt */ 99795536acSTomas Winkler if (pci_dev_msi_enabled(pdev)) 100795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 101795536acSTomas Winkler NULL, 102795536acSTomas Winkler mei_txe_irq_thread_handler, 103795536acSTomas Winkler IRQF_ONESHOT, KBUILD_MODNAME, dev); 104795536acSTomas Winkler else 105795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 106795536acSTomas Winkler mei_txe_irq_quick_handler, 107795536acSTomas Winkler mei_txe_irq_thread_handler, 108795536acSTomas Winkler IRQF_SHARED, KBUILD_MODNAME, dev); 109795536acSTomas Winkler if (err) { 110795536acSTomas Winkler dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n", 111795536acSTomas Winkler pdev->irq); 112f8a09605STomas Winkler goto end; 113795536acSTomas Winkler } 114795536acSTomas Winkler 115795536acSTomas Winkler if (mei_start(dev)) { 116795536acSTomas Winkler dev_err(&pdev->dev, "init hw failure.\n"); 117795536acSTomas Winkler err = -ENODEV; 118795536acSTomas Winkler goto release_irq; 119795536acSTomas Winkler } 120795536acSTomas Winkler 121cfe5ab85SAlexander Usyskin pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_TXI_RPM_TIMEOUT); 122cfe5ab85SAlexander Usyskin pm_runtime_use_autosuspend(&pdev->dev); 123cfe5ab85SAlexander Usyskin 124f3d8e878SAlexander Usyskin err = mei_register(dev, &pdev->dev); 125795536acSTomas Winkler if (err) 1261f7e489aSAlexander Usyskin goto stop; 127795536acSTomas Winkler 128795536acSTomas Winkler pci_set_drvdata(pdev, dev); 129795536acSTomas Winkler 130d2d56faeSAlexander Usyskin /* 131557909e1SAlexander Usyskin * MEI requires to resume from runtime suspend mode 132557909e1SAlexander Usyskin * in order to perform link reset flow upon system suspend. 133557909e1SAlexander Usyskin */ 134c2eac4d3SRafael J. Wysocki dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NEVER_SKIP); 135557909e1SAlexander Usyskin 136557909e1SAlexander Usyskin /* 137b42dc063SAlexander Usyskin * TXE maps runtime suspend/resume to own power gating states, 138b42dc063SAlexander Usyskin * hence we need to go around native PCI runtime service which 139b42dc063SAlexander Usyskin * eventually brings the device into D3cold/hot state. 140b42dc063SAlexander Usyskin * But the TXE device cannot wake up from D3 unlike from own 141b42dc063SAlexander Usyskin * power gating. To get around PCI device native runtime pm, 142b42dc063SAlexander Usyskin * TXE uses runtime pm domain handlers which take precedence. 143d2d56faeSAlexander Usyskin */ 144d2d56faeSAlexander Usyskin mei_txe_set_pm_domain(dev); 145d2d56faeSAlexander Usyskin 146cfe5ab85SAlexander Usyskin pm_runtime_put_noidle(&pdev->dev); 147cfe5ab85SAlexander Usyskin 148795536acSTomas Winkler return 0; 149795536acSTomas Winkler 1501f7e489aSAlexander Usyskin stop: 1511f7e489aSAlexander Usyskin mei_stop(dev); 152795536acSTomas Winkler release_irq: 153795536acSTomas Winkler mei_cancel_work(dev); 154795536acSTomas Winkler mei_disable_interrupts(dev); 155795536acSTomas Winkler free_irq(pdev->irq, dev); 156795536acSTomas Winkler end: 157795536acSTomas Winkler dev_err(&pdev->dev, "initialization failed.\n"); 158795536acSTomas Winkler return err; 159795536acSTomas Winkler } 160795536acSTomas Winkler 161795536acSTomas Winkler /** 1625c4c0106STomas Winkler * mei_txe_remove - Device Shutdown Routine 1635c4c0106STomas Winkler * 1645c4c0106STomas Winkler * @pdev: PCI device structure 1655c4c0106STomas Winkler * 1665c4c0106STomas Winkler * mei_txe_shutdown is called from the reboot notifier 1675c4c0106STomas Winkler * it's a simplified version of remove so we go down 1685c4c0106STomas Winkler * faster. 1695c4c0106STomas Winkler */ 1705c4c0106STomas Winkler static void mei_txe_shutdown(struct pci_dev *pdev) 1715c4c0106STomas Winkler { 1725c4c0106STomas Winkler struct mei_device *dev; 1735c4c0106STomas Winkler 1745c4c0106STomas Winkler dev = pci_get_drvdata(pdev); 1755c4c0106STomas Winkler if (!dev) 1765c4c0106STomas Winkler return; 1775c4c0106STomas Winkler 1785c4c0106STomas Winkler dev_dbg(&pdev->dev, "shutdown\n"); 1795c4c0106STomas Winkler mei_stop(dev); 1805c4c0106STomas Winkler 1815c4c0106STomas Winkler mei_txe_unset_pm_domain(dev); 1825c4c0106STomas Winkler 1835c4c0106STomas Winkler mei_disable_interrupts(dev); 1845c4c0106STomas Winkler free_irq(pdev->irq, dev); 1855c4c0106STomas Winkler } 1865c4c0106STomas Winkler 1875c4c0106STomas Winkler /** 1883908be6fSAlexander Usyskin * mei_txe_remove - Device Removal Routine 189795536acSTomas Winkler * 190795536acSTomas Winkler * @pdev: PCI device structure 191795536acSTomas Winkler * 192795536acSTomas Winkler * mei_remove is called by the PCI subsystem to alert the driver 193795536acSTomas Winkler * that it should release a PCI device. 194795536acSTomas Winkler */ 195795536acSTomas Winkler static void mei_txe_remove(struct pci_dev *pdev) 196795536acSTomas Winkler { 197795536acSTomas Winkler struct mei_device *dev; 198795536acSTomas Winkler 199795536acSTomas Winkler dev = pci_get_drvdata(pdev); 200795536acSTomas Winkler if (!dev) { 201f8a09605STomas Winkler dev_err(&pdev->dev, "mei: dev == NULL\n"); 202795536acSTomas Winkler return; 203795536acSTomas Winkler } 204795536acSTomas Winkler 205cfe5ab85SAlexander Usyskin pm_runtime_get_noresume(&pdev->dev); 206cfe5ab85SAlexander Usyskin 207795536acSTomas Winkler mei_stop(dev); 208795536acSTomas Winkler 209d2d56faeSAlexander Usyskin mei_txe_unset_pm_domain(dev); 210d2d56faeSAlexander Usyskin 211795536acSTomas Winkler mei_disable_interrupts(dev); 212795536acSTomas Winkler free_irq(pdev->irq, dev); 213795536acSTomas Winkler 214795536acSTomas Winkler mei_deregister(dev); 215795536acSTomas Winkler } 216795536acSTomas Winkler 217795536acSTomas Winkler 218e0270addSTomas Winkler #ifdef CONFIG_PM_SLEEP 219795536acSTomas Winkler static int mei_txe_pci_suspend(struct device *device) 220795536acSTomas Winkler { 221795536acSTomas Winkler struct pci_dev *pdev = to_pci_dev(device); 222795536acSTomas Winkler struct mei_device *dev = pci_get_drvdata(pdev); 223795536acSTomas Winkler 224795536acSTomas Winkler if (!dev) 225795536acSTomas Winkler return -ENODEV; 226795536acSTomas Winkler 227795536acSTomas Winkler dev_dbg(&pdev->dev, "suspend\n"); 228795536acSTomas Winkler 229795536acSTomas Winkler mei_stop(dev); 230795536acSTomas Winkler 231795536acSTomas Winkler mei_disable_interrupts(dev); 232795536acSTomas Winkler 233795536acSTomas Winkler free_irq(pdev->irq, dev); 234795536acSTomas Winkler pci_disable_msi(pdev); 235795536acSTomas Winkler 236795536acSTomas Winkler return 0; 237795536acSTomas Winkler } 238795536acSTomas Winkler 239795536acSTomas Winkler static int mei_txe_pci_resume(struct device *device) 240795536acSTomas Winkler { 241795536acSTomas Winkler struct pci_dev *pdev = to_pci_dev(device); 242795536acSTomas Winkler struct mei_device *dev; 243795536acSTomas Winkler int err; 244795536acSTomas Winkler 245795536acSTomas Winkler dev = pci_get_drvdata(pdev); 246795536acSTomas Winkler if (!dev) 247795536acSTomas Winkler return -ENODEV; 248795536acSTomas Winkler 249795536acSTomas Winkler pci_enable_msi(pdev); 250795536acSTomas Winkler 251795536acSTomas Winkler mei_clear_interrupts(dev); 252795536acSTomas Winkler 253795536acSTomas Winkler /* request and enable interrupt */ 254795536acSTomas Winkler if (pci_dev_msi_enabled(pdev)) 255795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 256795536acSTomas Winkler NULL, 257795536acSTomas Winkler mei_txe_irq_thread_handler, 258795536acSTomas Winkler IRQF_ONESHOT, KBUILD_MODNAME, dev); 259795536acSTomas Winkler else 260795536acSTomas Winkler err = request_threaded_irq(pdev->irq, 261795536acSTomas Winkler mei_txe_irq_quick_handler, 262795536acSTomas Winkler mei_txe_irq_thread_handler, 263795536acSTomas Winkler IRQF_SHARED, KBUILD_MODNAME, dev); 264795536acSTomas Winkler if (err) { 265795536acSTomas Winkler dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n", 266795536acSTomas Winkler pdev->irq); 267795536acSTomas Winkler return err; 268795536acSTomas Winkler } 269795536acSTomas Winkler 270795536acSTomas Winkler err = mei_restart(dev); 271795536acSTomas Winkler 272795536acSTomas Winkler return err; 273795536acSTomas Winkler } 274cfe5ab85SAlexander Usyskin #endif /* CONFIG_PM_SLEEP */ 275795536acSTomas Winkler 276bbd6d050SRafael J. Wysocki #ifdef CONFIG_PM 277cfe5ab85SAlexander Usyskin static int mei_txe_pm_runtime_idle(struct device *device) 278cfe5ab85SAlexander Usyskin { 279cfe5ab85SAlexander Usyskin struct mei_device *dev; 280cfe5ab85SAlexander Usyskin 281*ab81f3f3SChuhong Yuan dev_dbg(device, "rpm: txe: runtime_idle\n"); 282cfe5ab85SAlexander Usyskin 283*ab81f3f3SChuhong Yuan dev = dev_get_drvdata(device); 284cfe5ab85SAlexander Usyskin if (!dev) 285cfe5ab85SAlexander Usyskin return -ENODEV; 286cfe5ab85SAlexander Usyskin if (mei_write_is_idle(dev)) 287d5d83f8aSAlexander Usyskin pm_runtime_autosuspend(device); 288cfe5ab85SAlexander Usyskin 289cfe5ab85SAlexander Usyskin return -EBUSY; 290cfe5ab85SAlexander Usyskin } 291cfe5ab85SAlexander Usyskin static int mei_txe_pm_runtime_suspend(struct device *device) 292cfe5ab85SAlexander Usyskin { 293cfe5ab85SAlexander Usyskin struct mei_device *dev; 294cfe5ab85SAlexander Usyskin int ret; 295cfe5ab85SAlexander Usyskin 296*ab81f3f3SChuhong Yuan dev_dbg(device, "rpm: txe: runtime suspend\n"); 297cfe5ab85SAlexander Usyskin 298*ab81f3f3SChuhong Yuan dev = dev_get_drvdata(device); 299cfe5ab85SAlexander Usyskin if (!dev) 300cfe5ab85SAlexander Usyskin return -ENODEV; 301cfe5ab85SAlexander Usyskin 302cfe5ab85SAlexander Usyskin mutex_lock(&dev->device_lock); 303cfe5ab85SAlexander Usyskin 304cfe5ab85SAlexander Usyskin if (mei_write_is_idle(dev)) 305cfe5ab85SAlexander Usyskin ret = mei_txe_aliveness_set_sync(dev, 0); 306cfe5ab85SAlexander Usyskin else 307cfe5ab85SAlexander Usyskin ret = -EAGAIN; 308cfe5ab85SAlexander Usyskin 309b42dc063SAlexander Usyskin /* keep irq on we are staying in D0 */ 310cfe5ab85SAlexander Usyskin 311*ab81f3f3SChuhong Yuan dev_dbg(device, "rpm: txe: runtime suspend ret=%d\n", ret); 312cfe5ab85SAlexander Usyskin 313cfe5ab85SAlexander Usyskin mutex_unlock(&dev->device_lock); 31477537ad2SAlexander Usyskin 31577537ad2SAlexander Usyskin if (ret && ret != -EAGAIN) 31677537ad2SAlexander Usyskin schedule_work(&dev->reset_work); 31777537ad2SAlexander Usyskin 318cfe5ab85SAlexander Usyskin return ret; 319cfe5ab85SAlexander Usyskin } 320cfe5ab85SAlexander Usyskin 321cfe5ab85SAlexander Usyskin static int mei_txe_pm_runtime_resume(struct device *device) 322cfe5ab85SAlexander Usyskin { 323cfe5ab85SAlexander Usyskin struct mei_device *dev; 324cfe5ab85SAlexander Usyskin int ret; 325cfe5ab85SAlexander Usyskin 326*ab81f3f3SChuhong Yuan dev_dbg(device, "rpm: txe: runtime resume\n"); 327cfe5ab85SAlexander Usyskin 328*ab81f3f3SChuhong Yuan dev = dev_get_drvdata(device); 329cfe5ab85SAlexander Usyskin if (!dev) 330cfe5ab85SAlexander Usyskin return -ENODEV; 331cfe5ab85SAlexander Usyskin 332cfe5ab85SAlexander Usyskin mutex_lock(&dev->device_lock); 333cfe5ab85SAlexander Usyskin 334cfe5ab85SAlexander Usyskin mei_enable_interrupts(dev); 335cfe5ab85SAlexander Usyskin 336cfe5ab85SAlexander Usyskin ret = mei_txe_aliveness_set_sync(dev, 1); 337cfe5ab85SAlexander Usyskin 338cfe5ab85SAlexander Usyskin mutex_unlock(&dev->device_lock); 339cfe5ab85SAlexander Usyskin 340*ab81f3f3SChuhong Yuan dev_dbg(device, "rpm: txe: runtime resume ret = %d\n", ret); 341cfe5ab85SAlexander Usyskin 34277537ad2SAlexander Usyskin if (ret) 34377537ad2SAlexander Usyskin schedule_work(&dev->reset_work); 34477537ad2SAlexander Usyskin 345cfe5ab85SAlexander Usyskin return ret; 346cfe5ab85SAlexander Usyskin } 347d2d56faeSAlexander Usyskin 348d2d56faeSAlexander Usyskin /** 3497efceb55SGeert Uytterhoeven * mei_txe_set_pm_domain - fill and set pm domain structure for device 350d2d56faeSAlexander Usyskin * 351d2d56faeSAlexander Usyskin * @dev: mei_device 352d2d56faeSAlexander Usyskin */ 353d2d56faeSAlexander Usyskin static inline void mei_txe_set_pm_domain(struct mei_device *dev) 354d2d56faeSAlexander Usyskin { 355d08b8fc0STomas Winkler struct pci_dev *pdev = to_pci_dev(dev->dev); 356d2d56faeSAlexander Usyskin 357d2d56faeSAlexander Usyskin if (pdev->dev.bus && pdev->dev.bus->pm) { 358d2d56faeSAlexander Usyskin dev->pg_domain.ops = *pdev->dev.bus->pm; 359d2d56faeSAlexander Usyskin 360d2d56faeSAlexander Usyskin dev->pg_domain.ops.runtime_suspend = mei_txe_pm_runtime_suspend; 361d2d56faeSAlexander Usyskin dev->pg_domain.ops.runtime_resume = mei_txe_pm_runtime_resume; 362d2d56faeSAlexander Usyskin dev->pg_domain.ops.runtime_idle = mei_txe_pm_runtime_idle; 363d2d56faeSAlexander Usyskin 364989561deSTomeu Vizoso dev_pm_domain_set(&pdev->dev, &dev->pg_domain); 365d2d56faeSAlexander Usyskin } 366d2d56faeSAlexander Usyskin } 367d2d56faeSAlexander Usyskin 368d2d56faeSAlexander Usyskin /** 3697efceb55SGeert Uytterhoeven * mei_txe_unset_pm_domain - clean pm domain structure for device 370d2d56faeSAlexander Usyskin * 371d2d56faeSAlexander Usyskin * @dev: mei_device 372d2d56faeSAlexander Usyskin */ 373d2d56faeSAlexander Usyskin static inline void mei_txe_unset_pm_domain(struct mei_device *dev) 374d2d56faeSAlexander Usyskin { 375d2d56faeSAlexander Usyskin /* stop using pm callbacks if any */ 376989561deSTomeu Vizoso dev_pm_domain_set(dev->dev, NULL); 377d2d56faeSAlexander Usyskin } 378cfe5ab85SAlexander Usyskin 379cfe5ab85SAlexander Usyskin static const struct dev_pm_ops mei_txe_pm_ops = { 380cfe5ab85SAlexander Usyskin SET_SYSTEM_SLEEP_PM_OPS(mei_txe_pci_suspend, 381cfe5ab85SAlexander Usyskin mei_txe_pci_resume) 382cfe5ab85SAlexander Usyskin SET_RUNTIME_PM_OPS( 383cfe5ab85SAlexander Usyskin mei_txe_pm_runtime_suspend, 384cfe5ab85SAlexander Usyskin mei_txe_pm_runtime_resume, 385cfe5ab85SAlexander Usyskin mei_txe_pm_runtime_idle) 386cfe5ab85SAlexander Usyskin }; 387795536acSTomas Winkler 388795536acSTomas Winkler #define MEI_TXE_PM_OPS (&mei_txe_pm_ops) 389795536acSTomas Winkler #else 390795536acSTomas Winkler #define MEI_TXE_PM_OPS NULL 391cfe5ab85SAlexander Usyskin #endif /* CONFIG_PM */ 392cfe5ab85SAlexander Usyskin 393795536acSTomas Winkler /* 394795536acSTomas Winkler * PCI driver structure 395795536acSTomas Winkler */ 396795536acSTomas Winkler static struct pci_driver mei_txe_driver = { 397795536acSTomas Winkler .name = KBUILD_MODNAME, 398795536acSTomas Winkler .id_table = mei_txe_pci_tbl, 399795536acSTomas Winkler .probe = mei_txe_probe, 400795536acSTomas Winkler .remove = mei_txe_remove, 4015c4c0106STomas Winkler .shutdown = mei_txe_shutdown, 402795536acSTomas Winkler .driver.pm = MEI_TXE_PM_OPS, 403795536acSTomas Winkler }; 404795536acSTomas Winkler 405795536acSTomas Winkler module_pci_driver(mei_txe_driver); 406795536acSTomas Winkler 407795536acSTomas Winkler MODULE_AUTHOR("Intel Corporation"); 408795536acSTomas Winkler MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface"); 409795536acSTomas Winkler MODULE_LICENSE("GPL v2"); 410