pci-me.c 8.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
/*
 *
 * 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.
 *
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#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/aio.h>
#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/init.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>
#include <linux/miscdevice.h>

#include <linux/mei.h>

#include "mei_dev.h"
#include "hw-me.h"
#include "client.h"

/* mei_pci_tbl - PCI Device ID Table */
47
static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = {
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82946GZ)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G35)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82Q965)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82G965)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GM965)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_82GME965)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q35)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82G33)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82Q33)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_82X38)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_3200)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_6)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_7)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_8)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_9)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9_10)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_1)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_2)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_3)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH9M_4)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_1)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_2)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_3)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_ICH10_4)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_1)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_IBXPK_2)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_CPT_1)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PBG_1)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_1)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)},
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)},
80
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_W)},
81 82 83 84 85 86
	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)},

	/* required last entry */
	{0, }
};

87
MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl);
88 89 90

/**
 * mei_quirk_probe - probe for devices that doesn't valid ME interface
91
 *
92 93 94 95 96
 * @pdev: PCI device structure
 * @ent: entry into pci_device_table
 *
 * returns true if ME Interface is valid, false otherwise
 */
97
static bool mei_me_quirk_probe(struct pci_dev *pdev,
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
				const struct pci_device_id *ent)
{
	u32 reg;
	if (ent->device == MEI_DEV_ID_PBG_1) {
		pci_read_config_dword(pdev, 0x48, &reg);
		/* make sure that bit 9 is up and bit 10 is down */
		if ((reg & 0x600) == 0x200) {
			dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
			return false;
		}
	}
	return true;
}
/**
 * mei_probe - Device Initialization Routine
 *
 * @pdev: PCI device structure
 * @ent: entry in kcs_pci_tbl
 *
 * returns 0 on success, <0 on failure.
 */
119
static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
120 121
{
	struct mei_device *dev;
122
	struct mei_me_hw *hw;
123 124 125
	int err;


126
	if (!mei_me_quirk_probe(pdev, ent)) {
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
		err = -ENODEV;
		goto end;
	}

	/* 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;
	}
	/* allocates and initializes the mei dev structure */
146
	dev = mei_me_dev_init(pdev);
147 148 149 150
	if (!dev) {
		err = -ENOMEM;
		goto release_regions;
	}
151
	hw = to_me_hw(dev);
152
	/* mapping  IO device memory */
153 154
	hw->mem_addr = pci_iomap(pdev, 0, 0);
	if (!hw->mem_addr) {
155 156 157 158 159 160 161 162 163 164
		dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
		err = -ENOMEM;
		goto free_device;
	}
	pci_enable_msi(pdev);

	 /* request and enable interrupt */
	if (pci_dev_msi_enabled(pdev))
		err = request_threaded_irq(pdev->irq,
			NULL,
165
			mei_me_irq_thread_handler,
166 167 168
			IRQF_ONESHOT, KBUILD_MODNAME, dev);
	else
		err = request_threaded_irq(pdev->irq,
169 170
			mei_me_irq_quick_handler,
			mei_me_irq_thread_handler,
171 172 173 174 175 176 177 178
			IRQF_SHARED, KBUILD_MODNAME, dev);

	if (err) {
		dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
		       pdev->irq);
		goto disable_msi;
	}

179
	if (mei_start(dev)) {
180 181 182 183 184
		dev_err(&pdev->dev, "init hw failure.\n");
		err = -ENODEV;
		goto release_irq;
	}

T
Tomas Winkler 已提交
185
	err = mei_register(dev);
186 187 188 189 190 191 192
	if (err)
		goto release_irq;

	pci_set_drvdata(pdev, dev);

	schedule_delayed_work(&dev->timer_work, HZ);

193
	dev_dbg(&pdev->dev, "initialization successful.\n");
194 195 196 197

	return 0;

release_irq:
T
Tomas Winkler 已提交
198
	mei_cancel_work(dev);
199 200 201 202
	mei_disable_interrupts(dev);
	free_irq(pdev->irq, dev);
disable_msi:
	pci_disable_msi(pdev);
203
	pci_iounmap(pdev, hw->mem_addr);
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
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;
}

/**
 * mei_remove - Device Removal Routine
 *
 * @pdev: PCI device structure
 *
 * mei_remove is called by the PCI subsystem to alert the driver
 * that it should release a PCI device.
 */
223
static void mei_me_remove(struct pci_dev *pdev)
224 225
{
	struct mei_device *dev;
226
	struct mei_me_hw *hw;
227 228 229 230 231

	dev = pci_get_drvdata(pdev);
	if (!dev)
		return;

232 233
	hw = to_me_hw(dev);

234

235
	dev_dbg(&pdev->dev, "stop\n");
236
	mei_stop(dev);
237 238 239 240 241 242 243

	/* disable interrupts */
	mei_disable_interrupts(dev);

	free_irq(pdev->irq, dev);
	pci_disable_msi(pdev);

244 245
	if (hw->mem_addr)
		pci_iounmap(pdev, hw->mem_addr);
246

T
Tomas Winkler 已提交
247 248
	mei_deregister(dev);

249 250 251 252 253 254 255 256
	kfree(dev);

	pci_release_regions(pdev);
	pci_disable_device(pdev);


}
#ifdef CONFIG_PM
257
static int mei_me_pci_suspend(struct device *device)
258 259 260 261 262 263 264
{
	struct pci_dev *pdev = to_pci_dev(device);
	struct mei_device *dev = pci_get_drvdata(pdev);

	if (!dev)
		return -ENODEV;

265
	dev_dbg(&pdev->dev, "suspend\n");
266

267 268 269
	mei_stop(dev);

	mei_disable_interrupts(dev);
270 271 272 273

	free_irq(pdev->irq, dev);
	pci_disable_msi(pdev);

274
	return 0;
275 276
}

277
static int mei_me_pci_resume(struct device *device)
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
{
	struct pci_dev *pdev = to_pci_dev(device);
	struct mei_device *dev;
	int err;

	dev = pci_get_drvdata(pdev);
	if (!dev)
		return -ENODEV;

	pci_enable_msi(pdev);

	/* request and enable interrupt */
	if (pci_dev_msi_enabled(pdev))
		err = request_threaded_irq(pdev->irq,
			NULL,
293
			mei_me_irq_thread_handler,
294 295 296
			IRQF_ONESHOT, KBUILD_MODNAME, dev);
	else
		err = request_threaded_irq(pdev->irq,
297 298
			mei_me_irq_quick_handler,
			mei_me_irq_thread_handler,
299 300 301 302 303 304 305 306 307 308
			IRQF_SHARED, KBUILD_MODNAME, dev);

	if (err) {
		dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
				pdev->irq);
		return err;
	}

	mutex_lock(&dev->device_lock);
	dev->dev_state = MEI_DEV_POWER_UP;
309
	mei_clear_interrupts(dev);
310 311 312 313 314 315 316 317
	mei_reset(dev, 1);
	mutex_unlock(&dev->device_lock);

	/* Start timer if stopped in suspend */
	schedule_delayed_work(&dev->timer_work, HZ);

	return err;
}
318 319
static SIMPLE_DEV_PM_OPS(mei_me_pm_ops, mei_me_pci_suspend, mei_me_pci_resume);
#define MEI_ME_PM_OPS	(&mei_me_pm_ops)
320
#else
321
#define MEI_ME_PM_OPS	NULL
322 323 324 325
#endif /* CONFIG_PM */
/*
 *  PCI driver structure
 */
326
static struct pci_driver mei_me_driver = {
327
	.name = KBUILD_MODNAME,
328 329 330 331 332
	.id_table = mei_me_pci_tbl,
	.probe = mei_me_probe,
	.remove = mei_me_remove,
	.shutdown = mei_me_remove,
	.driver.pm = MEI_ME_PM_OPS,
333 334
};

335
module_pci_driver(mei_me_driver);
336 337 338 339

MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
MODULE_LICENSE("GPL v2");