xref: /linux/drivers/misc/mei/pci-txe.c (revision 795536acd80bc80f41f794eb16070ac361368840)
1*795536acSTomas Winkler /*
2*795536acSTomas Winkler  *
3*795536acSTomas Winkler  * Intel Management Engine Interface (Intel MEI) Linux driver
4*795536acSTomas Winkler  * Copyright (c) 2013-2014, Intel Corporation.
5*795536acSTomas Winkler  *
6*795536acSTomas Winkler  * This program is free software; you can redistribute it and/or modify it
7*795536acSTomas Winkler  * under the terms and conditions of the GNU General Public License,
8*795536acSTomas Winkler  * version 2, as published by the Free Software Foundation.
9*795536acSTomas Winkler  *
10*795536acSTomas Winkler  * This program is distributed in the hope it will be useful, but WITHOUT
11*795536acSTomas Winkler  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*795536acSTomas Winkler  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13*795536acSTomas Winkler  * more details.
14*795536acSTomas Winkler  *
15*795536acSTomas Winkler  */
16*795536acSTomas Winkler 
17*795536acSTomas Winkler #include <linux/module.h>
18*795536acSTomas Winkler #include <linux/kernel.h>
19*795536acSTomas Winkler #include <linux/device.h>
20*795536acSTomas Winkler #include <linux/fs.h>
21*795536acSTomas Winkler #include <linux/errno.h>
22*795536acSTomas Winkler #include <linux/types.h>
23*795536acSTomas Winkler #include <linux/pci.h>
24*795536acSTomas Winkler #include <linux/init.h>
25*795536acSTomas Winkler #include <linux/sched.h>
26*795536acSTomas Winkler #include <linux/uuid.h>
27*795536acSTomas Winkler #include <linux/jiffies.h>
28*795536acSTomas Winkler #include <linux/interrupt.h>
29*795536acSTomas Winkler #include <linux/workqueue.h>
30*795536acSTomas Winkler 
31*795536acSTomas Winkler #include <linux/mei.h>
32*795536acSTomas Winkler 
33*795536acSTomas Winkler 
34*795536acSTomas Winkler #include "mei_dev.h"
35*795536acSTomas Winkler #include "hw-txe.h"
36*795536acSTomas Winkler 
37*795536acSTomas Winkler static DEFINE_PCI_DEVICE_TABLE(mei_txe_pci_tbl) = {
38*795536acSTomas Winkler 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */
39*795536acSTomas Winkler 	{0, }
40*795536acSTomas Winkler };
41*795536acSTomas Winkler MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
42*795536acSTomas Winkler 
43*795536acSTomas Winkler 
44*795536acSTomas Winkler static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
45*795536acSTomas Winkler {
46*795536acSTomas Winkler 	int i;
47*795536acSTomas Winkler 	for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
48*795536acSTomas Winkler 		if (hw->mem_addr[i]) {
49*795536acSTomas Winkler 			pci_iounmap(pdev, hw->mem_addr[i]);
50*795536acSTomas Winkler 			hw->mem_addr[i] = NULL;
51*795536acSTomas Winkler 		}
52*795536acSTomas Winkler 	}
53*795536acSTomas Winkler }
54*795536acSTomas Winkler /**
55*795536acSTomas Winkler  * mei_probe - Device Initialization Routine
56*795536acSTomas Winkler  *
57*795536acSTomas Winkler  * @pdev: PCI device structure
58*795536acSTomas Winkler  * @ent: entry in mei_txe_pci_tbl
59*795536acSTomas Winkler  *
60*795536acSTomas Winkler  * returns 0 on success, <0 on failure.
61*795536acSTomas Winkler  */
62*795536acSTomas Winkler static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
63*795536acSTomas Winkler {
64*795536acSTomas Winkler 	struct mei_device *dev;
65*795536acSTomas Winkler 	struct mei_txe_hw *hw;
66*795536acSTomas Winkler 	int err;
67*795536acSTomas Winkler 	int i;
68*795536acSTomas Winkler 
69*795536acSTomas Winkler 	/* enable pci dev */
70*795536acSTomas Winkler 	err = pci_enable_device(pdev);
71*795536acSTomas Winkler 	if (err) {
72*795536acSTomas Winkler 		dev_err(&pdev->dev, "failed to enable pci device.\n");
73*795536acSTomas Winkler 		goto end;
74*795536acSTomas Winkler 	}
75*795536acSTomas Winkler 	/* set PCI host mastering  */
76*795536acSTomas Winkler 	pci_set_master(pdev);
77*795536acSTomas Winkler 	/* pci request regions for mei driver */
78*795536acSTomas Winkler 	err = pci_request_regions(pdev, KBUILD_MODNAME);
79*795536acSTomas Winkler 	if (err) {
80*795536acSTomas Winkler 		dev_err(&pdev->dev, "failed to get pci regions.\n");
81*795536acSTomas Winkler 		goto disable_device;
82*795536acSTomas Winkler 	}
83*795536acSTomas Winkler 
84*795536acSTomas Winkler 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
85*795536acSTomas Winkler 	if (err) {
86*795536acSTomas Winkler 		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
87*795536acSTomas Winkler 		if (err) {
88*795536acSTomas Winkler 			dev_err(&pdev->dev, "No suitable DMA available.\n");
89*795536acSTomas Winkler 			goto release_regions;
90*795536acSTomas Winkler 		}
91*795536acSTomas Winkler 	}
92*795536acSTomas Winkler 
93*795536acSTomas Winkler 	/* allocates and initializes the mei dev structure */
94*795536acSTomas Winkler 	dev = mei_txe_dev_init(pdev);
95*795536acSTomas Winkler 	if (!dev) {
96*795536acSTomas Winkler 		err = -ENOMEM;
97*795536acSTomas Winkler 		goto release_regions;
98*795536acSTomas Winkler 	}
99*795536acSTomas Winkler 	hw = to_txe_hw(dev);
100*795536acSTomas Winkler 
101*795536acSTomas Winkler 	/* mapping  IO device memory */
102*795536acSTomas Winkler 	for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
103*795536acSTomas Winkler 		hw->mem_addr[i] = pci_iomap(pdev, i, 0);
104*795536acSTomas Winkler 		if (!hw->mem_addr[i]) {
105*795536acSTomas Winkler 			dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
106*795536acSTomas Winkler 			err = -ENOMEM;
107*795536acSTomas Winkler 			goto free_device;
108*795536acSTomas Winkler 		}
109*795536acSTomas Winkler 	}
110*795536acSTomas Winkler 
111*795536acSTomas Winkler 
112*795536acSTomas Winkler 	pci_enable_msi(pdev);
113*795536acSTomas Winkler 
114*795536acSTomas Winkler 	/* clear spurious interrupts */
115*795536acSTomas Winkler 	mei_clear_interrupts(dev);
116*795536acSTomas Winkler 
117*795536acSTomas Winkler 	/* request and enable interrupt  */
118*795536acSTomas Winkler 	if (pci_dev_msi_enabled(pdev))
119*795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
120*795536acSTomas Winkler 			NULL,
121*795536acSTomas Winkler 			mei_txe_irq_thread_handler,
122*795536acSTomas Winkler 			IRQF_ONESHOT, KBUILD_MODNAME, dev);
123*795536acSTomas Winkler 	else
124*795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
125*795536acSTomas Winkler 			mei_txe_irq_quick_handler,
126*795536acSTomas Winkler 			mei_txe_irq_thread_handler,
127*795536acSTomas Winkler 			IRQF_SHARED, KBUILD_MODNAME, dev);
128*795536acSTomas Winkler 	if (err) {
129*795536acSTomas Winkler 		dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
130*795536acSTomas Winkler 			pdev->irq);
131*795536acSTomas Winkler 		goto free_device;
132*795536acSTomas Winkler 	}
133*795536acSTomas Winkler 
134*795536acSTomas Winkler 	if (mei_start(dev)) {
135*795536acSTomas Winkler 		dev_err(&pdev->dev, "init hw failure.\n");
136*795536acSTomas Winkler 		err = -ENODEV;
137*795536acSTomas Winkler 		goto release_irq;
138*795536acSTomas Winkler 	}
139*795536acSTomas Winkler 
140*795536acSTomas Winkler 	err = mei_register(dev);
141*795536acSTomas Winkler 	if (err)
142*795536acSTomas Winkler 		goto release_irq;
143*795536acSTomas Winkler 
144*795536acSTomas Winkler 	pci_set_drvdata(pdev, dev);
145*795536acSTomas Winkler 
146*795536acSTomas Winkler 	return 0;
147*795536acSTomas Winkler 
148*795536acSTomas Winkler release_irq:
149*795536acSTomas Winkler 
150*795536acSTomas Winkler 	mei_cancel_work(dev);
151*795536acSTomas Winkler 
152*795536acSTomas Winkler 	/* disable interrupts */
153*795536acSTomas Winkler 	mei_disable_interrupts(dev);
154*795536acSTomas Winkler 
155*795536acSTomas Winkler 	free_irq(pdev->irq, dev);
156*795536acSTomas Winkler 	pci_disable_msi(pdev);
157*795536acSTomas Winkler 
158*795536acSTomas Winkler free_device:
159*795536acSTomas Winkler 	mei_txe_pci_iounmap(pdev, hw);
160*795536acSTomas Winkler 
161*795536acSTomas Winkler 	kfree(dev);
162*795536acSTomas Winkler release_regions:
163*795536acSTomas Winkler 	pci_release_regions(pdev);
164*795536acSTomas Winkler disable_device:
165*795536acSTomas Winkler 	pci_disable_device(pdev);
166*795536acSTomas Winkler end:
167*795536acSTomas Winkler 	dev_err(&pdev->dev, "initialization failed.\n");
168*795536acSTomas Winkler 	return err;
169*795536acSTomas Winkler }
170*795536acSTomas Winkler 
171*795536acSTomas Winkler /**
172*795536acSTomas Winkler  * mei_remove - Device Removal Routine
173*795536acSTomas Winkler  *
174*795536acSTomas Winkler  * @pdev: PCI device structure
175*795536acSTomas Winkler  *
176*795536acSTomas Winkler  * mei_remove is called by the PCI subsystem to alert the driver
177*795536acSTomas Winkler  * that it should release a PCI device.
178*795536acSTomas Winkler  */
179*795536acSTomas Winkler static void mei_txe_remove(struct pci_dev *pdev)
180*795536acSTomas Winkler {
181*795536acSTomas Winkler 	struct mei_device *dev;
182*795536acSTomas Winkler 	struct mei_txe_hw *hw;
183*795536acSTomas Winkler 
184*795536acSTomas Winkler 	dev = pci_get_drvdata(pdev);
185*795536acSTomas Winkler 	if (!dev) {
186*795536acSTomas Winkler 		dev_err(&pdev->dev, "mei: dev =NULL\n");
187*795536acSTomas Winkler 		return;
188*795536acSTomas Winkler 	}
189*795536acSTomas Winkler 
190*795536acSTomas Winkler 	hw = to_txe_hw(dev);
191*795536acSTomas Winkler 
192*795536acSTomas Winkler 	mei_stop(dev);
193*795536acSTomas Winkler 
194*795536acSTomas Winkler 	/* disable interrupts */
195*795536acSTomas Winkler 	mei_disable_interrupts(dev);
196*795536acSTomas Winkler 	free_irq(pdev->irq, dev);
197*795536acSTomas Winkler 	pci_disable_msi(pdev);
198*795536acSTomas Winkler 
199*795536acSTomas Winkler 	pci_set_drvdata(pdev, NULL);
200*795536acSTomas Winkler 
201*795536acSTomas Winkler 	mei_txe_pci_iounmap(pdev, hw);
202*795536acSTomas Winkler 
203*795536acSTomas Winkler 	mei_deregister(dev);
204*795536acSTomas Winkler 
205*795536acSTomas Winkler 	kfree(dev);
206*795536acSTomas Winkler 
207*795536acSTomas Winkler 	pci_release_regions(pdev);
208*795536acSTomas Winkler 	pci_disable_device(pdev);
209*795536acSTomas Winkler }
210*795536acSTomas Winkler 
211*795536acSTomas Winkler 
212*795536acSTomas Winkler #ifdef CONFIG_PM
213*795536acSTomas Winkler static int mei_txe_pci_suspend(struct device *device)
214*795536acSTomas Winkler {
215*795536acSTomas Winkler 	struct pci_dev *pdev = to_pci_dev(device);
216*795536acSTomas Winkler 	struct mei_device *dev = pci_get_drvdata(pdev);
217*795536acSTomas Winkler 
218*795536acSTomas Winkler 	if (!dev)
219*795536acSTomas Winkler 		return -ENODEV;
220*795536acSTomas Winkler 
221*795536acSTomas Winkler 	dev_dbg(&pdev->dev, "suspend\n");
222*795536acSTomas Winkler 
223*795536acSTomas Winkler 	mei_stop(dev);
224*795536acSTomas Winkler 
225*795536acSTomas Winkler 	mei_disable_interrupts(dev);
226*795536acSTomas Winkler 
227*795536acSTomas Winkler 	free_irq(pdev->irq, dev);
228*795536acSTomas Winkler 	pci_disable_msi(pdev);
229*795536acSTomas Winkler 
230*795536acSTomas Winkler 	return 0;
231*795536acSTomas Winkler }
232*795536acSTomas Winkler 
233*795536acSTomas Winkler static int mei_txe_pci_resume(struct device *device)
234*795536acSTomas Winkler {
235*795536acSTomas Winkler 	struct pci_dev *pdev = to_pci_dev(device);
236*795536acSTomas Winkler 	struct mei_device *dev;
237*795536acSTomas Winkler 	int err;
238*795536acSTomas Winkler 
239*795536acSTomas Winkler 	dev = pci_get_drvdata(pdev);
240*795536acSTomas Winkler 	if (!dev)
241*795536acSTomas Winkler 		return -ENODEV;
242*795536acSTomas Winkler 
243*795536acSTomas Winkler 	pci_enable_msi(pdev);
244*795536acSTomas Winkler 
245*795536acSTomas Winkler 	mei_clear_interrupts(dev);
246*795536acSTomas Winkler 
247*795536acSTomas Winkler 	/* request and enable interrupt */
248*795536acSTomas Winkler 	if (pci_dev_msi_enabled(pdev))
249*795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
250*795536acSTomas Winkler 			NULL,
251*795536acSTomas Winkler 			mei_txe_irq_thread_handler,
252*795536acSTomas Winkler 			IRQF_ONESHOT, KBUILD_MODNAME, dev);
253*795536acSTomas Winkler 	else
254*795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
255*795536acSTomas Winkler 			mei_txe_irq_quick_handler,
256*795536acSTomas Winkler 			mei_txe_irq_thread_handler,
257*795536acSTomas Winkler 			IRQF_SHARED, KBUILD_MODNAME, dev);
258*795536acSTomas Winkler 	if (err) {
259*795536acSTomas Winkler 		dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
260*795536acSTomas Winkler 				pdev->irq);
261*795536acSTomas Winkler 		return err;
262*795536acSTomas Winkler 	}
263*795536acSTomas Winkler 
264*795536acSTomas Winkler 	err = mei_restart(dev);
265*795536acSTomas Winkler 
266*795536acSTomas Winkler 	return err;
267*795536acSTomas Winkler }
268*795536acSTomas Winkler 
269*795536acSTomas Winkler static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops,
270*795536acSTomas Winkler 			 mei_txe_pci_suspend,
271*795536acSTomas Winkler 			 mei_txe_pci_resume);
272*795536acSTomas Winkler 
273*795536acSTomas Winkler #define MEI_TXE_PM_OPS	(&mei_txe_pm_ops)
274*795536acSTomas Winkler #else
275*795536acSTomas Winkler #define MEI_TXE_PM_OPS	NULL
276*795536acSTomas Winkler #endif /* CONFIG_PM */
277*795536acSTomas Winkler /*
278*795536acSTomas Winkler  *  PCI driver structure
279*795536acSTomas Winkler  */
280*795536acSTomas Winkler static struct pci_driver mei_txe_driver = {
281*795536acSTomas Winkler 	.name = KBUILD_MODNAME,
282*795536acSTomas Winkler 	.id_table = mei_txe_pci_tbl,
283*795536acSTomas Winkler 	.probe = mei_txe_probe,
284*795536acSTomas Winkler 	.remove = mei_txe_remove,
285*795536acSTomas Winkler 	.shutdown = mei_txe_remove,
286*795536acSTomas Winkler 	.driver.pm = MEI_TXE_PM_OPS,
287*795536acSTomas Winkler };
288*795536acSTomas Winkler 
289*795536acSTomas Winkler module_pci_driver(mei_txe_driver);
290*795536acSTomas Winkler 
291*795536acSTomas Winkler MODULE_AUTHOR("Intel Corporation");
292*795536acSTomas Winkler MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface");
293*795536acSTomas Winkler MODULE_LICENSE("GPL v2");
294