2013-02-06 14:06:39 +02:00
/*
*
* Intel Management Engine Interface ( Intel MEI ) Linux driver
* Copyright ( c ) 2003 - 2012 , Intel Corporation .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
*/
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/device.h>
# include <linux/fs.h>
# include <linux/errno.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/pci.h>
# include <linux/poll.h>
# include <linux/ioctl.h>
# include <linux/cdev.h>
# include <linux/sched.h>
# include <linux/uuid.h>
# include <linux/compat.h>
# include <linux/jiffies.h>
# include <linux/interrupt.h>
2016-01-07 16:46:13 +01:00
# include <linux/pm_domain.h>
2014-03-18 22:52:02 +02:00
# include <linux/pm_runtime.h>
2013-02-06 14:06:39 +02:00
# include <linux/mei.h>
# include "mei_dev.h"
# include "client.h"
2014-03-11 14:49:23 +02:00
# include "hw-me-regs.h"
# include "hw-me.h"
2013-02-06 14:06:39 +02:00
/* mei_pci_tbl - PCI Device ID Table */
2014-03-16 14:35:58 +02:00
static const struct pci_device_id mei_me_pci_tbl [ ] = {
2014-05-13 01:30:53 +03:00
{ MEI_PCI_DEVICE ( MEI_DEV_ID_82946GZ , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_82G35 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_82Q965 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_82G965 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_82GM965 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_82GME965 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_82Q35 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_82G33 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_82Q33 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_82X38 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_3200 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_6 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_7 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_8 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_9 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9_10 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9M_1 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9M_2 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9M_3 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH9M_4 , mei_me_legacy_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH10_1 , mei_me_ich_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH10_2 , mei_me_ich_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH10_3 , mei_me_ich_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_ICH10_4 , mei_me_ich_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_IBXPK_1 , mei_me_pch_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_IBXPK_2 , mei_me_pch_cfg ) } ,
2014-05-13 01:30:54 +03:00
{ MEI_PCI_DEVICE ( MEI_DEV_ID_CPT_1 , mei_me_pch_cpt_pbg_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_PBG_1 , mei_me_pch_cpt_pbg_cfg ) } ,
2014-05-13 01:30:53 +03:00
{ MEI_PCI_DEVICE ( MEI_DEV_ID_PPT_1 , mei_me_pch_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_PPT_2 , mei_me_pch_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_PPT_3 , mei_me_pch_cfg ) } ,
2014-11-19 17:01:38 +02:00
{ MEI_PCI_DEVICE ( MEI_DEV_ID_LPT_H , mei_me_pch8_sps_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_LPT_W , mei_me_pch8_sps_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_LPT_LP , mei_me_pch8_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_LPT_HR , mei_me_pch8_sps_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_WPT_LP , mei_me_pch8_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_WPT_LP_2 , mei_me_pch8_cfg ) } ,
2013-02-06 14:06:39 +02:00
2015-08-02 22:20:57 +03:00
{ MEI_PCI_DEVICE ( MEI_DEV_ID_SPT , mei_me_pch8_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_SPT_2 , mei_me_pch8_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_SPT_H , mei_me_pch8_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_SPT_H_2 , mei_me_pch8_cfg ) } ,
2016-02-29 22:03:23 +02:00
{ MEI_PCI_DEVICE ( MEI_DEV_ID_BXT_M , mei_me_pch8_cfg ) } ,
{ MEI_PCI_DEVICE ( MEI_DEV_ID_APL_I , mei_me_pch8_cfg ) } ,
2013-02-06 14:06:39 +02:00
/* required last entry */
{ 0 , }
} ;
2013-03-27 16:58:29 +02:00
MODULE_DEVICE_TABLE ( pci , mei_me_pci_tbl ) ;
2013-02-06 14:06:39 +02:00
2014-12-04 22:43:07 +01:00
# ifdef CONFIG_PM
2014-03-18 22:52:05 +02:00
static inline void mei_me_set_pm_domain ( struct mei_device * dev ) ;
static inline void mei_me_unset_pm_domain ( struct mei_device * dev ) ;
# else
static inline void mei_me_set_pm_domain ( struct mei_device * dev ) { }
static inline void mei_me_unset_pm_domain ( struct mei_device * dev ) { }
2014-12-04 22:43:07 +01:00
# endif /* CONFIG_PM */
2014-03-18 22:52:05 +02:00
2013-02-06 14:06:39 +02:00
/**
2014-09-29 16:31:50 +03:00
* mei_me_quirk_probe - probe for devices that doesn ' t valid ME interface
2013-04-05 01:05:05 +09:00
*
2013-02-06 14:06:39 +02:00
* @ pdev : PCI device structure
2014-05-13 01:30:54 +03:00
* @ cfg : per generation config
2013-02-06 14:06:39 +02:00
*
2014-09-29 16:31:49 +03:00
* Return : true if ME Interface is valid , false otherwise
2013-02-06 14:06:39 +02:00
*/
2013-03-27 16:58:29 +02:00
static bool mei_me_quirk_probe ( struct pci_dev * pdev ,
2014-05-13 01:30:54 +03:00
const struct mei_cfg * cfg )
2013-02-06 14:06:39 +02:00
{
2014-05-13 01:30:54 +03:00
if ( cfg - > quirk_probe & & cfg - > quirk_probe ( pdev ) ) {
dev_info ( & pdev - > dev , " Device doesn't have valid ME Interface \n " ) ;
return false ;
2014-03-25 21:25:18 +02:00
}
2013-02-06 14:06:39 +02:00
return true ;
}
2014-05-13 01:30:54 +03:00
2013-02-06 14:06:39 +02:00
/**
2014-09-29 16:31:50 +03:00
* mei_me_probe - Device Initialization Routine
2013-02-06 14:06:39 +02:00
*
* @ pdev : PCI device structure
* @ ent : entry in kcs_pci_tbl
*
2014-09-29 16:31:49 +03:00
* Return : 0 on success , < 0 on failure .
2013-02-06 14:06:39 +02:00
*/
2013-03-27 16:58:29 +02:00
static int mei_me_probe ( struct pci_dev * pdev , const struct pci_device_id * ent )
2013-02-06 14:06:39 +02:00
{
2014-05-13 01:30:53 +03:00
const struct mei_cfg * cfg = ( struct mei_cfg * ) ( ent - > driver_data ) ;
2013-02-06 14:06:39 +02:00
struct mei_device * dev ;
2013-02-06 14:06:40 +02:00
struct mei_me_hw * hw ;
2015-08-02 22:20:52 +03:00
unsigned int irqflags ;
2013-02-06 14:06:39 +02:00
int err ;
2014-05-13 01:30:54 +03:00
if ( ! mei_me_quirk_probe ( pdev , cfg ) )
return - ENODEV ;
2013-02-06 14:06:39 +02:00
/* enable pci dev */
err = pci_enable_device ( pdev ) ;
if ( err ) {
dev_err ( & pdev - > dev , " failed to enable pci device. \n " ) ;
goto end ;
}
/* set PCI host mastering */
pci_set_master ( pdev ) ;
/* pci request regions for mei driver */
err = pci_request_regions ( pdev , KBUILD_MODNAME ) ;
if ( err ) {
dev_err ( & pdev - > dev , " failed to get pci regions. \n " ) ;
goto disable_device ;
}
2013-12-17 15:56:57 +02:00
if ( dma_set_mask ( & pdev - > dev , DMA_BIT_MASK ( 64 ) ) | |
dma_set_coherent_mask ( & pdev - > dev , DMA_BIT_MASK ( 64 ) ) ) {
err = dma_set_mask ( & pdev - > dev , DMA_BIT_MASK ( 32 ) ) ;
if ( err )
err = dma_set_coherent_mask ( & pdev - > dev ,
DMA_BIT_MASK ( 32 ) ) ;
}
if ( err ) {
dev_err ( & pdev - > dev , " No usable DMA configuration, aborting \n " ) ;
goto release_regions ;
}
2013-02-06 14:06:39 +02:00
/* allocates and initializes the mei dev structure */
2014-05-13 01:30:53 +03:00
dev = mei_me_dev_init ( pdev , cfg ) ;
2013-02-06 14:06:39 +02:00
if ( ! dev ) {
err = - ENOMEM ;
goto release_regions ;
}
2013-02-06 14:06:40 +02:00
hw = to_me_hw ( dev ) ;
2013-02-06 14:06:39 +02:00
/* mapping IO device memory */
2013-02-06 14:06:40 +02:00
hw - > mem_addr = pci_iomap ( pdev , 0 , 0 ) ;
if ( ! hw - > mem_addr ) {
2013-02-06 14:06:39 +02:00
dev_err ( & pdev - > dev , " mapping I/O device memory failure. \n " ) ;
err = - ENOMEM ;
goto free_device ;
}
pci_enable_msi ( pdev ) ;
/* request and enable interrupt */
2015-08-02 22:20:52 +03:00
irqflags = pci_dev_msi_enabled ( pdev ) ? IRQF_ONESHOT : IRQF_SHARED ;
err = request_threaded_irq ( pdev - > irq ,
2013-02-06 14:06:42 +02:00
mei_me_irq_quick_handler ,
mei_me_irq_thread_handler ,
2015-08-02 22:20:52 +03:00
irqflags , KBUILD_MODNAME , dev ) ;
2013-02-06 14:06:39 +02:00
if ( err ) {
dev_err ( & pdev - > dev , " request_threaded_irq failure. irq = %d \n " ,
pdev - > irq ) ;
goto disable_msi ;
}
2013-03-27 16:58:28 +02:00
if ( mei_start ( dev ) ) {
2013-02-06 14:06:39 +02:00
dev_err ( & pdev - > dev , " init hw failure. \n " ) ;
err = - ENODEV ;
goto release_irq ;
}
2014-03-18 22:52:02 +02:00
pm_runtime_set_autosuspend_delay ( & pdev - > dev , MEI_ME_RPM_TIMEOUT ) ;
pm_runtime_use_autosuspend ( & pdev - > dev ) ;
2014-06-23 15:10:35 +03:00
err = mei_register ( dev , & pdev - > dev ) ;
2013-02-06 14:06:39 +02:00
if ( err )
2016-02-07 23:35:20 +02:00
goto stop ;
2013-02-06 14:06:39 +02:00
pci_set_drvdata ( pdev , dev ) ;
schedule_delayed_work ( & dev - > timer_work , HZ ) ;
2014-03-18 22:52:05 +02:00
/*
* For not wake - able HW runtime pm framework
* can ' t be used on pci device level .
* Use domain runtime pm callbacks instead .
*/
if ( ! pci_dev_run_wake ( pdev ) )
mei_me_set_pm_domain ( dev ) ;
2014-03-18 22:52:02 +02:00
if ( mei_pg_is_enabled ( dev ) )
pm_runtime_put_noidle ( & pdev - > dev ) ;
2013-10-21 22:05:42 +03:00
dev_dbg ( & pdev - > dev , " initialization successful. \n " ) ;
2013-02-06 14:06:39 +02:00
return 0 ;
2016-02-07 23:35:20 +02:00
stop :
mei_stop ( dev ) ;
2013-02-06 14:06:39 +02:00
release_irq :
2013-11-11 13:26:06 +02:00
mei_cancel_work ( dev ) ;
2013-02-06 14:06:39 +02:00
mei_disable_interrupts ( dev ) ;
free_irq ( pdev - > irq , dev ) ;
disable_msi :
pci_disable_msi ( pdev ) ;
2013-02-06 14:06:40 +02:00
pci_iounmap ( pdev , hw - > mem_addr ) ;
2013-02-06 14:06:39 +02:00
free_device :
kfree ( dev ) ;
release_regions :
pci_release_regions ( pdev ) ;
disable_device :
pci_disable_device ( pdev ) ;
end :
dev_err ( & pdev - > dev , " initialization failed. \n " ) ;
return err ;
}
/**
2014-09-29 16:31:50 +03:00
* mei_me_remove - Device Removal Routine
2013-02-06 14:06:39 +02:00
*
* @ pdev : PCI device structure
*
* mei_remove is called by the PCI subsystem to alert the driver
* that it should release a PCI device .
*/
2013-03-27 16:58:29 +02:00
static void mei_me_remove ( struct pci_dev * pdev )
2013-02-06 14:06:39 +02:00
{
struct mei_device * dev ;
2013-02-06 14:06:40 +02:00
struct mei_me_hw * hw ;
2013-02-06 14:06:39 +02:00
dev = pci_get_drvdata ( pdev ) ;
if ( ! dev )
return ;
2014-03-18 22:52:02 +02:00
if ( mei_pg_is_enabled ( dev ) )
pm_runtime_get_noresume ( & pdev - > dev ) ;
2013-02-06 14:06:40 +02:00
hw = to_me_hw ( dev ) ;
2013-02-06 14:06:39 +02:00
2013-10-17 13:52:10 +03:00
dev_dbg ( & pdev - > dev , " stop \n " ) ;
2013-03-10 13:56:08 +02:00
mei_stop ( dev ) ;
2013-02-06 14:06:39 +02:00
2014-03-18 22:52:05 +02:00
if ( ! pci_dev_run_wake ( pdev ) )
mei_me_unset_pm_domain ( dev ) ;
2013-02-06 14:06:39 +02:00
/* disable interrupts */
mei_disable_interrupts ( dev ) ;
free_irq ( pdev - > irq , dev ) ;
pci_disable_msi ( pdev ) ;
2013-02-06 14:06:40 +02:00
if ( hw - > mem_addr )
pci_iounmap ( pdev , hw - > mem_addr ) ;
2013-02-06 14:06:39 +02:00
2013-04-05 22:10:34 +03:00
mei_deregister ( dev ) ;
2013-02-06 14:06:39 +02:00
kfree ( dev ) ;
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
}
2014-02-18 14:31:08 +02:00
# ifdef CONFIG_PM_SLEEP
2013-03-27 16:58:29 +02:00
static int mei_me_pci_suspend ( struct device * device )
2013-02-06 14:06:39 +02:00
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
struct mei_device * dev = pci_get_drvdata ( pdev ) ;
if ( ! dev )
return - ENODEV ;
2013-10-17 13:52:10 +03:00
dev_dbg ( & pdev - > dev , " suspend \n " ) ;
2013-02-06 14:06:39 +02:00
2013-03-10 13:56:08 +02:00
mei_stop ( dev ) ;
mei_disable_interrupts ( dev ) ;
2013-02-06 14:06:39 +02:00
free_irq ( pdev - > irq , dev ) ;
pci_disable_msi ( pdev ) ;
2013-03-10 13:56:08 +02:00
return 0 ;
2013-02-06 14:06:39 +02:00
}
2013-03-27 16:58:29 +02:00
static int mei_me_pci_resume ( struct device * device )
2013-02-06 14:06:39 +02:00
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
struct mei_device * dev ;
2015-08-02 22:20:52 +03:00
unsigned int irqflags ;
2013-02-06 14:06:39 +02:00
int err ;
dev = pci_get_drvdata ( pdev ) ;
if ( ! dev )
return - ENODEV ;
pci_enable_msi ( pdev ) ;
2015-08-02 22:20:52 +03:00
irqflags = pci_dev_msi_enabled ( pdev ) ? IRQF_ONESHOT : IRQF_SHARED ;
2013-02-06 14:06:39 +02:00
/* request and enable interrupt */
2015-08-02 22:20:52 +03:00
err = request_threaded_irq ( pdev - > irq ,
2013-02-06 14:06:42 +02:00
mei_me_irq_quick_handler ,
mei_me_irq_thread_handler ,
2015-08-02 22:20:52 +03:00
irqflags , KBUILD_MODNAME , dev ) ;
2013-02-06 14:06:39 +02:00
if ( err ) {
dev_err ( & pdev - > dev , " request_threaded_irq failed: irq = %d. \n " ,
pdev - > irq ) ;
return err ;
}
2014-01-12 00:36:09 +02:00
err = mei_restart ( dev ) ;
if ( err )
return err ;
2013-02-06 14:06:39 +02:00
/* Start timer if stopped in suspend */
schedule_delayed_work ( & dev - > timer_work , HZ ) ;
2014-01-12 00:36:09 +02:00
return 0 ;
2013-02-06 14:06:39 +02:00
}
2014-03-18 22:52:02 +02:00
# endif /* CONFIG_PM_SLEEP */
2014-12-04 22:43:07 +01:00
# ifdef CONFIG_PM
2014-03-18 22:52:02 +02:00
static int mei_me_pm_runtime_idle ( struct device * device )
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
struct mei_device * dev ;
dev_dbg ( & pdev - > dev , " rpm: me: runtime_idle \n " ) ;
dev = pci_get_drvdata ( pdev ) ;
if ( ! dev )
return - ENODEV ;
if ( mei_write_is_idle ( dev ) )
2014-07-17 10:53:36 +03:00
pm_runtime_autosuspend ( device ) ;
2014-03-18 22:52:02 +02:00
return - EBUSY ;
}
static int mei_me_pm_runtime_suspend ( struct device * device )
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
struct mei_device * dev ;
int ret ;
dev_dbg ( & pdev - > dev , " rpm: me: runtime suspend \n " ) ;
dev = pci_get_drvdata ( pdev ) ;
if ( ! dev )
return - ENODEV ;
mutex_lock ( & dev - > device_lock ) ;
if ( mei_write_is_idle ( dev ) )
2015-02-10 10:39:34 +02:00
ret = mei_me_pg_enter_sync ( dev ) ;
2014-03-18 22:52:02 +02:00
else
ret = - EAGAIN ;
mutex_unlock ( & dev - > device_lock ) ;
dev_dbg ( & pdev - > dev , " rpm: me: runtime suspend ret=%d \n " , ret ) ;
return ret ;
}
static int mei_me_pm_runtime_resume ( struct device * device )
{
struct pci_dev * pdev = to_pci_dev ( device ) ;
struct mei_device * dev ;
int ret ;
dev_dbg ( & pdev - > dev , " rpm: me: runtime resume \n " ) ;
dev = pci_get_drvdata ( pdev ) ;
if ( ! dev )
return - ENODEV ;
mutex_lock ( & dev - > device_lock ) ;
2015-02-10 10:39:34 +02:00
ret = mei_me_pg_exit_sync ( dev ) ;
2014-03-18 22:52:02 +02:00
mutex_unlock ( & dev - > device_lock ) ;
dev_dbg ( & pdev - > dev , " rpm: me: runtime resume ret = %d \n " , ret ) ;
return ret ;
}
2014-03-18 22:52:05 +02:00
/**
2014-09-16 22:00:47 +02:00
* mei_me_set_pm_domain - fill and set pm domain structure for device
2014-03-18 22:52:05 +02:00
*
* @ dev : mei_device
*/
static inline void mei_me_set_pm_domain ( struct mei_device * dev )
{
2014-09-29 16:31:44 +03:00
struct pci_dev * pdev = to_pci_dev ( dev - > dev ) ;
2014-03-18 22:52:05 +02:00
if ( pdev - > dev . bus & & pdev - > dev . bus - > pm ) {
dev - > pg_domain . ops = * pdev - > dev . bus - > pm ;
dev - > pg_domain . ops . runtime_suspend = mei_me_pm_runtime_suspend ;
dev - > pg_domain . ops . runtime_resume = mei_me_pm_runtime_resume ;
dev - > pg_domain . ops . runtime_idle = mei_me_pm_runtime_idle ;
2016-01-07 16:46:13 +01:00
dev_pm_domain_set ( & pdev - > dev , & dev - > pg_domain ) ;
2014-03-18 22:52:05 +02:00
}
}
/**
2014-09-16 22:00:47 +02:00
* mei_me_unset_pm_domain - clean pm domain structure for device
2014-03-18 22:52:05 +02:00
*
* @ dev : mei_device
*/
static inline void mei_me_unset_pm_domain ( struct mei_device * dev )
{
/* stop using pm callbacks if any */
2016-01-07 16:46:13 +01:00
dev_pm_domain_set ( dev - > dev , NULL ) ;
2014-03-18 22:52:05 +02:00
}
2014-03-18 22:52:02 +02:00
static const struct dev_pm_ops mei_me_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( mei_me_pci_suspend ,
mei_me_pci_resume )
SET_RUNTIME_PM_OPS (
mei_me_pm_runtime_suspend ,
mei_me_pm_runtime_resume ,
mei_me_pm_runtime_idle )
} ;
2014-02-18 14:31:08 +02:00
2013-03-27 16:58:29 +02:00
# define MEI_ME_PM_OPS (&mei_me_pm_ops)
2013-02-06 14:06:39 +02:00
# else
2013-03-27 16:58:29 +02:00
# define MEI_ME_PM_OPS NULL
2014-03-18 22:52:02 +02:00
# endif /* CONFIG_PM */
2013-02-06 14:06:39 +02:00
/*
* PCI driver structure
*/
2013-03-27 16:58:29 +02:00
static struct pci_driver mei_me_driver = {
2013-02-06 14:06:39 +02:00
. name = KBUILD_MODNAME ,
2013-03-27 16:58:29 +02:00
. id_table = mei_me_pci_tbl ,
. probe = mei_me_probe ,
. remove = mei_me_remove ,
. shutdown = mei_me_remove ,
. driver . pm = MEI_ME_PM_OPS ,
2013-02-06 14:06:39 +02:00
} ;
2013-03-27 16:58:29 +02:00
module_pci_driver ( mei_me_driver ) ;
2013-02-06 14:06:39 +02:00
MODULE_AUTHOR ( " Intel Corporation " ) ;
MODULE_DESCRIPTION ( " Intel(R) Management Engine Interface " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;