1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2003-2020, Intel Corporation. All rights reserved.
4*4882a593Smuzhiyun * Intel Management Engine Interface (Intel MEI) Linux driver
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/module.h>
8*4882a593Smuzhiyun #include <linux/kernel.h>
9*4882a593Smuzhiyun #include <linux/device.h>
10*4882a593Smuzhiyun #include <linux/errno.h>
11*4882a593Smuzhiyun #include <linux/types.h>
12*4882a593Smuzhiyun #include <linux/pci.h>
13*4882a593Smuzhiyun #include <linux/sched.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include <linux/pm_domain.h>
17*4882a593Smuzhiyun #include <linux/pm_runtime.h>
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #include <linux/mei.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include "mei_dev.h"
22*4882a593Smuzhiyun #include "client.h"
23*4882a593Smuzhiyun #include "hw-me-regs.h"
24*4882a593Smuzhiyun #include "hw-me.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* mei_pci_tbl - PCI Device ID Table */
27*4882a593Smuzhiyun static const struct pci_device_id mei_me_pci_tbl[] = {
28*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_82946GZ, MEI_ME_ICH_CFG)},
29*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_82G35, MEI_ME_ICH_CFG)},
30*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_82Q965, MEI_ME_ICH_CFG)},
31*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_82G965, MEI_ME_ICH_CFG)},
32*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_82GM965, MEI_ME_ICH_CFG)},
33*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_82GME965, MEI_ME_ICH_CFG)},
34*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q35, MEI_ME_ICH_CFG)},
35*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82G33, MEI_ME_ICH_CFG)},
36*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82Q33, MEI_ME_ICH_CFG)},
37*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_82X38, MEI_ME_ICH_CFG)},
38*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_3200, MEI_ME_ICH_CFG)},
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_6, MEI_ME_ICH_CFG)},
41*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_7, MEI_ME_ICH_CFG)},
42*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_8, MEI_ME_ICH_CFG)},
43*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_9, MEI_ME_ICH_CFG)},
44*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9_10, MEI_ME_ICH_CFG)},
45*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_1, MEI_ME_ICH_CFG)},
46*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_2, MEI_ME_ICH_CFG)},
47*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_3, MEI_ME_ICH_CFG)},
48*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH9M_4, MEI_ME_ICH_CFG)},
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_1, MEI_ME_ICH10_CFG)},
51*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_2, MEI_ME_ICH10_CFG)},
52*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_3, MEI_ME_ICH10_CFG)},
53*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICH10_4, MEI_ME_ICH10_CFG)},
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_1, MEI_ME_PCH6_CFG)},
56*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_IBXPK_2, MEI_ME_PCH6_CFG)},
57*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CPT_1, MEI_ME_PCH_CPT_PBG_CFG)},
58*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_PBG_1, MEI_ME_PCH_CPT_PBG_CFG)},
59*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_1, MEI_ME_PCH7_CFG)},
60*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_2, MEI_ME_PCH7_CFG)},
61*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_PPT_3, MEI_ME_PCH7_CFG)},
62*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_H, MEI_ME_PCH8_SPS_4_CFG)},
63*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_W, MEI_ME_PCH8_SPS_4_CFG)},
64*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_LP, MEI_ME_PCH8_CFG)},
65*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_LPT_HR, MEI_ME_PCH8_SPS_4_CFG)},
66*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP, MEI_ME_PCH8_CFG)},
67*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_WPT_LP_2, MEI_ME_PCH8_CFG)},
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)},
70*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)},
71*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_3, MEI_ME_PCH8_ITOUCH_CFG)},
72*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_4_CFG)},
73*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_4_CFG)},
74*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_SPS_4_CFG)},
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, MEI_ME_PCH8_CFG)},
77*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, MEI_ME_PCH8_CFG)},
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_DNV_IE, MEI_ME_PCH8_CFG)},
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_GLK, MEI_ME_PCH8_CFG)},
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, MEI_ME_PCH8_CFG)},
84*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, MEI_ME_PCH8_CFG)},
85*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_3, MEI_ME_PCH8_CFG)},
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP, MEI_ME_PCH12_CFG)},
88*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_LP_3, MEI_ME_PCH8_ITOUCH_CFG)},
89*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H, MEI_ME_PCH12_SPS_CFG)},
90*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CNP_H_3, MEI_ME_PCH12_SPS_ITOUCH_CFG)},
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP, MEI_ME_PCH12_CFG)},
93*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_LP_3, MEI_ME_PCH8_ITOUCH_CFG)},
94*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_V, MEI_ME_PCH12_CFG)},
95*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H, MEI_ME_PCH12_CFG)},
96*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_ITOUCH_CFG)},
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
99*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_N, MEI_ME_PCH12_CFG)},
100*4882a593Smuzhiyun
101*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH15_CFG)},
102*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_H, MEI_ME_PCH15_SPS_CFG)},
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_JSP_N, MEI_ME_PCH15_CFG)},
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_MCC, MEI_ME_PCH15_CFG)},
107*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_MCC_4, MEI_ME_PCH8_CFG)},
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_CDF, MEI_ME_PCH8_CFG)},
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_EBG, MEI_ME_PCH15_SPS_CFG)},
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_S, MEI_ME_PCH15_CFG)},
114*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_LP, MEI_ME_PCH15_CFG)},
115*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_P, MEI_ME_PCH15_CFG)},
116*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_ADP_N, MEI_ME_PCH15_CFG)},
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun {MEI_PCI_DEVICE(MEI_DEV_ID_RPL_S, MEI_ME_PCH15_CFG)},
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun /* required last entry */
121*4882a593Smuzhiyun {0, }
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl);
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun #ifdef CONFIG_PM
127*4882a593Smuzhiyun static inline void mei_me_set_pm_domain(struct mei_device *dev);
128*4882a593Smuzhiyun static inline void mei_me_unset_pm_domain(struct mei_device *dev);
129*4882a593Smuzhiyun #else
mei_me_set_pm_domain(struct mei_device * dev)130*4882a593Smuzhiyun static inline void mei_me_set_pm_domain(struct mei_device *dev) {}
mei_me_unset_pm_domain(struct mei_device * dev)131*4882a593Smuzhiyun static inline void mei_me_unset_pm_domain(struct mei_device *dev) {}
132*4882a593Smuzhiyun #endif /* CONFIG_PM */
133*4882a593Smuzhiyun
mei_me_read_fws(const struct mei_device * dev,int where,u32 * val)134*4882a593Smuzhiyun static int mei_me_read_fws(const struct mei_device *dev, int where, u32 *val)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(dev->dev);
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun return pci_read_config_dword(pdev, where, val);
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun /**
142*4882a593Smuzhiyun * mei_me_quirk_probe - probe for devices that doesn't valid ME interface
143*4882a593Smuzhiyun *
144*4882a593Smuzhiyun * @pdev: PCI device structure
145*4882a593Smuzhiyun * @cfg: per generation config
146*4882a593Smuzhiyun *
147*4882a593Smuzhiyun * Return: true if ME Interface is valid, false otherwise
148*4882a593Smuzhiyun */
mei_me_quirk_probe(struct pci_dev * pdev,const struct mei_cfg * cfg)149*4882a593Smuzhiyun static bool mei_me_quirk_probe(struct pci_dev *pdev,
150*4882a593Smuzhiyun const struct mei_cfg *cfg)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun if (cfg->quirk_probe && cfg->quirk_probe(pdev)) {
153*4882a593Smuzhiyun dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
154*4882a593Smuzhiyun return false;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun return true;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /**
161*4882a593Smuzhiyun * mei_me_probe - Device Initialization Routine
162*4882a593Smuzhiyun *
163*4882a593Smuzhiyun * @pdev: PCI device structure
164*4882a593Smuzhiyun * @ent: entry in kcs_pci_tbl
165*4882a593Smuzhiyun *
166*4882a593Smuzhiyun * Return: 0 on success, <0 on failure.
167*4882a593Smuzhiyun */
mei_me_probe(struct pci_dev * pdev,const struct pci_device_id * ent)168*4882a593Smuzhiyun static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun const struct mei_cfg *cfg;
171*4882a593Smuzhiyun struct mei_device *dev;
172*4882a593Smuzhiyun struct mei_me_hw *hw;
173*4882a593Smuzhiyun unsigned int irqflags;
174*4882a593Smuzhiyun int err;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun cfg = mei_me_get_cfg(ent->driver_data);
177*4882a593Smuzhiyun if (!cfg)
178*4882a593Smuzhiyun return -ENODEV;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun if (!mei_me_quirk_probe(pdev, cfg))
181*4882a593Smuzhiyun return -ENODEV;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun /* enable pci dev */
184*4882a593Smuzhiyun err = pcim_enable_device(pdev);
185*4882a593Smuzhiyun if (err) {
186*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to enable pci device.\n");
187*4882a593Smuzhiyun goto end;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun /* set PCI host mastering */
190*4882a593Smuzhiyun pci_set_master(pdev);
191*4882a593Smuzhiyun /* pci request regions and mapping IO device memory for mei driver */
192*4882a593Smuzhiyun err = pcim_iomap_regions(pdev, BIT(0), KBUILD_MODNAME);
193*4882a593Smuzhiyun if (err) {
194*4882a593Smuzhiyun dev_err(&pdev->dev, "failed to get pci regions.\n");
195*4882a593Smuzhiyun goto end;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) ||
199*4882a593Smuzhiyun dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) {
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun err = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
202*4882a593Smuzhiyun if (err)
203*4882a593Smuzhiyun err = dma_set_coherent_mask(&pdev->dev,
204*4882a593Smuzhiyun DMA_BIT_MASK(32));
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun if (err) {
207*4882a593Smuzhiyun dev_err(&pdev->dev, "No usable DMA configuration, aborting\n");
208*4882a593Smuzhiyun goto end;
209*4882a593Smuzhiyun }
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* allocates and initializes the mei dev structure */
212*4882a593Smuzhiyun dev = mei_me_dev_init(&pdev->dev, cfg);
213*4882a593Smuzhiyun if (!dev) {
214*4882a593Smuzhiyun err = -ENOMEM;
215*4882a593Smuzhiyun goto end;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun hw = to_me_hw(dev);
218*4882a593Smuzhiyun hw->mem_addr = pcim_iomap_table(pdev)[0];
219*4882a593Smuzhiyun hw->read_fws = mei_me_read_fws;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun pci_enable_msi(pdev);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun hw->irq = pdev->irq;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun /* request and enable interrupt */
226*4882a593Smuzhiyun irqflags = pci_dev_msi_enabled(pdev) ? IRQF_ONESHOT : IRQF_SHARED;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun err = request_threaded_irq(pdev->irq,
229*4882a593Smuzhiyun mei_me_irq_quick_handler,
230*4882a593Smuzhiyun mei_me_irq_thread_handler,
231*4882a593Smuzhiyun irqflags, KBUILD_MODNAME, dev);
232*4882a593Smuzhiyun if (err) {
233*4882a593Smuzhiyun dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
234*4882a593Smuzhiyun pdev->irq);
235*4882a593Smuzhiyun goto end;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (mei_start(dev)) {
239*4882a593Smuzhiyun dev_err(&pdev->dev, "init hw failure.\n");
240*4882a593Smuzhiyun err = -ENODEV;
241*4882a593Smuzhiyun goto release_irq;
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun pm_runtime_set_autosuspend_delay(&pdev->dev, MEI_ME_RPM_TIMEOUT);
245*4882a593Smuzhiyun pm_runtime_use_autosuspend(&pdev->dev);
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun err = mei_register(dev, &pdev->dev);
248*4882a593Smuzhiyun if (err)
249*4882a593Smuzhiyun goto stop;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun pci_set_drvdata(pdev, dev);
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun /*
254*4882a593Smuzhiyun * MEI requires to resume from runtime suspend mode
255*4882a593Smuzhiyun * in order to perform link reset flow upon system suspend.
256*4882a593Smuzhiyun */
257*4882a593Smuzhiyun dev_pm_set_driver_flags(&pdev->dev, DPM_FLAG_NO_DIRECT_COMPLETE);
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /*
260*4882a593Smuzhiyun * ME maps runtime suspend/resume to D0i states,
261*4882a593Smuzhiyun * hence we need to go around native PCI runtime service which
262*4882a593Smuzhiyun * eventually brings the device into D3cold/hot state,
263*4882a593Smuzhiyun * but the mei device cannot wake up from D3 unlike from D0i3.
264*4882a593Smuzhiyun * To get around the PCI device native runtime pm,
265*4882a593Smuzhiyun * ME uses runtime pm domain handlers which take precedence
266*4882a593Smuzhiyun * over the driver's pm handlers.
267*4882a593Smuzhiyun */
268*4882a593Smuzhiyun mei_me_set_pm_domain(dev);
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (mei_pg_is_enabled(dev)) {
271*4882a593Smuzhiyun pm_runtime_put_noidle(&pdev->dev);
272*4882a593Smuzhiyun if (hw->d0i3_supported)
273*4882a593Smuzhiyun pm_runtime_allow(&pdev->dev);
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun dev_dbg(&pdev->dev, "initialization successful.\n");
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun return 0;
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun stop:
281*4882a593Smuzhiyun mei_stop(dev);
282*4882a593Smuzhiyun release_irq:
283*4882a593Smuzhiyun mei_cancel_work(dev);
284*4882a593Smuzhiyun mei_disable_interrupts(dev);
285*4882a593Smuzhiyun free_irq(pdev->irq, dev);
286*4882a593Smuzhiyun end:
287*4882a593Smuzhiyun dev_err(&pdev->dev, "initialization failed.\n");
288*4882a593Smuzhiyun return err;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun /**
292*4882a593Smuzhiyun * mei_me_shutdown - Device Removal Routine
293*4882a593Smuzhiyun *
294*4882a593Smuzhiyun * @pdev: PCI device structure
295*4882a593Smuzhiyun *
296*4882a593Smuzhiyun * mei_me_shutdown is called from the reboot notifier
297*4882a593Smuzhiyun * it's a simplified version of remove so we go down
298*4882a593Smuzhiyun * faster.
299*4882a593Smuzhiyun */
mei_me_shutdown(struct pci_dev * pdev)300*4882a593Smuzhiyun static void mei_me_shutdown(struct pci_dev *pdev)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun struct mei_device *dev;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun dev = pci_get_drvdata(pdev);
305*4882a593Smuzhiyun if (!dev)
306*4882a593Smuzhiyun return;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun dev_dbg(&pdev->dev, "shutdown\n");
309*4882a593Smuzhiyun mei_stop(dev);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun mei_me_unset_pm_domain(dev);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun mei_disable_interrupts(dev);
314*4882a593Smuzhiyun free_irq(pdev->irq, dev);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun /**
318*4882a593Smuzhiyun * mei_me_remove - Device Removal Routine
319*4882a593Smuzhiyun *
320*4882a593Smuzhiyun * @pdev: PCI device structure
321*4882a593Smuzhiyun *
322*4882a593Smuzhiyun * mei_me_remove is called by the PCI subsystem to alert the driver
323*4882a593Smuzhiyun * that it should release a PCI device.
324*4882a593Smuzhiyun */
mei_me_remove(struct pci_dev * pdev)325*4882a593Smuzhiyun static void mei_me_remove(struct pci_dev *pdev)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun struct mei_device *dev;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun dev = pci_get_drvdata(pdev);
330*4882a593Smuzhiyun if (!dev)
331*4882a593Smuzhiyun return;
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun if (mei_pg_is_enabled(dev))
334*4882a593Smuzhiyun pm_runtime_get_noresume(&pdev->dev);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun dev_dbg(&pdev->dev, "stop\n");
337*4882a593Smuzhiyun mei_stop(dev);
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun mei_me_unset_pm_domain(dev);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun mei_disable_interrupts(dev);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun free_irq(pdev->irq, dev);
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun mei_deregister(dev);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
mei_me_pci_suspend(struct device * device)349*4882a593Smuzhiyun static int mei_me_pci_suspend(struct device *device)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(device);
352*4882a593Smuzhiyun struct mei_device *dev = pci_get_drvdata(pdev);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun if (!dev)
355*4882a593Smuzhiyun return -ENODEV;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun dev_dbg(&pdev->dev, "suspend\n");
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun mei_stop(dev);
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun mei_disable_interrupts(dev);
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun free_irq(pdev->irq, dev);
364*4882a593Smuzhiyun pci_disable_msi(pdev);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun return 0;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
mei_me_pci_resume(struct device * device)369*4882a593Smuzhiyun static int mei_me_pci_resume(struct device *device)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(device);
372*4882a593Smuzhiyun struct mei_device *dev;
373*4882a593Smuzhiyun unsigned int irqflags;
374*4882a593Smuzhiyun int err;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun dev = pci_get_drvdata(pdev);
377*4882a593Smuzhiyun if (!dev)
378*4882a593Smuzhiyun return -ENODEV;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun pci_enable_msi(pdev);
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun irqflags = pci_dev_msi_enabled(pdev) ? IRQF_ONESHOT : IRQF_SHARED;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun /* request and enable interrupt */
385*4882a593Smuzhiyun err = request_threaded_irq(pdev->irq,
386*4882a593Smuzhiyun mei_me_irq_quick_handler,
387*4882a593Smuzhiyun mei_me_irq_thread_handler,
388*4882a593Smuzhiyun irqflags, KBUILD_MODNAME, dev);
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun if (err) {
391*4882a593Smuzhiyun dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
392*4882a593Smuzhiyun pdev->irq);
393*4882a593Smuzhiyun return err;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun err = mei_restart(dev);
397*4882a593Smuzhiyun if (err)
398*4882a593Smuzhiyun return err;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun /* Start timer if stopped in suspend */
401*4882a593Smuzhiyun schedule_delayed_work(&dev->timer_work, HZ);
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun return 0;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun #ifdef CONFIG_PM
mei_me_pm_runtime_idle(struct device * device)408*4882a593Smuzhiyun static int mei_me_pm_runtime_idle(struct device *device)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun struct mei_device *dev;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun dev_dbg(device, "rpm: me: runtime_idle\n");
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun dev = dev_get_drvdata(device);
415*4882a593Smuzhiyun if (!dev)
416*4882a593Smuzhiyun return -ENODEV;
417*4882a593Smuzhiyun if (mei_write_is_idle(dev))
418*4882a593Smuzhiyun pm_runtime_autosuspend(device);
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun return -EBUSY;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun
mei_me_pm_runtime_suspend(struct device * device)423*4882a593Smuzhiyun static int mei_me_pm_runtime_suspend(struct device *device)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun struct mei_device *dev;
426*4882a593Smuzhiyun int ret;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun dev_dbg(device, "rpm: me: runtime suspend\n");
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun dev = dev_get_drvdata(device);
431*4882a593Smuzhiyun if (!dev)
432*4882a593Smuzhiyun return -ENODEV;
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun mutex_lock(&dev->device_lock);
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun if (mei_write_is_idle(dev))
437*4882a593Smuzhiyun ret = mei_me_pg_enter_sync(dev);
438*4882a593Smuzhiyun else
439*4882a593Smuzhiyun ret = -EAGAIN;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun mutex_unlock(&dev->device_lock);
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun dev_dbg(device, "rpm: me: runtime suspend ret=%d\n", ret);
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun if (ret && ret != -EAGAIN)
446*4882a593Smuzhiyun schedule_work(&dev->reset_work);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun return ret;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun
mei_me_pm_runtime_resume(struct device * device)451*4882a593Smuzhiyun static int mei_me_pm_runtime_resume(struct device *device)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun struct mei_device *dev;
454*4882a593Smuzhiyun int ret;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun dev_dbg(device, "rpm: me: runtime resume\n");
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun dev = dev_get_drvdata(device);
459*4882a593Smuzhiyun if (!dev)
460*4882a593Smuzhiyun return -ENODEV;
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun mutex_lock(&dev->device_lock);
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun ret = mei_me_pg_exit_sync(dev);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun mutex_unlock(&dev->device_lock);
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun dev_dbg(device, "rpm: me: runtime resume ret = %d\n", ret);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun if (ret)
471*4882a593Smuzhiyun schedule_work(&dev->reset_work);
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun return ret;
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /**
477*4882a593Smuzhiyun * mei_me_set_pm_domain - fill and set pm domain structure for device
478*4882a593Smuzhiyun *
479*4882a593Smuzhiyun * @dev: mei_device
480*4882a593Smuzhiyun */
mei_me_set_pm_domain(struct mei_device * dev)481*4882a593Smuzhiyun static inline void mei_me_set_pm_domain(struct mei_device *dev)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun struct pci_dev *pdev = to_pci_dev(dev->dev);
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun if (pdev->dev.bus && pdev->dev.bus->pm) {
486*4882a593Smuzhiyun dev->pg_domain.ops = *pdev->dev.bus->pm;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun dev->pg_domain.ops.runtime_suspend = mei_me_pm_runtime_suspend;
489*4882a593Smuzhiyun dev->pg_domain.ops.runtime_resume = mei_me_pm_runtime_resume;
490*4882a593Smuzhiyun dev->pg_domain.ops.runtime_idle = mei_me_pm_runtime_idle;
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun dev_pm_domain_set(&pdev->dev, &dev->pg_domain);
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun /**
497*4882a593Smuzhiyun * mei_me_unset_pm_domain - clean pm domain structure for device
498*4882a593Smuzhiyun *
499*4882a593Smuzhiyun * @dev: mei_device
500*4882a593Smuzhiyun */
mei_me_unset_pm_domain(struct mei_device * dev)501*4882a593Smuzhiyun static inline void mei_me_unset_pm_domain(struct mei_device *dev)
502*4882a593Smuzhiyun {
503*4882a593Smuzhiyun /* stop using pm callbacks if any */
504*4882a593Smuzhiyun dev_pm_domain_set(dev->dev, NULL);
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun static const struct dev_pm_ops mei_me_pm_ops = {
508*4882a593Smuzhiyun SET_SYSTEM_SLEEP_PM_OPS(mei_me_pci_suspend,
509*4882a593Smuzhiyun mei_me_pci_resume)
510*4882a593Smuzhiyun SET_RUNTIME_PM_OPS(
511*4882a593Smuzhiyun mei_me_pm_runtime_suspend,
512*4882a593Smuzhiyun mei_me_pm_runtime_resume,
513*4882a593Smuzhiyun mei_me_pm_runtime_idle)
514*4882a593Smuzhiyun };
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun #define MEI_ME_PM_OPS (&mei_me_pm_ops)
517*4882a593Smuzhiyun #else
518*4882a593Smuzhiyun #define MEI_ME_PM_OPS NULL
519*4882a593Smuzhiyun #endif /* CONFIG_PM */
520*4882a593Smuzhiyun /*
521*4882a593Smuzhiyun * PCI driver structure
522*4882a593Smuzhiyun */
523*4882a593Smuzhiyun static struct pci_driver mei_me_driver = {
524*4882a593Smuzhiyun .name = KBUILD_MODNAME,
525*4882a593Smuzhiyun .id_table = mei_me_pci_tbl,
526*4882a593Smuzhiyun .probe = mei_me_probe,
527*4882a593Smuzhiyun .remove = mei_me_remove,
528*4882a593Smuzhiyun .shutdown = mei_me_shutdown,
529*4882a593Smuzhiyun .driver.pm = MEI_ME_PM_OPS,
530*4882a593Smuzhiyun .driver.probe_type = PROBE_PREFER_ASYNCHRONOUS,
531*4882a593Smuzhiyun };
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun module_pci_driver(mei_me_driver);
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun MODULE_AUTHOR("Intel Corporation");
536*4882a593Smuzhiyun MODULE_DESCRIPTION("Intel(R) Management Engine Interface");
537*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
538