xref: /linux/drivers/misc/mei/pci-txe.c (revision a05f8f86e49749f239c49257db1d3ac6f474f0dd)
1795536acSTomas Winkler /*
2795536acSTomas Winkler  *
3795536acSTomas Winkler  * Intel Management Engine Interface (Intel MEI) Linux driver
4795536acSTomas Winkler  * Copyright (c) 2013-2014, Intel Corporation.
5795536acSTomas Winkler  *
6795536acSTomas Winkler  * This program is free software; you can redistribute it and/or modify it
7795536acSTomas Winkler  * under the terms and conditions of the GNU General Public License,
8795536acSTomas Winkler  * version 2, as published by the Free Software Foundation.
9795536acSTomas Winkler  *
10795536acSTomas Winkler  * This program is distributed in the hope it will be useful, but WITHOUT
11795536acSTomas Winkler  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12795536acSTomas Winkler  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13795536acSTomas Winkler  * more details.
14795536acSTomas Winkler  *
15795536acSTomas Winkler  */
16795536acSTomas Winkler 
17795536acSTomas Winkler #include <linux/module.h>
18795536acSTomas Winkler #include <linux/kernel.h>
19795536acSTomas Winkler #include <linux/device.h>
20795536acSTomas Winkler #include <linux/fs.h>
21795536acSTomas Winkler #include <linux/errno.h>
22795536acSTomas Winkler #include <linux/types.h>
23795536acSTomas Winkler #include <linux/pci.h>
24795536acSTomas Winkler #include <linux/init.h>
25795536acSTomas Winkler #include <linux/sched.h>
26795536acSTomas Winkler #include <linux/uuid.h>
27795536acSTomas Winkler #include <linux/jiffies.h>
28795536acSTomas Winkler #include <linux/interrupt.h>
29795536acSTomas Winkler #include <linux/workqueue.h>
30795536acSTomas Winkler 
31795536acSTomas Winkler #include <linux/mei.h>
32795536acSTomas Winkler 
33795536acSTomas Winkler 
34795536acSTomas Winkler #include "mei_dev.h"
35795536acSTomas Winkler #include "hw-txe.h"
36795536acSTomas Winkler 
37*a05f8f86STomas Winkler static const struct pci_device_id mei_txe_pci_tbl[] = {
38795536acSTomas Winkler 	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F18)}, /* Baytrail */
39795536acSTomas Winkler 	{0, }
40795536acSTomas Winkler };
41795536acSTomas Winkler MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
42795536acSTomas Winkler 
43795536acSTomas Winkler 
44795536acSTomas Winkler static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
45795536acSTomas Winkler {
46795536acSTomas Winkler 	int i;
47795536acSTomas Winkler 	for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
48795536acSTomas Winkler 		if (hw->mem_addr[i]) {
49795536acSTomas Winkler 			pci_iounmap(pdev, hw->mem_addr[i]);
50795536acSTomas Winkler 			hw->mem_addr[i] = NULL;
51795536acSTomas Winkler 		}
52795536acSTomas Winkler 	}
53795536acSTomas Winkler }
54795536acSTomas Winkler /**
55795536acSTomas Winkler  * mei_probe - Device Initialization Routine
56795536acSTomas Winkler  *
57795536acSTomas Winkler  * @pdev: PCI device structure
58795536acSTomas Winkler  * @ent: entry in mei_txe_pci_tbl
59795536acSTomas Winkler  *
60795536acSTomas Winkler  * returns 0 on success, <0 on failure.
61795536acSTomas Winkler  */
62795536acSTomas Winkler static int mei_txe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
63795536acSTomas Winkler {
64795536acSTomas Winkler 	struct mei_device *dev;
65795536acSTomas Winkler 	struct mei_txe_hw *hw;
66795536acSTomas Winkler 	int err;
67795536acSTomas Winkler 	int i;
68795536acSTomas Winkler 
69795536acSTomas Winkler 	/* enable pci dev */
70795536acSTomas Winkler 	err = pci_enable_device(pdev);
71795536acSTomas Winkler 	if (err) {
72795536acSTomas Winkler 		dev_err(&pdev->dev, "failed to enable pci device.\n");
73795536acSTomas Winkler 		goto end;
74795536acSTomas Winkler 	}
75795536acSTomas Winkler 	/* set PCI host mastering  */
76795536acSTomas Winkler 	pci_set_master(pdev);
77795536acSTomas Winkler 	/* pci request regions for mei driver */
78795536acSTomas Winkler 	err = pci_request_regions(pdev, KBUILD_MODNAME);
79795536acSTomas Winkler 	if (err) {
80795536acSTomas Winkler 		dev_err(&pdev->dev, "failed to get pci regions.\n");
81795536acSTomas Winkler 		goto disable_device;
82795536acSTomas Winkler 	}
83795536acSTomas Winkler 
84795536acSTomas Winkler 	err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
85795536acSTomas Winkler 	if (err) {
86795536acSTomas Winkler 		err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
87795536acSTomas Winkler 		if (err) {
88795536acSTomas Winkler 			dev_err(&pdev->dev, "No suitable DMA available.\n");
89795536acSTomas Winkler 			goto release_regions;
90795536acSTomas Winkler 		}
91795536acSTomas Winkler 	}
92795536acSTomas Winkler 
93795536acSTomas Winkler 	/* allocates and initializes the mei dev structure */
94795536acSTomas Winkler 	dev = mei_txe_dev_init(pdev);
95795536acSTomas Winkler 	if (!dev) {
96795536acSTomas Winkler 		err = -ENOMEM;
97795536acSTomas Winkler 		goto release_regions;
98795536acSTomas Winkler 	}
99795536acSTomas Winkler 	hw = to_txe_hw(dev);
100795536acSTomas Winkler 
101795536acSTomas Winkler 	/* mapping  IO device memory */
102795536acSTomas Winkler 	for (i = SEC_BAR; i < NUM_OF_MEM_BARS; i++) {
103795536acSTomas Winkler 		hw->mem_addr[i] = pci_iomap(pdev, i, 0);
104795536acSTomas Winkler 		if (!hw->mem_addr[i]) {
105795536acSTomas Winkler 			dev_err(&pdev->dev, "mapping I/O device memory failure.\n");
106795536acSTomas Winkler 			err = -ENOMEM;
107795536acSTomas Winkler 			goto free_device;
108795536acSTomas Winkler 		}
109795536acSTomas Winkler 	}
110795536acSTomas Winkler 
111795536acSTomas Winkler 
112795536acSTomas Winkler 	pci_enable_msi(pdev);
113795536acSTomas Winkler 
114795536acSTomas Winkler 	/* clear spurious interrupts */
115795536acSTomas Winkler 	mei_clear_interrupts(dev);
116795536acSTomas Winkler 
117795536acSTomas Winkler 	/* request and enable interrupt  */
118795536acSTomas Winkler 	if (pci_dev_msi_enabled(pdev))
119795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
120795536acSTomas Winkler 			NULL,
121795536acSTomas Winkler 			mei_txe_irq_thread_handler,
122795536acSTomas Winkler 			IRQF_ONESHOT, KBUILD_MODNAME, dev);
123795536acSTomas Winkler 	else
124795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
125795536acSTomas Winkler 			mei_txe_irq_quick_handler,
126795536acSTomas Winkler 			mei_txe_irq_thread_handler,
127795536acSTomas Winkler 			IRQF_SHARED, KBUILD_MODNAME, dev);
128795536acSTomas Winkler 	if (err) {
129795536acSTomas Winkler 		dev_err(&pdev->dev, "mei: request_threaded_irq failure. irq = %d\n",
130795536acSTomas Winkler 			pdev->irq);
131795536acSTomas Winkler 		goto free_device;
132795536acSTomas Winkler 	}
133795536acSTomas Winkler 
134795536acSTomas Winkler 	if (mei_start(dev)) {
135795536acSTomas Winkler 		dev_err(&pdev->dev, "init hw failure.\n");
136795536acSTomas Winkler 		err = -ENODEV;
137795536acSTomas Winkler 		goto release_irq;
138795536acSTomas Winkler 	}
139795536acSTomas Winkler 
140795536acSTomas Winkler 	err = mei_register(dev);
141795536acSTomas Winkler 	if (err)
142795536acSTomas Winkler 		goto release_irq;
143795536acSTomas Winkler 
144795536acSTomas Winkler 	pci_set_drvdata(pdev, dev);
145795536acSTomas Winkler 
146795536acSTomas Winkler 	return 0;
147795536acSTomas Winkler 
148795536acSTomas Winkler release_irq:
149795536acSTomas Winkler 
150795536acSTomas Winkler 	mei_cancel_work(dev);
151795536acSTomas Winkler 
152795536acSTomas Winkler 	/* disable interrupts */
153795536acSTomas Winkler 	mei_disable_interrupts(dev);
154795536acSTomas Winkler 
155795536acSTomas Winkler 	free_irq(pdev->irq, dev);
156795536acSTomas Winkler 	pci_disable_msi(pdev);
157795536acSTomas Winkler 
158795536acSTomas Winkler free_device:
159795536acSTomas Winkler 	mei_txe_pci_iounmap(pdev, hw);
160795536acSTomas Winkler 
161795536acSTomas Winkler 	kfree(dev);
162795536acSTomas Winkler release_regions:
163795536acSTomas Winkler 	pci_release_regions(pdev);
164795536acSTomas Winkler disable_device:
165795536acSTomas Winkler 	pci_disable_device(pdev);
166795536acSTomas Winkler end:
167795536acSTomas Winkler 	dev_err(&pdev->dev, "initialization failed.\n");
168795536acSTomas Winkler 	return err;
169795536acSTomas Winkler }
170795536acSTomas Winkler 
171795536acSTomas Winkler /**
172795536acSTomas Winkler  * mei_remove - Device Removal Routine
173795536acSTomas Winkler  *
174795536acSTomas Winkler  * @pdev: PCI device structure
175795536acSTomas Winkler  *
176795536acSTomas Winkler  * mei_remove is called by the PCI subsystem to alert the driver
177795536acSTomas Winkler  * that it should release a PCI device.
178795536acSTomas Winkler  */
179795536acSTomas Winkler static void mei_txe_remove(struct pci_dev *pdev)
180795536acSTomas Winkler {
181795536acSTomas Winkler 	struct mei_device *dev;
182795536acSTomas Winkler 	struct mei_txe_hw *hw;
183795536acSTomas Winkler 
184795536acSTomas Winkler 	dev = pci_get_drvdata(pdev);
185795536acSTomas Winkler 	if (!dev) {
186795536acSTomas Winkler 		dev_err(&pdev->dev, "mei: dev =NULL\n");
187795536acSTomas Winkler 		return;
188795536acSTomas Winkler 	}
189795536acSTomas Winkler 
190795536acSTomas Winkler 	hw = to_txe_hw(dev);
191795536acSTomas Winkler 
192795536acSTomas Winkler 	mei_stop(dev);
193795536acSTomas Winkler 
194795536acSTomas Winkler 	/* disable interrupts */
195795536acSTomas Winkler 	mei_disable_interrupts(dev);
196795536acSTomas Winkler 	free_irq(pdev->irq, dev);
197795536acSTomas Winkler 	pci_disable_msi(pdev);
198795536acSTomas Winkler 
199795536acSTomas Winkler 	pci_set_drvdata(pdev, NULL);
200795536acSTomas Winkler 
201795536acSTomas Winkler 	mei_txe_pci_iounmap(pdev, hw);
202795536acSTomas Winkler 
203795536acSTomas Winkler 	mei_deregister(dev);
204795536acSTomas Winkler 
205795536acSTomas Winkler 	kfree(dev);
206795536acSTomas Winkler 
207795536acSTomas Winkler 	pci_release_regions(pdev);
208795536acSTomas Winkler 	pci_disable_device(pdev);
209795536acSTomas Winkler }
210795536acSTomas Winkler 
211795536acSTomas Winkler 
212e0270addSTomas Winkler #ifdef CONFIG_PM_SLEEP
213795536acSTomas Winkler static int mei_txe_pci_suspend(struct device *device)
214795536acSTomas Winkler {
215795536acSTomas Winkler 	struct pci_dev *pdev = to_pci_dev(device);
216795536acSTomas Winkler 	struct mei_device *dev = pci_get_drvdata(pdev);
217795536acSTomas Winkler 
218795536acSTomas Winkler 	if (!dev)
219795536acSTomas Winkler 		return -ENODEV;
220795536acSTomas Winkler 
221795536acSTomas Winkler 	dev_dbg(&pdev->dev, "suspend\n");
222795536acSTomas Winkler 
223795536acSTomas Winkler 	mei_stop(dev);
224795536acSTomas Winkler 
225795536acSTomas Winkler 	mei_disable_interrupts(dev);
226795536acSTomas Winkler 
227795536acSTomas Winkler 	free_irq(pdev->irq, dev);
228795536acSTomas Winkler 	pci_disable_msi(pdev);
229795536acSTomas Winkler 
230795536acSTomas Winkler 	return 0;
231795536acSTomas Winkler }
232795536acSTomas Winkler 
233795536acSTomas Winkler static int mei_txe_pci_resume(struct device *device)
234795536acSTomas Winkler {
235795536acSTomas Winkler 	struct pci_dev *pdev = to_pci_dev(device);
236795536acSTomas Winkler 	struct mei_device *dev;
237795536acSTomas Winkler 	int err;
238795536acSTomas Winkler 
239795536acSTomas Winkler 	dev = pci_get_drvdata(pdev);
240795536acSTomas Winkler 	if (!dev)
241795536acSTomas Winkler 		return -ENODEV;
242795536acSTomas Winkler 
243795536acSTomas Winkler 	pci_enable_msi(pdev);
244795536acSTomas Winkler 
245795536acSTomas Winkler 	mei_clear_interrupts(dev);
246795536acSTomas Winkler 
247795536acSTomas Winkler 	/* request and enable interrupt */
248795536acSTomas Winkler 	if (pci_dev_msi_enabled(pdev))
249795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
250795536acSTomas Winkler 			NULL,
251795536acSTomas Winkler 			mei_txe_irq_thread_handler,
252795536acSTomas Winkler 			IRQF_ONESHOT, KBUILD_MODNAME, dev);
253795536acSTomas Winkler 	else
254795536acSTomas Winkler 		err = request_threaded_irq(pdev->irq,
255795536acSTomas Winkler 			mei_txe_irq_quick_handler,
256795536acSTomas Winkler 			mei_txe_irq_thread_handler,
257795536acSTomas Winkler 			IRQF_SHARED, KBUILD_MODNAME, dev);
258795536acSTomas Winkler 	if (err) {
259795536acSTomas Winkler 		dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
260795536acSTomas Winkler 				pdev->irq);
261795536acSTomas Winkler 		return err;
262795536acSTomas Winkler 	}
263795536acSTomas Winkler 
264795536acSTomas Winkler 	err = mei_restart(dev);
265795536acSTomas Winkler 
266795536acSTomas Winkler 	return err;
267795536acSTomas Winkler }
268795536acSTomas Winkler 
269795536acSTomas Winkler static SIMPLE_DEV_PM_OPS(mei_txe_pm_ops,
270795536acSTomas Winkler 			 mei_txe_pci_suspend,
271795536acSTomas Winkler 			 mei_txe_pci_resume);
272795536acSTomas Winkler 
273795536acSTomas Winkler #define MEI_TXE_PM_OPS	(&mei_txe_pm_ops)
274795536acSTomas Winkler #else
275795536acSTomas Winkler #define MEI_TXE_PM_OPS	NULL
276e0270addSTomas Winkler #endif /* CONFIG_PM_SLEEP */
277795536acSTomas Winkler /*
278795536acSTomas Winkler  *  PCI driver structure
279795536acSTomas Winkler  */
280795536acSTomas Winkler static struct pci_driver mei_txe_driver = {
281795536acSTomas Winkler 	.name = KBUILD_MODNAME,
282795536acSTomas Winkler 	.id_table = mei_txe_pci_tbl,
283795536acSTomas Winkler 	.probe = mei_txe_probe,
284795536acSTomas Winkler 	.remove = mei_txe_remove,
285795536acSTomas Winkler 	.shutdown = mei_txe_remove,
286795536acSTomas Winkler 	.driver.pm = MEI_TXE_PM_OPS,
287795536acSTomas Winkler };
288795536acSTomas Winkler 
289795536acSTomas Winkler module_pci_driver(mei_txe_driver);
290795536acSTomas Winkler 
291795536acSTomas Winkler MODULE_AUTHOR("Intel Corporation");
292795536acSTomas Winkler MODULE_DESCRIPTION("Intel(R) Trusted Execution Environment Interface");
293795536acSTomas Winkler MODULE_LICENSE("GPL v2");
294